/* ==========================================================================
   idcub 主题 · 基础层 (Base)
   reset + 排版 + 通用组件（按钮/徽章/表单/卡片/导航）
   所有取值一律引用 token.css 的变量，不写死具体数值
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Reset
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  -webkit-tap-highlight-color: transparent;
}

body {
  margin: 0;
  font-family: var(--nv-font);
  font-size: var(--nv-fs-body);
  line-height: var(--nv-lh-body);
  letter-spacing: var(--nv-ls-body);
  color: var(--nv-text-primary);
  background: var(--nv-page);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;

  /* ── 粘性页脚（sticky footer）──────────────────────────────────────
     ★ 解决「内容少时页脚自动抬上来，页面显得很矮」的问题。
       订单查询页在还没输入查询条件时只有 hero + 三条帮助，
       内容高度不足一屏，页脚就会顶到内容下面，露出一大片空白背景。

     做法：把 body 变成撑满视口的纵向 flex 容器，
           让 <main> 用 flex:1 吃掉剩余高度，
           页脚自然被推到底部。
     ★ 三层结构必须齐全：body(列) → main(flex:1) → footer(定高)，
       缺任一层都会失效。
     ★ 只影响高度分配，不改变任何间距与视觉 —— 页面内容高于一屏时
       行为与之前完全一致（main 会被内容撑开，非固定高度）。 */
  min-height: 100vh;
  min-height: 100dvh;   /* 移动端动态视口：避免地址栏收放导致高度跳动 */
  display: flex;
  flex-direction: column;
}

/* 页面主体：吃掉头部与页脚之外的全部剩余高度
   ★★ :not(.nv-auth) 这个排除不能省 ——
      认证页（登录/注册/找回密码）的 <main id="nv-main" class="nv-auth">
      把这两个类写在【同一个元素】上，而 .nv-auth 内部已经用
      min-height: calc(100vh - var(--nv-header-h) - var(--nv-footer-h))
      自己撑满了高度（shop.css 里的既有方案）。
      若这里再给 flex:1 撑一次，两者会叠加成 100vh + 剩余空间，
      页面被拉长一倍、卡片下方出现大片空白。
      → 认证页走它自己那套，不参与这里的 flex 分配。 */
#nv-main:not(.nv-auth) {
  flex: 1 0 auto;
}

/* 页脚：不被压缩，始终贴底 */
.nv-footer {
  flex: 0 0 auto;
}

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd {
  margin: 0;
}

ul, ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

img, picture, svg, video {
  display: block;
  max-width: 100%;
  height: auto;
}

button, input, select, textarea {
  font: inherit;
  color: inherit;
  margin: 0;
}

button {
  background: none;
  border: none;
  cursor: pointer;
}

a {
  color: var(--nv-brand-ink);
  text-decoration: none;
  transition: color var(--nv-dur-fast) var(--nv-ease-out);
}
a:hover { color: var(--nv-brand-hover); }

hr {
  border: 0;
  border-top: 1px solid var(--nv-border-soft);
  margin: var(--nv-space-6) 0;
}

table { border-collapse: collapse; width: 100%; }

/* --------------------------------------------------------------------------
   2. 可访问性工具类
   -------------------------------------------------------------------------- */
.nv-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.nv-skip-link {
  position: absolute;
  top: -100px; left: var(--nv-space-4);
  z-index: var(--nv-z-toast);
  padding: var(--nv-space-3) var(--nv-space-5);
  background: var(--nv-brand-solid);
  color: var(--nv-text-on-solid);
  border-radius: var(--nv-radius-md);
  font-weight: var(--nv-weight-medium);
  transition: top var(--nv-dur-fast) var(--nv-ease-out);
}
.nv-skip-link:focus { top: var(--nv-space-3); color: var(--nv-text-on-solid); }

/* 统一焦点环 —— 全站键盘可达性的唯一来源 */
:focus-visible {
  outline: none;
  box-shadow: var(--nv-ring);
  border-radius: var(--nv-radius-sm);
}

/* --------------------------------------------------------------------------
   3. 布局容器
   -------------------------------------------------------------------------- */
.nv-container {
  width: 100%;
  max-width: var(--nv-container);
  margin-inline: auto;
  padding-inline: var(--nv-space-4);
}
@media (min-width: 768px) {
  .nv-container { padding-inline: var(--nv-space-6); }
}
@media (min-width: 1280px) {
  .nv-container { padding-inline: var(--nv-space-8); }
}

.nv-container--narrow {
  max-width: var(--nv-container-narrow);
}

/* --------------------------------------------------------------------------
   4. 排版层级
   字距随字号反向变化，这是 Apple 排版的核心纪律
   -------------------------------------------------------------------------- */
.nv-display {
  font-size: var(--nv-fs-display);
  line-height: var(--nv-lh-display);
  letter-spacing: var(--nv-ls-display);
  font-weight: var(--nv-weight-bold);
}

.nv-title {
  font-size: var(--nv-fs-title);
  line-height: var(--nv-lh-display);
  letter-spacing: var(--nv-ls-title);
  font-weight: var(--nv-weight-bold);
}

.nv-heading {
  font-size: var(--nv-fs-heading);
  line-height: var(--nv-lh-heading);
  letter-spacing: var(--nv-ls-heading);
  font-weight: var(--nv-weight-medium);
}

.nv-body { font-size: var(--nv-fs-body); line-height: var(--nv-lh-body); }

.nv-caption {
  font-size: var(--nv-fs-caption);
  line-height: var(--nv-lh-tight);
  letter-spacing: var(--nv-ls-small);
  color: var(--nv-text-muted);
}

.nv-micro {
  font-size: var(--nv-fs-micro);
  line-height: var(--nv-lh-tight);
  letter-spacing: var(--nv-ls-small);
  color: var(--nv-text-muted);
}

/* 多行截断 */
.nv-clamp-1,
.nv-clamp-2,
.nv-clamp-3 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.nv-clamp-1 { -webkit-line-clamp: 1; }
.nv-clamp-2 { -webkit-line-clamp: 2; }
.nv-clamp-3 { -webkit-line-clamp: 3; }

