/* ═══════════════════════════════════════════════════════════════════
   雅思教练 · 排版系统（Typography）
   ───────────────────────────────────────────────────────────────────
   审计（2026-10-28）发现的问题：
     · 字号声明 367 处、**30 种不同字号** —— 6px / 7px / 8.5px 根本不可读
     · 实际渲染 16 种字号（9.44px 起步）
     · 字体栈有 3 套不同声明，其中一套引用了**并不存在**的 'Inter Tight'
     · 行高/字号比只有 1.6 / 1.68 两档 —— **中文正文偏挤**
       （中文方块字需要 1.75–1.8 才不粘连）
     · 数字没有等宽处理 —— 表格里的数字会跳字
     · 中英混排没有间隙控制 —— 中英相邻处视觉粘连

   这一层确立三条规则：
     ① **字号只有 9 级**（--fs-1 … --fs-9），全部走令牌
     ② 中英分开设字体栈：拉丁用系统 UI 字体，中文用 PingFang/YaHei，
        并开 `font-synthesis: none` 防止浏览器伪加粗伪斜体
     ③ 数字用 `font-variant-numeric: tabular-nums`，
        并给中英交界处加 1/8 em 的视觉间隙

   加载顺序：在 theme.css / layout.css / skins.css **之后** —— 覆盖式生效。
   ═══════════════════════════════════════════════════════════════════ */

/* ═══════════ 1. 字体栈 ═══════════ */
:root {
  /* 拉丁字体 —— 系统 UI 字体栈，macOS 上是 SF Pro。
     不加载外部字体：会挂住文档加载，且 macOS 自带 SF 的质量已足够。
     注意：这里**不放** 'Inter Tight' / 'Inter' —— 它们不在系统里，
     写了等于给出一个永远命中不了的回退。 */
  --font-latin: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;

  /* 中文字体 —— 独立栈。
     PingFang SC（macOS 中文默认，字重齐全、字面稳定）
     → Hiragino Sans GB（老 macOS）
     → Microsoft YaHei（Windows）
     → Noto Sans CJK SC（Linux）
     最后兜底 sans-serif，让浏览器自己挑系统中文。 */
  --font-cjk: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
    "Noto Sans CJK SC", "Source Han Sans SC", sans-serif;

  /* 等宽 —— 只给代码/编号/时间戳用。
     中文等宽用「PingFang SC」补位，否则数字与汉字基线不齐。 */
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", "PingFang SC", monospace;

  /* 组合栈 —— 正文用。
     关键：拉丁在前、中文在后。浏览器逐字符 fallback，
     汉字会自动落到 PingFang SC，英文/数字留在 SF。
     这样中英各用自己的最优字体，而不是「一个字体硬扛两种文字」。 */
  --font-body: var(--font-latin), var(--font-cjk);
  --font-display: var(--font-latin), var(--font-cjk);
}

/* ═══════════ 2. 字号阶梯（9 级）═══════════ */
/*  9.5 / 10.5 / 11.5 / 12.5 / 13.5 / 15 / 17 / 21 / 28
    分档依据：
      ①②③  标签 / 元信息 / 徽章（9.5–11.5）—— 只在 1440 以上出现，
             因为 --u 在大屏上会放大；小屏会自动收窄
      ④⑤   小正文 / 辅助正文（12.5–13.5）—— 内容区主力
      ⑥⑦   卡片标题 / 区块标题（15–17）
      ⑧    视图标题（21）
      ⑨    页面大标题（28）
    旧的 9 / 10 / 11 / 12 / 13 / 14 / 22 / 27 / 38 / 50 全部归并到这 9 级。 */
:root {
  --fs-1: calc(9.5 * var(--u));    /* 徽章 / 元信息下限 */
  --fs-2: calc(10.5 * var(--u));   /* 小标签 / 时间戳 */
  --fs-3: calc(11.5 * var(--u));   /* 辅助正文 / 卡片副文 */
  --fs-4: calc(12.5 * var(--u));   /* 正文小 */
  --fs-5: calc(13.5 * var(--u));   /* 正文标准 */
  --fs-6: calc(15 * var(--u));     /* 卡片标题 */
  --fs-7: calc(17 * var(--u));     /* 区块标题 */
  --fs-8: calc(21 * var(--u));     /* 视图标题 */
  --fs-9: calc(28 * var(--u));     /* 页面大标题 */

  /* 行高 —— 中文专用值。
     中文是方块字，视觉高度比拉丁字母大，同一 line-height 下会显得更挤。
     拉丁正文 1.5 舒服，中文正文 1.75 才不粘连。
     这里按用途给三档，不一刀切。 */
  --lh-tight: 1.35;    /* 单行文本：标签、数字、徽章 */
  --lh-snug:  1.55;    /* 短句：列表项标题 */
  --lh-body:  1.78;    /* 正文段落：中文长文 */
  --lh-loose: 1.95;    /* 大标题 */
}

