@import url('./tokens.css');
/* =========================================================
   基金从业 · 主样式
   --------------------------------------------------
   结构原则：
   页面主体是「连续文档流」，不是一堆等大的圆角卡。
   只有真正需要被点击的东西才给卡片和阴影。
   荧光笔四色是全站唯一的高饱和额度，只用于「标记」。

   本文件在 2026-10-03 整体重写过。重建原因：
   一次编辑把文件从 1200+ 行截断到 271 行，
   丢了 153 个 class 定义却没有任何报错。
   新增 check_cssom.py 逐条验证选择器真实存在，
   这类静默损坏才算抓得住。
   ========================================================= */

/* ================= 基础 ================= */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  background: var(--paper-50);
  color: var(--ink-900);
  font-family: var(--font);
  font-size: var(--fs-md);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

/* 纸面：极淡的横纹，模拟笔记本横格，不做彩色光斑 */
body::before {
  content: ''; position: fixed; inset: 0;
  pointer-events: none; z-index: 0; opacity: .55;
  background: repeating-linear-gradient(
    to bottom, transparent 0, transparent 33px,
    rgba(20,24,29,.028) 33px, rgba(20,24,29,.028) 34px);
}
html[data-theme="night"] body::before { opacity: .5; }

button {
  font: inherit; color: inherit;
  background: none; border: none;
  padding: 0; margin: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
input, select {
  font: inherit; color: inherit;
  background: var(--paper-0);
  border: 1.5px solid var(--paper-300);
  border-radius: var(--r-sm);
  padding: 0 var(--s3);
  min-height: var(--tap);
  width: 100%;
}
input:focus, select:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}
h1, h2, h3, p, ul, ol { margin: 0; }
ul, ol { padding-left: 1.2em; }
b, strong { font-weight: 850; }
s { color: var(--ink-300); text-decoration-thickness: 1.5px; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

#app {
  position: relative; z-index: 1;
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 var(--s4) calc(96px + env(safe-area-inset-bottom));
  min-height: 100vh;
}

/* ================= 顶栏 ================= */
.topbar {
  display: flex; align-items: center; gap: var(--s3);
  padding: calc(var(--s3) + env(safe-area-inset-top)) 0 var(--s2);
}
/* 顶栏是「品牌名 + 倒计时」两行设计。单行 18px 大字会让顶栏占到 87px，
   在 390×844 屏上吃掉 10% 视口高度。这里把行高压到 ~22/18，
   顶栏整体落到 60px 上下——手机上单手可达区不被顶栏吃掉。 */
.topbar .brand {
  display: flex; align-items: center; gap: var(--s2);
  /* flex 子项默认 min-width:auto。不加这行，内部 .brand-txt 的
     省略号不生效，"距 11月28日还有 57天"会把顶栏撑到 87px 高。 */
  min-width: 0;
  font-family: var(--font-serif);
  font-size: var(--fs-lg); font-weight: 700;
  color: var(--ink-900);
}
.brand-mark {
  width: 26px; height: 26px; flex: none;
  border-radius: var(--r-xs);
  background: var(--brand); color: var(--brand-ink);
  display: grid; place-items: center;
  font-size: var(--fs-sm); font-weight: 900;
}
.brand-txt { letter-spacing: .02em; min-width: 0; }
.brand-txt > b { line-height: 1.24; }
.brand-txt > span { font-size: var(--fs-xs); line-height: 1.3; color: var(--ink-500); }
/* 坑（2026-10-03 截图核查抓到）：品牌区缺 min-width:0 时，
   "距 11月28日还有 57天" 这行副标题不收缩，把整个顶栏挤变形。
   flex 子项默认 min-width:auto，必须显式归零 + 省略号。 */
.brand-txt > span, .brand-txt > b {
  display: block;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.spacer { flex: 1 1 auto; }

.back-btn {
  margin: var(--s3) 0 0;
  font-size: var(--fs-sm); font-weight: 700;
  color: var(--ink-500);
  padding: var(--s2) 0;
  min-height: 36px;
}
.back-btn:active { color: var(--ink-900); }

/* ================= 学习路径（2026-10-03 新增）=================
   路径感 = 顺序 + 位置 + 下一站，三者缺一不可。
   原来的"八章列表"只给了位置（每章掌握度），没有顺序也没有下一站，
   所以用户看到的是一张状态表，不是一条路。

   视觉上要真的是"路"：一条连续的竖线串起八个节点。
   已过的线是实线，没走的虚线——走到哪一眼看出来，不用读数字。 */
.path-hd {
  display: flex; align-items: flex-end; gap: var(--s3);
  margin: var(--s3) 0 var(--s4);
  padding-bottom: var(--s3);
  border-bottom: 2px solid var(--ink-900);
}
.path-hd h2 {
  font-family: var(--font-serif);
  font-size: var(--fs-xl); font-weight: 800;
  margin: 0 0 2px;
}
.path-hd p {
  margin: 0;
  font-size: var(--fs-sm); color: var(--ink-500);
}
.path-hd p b { color: var(--ink-900); }
.path-pct {
  margin-left: auto;
  font-size: var(--fs-3xl); font-weight: 900;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink-900);
}
.path-pct i {
  font-style: normal;
  font-size: var(--fs-md);
  font-weight: 800;
  color: var(--ink-500);
  margin-left: 2px;
}

.path { position: relative; }

/* 连接线：两个节点之间的竖线。
   用 border-left 而不是额外元素，省一个 DOM 节点。 */
.path-link {
  width: 2px;
  height: 18px;
  margin-left: 19px;              /* 对齐节点圆点中心 */
  background: repeating-linear-gradient(
    to bottom, var(--paper-300) 0 5px, transparent 5px 10px);
}
.path-link.on {
  background: var(--c7);
}

.path-node {
  display: flex; align-items: flex-start; gap: var(--s3);
  width: 100%; max-width: 100%; min-width: 0;
  text-align: left;
  background: transparent; border: none;
  padding: var(--s3) 0;
}
/* 没碰过的节点整体压暗，让"正在打的"那一站在余光里最显眼。
   这是"下一站"能被看见的前提 —— 路径图的重点永远是当前站。 */
.path-node:not(.touched) { opacity: .5; }
.path-node.cur { opacity: 1; }

.pn-dot {
  width: 40px; height: 40px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 2.5px solid var(--paper-300);
  background: var(--paper-0);
  color: var(--ink-500);
  font-size: var(--fs-md); font-weight: 900;
  font-variant-numeric: tabular-nums;
  transition: all .2s;
}
.path-node.touched .pn-dot { border-color: var(--ch); color: var(--ch); }
.path-node.pass .pn-dot {
  background: var(--c7);
  border-color: var(--c7);
  color: #fff;
  font-size: var(--fs-lg);
}
/* 当前站：加一圈外环。不加填充色，避免和"已过"的绿点混淆 */
.path-node.cur .pn-dot {
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--ch) 20%, transparent);
}

.pn-body { flex: 1; min-width: 0; }
.pn-top {
  display: flex; align-items: baseline; gap: var(--s2);
}
.pn-top b {
  font-size: var(--fs-md); font-weight: 800;
  color: var(--ink-900);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pn-w {
  margin-left: auto; flex: none;
  font-size: var(--fs-xs); font-weight: 800;
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
.pn-stats {
  display: flex; flex-wrap: wrap; gap: var(--s3);
  margin: 4px 0 6px;
  font-size: var(--fs-xs); color: var(--ink-500);
}
.pn-stats b {
  color: var(--ink-700);
  font-variant-numeric: tabular-nums;
}
.pn-tag {
  margin-top: 5px;
  font-size: var(--fs-xs); font-weight: 750;
  color: var(--ink-500);
}
.path-node.pass .pn-tag { color: var(--c7); }
/* 当前站的标签要够重 —— 它是"你该干什么"的答案 */
.path-node.cur .pn-tag {
  color: var(--ch);
  font-weight: 900;
}

.pass-rule {
  margin: 0; padding-left: 1.15em;
  font-size: var(--fs-sm); line-height: 1.85;
  color: var(--ink-700);
}

/* ================= 底栏 ================= */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: grid; grid-template-columns: repeat(4, 1fr);
  background: color-mix(in srgb, var(--paper-50) 92%, transparent);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--paper-200);
  padding-bottom: env(safe-area-inset-bottom);
}
.tabbar .tab {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 7px 0 5px;
  min-height: var(--tap);
  font-size: var(--fs-xs); font-weight: 700;
  color: var(--ink-500);
}
.tabbar .tab .ti { font-size: 17px; line-height: 1; }
.tabbar .tab[aria-selected="true"] { color: var(--brand); }
.tabbar .tab:active { background: var(--paper-100); }

/* ================= 按钮 ================= */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: 0 var(--s5);
  border-radius: var(--r-pill);
  font-size: var(--fs-md); font-weight: 800;
  background: var(--paper-0);
  border: 1.5px solid var(--paper-300);
  color: var(--ink-900);
  box-shadow: var(--sh-1);
  transition: transform .08s, box-shadow .08s;
}
.btn:active { transform: translateY(1px); box-shadow: var(--sh-press); }
.btn.primary {
  background: var(--brand); border-color: var(--brand);
  color: var(--brand-ink);
}
.btn.tint { background: var(--paper-100); border-color: var(--paper-200); }
.btn.sm { min-height: 36px; padding: 0 var(--s3); font-size: var(--fs-sm); }
.btn.block { display: flex; width: 100%; }
.btn:disabled { opacity: .45; pointer-events: none; }

/* 底部操作条：贴在底栏之上，滚动时不遮内容 */
.done-bar {
  position: sticky; bottom: 0; z-index: 10;
  display: flex; gap: var(--s2);
  margin-top: var(--s5);
  padding: var(--s3) 0;
  background: linear-gradient(to bottom,
    transparent, var(--paper-50) 26%);
}

/* sticky 底栏要躲开固定导航栏。
   坑（2026-10-03 模考实测抓到，playwright 直接报
   "tabbar intercepts pointer events"）：
   tabbar 是 position:fixed z-index:20，.done-bar 是 sticky z-index:10。
   #app 那句 padding-bottom:96px 只给**文档流末尾**留了空，
   管不到 sticky 元素——sticky 到了自己可粘的底边就停，
   而那个底边正好在 tabbar 后面。于是长页面（模考报告、
   错题本、章节列表）滚到底时，"交卷""看结果"这些
   **结束一局的关键按钮全部点不到**。
   这是全站性问题，不止模考。

   修法：把 bottom 抬到导航栏之上。
   tabbar 没有宽屏隐藏规则（扫过全部 @media，
   4 个断点里没有一个动 .tabbar），所以不写媒体查询——
   写一个"宽屏大概是 0"的猜测，只会在平板上重新踩一遍
   按钮点不到的坑。 */
:root {
  --tabbar-h: 58px;   /* = tabbar .tab 的 min-height(48) + 上下 padding(7+5) - 2 */
}
.done-bar {
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
}

/* ================= 文本工具 ================= */
.sub { font-size: var(--fs-sm); color: var(--ink-500); line-height: 1.6; }
.note { font-size: var(--fs-xs); color: var(--ink-300); font-weight: 400; }
.wlbl {
  margin-left: auto; font-size: var(--fs-sm);
  font-weight: 800; color: var(--ink-700);
  font-variant-numeric: tabular-nums;
}
.crumb {
  font-size: var(--fs-xs); color: var(--ink-500);
  letter-spacing: .02em;
}
.seal { display: none; }
.why { color: var(--ink-700); }