/* 数字等宽 —— 价格、库存、订单号必须用 */
.nv-num {
  font-family: var(--nv-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* --------------------------------------------------------------------------
   5. 按钮 · Buttons
   触控热区统一 ≥44px（WCAG 2.5.5）
   -------------------------------------------------------------------------- */
.nv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--nv-space-2);
  min-height: var(--nv-tap-min);
  padding: var(--nv-space-2) var(--nv-space-5);
  border-radius: var(--nv-radius-btn);
  border: 1px solid transparent;
  font-size: var(--nv-fs-body);
  font-weight: var(--nv-weight-medium);
  letter-spacing: var(--nv-ls-small);
  text-align: center;
  cursor: pointer;
  user-select: none;
  transition:
    background-color var(--nv-dur-fast) var(--nv-ease-out),
    border-color var(--nv-dur-fast) var(--nv-ease-out),
    color var(--nv-dur-fast) var(--nv-ease-out),
    box-shadow var(--nv-dur-normal) var(--nv-ease-out),
    transform var(--nv-dur-fast) var(--nv-ease-out);
}

.nv-btn:active:not(:disabled) { transform: translateY(1px); }

.nv-btn:disabled,
.nv-btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
  pointer-events: none;
}

/* 主 CTA —— 品牌渐变 + 白字 */
.nv-btn--primary {
  background-image: var(--nv-gradient);
  color: var(--nv-text-on-solid);
  box-shadow: var(--nv-shadow-brand);
}
.nv-btn--primary:hover:not(:disabled) {
  color: var(--nv-text-on-solid);
  box-shadow: 0 16px 34px -14px rgba(37, 99, 235, .55);
  transform: translateY(-1px);
}

/* 实心 —— 用 -solid 保证白字达标 */
.nv-btn--solid {
  background-color: var(--nv-brand-solid);
  color: var(--nv-text-on-solid);
}
.nv-btn--solid:hover:not(:disabled) {
  background-color: var(--nv-brand-hover);
  color: var(--nv-text-on-solid);
}

/* 中性 —— soft 底 + 边框 */
.nv-btn--neutral {
  background-color: var(--nv-soft);
  border-color: var(--nv-border);
  color: var(--nv-text-primary);
}
.nv-btn--neutral:hover:not(:disabled) {
  background-color: var(--nv-muted);
  border-color: var(--nv-border-strong);
  color: var(--nv-text-primary);
}

/* 幽灵 —— 透明底 */
.nv-btn--ghost {
  background-color: transparent;
  border-color: var(--nv-border-strong);
  color: var(--nv-text-primary);
}
.nv-btn--ghost:hover:not(:disabled) {
  background-color: var(--nv-brand-soft);
  border-color: var(--nv-border-brand);
  color: var(--nv-brand-ink);
}

/* 危险 */
.nv-btn--danger {
  background-color: var(--nv-danger-soft);
  color: var(--nv-danger-ink);
}
.nv-btn--danger:hover:not(:disabled) {
  background-color: var(--nv-danger);
  color: #fff;
}

/* 尺寸 */
.nv-btn--sm { min-height: 34px; padding: var(--nv-space-1) var(--nv-space-3); font-size: var(--nv-fs-caption); }
.nv-btn--lg { min-height: 52px; padding: var(--nv-space-3) var(--nv-space-8); font-size: var(--nv-fs-heading); }
.nv-btn--block { display: flex; width: 100%; }

/* --------------------------------------------------------------------------
   6. 徽章 · Badges
   ★ 彩色徽章文字必须走 -ink（AA 达标），不能用 -solid
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   7. 表单 · Forms
   移动端 16px 防 iOS Safari 自动放大
   -------------------------------------------------------------------------- */
.nv-field { display: block; margin-bottom: var(--nv-space-4); }

.nv-label {
  display: block;
  margin-bottom: var(--nv-space-2);
  font-size: var(--nv-fs-caption);
  font-weight: var(--nv-weight-medium);
  color: var(--nv-text-secondary);
  letter-spacing: var(--nv-ls-small);
}

.nv-input,
.nv-select,
.nv-textarea {
  display: block;
  width: 100%;
  min-height: var(--nv-tap-min);
  padding: var(--nv-space-3) var(--nv-space-4);
  background-color: var(--nv-elevated);
  border: 1px solid var(--nv-border);
  border-radius: var(--nv-radius-btn);
  font-size: 16px;                      /* 防 iOS 缩放 */
  color: var(--nv-text-primary);
  transition:
    border-color var(--nv-dur-fast) var(--nv-ease-out),
    box-shadow var(--nv-dur-fast) var(--nv-ease-out);
}

.nv-textarea { min-height: 96px; resize: vertical; line-height: var(--nv-lh-body); }

.nv-input::placeholder,
.nv-textarea::placeholder { color: var(--nv-text-faint); }

.nv-input:focus,
.nv-select:focus,
.nv-textarea:focus {
  outline: none;
  border-color: var(--nv-brand);
  box-shadow: var(--nv-ring);
}

.nv-input:disabled { background-color: var(--nv-soft); color: var(--nv-text-muted); cursor: not-allowed; }

/* 校验失败态：边框与 ring 换成危险色。
   ★ 不只靠颜色传达 —— 下方还会跟一条文字提示，
     色盲用户与读屏用户都能获得反馈。 */
.nv-input.is-invalid,
.nv-select.is-invalid,
.nv-textarea.is-invalid {
  border-color: var(--nv-danger);
  box-shadow: 0 0 0 3px rgba(var(--nv-danger-rgb), 0.16);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--nv-danger) 16%, transparent);
}
.nv-input.is-invalid:focus,
.nv-select.is-invalid:focus,
.nv-textarea.is-invalid:focus { border-color: var(--nv-danger); }