/* ═══════════ 3. 根元素应用 ═══════════ */
body {
  font-family: var(--font-body);
  font-size: var(--fs-5);
  line-height: var(--lh-body);
  font-feature-settings: "kern" 1, "liga" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* 关键：关闭字体合成。
     浏览器在缺少粗体/斜体字重时会「伪加粗」「伪倾斜」——
     对中文尤其难看（笔画糊成一团）。关掉后，缺字重就正常回退。 */
  font-synthesis: none;
  text-rendering: optimizeLegibility;
}

/* ═══════════ 4. 数字等宽化 ═══════════ */
/* 表格、统计、KPI 里的数字必须等宽，否则换行时列会跳。
   tabular-nums 让所有数字占同宽 —— 这是数据可读性的底线。 */
.kpi-v, .vh-mv, .g-stat .v, .sp-amt, .sp-fs .v, .fd-score-cell span,
.fd-score2-r span, .fd-band-b, .fd-time-t, .fd-comp-b6 b, .fd-comp-b7 b,
.g-fac b, .fd-must-x, .p-ev, .kpi-chart-v, .kpi-chart-k,
.kpi-cell .v, .sp-dt, .fd-spec-l, .fd-step-n, .fd-order-n,
.tb-name, .fd-level-n span, .rail-item .rc {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "kern" 1;
}

/* 大数字额外加一点字距补偿 —— 表格数字等宽后视觉会偏松 */
.kpi-v, .vh-mv, .g-stat .v, .sp-dt {
  letter-spacing: calc(-.4 * var(--u));
}

/* ═══════════ 5. 中英混排间隙 ═══════════ */
/* 中文与拉丁字母相邻时，浏览器不做任何间距补偿 —— 视觉上会粘连。
   办法：在中文标点/汉字后紧跟拉丁或数字时，加一个极小的间隙。
   用 :lang() + 伪元素做不了（需要知道下一字符），所以改用
   「中文段落里的英文/数字包一层」的办法 —— 见下方 .mix。 */

/* 常见做法：给中文段落里的西文片段加左右间距。
   通过 text-autospace（新版 Chrome 支持）自动处理更优雅，
   但兼容性不足，所以同时提供手动方案。 */
@supports (text-autospace: normal) {
  body { text-autospace: normal; }
}

/* 手动方案：西文/数字紧跟中文时，用 letter-spacing 无法精确控制，
   改用 word-spacing —— 给中英交界处的空格加宽。 */
.zh-en {
  word-spacing: calc(.12 * var(--u));
}

/* ═══════════ 6. 标题排版 ═══════════ */
/* 中文标题不需要西文那样紧的字距（negative tracking 会让汉字挤）。
   所以 display 级别的标题 letter-spacing 只在 0 ~ -0.3 之间。 */
.pg-title, .vh-title, .g-card h3, .fd-dim-n, .fd-level-n,
.fd-card-t, .fd-scard-t, .fd-part-n, .fd-comp-d {
  letter-spacing: calc(-.2 * var(--u));
  line-height: var(--lh-loose);
  /* 中文标题的字面率比西文高，字重可以稍轻一点显得精致 */
  font-weight: 800;
}

/* 英文小标签（eyebrow）—— 全大写 + 宽字距是西文惯例，
   但中文全大写无意义，所以只对纯英文标签用。 */
.vh-eyebrow, .fd-block-l, .fd-mistake-p, .fd-dim-r b, .fd-fam-w b,
.fd-level-exit b, .fd-comp-b6 b, .fd-comp-b7 b, .fd-diag-r b {
  letter-spacing: calc(.9 * var(--u));
  text-transform: uppercase;
}

/* 中文语境下的这类标签应该保留字形（不转大写），只保留字距 */
.fd-block-l, .fd-mistake-p, .fd-dim-r b, .fd-fam-w b, .fd-fam-f b,
.fd-level-exit b, .fd-diag-r b, .fd-comp-x b {
  text-transform: none;
  letter-spacing: calc(.4 * var(--u));
}

/* ═══════════ 7. 代码与编号 ═══════════ */
code, kbd, .mono, .p-ev, .fd-dim-band, .fd-step-t span,
.kpi-chart-k, .kpi-chart-v, .fd-vg-w {
  font-family: var(--font-mono);
}

