/* ============================================================
   说写吧 · 设计系统（浅色主题）
   类名策略：语义化 + 少量工具类。不依赖任何外部 CSS 框架。

   商标（2026-10-12 用户拍板采用 P08「蓝图白线」）：
     · 商标是**固定身份**，配色写死在 SVG 里（见 core/icons.js 的 brandMark()）；
     · 下面的 --wn-* 只服务商标与字标，**不改变界面主题色**（仍是靛蓝 --brand 系）。
       两套并存是刻意的：商标不能随皮肤变，UI 皮肤将来可以换。
   ============================================================ */
:root {
  --bg: #f5f6fa;
  --surface: #ffffff;
  --surface-2: #fafbfd;
  --ink: #171a24;
  --ink-2: #3d4354;
  /* ★ 文字四级阶梯（2026-10-17 第三轮）：ink 17.4 / ink-2 9.9 / muted 5.2 /
     faint 3.7（对白底）。原来是 4.29 / 2.59 —— faint 那档只有 2.59，11.5px
     的元信息（「共 3 篇」「全文 118 词 · 共 4 段」「城市化 · 165 词 · 9 句」）
     铺满全站，读起来是一片糊的灰。用户说的「颜色处理好」有一半在这里：
     **不是把彩色调艳，而是把不该灰的文字调回来**。
     取值约束（两个都测过，别单独改一个）：
       muted ≥ 4.5 对 **brand-soft / warn-soft / good-soft**（chip 里的标签字）
       faint 仍要比 muted 明显浅 -> 保持在 3.6~3.9，别追到 AA 4.5，
             否则元信息和正文标签分不开、层级塌成两档。 */
  --muted: #666d7c;
  --faint: #7e8698;
  --line: #e7e9f0;
  --line-strong: #d6dae6;

  --brand: #4f46e5;
  --brand-2: #6d5ef0;
  --brand-ink: #ffffff;
  --brand-soft: #eef0ff;
  --brand-line: #d5d9ff;
  /* 导航「敞口」里那一层**看得见**的品牌淡彩（--brand-soft 太淡，与白条只差
     4%，用户 2026-10-17 的原话是「底色还是太淡 不够清晰」）。
     只在敞口**闭合端**用，敞口那一侧的前 14px 仍然是 --bg。 */
  --brand-wash: #dde3ff;

  --good: #0f9d76;
  --good-soft: #e6f7f1;
  --warn: #c2751a;
  --warn-soft: #fdf3e3;
  --bad: #d64550;
  --bad-soft: #fdecee;
  --info: #2f7fd4;
  --info-soft: #eaf3fd;
  /* ★ 语义色的**两个用途**，别再混用（2026-10-17 第三轮）：
       --good / --warn / --bad / --info  = 实底、描边、图表、小圆点（大面积或图形）
       --*-text                           = 淡底上的**小字**
     起因：这四个 solid 色本身偏亮，当 11.5px 文字压在自家 -soft 上时对比度只有
     3.1~3.8（AA 要 4.5），而相邻的 --brand 是 5.55 —— 于是「绿色的已完成」
     比「紫色的品牌标签」明显更糊。数值取的是能到 4.8 以上、且已经出现在
     exam-theme.js 里的深色档（gaokao.dark / cet.dark），不是新造的颜色。 */
  --good-text: #0b7a5c;
  --warn-text: #9a5a10;
  --bad-text: #bb3242;
  --info-text: #1f66ad;

  /* --- 顶栏「记灵感」灯光黄实底按钮（2026-10-15：灯光黄 + 💡 + 查词同款框线）---
     与 App 端**逐值相同**（mobile/lib/theme.dart 的 Wl.sparkFill / sparkInk），
     两端是同一颗按钮，不该出现两个色。
     ⚠️⚠️ 「看不看得见」**不能用框线的对比度衡量**：--spark-fill #ffc53d 对顶栏
        #f5f6fa 的**亮度**比只有 **1.46:1**（旧的深琥珀是 4.48:1）。这不是选色失手，
        是黄这个色相的固有属性 —— 要 3:1 就得把黄压成 #a8600c 那种深棕，而那正是
        用户否掉的色。真正让人看见它的是**实底自己的色相**（ΔE76 = 75.4；旧淡奶油
        底只有 11.0 —— 用户报的「太淡」就是那种「又近亮又近色」）。
     ★ 框线 = **查词同款**（`var(--line-strong)`，与 .dict-top-btn 同一个 token）：
        用户 2026-10-15 看过实物后说「不需要圆圈外周的线」，紧接着给了替代方案
        「或者用查词那样的浅蓝的框线」。所以那圈深金 --spark-ring 已**整个删除**
        （不留死变量）—— 框线这件事的正解是**复用查词那个 token**，
        而不是再调一个「更配黄」的色。
        ⚠️ 它**不承担**边界职责（对顶栏仅 1.29:1，与查词那根同量级）；别把它调深，
           调深就是退回被用户否掉的那条轮廓线。
     ⚠️ 字色必须是 --spark-ink（#5b3a00，对黄底 6.49:1）。**白字对黄底只有 1.58:1**，
        第一版的 `color: #fff` 直接搬过来会变成一片看不见的白字。 */
  --spark-fill: #ffc53d;
  --spark-fill-hover: #ffb91f;
  --spark-ink: #5b3a00;

  /* --- P08「蓝图白线」商标调色板（**参考用**；目前只有 --wn-accent-ink 被真正引用）---
     ⚠️ 商标图形本身的颜色**不从这里取**：它由 JS 内联生成、自带 fill
        （见 public/js/core/icons.js 的 brandMark()）。只改下面这几个变量
        不会有任何视觉变化 —— 要改品牌色得去改 brandMark() / logo-mark.svg。
     ⚠️ 这几行刻意保留为「取色参考」，别当成已接线的主题变量。 */
  --wn-paper: #123a63;
  --wn-grid: #4b7cae;
  --wn-bind: #e08b7e;
  --wn-pen: #f4f8fb;
  --wn-accent: #ffb703;
  /* 字标用的琥珀：P08 原色 #FFB703 在白底上对比度仅 ~1.8:1，当正文大小的字标
     读不清；文字场合压深到 #c97c00（≈3.9:1）。**商标图形内部仍用原色**。 */
  --wn-accent-ink: #c97c00;

  --r-sm: 7px;
  --r: 12px;
  --r-lg: 16px;
  --r-xl: 22px;
  --shadow-1: 0 1px 2px rgba(23,26,36,.05), 0 1px 3px rgba(23,26,36,.04);
  --shadow-2: 0 2px 6px rgba(23,26,36,.06), 0 8px 24px rgba(23,26,36,.06);
  --shadow-3: 0 12px 40px rgba(23,26,36,.14);
  --sidebar-w: 232px;
  --maxw: 1180px;
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
          "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  --mono: "SF Mono", ui-monospace, "JetBrains Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  font-size: 14.5px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3, h4 { margin: 0; font-weight: 650; line-height: 1.3; letter-spacing: -.01em; }
h1 { font-size: 25px; }
h2 { font-size: 19px; }
h3 { font-size: 16px; }
h4 { font-size: 14px; }
p { margin: 0 0 10px; }
a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }
button { font-family: inherit; font-size: inherit; }
code, pre, .mono { font-family: var(--mono); }
hr { border: none; border-top: 1px solid var(--line); margin: 18px 0; }
::selection { background: var(--brand-soft); }

/* ---------- 启动占位 ---------- */
.boot { position: fixed; inset: 0; display: grid; place-content: center; justify-items: center; gap: 14px; background: var(--bg); z-index: 999; }
/* 启动图：P08 商标 SVG（不是文字 emoji 了，所以不再靠 font-size 定尺寸，
   尺寸由 svg 上的 width/height 给）。bob 动画保留。 */
.boot-mark { line-height: 1; animation: bob 1.4s ease-in-out infinite; }
.boot-mark > svg { display: block; filter: drop-shadow(0 2px 6px rgba(16, 42, 72, .22)); }
.boot-text { color: var(--muted); font-size: 13.5px; }
@keyframes bob { 0%,100% { transform: translateY(0) } 50% { transform: translateY(-7px) } }

/* ---------- 骨架 ---------- */
#app { display: flex; min-height: 100vh; }
.sidebar {
  width: var(--sidebar-w); flex: 0 0 var(--sidebar-w);
  background: var(--surface); border-right: 1px solid var(--line);
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
  display: flex; flex-direction: column; padding: 16px 12px 14px;
}
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* 底部留白要托住固定底栏（≈62px + 安全区），否则最后一张卡会被底栏压住。 */
.view { padding: 22px 26px 104px; max-width: var(--maxw); width: 100%; margin: 0 auto; flex: 1; }

/* ---------- 线条图标徽标（导航用；对齐 App「我的」页风格）---------- */
/* 柔和色底圆角方块 + 线条 SVG；颜色由 .wl-ic-<accent> 决定，尺寸走行内 style。 */
.wl-ic { display: inline-flex; align-items: center; justify-content: center; border-radius: 9px; flex: none; }
.wl-ic svg { display: block; }
.wl-ic-brand { background: var(--brand-soft); color: var(--brand); }
.wl-ic-good { background: var(--good-soft); color: var(--good-text); }
.wl-ic-warn { background: var(--warn-soft); color: var(--warn-text); }
.wl-ic-info { background: var(--info-soft); color: var(--info-text); }

/* ---------- 品牌 ---------- */
.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 14px; }
/* 商标位：底色 / 圆角 / 阴影全部由 P08 商标 SVG **自带**，这里只当容器 ——
   外层再叠一层靛蓝渐变会和商标的蓝图蓝打架（改前就是这么叠的）。 */
.brand-logo { width: 34px; height: 34px; display: grid; place-items: center; }
.brand-logo > svg { display: block; filter: drop-shadow(0 1px 2px rgba(16, 42, 72, .28)); }
.brand-name { font-weight: 700; font-size: 15px; letter-spacing: -.02em; }
/* 双色字标（P08 lockup 规则：Write 墨色 / Now 强调色） */
.brand-name em { font-style: normal; color: var(--wn-accent-ink); }
.brand-sub { font-size: 11px; color: var(--faint); letter-spacing: .04em; text-transform: uppercase; }
/* 登录页品牌主标题：和 .brand-name 是**同一套字标规则**，只是按 hero 放大。
   ⚠️ 两处必须同步改 —— 渲染同一句话（auth.js 的 h1 与 app.js 的 .brand-name），
   分色靠的是各自作用域里的 `em` 规则，漏改一处就会出现「一边分色一边斜体」。 */
.auth-brand-name { font-size: 26px; font-weight: 800; letter-spacing: -.02em; margin: 0; line-height: 1.15; }
.auth-brand-name em { font-style: normal; color: var(--wn-accent-ink); }

/* ---------- 侧栏导航 ---------- */
.nav-group { margin-bottom: 14px; }
.nav-label { font-size: 11px; font-weight: 650; color: var(--faint); letter-spacing: .07em; text-transform: uppercase; padding: 0 10px 6px; }
.nav-item {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--r-sm);
  color: var(--ink-2); font-weight: 500; cursor: pointer; border: none; background: none;
  width: 100%; text-align: left; transition: background .13s, color .13s;
}
.nav-item:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }
.nav-item.active { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
.nav-icon { font-size: 15px; width: 20px; text-align: center; flex: none; }
.nav-badge { margin-left: auto; background: var(--bad); color: #fff; font-size: 10.5px; font-weight: 700; min-width: 18px; height: 18px; border-radius: 9px; display: grid; place-items: center; padding: 0 5px; }
.nav-spacer { flex: 1; }

/* ---------- 顶栏 ---------- */
/* 左右 padding 跟「居中内容列」对齐：栏本身通铺全宽（背景/描边不断），
   内容却和 .view 的列边对齐（侧栏退场后，两者若不齐会明显错位）。 */
.topbar { position: sticky; top: 0; z-index: 40; background: rgba(255,255,255,.86); backdrop-filter: saturate(180%) blur(12px); border-bottom: 1px solid var(--line); padding: 11px max(26px, calc((100% - var(--maxw)) / 2)); display: flex; align-items: center; gap: 14px; }
.topbar-title { font-weight: 650; font-size: 15.5px; }
.topbar-sub { color: var(--faint); font-size: 12px; }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
/* 顶栏「我的」按钮上的未读角标（2026-10-12 通知入口从顶栏铃铛搬进「我的」）。
   角标挂在按钮右上角，不占额外宽度 —— 顶栏在 400px 下本来就挤。
   pointer-events:none：点角标 = 点「我的」，别让它变成第三个目标。 */
[data-global-me] { position: relative; }
.me-unread {
  position: absolute; top: -1px; right: 1px;
  background: var(--bad); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 1;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  display: grid; place-items: center;
  pointer-events: none;
}

/* 导航壳（2026-10-12 版面统一）：网页端与 App 同版面 —— 三个主入口固定在
   底部（Write / Now / Lab），每个主 tab 内部用吸顶子目录切换。
   左侧栏退场：它的入口全部能在「我的」页与顶栏找到（我的 / 管理后台在顶栏）。 */
.sidebar { display: none; }

/* 底栏在**所有宽度**都显示（不再是手机专属）。宽屏下三个入口居中成一个
   「坞」（.tabbar-inner），避免各自铺满 1/3 屏、图标之间离得太远。 */
.tabbar { position: fixed; bottom: 0; left: 0; right: 0; z-index: 45; background: rgba(255,255,255,.94); backdrop-filter: blur(12px); border-top: 1px solid var(--line); display: flex; justify-content: center; padding: 4px 4px calc(4px + env(safe-area-inset-bottom)); }
.tabbar-inner { display: flex; width: 100%; max-width: 720px; margin: 0 auto; }
/* 底栏按钮（2026-10-12 用户定）：
   选中态要**一直保持**一圈品牌色描边 + 柔和底色 —— 原来只有文字变蓝，
   在手机上几乎看不出「我现在在哪个 tab」。描边用 inset box-shadow 而不是
   border，这样切换时几何尺寸不变（用 border 会让 tab 抖一下）。
   非选中态留同宽的透明描边，保证两者外框完全一致。 */
.tab { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 5px 2px; margin: 2px 1px; border: none; background: none; color: var(--muted); font-size: 10.5px; cursor: pointer; border-radius: var(--r); box-shadow: inset 0 0 0 2px transparent; transition: background .16s, box-shadow .16s, color .16s; }
.tab > span:last-child { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tab:hover { background: var(--surface-2); }
.tab.active { color: var(--brand); background: var(--brand-soft); box-shadow: inset 0 0 0 2px var(--brand); }
.tab-icon { font-size: 18px; }
.tab.active .wl-ic { background: rgba(79,70,229,.18); }

/* 吸顶子目录（Write / Now / Lab 各自的子目录）—— top 由 JS 跟随顶栏高度 */
.subtabs { position: sticky; z-index: 39; display: flex; gap: 6px; padding: 8px max(26px, calc((100% - var(--maxw)) / 2)); background: rgba(255,255,255,.86); backdrop-filter: saturate(180%) blur(12px); border-bottom: 1px solid var(--line); }
.subtabs[hidden] { display: none; }
.subtab { display: flex; align-items: center; gap: 7px; padding: 5px 14px 5px 8px; border-radius: 999px; border: 1px solid var(--line); background: var(--surface); color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer; white-space: nowrap; }
.subtab .tab-icon { font-size: 14px; }
.subtab.active { background: var(--brand-soft); border-color: var(--brand-line); color: var(--brand); }
.subtab.active .wl-ic { background: rgba(79,70,229,.16); }

/* ── 下拉刷新指示器（2026-10-12 #2）───────────────────────────────
   网页版此前没有下拉刷新。指示器固定在视口顶部，随手指位移下滑（transform
   由 JS 给，这里只给静止态）。pointer-events:none —— 它浮在内容上，绝不能
   吃掉点击。 */
#ptr {
  position: fixed; top: 0; left: 50%; z-index: 60;
  display: flex; align-items: center; gap: 7px;
  padding: 7px 13px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-2);
  font-size: 12.5px; font-weight: 600; color: var(--muted);
  pointer-events: none; opacity: 0;
  transform: translate(-50%, -46px);
  transition: opacity .18s, transform .12s;
}
#ptr .ptr-dot {
  width: 13px; height: 13px; border-radius: 50%;
  border: 2px solid var(--brand-line); border-top-color: var(--brand); flex: none;
}
#ptr.ptr-busy .ptr-dot { animation: ptrspin .7s linear infinite; }
@keyframes ptrspin { to { transform: rotate(360deg); } }

/* ── 时事精读 / 重点标注（2026-10-12 #6 #9）──────────────────────
   正文里的重点词可点（加入词库），所以高亮必须有「可点的样子」：
   底色 + 下划虚线，hover 加深。三种类型用三种底色区分，
   与「词 / 短语 / 句型」三种 chip 的配色一致（brand / brand / warn）。 */
.news-sec + .news-sec { margin-top: 18px; padding-top: 16px; border-top: 1px dashed var(--line); }
.news-para { font-size: 15px; line-height: 1.95; color: var(--ink); margin: 0 0 12px; }
.news-para:last-child { margin-bottom: 0; }
.news-para-en { font-size: 15.5px; line-height: 1.9; color: var(--ink-2); }

.hl { border-radius: 4px; padding: 0 2px; cursor: pointer; font-weight: 600; transition: background .15s; }
.hl-vocab { background: rgba(79,70,229,.13); color: var(--brand); box-shadow: inset 0 -2px 0 rgba(79,70,229,.35); }
.hl-phrase { background: rgba(47,127,212,.14); color: var(--info-text); box-shadow: inset 0 -2px 0 rgba(47,127,212,.35); }
.hl-pattern { background: rgba(194,117,26,.16); color: var(--warn-text); box-shadow: inset 0 -2px 0 rgba(194,117,26,.4); }
.hl:hover { background: rgba(79,70,229,.22); }