/* ══════════════════════════════════════════════════════════════════
   认证页错误横幅（.nv-auth__alert）
   ──────────────────────────────────────────────────────────────────
   ★ 起因（2026-10-16 用户反馈）：
     核心 login.js 出错只调 message.error()，那是【右上角 toast】。
     登录页用户视线在表单上，右上角几乎等于看不见。

   ★ 设计取舍：
     · 浅红底 + 深红字 + 左侧图标 —— 三个通道同时表意，
       不只靠颜色（色盲/读屏用户一样能感知）。
     · 与输入框的 .is-invalid 共用 --nv-danger 系，
       整个表单的错误语言保持一致。
     · 用 hidden 属性控制显隐 —— 无错误时不占高度，
       不会把下面的输入框往下推。
     · 深色模式下 --nv-danger-* 会自动切换到更亮的那套
       （token.css 第 283-287 行），无需在这里单独写 dark 覆盖。
   ══════════════════════════════════════════════════════════════════ */
.nv-auth__alert {
  display: flex;
  align-items: flex-start;
  gap: var(--nv-space-2);
  margin-bottom: var(--nv-space-4);
  padding: 10px 12px;
  border: 1px solid rgba(var(--nv-danger-rgb), 0.35);
  border-left: 3px solid var(--nv-danger);
  border-radius: var(--nv-radius-md);
  background-color: var(--nv-danger-soft);
  color: var(--nv-danger-ink);
  font-size: var(--nv-fs-small);
  line-height: 1.55;
}
/* ★ hidden 必须显式声明 display:none —— 上面给了 display:flex，
   否则 [hidden] 的浏览器默认样式会被作者样式覆盖，藏不住。 */
.nv-auth__alert[hidden] { display: none; }
.nv-auth__alert .material-icons-outlined {
  flex: 0 0 auto;
  font-size: 18px;
  line-height: 1.4;
}
.nv-auth__alert-text { flex: 1 1 auto; min-width: 0; }
/* 出错时轻微抖一下，把注意力拉过来（尊重「减少动态效果」偏好） */
@media (prefers-reduced-motion: no-preference) {
  .nv-auth__alert.is-shake { animation: nv-auth-shake .32s ease-in-out 1; }
}
@keyframes nv-auth-shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}

/* 字段级提示文案（校验错误等） */
.nv-field-tip {
  margin: 6px 0 0;
  font-size: var(--nv-fs-micro);
  line-height: 1.5;
  color: var(--nv-danger-ink, var(--nv-danger));
}

.nv-select {
  appearance: none;
  padding-right: var(--nv-space-10);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%236e6e73' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--nv-space-4) center;
  cursor: pointer;
}

.nv-hint { margin-top: var(--nv-space-2); font-size: var(--nv-fs-micro); color: var(--nv-text-muted); }
.nv-error { margin-top: var(--nv-space-2); font-size: var(--nv-fs-micro); color: var(--nv-danger-ink); }

/* --------------------------------------------------------------------------
   8. 卡片 · Card
   -------------------------------------------------------------------------- */
.nv-card {
  background-color: var(--nv-elevated);
  border: 1px solid var(--nv-border-soft);
  border-radius: var(--nv-radius-card);
  box-shadow: var(--nv-shadow-1);
  overflow: hidden;
}

/* 毛玻璃表面 —— 纪律：不能叠在另一层玻璃上 */
.nv-glass {
  background-color: var(--nv-glass);
  backdrop-filter: var(--nv-blur);
  -webkit-backdrop-filter: var(--nv-blur);
  border: 1px solid var(--nv-glass-border);
}

/* --------------------------------------------------------------------------
   9. 顶栏 · Header（毛玻璃悬浮）
   -------------------------------------------------------------------------- */
.nv-header {
  position: sticky;
  top: 0;
  z-index: var(--nv-z-header);
  background-color: var(--nv-glass);
  backdrop-filter: var(--nv-blur);
  -webkit-backdrop-filter: var(--nv-blur);
  border-bottom: 1px solid var(--nv-border-soft);
}
/* 顶边高光：模拟光打在材质上 */
.nv-header::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  background: var(--nv-glass-border);
  pointer-events: none;
}

.nv-header__inner {
  display: flex;
  align-items: center;
  gap: var(--nv-space-4);
  height: var(--nv-header-h);
}

.nv-brand {
  display: flex;
  align-items: center;
  gap: var(--nv-space-3);
  flex-shrink: 0;
  color: var(--nv-text-primary);
}
.nv-brand:hover { color: var(--nv-text-primary); }

/* 店铺 logo 方块
   ★ 两种形态，视觉尺寸完全一致（28×28 / 圆角 / 同阴影），只是内容来源不同：
     · 有真实 favicon → 里面放 <img>，宽高填满、圆角继承
     · 加载失败        → JS 打上 .is-fallback 并移除 img，回落到品牌渐变底
   这样页头与页脚（页脚直接是 <img>）看起来是同一个 logo，不会再一个色块一个图片。 */
.nv-brand__mark {
  position: relative;
  display: block;
  width: 28px; height: 28px;
  border-radius: var(--nv-radius-sm);
  background-image: var(--nv-gradient);
  box-shadow: var(--nv-shadow-brand);
  flex-shrink: 0;
  overflow: hidden;
}

.nv-brand__mark > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: inherit;
}

/* 有图时不要再透出渐变底（透明 PNG 也能干净显示） */
.nv-brand__mark:has(> img) {
  background-image: none;
  box-shadow: none;
}

/* 降级：无图 → 渐变方块（默认样式即为此，这里只是显式兜底） */
.nv-brand__mark.is-fallback {
  background-image: var(--nv-gradient);
  box-shadow: var(--nv-shadow-brand);
}

.nv-brand__name {
  font-size: var(--nv-fs-body);
  font-weight: var(--nv-weight-bold);
  letter-spacing: var(--nv-ls-heading);
  -webkit-text-stroke: .4px currentColor;
}