/* 文档流分节：替代等大圆角卡 */
.sect {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--paper-200);
}
.sect-hd {
  margin: 0 0 var(--s3);
  font-family: var(--font-serif);
  font-size: var(--fs-lg); font-weight: 700; line-height: 1.3;
  display: flex; align-items: baseline; gap: var(--s2);
}
/* 标题栏里的跳转链接。放在标题行右侧而不是单独一个按钮——
   "看全貌"是次要动作，不该和主行动抢注意力。 */
.hd-link {
  margin-left: auto; flex: none;
  font-family: var(--font);
  font-size: var(--fs-xs); font-weight: 800;
  color: var(--ink-500);
  padding: 4px 2px;
  min-height: 28px;
}
.hd-link:active { color: var(--brand); }
.sub-hd {
  margin: var(--s5) 0 var(--s2);
  font-size: var(--fs-md); font-weight: 850;
}
.sub-hd.bad { color: var(--bad); }

.prose { font-size: var(--fs-md); line-height: 1.78; color: var(--ink-700); }
.prose p { margin: 0 0 var(--s3); }
.prose ul, .prose ol { margin: 0 0 var(--s3); }
.prose li { margin: 0 0 5px; }
.prose b { color: var(--ink-900); }

/* 荧光笔三层：锚点 / 陷阱 / 考法 */
.anchor, .trap, .exam-pred, .feedback {
  margin: var(--s3) 0;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-xs);
  font-size: var(--fs-md); line-height: 1.7;
}
.anchor   { background: var(--hl-y-soft); border-left: 5px solid var(--hl-y); }
.trap     { background: var(--hl-p-soft); border-left: 5px solid var(--hl-p); }
.exam-pred{ background: var(--hl-b-soft); border-left: 5px solid var(--hl-b); }
.feedback { background: var(--paper-100);  border-left: 5px solid var(--paper-300); }
.anchor b, .trap b, .exam-pred b, .feedback b {
  display: block; font-size: var(--fs-xs); font-weight: 850;
  color: var(--ink-500); margin-bottom: 3px; letter-spacing: .04em;
}
.anchor b:first-child, .trap b:first-child,
.exam-pred b:first-child, .feedback b:first-child { color: var(--ink-700); }

/* ================= 通用小件 ================= */
.qdot {
  display: inline-block;
  font-size: var(--fs-xs); font-weight: 800;
  padding: 1px 7px; border-radius: var(--r-xs);
  background: var(--paper-100); color: var(--ink-500);
  white-space: nowrap;
}
.lv { display: inline-block; font-size: var(--fs-xs); font-weight: 800; }
.lv-掌握, .qdot.lv-掌握 { background: var(--hl-y-soft); color: #8a6a00; }
.lv-理解, .qdot.lv-理解 { background: var(--hl-b-soft); color: #1c5c9e; }
.lv-了解, .qdot.lv-了解 { background: var(--hl-g-soft); color: #2c7a3c; }
.qdot.real { background: var(--hl-p-soft); color: #b32b56; }
html[data-theme="night"] .lv-掌握,
html[data-theme="night"] .qdot.lv-掌握 { color: var(--hl-y); }
html[data-theme="night"] .lv-理解,
html[data-theme="night"] .qdot.lv-理解 { color: var(--hl-b); }
html[data-theme="night"] .lv-了解,
html[data-theme="night"] .qdot.lv-了解 { color: var(--hl-g); }

/* 进度条：细，不做粗重条 */
.wbar {
  height: 6px; border-radius: var(--r-pill);
  background: var(--paper-200); overflow: hidden;
}
.wbar i { display: block; height: 100%; background: var(--ch, var(--brand)); }

.ring {
  --p: 0;
  width: 64px; height: 64px; flex: none;
  border-radius: 50%;
  background: conic-gradient(var(--ch, var(--brand)) calc(var(--p) * 1%), var(--paper-200) 0);
  display: grid; place-items: center;
}
.ring-info {
  width: 52px; height: 52px; border-radius: 50%;
  background: var(--paper-0);
  display: grid; place-items: center;
  font-size: var(--fs-sm); font-weight: 900;
  color: var(--ch, var(--brand));
  font-variant-numeric: tabular-nums;
}

/* toast：JS 靠 .show 类切换显隐。
   坑（2026-10-03 回归抓到）：这里原来只写了基础样式，漏了 .show 规则，
   结果 toast 一旦创建就永久可见，还因为 position:fixed 挡住底栏点击，
   regress.py 点"下一步"直接被它 intercepts pointer events 卡死 30s。
   必须写全三态：默认隐藏 + 显示态 + 永不吃指针事件。 */
.toast {
  position: fixed; left: 50%; bottom: calc(84px + env(safe-area-inset-bottom));
  transform: translateX(-50%) translateY(6px);
  z-index: 60; max-width: 88vw;
  padding: 10px var(--s4);
  border-radius: var(--r-pill);
  background: var(--ink-900); color: var(--paper-0);
  font-size: var(--fs-sm); font-weight: 700;
  box-shadow: var(--sh-3);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .18s ease, transform .18s ease, visibility .18s;
}
.toast.show {
  opacity: 1; visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* ================= 首页 ================= */
.today {
  padding: var(--s5) 0 var(--s4);
  border-bottom: 2px solid var(--ch, var(--c1));
}
.today-kicker {
  font-size: var(--fs-xs); font-weight: 850;
  color: var(--ch, var(--c1));
  letter-spacing: .06em;
}
.today-title {
  margin: var(--s2) 0 0;
  font-family: var(--font-serif);
  font-size: var(--fs-2xl); font-weight: 700; line-height: 1.25;
}
.today-sub {
  margin: var(--s2) 0 0;
  font-size: var(--fs-md); color: var(--ink-700);
}
.today-metrics {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--s2); margin: var(--s4) 0;
}
.today-metrics > div {
  padding: var(--s2) var(--s3);
  background: var(--paper-100);
  border-radius: var(--r-sm);
}
.today-metrics b {
  display: block; font-size: var(--fs-lg); font-weight: 900;
  font-variant-numeric: tabular-nums; line-height: 1.3;
}
.today-metrics span { font-size: var(--fs-xs); color: var(--ink-500); }

.stat-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 1px; background: var(--paper-200);
  border: 1px solid var(--paper-200);
  border-radius: var(--r-sm); overflow: hidden;
}
.stat-box { background: var(--paper-0); padding: var(--s3) var(--s4); }
.stat-box b {
  display: block; font-size: var(--fs-xl); font-weight: 900;
  font-variant-numeric: tabular-nums; line-height: 1.2;
}
.stat-box span { font-size: var(--fs-xs); color: var(--ink-500); }

/* ---- 今日三关（2026-10-03 新增）----
   关卡不是卡片，是行。理由和 .ch-btn 一样：
   三个同类的东西要能一眼扫完，卡片会把它们变成三块色斑，
   反而看不出"过了几关"。行式 + 左侧序号 = 一列进度。
   过关的那一行压暗 + 打勾，让"已过"和"待过"在余光里就能分开。 */
.stage {
  display: flex; align-items: center; gap: var(--s3);
  width: 100%; max-width: 100%; min-width: 0;
  text-align: left;
  background: transparent; border: none;
  border-bottom: 1px solid var(--paper-200);
  padding: var(--s3) 0;
  transition: opacity .18s;
}
.stage:active { background: var(--paper-100); }
.stage-no {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--c1) 14%, transparent);
  color: var(--c1);
  font-size: var(--fs-md); font-weight: 900;
  font-variant-numeric: tabular-nums;
}
.stage.ok .stage-no {
  background: color-mix(in srgb, var(--c7) 16%, transparent);
  color: var(--c7);
  font-size: var(--fs-lg);
}
.stage-txt { flex: 1; min-width: 0; }
.stage-txt b {
  display: block;
  font-size: var(--fs-md); font-weight: 800;
  color: var(--ink-900);
  /* 关卡名可能长（"合上书想 5 题"之外还有更长的），
     超出要截断，不能把右侧计数挤走 */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.stage-txt span {
  display: block;
  margin-top: 1px;
  font-size: var(--fs-sm); color: var(--ink-500);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.stage-txt .wbar { margin-top: 6px; }
.stage-right {
  flex: none;
  font-size: var(--fs-sm); font-weight: 800;
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
/* 过关的整行压暗：这是"已过"最省字的表达，
   比加灰底更轻，也不会让下面的未过行看起来更重要 */
.stage.ok { opacity: .55; }
.stage.ok .stage-txt b { text-decoration: line-through; text-decoration-thickness: 1.5px; }

/* 章节列表：行式，不用卡片 */
.ch-map { display: grid; gap: 0; }
.ch-btn {
  display: flex; align-items: center; gap: var(--s3);
  width: 100%; max-width: 100%;
  min-width: 0;                 /* flex 子项默认不收缩，nowrap 时会撑破容器 */
  text-align: left;
  background: transparent; border: none;
  border-bottom: 1px solid var(--paper-200);
  padding: var(--s3) 0;
  overflow: hidden;
}
.ch-btn:active { background: var(--paper-100); }
.ch-no {
  width: 30px; height: 30px; flex: none;
  border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--ch) 14%, transparent);
  color: var(--ch);
  display: grid; place-items: center;
  font-weight: 850; font-variant-numeric: tabular-nums;
}
.ch-meta { flex: 1 1 auto; min-width: 0; }
.ch-meta b {
  display: block; font-size: var(--fs-md); font-weight: 800;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ch-meta span {
  display: block; font-size: var(--fs-xs); color: var(--ink-500);
  margin-bottom: 5px;
}
.ch-btn .wlbl { flex: none; margin-left: 0; }

.rank-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--fs-xs); font-weight: 800;
  padding: 2px 9px; border-radius: var(--r-pill);
  background: var(--brand-soft); color: var(--brand);
}
.flame { font-style: normal; }
.streak-row { display: flex; align-items: center; gap: var(--s2); }
.day-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--paper-300);
}
.day-dot.on { background: var(--ch, var(--brand)); }