/* ── 高亮词的悬停操作条（2026-10-13 用户 #6）──────────────────────
   复制 / 查词 / 加入词库 / 记灵感。由 core/hl.js 在 hover（或点击）时
   动态挂到 <body> 上，所以必须 position:fixed —— 素材卡的外层是 overflow
   的滚动容器，就地绝对定位会被裁掉半条。宽度给上限，窄屏不撑破视口。
   （老的那条 .hl-bar「点一下吸在内容底部」已随本次改版退役。）

   ★★ z 阶梯（改这一行之前先把这张表读一遍）：
        39/40/45  吸顶子目录 / 顶栏 / 底栏
        150       .modal-mask（弹层遮罩）
        160       .dict-overlay（查词搜索浮层）
        170       ● 本条 .hl-pop
        200       .toasts（轻提示，永远压住条）
        999       .boot（启动幕布）
   2026-10-13 用户报「通用素材的操作弹窗隐藏在后面了」：条从前是 60，
   **低于弹层遮罩的 150** ⇒ 在「素材弹层阅读」（.modal-mask 里的 .rv-reader）
   里悬停时条被弹层卡盖住半截，实测 elementFromPoint 命中的是弹层里的元素，
   连「复制」按钮的一压都会落到遮罩上（顺带把弹层关掉）。所以提到 170：
   压过所有弹层，但仍低于轻提示 —— toast 是真·最上层反馈，不该被条挡住。 */
.hl-pop {
  position: fixed; z-index: 170;
  max-width: min(420px, calc(100vw - 16px));
  background: var(--surface); border: 1px solid var(--brand-line);
  border-radius: var(--r); box-shadow: var(--shadow-2); padding: 8px 10px;
}
.hl-pop-row { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.hl-pop-row + .hl-pop-row { margin-top: 7px; }
.hl-pop-term { font-size: 13px; }

/* 顶栏里的线条图标按钮（我的 / 管理后台 / 考试切换 / 通知） */
.btn svg { display: block; }
/* 考试切换器。★ `min-width:0` + `.exam-switch-label` 的省略号是**一对**：
   按钮是 inline-flex，flex 项默认 `min-width:auto` ⇒ 不肯被压缩到内容宽度以下，
   加了省略号也截不到。2026-10-17 实测：375 宽下这颗 205px，把 `.topbar-right`
   顶出视口 5px（整页能横向拖），而它的文案来自用户选的考试名，没有上限。 */
.exam-switch { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.exam-switch-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- 卡片 ---------- */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-1); min-width: 0; }
.card-pad { padding: 18px 20px; }
.card-head { display: flex; align-items: center; gap: 10px; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.card-head h3 { flex: 1; }
.card-body { padding: 16px 18px; }
.card-hover { transition: box-shadow .15s, transform .15s, border-color .15s; cursor: pointer; }
.card-hover:hover { box-shadow: var(--shadow-2); transform: translateY(-1px); border-color: var(--line-strong); }

/* ── 个人中心顶部快捷入口（2026-10-12 #4）─────────────────────────
   原先是右栏底部一列纯文字按钮（「形式太单调」），改成 App 同款的
   「柔和色底圆角图标 + 文字」磁贴网格，并整体搬到页面顶部。 */
/* ── 个人中心「重点功能」大磁贴（2026-10-12 问题 3）───────────────
   对齐 App 端强调展示的四格：选择考试 / AI 范文 / 摸摸底 / 真题库。
   比下面的小磁贴更大更醒目（大图标 + 大字 + 副标），一眼可见、一点直达。 */
.me-biggrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.me-big {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 16px 10px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); cursor: pointer; color: inherit;
  transition: border-color .15s, box-shadow .15s, transform .12s;
}
.me-big:hover { border-color: var(--brand-line); box-shadow: var(--shadow-1); transform: translateY(-2px); }
.me-big:active { transform: translateY(0); }
.me-big-t { font-size: 15px; font-weight: 750; color: var(--ink); letter-spacing: -.01em; }
.me-big-s { font-size: 11.5px; color: var(--muted); text-align: center; line-height: 1.3; }

.me-qgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(86px, 1fr)); gap: 10px; }
.me-q {
  position: relative;   /* 给通知磁贴的未读角标当定位锚 */
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 13px 6px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); cursor: pointer; color: inherit;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.me-q:hover { border-color: var(--brand-line); box-shadow: var(--shadow-1); transform: translateY(-1px); }
.me-q:active { transform: translateY(0); }
.me-q-t { font-size: 12px; color: var(--ink-2); text-align: center; line-height: 1.25; }
/* 通知磁贴的未读数（顶栏铃铛搬进「我的」的配套，2026-10-12） */
.me-q-badge {
  position: absolute; top: 6px; right: 6px;
  background: var(--bad); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 1;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  display: grid; place-items: center;
  pointer-events: none;
}
@media (max-width: 640px) {
  .me-biggrid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .me-big { padding: 13px 8px; gap: 6px; }
  .me-big-t { font-size: 14px; }
  .me-qgrid { grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px; }
  .me-q { padding: 11px 4px; gap: 6px; }
  .me-q-t { font-size: 11px; }
}

.grid { display: grid; gap: 14px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
.grid-auto { grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }
.row { display: flex; gap: 10px; align-items: center; }
.row-wrap { flex-wrap: wrap; }
.row-top { align-items: flex-start; }
.col { display: flex; flex-direction: column; gap: 10px; }
.between { justify-content: space-between; }
.center { text-align: center; }
.mt { margin-top: 14px; } .mt-sm { margin-top: 8px; } .mt-lg { margin-top: 24px; }
.mb { margin-bottom: 14px; } .mb-sm { margin-bottom: 8px; } .mb-lg { margin-bottom: 24px; }
.grow { flex: 1; min-width: 0; }
.wrap { flex-wrap: wrap; }

/* ---------- 排版工具 ---------- */
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.small { font-size: 12.5px; }
.xsmall { font-size: 11.5px; }
.big { font-size: 17px; }
.strong { font-weight: 650; }
.semi { font-weight: 600; }
.nowrap { white-space: nowrap; }
.pre-wrap { white-space: pre-wrap; }
.clamp-1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.lead { font-size: 15px; color: var(--ink-2); line-height: 1.7; }
.divider { height: 1px; background: var(--line); margin: 14px 0; }
.eyebrow { font-size: 11.5px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--faint); }