.nv-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  border-radius: var(--nv-radius-btn);
  color: var(--nv-text-secondary);
  transition: background-color var(--nv-dur-fast) var(--nv-ease-out);
}
.nv-icon-btn:hover { background-color: var(--nv-brand-softer); color: var(--nv-brand-ink); }
.nv-icon-btn svg { width: 18px; height: 18px; }

/* 汉堡（窄屏菜单开关）
   ★ 固定为「36×36 圆角方钮 + 品牌浅底」：
     它出现在窄屏，此时右侧动作区常只剩它一个可点元素，
     需要比其他图标按钮更明确的可点边界，避免被当成装饰。
     尺寸/圆角/色彩全部显式声明（不依赖 .nv-icon-btn 继承），保证稳定。 */
.nv-burger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  flex: 0 0 36px;
  border: 1px solid var(--nv-border);
  border-radius: var(--nv-radius-btn);
  background-color: var(--nv-soft);
  color: var(--nv-text-secondary);
  transition:
    background-color var(--nv-dur-fast) var(--nv-ease-out),
    border-color var(--nv-dur-fast) var(--nv-ease-out),
    color var(--nv-dur-fast) var(--nv-ease-out);
}
.nv-burger:hover {
  background-color: var(--nv-brand-soft);
  border-color: var(--nv-border-brand);
  color: var(--nv-brand-ink);
}
.nv-burger:active { transform: translateY(1px); }
.nv-burger .material-icons-outlined { font-size: 20px; }

@media (min-width: 900px) {
  .nv-burger { display: none; }
}

/* --------------------------------------------------------------------------
   9.1 搜索框 · 仅作用于抽屉内（.nv-search--drawer）
   --------------------------------------------------------------------------
   ★ 页头里的主搜索框样式已迁到 header.css（三层改版）。
     这里只保留抽屉内那份：它是 flex column 里的子项，
     需要独立的高度/宽度约束，与页头版本差异较大，故留在此处。
   -------------------------------------------------------------------------- */
.nv-search {
  display: flex;
  align-items: center;
  gap: var(--nv-space-2);
  min-width: 0;
  height: 42px;
  padding: 0 var(--nv-space-1) 0 var(--nv-space-3);
  border: 1px solid var(--nv-border);
  border-radius: var(--nv-radius-pill);
  background-color: var(--nv-soft);
  transition:
    border-color var(--nv-dur-fast) var(--nv-ease-out),
    background-color var(--nv-dur-fast) var(--nv-ease-out),
    box-shadow var(--nv-dur-fast) var(--nv-ease-out);
}

.nv-search:focus-within {
  border-color: var(--nv-border-brand);
  background-color: var(--nv-elevated);
  box-shadow: var(--nv-ring);
}

.nv-search__ico {
  font-size: 18px;
  flex: 0 0 18px;
  color: var(--nv-text-faint);
  transition: color var(--nv-dur-fast) var(--nv-ease-out);
}
.nv-search:focus-within .nv-search__ico { color: var(--nv-brand); }

/* 输入框本体：清掉浏览器默认 search 外观，保证与胶囊容器融为一体 */
.nv-search__input {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  outline: none;
  background: transparent;
  font-size: var(--nv-fs-caption);
  color: var(--nv-text-primary);
}
.nv-search__input::placeholder { color: var(--nv-text-faint); }
.nv-search__input::-webkit-search-cancel-button { -webkit-appearance: none; }

.nv-search__btn {
  flex: 0 0 auto;
  height: 28px;
  padding-inline: var(--nv-space-3);
  border-radius: var(--nv-radius-pill);
  background-image: var(--nv-gradient);
  color: #fff;
  font-size: var(--nv-fs-micro);
  font-weight: var(--nv-weight-medium);
  white-space: nowrap;
  transition: opacity var(--nv-dur-fast) var(--nv-ease-out);
}
.nv-search__btn:hover { opacity: .9; }

/* 抽屉内的搜索框：始终显示，占满一行，与抽屉链接留出间距
   ★★ 必须压住高度（flex: 0 0 auto + 固定 height）：
     .nv-drawer 是 flex column，子项默认 flex-shrink:1 / align-stretch，
     不加约束时这个搜索框会被「拉伸填满剩余高度」，
     实测渲染成一个巨大的椭圆（860px 高），把导航全挤到下面去了。
   ★ align-self: stretch 保留（要横向占满），但纵向必须定死。 */
.nv-search--drawer {
  display: flex;
  flex: 0 0 auto;
  align-self: stretch;
  width: 100%;
  height: 42px;
  max-width: none;
  margin-bottom: var(--nv-space-4);
  background-color: var(--nv-soft);
}

/* --------------------------------------------------------------------------
   10. 抽屉 · Drawer（窄屏导航）
   -------------------------------------------------------------------------- */
.nv-drawer {
  position: fixed;
  inset-block: 0;
  right: 0;
  width: min(320px, 84vw);
  z-index: var(--nv-z-drawer);
  display: flex;
  flex-direction: column;
  /* ★★ 关键：抽屉是「高 100vh 的 flex column」，子项默认会被拉伸/压缩。
     必须让它们保持内容高度（flex-shrink:0），否则一旦内容超过视口，
     链接会被压扁；而单个子项（如搜索框）在内容少时又会被拉长。
     配套规则：内容超出时整体可滚动。 */
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--nv-space-5);
  background-color: var(--nv-glass-strong);
  backdrop-filter: var(--nv-blur-strong);
  -webkit-backdrop-filter: var(--nv-blur-strong);
  border-left: 1px solid var(--nv-border-soft);
  box-shadow: var(--nv-shadow-3);
  transform: translateX(100%);
  visibility: hidden;
  transition:
    transform var(--nv-dur-normal) var(--nv-ease-out),
    visibility var(--nv-dur-normal) var(--nv-ease-out);
}
.nv-drawer.is-open { transform: translateX(0); visibility: visible; }

.nv-drawer__shade {
  position: fixed;
  inset: 0;
  z-index: calc(var(--nv-z-drawer) - 1);
  background: rgba(0, 0, 0, .32);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--nv-dur-normal) var(--nv-ease-out), visibility var(--nv-dur-normal);
}
.nv-drawer__shade.is-open { opacity: 1; visibility: visible; }