/* ================= 学习：考点列表 ================= */
.point-list { display: grid; gap: 0; }
.point-item {
  display: flex; align-items: center; gap: var(--s3);
  width: 100%; min-width: 0;
  text-align: left;
  background: transparent; border: none;
  border-bottom: 1px solid var(--paper-200);
  padding: var(--s3) 0;
}
.point-item:active { background: var(--paper-100); }
.pi-no {
  width: 26px; height: 26px; flex: none;
  display: grid; place-items: center;
  font-size: var(--fs-xs); font-weight: 850;
  color: var(--ink-500); background: var(--paper-100);
  border-radius: var(--r-xs);
  font-variant-numeric: tabular-nums;
}
.pi-name {
  flex: 1 1 auto; min-width: 0;
  font-size: var(--fs-md); font-weight: 700;
}
.pi-mark {
  flex: none;
  font-size: var(--fs-xs); font-weight: 700;
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
.pi-mark.done { color: var(--ok); }

/* ================= 讲解页 ================= */
.lesson { padding-top: var(--s3); }
.lesson-hd { margin-bottom: var(--s3); }
.lesson-hd h1 {
  margin: var(--s2) 0;
  font-family: var(--font-serif);
  font-size: var(--fs-2xl); font-weight: 700; line-height: 1.3;
}
.lesson-body { padding: var(--s4) 0 var(--s5); max-width: var(--docw); }
/* 讲义是拿来读的，字号比功能页大一级 */
.lesson-body .prose p,
.lesson-body .prose li { font-size: var(--fs-lg); }

/* ================= 题库 / 答题 ================= */
.q-head {
  display: flex; align-items: baseline; gap: var(--s2);
  margin-bottom: var(--s2);
}
.q-count {
  font-size: var(--fs-xs); font-weight: 850;
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
.timer {
  margin-left: auto;
  font-size: var(--fs-xs); font-weight: 800;
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
.q-progress { margin: var(--s2) 0 var(--s4); }
.q-stem {
  font-size: var(--fs-lg); font-weight: 700; line-height: 1.6;
  margin-bottom: var(--s4);
}
.q-tagline {
  font-size: var(--fs-sm); color: var(--ink-500);
  margin-top: var(--s2);
}

.opts { display: grid; gap: var(--s2); }
/* 选项做成纸条：左侧竖条代替完整描边 */
.opt {
  display: flex; align-items: flex-start; gap: var(--s3);
  width: 100%; min-width: 0; text-align: left;
  padding: var(--s3) var(--s3) var(--s3) var(--s2);
  background: var(--paper-0);
  border: 1.5px solid var(--paper-200);
  border-left: 5px solid var(--paper-300);
  border-radius: var(--r-xs);
  font-size: var(--fs-md); line-height: 1.6;
  transition: border-color .12s, background .12s;
}
.opt:active { background: var(--paper-100); }
.opt-key {
  flex: none;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: var(--r-xs);
  background: var(--paper-100); color: var(--ink-500);
  font-size: var(--fs-xs); font-weight: 850;
}
.opt.right { border-color: var(--ok); border-left-color: var(--ok); background: var(--hl-g-soft); }
.opt.wrong { border-color: var(--bad); border-left-color: var(--bad); background: var(--hl-p-soft); }
.opt.right .opt-key { background: var(--ok); color: #fff; }
.opt.wrong .opt-key { background: var(--bad); color: #fff; }

/* ---- 答题反馈（2026-10-03 新增）----
   原来答完立刻全量重绘，选项来不及展示"对/错"就被换掉，
   于是点一下什么也没留下。现在先在原 DOM 上标记 + 播动画，
   停 420/760ms 再进下一题，所以这几条样式是那段停顿里给人看的。 */
.opt.locked { pointer-events: none; }
.opt.locked:not(.right):not(.wrong) { opacity: .5; }
/* 没被选中也不对的选项：压暗，让眼睛只落在两个关键项上 */
.opt.right::after,
.opt.wrong::after {
  margin-left: auto; align-self: center;
  font-size: var(--fs-lg); font-weight: 900; line-height: 1;
}
.opt.right::after { content: '✓'; color: var(--ok); }
.opt.wrong::after { content: '✗'; color: var(--bad); }

/* ================= 反馈特效层 ================= */
/* fx.js 用 WAAPI 挂的一次性动画元素。它们必须脱离文档流、
   绝对定位、不吃指针事件，否则会挡住下面的按钮。 */
.fx-burst {
  position: absolute;
  left: 50%; top: 8px;
  z-index: 5;
  pointer-events: none;
  font-size: var(--fs-xl); font-weight: 900;
  color: var(--warn);
  text-shadow: 0 2px 10px rgba(0, 0, 0, .18);
  white-space: nowrap;
}
.fx-points {
  position: absolute;
  right: 10px; top: 4px;
  z-index: 5;
  pointer-events: none;
  font-size: var(--fs-md); font-weight: 900;
  color: var(--ok);
  text-shadow: 0 1px 6px rgba(0, 0, 0, .14);
}
/* fx-burst / fx-points 需要一个能定位的祖先 */
.opt, .sb-opt, .cb-card, .nc-card, .mode { position: relative; }

/* ---- 被击中的红闪（2026-10-03 新增）----
   答错时全屏盖一层红闪，占满视野。
   关键约束：必须 pointer-events:none 且极短（420ms）——
   长了就从"反馈"变成"惩罚"，用户会直接不玩了。
   学习类产品的失败反馈要"难过但能继续"，这是 Duolingo 的核心取舍。 */
.fx-hit-veil {
  position: fixed;
  inset: 0;
  z-index: 999;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center,
      rgba(193, 48, 38, .05) 0%,
      rgba(193, 48, 38, .30) 100%);
}

/* ---- 开放回忆题 ----
   开放题没有四个选项，视觉重心完全落在"你写下的字"上。
   所以输入框要够大、要有行、要有等宽感——让人愿意认真写。 */
.rc-card {
  background: var(--paper-0);
  border: 1.5px solid var(--paper-200);
  border-left: 5px solid var(--brand);
  border-radius: var(--r-sm);
  padding: var(--s4);
  box-shadow: 0 1px 0 var(--paper-200);
}
.rc-kind {
  display: inline-block;
  font-size: var(--fs-xs); font-weight: 850;
  color: var(--brand);
  background: var(--paper-100);
  border-radius: var(--r-xs);
  padding: 2px 9px;
  margin-bottom: var(--s3);
}
.rc-q {
  font-family: var(--font-serif);
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: 1.65;
  color: var(--ink-900);
  margin: 0 0 var(--s3);
}
/* 挖空题：句子里的空用下划线标出来，
   这比"___"更像"这里要填" */
.rc-cloze {
  font-size: var(--fs-md);
  line-height: 2.05;
  color: var(--ink-700);
  margin: 0 0 var(--s3);
}
.rc-cloze b {
  color: var(--brand);
  font-weight: 900;
  border-bottom: 2.5px solid var(--brand);
  padding: 0 22px 2px;
  margin: 0 3px;
  /* 下划线本身要像"待填的空"，不能太花 */
  background: linear-gradient(transparent 62%, rgba(0,0,0,.045) 62%);
}
.rc-hint {
  font-size: var(--fs-sm);
  color: var(--ink-500);
  margin: 0 0 var(--s3);
  padding-left: var(--s3);
  border-left: 3px solid var(--paper-200);
}
.rc-input {
  width: 100%;
  min-height: 3.2rem;
  padding: var(--s3);
  font-size: var(--fs-lg);
  font-weight: 650;
  line-height: 1.7;
  font-family: var(--font-serif);
  color: var(--ink-900);
  background: var(--paper-0);
  border: 2px solid var(--brand);
  border-radius: var(--r-sm);
  resize: vertical;
}
.rc-input::placeholder { color: var(--ink-300); font-weight: 500; }
.rc-input:focus {
  outline: none;
  border-color: var(--ink-700);
  box-shadow: 0 0 0 3px rgba(45,140,110,.14);
}
/* 默写题输入框更高：要多写几个关键词 */
.rc-input.tall { min-height: 6.5rem; }
/* 手机上 textarea 字号小于 16px 会触发自动放大，破坏布局 */
@media (max-width: 480px) {
  .rc-input { font-size: 16px; }
}

/* 排序题：已选区 + 待选区 */
.rc-order-picked { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--s3); }
.rc-order-slot {
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s3);
  min-height: 3rem;
  background: var(--paper-100);
  border: 1.5px dashed var(--paper-300, #d8dde3);
  border-radius: var(--r-sm);
  font-size: var(--fs-md);
  color: var(--ink-300);
  text-align: left;
  width: 100%;
}
.rc-order-slot.filled {
  background: var(--paper-0);
  border-style: solid;
  border-color: var(--brand);
  color: var(--ink-900);
  font-weight: 650;
}
.rc-order-no {
  width: 22px; height: 22px; flex: 0 0 22px;
  display: grid; place-items: center;
  font-size: var(--fs-xs); font-weight: 900;
  border-radius: 50%;
  background: var(--brand); color: #fff;
}
.rc-order-txt { flex: 1; min-width: 0; }
.rc-order-x {
  flex: 0 0 auto;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  font-size: 17px; line-height: 1;
  color: var(--ink-500);
  border-radius: 50%;
  transition: background .15s, color .15s;
}
.rc-order-x:hover { background: var(--bad-bg); color: var(--bad); }
/* 可撤销的槽位：给出可点的暗示，不然用户不知道能撤 */
.rc-order-slot.live { cursor: pointer; }
.rc-order-slot.live:hover { border-color: var(--bad); }
.rc-order-tools { display: flex; gap: var(--s2); margin-top: var(--s3); }
.rc-order-tools .btn { flex: 1; }
.rc-order-bank { display: flex; flex-direction: column; gap: 6px; }
.rc-order-chip {
  padding: var(--s3);
  font-size: var(--fs-md);
  text-align: left;
  background: var(--paper-0);
  border: 1.5px solid var(--paper-200);
  border-radius: var(--r-sm);
  color: var(--ink-700);
  box-shadow: 0 1px 0 var(--paper-200);
}
.rc-order-chip:active { transform: translateY(-1px); }

/* 开放题判定结果 */
.rc-result {
  margin-top: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-sm);
  font-size: var(--fs-md);
  line-height: 1.7;
}
.rc-result.ok { background: rgba(45,140,110,.09); border-left: 4px solid var(--ok); }
.rc-result.bad { background: rgba(193,48,38,.07); border-left: 4px solid var(--bad); }
.rc-answer {
  display: block;
  margin-top: 6px;
  font-family: var(--font-serif);
  font-weight: 800;
  color: var(--ink-900);
}
/* 漏掉的关键词逐个列出来——"你答对了 3 个，漏了这 1 个"
   比只说"错了"有用得多，也比"全对/全错"更有信息量 */
.rc-missed {
  margin-top: 6px;
  font-size: var(--fs-sm);
  color: var(--bad);
  line-height: 1.7;
}
.rc-missed b {
  background: rgba(193,48,38,.1);
  padding: 1px 6px;
  border-radius: var(--r-xs);
  margin-right: 4px;
}

/* 正确项的呼吸描边：答对后短暂发光，和 WAAPI 的 scale 叠在一起 */
@keyframes okGlow {
  0%   { box-shadow: 0 0 0 0 rgba(45, 140, 110, 0); }
  40%  { box-shadow: 0 0 0 6px rgba(45, 140, 110, .18); }
  100% { box-shadow: 0 0 0 0 rgba(45, 140, 110, 0); }
}
.opt.right { animation: okGlow .5s ease-out; }


.result-hero {
  margin: var(--s4) 0;
  padding: var(--s4) 0;
  border-top: 1px solid var(--paper-200);
  border-bottom: 1px solid var(--paper-200);
  text-align: center;
}
.rh-lbl { font-size: var(--fs-sm); color: var(--ink-500); }
.rh-num {
  font-size: var(--fs-3xl); font-weight: 900; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.rh-num.good { color: var(--ok); }
.rh-num.bad { color: var(--bad); }

/* ================= 玩法入口 ================= */
.mode-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--s2);
}
.mode {
  position: relative;
  display: flex; flex-direction: column; gap: 4px;
  padding: var(--s4);
  text-align: left;
  background: var(--paper-0);
  border: 1.5px solid var(--paper-200);
  border-top: 5px solid var(--mc, var(--brand));
  border-radius: var(--r-sm);
  min-height: 104px;
  overflow: hidden;
  transition: transform .1s ease;
}
.mode:active { transform: translateY(2px); background: var(--paper-100); }
.mode.wide { grid-column: 1 / -1; }
.mode-ico {
  width: 36px; height: 36px;
  border-radius: var(--r-sm);
  display: grid; place-items: center;
  font-size: 19px; line-height: 1;
  margin-bottom: 2px;
  /* 坑：--mc 可能是 var(--c4) 这类变量引用，
     在 background 里能解析，但 color-mix 里嵌套 var() 会失败。
     所以 JS 那边把 --mc-soft 算成字面量传进来，这里直接用。 */
  background: var(--mc-soft, var(--paper-100));
  color: var(--mc, var(--ink-700));
}
.mode-txt {
  font-size: var(--fs-md); font-weight: 800;
  font-family: var(--font-serif);
}
.mode .sub { font-size: var(--fs-xs); line-height: 1.5; }
.mode.primary-mode {
  grid-column: 1 / -1;
  background: var(--brand-soft);
  border-color: color-mix(in srgb, var(--brand) 30%, transparent);
}
.mode-go { margin-left: auto; font-size: var(--fs-xs); color: var(--ink-300); }

/* ================= 记忆对撞 ================= */
.mem-grid {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--s2);
}
.mem-card {
  aspect-ratio: 3 / 4;
  border-radius: var(--r-sm);
  background: var(--paper-0);
  border: 1.5px solid var(--paper-300);
  padding: var(--s2);
  font-size: var(--fs-sm); font-weight: 800; line-height: 1.4;
  display: grid; place-items: center;
  text-align: center;
  overflow: hidden;
}
.mem-face { word-break: break-all; }
.mem-stats { display: flex; gap: var(--s4); margin: var(--s3) 0; }
.mem-stat b {
  display: block; font-size: var(--fs-lg); font-weight: 900;
  font-variant-numeric: tabular-nums;
}
.mem-stat span { font-size: var(--fs-xs); color: var(--ink-500); }