/* ═══════════ 8. 逐级字号迁移 ═══════════
   把散落的字号声明统一到 9 级令牌。
   用 CSS 覆盖而不是逐个改源文件 —— 改动面小、可回滚、探针可验证。
   ═══════════ */

/* ── 徽章与元信息 ── */
.p-tag { font-size: var(--fs-2); }
.g-tag { font-size: var(--fs-1); }
.p-ev { font-size: var(--fs-1); }
.fd-dim-map, .fd-kpi-l, .kpi-l, .kpi-sub, .kpi-chart-k, .kpi-chart-v,
.fd-fam-t, .fd-mistake-p, .fd-diag-r b, .fd-dim-r b, .fd-fam-w b, .fd-fam-f b,
.fd-scard-q, .fd-qt-c, .fd-qt-d, .fd-scard-d, .fd-part-t, .fd-fam-m span,
.fd-core-w, .fd-alloc-e, .fd-gap, .fd-sc-d, .fd-sc-q, .fd-core-e { font-size: var(--fs-1); }
.fd-must-l, .fd-must-s em, .fd-core-n em, .fd-subc-n em, .fd-dim-n em,
.fd-tab em, .fd-dim-band, .fd-level-exit b, .fd-resc-h .p-ev { font-size: var(--fs-2); }

/* ── 小标签 ── */
.rr-q, .rr-what, .rr-verify, .rr-reason, .g-lbl .hint, .fd-evi,
.fd-note, .fd-caution, .fd-rule, .fd-why, .fd-risk-d, .fd-risk-f,
.fd-vg-w, .fd-qt-re, .fd-spec-w, .fd-spec-u, .fd-resc-t,
.fd-move-e, .fd-move-bad, .fd-trap-d, .fd-trap-f, .fd-core-d, .fd-core-e,
.fd-subc-d, .fd-subc-h, .fd-diag-h, .fd-alloc-d, .fd-alloc-r,
.fd-strat, .fd-scard-nat, .fd-qt-why, .fd-check, .fd-part-d,
.fd-family-m span, .fd-fam-m span, .fd-vg-words, .fd-spec-e { font-size: var(--fs-2); }

/* ── 辅助正文 ── */
.fd-dim-q, .fd-dim-r, .fd-must-e, .fd-risk-p, .fd-bp-d, .fd-time-d,
.fd-must-x, .fd-mistake-d, .fd-mistake-f, .fd-trap-t, .fd-qt-rd,
.fd-scard-why, .fd-level-d, .fd-fam-w, .fd-fam-f, .fd-card-d,
.fd-move-d, .fd-step-d, .fd-level-exit, .fd-dim-q, .fd-scard-strat .fd-strat,
.rr-q, .rr-what, .rr-verify, .rr-reason, .rr-cgoal, .rr-cname,
.ex-bc, .ex-scn, .ex-oh, .ex-on, .ex-mk, .ex-ul, .ex-cb, .ex-cs { font-size: var(--fs-3); }

/* ── 正文 ── */
.fd-lede, .fd-keyline, .fd-correct, .fd-step-t, .fd-diag-n, .fd-score2-note,
.fd-comp-b6, .fd-comp-b7, .fd-comp-x, .fd-scard-n, .fd-band-d, .fd-band-a,
.fd-bp-n, .fd-time-t, .fd-spec-l, .fd-qt-n, .fd-qt-rule, .fd-must-s,
.fd-dim-n, .fd-diag-c, .fd-mistake-m, .fd-trap-t, .fd-fam-n,
.fd-scard-t, .fd-part-n, .fd-qt-rn, .fd-diag-h, .fd-must-row .fd-must-e,
.vh-lede, .g-card .sub, .g-block .bc, .lay-read p, .sb-goal,
.rr-q, .rr-head, .rr-v, .rr-h { font-size: var(--fs-4); }

/* ── 卡片标题 ── */
.fd-dim-n, .fd-level-n, .fd-card-t, .fd-sec-h, .fd-fam-n, .fd-qt-n,
.fd-part-n, .fd-diag-n, .fd-score2-h, .fd-resc-h, .fd-spec-l,
.fd-band-b, .fd-bp-n, .fd-time-t, .fd-comp-d, .fd-mistake-m,
.fd-scard-n, .fd-core-n, .fd-subc-n, .fd-must-s, .fd-diag-h { font-size: var(--fs-5); }

/* ── 区块标题 ── */
.fd-sec-h, .fd-scard-t, .fd-part-n, .fd-score2-h { font-size: var(--fs-6); }

/* ── 视图标题 ── */
.vh-title { font-size: var(--fs-8); }

/* ── 页面大标题 ── */
.pg-title { font-size: var(--fs-9); }