.nv-drawer__link {
  flex: 0 0 auto;                 /* ★ 防止在 flex column 里被压扁 */
  display: flex;
  align-items: center;
  gap: var(--nv-space-3);
  min-height: var(--nv-tap-min);
  padding: var(--nv-space-2) var(--nv-space-3);
  border-radius: var(--nv-radius-md);
  font-size: var(--nv-fs-body);
  font-weight: var(--nv-weight-medium);
  color: var(--nv-text-primary);
}
.nv-drawer__link:hover { background-color: var(--nv-brand-softer); color: var(--nv-text-primary); }
.nv-drawer__link svg { width: 17px; height: 17px; color: var(--nv-text-muted); }
.nv-drawer__link.is-danger { color: var(--nv-danger-ink); }
.nv-drawer__link.is-danger svg { color: var(--nv-danger); }

/* 抽屉内的分组容器：同样不能被 flex 拉伸/压缩 */
.nv-drawer .nv-user-block,
.nv-drawer .nv-guest-block,
.nv-drawer > .nv-flex {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

.nv-drawer__sep {
  flex: 0 0 auto;
  height: 1px;
  margin: var(--nv-space-3) 0;
  background: var(--nv-border-soft);
}

/* 抽屉打开时锁定滚动 */
html.nv-drawer-open { overflow: hidden; }

/* --------------------------------------------------------------------------
   11. 下拉 · Dropdown
   -------------------------------------------------------------------------- */
.nv-drop { position: relative; }

.nv-drop__menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 168px;
  padding: var(--nv-space-2);
  background-color: var(--nv-glass-strong);
  backdrop-filter: var(--nv-blur-strong);
  -webkit-backdrop-filter: var(--nv-blur-strong);
  border: 1px solid var(--nv-border-soft);
  border-radius: var(--nv-radius-card);
  box-shadow: var(--nv-shadow-2);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition:
    opacity var(--nv-dur-fast) var(--nv-ease-out),
    transform var(--nv-dur-fast) var(--nv-ease-out),
    visibility var(--nv-dur-fast);
}
.nv-drop.is-open .nv-drop__menu { opacity: 1; visibility: visible; transform: translateY(0); }

.nv-drop__item {
  display: flex;
  align-items: center;
  gap: var(--nv-space-2);
  min-height: 38px;
  padding: var(--nv-space-2) var(--nv-space-3);
  border-radius: var(--nv-radius-sm);
  font-size: var(--nv-fs-caption);
  color: var(--nv-text-primary);
  cursor: pointer;
}
.nv-drop__item:hover { background-color: var(--nv-brand-softer); color: var(--nv-text-primary); }
.nv-drop__item.is-active { color: var(--nv-brand-ink); font-weight: var(--nv-weight-medium); }

/* --------------------------------------------------------------------------
   12. 页脚 · Footer（两行紧凑版）
   --------------------------------------------------------------------------
   第一行：品牌 + 简介 + 联系方式（右对齐）
   第二行：版权 + 服务徽章

   ★ 高度优化：旧版三段式（左右两栏 + 底栏）在右侧无内容时高达 220px；
     本版改为两行流式排布，内边距从 48/32 收到 22/14，实测降至 ~129px。

   ★ 内容固定，不再新增：品牌 / 简介 / 联系方式（主题设置可配）/ 服务徽章。
   ★ 备案号已按需求移除（原 $setting.icp 不再渲染）。
   ★ 窄屏（≤900px）自然换行堆叠，无需额外媒体查询。
   -------------------------------------------------------------------------- */
.nv-footer {
  margin-top: var(--nv-space-8);
  border-top: 1px solid var(--nv-border-soft);
  background-color: var(--nv-elevated);
}

/* ── 第一行：品牌 · 简介 · 联系方式 ──
   ★★★ 2026-10-17 修：align-items 从 center 改为 flex-start
   --------------------------------------------------------------------------
   用户反馈：简介换行时效果不好，第二行「护航。」顶在 logo 下面，
   和第一行错开，看着像独立的一段。

   实测两个层级的问题：

   ① 宽屏（≥1024）：三者同行，但
        brand  高 30px（logo+站名）
        slogan 高 38px（两行 × 19.2px）
      `align-items: center` 把 brand 垂直居中于 38px 高度里 →
      它的顶部比 slogan 首行低 4px，**首行不对齐**。

   ② 窄屏（≤768）：flex-wrap 让三者变成三行堆叠，
      `center` 对每一行独立生效，行与行之间出现不匀的 50px 空隙。

   ★ 根因：**flex 容器的 align-items 只对"单行内的子项"有意义** ——
     一旦子项高度不一致（或换行成多行），"垂直居中"就等于"都歪一点"。
     这里三个子项的高度天然不同（30 / 38 / 30），且会换行，
     所以必须用 **flex-start** 让它们从同一条顶线开始。
   -------------------------------------------------------------------------- */
.nv-footer__top {
  display: flex;
  align-items: flex-start;   /* ★ 原 center：导致首行错位 / 换行后间距不匀 */
  gap: var(--nv-space-5);
  flex-wrap: wrap;
  padding: var(--nv-space-5) 0 var(--nv-space-4);
}

/* 品牌区的 logo + 站名本身是单行，高度 30px。
   在 flex-start 下它会贴顶，而简介首行的**文字中线**比 30px 盒子顶部低 ——
   加一点上边距让两者视觉基线对齐（不是数学对齐，是观感对齐）。
   ★ 6px 的来历：(38 - 30)/2 ≈ 4，再补 2px 弥补字体的行盒上下留白。 */
.nv-footer__brand {
  display: flex;
  align-items: center;
  gap: var(--nv-space-2);
  flex: 0 0 auto;
  margin-top: 2px;
}