/* ================= 错题归因 ================= */
.attrib-hd { margin-bottom: var(--s3); }
.attrib-opts { display: grid; gap: var(--s2); }
.kv {
  display: flex; justify-content: space-between; gap: var(--s3);
  padding: var(--s2) 0;
  border-bottom: 1px solid var(--paper-200);
  font-size: var(--fs-sm);
}
.kv b { font-variant-numeric: tabular-nums; }
.set-row {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--paper-200);
  min-height: var(--tap);
}
.set-row .grow { flex: 1 1 auto; min-width: 0; }
.set-row b { display: block; font-size: var(--fs-md); }

/* 开关：纯 CSS，不用 JS 改 class */
.toggle {
  flex: none;
  width: 46px; height: 27px; flex: none;
  border-radius: var(--r-pill);
  background: var(--paper-300);
  position: relative;
  transition: background .16s;
}
.toggle::after {
  content: ''; position: absolute;
  top: 3px; left: 3px;
  width: 21px; height: 21px; border-radius: 50%;
  background: #fff;
  box-shadow: var(--sh-1);
  transition: transform .16s;
}
.toggle[aria-checked="true"] { background: var(--ok); }
.toggle[aria-checked="true"]::after { transform: translateX(19px); }

.memo-item {
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--paper-200);
  font-size: var(--fs-sm);
}
.marks.length { display: none; }

/* ================= 短内容页撑满 =================
   案情一小段 + 选项两三个，总高度只有半屏。
   做法是让「操作区」填掉中间多余高度，而不是把它推到最底——
   推到最底会在中间留一大块刺眼的空白，比分两截更难看。 */
.gm-fill {
  min-height: calc(100vh - 96px - env(safe-area-inset-bottom) - 40px);
  display: flex;
  flex-direction: column;
}
.gm-fill .sb-steps { margin-bottom: var(--s2); }
.gm-fill .sb-step,
.gm-fill .cb-hand { flex: 1 0 auto; align-content: start; }
/* 数字卡内容太少。原来用 margin-top:auto 把输入区推到底，
   结果题干和输入区之间裂开一大块空白（截图核查抓到）。
   只把空白转移到下半屏也不算修好——正确做法是让整张卡
   （题干 + 输入 + 提示）作为一组在可用高度里垂直居中，
   视线是"题干 → 想起来 → 填"一条线，上下留白对称。 */
.gm-fill.nc-card { justify-content: center; }
.gm-fill .dl-input { margin-top: var(--s3); }
/* 提交按钮：390px 宽下"提交"两字会被挤成竖排，加 nowrap 保住单行 */
.gm-fill .dl-input .btn { white-space: nowrap; flex: none; }

/* ================= 合规沙盘 ================= */
.sb-case {
  padding: var(--s4) 0 var(--s3);
  border-bottom: 2px solid var(--ch, var(--c5));
}
.sb-hd { margin-bottom: var(--s2); }
.sb-hd h1 {
  margin: 4px 0 0;
  font-family: var(--font-serif);
  font-size: var(--fs-xl); font-weight: 700; line-height: 1.3;
}
.sb-tag {
  display: inline-block;
  font-size: var(--fs-xs); font-weight: 850;
  color: var(--ch, var(--c5));
  background: color-mix(in srgb, var(--ch, var(--c5)) 13%, transparent);
  padding: 2px 9px; border-radius: var(--r-pill);
}
.sb-brief {
  font-size: var(--fs-md); line-height: 1.7; color: var(--ink-700);
}
.sb-facts {
  margin: var(--s3) 0 0;
  padding: var(--s3) var(--s4);
  background: var(--paper-100);
  border-left: 4px solid var(--ch, var(--c5));
  border-radius: var(--r-xs);
  list-style: none;
}
.sb-facts li {
  font-size: var(--fs-sm); line-height: 1.75; color: var(--ink-700);
}
.sb-facts li + li { margin-top: 2px; }

/* 步骤条：几个小横杠，不做圆点连线 */
.sb-steps {
  display: flex; align-items: center; gap: 5px;
  padding: var(--s4) 0 var(--s3);
}
.sb-steps i {
  display: block; height: 4px; flex: 0 0 22px;
  border-radius: var(--r-pill);
  background: var(--paper-200);
  transition: background .18s;
}
.sb-steps i.done { background: var(--ch, var(--brand)); }
.sb-steps i.now  { background: var(--ch, var(--brand)); box-shadow: 0 0 0 2px color-mix(in srgb, var(--ch, var(--brand)) 22%, transparent); }
.sb-steps span {
  margin-left: var(--s2);
  font-size: var(--fs-xs); font-weight: 700; color: var(--ink-500);
}

.sb-stepno {
  display: inline-grid; place-items: center;
  width: 24px; height: 24px; flex: none;
  border-radius: var(--r-xs);
  background: var(--brand); color: var(--brand-ink);
  font-size: var(--fs-xs); font-weight: 900;
  margin-right: var(--s2);
}
.sb-know {
  margin: var(--s2) 0 var(--s3);
  font-size: var(--fs-sm); color: var(--ink-700);
}
.sb-know b {
  display: inline-block;
  font-size: var(--fs-xs); font-weight: 850;
  color: var(--ink-500);
  background: var(--paper-100);
  padding: 1px 7px; border-radius: var(--r-xs);
  margin-right: 6px;
}
.sb-opts { display: grid; gap: var(--s2); }
.sb-opt {
  display: flex; align-items: flex-start; gap: var(--s3);
  width: 100%; min-width: 0; text-align: left;
  padding: var(--s3);
  background: var(--paper-0);
  border: 1.5px solid var(--paper-200);
  border-left: 5px solid var(--paper-300);
  border-radius: var(--r-xs);
  font-size: var(--fs-md); line-height: 1.6;
}
.sb-opt:active { background: var(--paper-100); }
.sb-key {
  flex: none;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: var(--r-xs);
  background: var(--paper-100); color: var(--ink-500);
  font-size: var(--fs-xs); font-weight: 850;
}

/* 判定结果：荧光笔一整条，不是小标签 */
.sb-res {
  margin-top: var(--s4);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-xs);
  font-size: var(--fs-md); line-height: 1.7;
}
.sb-res.ok  { background: var(--hl-g-soft); border-left: 5px solid var(--hl-g); }
.sb-res.bad { background: var(--hl-p-soft); border-left: 5px solid var(--hl-p); }
.sb-res b { display: block; font-size: var(--fs-sm); font-weight: 850; margin-bottom: 3px; }
.sb-fix { margin-top: 5px; font-size: var(--fs-sm); color: var(--ink-700); }

.sb-verdict {
  margin: var(--s4) 0;
  padding: var(--s5) var(--s4);
  text-align: center;
  border-radius: var(--r-sm);
}
.sb-verdict.good { background: var(--hl-g-soft); }
.sb-verdict.mixed { background: var(--hl-y-soft); }
.sb-seal {
  display: inline-block;
  font-size: var(--fs-xs); font-weight: 850;
  padding: 3px 12px; border-radius: var(--r-pill);
  background: var(--ink-900); color: var(--paper-0);
  margin-bottom: var(--s3);
}
.sb-verdict h2 {
  font-family: var(--font-serif);
  font-size: var(--fs-xl); font-weight: 700; line-height: 1.3;
}
.sb-verdict p { margin-top: var(--s2); font-size: var(--fs-sm); color: var(--ink-700); }
.sb-take {
  margin-top: var(--s3);
  padding: var(--s3);
  background: var(--paper-0);
  border-left: 4px solid var(--paper-300);
  border-radius: var(--r-xs);
  font-size: var(--fs-sm); line-height: 1.7;
  text-align: left;
}

/* 逐步复盘 */
.sb-review {
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--paper-200);
}
.sb-review.ok  { border-left: 4px solid var(--ok);  padding-left: var(--s3); }
.sb-review.bad { border-left: 4px solid var(--bad); padding-left: var(--s3); }
.sb-rv-hd {
  display: flex; align-items: baseline; gap: var(--s2);
  font-size: var(--fs-md); font-weight: 700; line-height: 1.5;
}
.sb-rv-no {
  flex: none;
  font-size: var(--fs-xs); font-weight: 850; color: var(--ink-300);
  font-variant-numeric: tabular-nums;
}
.sb-rv-a, .sb-rv-c, .sb-rv-w {
  margin-top: 5px; font-size: var(--fs-sm); line-height: 1.7;
  color: var(--ink-700);
}
.sb-rv-c { color: var(--ok); font-weight: 700; }
.sb-rv-w {
  padding: var(--s2) var(--s3);
  background: var(--paper-100);
  border-radius: var(--r-xs);
}

/* ================= 条款连击 ================= */
.cb-bar {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s4) 0 var(--s3);
  border-bottom: 1px solid var(--paper-200);
}
.cb-stat b, .cb-mult b {
  display: block; font-size: var(--fs-xl); font-weight: 900;
  font-variant-numeric: tabular-nums; line-height: 1.2;
}
.cb-stat span, .cb-mult span { font-size: var(--fs-xs); color: var(--ink-500); }
.cb-mult b { color: var(--mc, var(--ink-500)); }
.cb-chain {
  margin-left: auto;
  font-size: var(--fs-sm); font-weight: 850;
  color: var(--mc, var(--brand));
}
.cb-tip {
  margin: var(--s3) 0;
  font-size: var(--fs-sm); line-height: 1.65; color: var(--ink-500);
}
.cb-tip b { color: var(--ink-900); }

.cb-last {
  margin: var(--s3) 0;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-xs);
  border-left: 5px solid var(--paper-300);
  background: var(--paper-100);
}
.cb-last.same { border-left-color: var(--hl-b); background: var(--hl-b-soft); }
.cb-last.link { border-left-color: var(--hl-y); background: var(--hl-y-soft); }
.cb-last-hd {
  display: flex; align-items: center; gap: var(--s2);
  font-size: var(--fs-md); font-weight: 800;
}
.cb-badge {
  font-size: var(--fs-xs); font-weight: 850;
  padding: 1px 8px; border-radius: var(--r-pill);
  background: var(--paper-0); color: var(--ink-700);
}
.cb-badge.link { background: var(--hl-y); color: var(--ink-900); }
.cb-last p {
  margin-top: 4px; font-size: var(--fs-sm); line-height: 1.65;
  color: var(--ink-700);
}
.cb-link {
  margin-top: 6px; font-size: var(--fs-sm); font-weight: 700;
  color: #8a6a00;
}
.cb-gain {
  margin-top: 6px;
  font-size: var(--fs-lg); font-weight: 900;
  color: var(--ok);
  font-variant-numeric: tabular-nums;
}