/* ═══════════ 9. 全局行高归一 ═══════════ */
/* 原来行高散落在各处（1.5 / 1.62 / 1.65 / 1.68 / 1.7 / 1.75 / 1.8），
   同一类元素在不同页面行高不同 —— 这是「看起来不专业」的主因之一。
   统一：短文本用 --lh-tight，正文用 --lh-body。 */
.g-card .sub, .g-block .bc, .vh-lede, .lay-read p { line-height: var(--lh-body); }
.g-card h3, .fd-sec-h, .fd-card-t { line-height: var(--lh-snug); }
.p-tag, .g-tag, .p-ev, .fd-must-l, .kpi-l, .kpi-sub,
.fd-must-s, .fd-diag-r b, .fd-block-l { line-height: var(--lh-tight); }
.kpi-v, .vh-mv, .g-stat .v, .sp-dt, .fd-level-id { line-height: var(--lh-tight); }

/* ═══════════ 10. 图标尺寸归一 ═══════════ */
/* 审计发现图标渲染尺寸有 11 种（12 → 44.4px）。收敛到 4 档：
     xs 12  辅助图标（g-f 内、页签内）
     sm 14  按钮内
     md 17  导航 / 常规
     lg 22  空状态 / 大图标 */
.tb-ibtn svg, .rail-item .ri svg { width: calc(17 * var(--u)); height: calc(17 * var(--u)); }
.g-f svg, .fs-pill svg { width: calc(12 * var(--u)); height: calc(12 * var(--u)); }
.g-btn svg, .sp-ib svg { width: calc(14 * var(--u)); height: calc(14 * var(--u)); }
.g-empty svg { width: calc(22 * var(--u)); height: calc(22 * var(--u)); }
.tb-mark { width: calc(22 * var(--u)); height: calc(22 * var(--u)); }
/* 侧栏图标比通用按钮略大 —— 折叠态全靠图形认路，必须够醒目 */
.rail-item .ri { width: calc(20 * var(--u)); height: calc(20 * var(--u)); }
.rail-item .ri svg { width: 100%; height: 100%; }
.rail-logo { width: calc(38 * var(--u)); height: calc(38 * var(--u)); }
.rail:not(.open) .rail-logo { width: calc(26 * var(--u)); height: calc(26 * var(--u)); }
.rail.open .rail-top .rail-logo { width: calc(26 * var(--u)); height: calc(26 * var(--u)); }

/* ═══════════ 11. 文本溢出与折行 ═══════════ */
/* 中文没有词边界，长英文单词会撑破容器。
   overflow-wrap 让长词在必要时断开；word-break: break-all 会破坏英文，
   所以只对中文段落用 line-break: strict（中日韩标点禁则）。 */
.g-card, .fd-card, .g-item, .fd-dim, .kpi, .sp-detail, .sp-list,
.fd-scard, .fd-qt, .fd-part, .fd-core-c, .fd-subc, .fd-resc, .fd-diag-c {
  overflow-wrap: break-word;
  line-break: strict;
}

/* 英文内容允许连字，但不要在窄容器里强制断词 */
.en, .qp, .ofc-text, .ex-sen { word-break: normal; overflow-wrap: break-word; }

/* ═══════════ 12. 文本渲染细节 ═══════════ */
/* 数字与单位之间加极细空格（中文排版惯例）：
   「77 道」而不是「77道」—— 但只对已存在的空格生效，
   这里用 letter-spacing 无法实现，故跳过。 */

/* 表头/标签的中文不做 uppercase 变形（汉字无大小写），
   但要保证字距不塌 */
th, .g-tbl th, .fd-must-s, .g-lbl {
  font-variant-east-asian: normal;
  letter-spacing: calc(.3 * var(--u));
}

/* ═══════════ 13. 浅色主题的字体微调 ═══════════ */
/* 浅色底上细字重会发虚 —— 深色主题可以用 400，浅色需要 450+ */
[data-theme="light"] body { font-weight: 450; }
[data-theme="light"] .fd-note,
[data-theme="light"] .fd-dim-r,
[data-theme="light"] .g-block .bc { font-weight: 450; }

/* ═══════════ 14. 打印 ═══════════ */
@media print {
  body { font-size: 10.5pt; line-height: var(--lh-body); }
  .kpi-v, .vh-mv, .g-stat .v { font-size: 16pt; }
}