/* 页脚 logo 比页头小一档，避免页脚比页头还重 */
.nv-footer .nv-brand__mark {
  width: 30px;
  height: 30px;
  flex: 0 0 30px;
}
.nv-footer .nv-brand__name {
  font-size: var(--nv-fs-body);
  font-weight: var(--nv-weight-bold);
  letter-spacing: var(--nv-ls-heading);
}

.nv-footer__slogan {
  margin: 0;
  flex: 1 1 28ch;
  min-width: 0;
  font-size: var(--nv-fs-caption);
  line-height: 1.6;
  color: var(--nv-text-muted);
  /* 限宽：简介过长时折成两行而不是把联系方式挤到下一行 */
  max-width: 52ch;
  /* ★★★ 2026-10-17 中文断行修复（用户反馈「换行效果不太好」）
     ==================================================================
     问题：35 字文案在窄屏（每行约 30 字）下断成
       第 1 行 30 字：「…为你的每一次购买」
       第 2 行  5 字：「保驾护航。」   ← 孤行，像一句多余的话

     ★★ 关键认知：**中文默认允许在任意字之间断行**
        （汉字之间没有空格，CSS 的 normal 规则会在字间断开）
        所以不管容器多宽，都可能出现「全天 / 候售后」这种劈词。

     实测 5 种组合（393px 与 1440px 结果一致）：

       | 模式                 | 断行      | 结果 |
       |----------------------|-----------|------|
       | balance              | 18 + 17   | ❌ 劈开「全天候」|
       | **keep-all**         | **22+13** | ✅ 断在「，」后 |
       | **keep-all+balance** | **16+19** | ✅ 断在「、」后，更均衡 |
       | strict               | 30 + 5    | ❌ 孤行 |
       | strict + balance     | 18 + 17   | ❌ 劈词 |

     → 采用 **word-break: keep-all + text-wrap: balance**：
       · keep-all = 禁止汉字之间断行，只允许在标点处断 →
         保证语义完整，不会把「全天候」劈成两半
       · balance  = 在合法断点之间挑最均衡的那个 →
         从 22:13 优化到 16:19

     ★ 这条规则对【后台任意文案】都成立，不依赖具体内容 ——
       所以只改 CSS、不改文案（用户要求以后台设置为准）。

     ★ 兼容性：keep-all 是 CSS2.1 属性，全平台支持；
       balance 不支持的浏览器会忽略，退回"只按标点断行"，
       依然不会劈词 —— 这是安全的降级方向。 */
  word-break: keep-all;
  overflow-wrap: break-word;   /* ★ 兜底：超长英文/URL 仍需能断，否则会溢出 */
  text-wrap: balance;
}

/* 联系方式：芯片形态，与页头的交互元素语言一致 */
.nv-footer__contact {
  display: flex;
  align-items: center;
  gap: var(--nv-space-2);
  flex-wrap: wrap;
  margin-left: auto;
  flex: 0 0 auto;
}
.nv-footer__contact-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 12px;
  border-radius: var(--nv-radius-pill);
  background-color: var(--nv-soft);
  font-size: var(--nv-fs-micro);
  color: var(--nv-text-muted);
  transition:
    background-color var(--nv-dur-fast) var(--nv-ease-out),
    color var(--nv-dur-fast) var(--nv-ease-out);
}
.nv-footer__contact-item:hover {
  background-color: var(--nv-brand-soft);
  color: var(--nv-brand-ink);
}
.nv-footer__contact-item .material-icons-outlined {
  font-size: var(--nv-icon-sm);
}

/* ── 第二行：版权 · 服务徽章 ── */
.nv-footer__bottom {
  display: flex;
  align-items: center;
  gap: var(--nv-space-4);
  flex-wrap: wrap;
  padding: var(--nv-space-3) 0;
  border-top: 1px solid var(--nv-border-soft);
}

.nv-footer__copy {
  font-size: var(--nv-fs-micro);
  color: var(--nv-text-faint);
}

.nv-footer__badges {
  display: flex;
  align-items: center;
  gap: var(--nv-space-4);
  flex-wrap: wrap;
  margin-left: auto;
}
.nv-footer__badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--nv-fs-micro);
  color: var(--nv-text-muted);
  white-space: nowrap;
}
.nv-footer__badge .material-icons-outlined {
  font-size: 14px;
  color: var(--nv-text-faint);
}

/* ICP 备案徽章 —— 与同排徽章共用形态与节奏，但它是【可点外链】。
   --------------------------------------------------------------------------
   ★ 设计纪律：这一排里「陈述性」徽章（自动发货 / 售后保障 / 在线客服）都不加底色，
     备案号也不能靠加底色来区分 —— 那会让并列的四条看起来不同类。
     区分手段改用「链接才有的反馈」：hover 下划线 + 品牌色。
     扫读时它不突兀，鼠标移上去才知道可点，符合「可点即显形」。
   ★ 备案号较长（如 沪ICP备xxx号-12）时它比另三条宽，flex-wrap 会自然换行，
     无需额外处理。 */