/* 手牌：两列网格。
   原来这里是横向滑动 + 固定牌宽，那在 390px 屏上正好占满整屏，
   玩家看不到第二张牌、不知道手上有什么——而这个玩法的核心决策
   恰恰是「该接哪张」，必须一眼看全。两列同时解决可见性和拇指可达。 */
.cb-hand {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s2);
  align-content: flex-start;
}
.cb-card {
  position: relative;
  display: flex;
  flex-direction: column;
  text-align: left;
  min-width: 0;              /* grid 子项默认不收缩，长词会撑破容器 */
  min-height: 8.5rem;
  padding: var(--s3) var(--s3) var(--s3) var(--s4);
  background: var(--paper-0);
  border: 1.5px solid var(--paper-200);
  border-left: 5px solid var(--mc);
  border-radius: var(--r-sm);
  box-shadow: 0 1px 0 var(--paper-200);
  transition: transform .1s;
}
.cb-card:active { transform: translateY(-3px); }
/* 出牌后的输入锁（2026-10-03 加）。
   停顿期间牌还能点的话，手快的用户能在一瞬间把整手牌打完，
   音阶/动画/飘字全被下一次点击的重绘吃掉，反馈层等于没做。
   压暗 + 禁用指针，让人一眼看出"这一小会儿在结算"。 */
.cb-card.locked {
  pointer-events: none;
  opacity: .55;
  filter: saturate(.7);
}
.cb-dim {
  display: inline-block;
  align-self: flex-start;
  font-size: var(--fs-xs); font-weight: 850;
  color: var(--mc); background: var(--paper-100);
  border-radius: var(--r-xs); padding: 1px 8px;
  margin-bottom: 5px;
}
.cb-card b { display: block; font-size: var(--fs-md); font-weight: 850; }
.cb-body {
  display: block; margin-top: 3px;
  font-size: var(--fs-sm); line-height: 1.6; color: var(--ink-700);
}
/* 可接上一张：唯一的「提示性」视觉 */
.cb-hint {
  position: absolute; right: var(--s3); top: var(--s3);
  font-size: var(--fs-xs); font-weight: 850;
  background: var(--hl-y); color: var(--ink-900);
  border-radius: var(--r-pill); padding: 2px 8px;
}
/* 牌打完了。两列网格下要占满两列，否则会被挤成一格宽 */
.cb-empty {
  grid-column: 1 / -1;
  padding: var(--s5) var(--s4);
  text-align: center;
  background: var(--paper-100);
  border-radius: var(--r-sm);
  font-size: var(--fs-lg); font-weight: 800; color: var(--ink-700);
}

/* ================= 判例推理 ================= */
.rc-scene {
  padding: var(--s4) 0;
  border-bottom: 2px solid var(--paper-200);
}
.rc-text {
  margin-top: var(--s2);
  font-size: var(--fs-md); line-height: 1.75; color: var(--ink-700);
}

/* ================= 数字记忆卡 ================= */
.nc-card {
  padding: var(--s4) 0;
  border-bottom: 2px solid var(--hl-b);
}
.nc-card h1 {
  margin: var(--s2) 0 0;
  font-family: var(--font-serif);
  font-size: var(--fs-xl); font-weight: 700; line-height: 1.35;
}
.nc-ask {
  margin: var(--s4) 0 var(--s2);
  font-size: var(--fs-md); font-weight: 700;
}
.dl-input { display: flex; gap: var(--s2); }
.dl-input input { flex: 1 1 auto; min-width: 0; }
.dl-hint { margin-top: var(--s2); font-size: var(--fs-xs); color: var(--ink-500); }

/* 揭晓：答案是这张卡的主角，用荧光笔涂 */
.nc-reveal {
  margin-top: var(--s4);
  padding: var(--s4);
  border-radius: var(--r-sm);
  text-align: center;
}
.nc-reveal.ok  { background: var(--hl-g-soft); }
.nc-reveal.bad { background: var(--hl-p-soft); }
.nc-truth b {
  font-size: var(--fs-2xl); font-weight: 900;
  font-variant-numeric: tabular-nums; line-height: 1.2;
}
.nc-reveal.ok  .nc-truth b { color: var(--ok); }
.nc-reveal.bad .nc-truth b { color: var(--bad); }
.nc-vs {
  margin-top: var(--s2);
  font-size: var(--fs-sm); color: var(--ink-500);
}

/* ================= 动画 ================= */
@keyframes rise {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}
@keyframes shake {
  0%,100% { transform: translateX(0); }
  22% { transform: translateX(-5px); }
  46% { transform: translateX(5px); }
  70% { transform: translateX(-3px); }
}
@keyframes pulse {
  0%,100% { opacity: 1; }
  50% { opacity: .55; }
}
.fade-in { animation: rise .3s cubic-bezier(.2,1,.35,1); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

@media (min-width: 620px) {
  #app { padding-left: var(--s5); padding-right: var(--s5); }
}

/* ================= 顶栏小件 ================= */
.xp-mini {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--fs-sm); font-weight: 850;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}
.xp-mini i { font-style: normal; font-size: var(--fs-xs); }
.flame {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--fs-sm); font-weight: 850;
  font-variant-numeric: tabular-nums;
}
.flame i { font-style: normal; }
.flame.frozen { color: var(--info); }

/* ================= 卡片（统计页用，页面主体仍走文档流） ================= */
.card {
  background: var(--paper-0);
  border: 1px solid var(--paper-200);
  border-radius: var(--r-sm);
  padding: var(--s4);
}
.card-hd {
  display: flex; align-items: center; gap: var(--s2);
  margin-bottom: var(--s3);
}
.card-hd h2 {
  font-family: var(--font-serif);
  font-size: var(--fs-lg); font-weight: 700;
}

/* 掌握度圆环 */
.ring-row {
  display: flex; align-items: center; gap: var(--s4);
}
.ring-row .ring-info {
  display: flex; flex-direction: column; gap: 2px;
  width: auto; height: auto; background: none;
  text-align: left;
}
.ring-row .ring-info b {
  font-family: var(--font-serif);
  font-size: var(--fs-lg); font-weight: 700;
  color: var(--ink-900);
}
.ring-row .ring-info span { font-size: var(--fs-sm); color: var(--ink-500); }

/* 徽章墙 */
.badge-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--s2);
}
.badge {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: var(--s3) var(--s2);
  text-align: center;
  background: var(--paper-100);
  border-radius: var(--r-sm);
}
.badge.locked { opacity: .45; }
.badge .bi { font-size: 21px; line-height: 1.2; }
.badge b { font-size: var(--fs-xs); font-weight: 800; line-height: 1.35; }

/* ================= 错题归因 ================= */
.attrib {
  margin-top: var(--s4);
  padding: var(--s3) var(--s4);
  background: var(--hl-b-soft);
  border-left: 5px solid var(--hl-b);
  border-radius: var(--r-xs);
}
.attrib-hd {
  font-size: var(--fs-sm); font-weight: 850;
  margin-bottom: var(--s2);
}
.attrib-opts { display: grid; gap: var(--s2); }

/* 讲解页记忆锚点里的 hook：一句话抓手 */
.hook {
  font-family: var(--font-serif);
  font-size: var(--fs-md); font-weight: 700;
  color: var(--ink-900);
  margin-bottom: 3px;
}
.anchor .k {
  display: inline-block;
  font-size: var(--fs-xs); font-weight: 850;
  color: #8a6a00;
  background: var(--hl-y);
  padding: 1px 8px; border-radius: var(--r-xs);
  margin-bottom: var(--s2);
}
.exp-title {
  font-size: var(--fs-sm); font-weight: 850;
  color: var(--ink-500);
  margin-bottom: var(--s2);
}

/* ================= 案例法庭（保留给旧玩法） ================= */
.case-scene {
  margin: var(--s4) 0;
  padding: var(--s4);
  background: var(--paper-100);
  border-left: 4px solid var(--c1);
  border-radius: var(--r-xs);
  font-size: var(--fs-md); line-height: 1.75;
}
.case-tag {
  display: inline-block;
  font-size: var(--fs-xs); font-weight: 850;
  padding: 2px 9px; border-radius: var(--r-pill);
  background: var(--paper-0); color: var(--ink-500);
  margin-bottom: var(--s2);
}

/* 通用状态类：JS 里用 class 名直接切状态 */
.good { color: var(--ok); }
.bad  { color: var(--bad); }
.front { color: var(--ink-900); }
.active { color: var(--brand); }

/* 归因标签选中态：.back 表示"回到已选"，.v 表示已选中 */
.attrib-opts .back { border-left-color: var(--paper-300); }
.attrib-opts .v {
  background: var(--hl-b); border-color: var(--hl-b);
  color: var(--ink-900); font-weight: 800;
}

/* =========================================================
   科目切换
   ========================================================= */
.subj-pill {
  display: inline-flex; align-items: center;
  height: 26px; padding: 0 10px;
  border-radius: 999px;
  background: var(--paper-100);
  border: 1.5px solid var(--paper-200);
  color: var(--ink-700);
  font-size: var(--fs-xs); font-weight: 800;
  letter-spacing: .02em;
  white-space: nowrap;
  transition: background .15s, border-color .15s, transform .12s;
}
.subj-pill:not(.static):active { transform: translateY(1px); }
.subj-pill:not(.static):hover { border-color: var(--brand); color: var(--ink-900); }
.subj-pill.static { cursor: default; }

.subj-card {
  display: block; width: 100%;
  text-align: left;
  background: var(--paper-0);
  border: 1.5px solid var(--paper-200);
  border-radius: var(--r-md);
  padding: var(--s4);
  margin-bottom: var(--s3);
  transition: border-color .15s, box-shadow .15s;
}
.subj-card.on { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft, rgba(242,115,63,.12)); }
.subj-card-top {
  display: flex; align-items: center; gap: var(--s2);
  font-size: var(--fs-md);
}
.subj-card-top b { color: var(--ink-900); }
.subj-cur {
  margin-left: auto;
  font-size: var(--fs-xs); font-weight: 800;
  color: var(--brand);
  background: var(--brand-soft, rgba(242,115,63,.12));
  padding: 2px 8px; border-radius: 999px;
}
.subj-card-stats {
  display: flex; flex-wrap: wrap; gap: var(--s3);
  margin-top: var(--s2);
  font-size: var(--fs-sm);
  color: var(--ink-500);
}
.subj-card-date {
  margin-top: var(--s2);
  font-size: var(--fs-xs);
  color: var(--ink-300);
}

/* =========================================================
   计算特训（科目二）
   ---------------------------------------------------------
   界面上要解决的核心问题是"让用户愿意动笔"。
   所以这里的每一条样式都在做同一件事：
   把公式放在最显眼的位置（消除"我是不是忘了公式"的焦虑），
   把输入框做成整行的终点（视线自然落到那里）。
   ========================================================= */
.cal-card { --ch: var(--c8); }

/* 公式条：这是整个玩法的定心锚。
   常驻显示而不是折叠——考场上要记得公式，
   这里考的是"能不能算"，藏起来只会让人分心找按钮。 */
.cal-formula {
  margin: var(--s3) 0 var(--s4);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: var(--paper-100);
  border-left: 4px solid var(--c8);
}
.cal-formula code {
  display: block;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--ink-900);
  line-height: 1.5;
  word-break: break-word;
}
.cal-warn {
  display: block;
  margin-top: var(--s2);
  font-size: var(--fs-xs);
  color: var(--warn);
  font-weight: 700;
}

.cal-q {
  margin: 0 0 var(--s4);
  font-size: var(--fs-md);
  line-height: 1.72;
  color: var(--ink-700);
}

/* 输入行：单位固定在框内右侧，不放在 placeholder 里。
   placeholder 写单位的好处是界面干净，坏处是用户填完数字
   就看不见单位了，得回头看题。这里做成常驻标签。 */