/* ═══════════ 15. 补齐迁移（第二轮）═══════════
   第一轮覆盖后仍有 16 档。逐项归并：
   · 10px    → fs-2（small / av / cnt / sp-chain-n）
   · 11.1px  → fs-2（rr-badge / rr-cen / rr-vh）
   · 12.2px  → fs-3（fs-lbl / bh / th）
   · 12.8px  → fs-4（tb-avatar / kpi-cta / fs-pill / float-segi）
   · 13.3px  → fs-4（tb-segi / sb-no / g-btn）
   · 14.4px  → fs-5（sb-nm）
   · 16.7px  → fs-6（.bn）
   · 18.9px  → fs-6（.kpi-v 窄卡）
   ════════════════════════════════════════════════════════════════ */
small, .cnt, .av, .sp-chain-n, .rr-badge, .rr-cen, .rr-vh,
.rail-sec, .rc, .rf-t, .bs, .sl-item, .sl-v {
  font-size: var(--fs-2);
}
.fs-lbl, .bh, .th, .g-tbl th, .sp-dl, .sp-dc-s, .k, .sp-dc-av {
  font-size: var(--fs-3);
}
.tb-avatar, .kpi-cta, .fs-pill, .float-segi, .float-segi.on,
.tb-segi, .tb-segi.on, .sb-no, .g-btn.sm, .g-btn.accent.sm,
.g-btn.ghost.sm, .kpi-sub, .kpi-l, .fd-tab {
  font-size: var(--fs-4);
}
.sb-nm, .rl, .tb-name, .sp-dc-n {
  font-size: var(--fs-4);
}
.bn, .g-card h3, .sp-list-h {
  font-size: var(--fs-6);
}

/* KPI 数字分级 —— 大数字（宽卡）/ 中数字（窄卡）/ 小数字（内嵌）
   这三档是语义差异，保留但明确化 */
.kpi-3 .kpi-v { font-size: var(--fs-7); }
.kpi:not(.kpi-3) > .kpi-v { font-size: var(--fs-8); }
.kpi > .kpi-v { font-size: var(--fs-9); }
.kpi-cell .v { font-size: var(--fs-4); }
.donut-v { font-size: var(--fs-8); }
.sp-dt { font-size: var(--fs-8); }
.sp-fs .v { font-size: var(--fs-6); }
.vh-mv { font-size: var(--fs-8); }
.g-stat .v { font-size: var(--fs-8); }

/* 侧栏品牌区 */
.rail-brand .bn { font-size: var(--fs-6); }
.rail-brand .bs { font-size: var(--fs-2); }

/* 视图页头 —— 大标题 */
.vh-title { font-size: var(--fs-8); line-height: var(--lh-snug); }
.pg-title { font-size: var(--fs-9); line-height: var(--lh-snug); }

/* 正文字号统一 */
.g-card .sub, .g-block .bc, .vh-lede { font-size: var(--fs-4); }
.fd-lede, .fd-keyline, .fd-correct { font-size: var(--fs-5); }


/* ═══════════ 16. 字号下限保护（全局，不限视口）═══════════
   实测问题：--u = min(100vw/1440, 100dvh/900)
     · 1600px → --u = 1.11，字号正常
     · 1440px → --u = 1.00，--fs-1 渲染 9.5px（临界）
     · 1280px → --u = 0.89，--fs-1 渲染 **8.4px**（不可读）
   也就是说「辅助文字」在 1440 以下全部跌进不可读区。

   解法：字号用 `max(绝对下限, 计算值)`。
   视口变小时正文仍可缩小（合理），但辅助文字**不低于可读阈值**。
   这条规则对全站生效，不依赖媒体查询。 */
:root {
  --fs-1: max(9.5px, calc(9.5  * var(--u)));
  --fs-2: max(10px,  calc(10.5 * var(--u)));
  --fs-3: max(10.5px, calc(11.5 * var(--u)));
  --fs-4: max(11px,  calc(12.5 * var(--u)));
  --fs-5: max(12px,  calc(13.5 * var(--u)));
  --fs-6: max(13px,  calc(15   * var(--u)));
  --fs-7: max(14px,  calc(17   * var(--u)));
  --fs-8: max(16px,  calc(21   * var(--u)));
  --fs-9: max(20px,  calc(28   * var(--u)));
}

/* 少数元素原本直接用 calc() 写死了字号，同样要加下限 */
.tb-name small { font-size: max(9.5px, calc(9.5 * var(--u))); }
.rail-brand .bs { font-size: max(9.5px, calc(10.5 * var(--u))); }
.rail-sec { font-size: max(9.5px, calc(9.5 * var(--u))); }
.rail-item .rc { font-size: max(9.5px, calc(9.5 * var(--u))); }
.tb-segi .n { font-size: max(9.5px, calc(9.5 * var(--u))); }
.rr-mini-n { font-size: max(9px, calc(9 * var(--u))); }
.g-f .n { font-size: inherit; }