.nv-footer__badge--link {
  text-decoration: none;
  transition: color var(--nv-dur-fast) var(--nv-ease-out);
}
.nv-footer__badge--link:hover {
  color: var(--nv-brand-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.nv-footer__badge--link:hover .material-icons-outlined {
  color: var(--nv-brand-ink);
}

/* ── 窄屏：联系方式与徽章各占一行，避免与品牌挤在一起 ── */
@media (max-width: 900px) {
  .nv-footer__slogan {
    flex: 1 1 100%;
    max-width: none;
  }
  .nv-footer__contact {
    margin-left: 0;
    flex: 1 1 100%;
  }
  .nv-footer__badges {
    margin-left: 0;
    flex: 1 1 100%;
  }
}


/* --------------------------------------------------------------------------
   13. 公告条 · Notice
   -------------------------------------------------------------------------- */
.nv-notice {
  display: flex;
  align-items: center;
  gap: var(--nv-space-2);
  padding: var(--nv-space-2) var(--nv-space-3);
  background-color: var(--nv-brand-soft);
  border-radius: var(--nv-radius-card);
  font-size: var(--nv-fs-caption);
  color: var(--nv-brand-ink);
}
.nv-notice svg { width: 15px; height: 15px; flex-shrink: 0; }
.nv-notice__text { flex: 1; }

/* --------------------------------------------------------------------------
   14. 空态 / 加载态
   --------------------------------------------------------------------------
   ★ 对齐 idcub-dujiao-myuse（Nuxt 4.3）的 EmptyState.vue：
     · 图标 24px 线性 + 弱化色
     · 标题 text-lg 加粗，说明文字弱化并限宽（避免长句拉成一整行）
     · 可选【行动按钮】：药丸形 + 品牌实心，给用户一条出路
     · 可选 soft 变体：虚线描边 + 浅底，用于「区块内」的空态
       （与「整页空态」区分 —— 整页空态不需要外框）
   -------------------------------------------------------------------------- */
.nv-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nv-space-3);
  padding: var(--nv-space-16) var(--nv-space-4);
  text-align: center;
}
.nv-empty svg { width: 40px; height: 40px; color: var(--nv-text-faint); }
.nv-empty__title { font-size: var(--nv-fs-heading); font-weight: var(--nv-weight-medium); }
.nv-empty__text { font-size: var(--nv-fs-caption); color: var(--nv-text-muted); max-width: 34ch; }

/* soft 变体：区块内的空态，加虚线框把它"圈"出来，
   否则在一堆实心卡片之间会显得像漏渲染。 */
.nv-empty--soft {
  padding: var(--nv-space-10) var(--nv-space-6);
  border: 1px dashed var(--nv-border);
  border-radius: var(--nv-radius-xl);
  background-color: var(--nv-soft);
}

/* 行动按钮：空态不该是"死胡同"，给一条明确的下一步 */
.nv-empty__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: var(--nv-space-3);
  padding: 10px var(--nv-space-5);
  border-radius: var(--nv-radius-pill);
  background-color: var(--nv-brand-solid);
  color: var(--nv-text-on-solid);
  font-size: var(--nv-fs-caption);
  font-weight: var(--nv-weight-medium);
  transition: background-color var(--nv-dur-fast) var(--nv-ease-out),
              transform var(--nv-dur-fast) var(--nv-ease-out);
}
.nv-empty__action:hover {
  background-color: var(--nv-brand-hover);
  transform: translateY(-1px);
}
.nv-empty__action:active { transform: translateY(0); }

.nv-skeleton {
  background: linear-gradient(90deg, var(--nv-soft) 25%, var(--nv-muted) 50%, var(--nv-soft) 75%);
  background-size: 200% 100%;
  animation: nv-shimmer 1.4s ease-in-out infinite;
  border-radius: var(--nv-radius-card);
}
@keyframes nv-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* --------------------------------------------------------------------------
   15. 富文本 · RichHtml（核心自带 .acg-rich 样式，此处补品牌色调）
   -------------------------------------------------------------------------- */
.nv-rich { color: var(--nv-text-primary); }
.nv-rich :where(h1, h2, h3, h4) {
  font-weight: var(--nv-weight-bold);
  letter-spacing: var(--nv-ls-heading);
}
.nv-rich :where(a) { color: var(--nv-brand-ink); }
.nv-rich :where(blockquote) {
  border-left: 3px solid var(--nv-brand);
  background-color: var(--nv-brand-softer);
  color: var(--nv-text-secondary);
}
.nv-rich :where(th) { background-color: var(--nv-soft); }

/* ★★ 富文本图片必须约束宽度（2026-10-14 修）：
   原来只设了 border-radius，没设 max-width ——
   商品描述里的图（如 600×360 或更大）会按【原始尺寸】渲染，
   详情区被撑得极长、横向还可能溢出。
   这里统一：宽度不超容器、高度自适应、块级居中，并给一点上下留白。 */
.nv-rich :where(img) {
  display: block;
  max-width: 100%;
  height: auto;
  margin-inline: auto;
  border-radius: var(--nv-radius-card);
}
/* 图片之间、以及图片与文字之间留一档呼吸空间 */
.nv-rich :where(p:has(> img)) { margin-block: var(--nv-space-4); }
.nv-rich :where(video, iframe) {
  display: block;
  max-width: 100%;
  margin-inline: auto;
  border: 0;
  border-radius: var(--nv-radius-card);
}
/* 代码块/长表格在窄容器里可横向滚动，避免撑破卡片 */
.nv-rich :where(pre, table) {
  max-width: 100%;
  overflow-x: auto;
}
/* 长英文串/URL 不撑破卡片 */
.nv-rich { overflow-wrap: anywhere; }

/* --------------------------------------------------------------------------
   16. 工具类
   -------------------------------------------------------------------------- */
.nv-flex { display: flex; }
.nv-items-center { align-items: center; }
.nv-justify-between { justify-content: space-between; }
.nv-gap-1 { gap: var(--nv-space-1); }
.nv-gap-2 { gap: var(--nv-space-2); }
.nv-gap-3 { gap: var(--nv-space-3); }
.nv-gap-4 { gap: var(--nv-space-4); }
.nv-hidden { display: none !important; }
/* ★ 条件类的「显示」分支：与 .nv-hidden 配对使用。
   条件类写成 class="#{if 条件}nv-hidden#{else}nv-inline#{/if}" 时，
   false 分支需要一个明确的"显示"类 —— 既保持语义对称，
   也避免留下空的 class="" 属性。这些元素都是行内链接，故用 inline。 */