.cal-input {
  display: flex;
  align-items: center;
  gap: var(--s2);
}
.cal-input input {
  flex: 1;
  min-width: 0;
  height: 48px;
  padding: 0 var(--s3);
  font-size: var(--fs-lg);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  border: 2px solid var(--paper-200);
  border-radius: var(--r-md);
  background: var(--paper-0);
  color: var(--ink-900);
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.cal-input input:focus {
  border-color: var(--c8);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c8) 18%, transparent);
}
.cal-input .cal-unit {
  flex: none;
  font-size: var(--fs-sm);
  font-weight: 800;
  color: var(--ink-500);
  min-width: 34px;
}
.cal-input .btn { flex: none; white-space: nowrap; }

.cal-hintbtn {
  width: 100%;
  margin-top: var(--s3);
}
.cal-hint {
  margin-top: var(--s3);
  padding: var(--s3);
  border-radius: var(--r-md);
  background: var(--warn-bg);
  border-left: 4px solid var(--warn);
  font-size: var(--fs-sm);
  line-height: 1.65;
  color: var(--ink-700);
}
.cal-note {
  margin: var(--s3) 0 0;
  font-size: var(--fs-xs);
  color: var(--ink-500);
  line-height: 1.6;
}

/* 揭晓区 */
.cal-reveal {
  margin-top: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-md);
  border: 2px solid var(--paper-200);
  background: var(--paper-0);
  animation: calPop .28s cubic-bezier(.2,.9,.3,1.2);
}
@keyframes calPop {
  from { opacity: 0; transform: translateY(8px) scale(.97); }
  to   { opacity: 1; transform: none; }
}
.cal-reveal.ok { border-color: var(--ok); background: color-mix(in srgb, var(--ok) 8%, var(--paper-0)); }
.cal-reveal.bad { border-color: var(--bad); background: var(--bad-bg); }
.cal-truth {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
}
.cal-truth b {
  font-size: var(--fs-2xl);
  font-weight: 850;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  color: var(--ink-900);
  word-break: break-all;
}
.cal-reveal.ok .cal-truth b { color: var(--ok); }
.cal-reveal.bad .cal-truth b { color: var(--bad); }
.cal-vs {
  margin-top: var(--s2);
  font-size: var(--fs-sm);
  color: var(--ink-500);
}
.cal-vs b { color: var(--ink-900); }

/* 解题步骤：这是这个玩法最不能省的一块。
   科目二的计算题九成不是"不会"，是单位错、漏乘、方向反。
   只给答案不给人看见自己在哪一步错的，下次还会错在原地。 */
.cal-steps {
  margin-top: var(--s4);
  border-radius: var(--r-md);
  border: 1.5px dashed var(--paper-200);
  background: var(--paper-100);
  padding: var(--s3) var(--s4);
}
.cal-steps-hd {
  font-size: var(--fs-xs);
  font-weight: 850;
  color: var(--ink-500);
  letter-spacing: .06em;
  margin-bottom: var(--s2);
}
.cal-step {
  padding: 5px 0;
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--ink-700);
  font-variant-numeric: tabular-nums;
  border-top: 1px solid var(--paper-200);
}
.cal-step:first-of-type { border-top: none; }

/* 陷阱提醒：只在答错时出现。
   它不是"再讲一遍知识点"，是专门指出这一类题最容易踩的那个坑。 */
.cal-trap {
  margin-top: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: var(--warn-bg);
  border-left: 4px solid var(--warn);
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--ink-700);
}
.cal-trap b { color: var(--warn); }

.cal-run {
  margin-top: var(--s2);
  display: inline-block;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: var(--fs-xs);
  font-weight: 850;
}


/* =========================================================
   模考 · 机考仿真
   ---------------------------------------------------------
   为什么模考要用一套自己的视觉语言，而不是复用刷题样式：

   刷题的界面要让用户放松——大按钮、即时反馈、彩色。
   模考的界面要让用户**紧张**——宋体（试卷的字体）、
   墨蓝（印务的蓝）、倒计时、密集的题号。
   换皮不是装饰，是让用户在点进去的第一眼就把心态切到"考试"。

   颜色只用 --brand（墨蓝）和语义色，不碰荧光笔四色——
   荧光笔是"学习/标记"的意思，模考里不该出现。
   ========================================================= */

.mk-hero {
  padding: var(--s5) 0 var(--s4);
  text-align: center;
}
.mk-hero h1 {
  font-family: var(--font-serif);
  font-size: var(--fs-2xl);
  font-weight: 800;
  letter-spacing: .04em;
  margin: var(--s3) 0 var(--s2);
  color: var(--ink-900);
}
.mk-hero p {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-500);
  line-height: 1.7;
}
.mk-hero p b { color: var(--brand); }

/* 印章：模考开始页的视觉锚。
   做成方形印记而不是圆形徽章——印章本来就是方的。 */
.mk-seal {
  width: 54px; height: 54px;
  margin: 0 auto;
  display: grid; place-items: center;
  border: 2.5px solid var(--brand);
  border-radius: var(--r-xs);
  font-family: var(--font-serif);
  font-size: var(--fs-2xl);
  font-weight: 900;
  color: var(--brand);
  letter-spacing: 0;
  transform: rotate(-4deg);
  background: var(--brand-soft);
}

/* 四格关键数据：题量 / 时长 / 节奏 / 及格线。
   开考前必须一眼看完这四个数——它们决定"现在做不做得完"。 */
.mk-rules {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--paper-200);
  border: 1px solid var(--paper-200);
  border-radius: var(--r-md);
  overflow: hidden;
  margin-bottom: var(--s5);
}
.mk-rules > div {
  background: var(--paper-0);
  padding: var(--s3) var(--s1);
  text-align: center;
}
.mk-rules b {
  display: block;
  font-size: var(--fs-xl);
  font-weight: 850;
  color: var(--ink-900);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}
.mk-rules span {
  display: block;
  font-size: var(--fs-xs);
  color: var(--ink-500);
  margin-top: 2px;
}

/* 选卷 */
.mk-papers { display: grid; gap: var(--s2); }
.mk-paper {
  display: block; width: 100%;
  text-align: left;
  padding: var(--s3) var(--s4);
  border: 1.5px solid var(--paper-300);
  border-radius: var(--r-md);
  background: var(--paper-0);
  cursor: pointer;
  position: relative;
  transition: border-color .15s, background .15s;
}
.mk-paper.on {
  border-color: var(--brand);
  background: var(--brand-soft);
}
.mk-paper b {
  display: block;
  font-size: var(--fs-md);
  font-weight: 800;
  color: var(--ink-900);
  margin-bottom: 2px;
}
.mk-paper span {
  display: block;
  font-size: var(--fs-xs);
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
.mk-pick {
  position: absolute; top: var(--s3); right: var(--s4);
  color: var(--brand) !important;
  font-weight: 800;
}

/* 卷子构成标签：机考形态分布。
   放在开始页而不是结算页——用户点进去之前就该知道
   "这张卷里组合题很多"，而不是考完才被告知。 */
.mock-tags {
  display: flex; flex-wrap: wrap; gap: var(--s2);
  margin-top: var(--s3);
}
.mock-tag {
  font-size: var(--fs-xs);
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--paper-100);
  color: var(--ink-700);
  border: 1px solid var(--paper-200);
  font-variant-numeric: tabular-nums;
}
.mock-tag.warn {
  background: var(--warn-bg);
  color: var(--warn);
  border-color: transparent;
  font-weight: 700;
}

/* 成绩历史条 */
.mock-hist { margin-top: var(--s3); display: grid; gap: 1px; }
.mock-hrow {
  display: grid;
  grid-template-columns: 52px 1fr auto;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
  background: var(--paper-50);
  font-size: var(--fs-sm);
}
.mock-hrow b {
  font-size: var(--fs-lg);
  font-weight: 850;
  font-variant-numeric: tabular-nums;
}
.mock-hrow.ok b { color: var(--ok); }
.mock-hrow.bad b { color: var(--bad); }
.mock-hrow span { color: var(--ink-500); }
.mock-hdate { font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }

/* 免责：仿真题不是真题。这条必须显眼——
   用户拿这个分数去预测真实考试，那是我们造成的伤害。 */
.mk-warn {
  margin: var(--s5) 0;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: var(--warn-bg);
  border-left: 4px solid var(--warn);
  font-size: var(--fs-xs);
  line-height: 1.75;
  color: var(--ink-700);
}
.mk-warn b { color: var(--warn); }

/* ---------- 答题页 ---------- */

/* 顶栏：倒计时是这个页面的主角，位置和字号都要压过其他元素。 */
.mk-bar {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2) 0 var(--s3);
  position: sticky; top: 0; z-index: 5;
  background: var(--paper-50);
}
.mk-clock {
  flex: 1;
  text-align: center;
  font-family: var(--mono);
  font-size: var(--fs-xl);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--ink-900);
  letter-spacing: .02em;
}
/* 剩 15 分钟转警告色。要显眼到"抬头就能看见"，
   又不能闪——闪烁在模考里是干扰，不是提醒。 */
.mk-clock.warn { color: var(--bad); }

/* 进度条 + 剩余未答 */
.mk-prog {
  display: flex; align-items: center; gap: var(--s3);
  margin-bottom: var(--s4);
}
.mk-prog-bar {
  flex: 1;
  height: 4px;
  background: var(--paper-200);
  border-radius: var(--r-pill);
  overflow: hidden;
}
.mk-prog-bar i {
  display: block; height: 100%;
  background: var(--brand);
  border-radius: var(--r-pill);
  transition: width .25s ease;
}
.mk-prog span {
  font-size: var(--fs-xs);
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* 题干卡片：宋体，题号和题干之间留大气。
   试卷的呼吸感来自行距，不是来自字号。 */
.mk-card {
  background: var(--paper-0);
  border: 1px solid var(--paper-200);
  border-radius: var(--r-lg);
  padding: var(--s5) var(--s4);
  box-shadow: var(--sh-1);
}
.mk-hd {
  display: flex; align-items: center; gap: var(--s2);
  margin-bottom: var(--s3);
}
.mk-type {
  font-size: var(--fs-xs);
  font-weight: 800;
  color: var(--brand);
  background: var(--brand-soft);
  padding: 2px 9px;
  border-radius: var(--r-pill);
}
.mk-hard {
  font-size: var(--fs-xs);
  color: var(--warn);
  background: var(--warn-bg);
  padding: 2px 9px;
  border-radius: var(--r-pill);
  font-weight: 700;
}
.mk-q {
  font-family: var(--font-serif);
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: 1.75;
  color: var(--ink-900);
  margin: 0 0 var(--s5);
}

/* 选项 */
.mk-opts { display: grid; gap: var(--s2); }
.mk-opt {
  display: flex; align-items: flex-start; gap: var(--s3);
  width: 100%; text-align: left;
  padding: var(--s3) var(--s4);
  min-height: var(--tap);
  border: 1.5px solid var(--paper-300);
  border-radius: var(--r-md);
  background: var(--paper-0);
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.mk-opt i {
  flex: 0 0 24px;
  height: 24px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--paper-100);
  color: var(--ink-700);
  font-style: normal;
  font-weight: 800;
  font-size: var(--fs-xs);
}
/* 选中态：只标"我选了它"，不标"它对不对"。
   这是零反馈的实现落点——没有任何对错类名。 */
.mk-opt.on {
  border-color: var(--brand);
  background: var(--brand-soft);
}
.mk-opt.on i {
  background: var(--brand);
  color: var(--brand-ink);
}
.mk-opt span {
  flex: 1;
  font-size: var(--fs-md);
  line-height: 1.65;
  color: var(--ink-900);
}

.mk-note {
  margin: var(--s4) 0 0;
  font-size: var(--fs-xs);
  color: var(--ink-300);
  text-align: center;
}

/* ---------- 答题卡 ---------- */
/* 覆盖式而不是页面跳转：真机考的答题卡盖在题目上，
   关掉必须回到原题号。 */
.mk-sheet-wrap {
  background: var(--paper-50);
  min-height: 60vh;
  padding-bottom: var(--s6);
}
.mk-sheet-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--paper-200);
  margin-bottom: var(--s4);
}
.mk-sheet-bar b { font-size: var(--fs-lg); font-weight: 800; }
.mk-sheet-hd {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: var(--s3);
}
.mk-sheet-hd b { font-size: var(--fs-md); font-weight: 800; }
.mk-sheet-hd span {
  font-size: var(--fs-xs); color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
.mk-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: var(--s2);
}
.mk-cell {
  aspect-ratio: 1;
  min-height: 44px;
  border: 1.5px solid var(--paper-300);
  border-radius: var(--r-sm);
  background: var(--paper-0);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.mk-cell.done {
  background: var(--brand-soft);
  border-color: var(--brand);
  color: var(--brand);
}
.mk-cell.now {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--brand-ink);
  box-shadow: 0 0 0 3px var(--brand-soft);
}
.mk-legend {
  display: flex; gap: var(--s4);
  margin-top: var(--s4);
  font-size: var(--fs-xs);
  color: var(--ink-500);
}
.mk-legend span { display: flex; align-items: center; gap: 5px; }
.mk-legend i {
  width: 12px; height: 12px;
  border-radius: 3px;
  border: 1.5px solid var(--paper-300);
  background: var(--paper-0);
}
.mk-legend i.done { background: var(--brand-soft); border-color: var(--brand); }
.mk-legend i.now { background: var(--brand); border-color: var(--brand); }