/* ---------- 按钮 ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 15px; border-radius: var(--r-sm); border: 1px solid var(--line-strong);
  background: var(--surface); color: var(--ink); font-weight: 550; cursor: pointer;
  transition: background .13s, border-color .13s, box-shadow .13s, transform .08s; white-space: nowrap;
}
.btn:hover { background: var(--surface-2); border-color: var(--faint); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }
.btn-primary { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); box-shadow: 0 1px 2px rgba(79,70,229,.3); }
.btn-primary:hover { background: #4338ca; border-color: #4338ca; }
.btn-soft { background: var(--brand-soft); border-color: var(--brand-line); color: var(--brand); }
.btn-soft:hover { background: #e4e7ff; }
.btn-danger { color: var(--bad-text); border-color: #f3c9cd; background: var(--bad-soft); }
.btn-danger:hover { background: #fbdde0; }
.btn-ghost { border-color: transparent; background: transparent; color: var(--ink-2); }
.btn-ghost:hover { background: var(--surface-2); }
.btn-sm { padding: 5px 11px; font-size: 12.5px; border-radius: 6px; }
.btn-lg { padding: 11px 22px; font-size: 15px; }
.btn-block { width: 100%; }
.btn-icon { padding: 7px 9px; }

/* ---------- 标签 / 徽章 ---------- */
.chip { display: inline-flex; align-items: center; gap: 5px; padding: 2.5px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 600; background: var(--surface-2); border: 1px solid var(--line); color: var(--ink-2); white-space: nowrap; }
.chip-brand { background: var(--brand-soft); border-color: var(--brand-line); color: var(--brand); }
.chip-good { background: var(--good-soft); border-color: #bde9da; color: var(--good-text); }
.chip-warn { background: var(--warn-soft); border-color: #f3dcb4; color: var(--warn-text); }
.chip-bad { background: var(--bad-soft); border-color: #f4cdd1; color: var(--bad-text); }
.chip-info { background: var(--info-soft); border-color: #c5ddf6; color: var(--info-text); }
.chip-ghost { background: transparent; }
.chip-gold { background: #fdf3d7; border-color: #f0d489; color: #9a6b00; }

/* 收藏星标：金黄 + 放大，一眼能找到 */
.fav-btn { font-size: 19px; line-height: 1; padding: 2px 10px; color: var(--faint); }
.fav-btn.fav-on { color: #eab308; }
.fav-text-on { color: #9a6b00; font-weight: 700; }

/* 分数徽章 */
.band { display: inline-grid; place-items: center; font-weight: 700; font-variant-numeric: tabular-nums; border-radius: 8px; min-width: 38px; padding: 3px 7px; font-size: 14px; letter-spacing: -.02em; }
.band-sm { min-width: 30px; font-size: 12px; padding: 1px 6px; border-radius: 6px; }
.band-lg { min-width: 62px; font-size: 26px; padding: 7px 12px; border-radius: 12px; }
.band-b1 { background: var(--bad-soft); color: var(--bad-text); }
.band-b2 { background: var(--warn-soft); color: var(--warn-text); }
.band-b3 { background: #eef4fb; color: #3f6f9e; }
.band-b4 { background: var(--info-soft); color: var(--info-text); }
.band-b5 { background: var(--good-soft); color: var(--good-text); }
.band-b6 { background: #e3f4ec; color: #06795a; }

/* ---------- 表单 ---------- */
label.field { display: block; margin-bottom: 13px; }
.field-label { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 5px; }
.field-hint { font-size: 11.5px; color: var(--faint); margin-top: 4px; }
.input, .select, .textarea {
  width: 100%; padding: 9px 12px; border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink); font-family: inherit; font-size: 14px;
  transition: border-color .13s, box-shadow .13s;
}
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.textarea { resize: vertical; line-height: 1.7; min-height: 120px; }
.input-lg { padding: 12px 15px; font-size: 15px; }
.select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' stroke='%23737a8c' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 11px center; padding-right: 32px; }
.check { display: flex; gap: 9px; align-items: flex-start; cursor: pointer; }
.check input { margin-top: 4px; accent-color: var(--brand); }
.seg { display: inline-flex; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 2.5px; gap: 2px; }
.seg button { border: none; background: none; padding: 5px 13px; border-radius: 6px; cursor: pointer; color: var(--muted); font-weight: 550; font-size: 13px; }
.seg button.active { background: var(--surface); color: var(--brand); box-shadow: var(--shadow-1); font-weight: 650; }
/* 「我的」页签上的未读数（2026-10-12：通知入口从顶栏搬来，未读提示只剩这里）。
   inline-grid 而不是复用 .nav-badge —— 后者是 display:grid（块级），塞进
   button 的匿名行内盒里会把标签文字和角标**拆成两行**。 */
.tab-badge {
  margin-left: 6px; vertical-align: 1px;
  background: var(--bad); color: #fff;
  font-size: 10.5px; font-weight: 700; line-height: 1;
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: 9px;
  display: inline-grid; place-items: center;
}

/* ---------- 表格 ---------- */
.tbl { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.tbl th { text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--faint); font-weight: 650; padding: 8px 11px; border-bottom: 1px solid var(--line); }
.tbl td { padding: 10px 11px; border-bottom: 1px solid var(--line); vertical-align: top; }
.tbl tr:last-child td { border-bottom: none; }
.tbl tbody tr:hover { background: var(--surface-2); }

/* ---------- 空状态 / 加载 ---------- */
.empty { text-align: center; padding: 46px 20px; color: var(--muted); }
.empty-icon { font-size: 36px; margin-bottom: 10px; opacity: .6; }
.skel { background: linear-gradient(90deg, #eef0f5 25%, #f6f7fb 50%, #eef0f5 75%); background-size: 200% 100%; animation: shim 1.3s infinite; border-radius: 6px; }
@keyframes shim { 0% { background-position: 200% 0 } 100% { background-position: -200% 0 } }
.spinner { width: 17px; height: 17px; border: 2px solid var(--brand-line); border-top-color: var(--brand); border-radius: 50%; animation: spin .7s linear infinite; display: inline-block; }
@keyframes spin { to { transform: rotate(360deg) } }

/* ---------- Toast / Modal ---------- */
.toasts { position: fixed; top: 16px; left: 0; right: 0; z-index: 200; display: flex; flex-direction: column; align-items: center; gap: 9px; max-width: 100%; padding: 0 16px; pointer-events: none; }
.toast { pointer-events: auto; background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--brand); border-radius: var(--r-sm); box-shadow: var(--shadow-3); padding: 11px 15px; font-size: 13.5px; animation: slide-in .2s ease; max-width: 440px; }
.toast-good { border-left-color: var(--good); }
.toast-bad { border-left-color: var(--bad); }
.toast-warn { border-left-color: var(--warn); }
@keyframes slide-in { from { opacity: 0; transform: translateY(-12px) } }
.modal-mask { position: fixed; inset: 0; background: rgba(23,26,36,.42); z-index: 150; display: grid; place-items: center; padding: 20px; animation: fade .15s; }
@keyframes fade { from { opacity: 0 } }
.modal { background: var(--surface); border-radius: var(--r-lg); box-shadow: var(--shadow-3); width: 100%; max-width: 520px; max-height: 88vh; display: flex; flex-direction: column; animation: pop .18s ease; }
.modal-wide { max-width: 760px; }
@keyframes pop { from { opacity: 0; transform: scale(.96) translateY(8px) } }
.modal-head { padding: 17px 20px; border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 10px; }
.modal-body { padding: 18px 20px; overflow-y: auto; }
.modal-foot { padding: 14px 20px; border-top: 1px solid var(--line); display: flex; gap: 9px; justify-content: flex-end; }

/* ---------- 备考考试切换弹层：考试族卡片（app.js openExamSwitcher） ----------
   交互约定（2026-10-07 用户拍板的最终版）：
   · 点族方块空白处 = 只**凸显**（.exam-hl 聚焦态），不选定任何考试；
   · 点族内具体考试 chip = 选定，且先弹确认层。
   exam-cur（当前族，内联主色描边+柔和底）是被动指示；exam-hl 是用户点出来的
   主动聚焦：描边更醒目 + 族色光环 + 微抬 + 提示行，各族互斥、再点一次收起。
   族色从卡片内联的 --fam / --fam-soft 取（exam-theme.js 每族一块）。 */
.exam-family { transition: box-shadow .16s, transform .16s, border-color .16s, background .16s, color .16s; }
.exam-family.exam-hl {
  border-color: var(--fam) !important;
  background: var(--fam-soft) !important;
  box-shadow: inset 0 0 0 1px var(--fam), 0 0 0 4px var(--fam-soft), 0 12px 28px rgba(15, 23, 42, .13);
  transform: translateY(-2px);
}
.exam-family .exam-hl-tip { display: none; margin-top: 10px; font-weight: 600; }
.exam-family.exam-hl .exam-hl-tip { display: block; }

/* ---------- 评分标准弹层/页：多变体考试族顶部的「按具体考试」选择卡片 ----------
   （views/bands.js mountBandsContent）点卡片只切换下方展示的评分标准，
   不写备考目标 —— 与切换器的选定确认是两条路。族色从卡片内联 --fam 取。 */
.band-var-card {
  display: inline-flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 7px 12px; border-radius: 10px; cursor: pointer; text-align: left;
  background: #fff; border: 1.5px solid var(--line);
  transition: border-color .15s, background .15s, box-shadow .15s;
  font: inherit;
}
.band-var-card:hover { border-color: var(--fam, var(--brand)); }
.band-var-card.on {
  border-color: var(--fam, var(--brand));
  background: var(--fam-soft, var(--brand-soft));
  box-shadow: 0 1px 4px rgba(15, 23, 42, .07);
}

/* ---------- 头像 ---------- */
.avatar { width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; background: var(--brand-soft); font-size: 17px; flex: none; border: 1px solid var(--brand-line); }
.avatar-sm { width: 26px; height: 26px; font-size: 13px; }
.avatar-xs { width: 18px; height: 18px; font-size: 10px; flex: none; }
.avatar-lg { width: 56px; height: 56px; font-size: 26px; }
.avatar-mine { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-soft); }

/* ---------- 进度条 ---------- */
.bar { height: 7px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 999px; overflow: hidden; }
.bar > i { display: block; height: 100%; background: linear-gradient(90deg, var(--brand), var(--brand-2)); border-radius: 999px; transition: width .5s ease; }
.bar-good > i { background: linear-gradient(90deg, #12a67c, #2bc79b); }
.bar-warn > i { background: linear-gradient(90deg, #d98c22, #edb154); }

/* ---------- 关键数字 ---------- */
.stat { padding: 15px 17px; }
.stat-v { font-size: 26px; font-weight: 700; letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1.15; }
.stat-l { font-size: 11.5px; color: var(--muted); font-weight: 600; letter-spacing: .03em; margin-top: 3px; }

/* ---------- 提示块 ---------- */
.note { border-radius: var(--r-sm); padding: 11px 14px; font-size: 13px; border: 1px solid var(--line); background: var(--surface-2); color: var(--ink-2); display: flex; gap: 9px; align-items: flex-start; }
.note-info { background: var(--info-soft); border-color: #cfe2f7; color: #20598f; }
.note-warn { background: var(--warn-soft); border-color: #f3dcb4; color: var(--warn-text); }
.note-bad { background: var(--bad-soft); border-color: #f4cdd1; color: #9c2a33; }
.note-good { background: var(--good-soft); border-color: #bde9da; color: #0a6b50; }
.note-icon { flex: none; }

/* ---------- 列表项 ---------- */
.item { padding: 13px 16px; border-bottom: 1px solid var(--line); }
.item:last-child { border-bottom: none; }
.item-click { cursor: pointer; transition: background .12s; }
.item-click:hover { background: var(--surface-2); }

/* ---------- 真题 / 作文卡 ---------- */
.q-card { padding: 16px 18px; display: flex; flex-direction: column; gap: 9px; }
.q-prompt { font-size: 13.8px; line-height: 1.66; color: var(--ink); }
/* 题图（Task 1 图表题）：详情页与写作页共用，宽度自适应、不撑破移动端 */
.q-fig { margin: 10px 0 0; }
.q-img { display: block; max-width: 100%; height: auto; max-height: 420px;
  margin: 0 auto; background: #fff; border: 1px solid var(--line, #e3e7ec);
  border-radius: 8px; padding: 6px; box-sizing: border-box; }
.q-meta { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; }
.q-foot { display: flex; gap: 12px; align-items: center; color: var(--faint); font-size: 11.5px; margin-top: auto; }

/* ---------- 头脑风暴 7 维度 ---------- */
.dim { border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); overflow: hidden; }
.dim-head { display: flex; align-items: center; gap: 9px; padding: 11px 14px; background: var(--surface-2); border-bottom: 1px solid var(--line); }
.dim-head .dim-icon { font-size: 16px; }
.dim-title { font-weight: 650; font-size: 13.5px; }
.dim-hint { font-size: 11.5px; color: var(--faint); }
.dim-count { margin-left: auto; font-size: 11.5px; color: var(--muted); font-weight: 650; }
.dim-body { padding: 10px 14px 13px; }
.dim.done { border-color: #bde9da; }
.dim.done .dim-head { background: var(--good-soft); border-color: #bde9da; }
.bs-item { display: flex; gap: 8px; align-items: flex-start; padding: 6px 0; border-bottom: 1px dashed var(--line); }
.bs-item:last-child { border-bottom: none; }
.bs-item-text { flex: 1; font-size: 13px; }
.bs-child { margin-left: 22px; padding-left: 11px; border-left: 2px solid var(--brand-line); }
.bs-child .bs-item-text { font-size: 12.5px; color: var(--ink-2); }

/* ---------- 头脑风暴思维导图（Xmind 风格） ---------- */
/* 结构：.mm = [根节点][.mm-tree = 列(分支行)]；每个 .mm-row = [节点][.mm-kids = 列(子行)]。
   连接线三段式：主干（父节点右缘 → 中轴线）、中轴（首行到末行）、弧线（中轴 → 子节点）。
   颜色走 --bc / --bc-soft / --bc-bg，由 JS 按分支算好注入，不依赖 color-mix。 */
.mm-card { overflow: auto; }
.mm { display: flex; align-items: center; padding: 24px 28px; min-width: max-content; }
.mm-root {
  flex: none; background: var(--surface); border: 2px solid #454c5c; border-radius: 14px;
  padding: 12px 18px; max-width: 320px; min-width: 170px;
  font-weight: 700; font-size: 14px; line-height: 1.55;
  box-shadow: 0 3px 14px rgba(20, 30, 60, .07);
}
.mm-clamp { display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden; }
.mm-tree, .mm-kids { display: flex; flex-direction: column; padding-left: 32px; position: relative; flex: none; }
/* 主干：父节点右缘 → 中轴 */
.mm-tree::before, .mm-kids::before {
  content: ''; position: absolute; left: 0; top: 50%; width: 16px; height: 2px; margin-top: -1px;
  background: var(--mm-trunk, #c3cad6); border-radius: 1px;
}
.mm-tree > .mm-row, .mm-kids > .mm-row { position: relative; padding: 7px 0; display: flex; align-items: center; }
/* 中轴：贯穿首行到末行（末行截到 50%，弧线从中轴分出） */
.mm-tree > .mm-row::after, .mm-kids > .mm-row::after {
  content: ''; position: absolute; left: -16px; top: 0; bottom: 0; width: 2px;
  background: var(--bc, #c3cad6); opacity: .8;
}
.mm-tree > .mm-row:last-child::after, .mm-kids > .mm-row:last-child::after { bottom: 50%; }
/* 弧线：从中轴拐进子节点左缘中点（圆角边框画弧） */
.mm-tree > .mm-row::before, .mm-kids > .mm-row::before {
  content: ''; position: absolute; left: -16px; top: calc(50% - 14px); width: 16px; height: 15px;
  border-left: 2px solid var(--bc, #c3cad6); border-bottom: 2px solid var(--bc, #c3cad6);
  border-bottom-left-radius: 14px 14px; opacity: .9;
}
.mm-node { flex: none; background: var(--surface); border-radius: 10px; position: relative; }
.mm-head {
  display: flex; align-items: center; gap: 7px; min-width: 128px;
  border: 2px solid var(--bc, var(--line)); padding: 8px 13px;
  font-weight: 700; font-size: 13.5px; cursor: default;
}
.mm-head.done { background: var(--bc-bg, transparent); }
.mm-head .mm-hint { font-size: 11px; color: var(--faint); font-weight: 500; display: block; }
.mm-count { margin-left: auto; font-size: 11px; color: var(--faint); font-weight: 650; padding-left: 8px; white-space: nowrap; }
.mm-leaf {
  border: 1.5px solid var(--bc-soft, var(--line)); padding: 1px 8px;
  display: flex; align-items: center; gap: 4px; max-width: 380px;
}
.mm-leaf:hover { border-color: var(--bc, var(--line-strong)); box-shadow: 0 1px 8px rgba(20,30,60,.06); }
.mm-leaf input {
  border: none; outline: none; background: transparent; font: inherit; font-size: 13px;
  color: var(--ink); width: 200px; min-width: 90px; max-width: 340px; padding: 6px 2px;
  field-sizing: content;
}
.mm-leaf input::placeholder { color: var(--faint); }
.mm-ro { border: 1.5px solid var(--bc-soft, var(--line)); padding: 6px 12px; font-size: 13px; max-width: 360px; }
.mm-ro .xsmall { margin-top: 1px; }
/* 延伸项（核心名词延伸 / 观点延伸 / 例证）：比核心项弱一级 —— 虚线边、更淡、更小，
   让「核心 vs 延伸」一眼可分（诊断报告问题 15）。 */
.mm-row.mm-ext .mm-node.mm-ro {
  border-style: dashed; border-width: 1.5px;
  background: var(--bc-bg, var(--surface-2, #f7f8fa));
  color: var(--muted, #6b7280);
  font-size: 12px; padding: 4px 10px; max-width: 300px;
  box-shadow: none;
}
.mm-row.mm-ext .mm-node.mm-ro .xsmall { color: var(--faint); }
.mm-ghost { border: 1.5px dashed var(--line); color: var(--faint); font-size: 12px; padding: 6px 12px; }
.mm-add { border: 1.5px dashed var(--bc-soft, var(--line)); background: transparent; }
.mm-add:hover { border-style: solid; }
.mm-add .btn { font-size: 12px; padding: 4px 10px; }
.mm-del {
  border: none; background: transparent; cursor: pointer; color: var(--faint);
  font-size: 12px; padding: 2px 4px; opacity: 0; transition: opacity .12s;
}
.mm-row:hover .mm-del { opacity: 1; }
.mm-del:hover { color: var(--bad-text); }
.mm-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; padding: 10px 14px 0; font-size: 11.5px; color: var(--faint); }
.mm-legend span i { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }

/* ---------- 导图缩放平移 ---------- */
/* 挂了 pan/zoom 的容器：滚动交给拖拽，overflow 收掉；transform 原点固定左上 */
.mm-pz-card { overflow: hidden !important; position: relative; cursor: grab; }
.mm-pz-card.panning { cursor: grabbing; user-select: none; }
.mm-pz-card.panning .mm { pointer-events: none; } /* 拖动时别让节点偷鼠标事件 */
.mm-pz-card .mm { transform-origin: 0 0; }
.mm-pz {
  position: absolute; top: 10px; right: 10px; z-index: 5;
  display: flex; align-items: center; gap: 2px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 9px;
  padding: 3px 6px; box-shadow: 0 2px 10px rgba(20, 30, 60, .08);
}
.mm-pz button {
  border: none; background: transparent; cursor: pointer; color: var(--ink-2);
  font-size: 14px; line-height: 1; padding: 4px 7px; border-radius: 6px; font-weight: 700;
}
.mm-pz button:hover { background: var(--surface-2); color: var(--ink); }
.mm-pz-label { font-size: 11px; color: var(--faint); min-width: 34px; text-align: center; font-variant-numeric: tabular-nums; }

/* 写作页右栏迷你导图 / 放大弹层 */
.bs-mini-map { height: 360px; border: none; border-top: 1px solid var(--line); border-radius: 0; }
.bs-modal-map { height: min(66vh, 640px); }
/* 迷你容器里把节点收紧一档：右栏只有 ~280px，节点瘦下来初始适配比例才够看 */
.bs-mini-map .mm { padding: 14px 16px; }
.bs-mini-map .mm-root { max-width: 180px; min-width: 110px; font-size: 12px; padding: 8px 12px; border-radius: 11px; }
.bs-mini-map .mm-tree, .bs-mini-map .mm-kids { padding-left: 20px; }
.bs-mini-map .mm-tree::before, .bs-mini-map .mm-kids::before { width: 12px; }
.bs-mini-map .mm-tree > .mm-row::after, .bs-mini-map .mm-kids > .mm-row::after { left: -12px; }
.bs-mini-map .mm-tree > .mm-row::before, .bs-mini-map .mm-kids > .mm-row::before { left: -12px; width: 12px; }
.bs-mini-map .mm-head { min-width: 88px; padding: 5px 9px; font-size: 12px; }
.bs-mini-map .mm-leaf { max-width: 190px; }
.bs-mini-map .mm-leaf input { width: 110px; min-width: 70px; max-width: 170px; font-size: 12px; }
.bs-mini-map .mm-ro { max-width: 190px; font-size: 12px; padding: 4px 9px; }
.bs-mini-map .mm-ghost { padding: 4px 9px; }

/* 对比列 */
.cmp { display: grid; gap: 0; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; background: var(--surface); }
.cmp-heads { display: grid; }
.cmp-head { padding: 12px 14px; background: var(--surface-2); border-bottom: 1px solid var(--line); border-right: 1px solid var(--line); }
.cmp-head:last-child { border-right: none; }
.cmp-head.mine { background: var(--brand-soft); }
.cmp-row-label { padding: 9px 13px; background: #fbfbfe; border-bottom: 1px solid var(--line); border-right: 1px solid var(--line); font-size: 12px; font-weight: 650; color: var(--ink-2); display: flex; align-items: center; gap: 6px; }
.cmp-cell { padding: 10px 13px; border-bottom: 1px solid var(--line); border-right: 1px solid var(--line); font-size: 12.5px; vertical-align: top; }
.cmp-cell:last-child { border-right: none; }
.cmp-cell.no { color: var(--faint); font-style: italic; }
.cmp-mine { background: rgba(238,240,255,.5); }

/* ---------- 批改报告 ---------- */
.report-hero { background: linear-gradient(135deg, #4f46e5, #7c6bf5); color: #fff; border-radius: var(--r-lg); padding: 26px 28px; display: flex; gap: 26px; align-items: center; flex-wrap: wrap; box-shadow: 0 8px 28px rgba(79,70,229,.24); }
.report-hero .rh-band { font-size: 58px; font-weight: 750; line-height: 1; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
.report-hero .rh-label { opacity: .85; font-size: 12px; text-transform: uppercase; letter-spacing: .1em; font-weight: 650; }
.crit { display: grid; grid-template-columns: 84px 1fr; gap: 12px; padding: 14px 0; border-bottom: 1px solid var(--line); }
.crit:last-child { border-bottom: none; }
.crit-name { font-weight: 650; font-size: 13.5px; }
.crit-en { font-size: 11px; color: var(--faint); font-weight: 500; }
/* 档位边界说明归位到四项里的具体项（2026-10-07 用户要求「分列于四项里」） */
.crit-margin { border-left: 2px solid var(--line); padding-left: 10px; margin-top: 4px; }
/* 引擎判定依据：四项评分卡底部，保持可展开/收缩 */
.crit-basis { border-top: 1px solid var(--line); padding: 12px 16px; }
/* ⚠️ 同上：`--faint-strong` 也不存在（一直在吃兜底 #64748b，一个没进色板的
   孤立十六进制）。统一用 --muted —— 「引擎判定依据」是折叠条，属于次级信息。 */
.crit-basis summary { color: var(--muted); }
.crit-basis[open] summary { margin-bottom: 2px; }
/* ⚠️ 2026-10-17：原来这里是 `color: var(--strong)`，而 `--strong` **从没定义过**
   （全站唯一一处引用）。未定义且无兜底的 var() 在计算期无效 ⇒ color 回落到
   inherit ⇒ 这个「加重」类实际上只是加了字重、颜色跟父级走。名字承诺的加强
   有一半是假的。改成真实存在的 --ink-2。 */
.faint-strong { color: var(--ink-2); font-weight: 650; }
/* 题干分析·建议结构：段落框架 + 句型模版 */
.struc-step { border: 1px solid var(--line); border-radius: var(--r); padding: 10px 12px; background: var(--surface); }
.struc-idx { flex: none; width: 22px; height: 22px; border-radius: 6px; background: var(--brand-soft); color: var(--brand); font-weight: 700; font-size: 12px; display: inline-flex; align-items: center; justify-content: center; }
.struc-tpl { margin: 0 0 2px 26px; font-size: 12.5px; }
.struc-tpl code { background: var(--surface-2); padding: 2px 6px; border-radius: 5px; font-size: 12px; }
/* 范文段落 */
.essay-para { margin: 0 0 12px; line-height: 1.85; font-family: Georgia, 'Songti SC', serif; }
.essay-para:last-child { margin-bottom: 0; }
.diff { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; }
.diff > div { background: var(--surface); padding: 11px 13px; font-size: 12.8px; line-height: 1.62; }
.diff-before { color: var(--bad-text); }
.diff-after { color: var(--good-text); }
/* 词级 diff（可达到版本）：正文黑字，只有被修改的片段标色 —— 原文红 / 修正后绿 */
.wdiff .diff-before { color: inherit; }
.wdiff .diff-after { color: inherit; }
.wdiff .diff-del { color: var(--bad-text); }
.wdiff .diff-add { color: var(--good-text); }
.diff-label { display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; opacity: .65; margin-bottom: 4px; }
mark.err { background: #fdd; color: #a01a26; border-radius: 3px; padding: 0 3px; font-weight: 600; }
mark.fix { background: #d7f5e7; color: #06654a; border-radius: 3px; padding: 0 3px; font-weight: 600; }

/* ---------- 热力图 ---------- */
.heat { display: grid; grid-auto-flow: column; grid-template-rows: repeat(7, 11px); gap: 2.5px; overflow-x: auto; padding-bottom: 5px; max-width: 100%; min-width: 0; }
.heat i { width: 11px; height: 11px; border-radius: 2.5px; background: #eceef4; display: block; }
.heat i.l1 { background: #cfd6f7; } .heat i.l2 { background: #a9b4f0; } .heat i.l3 { background: #7d8ce8; } .heat i.l4 { background: var(--brand); }

/* ---------- 编辑器 ---------- */
.editor-wrap { display: grid; grid-template-columns: 1fr 268px; gap: 18px; align-items: start; }
.editor { min-height: 460px; font-size: 15.5px; line-height: 1.78; padding: 18px 20px; border: 1px solid var(--line-strong); border-radius: var(--r); background: var(--surface); width: 100%; font-family: Georgia, "Songti SC", serif; resize: vertical; }
.editor:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.side-panel { position: sticky; top: 74px; }
.prompt-box { background: var(--brand-soft); border: 1px solid var(--brand-line); border-radius: var(--r); padding: 14px 16px; font-size: 13.5px; line-height: 1.66; }

/* ---------- 老师卡 ---------- */
.t-card { padding: 16px 18px; display: flex; flex-direction: column; gap: 10px; }
.t-head { display: flex; gap: 11px; align-items: flex-start; }
.t-name { font-weight: 650; font-size: 15px; }
.trust-ring { width: 42px; height: 42px; flex: none; position: relative; }
/* data-ring 小环 canvas：属性宽默认 300×150，若未被绘制会撑破 42px 容器 → 横向溢出。
   强制贴合容器（2026-10-09 布局审查） */
.trust-ring canvas { width: 100% !important; height: 100% !important; }
.offer { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 10px 12px; display: flex; gap: 10px; align-items: center; }
.offer:hover { border-color: var(--brand-line); background: var(--brand-soft); }

/* ---------- 时间线 ---------- */
.tl { position: relative; padding-left: 22px; }
.tl::before { content: ''; position: absolute; left: 5px; top: 6px; bottom: 6px; width: 2px; background: var(--line); }
.tl-item { position: relative; padding: 0 0 15px; }
.tl-item::before { content: ''; position: absolute; left: -21px; top: 6px; width: 9px; height: 9px; border-radius: 50%; background: var(--brand); border: 2px solid var(--surface); box-shadow: 0 0 0 1.5px var(--brand-line); }
.tl-item.dim::before { background: var(--line-strong); box-shadow: 0 0 0 1.5px var(--line); }

/* ---------- 排行 ---------- */
.rank-row { display: flex; align-items: center; gap: 11px; padding: 8px 12px; border-radius: var(--r-sm); }
.rank-row.me { background: var(--brand-soft); }
.rank-no { width: 24px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--muted); text-align: center; }
.rank-no.top { color: var(--brand); }

/* ---------- 勋章 ---------- */
.medal { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 12px 8px; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); text-align: center; }
.medal.locked { opacity: .42; filter: grayscale(1); }
.medal-icon { font-size: 25px; }
.medal-name { font-size: 11.5px; font-weight: 650; }

/* ---------- 图表 ---------- */
.chart-wrap { position: relative; width: 100%; }
.chart-wrap canvas { width: 100% !important; display: block; }
.legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 11.5px; color: var(--muted); }
.legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; vertical-align: middle; }

/* ---------- 评论 ---------- */
.cmt { display: flex; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.cmt:last-child { border-bottom: none; }

/* ---------- 首页热力 hero（2026-10-05：通栏置顶，面积拉大） ---------- */
.hero-heat {
  border: 1px solid var(--brand-line);
  background:
    radial-gradient(900px 320px at 88% -30%, rgba(79, 70, 229, .09), transparent 62%),
    radial-gradient(700px 280px at 6% -40%, rgba(15, 157, 118, .08), transparent 60%),
    var(--surface);
  box-shadow: var(--shadow-1);
}
.hero-heat .card-head h3 { font-size: 17px; letter-spacing: .2px; }
.hero-heat .card-head { padding-bottom: 10px; border-bottom: 1px dashed var(--line); }
.heat-dot { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.heat-dot-me { background: var(--brand); }
.heat-dot-site { background: var(--ink-2); opacity: .55; }
.heat-cell { transition: opacity .12s ease; }
.heat-cell:hover { opacity: .86; }

/* ---------- 我的写作：统计块 + 题型模块网格（2026-10-05 视觉重做） ---------- */
.mw-stats {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
}
.mw-stat {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 13px 16px;
  box-shadow: var(--shadow-1);
}
.mw-stat-num { font-size: 24px; font-weight: 760; line-height: 1.15; color: var(--ink); }
.mw-stat.accent .mw-stat-num { color: var(--brand); }
.mw-stat-label { font-size: 11.5px; color: var(--muted); margin-top: 2px; }

.mw-module {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 16px 18px 14px;
  box-shadow: var(--shadow-1);
}
.mw-mod-head { display: flex; align-items: center; gap: 12px; margin-bottom: 13px; }
.mw-mod-head h3 { margin: 0; font-size: 15px; }
.mw-mod-icon {
  width: 38px; height: 38px; border-radius: 11px; flex: none;
  background: var(--brand-soft); border: 1px solid var(--brand-line);
  display: flex; align-items: center; justify-content: center; font-size: 19px;
}
.mw-bar {
  width: 130px; height: 6px; border-radius: 3px; flex: none;
  background: var(--line); overflow: hidden;
}
.mw-bar i {
  display: block; height: 100%; border-radius: 3px;
  background: linear-gradient(90deg, var(--brand), var(--brand-2));
}
.mw-more { margin-top: 12px; }

/* 第一级：左右分栏（左大作文 / 右小作文）+ 雷达图导航 */
.mw-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
}
.mw-panel { padding: 14px 16px 16px; }
.mw-task-banner {
  display: flex; align-items: center; gap: 13px;
  padding: 12px 16px;
  border-radius: var(--r-lg);
  border: 1px solid var(--brand-line);
  background: linear-gradient(90deg, var(--brand-soft), rgba(255, 255, 255, 0) 72%);
  margin-bottom: 12px;
}
.mw-task-banner.t1 {
  border-color: #bfe3d4;
  background: linear-gradient(90deg, var(--good-soft), rgba(255, 255, 255, 0) 72%);
}
.mw-task-icon {
  width: 42px; height: 42px; border-radius: 12px; flex: none;
  background: var(--surface); border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  font-size: 21px; box-shadow: var(--shadow-1);
}
.mw-task-title { font-size: 17px; font-weight: 760; letter-spacing: .3px; }

/* 第二级：雷达图 + 题型胶囊切换 */
.mw-vertex circle { transition: r .12s ease; }
.mw-vertex:hover text { fill: var(--ink); }
.mw-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.mw-type-chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface-2); color: var(--ink-2);
  font-size: 12px; padding: 4px 11px; cursor: pointer;
  font-family: inherit;
}
.mw-type-chip b { font-weight: 650; color: var(--muted); }
.mw-type-chip.active {
  border-color: var(--brand-line); background: var(--brand-soft); color: var(--brand);
}
.mw-type-chip.active b { color: var(--brand); }
.mw-panel.t1 .mw-type-chip.active {
  border-color: #bfe3d4; background: var(--good-soft); color: var(--good-text);
}
.mw-panel.t1 .mw-type-chip.active b { color: var(--good-text); }

/* ---------- 真题库：按考试分栏，各自筛选（2026-10-05；2026-10-06 加考试范围条） ---------- */
/* auto-fit 而不是写死 1fr 1fr：分栏数由考试版本决定（雅思/高考 2 栏、
   托福 3 栏），写死两列时三栏会挤成两行且第一行只剩一半宽。 */
.q-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 16px;
  align-items: start;
}
.q-panel { padding: 14px 16px 16px; border-top: 3px solid var(--brand); }
.q-panel.t1 { border-top-color: var(--good); }
.q-panel.gen { border-top-color: var(--brand-2); }
.q-panel-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.q-panel-title { font-size: 16px; font-weight: 760; }
/* 考试范围条：两个下拉 + 两个动作按钮，窄屏自动换行 */
.q-scope .field-label { font-size: 11.5px; }
.q-scope .select { height: 36px; }
.q-scope optgroup { font-style: normal; font-weight: 700; }
.q-scope option:disabled { color: var(--faint); }
.q-panel-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.q-panel-filters .select, .q-panel-filters .input {
  flex: 1 1 128px; min-width: 0; width: auto; height: 34px;
}
.q-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(238px, 1fr));
  gap: 12px;
}
.q-panel .q-card { margin-bottom: 0; }
.q-panel-page { margin-top: 12px; }
.q-panel-page .row { gap: 10px; }

.mw-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(262px, 1fr));
  gap: 12px;
}
.mw-tile {
  display: flex; flex-direction: column;
  transition: transform .14s ease, box-shadow .14s ease;
}
.mw-tile:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.mw-tile-foot {
  margin-top: auto; padding-top: 10px;
  border-top: 1px dashed var(--line);
  display: flex; gap: 8px;
}
.mw-score { font-size: 21px; font-weight: 760; color: var(--brand); text-align: center; line-height: 1.05; }
.mw-score small { display: block; font-size: 10px; font-weight: 500; color: var(--faint); margin-top: 1px; }
.mw-score-none { color: var(--faint); font-weight: 500; }
.mw-ghost {
  border: 1.5px dashed var(--line-strong);
  background: transparent; box-shadow: none;
  display: flex; flex-direction: column;
}

/* ---------- 社区：信息流 + 热榜（2026-10-05） ---------- */
.cm-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 16px;
  align-items: start;
}
/* X 式单列时间线：一行一张卡，动作栏直接躺在卡上 */
.cm-timeline { display: flex; flex-direction: column; gap: 12px; max-width: 720px; }
.cm-card {
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 9px;
}
.cm-tweet.is-new { animation: cmNew 2s ease; }
@keyframes cmNew {
  0% { background: var(--brand-soft); box-shadow: 0 0 0 2px var(--brand); transform: translateY(-4px); opacity: 0; }
  35% { opacity: 1; transform: none; }
  100% { background: var(--surface); box-shadow: none; }
}
/* 卡上的动作栏：回复 / 点赞 / 分享 / 浏览 */
.cm-acts {
  display: flex; align-items: center; gap: 2px;
  border-top: 1px dashed var(--line);
  padding-top: 7px; margin-top: 1px;
}
.cm-act {
  border: none; background: transparent; cursor: pointer;
  color: var(--muted); font-size: 12.5px; font-weight: 500;
  padding: 4px 9px; border-radius: 8px;
  display: inline-flex; align-items: center; gap: 5px;
  font-family: inherit;
}
.cm-act:hover { background: var(--brand-soft); color: var(--brand); }
.cm-act.on { color: #e0245e; font-weight: 700; }
.cm-act.cm-act-primary { color: var(--brand); font-weight: 700; }
.cm-act.cm-views { cursor: default; }
.cm-act.cm-views:hover { background: transparent; color: var(--muted); }
/* 卡上的关注按钮：小药丸，未关注描边 / 已关注置灰 */
.cm-follow {
  flex: none; font-size: 12px; font-weight: 700; font-family: inherit;
  padding: 3px 11px; border-radius: 999px; cursor: pointer;
  border: 1.5px solid var(--brand); color: var(--brand); background: transparent;
}
.cm-follow:hover { background: var(--brand-soft); }
.cm-follow.on { border-color: var(--line-strong); color: var(--muted); }
.cm-follow.on:hover { background: transparent; }
/* 内联回复区 */
.cm-replies {
  border-top: 1px dashed var(--line);
  padding-top: 10px;
  display: flex; flex-direction: column; gap: 8px;
}
.cm-replies[hidden] { display: none; }
.cm-reply-row { display: flex; gap: 8px; align-items: flex-start; }
.cm-reply-row .textarea { flex: 1; min-width: 0; }
.cm-reply { display: flex; gap: 8px; align-items: flex-start; }
.cm-reply .grow { min-width: 0; }
.cm-note { line-height: 1.6; }
/* 转发引用卡（X 式 quote）：内嵌在转发卡 / 弹层里，点击进原帖 */
.cm-quoted {
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2);
  padding: 10px 12px; margin-top: 8px;
  cursor: pointer; transition: border-color .15s, background .15s;
}
.cm-quoted:hover { border-color: var(--brand); background: var(--brand-soft); }
.cm-quoted.is-dead { cursor: default; color: var(--muted); font-size: 12.5px; }
.cm-quoted.is-dead:hover { border-color: var(--line); background: var(--surface-2); }
.cm-band { margin-left: 8px; font-weight: 800; color: var(--brand); }
.cm-quoted .cm-band { margin-left: 0; display: inline-block; margin-top: 6px; }

/* ---------- 评论线程（根评论向下线形排列，回复缩进挂父评论下） ---------- */
#cmt-list { display: flex; flex-direction: column; gap: 16px; }
.cmt { display: flex; flex-direction: column; gap: 6px; }
.cmt-thread {
  /* 缩进 = 头像宽(26) + 间距(9)，左侧连接线把回复串在父评论下面 */
  margin: 2px 0 0 35px;
  padding-left: 14px;
  border-left: 2px solid var(--line);
  display: flex; flex-direction: column; gap: 12px;
}
.cmt-replybox { margin-top: 8px; }
.cmt-replybox[hidden] { display: none; }
.cmt-replybox .textarea { width: 100%; }
.cm-attach {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 10px; padding: 9px 11px;
  font-size: 12.5px; color: var(--ink-2); line-height: 1.5;
}
.cm-composer .textarea { width: 100%; }
/* 右侧热榜 */
.cm-side { position: sticky; top: 74px; }
.cm-hot-seg { margin: 0 14px 4px; }
.cm-hot-item {
  display: flex; gap: 10px; align-items: center;
  padding: 10px 14px; border-top: 1px dashed var(--line);
  cursor: pointer;
}
.cm-hot-item:hover { background: var(--brand-soft); }
.cm-rank {
  width: 22px; height: 22px; border-radius: 7px; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 800;
  background: var(--surface-2); color: var(--muted);
}
.cm-rank.r1 { background: linear-gradient(135deg, #ff9a3d, #ff5e3a); color: #fff; }
.cm-rank.r2 { background: linear-gradient(135deg, #ffb75e, #ed8f03); color: #fff; }
.cm-rank.r3 { background: linear-gradient(135deg, #ffd194, #d1913c); color: #fff; }

/* ---------- 响应式 ---------- */
@media (max-width: 1080px) {
  .editor-wrap { grid-template-columns: 1fr; }
  .side-panel { position: static; }
  .grid-4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .mw-stats { grid-template-columns: repeat(3, minmax(0,1fr)); }
  .mw-split { grid-template-columns: 1fr; }
  .q-split { grid-template-columns: 1fr; }
  .cm-grid { grid-template-columns: 1fr; }
  .cm-side { position: static; }
}
@media (max-width: 860px) {
  .tabbar { display: flex; }
  .view { padding: 16px 14px 96px; }
  /* 顶栏移动端（2026-10-09 手机修复）：原 flex 不换行，右侧动作区（按钮+chip+铃铛）
     min-content 很宽，把「标题+副标题」的 wrapper 压到 min-content → CJK 逐字断行变竖排。
     现在允许整行换行：标题块可收缩（min-width:0），动作区内部也能换行。 */
  .topbar { padding: 10px 14px; flex-wrap: wrap; row-gap: 4px; }
  .topbar > div:not(.topbar-right) { min-width: 0; }
  .topbar-title { white-space: nowrap; }
  .topbar-sub { white-space: normal; }
  .topbar-right { flex: none; flex-wrap: wrap; justify-content: flex-end; row-gap: 4px; }
  /* 窄屏给考试切换器一个上限，让它**先让位**给记灵感/查词（那两颗是固定宽度的图标/短词），
     超出部分走省略号。168px 的取法：34(记灵感)+68(查词)+168+41(EN)+3×6(间隙)+28(左右留白)
     = 357 < 375，还能容下以后再多一颗 ~18px 的入口。 */
  .topbar-right .exam-switch { max-width: 168px; }
  .subtabs { padding: 6px 14px; }
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  /* 侧栏型 grid（内联 1fr 320px / 340px 1fr 等）在手机端折叠成单列。
     内联 grid-template-columns 优先级高于 class，必须 !important 才能覆盖；
     否则 320px 侧栏 + 被压到 ~11px 的主栏 → 整页横向溢出（2026-10-09 布局审查） */
  .grid-side { grid-template-columns: 1fr !important; }
  .diff { grid-template-columns: 1fr; }
  h1 { font-size: 21px; }
  .crit { grid-template-columns: 1fr; gap: 6px; }
  .mw-stats { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .mw-bar { display: none; }
  .hero-cols { grid-template-columns: 1fr !important; }
  /* 热力图卡头：标题 + 我的/全站 chips + 按话题/按题型 seg + 放大按钮，一行塞不下，
     手机端允许换行，避免把 h3 挤成逐字竖排（2026-10-09 手机修复） */
  .hero-heat .card-head { flex-wrap: wrap; row-gap: 6px; }
  .hero-heat .card-head h3 { flex: 1 1 100%; }
  /* 通用卡头：chip/按钮较多时（如「记灵感」卡头 3 chip + 2 按钮），窄屏允许换行，
     避免 nowrap 按钮/chip 把整卡撑破 → 横向溢出（2026-10-09 布局审查） */
  .card-head { flex-wrap: wrap; row-gap: 6px; }
  .card-head .grow { display: none; }
  /* 行内 chip 组（题型/话题/年份/下次复习等）窄屏换行，避免 nowrap chip 溢出（2026-10-09） */
  .row { flex-wrap: wrap; row-gap: 6px; }
  .hero-heat .card-head .seg { flex: 1 1 auto; }
}
@media print {
  /* 导出 PDF：只留报告正文，隐藏一切界面壳；卡片拆掉阴影圆角，用边框分节，
     避免浅色底在打印里糊成灰块。文字全黑保证清晰。 */
  @page { size: A4; margin: 14mm 12mm; }
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  body { background: #fff !important; }
  .sidebar, .topbar, .subtabs, .tabbar, .btn, .nav-badge, .grow { display: none !important; }
  .view { padding: 0 !important; max-width: none !important; }
  .card { box-shadow: none !important; border: 1px solid #d8dce4; break-inside: avoid; }
  .card-head { border-bottom: 1px solid #e5e8ee; }
  .report-hero { background: #fff !important; color: #111 !important; box-shadow: none !important; border: 1px solid #d8dce4; }
  .report-hero .rh-band { color: #111; }
  .report-hero .rh-label { color: #666; }
  .band, .chip { color: #111 !important; background: #f1f3f7 !important; border: 1px solid #d8dce4 !important; }
  .diff { border: 1px solid #e5e8ee; }
  .diff-before, .diff-after { background: #fafbfc !important; }
  .struc-step, .struc-tpl code { background: #fafbfc !important; }
  h1, h2, h3, .rh-band, .crit-name, .lead, p, li, td, th, code { color: #111 !important; }
  .small.muted, .xsmall.faint, .faint, .crit-en, .muted { color: #444 !important; }
  a { color: #111; text-decoration: none; }
  details > summary { list-style: none; }
  details > summary::marker, details > summary::-webkit-details-marker { display: none; }
  .pre-wrap, .essay-para { white-space: pre-wrap; }
}

/* ============================================================
   复习板块（/revision）
   ============================================================ */
.rv-overview .card-head { flex-wrap: wrap; }
.rv-overview-body { display: grid; grid-template-columns: minmax(0,1.35fr) minmax(0,1fr); gap: 20px; }
.rv-spark { min-width: 0; }
.rv-bars { display: flex; align-items: flex-end; gap: 4px; height: 108px; padding-top: 6px; }
.rv-bar { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; height: 100%; gap: 4px; }
.rv-bar > i { display: block; width: 100%; border-radius: 4px 4px 2px 2px; background: linear-gradient(180deg, var(--brand-2), var(--brand)); min-height: 2px; }
.rv-bar > span { font-size: 9.5px; color: var(--faint); font-variant-numeric: tabular-nums; }
.rv-dims { border-left: 1px solid var(--line); padding-left: 20px; min-width: 0; }
.rv-topq { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: var(--r-sm); cursor: pointer; }
.rv-topq:hover { background: var(--surface-2); }

.rv-dimtabs { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 10px; }
.rv-dimtab { display: flex; align-items: center; gap: 10px; text-align: left; padding: 11px 13px; border: 1px solid var(--line); background: var(--surface); border-radius: var(--r); cursor: pointer; transition: border-color .15s, box-shadow .15s; }
.rv-dimtab:hover { border-color: var(--line-strong); box-shadow: var(--shadow-1); }
.rv-dimtab.active { border-color: var(--brand); background: var(--brand-soft); box-shadow: var(--shadow-1); }
.rv-dimtab-icon { font-size: 20px; flex: none; }
.rv-dimtab-text { display: flex; flex-direction: column; min-width: 0; }
.rv-dimtab-text b { font-size: 13px; }
.rv-dimtab-text i { font-style: normal; font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rv-split { grid-template-columns: 330px minmax(0,1fr); align-items: start; gap: 14px; }
.rv-list { position: sticky; top: 12px; max-height: calc(100vh - 130px); display: flex; flex-direction: column; overflow: hidden; }
.rv-filter { padding: 12px; border-bottom: 1px solid var(--line); display: flex; flex-direction: column; gap: 8px; }
.rv-seg { width: 100%; }
.rv-seg button { flex: 1; }
.rv-search { width: 100%; }
.rv-chips { gap: 8px; }
.rv-chips .input { flex: 1; min-width: 0; }
.rv-items { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 7px; }
.rv-item { text-align: left; border: 1px solid var(--line); background: var(--surface); border-radius: var(--r-sm); padding: 10px 11px; cursor: pointer; display: flex; flex-direction: column; gap: 6px; transition: border-color .15s, background .15s; }
.rv-item:hover { border-color: var(--line-strong); background: var(--surface-2); }
.rv-item.active { border-color: var(--brand); background: var(--brand-soft); }
.rv-item-tags { gap: 5px; flex-wrap: wrap; }
.rv-item-prompt { font-size: 12.5px; line-height: 1.5; color: var(--ink-2); }
.rv-item-foot { gap: 6px; }
.rv-detail { min-width: 0; }
.rv-prompt { font-size: 14px; line-height: 1.7; color: var(--ink); }

.rv-map, .bs-mini-map { height: 330px; }
.rv-versions { gap: 6px; flex-wrap: wrap; }

.rv-wordgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px,1fr)); gap: 10px; }
.rv-word { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 9px 11px; background: var(--surface-2); }
.rv-word-w { font-weight: 700; font-size: 14.5px; letter-spacing: -.01em; }
.rv-phon { font-family: var(--mono, monospace); }
.rv-ex { color: var(--ink-2); line-height: 1.55; margin-top: 4px; }
.rv-meaning { font-size: 13px; margin-top: 2px; }
.rv-coll { color: var(--muted); margin-top: 3px; }
.rv-exbox { margin-top: 8px; padding: 8px 10px; background: var(--brand-soft); border-left: 3px solid var(--brand-line); border-radius: 6px; line-height: 1.6; }
.rv-say { padding: 2px 6px; font-size: 12px; }
.rv-tags { gap: 6px; flex-wrap: wrap; }
.rv-tags .chip { cursor: pointer; }
.rv-tags .chip:not([data-act]) { cursor: default; }

.rv-vocabgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(272px,1fr)); gap: 12px; }
.rv-vcard { padding: 13px 14px; display: flex; flex-direction: column; }

.rv-tpl, .rv-gram { border: 1px solid var(--line); border-radius: var(--r-sm); padding: 10px 12px; background: var(--surface-2); }
.rv-struct { font-family: var(--mono, monospace); font-size: 12px; color: var(--brand); background: var(--brand-soft); border-radius: 5px; padding: 5px 8px; margin: 6px 0; display: inline-block; }

.rv-matcard .rv-matcn { font-size: 12.5px; color: var(--ink-2); background: var(--warn-soft); border-radius: 6px; padding: 8px 10px; margin-bottom: 10px; line-height: 1.6; }
.rv-matbody { font-size: 13.5px; line-height: 1.85; color: var(--ink); display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.rv-matbody.open { display: block; -webkit-line-clamp: unset; }
.rv-matrow { padding: 6px 0; border-bottom: 1px dashed var(--line); }
.rv-matrow:last-child { border-bottom: none; }
.rv-reader-body { font-size: 15px; line-height: 1.95; }

/* 记忆模式（闪卡拼写）：一屏一张卡，字要大 —— 拼写是「写出来」不是「认出来」 */
.rv-flash { max-width: 620px; margin: 0 auto; width: 100%; }
.rv-flash-zone { min-height: 240px; }
.rv-flash-meaning { font-size: 19px; font-weight: 680; line-height: 1.5; }
.rv-flash-word { font-size: 30px; font-weight: 750; letter-spacing: .01em; }
.rv-flash-word.is-ok { color: var(--good-text); }
.rv-flash-word.is-miss { color: var(--bad-text); }
.rv-flash-input { font-size: 16px; font-family: var(--mono, monospace); }
.rv-flash-input.is-ok { border-color: var(--good); background: var(--good-soft); }
.rv-flash-input.is-miss { border-color: var(--bad); background: var(--bad-soft); }

/* 跟读练习：例句是主角，字号拉大；录音状态按钮换警示色 */
.rv-shadow { max-width: 720px; margin: 0 auto; width: 100%; }
.rv-shadow-zone { min-height: 260px; }
.rv-shadow-sentence { font-size: 19px; line-height: 1.7; color: var(--ink); }
.rv-shadow-audio { width: 100%; }
.rv-shadow-ctrl .btn-danger { background: var(--bad); border-color: var(--bad); color: #fff; }

@media (max-width: 980px) {
  .rv-split { grid-template-columns: 1fr; }
  .rv-list { position: static; max-height: 460px; }
  .rv-overview-body { grid-template-columns: 1fr; }
  .rv-dims { border-left: none; padding-left: 0; border-top: 1px solid var(--line); padding-top: 14px; }
  .rv-dimtabs { grid-template-columns: repeat(2, minmax(0,1fr)); }
}

/* 首页复习提醒卡：有到期题目时整卡轻描一层警示色，扫一眼就能看到 */
.rv-due-card { border-color: #f0d489; background: #fffdf6; }

/* ============================================================
   灵感碎片（2026-10-06）
   卡片要同时容下「我的原文」和「AI 扩写」两种内容 ——
   原文用引号样式标注归属，扩写用浅底块区分，两者一眼分得清。
   ============================================================ */
.spk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(360px, 100%), 1fr)); gap: 12px; align-items: start; }
.spk-card { padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; cursor: pointer; transition: border-color .15s, box-shadow .15s; }
.spk-card:hover { border-color: var(--line-strong); box-shadow: var(--shadow-2); }
.spk-compact { padding: 10px 12px; gap: 6px; }
.spk-title { font-size: 14px; font-weight: 650; color: var(--ink); }
.spk-raw { font-size: 12.5px; color: var(--ink-2); background: var(--surface-2); border-left: 3px solid var(--brand-line); border-radius: 0 var(--r-sm) var(--r-sm) 0; padding: 7px 10px; white-space: pre-wrap; }
.spk-exp { background: var(--brand-soft); border: 1px solid var(--brand-line); border-radius: var(--r-sm); padding: 8px 10px; }
.spk-exp-body { font-size: 12px; color: var(--ink-2); white-space: pre-wrap; line-height: 1.6; }

/* ---- PEEL 结构卡（2026-10-07）：字母居左、内容居中、同色关联 ----
   P 观点=蓝 · E 解释=紫 · E 例证=橙 · L 回扣=绿；字母块实色、内容块同色浅底，
   一眼看出「哪个字母管哪段话」。颜色写死不接主题变量 —— 这四个色就是教学记号。 */
.spk-peel { display: flex; flex-direction: column; gap: 6px; }
.spk-peel-row { display: flex; align-items: stretch; gap: 8px; }
.spk-peel-tag { flex: none; width: 26px; min-height: 26px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 12.5px; color: #fff; }
.spk-peel-txt { flex: 1; min-width: 0; text-align: center; border-radius: 8px; padding: 4px 10px 5px; font-size: 12px; line-height: 1.65; color: var(--ink); white-space: pre-wrap; word-break: break-word; }
.spk-peel-name { display: block; font-size: 10px; font-weight: 750; letter-spacing: .5px; opacity: .68; margin-bottom: 1px; }
.spk-peel-row.p  .spk-peel-tag { background: #3b82f6; }
.spk-peel-row.p  .spk-peel-txt { background: rgba(59,130,246,.10); border: 1px solid rgba(59,130,246,.32); }
.spk-peel-row.e1 .spk-peel-tag { background: #8b5cf6; }
.spk-peel-row.e1 .spk-peel-txt { background: rgba(139,92,246,.10); border: 1px solid rgba(139,92,246,.32); }
.spk-peel-row.e2 .spk-peel-tag { background: #d97706; }
.spk-peel-row.e2 .spk-peel-txt { background: rgba(217,119,6,.12); border: 1px solid rgba(217,119,6,.34); }
.spk-peel-row.l  .spk-peel-tag { background: #059669; }
.spk-peel-row.l  .spk-peel-txt { background: rgba(5,150,105,.10); border: 1px solid rgba(5,150,105,.32); }

/* ---- 首页双列交错布局（2026-10-07）：左右均匀、板块各占一色 ----
   每个板块一道专属顶边 + 同色浅底：正在练习中=靛蓝 · 摸摸底=紫 · 记灵感=琥珀 ·
   复习提醒=绿 · 写作任务=天蓝 · 词汇任务=青 · 语法任务=红。
   （评分标准卡 2026-10-07 迁去备考目标弹窗，hc-bands 随之删除。）
   复习提醒到期时仍走 .rv-due-card 的琥珀警示（home.js 里二选一，不叠打）。 */
.home-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
@media (max-width: 980px) { .home-cols { grid-template-columns: 1fr; } }
.hc-doing  { border-top: 3px solid #4f46e5; background: #fcfcff; }
.hc-assess { border-top: 3px solid #7c3aed; background: #fdfcff; }
.hc-spark  { border-top: 3px solid #d97706; background: #fffdf8; }
.hc-review { border-top: 3px solid #059669; background: #f9fcfb; }
.hc-writ   { border-top: 3px solid #0284c7; background: #f9fcff; }
.hc-vocab  { border-top: 3px solid #0d9488; background: #f8fcfb; }
.hc-gram   { border-top: 3px solid #dc2626; background: #fffafa; }
.hc-plan   { border-top: 3px solid #0891b2; background: #f6fcfd; }
.spk-claim { color: var(--brand); font-weight: 550; }
.spk-acts { border-top: 1px solid var(--line); padding-top: 8px; }
.spk-del:hover { color: var(--bad-text); border-color: var(--bad); }
.spk-num { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }
.spk-unit { margin-left: 4px; }

.spk-composer .spk-input { min-height: 52px; }
.spk-kind { cursor: pointer; }

.spk-mini { display: flex; align-items: center; gap: 7px; padding: 6px 9px; border-radius: var(--r-sm); cursor: pointer; border: 1px solid var(--line); background: var(--surface); }
.spk-mini:hover { background: var(--surface-2); border-color: var(--line-strong); }

.spk-bar { height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; min-width: 40px; }
.spk-bar > i { display: block; height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--brand-2), var(--brand)); }

.spk-rel-item { padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-sm); cursor: pointer; }
.spk-rel-item:hover { background: var(--surface-2); border-color: var(--line-strong); }

.spk-month .rv-bar > i { background: linear-gradient(180deg, #f0b429, #c2751a); }

.rv-srcseg { flex: none; }
.rv-srchead { display: flex; align-items: center; gap: 8px; padding: 2px 2px 0; }
.spk-matcard .rv-matcn { color: var(--brand); }
.spk-edit .field { display: block; }
.spk-edit .field-label { display: block; font-size: 11px; color: var(--muted); margin-bottom: 3px; }

/* ============================================================
   站外社交分享弹层（2026-10-07）
   零资质零 SDK：canvas 卡片图 + 复制文案 + 各平台手动指引。
   ============================================================ */
.social-share { display: flex; flex-direction: column; gap: 12px; }
.social-card-wrap { text-align: center; }
.social-card-img {
  width: 100%; max-width: 420px; border-radius: var(--r);
  border: 1px solid var(--line); box-shadow: var(--shadow-2);
  display: block; margin: 0 auto; background: var(--surface);
}
.social-card-hint { margin-top: 6px; }
.social-platforms { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.social-platform {
  display: flex; align-items: center; gap: 10px;
  border: 1px solid var(--line); border-radius: var(--r);
  padding: 10px 12px; background: var(--surface);
}
.social-platform:hover { border-color: var(--line-strong); background: var(--surface-2); }
.social-platform-icon { font-size: 22px; flex: none; }
@media (max-width: 720px) {
  .social-platforms { grid-template-columns: 1fr; }
}

/* ============================================================
   好友裂变邀请弹层（2026-10-10）
   ============================================================ */
.invite-card { display: flex; flex-direction: column; gap: 10px; }
.invite-code-row {
  display: flex; align-items: center; gap: 12px;
  border: 1px solid var(--line); border-radius: var(--r);
  padding: 12px 14px; background: var(--surface);
}
.invite-code {
  font-size: 24px; letter-spacing: 3px; font-weight: 800;
  color: var(--brand); font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.invite-card .stat { flex: 1; font-size: 13px; color: var(--ink-2); }
.invite-card .stat b { color: var(--ink); font-size: 16px; margin: 0 2px; }
.invite-user {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: var(--r-sm); background: var(--surface-2);
  margin-bottom: 6px;
}

/* ============================================================
   备考计划左栏（2026-10-07 晚·七）：目录右侧、主页左侧
   ============================================================ */
.home-plan-layout { display: grid; grid-template-columns: 356px minmax(0, 1fr); gap: 16px; align-items: start; }
.plan-rail {
  position: sticky; top: 76px;
  max-height: calc(100vh - 92px); overflow: auto;
  scrollbar-width: thin;
}
.plan-item { border-radius: var(--r-sm, 8px); }
.plan-item:hover { background: rgba(8, 145, 178, .06); }
.plan-check {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  border: 1.5px solid var(--line, #cbd5e1); background: var(--surface, #fff);
  cursor: pointer; font-size: 13px; line-height: 1; color: #fff; padding: 0;
}
.plan-check:hover:not(:disabled) { border-color: #1f8f52; }
.plan-check.on { background: #1f8f52; border-color: #1f8f52; }
.plan-check:disabled { cursor: default; }
/* 月历 */
.cal-head { display: flex; align-items: center; gap: 6px; }
.cal-title { font-weight: 700; font-size: 13.5px; }
.cal-nav {
  width: 24px; height: 24px; border-radius: 6px; flex: none;
  border: 1px solid var(--line, #cbd5e1); background: var(--surface, #fff);
  cursor: pointer; line-height: 1; font-size: 14px;
}
.cal-nav:hover { border-color: #0891b2; color: #0891b2; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.cal-dow { text-align: center; font-size: 10.5px; color: #94a3b8; padding: 2px 0; }
.cal-cell {
  border: 1px solid transparent; border-radius: 8px; background: transparent;
  padding: 3px 0 2px; min-height: 40px; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.cal-cell:hover { background: rgba(8, 145, 178, .10); }
.cal-cell.cal-pad { cursor: default; min-height: 0; }
.cal-cell.cal-pad:hover { background: transparent; }
.cal-cell.cal-has { background: rgba(8, 145, 178, .07); }
.cal-cell.cal-today { border-color: #0891b2; }
.cal-cell.cal-sel, .cal-cell.cal-sel:hover { background: #0891b2; }
.cal-cell.cal-sel .cal-d { color: #fff; font-weight: 700; }
.cal-d { font-size: 12px; line-height: 1; color: var(--ink, #1e293b); }
.cal-marks { display: flex; gap: 2px; align-items: center; min-height: 6px; }
.cal-marks i { width: 6px; height: 6px; border-radius: 50%; display: inline-block; }
.cal-marks b { font-size: 8.5px; color: #64748b; font-weight: 600; }
@media (max-width: 1150px) {
  .home-plan-layout { grid-template-columns: 1fr; }
  .plan-rail { position: static; max-height: none; overflow: visible; }
}

/* ============================================================
   温故知新 · 次级筛选条：吸顶 + 可折叠（2026-10-11，用户 #4f）
   四个板块（回顾题目/夯实词汇/巩固语法/积累素材）的次级筛选
   固定不动、且能一键收起省空间。折叠状态记在 JS 模块里。
   ============================================================ */
.rv-sticky {
  position: sticky;
  /* 74px ≈ 顶栏高度 + 一点呼吸位，与 .side-panel / .plan-rail 的既有口径一致 */
  top: 74px;
  z-index: 20;
  background: var(--surface, #fff);
  box-shadow: 0 1px 0 var(--line, #e2e8f0), 0 8px 16px -14px rgba(15, 23, 42, .45);
}
/* ⚠️ 2026-10-12 修 #4（**宽屏**复现，这才是用户反复报的那一处）：
   上一轮只改了 `@media (max-width: 980px)`，而宽屏走的是另一套布局 ——
   用户在电脑上怎么看都没变化，于是「每次都不改」。
   宽屏下「回顾题目」左边那栏是 `.card.rv-list`：display:flex + overflow:hidden，
   筛选条与 `.rv-items` 是它的两个 flex 子项，**真正滚动的是 .rv-items**。
   而 overflow:hidden 的 .rv-list 本身就是一个滚动口，于是 `top:74px` 的 sticky
   被解释成「相对 .rv-list 顶部下移 74px」——筛选条直接压在题干上。
   CDP 实测 1280×900：第一题被压 66.3px，而 `.rv-items.scrollTop` 最小只能到 0，
   第一题的顶部**永远**露不出来（既滚不动也盖不住）。
   卡片内的筛选条本来就由 flex 排在列表之上、根本不会随内容滚走，
   sticky 在这里既多余又有害 —— 取消即可（其余三个维度不受影响，它们仍跟着页面滚）。 */
.rv-list .rv-sticky { position: static; }
.rv-foldhead { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rv-foldhead .rv-seg { flex: 1 1 220px; width: auto; }
.rv-foldtitle {
  font-size: 11px; font-weight: 650; letter-spacing: .06em;
  text-transform: uppercase; color: var(--faint);
}
.rv-foldbtn { margin-left: auto; flex: none; }
.rv-foldbody { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.rv-sticky.collapsed .rv-foldbody { display: none; }
@media (max-width: 980px) {
  /* 手机上顶栏会换行 → 吸顶偏移取小一点 */
  .rv-sticky { top: 56px; }
  /* ⚠️ 2026-10-12 修 #12/#2：筛选条**不能**在手机上相对页面吸顶。
     原来放开 .rv-list 后，筛选条 sticky 到 top:56px，于是它把自己下面的
     题目**盖住**了 —— CDP 实测：滚动 1100px 时第 2 题被压 70px、第 3 题被
     压 110px，两题永远露不出来也滚不出来（上下都是吸顶条，中间是死区）。
     现在分两路：
       · 网格型维度（词汇/语法/素材）→ 筛选条跟随页面滚动，谁都不压；
       · 题目维度 → 卡片自身当滚动容器，筛选条在**卡片滚动口内**吸顶，
         题目依次从它下方经过，每一题都能滚出来看（保住 #4f 的「筛选不随
         内容滚走」）。 */
  .rv-sticky { position: static; }
  /* 关键：父容器不能是滚动容器，否则 sticky 只相对它生效、等于不吸顶。 */
  /* ⚠️ 2026-10-12 修 #4（用户实报「题目列表被压住、展示不全」）：
     上一版把 .rv-list 做成定高内滚卡（max-height: 100vh-170 + overflow-y:auto）
     并在卡内吸顶筛选条。实测（tools/probe-rv-check.mjs，390×780）：
        .rv-list 高 610，内容 808 → 有 198px 被裁；.rv-items 可见 423 / 内容 624。
     即「只能看到一小截题目，剩下的滚在卡里」，加上吸顶筛选还会盖住首题。
     现在**不再定高、不再卡内滚动**：列表跟随页面自然铺开，每一题都整条可见，
     页面滚到底就能看全。筛选条也跟随页面滚动（与另外三个维度口径一致）。
     代价是筛选条不再吸顶 —— 但「能看全题目」优先级更高。 */
  .rv-list { position: static; max-height: none; overflow: visible; }
  .rv-filter { position: static; }
  .rv-items { max-height: none; overflow: visible; }
}

/* ── 空档签（#4c）───────────────────────────────────────────────
   分数段签上的数字是**真数**（现在按「不含 tier 筛选」的条件统计，
   选了某一档其余档也不归零）。但内容库确实有天然空的档 —— 例如
   词汇库最低档「6 分以下」一个词都没有。留一个亮着的「0」看起来像
   页面坏了，所以压暗 + 不可点，并把原因放进 title。 */
.chip-empty { opacity: .5; cursor: not-allowed; }
.chip-empty:hover { border-color: currentColor; }

/* ── 例证卡（#9 / #4g）──────────────────────────────────────────
   题库的「📌 可核查素材」与批改报告的「📌 本题可用素材」是同一形状，
   共用 core/evidence.js 一份渲染。原来两处都是**纯文本 div**：例证常常
   只显示两行就被 clamp 掉，学员既点不动也抄不走。
   这里把整行做成按钮：默认收着（正文 clamp-2），点开进全屏弹层读全文 + 复制。
   注意整行是 <button>，所以要把 UA 默认的外观/边距全部抹掉，
   只保留 .item 给的「下边线分隔」。 */
.ev-item {
  display: block;
  width: 100%;
  box-sizing: border-box;
  border: 0;                       /* 抹掉 UA 按钮边框，只留 .item 的下边线 */
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: background .12s;
}
.ev-item:hover { background: var(--surface-2); }
.ev-item:active { background: var(--brand-soft); }
.ev-item:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.ev-item .ev-claim-line { color: var(--ink); }

/* 弹层里的正文：例证常有换行，必须 pre-wrap，否则整段挤成一行 */
.ev-detail { max-width: 720px; }
.ev-claim { margin: 0 0 6px; font-size: 15px; line-height: 1.5; color: var(--ink); }
.ev-body {
  white-space: pre-wrap;
  line-height: 1.8;
  font-size: 13.5px;
  color: var(--ink-2);
  background: var(--surface-2);
  border-left: 3px solid var(--brand-line);
  border-radius: var(--r-sm);
  padding: 10px 12px;
}

/* ============================================================
   写作词典（M2 入口/浮层/词条卡；M3 起带第三方样式）
   ------------------------------------------------------------
   ⚠️ 关于第三方词典正文（.dict-html）的立场 —— M3 起**变了**，别再看旧注释：
     M2 时服务端把词典自带的 <style> 整个剥掉，所以这边只做「防御性重置」。
     M3 改成**作用域化后照发**：tools/dict-css.py 把每个选择器前缀成
     `.dict-scope-<pack>`（`.entry` / `h1` / `body` 这类通用选择器全部关在这个
     容器里，见方案 §4.1 第 3 条 / §8.4），前端按需 <link> 一次。
     于是本文件里跟词典有关的规则**必须自重**：能赢的就赢（我们的规则在后加载
     的包 CSS 之前才有把握），赢不了的别硬来 —— 硬来会**压掉词典自己的状态机**。
     典型：`div.collapse .body{display:none}` 是折叠态、`.is-active` 才展开，
     所以绝不能给 `table/img/.body` 加 `display:block !important`。

   ⚠️ 还有一条比样式更隐蔽的：包 CSS 里的喇叭图标是挂在**空 <a>** 上的
     background-image（base64 内联 SVG）。包 CSS 一旦没到，那些 <a> 就是隐形方块 ——
     所以下面的 `[data-dict-css-failed]` 兜底规则不是装饰，是可达性底线。
   ============================================================

/* ---------- 顶栏常驻入口（做成「搜索框」的样子） ----------
   2026-10-12 用户要求：「只需要右上角加一个搜索框，显示"查词"即可」。
   M2 那版是 .btn.btn-ghost.btn-icon 的纯放大镜 —— 用户得先知道这里有查词才敢点；
   现在它自己写成「搜索框」，一眼就知道点进去是查词。
   ⚠️ 它是个 <button>，不是只读 <input>：真输入框在浮层里（点开即聚焦）。
      做成只读 input 的话，点了能拿到焦点却打不了字 —— 那是**假的可交互**。
   ⚠️ 别再给它加 .btn-icon：那是「图标按钮」的类，宽度会被压成图标大小，
      框里的「查词」两个字就会被挤没（探针有一条宽度断言专门钉这个回归）。 */
.dict-top-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px 5px 9px; border-radius: 999px;
  border: 1px solid var(--line-strong); background: var(--surface-2);
  color: var(--muted); font-family: inherit; font-size: 12.5px; font-weight: 600;
  line-height: 1; white-space: nowrap; cursor: pointer;
  transition: border-color .13s, background .13s, color .13s, box-shadow .13s;
}
.dict-top-btn:hover { border-color: var(--brand-line); background: var(--brand-soft); color: var(--brand); }
.dict-top-btn:focus-visible { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.dict-top-btn svg { flex: none; }
.dict-top-t { line-height: 1; }

/* ---------- 顶栏常驻「记灵感」入口（2026-10-15 用户要求）----------
   与 App 端**同一颗**：实底琥珀 + 白色灯泡图标，与右侧「查词」并成一组。

   ⚠️ 为什么是**实底**而不是淡底（--warn-soft）—— 这是量出来的，不是审美：
      App 端第一版用过淡底 #fdf3e3，而顶栏底色是 #f5f6fa，两者对比度只有
      **1.02 : 1** ⇒ 等于隐形（用户原话「颜色太淡不明显」）。换 --warn 实底后
      对顶栏是 **4.5 : 1**，白图标对实底 4.8 : 1（UI 控件按 WCAG 1.4.11 要 ≥3:1）。
      ⇒ 别再把它改回 --warn-soft「淡一点更协调」，那正是用户报的那个问题。

   ⚠️ 为什么窄屏把「记灵感」三个字收起来：`.topbar-right` 在 400px 下本来就挤
      （见上面 .me-unread 的注释），那里已经有 查词 + 我的 + 考试切换器。
      查词是**先来的**且它的字样不能动（见 .dict-top-btn 的注释），所以新增的
      这颗让位 —— 窄屏只留灯泡图标，与 App 端逐字同形（App 顶栏放不下三个字）。

   ★ 2026-10-15 实测（375 宽，改完立刻发现的**真**回归，不是假红）：
     `.topbar-right` 里 5 个孩子（记灵感 / 查词 / 考试切换 / EN / 我的）总宽 365.2px，
     而可用只有 ~361px ⇒ 整页能横向拖动 4px。负向对照（把任一颗 display:none）
     后溢出都归 0 —— 说明是**总宽**超了，我这颗是最后那 4px。
     处置：窄屏把 .topbar-right 的间距从 8px 收到 6px（5 个孩子 = 4 个间隙 ⇒ 省 8px）。
     ⚠️ 为什么不继续缩这颗按钮的 padding：那会把触控目标压到 21px 高，点不中。
     为什么要写这条而不是「让页面能横向滚」：能横向拖动本身就是缺陷。 */
.spark-top-btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 11px 5px 9px; border-radius: 999px;
  border: 1px solid var(--line-strong); background: var(--spark-fill);
  color: var(--spark-ink); font-family: inherit; font-size: 12.5px; font-weight: 600;
  line-height: 1; white-space: nowrap; cursor: pointer;
  box-shadow: 0 2px 8px rgba(255, 179, 0, .45);
  transition: border-color .13s, background .13s, box-shadow .13s;
}
/* hover 只动底色与光晕，**不动框线**：框线一变深就退回被用户否掉的「轮廓线」
   （查词那颗 hover 时是整体换一套配色，这颗是实底按钮，底色已经是强调色）。 */
.spark-top-btn:hover { background: var(--spark-fill-hover); box-shadow: 0 2px 10px rgba(255, 179, 0, .55); }
.spark-top-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(255, 197, 61, .65); }
/* 灯泡字形 = **💡 这个字符本身**（2026-10-15 用户：「这个 icon 必须是灯泡💡」）。
   ⚠️ 别「顺手统一风格」把它换回线条图标（icons.js 里的 `bulb` 路径就是这个用途，
      现在**顶栏不用了**）：那枚 15px 的白色线条灯泡在真机/小尺寸下就是一团白斑，
      正是用户报的「尤其不像灯泡」。emoji 的字形自带近白的灯泡玻璃，压在灯光黄上
      反而更清楚；而且 emoji 在这个产品里不是外来物 ——
      sparks.js 的 kindIcon() 兜底就是 '💡'（📰🔎🙋👀📖💬 一族本就是 emoji 类型签）。 */
.spark-top-e { flex: none; font-size: 14px; line-height: 1; }
.spark-top-t { line-height: 1; }
@media (max-width: 767px) {
  .spark-top-t { display: none; }
  .spark-top-btn { padding: 5px 7px; }
  /* 给这颗按钮腾地方（见下面 375 宽的实测）—— 只收间距，不动任何人的尺寸 */
  .topbar-right { gap: 6px; }
}

/* ---------- 搜索浮层 ---------- */
.dict-overlay {
  position: fixed; inset: 0; z-index: 160;
  background: rgba(23, 26, 36, .34);
  display: flex; justify-content: center; align-items: flex-start;
  padding: 72px 16px 16px;
  animation: fade .12s;
}
/* ⚠️ 必须显式写这一条：上面给了 display:flex，作者样式的优先级高于 UA 的
   [hidden]{display:none} —— 不补这条，hidden 就完全失效，浮层永远收不起来
   （#app / .tabbar 早就踩过同一个坑，见 index.html 里的注释）。 */
.dict-overlay[hidden] { display: none; }
.dict-panel {
  width: 100%; max-width: 720px; max-height: calc(100vh - 108px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-3);
  display: flex; flex-direction: column; overflow: hidden;
}
.dict-bar {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 10px 10px 14px; border-bottom: 1px solid var(--line);
}
.dict-bar-ic { color: var(--faint); display: inline-flex; flex: none; }
.dict-q {
  flex: 1; min-width: 0; border: 0; outline: 0; background: transparent;
  font-family: inherit; font-size: 16px; color: var(--ink); padding: 4px 0;
}
.dict-q::placeholder { color: var(--faint); }
.dict-x { flex: none; }
.dict-scroll { flex: 1; min-height: 0; overflow-y: auto; }
.dict-sugs { display: flex; flex-direction: column; padding: 6px; }
.dict-sugs[hidden] { display: none; }
.dict-sug {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 10px; border: 0; border-radius: var(--r-sm);
  background: transparent; cursor: pointer; text-align: left;
  font: inherit; color: var(--ink-2);
}
.dict-sug:hover { background: var(--surface-2); }
.dict-sug.active { background: var(--brand-soft); }
.dict-sug-word { font-weight: 600; font-size: 14.5px; color: var(--ink); }
.dict-sug.active .dict-sug-word { color: var(--brand); }
.dict-foot {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 14px; border-top: 1px solid var(--line); background: var(--surface-2);
}
.dict-open-page { font-size: 12.5px; font-weight: 600; }

/* ---------- 词条卡（浮层与 /dict 页共用） ---------- */
.dict-card { padding: 14px; }
.dict-card-compact { padding: 12px; }
.dict-head { display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
.dict-head-main { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0; }
.dict-word { font-size: 21px; font-weight: 700; letter-spacing: -.01em; color: var(--ink); }
.dict-phon { color: var(--muted); font-size: 13px; }
.dict-redirect { margin-top: 6px; font-size: 12.5px; color: var(--muted); }
.dict-layer { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--line); }
.dict-layer-head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-bottom: 8px; }

/* ---------- 词典段落折叠箭头（2026-10-13：向 App 端对齐） ----------
   用户原话：「网页端的词典查词页面没有点击收缩展示的小帽子箭头。
   这个要向手机 app 端的查词页面对齐。」
   与 App 的 _PackSection 同语义：默认展开、点箭头收起、箭头转 -90°。
   ⚠️ 收起的是 `.dict-layer-body`（正文），不是整个 section ——
      标题（词典名）必须一直可见，否则收起后就不知道那一条是什么了。 */
.dict-layer-toggle {
  /* margin-left:auto = 推到最右，与 App 的 Expanded 布局同位置 */
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  border: 0; border-radius: 999px; background: transparent;
  color: var(--muted); cursor: pointer;
  transition: color .13s, background .13s;
}
.dict-layer-toggle:hover { color: var(--brand); background: var(--brand-soft); }
.dict-layer-toggle:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--brand-soft); }
.dict-layer-toggle svg { transition: transform .16s; }
/* 收起 → 箭头朝右（-90°）。与 App 的 AnimatedRotation(turns: _open ? 0 : -0.25)
   是同一个角度、同一段时长量级，两端观感一致。 */
.dict-layer.closed .dict-layer-toggle svg { transform: rotate(-90deg); }
.dict-layer.closed .dict-layer-body { display: none; }

/* ---------- 发音按钮（M3）：音轨是 MDD 里的真人录音 ---------- */
.dict-audio { display: inline-flex; align-items: center; gap: 6px; }
.dict-audio-btn {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 9px; font-size: 12px; line-height: 1.2;
}
.dict-audio-btn span { font-weight: 600; }
/* 正在播的那颗按钮要能看出来 —— 否则「点了没反应」和「在播」分不清 */
.dict-audio-btn.playing {
  color: var(--brand); border-color: var(--brand-line); background: var(--brand-soft);
}
.dict-mean { font-size: 14.5px; color: var(--ink-2); }
.dict-sub {
  margin: 10px 0 6px; font-size: 11px; font-weight: 650;
  letter-spacing: .06em; text-transform: uppercase; color: var(--faint);
}
.dict-coll { cursor: default; }
.dict-eg {
  margin-top: 10px; padding: 9px 11px; background: var(--surface-2);
  border-left: 3px solid var(--brand-line); border-radius: var(--r-sm);
}
.dict-eg-en { font-size: 13.5px; line-height: 1.7; color: var(--ink); }
.dict-eg-cn { margin-top: 4px; font-size: 12.5px; color: var(--muted); }
.dict-stars { color: #e0a53a; font-size: 15px; letter-spacing: 2px; }

/* ---------- 第三方正文：防御性重置 + 兜底 ---------- */
.dict-html { font-size: 14px; line-height: 1.78; color: var(--ink-2); word-break: break-word; }
.dict-html :is(h1, h2, h3, h4, h5, h6) {
  margin: 8px 0 4px; font-size: 14.5px; font-weight: 650; color: var(--ink);
}
.dict-html p { margin: 0 0 6px; }
/* 图片防溢出：词典里有宽到 1200px 的整版插图（oald10 的 big_pic / 韦氏的 gif） */
.dict-html img { max-width: 100%; height: auto; }
/* 表格防溢出：`display:block + overflow-x` 是**故意**的 —— 词典的变位表、
   collocations 表在窄屏必然撑破卡片。注意这里**不能**加 !important：
   包 CSS 的 `div.collapse table{display:none}`（折叠态）与
   `div.collapse .is-active table{display:inherit}`（展开态）特异性比我们高，
   一加 !important 就把折叠/展开整个压死。 */
.dict-html table { display: block; width: 100%; border-collapse: collapse; overflow-x: auto; }
.dict-html td, .dict-html th { padding: 3px 6px; border: 1px solid var(--line); font-size: 13px; }
.dict-html a { color: var(--brand); }
/* 只压掉 <font size=…>（能造出巨字），**保留 color** —— 词频星级就是靠色标传达的 */
.dict-html font { font-size: inherit; }

/* 正文里的发音链接（`<a href="/dict-assets/…mp3">`，内容是个空白）：
   正常由包 CSS 画喇叭图标；这里只保证「能点」（可见性交给下面的兜底）。 */
.dict-html a[href$=".mp3"] { cursor: pointer; }

/* ⚠️ 包 CSS 没加载成功时的兜底（标志由 core/dict.js 的 ensurePackCss 在
   <link> onerror 时打到 <html> 上）。此时那些空 <a> 没有图标、就是隐形方块，
   补一个不依赖任何图片的喇叭，并给一点可见的轮廓 —— 宁可丑，不能点不到。 */
html[data-dict-css-failed] .dict-html a[href$=".mp3"] {
  display: inline-block; min-width: 16px; min-height: 16px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 4px;
}
html[data-dict-css-failed] .dict-html a[href$=".mp3"]::after { content: "🔊"; font-size: 11px; }

/* ---------- 查词页 /dict ---------- */
.dict-page-ic { color: var(--faint); display: inline-flex; flex: none; }
.dict-ex { cursor: pointer; }
.dict-pack {
  align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--line);
}
.dict-pack:last-child { border-bottom: 0; }

/* ---------- 我的词典包（用户自带 MDX/MDD，M5 2026-10-14） ----------
   与 .dict-pack 视觉一致但**类名独立**：probe-dict-ui.mjs 用的是不带作用域的
   `#view .dict-pack`（数行数 / 点第一个 packToggle / 找拖影），而这一块也会出现在
   /dict 页上 ⇒ 复用类名 = 把两个列表的断言耦合起来（今天绿，改天静默红）。 */
.dict-up-job {
  align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--line);
}
.dict-up-job:last-child { border-bottom: 0; }

/* ---------- 词典库长按拖动排序（2026-10-13 用户要求 #4） ----------
   touch-action:none 是必需的：不写的话手指按在行上滑动会先触发页面滚动，
   我们根本收不到 pointermove；user-select:none 防的是桌面上拖动时选中文字。 */
.dict-pack-reorder {
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  border-radius: 10px;
  padding-left: 4px;
  padding-right: 4px;
}
.dict-pack-reorder:active { cursor: grabbing; }
.dict-pack-handle {
  flex: none; color: var(--faint); letter-spacing: -2px;
  font-size: 15px; line-height: 1; margin-right: 2px;
}
/* 被拖走的那一行 = 占位符：留位置、但明显「已被拿起」 */
.dict-pack-dragging { opacity: .32; background: var(--surface-2); }
/* 跟手的拖影。必须 fixed —— 列表是 flex 列，absolute 会被父级定位吃掉。 */
.dict-pack-ghost {
  position: fixed; z-index: 9999; pointer-events: none;
  background: var(--surface); border-radius: 10px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .22);
  border: 1px solid var(--line);
  padding: 9px 6px; opacity: .97;
}

@media (max-width: 860px) {
  /* 手机上浮层贴边铺开，别留 72px 的顶缝（顶栏本来就矮） */
  .dict-overlay { padding: 56px 10px 10px; }
  .dict-panel { max-height: calc(100vh - 74px); border-radius: var(--r); }
  .dict-word { font-size: 19px; }
  /* 键盘提示在触屏上没意义，让位给「在查词页打开」 */
  .dict-foot .xsmall { display: none; }
}

@media print {
  /* 打印（导出 PDF）时浮层不该出现在纸面上 */
  .dict-overlay { display: none !important; }
  .dict-html font { color: #111 !important; }
}

/* ============================================================
   口语板块（2026-10-14｜Speak Write Now · Speak）
   命名空间 `sp-`。全部走主题变量，别写死颜色 —— 换肤时这一块才能跟着走。
   ============================================================ */

/* ---- 题库 ---- */
.sp-filter { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 10px; }
.sp-filter-l { flex: none; width: 46px; padding-top: 3px; font-size: 11.5px; color: var(--faint); font-weight: 600; }
.sp-filter .chips { display: flex; flex-wrap: wrap; gap: 6px; }
.sp-search { margin-top: 4px; }
.sp-search .input { width: 100%; }

.sp-items, .sp-sessions { display: flex; flex-direction: column; gap: 8px; }
.sp-item {
  text-align: left; width: 100%; cursor: pointer;
  display: block; font: inherit; color: inherit; border: 1px solid var(--line);
}
.sp-session {
  text-align: left; width: 100%; cursor: pointer;
  display: block; font: inherit; color: inherit; border: 1px solid var(--line);
}
/* 难度圆点：只做「几颗星」的密度提示，别当分数读 */
.sp-diff { flex: none; color: var(--warn-text); font-size: 9px; letter-spacing: 1px; padding-top: 4px; }
.sp-pager { gap: 8px; justify-content: center; }

/* ---- 题目页 ---- */
.sp-h2 { margin: 8px 0 4px; font-size: 17px; line-height: 1.45; }
.sp-h3 { margin: 0 0 8px; font-size: 14.5px; }
.sp-prompt {
  padding: 11px 13px; border-radius: var(--r); background: var(--surface-2);
  border: 1px solid var(--line); line-height: 1.75; white-space: pre-wrap;
}
.sp-timing { font-size: 11.5px; color: var(--faint); }
.sp-cues { }
.sp-ul { margin: 4px 0 0; padding-left: 18px; line-height: 1.7; }
.sp-ul li { margin-bottom: 3px; }
.sp-warn-list li { color: var(--warn-text); }
.sp-script { white-space: pre-wrap; line-height: 1.8; }

/* 折叠块（原生 <details>：零 JS 状态，重绘不丢展开态） */
.sp-fold { border: 1px solid var(--line); border-radius: var(--r); margin-bottom: 8px; background: var(--surface); }
.sp-fold > summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 9px 12px; font-size: 13px; list-style: none;
}
.sp-fold > summary::-webkit-details-marker { display: none; }
.sp-fold > summary::before {
  content: '▸'; flex: none; color: var(--faint); font-size: 11px;
  transition: transform .15s; display: inline-block;
}
.sp-fold[open] > summary::before { transform: rotate(90deg); }
.sp-fold-t { font-weight: 600; }
.sp-fold > summary .xsmall { margin-left: auto; }
.sp-fold-b { padding: 2px 12px 12px; border-top: 1px solid var(--line); }

/* ---- 录音 ---- */
.sp-rec-card.is-rec { border-color: var(--bad); box-shadow: 0 0 0 3px var(--bad-soft); }
.sp-wave {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: var(--r); background: var(--surface-2);
  border: 1px solid var(--line); min-height: 54px;
}
.sp-timer { flex: none; font-variant-numeric: tabular-nums; font-weight: 700; font-size: 15px; }
.sp-left { flex: none; font-size: 11.5px; color: var(--faint); font-variant-numeric: tabular-nums; }
.sp-bars { flex: 1; display: flex; align-items: center; gap: 2px; height: 34px; min-width: 0; overflow: hidden; }
.sp-bars > i { flex: 1; min-width: 1px; border-radius: 2px; background: var(--brand); display: block; }
.sp-wave-idle .sp-bars > i { background: var(--line-strong); }
.sp-rec-card.is-rec .sp-bars > i { background: var(--bad); }
.sp-audio { width: 100%; margin-top: 10px; }
.sp-err { color: var(--bad-text); }
.sp-warn-inline { color: var(--warn-text); }
.sp-transcript { border-top: 1px dashed var(--line); padding-top: 10px; }
.sp-pre { white-space: pre-wrap; line-height: 1.75; }

/* ---- 分数色阶：分越高越好（与股票涨跌色无关，别套红绿惯例） ---- */
.f-good { color: var(--good-text); }
.f-info { color: var(--info-text); }
.f-warn { color: var(--warn-text); }
.f-bad { color: var(--bad-text); }
.f-none { color: var(--faint); }
.sp-instant-bar > i.f-good, .sp-factor-bar > i.f-good { background: var(--good); }
.sp-instant-bar > i.f-info, .sp-factor-bar > i.f-info { background: var(--info); }
.sp-instant-bar > i.f-warn, .sp-factor-bar > i.f-warn { background: var(--warn); }
.sp-instant-bar > i.f-bad, .sp-factor-bar > i.f-bad { background: var(--bad); }
.sp-instant-bar > i.f-none, .sp-factor-bar > i.f-none { background: var(--line-strong); }

/* ---- 即时分 ---- */
.sp-instant-row {
  display: grid; grid-template-columns: 62px 1fr 40px; align-items: center;
  gap: 8px; padding: 5px 0;
}
.sp-instant-k { font-size: 12.5px; font-weight: 600; }
.sp-instant-bar { height: 7px; border-radius: 4px; background: var(--surface-2); overflow: hidden; }
.sp-instant-bar > i { display: block; height: 100%; border-radius: 4px; }
.sp-instant-v { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; font-size: 13px; }
.sp-instant-d { grid-column: 1 / -1; }

/* ---- 报告 ---- */
.sp-overall { display: flex; align-items: center; gap: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--line); }
.sp-overall-v { font-size: 38px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.sp-factors { margin-top: 12px; display: flex; flex-direction: column; gap: 12px; }
.sp-factor.is-none { opacity: .62; }
.sp-factor-h { display: flex; align-items: baseline; gap: 8px; }
.sp-factor-v { font-weight: 700; font-variant-numeric: tabular-nums; min-width: 34px; text-align: right; }
.sp-factor-bar { height: 6px; border-radius: 4px; background: var(--surface-2); overflow: hidden; margin: 5px 0; }
.sp-factor-bar > i { display: block; height: 100%; border-radius: 4px; }
.sp-reason { margin-top: 2px; }
.sp-preflight { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; }
.sp-check.is-ok { color: var(--good-text); }
.sp-check.is-no { color: var(--faint); }
.sp-sub { margin: 14px 0 5px; font-size: 12px; font-weight: 700; color: var(--faint); letter-spacing: .03em; }
.sp-fix { padding: 8px 10px; border-radius: var(--r); background: var(--surface-2); margin-bottom: 7px; }
.sp-fix-o { text-decoration: line-through; color: var(--bad-text); line-height: 1.6; }
.sp-fix-b { color: var(--good-text); font-weight: 600; line-height: 1.6; }
.sp-errbox {
  padding: 9px 11px; border-radius: var(--r); background: var(--bad-soft);
  border: 1px solid #f4cdd1; color: var(--bad-text); font-size: 12.5px; line-height: 1.65;
}
.sp-draftwarn {
  padding: 8px 11px; border-radius: var(--r); background: var(--warn-soft);
  border: 1px solid #f0dcbd; color: var(--warn-text); font-size: 12.5px; line-height: 1.6;
}
.sp-session-score { font-size: 22px; font-weight: 800; font-variant-numeric: tabular-nums; }

/* ---- 内容块正文 ---- */
.sp-tagline { font-size: 12.5px; font-weight: 600; color: var(--brand); margin-bottom: 6px; }
.sp-kp { padding: 7px 0; border-bottom: 1px dashed var(--line); }
.sp-kp:last-child { border-bottom: none; }
.sp-angle { padding: 8px 0; border-bottom: 1px dashed var(--line); }
.sp-angle:last-child { border-bottom: none; }
.sp-angle-h { font-weight: 700; font-size: 13px; margin-bottom: 3px; }
.sp-struct-row {
  display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap;
  padding: 6px 0; border-bottom: 1px dashed var(--line);
}
.sp-struct-p { font-weight: 700; font-size: 12.5px; flex: none; min-width: 84px; }
.sp-struct-s { font-size: 11.5px; color: var(--faint); flex: none; }
.sp-struct-say, .sp-say {
  flex-basis: 100%; font-style: italic; color: var(--ink-2);
  background: var(--surface-2); border-left: 3px solid var(--brand-line);
  padding: 4px 9px; border-radius: 0 6px 6px 0; margin-top: 4px; line-height: 1.65;
}
.sp-beat { display: flex; gap: 10px; padding: 8px 0; border-bottom: 1px dashed var(--line); }
.sp-beat:last-child { border-bottom: none; }
.sp-beat-at { flex: none; min-width: 76px; font-size: 12px; font-weight: 700; color: var(--brand); }
.sp-pgroup { margin-bottom: 10px; }
.sp-pgroup-h { font-weight: 700; font-size: 12.5px; margin-bottom: 3px; color: var(--warn-text); }
.sp-pitem { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; padding: 2px 0; }
.sp-en { font-weight: 600; color: var(--ink); }
.sp-vrow { padding: 8px 0; border-bottom: 1px dashed var(--line); }
.sp-vrow:last-child { border-bottom: none; }
.sp-instead-row { padding: 6px 0; border-bottom: 1px dashed var(--line); }
.sp-instead-row:last-child { border-bottom: none; }
.sp-plain { color: var(--bad-text); text-decoration: line-through; }
.sp-arrow { color: var(--faint); margin: 0 4px; }
.sp-better { color: var(--good-text); font-weight: 600; }
.sp-fallback { padding: 10px 12px; border-radius: var(--r); background: var(--warn-soft); border: 1px solid #f3dcb4; }

@media (max-width: 860px) {
  /* 手机上筛选条改成上下排，否则「考试」标签栏会被挤成一列一个字 */
  .sp-filter { flex-direction: column; gap: 4px; }
  .sp-filter-l { width: auto; padding-top: 0; }
  .sp-instant-row { grid-template-columns: 54px 1fr 34px; }
}


/* ============================================================
   吸顶子目录：四条之后必须能横向滚
   ★ 2026-10-16（Speak 由 2 个 tab 扩到 4 个）：`.subtab` 是 nowrap，
     四条加起来在 375px 屏上溢出容器，而 `.subtabs` 是 flex 且没有 overflow
     ⇒ 第 4 个 tab 直接**被切出屏幕**（看得见一半、点不到），手机上尤其明显。
   ★ flex: 0 0 auto 是必须的：不然 flex 会先把各条压窄，文字 nowrap 反而溢出。
   ============================================================ */
.subtabs { overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none; }
.subtabs::-webkit-scrollbar { display: none; }
.subtab { flex: 0 0 auto; }

/* ============================================================
   跟读 / 复述（2026-10-16｜说写吧 · Speak）
   命名空间 `dr-`。与 sp- 块同一套约定：**只用主题变量**，不写死颜色。
   ★ 2026-10-16 第二轮：复述拆成 阅读复述 / 精听复述 两块 ⇒ 多了 `.dr-blocks`。
   ============================================================ */
/* 目录页：块切换器（两块并列，等分整宽） */
.dr-blocks {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2); padding: 4px;
}
.dr-block {
  appearance: none; border: 0; cursor: pointer;
  padding: 9px 12px; border-radius: 8px;
  background: transparent; color: var(--ink-2);
  font-size: 14.5px; font-weight: 700; letter-spacing: .2px;
  transition: background .15s, color .15s;
}
.dr-block:hover { color: var(--ink); }
.dr-block.is-on { background: var(--surface); color: var(--brand); box-shadow: 0 1px 2px rgba(0, 0, 0, .06); }

/* 目录页：说明卡 */
.dr-intro-ic { font-size: 26px; line-height: 1; }
.dr-steps-mini { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.dr-step-mini {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: 12.5px; color: var(--ink-2);
}
.dr-step-mini b {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--brand-soft); color: var(--brand); font-size: 11px;
}
.dr-step-arrow { color: var(--faint); font-size: 12px; }

.dr-h3 { font-size: 15px; font-weight: 700; color: var(--ink); }

/* 阶梯条：4 档**横排**（2026-10-18 由「4 张竖排卡」改来）
   ★★ 为什么不再竖排：竖排时每档都带描述 + 5 个参数片，光阶梯就吃掉一屏，
      「这一档配了什么材料」全部落到首屏之外 —— 用户不知道下面还有东西可看。
      横排之后阶梯只有一行，描述与参数进 `.dr-lvl-detail`，材料清单必然在首屏里。
   ★ 四等分铺满内容宽（不设 max-width）：下面那张 `.dr-lvl-detail` 是整宽的，
      两张宽度对齐才读成「上条下卡」；给格子设上限会让条比卡短一截，
      在桌面端尤其明显（截图里一眼就是没对齐）。 */
.dr-lvls { display: flex; gap: 8px; }
.dr-lvl {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 7px 6px 8px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); cursor: pointer;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.dr-lvl:hover { border-color: var(--brand-line); }
.dr-lvl.is-on { border-color: var(--brand); background: var(--brand-soft); box-shadow: 0 0 0 3px var(--brand-soft); }
.dr-lvl-top { display: flex; align-items: center; gap: 5px; }
.dr-lvl-code {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 30px; height: 22px; padding: 0 6px; border-radius: 6px;
  background: var(--brand-soft); color: var(--brand);
  font-size: 12px; font-weight: 800; letter-spacing: .3px;
}
.dr-lvl.is-on .dr-lvl-code { background: var(--brand); color: var(--brand-ink); }
/* 条数：裸数字（不写「共 N 篇」）—— 四格横排放不下那句话，完整说法在
   `.dr-lvl-detail` 的右端，以及每格的 title 上（读屏/悬浮都能拿到）。 */
.dr-lvl-n { font-size: 11px; font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; }
.dr-lvl.is-on .dr-lvl-n { color: var(--brand); }
/* 档名：三五个字，放不下就省略号 —— **完整档名一定会出现在下面的 detail 里** */
.dr-lvl-name {
  display: block; max-width: 100%;
  font-size: 12.5px; font-weight: 700; letter-spacing: .2px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dr-lvl.is-on .dr-lvl-name { color: var(--brand); }

/* 选中档的说明与参数区间：紧贴阶梯条，读成「上条下卡」一整块 */
.dr-lvl-detail {
  padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface-2);
}

/* 材料卡 */
.dr-list { display: grid; gap: 8px; }
.dr-mat { text-align: left; cursor: pointer; width: 100%; }
.dr-mat:hover { border-color: var(--brand-line); }

/* 步骤条 */
.dr-stepbar { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none; }
.dr-stepbar::-webkit-scrollbar { display: none; }
.dr-step {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px 6px 8px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface); color: var(--muted);
  font-size: 13px; font-weight: 600; cursor: pointer; white-space: nowrap;
}
.dr-step b {
  display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--surface-2); color: var(--muted); font-size: 11px;
}
.dr-step.is-on { background: var(--brand-soft); border-color: var(--brand-line); color: var(--brand); }
.dr-step.is-on b { background: var(--brand); color: var(--brand-ink); }
/* 到不了的那一步：**照样画出来**（点了会说明原因），只是视觉上退后一层。
   藏起来的话用户不知道后面还有什么、也不知道被什么挡住了。 */
.dr-step.is-locked { opacity: .5; border-style: dashed; }

/* ① 盲听：锁着的原文卡用灰条占位 —— **正文一个字都不进 DOM**（不是 CSS 遮住） */
.dr-lockline {
  height: 10px; border-radius: 4px; margin-top: 8px;
  background: repeating-linear-gradient(90deg, var(--surface-2) 0 18px, var(--line) 18px 22px);
}
/* ① 盲听的逐句圆点：只有句号、没有字，点了单独重听这一句 */
.dr-sdot {
  min-width: 27px; height: 27px; padding: 0 6px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface); color: var(--muted);
  font-size: 12px; font-weight: 700; cursor: pointer;
}
.dr-sdot:hover { border-color: var(--brand-line); color: var(--brand); }
.dr-sdot.is-on { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }

/* ③ 看稿对照：一句一行（文本 + 逐句重听按钮），行内换行不留空洞 */
.dr-sline { display: flex; align-items: flex-start; gap: 6px; padding: 3px 0; }
.dr-sline .dr-en { flex: 1 1 auto; min-width: 0; }

/* 步骤说明 */
.dr-stage-in {
  padding: 12px 14px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
}

/* 逐句列表 */
.dr-sentlist { display: grid; gap: 8px; }
.dr-sent {
  padding: 10px 12px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  transition: border-color .15s, background .15s;
}
.dr-sent.is-on { border-color: var(--brand); background: var(--brand-soft); }
.dr-sent.is-rec { border-color: var(--bad); background: var(--bad-soft); }
.dr-no {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; border-radius: 6px; margin-top: 2px;
  background: var(--surface-2); color: var(--faint);
  font-size: 11px; font-weight: 700;
}
.dr-en { font-size: 15.5px; line-height: 1.55; color: var(--ink); }
.dr-hid { font-size: 14px; color: var(--faint); letter-spacing: 2px; }
.dr-tip {
  margin-top: 6px; padding: 6px 9px; border-radius: 6px;
  background: var(--warn-soft); color: var(--warn-text);
  font-size: 12.5px; line-height: 1.6;
}

/* 时长对照 */
.dr-cmp { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.dr-cmp-cell {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 3px 8px; border-radius: 6px;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: 12.5px; color: var(--ink-2);
}
.dr-cmp-cell b { color: var(--faint); font-weight: 600; font-size: 11.5px; }
.dr-cmp-cell.is-ok { background: var(--good-soft); border-color: transparent; color: var(--good-text); }
.dr-cmp-cell.is-off { background: var(--bad-soft); border-color: transparent; color: var(--bad-text); }

/* 录音块：复用 sp- 那一套波形，这里只补「被录的那一句」的高亮 */
.dr-rec { border-color: var(--line); }
.dr-rec.is-rec { border-color: var(--bad); }

/* 结果 */
.dr-ul { margin: 0; padding-left: 18px; }
.dr-ul li { font-size: 13.5px; line-height: 1.7; color: var(--ink-2); }
.dr-issue {
  padding: 10px 12px; border-radius: var(--r); margin-bottom: 8px;
  background: var(--surface-2); border: 1px solid var(--line);
}

/* 精读正文 */
.dr-para { padding: 10px 0; border-bottom: 1px dashed var(--line); }
.dr-para:last-child { border-bottom: 0; padding-bottom: 0; }
.dr-para:first-child { padding-top: 0; }
.dr-role {
  display: inline-block; margin-bottom: 6px; padding: 2px 8px;
  border-radius: 999px; font-size: 11.5px; font-weight: 700;
}
.dr-role-topic { background: var(--brand-soft); color: var(--brand); }
.dr-role-support { background: var(--info-soft); color: var(--info-text); }
.dr-role-conclusion { background: var(--good-soft); color: var(--good-text); }

/* 覆盖率 */
.dr-cov { font-size: 26px; font-weight: 800; line-height: 1; color: var(--muted); }
.dr-cov.is-good { color: var(--good-text); }
.dr-cov.is-mid { color: var(--warn-text); }
.dr-cov.is-low { color: var(--bad-text); }

/* 要点逐条命中 */
.dr-pt {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 8px 0; border-bottom: 1px dashed var(--line);
}
.dr-pt:last-child { border-bottom: 0; }
.dr-pt-ic { font-weight: 800; line-height: 1.5; }
.dr-pt.is-hit .dr-pt-ic { color: var(--good-text); }
.dr-pt.is-miss .dr-pt-ic { color: var(--bad-text); }

/* 紧凑按钮：逐句那一行要塞 4 颗，btn-sm 太占地方 */
.dr-sent .btn-xs {
  padding: 3px 9px; font-size: 12px; line-height: 1.5;
  border-radius: 6px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-2); cursor: pointer; font-weight: 600;
}
.dr-sent .btn-xs:hover:not(:disabled) { border-color: var(--brand-line); color: var(--brand); }
.dr-sent .btn-xs:disabled { opacity: .55; cursor: not-allowed; }
.dr-sent .btn-xs.btn-primary { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }
.dr-sent .btn-xs.btn-soft { background: var(--brand-soft); border-color: var(--brand-line); color: var(--brand); }
.dr-sent .btn-xs.btn-ghost { background: transparent; color: var(--muted); }
.dr-sent .btn-xs.btn-danger { background: var(--bad); border-color: var(--bad); color: #fff; }

/* ============================================================
   导航「敞口」（2026-10-17 用户定）
   ————————————————————————————————————————————————————————————
   原来的选中态是「高亮底 + 一圈完整框线」：功能上够用，但它是一个**封闭的
   盒子** —— 盒子和它要说明的那块内容之间没有任何关系。用户要的是：
   目录**朝主页的那一侧不留边**，底色换成页面自己的底色，两端用内凹圆角
   过渡到条形的那根线上。读起来就像「页面从这条缝里漏出来」，
   目录与内容是**同一张纸**，而不是「贴在纸上的一个按钮」。

   三条目录共用同一条判据，只是敞口朝向不同：
     · 底部主目录（页面在它**上方**）⇒ 敞口朝上  `.tab.active::before`
     · 吸顶子目录（页面在它**下方**）⇒ 敞口朝下  `.subtab.active::before`
     · 复述里的 阅读/精听（页面在它**下方**）⇒ 敞口朝下 `.dr-block.is-on::before`

   ★ 实现只有一个套路：一个绝对定位的伪元素，用**三层背景**一次画完
     「实底 + 左右两个内凹圆角」：
       第 1、2 层 = 10×10 的径向渐变（凹角），放在敞口那一侧的两个角上
       第 3 层    = calc(100% - 20px) 宽的实底，居中
     ⇒ 伪元素比按钮左右各宽 10px、并**跨出**敞口那一侧的边缘（盖住那根线），
       按钮自己的盒子 / 内边距 / 边框一概不动 ⇒ 切换时**不会抖**。
   ⚠️ 凹角的圆心在**敞口那一侧的对角**：
       敞口朝上 ⇒ circle at 0 100% / 100% 100%（圆心在下）
       敞口朝下 ⇒ circle at 0 0 / 100% 0（圆心在上）
      方向反了会变成「外凸圆角」，读起来是张卡片，不是一道缝。
   ⚠️ 底色必须**就是页面底色 var(--bg)**。差一点点（比如用 --surface 白）
      就不成「连成一体」，会读成「贴上去的一块白片」。
   ⚠️ 那根线不能再用 border 画：`.subtabs` 是横向滚动容器，会把跨出去的
      1px 裁掉 ⇒ 线又露出来，口子被一条线封死。改成伪元素画在容器**内部**，
      选中项用 z-index 压住它。
   ⚠️ 同一份判据在 App 端有镜像（mobile/lib/widgets/wl_mouth.dart），
      改这里的半径/朝向必须同步那边，否则两端会长得不一样。

   ── 第二轮（2026-10-17 傍晚，用户反馈「还是太淡 / 还能看到一条线」）──────
   ①「一条线」的真身是**1px 边框的偏移**：绝对定位伪元素的 `bottom` 是相对
     **内边距盒**算的，而 `.subtab` 有 `border: 1px` ⇒ `bottom: -8px` 实际只
     下探了 7px，正好差最后那一行 —— 线就露在口子底下。补成 `-9px`、
     同时 `top: -1px` 把上边框那 1px 也盖住。
   ②「太淡」是因为口子的底色 = 页面底色（#f5f6fa）、条是近白（4%），
     光靠色差读不出来。现在**口子里叠一层更实的品牌淡彩**（--brand-wash），
     但**敞口那一侧的前 14px 必须仍然是页面底色** —— 否则「连成一体」不成立。
     14px 这个数不是随手取的：两个凹角各占 12px，少于 12px 就在凹角处露出
     两截不同颜色的边。
   ③「复述和真题颜色太接近」不是配色问题：`isActive` 是**前缀**匹配，
     `/speak` 是 `/speak/intensive` 的前缀 ⇒ 两格同时 `active`。
     修在 `app.js` 的 `subTabOn()`（最深前缀胜出），与配色无关。
   ④ 未选中项一律**中性**（透明底 + 灰图标）：四格各带一抹强调色时，
     眼睛先看到「四个彩色的东西」，反而认不出哪个是选中的。
   ============================================================ */

/* —— 底栏：线画在内部（0 高、绝对定位），选中项压住它 —— */
.tabbar { border-top: 0; }
.tabbar::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: var(--line); pointer-events: none; z-index: 0;
}
.tab { position: relative; z-index: 1; }
/* ★ 未选中的图标一律**中性**：四格各自带一抹强调色时，眼睛先看到「四个彩色的
   东西」，反而认不出哪个是选中的。强调色留给**页面内容**（阶梯卡、徽章），
   导航只回答一个问题：你现在在哪。 */
.tab .wl-ic { background: transparent; color: var(--muted); transition: background .16s, color .16s; }
.tab.active {
  color: var(--brand);
  background: none;          /* 底色由伪元素画（它要跨出按钮的盒子） */
  box-shadow: none;
}
/* 选中的**第二信号**：实心品牌色图标 + 白线图标。只靠一块淡彩，在浅色条上
   永远读不实（用户 2026-10-17 的原话：「底色还是太淡 不够清晰」）。 */
.tab.active .wl-ic {
  background: var(--brand); color: var(--brand-ink);
  box-shadow: 0 2px 7px rgba(79, 70, 229, .32);
}
.tab.active > span:last-child { font-weight: 800; }
.tab.active::before {
  content: '';
  position: absolute; left: -12px; right: -12px; top: -7px; bottom: -2px;
  z-index: -1; pointer-events: none;
  /* 下角收圆：不然口的底边是一条硬直线 + 阴影，读起来像「浮在条上的一张卡」
     而不是「页面凹进条里的一只口袋」。 */
  border-radius: 0 0 14px 14px;
  /* 阴影沿**口的轮廓**走（跟着 alpha 走，两个凹角也一起带上）。 */
  filter: drop-shadow(0 2px 4px rgba(23, 26, 36, .10));
  /* ★ 三层：左右两个凹角（12×12）+ 中间实底。
     前 14px 必须是 --bg：凹角就在这 14px 里，颜色不一致会在凹角处
     露出两截边（12px 的凹角 + 2px 余量）。之后才淡入品牌淡彩。 */
  background-image:
    radial-gradient(circle at 0 100%, transparent 11.4px, var(--bg) 11.4px),
    radial-gradient(circle at 100% 100%, transparent 11.4px, var(--bg) 11.4px),
    linear-gradient(to bottom, var(--bg) 0 14px, var(--brand-soft) 30px, var(--brand-wash) 46px);
  background-size: 12px 12px, 12px 12px, calc(100% - 24px) 100%;
  background-position: left top, right top, center top;
  background-repeat: no-repeat;
}

/* —— 吸顶子目录：敞口朝下（页面在它下面）—— */
/* ⚠️ 下内边距必须**钉死** 8px：口子往下探的距离由它换算。
   媒体查询不加特异性，这条写在后面就能盖住窄屏那一档的 6px。 */
.subtabs { border-bottom: 0; padding-bottom: 8px; }
.subtabs::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--line); pointer-events: none; z-index: 0;
}
/* ★ 未选中 = 一枚「没有盒子」的图标 + 文字：原来的白色小药丸 + 1px 描边让
   每一格都像一个按钮，四格并排时既挤又分不清谁被选中。 */
.subtab {
  position: relative; z-index: 1;
  background: transparent;
  border: 1px solid transparent;   /* 留 1px：去掉会让格子尺寸变化 2px */
  color: var(--muted);
}
.subtab .wl-ic { background: transparent; color: var(--muted); transition: background .16s, color .16s; }
.subtab:hover { color: var(--ink); background: rgba(23, 26, 36, .035); }
.subtab.active {
  background: none;
  border-color: transparent;  /* 敞口处与两端都不留边，形状交给伪元素 */
  color: var(--brand);
}
.subtab.active .wl-ic { background: var(--brand); color: var(--brand-ink); }
.subtab.active > span:last-child { font-weight: 800; }
/* ★★★ 口子的 `bottom` 是相对**内边距盒**算的，而这个按钮有 1px 边框：
   写 -8px 实际只下探 7px ⇒ 条的那根线（在最后 1px 上）会露出来 ——
   用户看到的「还是有一条横线与主页隔离开」就是它。所以：
     top: -1px  盖住按钮自己的上边框那 1px
     bottom: -9px = 1px 边框 + 8px 下内边距，正好压到条的下边缘
   改 padding-bottom 必须同步改这个数（-1 - padding-bottom）。 */
.subtab.active::before {
  content: '';
  position: absolute; left: -12px; right: -12px; top: -1px; bottom: -9px;
  z-index: -1; pointer-events: none;
  border-radius: 14px 14px 0 0;
  filter: drop-shadow(0 -2px 4px rgba(23, 26, 36, .08));
  background-image:
    radial-gradient(circle at 0 0, transparent 11.4px, var(--bg) 11.4px),
    radial-gradient(circle at 100% 0, transparent 11.4px, var(--bg) 11.4px),
    linear-gradient(to top, var(--bg) 0 12px, var(--brand-soft) 21px, var(--brand-wash) 32px);
  background-size: 12px 12px, 12px 12px, calc(100% - 24px) 100%;
  background-position: left bottom, right bottom, center bottom;
  background-repeat: no-repeat;
}

/* —— 复述里的「阅读 / 精听」：同一条判据，只是它嵌在内容里 ——
   这里把两块从「分段控件」改成**贴在说明卡顶上的两个 tab**：
   容器不再画底线、也不再有下圆角，说明卡自己承担下半张纸的角色。
   选中项是**卡片白**（不是页面底色）—— 因为它下面那张纸是白的，
   敞口要连的是那张卡，不是页面。 */
.dr-blocks {
  margin-bottom: 0;
  border-bottom: 0;
  border-radius: 12px 12px 0 0;
  /* 左右留 8px：口子向两侧各张开 8px，槽本身只有 6px 时会被顶到容器外。 */
  padding: 6px 8px 0;
  /* ★ 槽底用**页面底色**而不是 --surface-2：选中项是白（=下面那张卡），
     槽底要是也接近白，两个白就连成一片、读不出「选中了哪一块」。 */
  background: var(--bg);
}
.dr-block {
  position: relative; z-index: 1;
  padding: 9px 12px 8px;
  border-radius: 9px 9px 0 0;
  color: var(--muted);
}
.dr-block:hover { color: var(--ink); background: rgba(23, 26, 36, .035); }
.dr-block.is-on { background: none; box-shadow: none; color: var(--brand); font-weight: 800; }
.dr-block.is-on::before {
  content: '';
  position: absolute; left: -8px; right: -8px; top: 0; bottom: -1px;
  z-index: -1; pointer-events: none;
  border-radius: 10px 10px 0 0;
  filter: drop-shadow(0 -2px 5px rgba(23, 26, 36, .10));
  background-image:
    radial-gradient(circle at 0 0, transparent 7.4px, var(--surface) 7.4px),
    radial-gradient(circle at 100% 0, transparent 7.4px, var(--surface) 7.4px),
    linear-gradient(var(--surface), var(--surface));
  background-size: 8px 8px, 8px 8px, calc(100% - 16px) 100%;
  background-position: left bottom, right bottom, center bottom;
  background-repeat: no-repeat;
}
/* 说明卡接手下半张纸：去掉上圆角与顶边，和上面的 tab 条合成一整块 */
.dr-blocks + .dr-intro {
  border-top-color: transparent;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}