.nv-inline { display: inline !important; }
/* 表单字段的显示分支。
   ★★ 这里【绝对不能】加 !important —— 加了会让「条件隐藏」失效。
     原因：.nv-block 这个名字被两处复用了：
       ① 条件工具类：Authentication/Register.html 里
          `class="nv-field #{if 条件}nv-block#{else}nv-hidden#{/if}"`
       ② 表单字段包裹：Index/Item.html 里大量 `<div class="nv-block">`
     而 Item.html 的「人机验证」块是靠【内联 style】做条件显隐的：
          <div class="nv-block" style="display:#{if $item.trade_captcha == 1}block#{else}none#{/if}">
     内联样式只能被「!important 的样式表规则」压过 ——
     一旦这里写了 !important，(系统设置里关掉的) 验证码就会被强行显示出来。
     （2026-10-16 实测：trade_verification=0 时该块 computed display 仍为 block。）
   ★ 去掉 !important 后仍然安全：Register.html 的 5 处用法都同时带 .nv-field，
      而 .nv-field 自己就有 display:block，无需 .nv-block 兜底；
      隐藏分支的 .nv-hidden 自带 !important，优先级依旧最高。 */
.nv-block { display: block; }
.nv-mt-2 { margin-top: var(--nv-space-2); }
.nv-mt-4 { margin-top: var(--nv-space-4); }
.nv-mt-6 { margin-top: var(--nv-space-6); }
.nv-mb-2 { margin-bottom: var(--nv-space-2); }
.nv-mb-4 { margin-bottom: var(--nv-space-4); }
.nv-mb-6 { margin-bottom: var(--nv-space-6); }
.nv-text-center { text-align: center; }

/* 打印时去掉所有装饰 */
@media print {
  .nv-header, .nv-drawer, .nv-drawer__shade, .nv-footer, .nv-burger { display: none !important; }
  body { background: #fff; }
}
/* --------------------------------------------------------------------------
   nv-hidden —— 条件显隐的唯一手段
   --------------------------------------------------------------------------
   ★ 为什么不用 #{if} 包裹元素：
     本项目 Smarty 分隔符是 #{ 和 }，#{if} 作为独立文本节点会编译失败
     （整页 HTTP 200 但响应体 0 字节，无任何报错）。
     可行写法只有一种：把条件写进 HTML 属性值，用 class 切换显隐。
     所以「已登录 / 未登录」这类分支一律拆成两个带 class 的兄弟元素。

   用 !important 是因为它要能压过 .nv-flex / .nv-drop 等 display 声明。
   -------------------------------------------------------------------------- */
.nv-hidden { display: none !important; }

/* --------------------------------------------------------------------------
   13. 页头用户区 · 条件显隐容器
   --------------------------------------------------------------------------
   ★ 本项目 Smarty 分隔符是 #{ 和 }，条件标签作为独立文本节点会编译失败
     （整页 HTTP 200 但响应体 0 字节，无任何报错）。
     所以「已登录 / 未登录」不能写成 `#{if $user}...#{else}...{/if}`，
     而是拆成两个带 class 的兄弟节点，由核心 PHP 侧判断加 nv-hidden。
   -------------------------------------------------------------------------- */
.nv-user-block,
.nv-guest-block {
  display: flex;
  align-items: center;
  gap: var(--nv-space-2);
}

/* 下拉菜单里的分隔线 */
.nv-drop__sep {
  height: 1px;
  margin: var(--nv-space-1) 0;
  background-color: var(--nv-border-soft);
}

/* 用户菜单按钮（2026-10-16 改）
   ★★ 原来是 `padding: 0; overflow: hidden;` —— 那是「整个按钮就是一张圆形头像」的写法。
      现在按钮里还有「用户中心」文字，padding 必须交回 header.css 控制，
      overflow 也不能 hidden（否则聚焦环/描边会被裁掉）。
   ★ 头像本身仍是 24px 圆形，由下面这条负责。 */
.nv-user-btn img {
  display: block;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
}

/* 下拉菜单里的用户名（不可点） */
.nv-user-name {
  font-size: var(--nv-fs-caption);
  color: var(--nv-text-primary);
}

/* ══════════════════════════════════════════════════════════════════════════
   15. 图标规范 · 尺寸三档
   --------------------------------------------------------------------------
   ★★ 为什么需要：
     实测首页有 10 种不同的图标字号在同时使用
     （11 / 12 / 14 / 15 / 16 / 18 / 19 / 20 / 22 / 24px）。
     每个图标各自为政，整体就显得"草"，这正是与 Nuxt 4.3 气质差异的主因之一
     —— Nuxt 用 lucide，全局固定 16 / 20 / 24 三档（其组件里只有 w-4/w-5/w-6）。

   ★ 规范（对 Material Icons 与 Font Awesome 同时生效）：
       --nv-icon-sm  16px  正文内联、徽章、按钮内
       --nv-icon-md  20px  区块标题、导航项、表格操作
       --nv-icon-lg  24px  空态、大按钮、装饰性强调

   ★ 为什么不换图标库：
     改图标库要动 90+ 处调用点，收益（更贴 lucide）远小于风险（漏改/错改）。
     统一【尺寸与颜色】，气质就能接近；字形差异在日常使用中几乎无感。

   ★ 颜色一律继承 currentColor —— 禁止硬编码色值，
     这样深色模式与品牌换色都能自动跟随。
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  --nv-icon-sm: 16px;
  --nv-icon-md: 20px;
  --nv-icon-lg: 24px;
}

/* ★ 只做【兜底】与【上限约束】，不强行覆盖已有的精确设定 ——
   很多地方（如面包屑 14px、侧栏 19px）是配合特定排版调过的，
   一刀切会把它们改坏。这里只把"超出规范范围"的值收回来。 */

/* Material Icons：默认 24px，在正文/按钮里偏大。
   限定最大不超过规范的最大档，避免撑破行高。 */
.nv-badge .material-icons-outlined,
.nv-btn .material-icons-outlined,
.nv-label .material-icons-outlined {
  font-size: var(--nv-icon-sm);
}

/* Font Awesome 图标：与相邻文字对齐，不撑行高 */
.fa-duotone, .fa-regular, .fa-solid {
  line-height: 1;
  vertical-align: -0.125em;   /* 视觉上与文字基线上移一点，看着更居中 */
}

/* 图标默认继承文字色；仅在需要"弱化"时显式降级 */
.nv-icon--muted { color: var(--nv-text-muted); }
.nv-icon--faint { color: var(--nv-text-faint); }