/* 交卷确认 */
.mk-confirm { text-align: center; padding: var(--s6) 0; }
.mk-confirm h2 {
  font-family: var(--font-serif);
  font-size: var(--fs-2xl);
  margin: var(--s3) 0 var(--s2);
  color: var(--ink-900);
}
.mk-confirm-btns { display: flex; gap: var(--s2); margin-top: var(--s5); }

/* ---------- 诊断报告 ---------- */

.mk-scorebar {
  position: relative;
  height: 10px;
  background: var(--paper-200);
  border-radius: var(--r-pill);
  margin: var(--s4) 0 var(--s2);
  overflow: hidden;
}
.mk-scorebar i {
  display: block; height: 100%;
  background: var(--brand);
  border-radius: var(--r-pill);
  transition: width .6s cubic-bezier(.2,.8,.3,1);
}
/* 及格线标记：60 分那条线必须看得见，
   否则"59 分"和"61 分"在用户眼里没有区别。 */
.mk-line {
  position: absolute; top: 0; bottom: 0;
  width: 2px;
  background: var(--ink-900);
  opacity: .55;
}
.mk-score-ft {
  display: flex; justify-content: space-between;
  font-size: var(--fs-xs);
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}
.mk-score-ft .ok { color: var(--ok); font-weight: 700; }
.mk-score-ft .bad { color: var(--bad); font-weight: 700; }

.mk-metrics {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--s2);
  margin: var(--s5) 0 var(--s2);
}
.mk-metrics > div {
  text-align: center;
  padding: var(--s3) var(--s1);
  background: var(--paper-0);
  border: 1px solid var(--paper-200);
  border-radius: var(--r-md);
}
.mk-metrics b {
  display: block;
  font-size: var(--fs-xl);
  font-weight: 850;
  font-variant-numeric: tabular-nums;
  color: var(--ink-900);
}
.mk-metrics b.ok { color: var(--ok); }
.mk-metrics b.bad { color: var(--bad); }
.mk-metrics span { font-size: var(--fs-xs); color: var(--ink-500); }

/* 分章诊断条：这是整份报告最有行动价值的部分。 */
.mk-chs { display: grid; gap: var(--s3); }
.mk-ch {
  padding: var(--s3) var(--s4);
  background: var(--paper-0);
  border: 1px solid var(--paper-200);
  border-radius: var(--r-md);
}
.mk-ch-hd {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s2);
}
.mk-ch-hd b {
  font-size: var(--fs-sm);
  font-weight: 750;
  color: var(--ink-900);
  flex: 1;
  min-width: 0;
}
.mk-ch-hd span {
  font-size: var(--fs-xs);
  font-weight: 800;
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.mk-ch-hd .ok { color: var(--ok); }
.mk-ch-hd .bad { color: var(--bad); }
.mk-ch-bar {
  height: 6px;
  background: var(--paper-200);
  border-radius: var(--r-pill);
  overflow: hidden;
}
.mk-ch-bar i {
  display: block; height: 100%;
  border-radius: var(--r-pill);
  transition: width .5s ease;
}
.mk-ch-bar i.ok { background: var(--ok); }
.mk-ch-bar i.mid { background: var(--warn); }
.mk-ch-bar i.bad { background: var(--bad); }
.mk-ch-ft {
  margin-top: 5px;
  font-size: var(--fs-xs);
  color: var(--ink-300);
  font-variant-numeric: tabular-nums;
}
/* 样本不足的提示。比正文更淡一档——它是免责声明不是结论，
   不该跟"平均 62s/题"这个真数据抢注意力。 */
/* 样本不足的提示。比正文更淡一档——它是免责声明不是结论，
   不该跟"平均 62s/题"这个真数据抢注意力。
   坑（2026-10-03）：原来这里写的是 opacity:.85。
   opacity 会让对比度检查算不准——WCAG 要的是**合成后**的颜色比值，
   而检查读的是 opacity 之前的 color，于是这行永远显示不达标，
   我第一反应是"检查写错了"。其实两种表达等价，但 token 更准：
   淡一档就该用更淡的墨色，而不是给一个已达标的颜色再打折。
   顺带一提，opacity 打折还有个副作用：它对**背景**也生效，
   文字压到什么底上都会一起变淡，比选错一个固定色更难预测。 */
.mk-ch-thin { color: var(--ink-300); }

/* 行动出口：诊断不只是报告，得能一键去补。 */
.mk-weak {
  display: block; width: 100%; text-align: left;
  padding: var(--s3) var(--s4);
  margin-bottom: var(--s2);
  border: 1.5px solid var(--paper-300);
  border-left: 4px solid var(--bad);
  border-radius: var(--r-md);
  background: var(--paper-0);
  cursor: pointer;
}
.mk-weak b {
  display: block; font-size: var(--fs-md);
  font-weight: 750; color: var(--ink-900);
  margin-bottom: 2px;
}
.mk-weak span {
  font-size: var(--fs-xs); color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}

/* 逐题回顾 */
.mk-review { display: grid; gap: var(--s2); }
.mk-rv {
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  border-left: 4px solid var(--ok);
  background: var(--ok-bg);
}
.mk-rv.bad { border-left-color: var(--bad); background: var(--bad-bg); }
.mk-rv-hd {
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--ink-900);
  margin-bottom: var(--s2);
}
.mk-rv-hd b { color: var(--ink-500); font-variant-numeric: tabular-nums; }
.mk-rv-o {
  font-size: var(--fs-xs);
  display: grid; gap: 3px;
  font-variant-numeric: tabular-nums;
}
.mk-rv-o .ok { color: var(--ok); font-weight: 700; }
.mk-rv-o .bad { color: var(--bad); font-weight: 700; }
.mk-rv-c { color: var(--ink-700); }
/* 解析沿用题库里的富文本（<strong> 标重点） */
.mk-rv-ex {
  margin-top: var(--s2);
  padding-top: var(--s2);
  border-top: 1px dashed var(--paper-300);
  font-size: var(--fs-xs);
  line-height: 1.8;
  color: var(--ink-700);
}
.mk-rv-ex strong { color: var(--ink-900); }
.mk-rv-t {
  margin-top: var(--s2);
  font-size: var(--fs-xs);
  color: var(--warn);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

/* ---------- 材料正文 ----------
   这是接UI 时才发现的一处严重缺失（2026-10-03）：
   数据层把"材料"和"问题"分开存，抽题时只抽了可作答题，
   于是材料本身没进卷子——而每道材料题的题干都写着
   "根据上述材料，回答第 32~34 题"。
   用户看到这句话，材料却 nowhere：那 23 道材料题全部无法作答，
   而他的分数里还混进了这批废题。

   样式上按"试卷的附页"处理：带边框的浅底块，
   和题干之间有明显分隔——因为材料在机考里是独立的一段。 */
.mk-passage {
  margin-bottom: var(--s4);
  border: 1px solid var(--paper-300);
  border-left: 3px solid var(--brand);
  border-radius: var(--r-sm);
  background: var(--paper-50);
  overflow: hidden;
  cursor: pointer;
}
.mk-passage-hd {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s2) var(--s3);
  font-size: var(--fs-xs);
  font-weight: 800;
  color: var(--brand);
  background: var(--brand-soft);
  user-select: none;
}
.mk-passage-tg {
  font-weight: 600;
  color: var(--ink-500);
}
/* 折叠时只留标题条，材料正文不占空间 */
.mk-passage-bd {
  display: none;
  padding: var(--s3);
  font-family: var(--font-serif);
  font-size: var(--fs-sm);
  line-height: 1.9;
  color: var(--ink-700);
  white-space: pre-wrap;
}
.mk-passage.open .mk-passage-bd { display: block; }
.mk-passage.open .mk-passage-hd { border-bottom: 1px solid var(--paper-200); }

/* 组内题号："第 32 问"。让用户知道这组材料还剩几问没做。 */
.mk-no {
  font-size: var(--fs-xs);
  color: var(--ink-500);
  background: var(--paper-100);
  padding: 2px 9px;
  border-radius: var(--r-pill);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  margin-left: auto;
}

/* ---------- 报告折叠 ----------
   为什么要折叠（2026-10-03 实测量出来的）：
   全错 71 题的报告原本要滚 31.7 屏。
   不是"内容太多"，是**默认全展开**——
   71 条逐题回顾 + 18 条分章，用户滑到一半就放弃了，
   报告最该被看到的"最差的三章"反而被埋在中间。

   折叠规则按"用户想看什么"定：
   - 分章：只展开正确率最低的 4 章（那才是问题所在）
   - 逐题：只展开答错的（对的没必要看解析）
   两处都保留一键展开，不用担心"藏起来看不到"。 */
.mk-ch {
  /* 折叠时只留标题行 */
}
.mk-ch .mk-ch-bar,
.mk-ch .mk-ch-ft { display: none; }
.mk-ch.open .mk-ch-bar,
.mk-ch.open .mk-ch-ft { display: block; }
.mk-ch-hd {
  cursor: default;
}
.mk-ch-hd[data-act] { cursor: pointer; }
.mk-ch-tg {
  font-size: var(--fs-xs);
  color: var(--ink-300);
  font-weight: 700;
  padding-left: var(--s2);
  white-space: nowrap;
}

/* 题干/选项跟随整条折叠。
   坑（2026-10-03 加解析折叠时踩的）：这里原来还有一条
   `.mk-rv.open .mk-rv-ex { display: block }`——
   它的特异性 (0,2,1) 高于后面新加的
   `.mk-rv-exwrap.open .mk-rv-ex` (0,2,1 相等，但写在后面才生效)，
   于是"展开解析"按钮点了没反应，报告反而更长（27→30 屏）。
   解析已经挪进 .mk-rv-exwrap 独立控制，这行必须删掉。 */
.mk-rv .mk-rv-o,
.mk-rv .mk-rv-t { display: none; }
.mk-rv.open .mk-rv-o,
.mk-rv.open .mk-rv-t { display: block; }
/* 答对的可点，答错的默认展开不需要点 */
.mk-rv.ok { cursor: pointer; }
.mk-rv-hd {
  display: flex; align-items: flex-start; gap: var(--s2);
}
.mk-rv-txt {
  flex: 1;
  min-width: 0;
  /* 多行截断：折叠态下一条只占两行，
     否则 71 条题干本身就够滚好几屏了 */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.mk-rv.ok.open .mk-rv-txt {
  -webkit-line-clamp: unset;
}
.mk-rv-tg {
  flex: 0 0 auto;
  font-size: var(--fs-xs);
  font-weight: 800;
  color: var(--ok);
  padding: 1px 8px;
  border-radius: var(--r-pill);
  background: var(--paper-0);
}
.mk-rv-tg.bad { color: var(--bad); }

/* 解析单独一层折叠。
   错题的题干和选项必须默认展开——那是"我选了什么、对的是什么"，
   考完第一眼就要看到。解析是"为什么"，属于想深究时才读的第二层。
   分成两层之后，一屏能看到的信息量刚好等于用户真正需要的量。 */
.mk-rv-exwrap { margin-top: var(--s2); }
.mk-rv-ex { display: none; }
.mk-rv-exwrap.open .mk-rv-ex { display: block; }
.mk-rv-exbtn {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 800;
  color: var(--brand);
  background: var(--brand-soft);
  padding: 3px 10px;
  border-radius: var(--r-pill);
  cursor: pointer;
  user-select: none;
}
.mk-rv-exwrap.open .mk-rv-exbtn {
  background: var(--paper-0);
  color: var(--ink-500);
}

/* =========================================================
   考前急救
   ---------------------------------------------------------
   视觉上刻意**不用**红色警示，也不用大面积色块。
   理由：这个页面的用户已经是焦虑状态，
   再用"警告色 + 感叹号"等于火上浇油。
   它的语气应该是安静的、可执行的——像考前一晚
   有人把书翻到该背的那几页，说"先看这些"。
   所以：判断用一句陈述（"还差 X 分"）而不是感叹号，
   底色用纸面而不是警示底。
   ========================================================= */

.cr-entry {
  display: block; width: 100%; text-align: left;
  background: var(--paper-0);
  border: 1.5px solid var(--paper-300);
  border-left: 4px solid var(--brand);
  border-radius: var(--r-md);
  padding: var(--s4);
  box-shadow: var(--sh-1);
  transition: transform .12s ease, box-shadow .12s ease;
}
.cr-entry:active { transform: scale(.99); box-shadow: var(--sh-press); }

.cr-entry-hd {
  display: flex; align-items: baseline; gap: var(--s2);
  flex-wrap: wrap; margin-bottom: var(--s3);
}
.cr-entry-hd b {
  font-family: var(--font-serif);
  font-size: var(--fs-lg); font-weight: 700;
}
.cr-entry-tag {
  margin-left: auto;
  font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
  padding: 2px 8px; border-radius: var(--r-pill);
}
/* 判定标签。
   坑（2026-10-03 对比度实测抓到）：直接用 --bad 前景 + --bad-bg 背景，
   亮色 3.61:1、夜间 3.48:1，两边都不达标。
   原因是这两个 token 是给"整块告警底"用的，落在淡红底上时
   玫红本身不够深——它们从来没为"小字 + 淡底"这个组合设计过。
   亮色压深一档 #b3185a（5.7:1，色相不变只是更深，还是玫红），
   夜间提亮一档 #ff9db7（7.42:1，深底上要更亮才读得出）。 */
.cr-entry-tag.ok { background: var(--ok-bg); color: var(--ok); }
.cr-entry-tag.bad { background: var(--bad-bg); color: #b3185a; }
html[data-theme="night"] .cr-entry-tag.ok { color: #62c983; }
html[data-theme="night"] .cr-entry-tag.bad { color: #ff9db7; }

.cr-entry-top {
  display: flex; flex-wrap: wrap; gap: var(--s2);
  margin-bottom: var(--s3);
}
.cr-entry-top span {
  font-size: var(--fs-sm);
  background: var(--paper-100);
  border-radius: var(--r-sm);
  padding: 3px 9px;
  color: var(--ink-700);
}

.cr-entry-ft {
  font-size: var(--fs-xs); color: var(--ink-500);
}

/* 判定块：分数大字 + 一句陈述 */
.cr-verdict {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s4);
  border-radius: var(--r-md);
  margin-bottom: var(--s4);
}
.cr-verdict.ok  { background: var(--ok-bg); }
.cr-verdict.bad { background: var(--bad-bg); }
.cr-verdict-n {
  display: flex; flex-direction: column; align-items: center;
  flex: 0 0 auto; min-width: 76px;
}
.cr-verdict-n b {
  font-family: var(--font-serif);
  font-size: var(--fs-3xl); line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.cr-verdict.ok  .cr-verdict-n b { color: var(--ok); }
.cr-verdict.bad .cr-verdict-n b { color: var(--bad); }
.cr-verdict-n span { font-size: var(--fs-xs); color: var(--ink-500); }
.cr-verdict-t {
  font-size: var(--fs-sm); line-height: 1.6; color: var(--ink-700);
}
.cr-verdict-t b {
  font-family: var(--font-serif);
  font-size: var(--fs-lg); font-variant-numeric: tabular-nums;
}
.cr-verdict-t span {
  display: block; margin-top: 3px;
  font-size: var(--fs-xs); color: var(--ink-500);
}

.cr-do {
  display: flex; gap: var(--s3); margin-bottom: var(--s2);
}
.cr-do .btn { flex: 1; }
.cr-do .btn:first-child { flex: 1.5; }

/* 清单：行，不是卡。81 个考点排下来，卡片会变成一堵墙。 */
.cr-list {
  border-top: 1.5px solid var(--paper-200);
}
.cr-row {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--paper-200);
  cursor: pointer;
}
.cr-row:active { background: var(--paper-100); }

/* 序号。原来用 --ink-300（"最淡一档"），亮色下实测只有 2.36:1 ——
   远低于 WCAG AA 的 4.5:1，81 行清单里每个数字都是半隐形的。
   坑（2026-10-03 深色/对比度实测抓到）：这是本模块**新写**的样式，
   之前没被任何对比度检查覆盖过。"设计上想让它退到背景里"
   和"读不清"之间只隔一个对比度阈值，而阈值是硬线不是审美问题。
   改用 --ink-500：亮色 4.87:1 达标；数字比考点名小一号字号，
   层级还在，不会跟正文抢。 */
.cr-no {
  flex: 0 0 26px;
  font-family: var(--font-serif);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--ink-500);
  text-align: right;
}
/* 夜间 --ink-500 是 #8f9aa6，在 --paper-50 上只有 3.38:1（深色模式
   的墨色整体更亮、直接搬过来反而不够）。这一档实测 5.92:1。 */
html[data-theme="night"] .cr-no { color: #8a96a2; }

.cr-bd { flex: 1 1 auto; min-width: 0; }
.cr-bd b {
  display: block;
  font-size: var(--fs-md); font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cr-sub {
  display: block;
  font-size: var(--fs-xs); color: var(--ink-500);
  font-variant-numeric: tabular-nums;
}

/* 掌握度细条。占位很小——急救页的主角是名字和权重，
   不是一根进度条。 */
.cr-bar {
  flex: 0 0 44px; height: 4px;
  background: var(--paper-200);
  border-radius: var(--r-pill);
  overflow: hidden;
}
.cr-bar i {
  display: block; height: 100%;
  background: var(--brand);
  border-radius: var(--r-pill);
}
.cr-mv {
  flex: 0 0 26px; text-align: right;
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink-500);
}

/* 清单 81 行很长。首屏之外的行默认不画细边框以外的装饰，
   靠 1px 分隔线分隔就够了，不要给每行加阴影或圆角。 */
@media (min-width: 700px) {
  .cr-row { padding: var(--s3) var(--s2); }
}

/* 考纲层次小标。跟答题页的 .qdot.lv-* 同一套色，
   这样"掌握/理解/了解"在全站是同一个视觉语言。 */
.cr-lv {
  display: inline-block;
  padding: 0 5px; margin-right: 5px;
  border-radius: var(--r-xs);
  font-size: var(--fs-xs);
}
.cr-lv.lv-掌握 { background: var(--hl-y-soft); color: #8a6a00; }
.cr-lv.lv-理解 { background: var(--hl-b-soft); color: #1c5c9e; }
.cr-lv.lv-了解 { background: var(--hl-g-soft); color: #2c7a3c; }
html[data-theme="night"] .cr-lv.lv-掌握 { color: var(--hl-y); }
html[data-theme="night"] .cr-lv.lv-理解 { color: var(--hl-b); }
html[data-theme="night"] .cr-lv.lv-了解 { color: var(--hl-g); }

/* =========================================================
   启动守卫（#boot-guard）
   ---------------------------------------------------------
   只在"脚本没能跑起来"时出现，也就是双击打开 index.html 的场景。
   坑（2026-10-03 用户报"只显示这个页面"时定的）：
   修好白屏之后，这个页面容易被当成多余的补丁删掉——
   但它是那个场景**唯一的信息出口**。
   file:// 下 ES Module 被 CORS 拦，脚本一行都不执行，
   连 console error 都不保证有，用户能看到的只有一片空白。
   所以它必须留在 index.html 里，而且必须说人话：
   "协议不对"和"你该双击哪个文件"，而不是丢一个错误码。

   语气选择：不用红色告警底。这个场景里用户已经有点慌了
   （他看到的是"我的东西打不开"），警告色会加重挫败感。
   跟考前急救页同一个判断：错误页要让人知道怎么办，不是让人害怕。
   ========================================================= */
#boot-guard {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s5);
  background: var(--paper-50);
  font-family: var(--font);
}
#boot-guard[hidden] { display: none; }

.bg-card {
  max-width: 34em;
  padding: var(--s6) var(--s5);
  background: var(--paper-0);
  border: 1px solid var(--paper-300);
  border-radius: var(--r-md);
  box-shadow: var(--sh-2);
}
.bg-title {
  margin: 0 0 var(--s3);
  font-family: var(--font-serif);
  font-size: var(--fs-2xl);
  font-weight: 700;
  color: var(--ink-900);
}
.bg-msg {
  margin: 0 0 var(--s4);
  font-size: var(--fs-md);
  line-height: 1.7;
  color: var(--ink-700);
}
.bg-hint {
  padding: var(--s3) var(--s4);
  background: var(--hl-b-soft);
  border-radius: var(--r-sm);
  font-size: var(--fs-md);
  line-height: 1.75;
  color: var(--ink-900);
}
.bg-hint p { margin: 0 0 var(--s2); }
.bg-hint p:last-child { margin-bottom: 0; }
.bg-hint b { font-weight: 700; }
/* 文件名用等宽，因为 启动.bat 是一个必须被逐字符照着找的东西，
   不是一句话里的普通词。 */
.bg-hint code,
.bg-hint b + b,
.bg-hint .bg-file {
  font-family: var(--mono);
  font-size: var(--fs-md);
}
.bg-foot {
  margin: var(--s4) 0 0;
  font-size: var(--fs-sm);
  line-height: 1.7;
  /* 弱化档 --ink-300 实测 4.64:1（见 tokens.css 里的说明），
     不要用 opacity 表达"更淡"——它对背景也生效，比选错固定色难预测。 */
  color: var(--ink-300);
}
html[data-theme="night"] .bg-hint {
  background: #1a2b3d;
}
