/* ============================================================================
 * ADHD家长课堂 · 组件层 components.css（第二批）
 * ----------------------------------------------------------------------------
 * 加载顺序（DESIGN-SPEC §5.10）：
 *   tokens.css → themes.css → style.css → components.css
 * 本文件在 style.css **之后**加载，因此**同名类以本文件为准**
 * （components.css 是新契约，style.css 本批只减不增，第三批整体退役）。
 *
 * 约束（DESIGN-SPEC §5.1 / §5.6 / §5.7 / §5.8）：
 *   - 只消费 L2/L3 语义 token：--c-* --fs-* --lh-* --fw-* --sp-* --r-* --sh-*
 *     --bw-* --border-style --density-* --measure
 *   - 禁止：裸 hex / 强制覆盖声明（CSS 的 `!` 前缀）/ 引用 L1 --p-* 原始值
 *   - 容器边框走 var(--border-style)；静止态带阴影（--sh-1）；grid/flex 子项 min-width:0
 * 本文件实现 §5.8 清单里的全部类，类名逐字照抄，不自创、不改名。
 * ========================================================================== */


/* ==========================================================================
 * A. 状态块（吸收原「加载中 / 空 / 错误 / 404」内联样式）
 * ========================================================================== */

/* 主题自洽（2026-10-03 a11y 修复）：style.css 的 body 底色走遗留 --bg（#f7fafc，主题盲），
   而本组标题/正文用的是主题化的 --c-text / --c-text-muted。暗色主题下 --c-text 变浅、
   容器底色却仍是亮的 → 实测 1.17:1（indigo-night）/ 1.20:1（ember）不可读。
   故给容器自带主题底 + 主题前景，使本组件内部自洽（底与字同源同主题）。
   color 那一行不是可选的：.state-block__hint 靠继承取色，缺了它会把新底配遗留深字。 */
.state-block {
  text-align: center;
  padding: var(--sp-12) var(--sp-5);      /* 原 48px 20px */
  background: var(--c-surface);
  color: var(--c-text);
  /* 有了底就是「卡片」→ 补形态（team-lead 2026-10-03 裁决）：
     无圆角无阴影时 --c-surface(#fff) 与 body 遗留底(#f7fafc) 仅 1.02:1，边界发虚、直角生硬。
     §5.6 规则二「静止态必须有阴影」此刻对本类成立（与 .alert/.disclosure-toggle/.theme-option 一致）。 */
  border-radius: var(--r-md);
  box-shadow: var(--sh-1);
}

.state-block--tall {
  padding: var(--sp-16) var(--sp-5);      /* 原 60px 20px */
}

.state-block__icon {
  font-size: var(--fs-4xl);               /* 原 48px */
  line-height: var(--lh-flat);
  margin-bottom: var(--sp-4);             /* 原 16px */
}

.state-block__title {
  font-size: var(--fs-lg);                /* 原 20px */
  font-weight: var(--fw-semibold);
  color: var(--c-text);                   /* 原 var(--primary-dark) */
  margin-bottom: var(--sp-3);             /* 原 12px */
}

.state-block__text {
  font-size: var(--fs-sm);                /* 原 14px */
  color: var(--c-text-muted);             /* 原 var(--text-light) */
}

/* 显式声明文字色，消除「靠继承容器取色」的隐式依赖：
   组件不应把可读性挂在它控制不到的祖先上。兄弟 .state-block__text 本就 muted，此处对齐。 */
.state-block__hint {
  max-width: var(--measure);              /* 原 34em */
  margin: var(--sp-3) auto 0;             /* 原 12px auto 0 */
  text-align: left;
  color: var(--c-text-muted);
}

.state-block__actions {
  margin-top: var(--sp-6);                /* 原 24px */
  display: flex;
  gap: var(--sp-3);                       /* 原 12px */
  justify-content: center;
  flex-wrap: wrap;
}

/* .entry-btn 是伪装成按钮的链接（<a>），两种用法共用：
   ① 状态块 / 404：class="entry-btn entry-btn--secondary"（浅底，见下）
   ② 首页入口卡：class="entry-btn"（实心主色底）
   事实：style.css 里 .entry-btn 的旧规则（原 :1324 裸 hex 块、:1449 的 height:48px 块、
   以及 :1752 的强制覆盖块）已于 2026-10-03 被删除，style.css 对本类已无生效规则，
   本文件是 .entry-btn 的唯一权威；下方 padding 12px/24px 当下即生效。
   高度用 min-height 而不是 height：clarity 无障碍主题下字号与行高整体上浮，
   固定 height 会裁切文字，故不能用 height。 */
.entry-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;                        /* 触控目标；min-height 以防 clarity 主题裁字 */
  align-self: flex-start;                  /* 首页入口卡是 flex column，防止按钮被拉伸为满宽 */
  padding: var(--sp-3) var(--sp-6);        /* 原 12px 24px */
  border: var(--bw-1) var(--border-style) transparent;
  border-radius: var(--r-md);              /* 原 8px */
  background: var(--c-accent);
  color: var(--c-on-accent);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  text-align: center;                      /* 文字换行到多行时保持行内居中 */
  text-decoration: none;
  cursor: pointer;
  min-width: 0;                            /* §5.6 规则三：flex 子项显式 min-width:0 */
  box-shadow: var(--sh-1);                 /* §5.6 规则二：静止态必须有阴影 */
  /* color 必须进过渡列表：否则切主题的 200ms 内会出现「新文字色 + 旧背景色」的
     瞬时低对比闪烁（实测 indigo-night 主色底掉到 2.77、wisteria 掉到 2.15，
     是真值 6.98 的 31%）。用户每次切主题都会真实看到。 */
  transition: color var(--dur-2) var(--ease-out),
              background var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}

.entry-btn:hover {
  background: var(--c-accent-hover);
  box-shadow: var(--sh-2);                 /* hover 升一档 */
}

.entry-btn--secondary {
  background: var(--c-accent-soft);        /* 原 var(--primary-light) */
  color: var(--c-accent-text);             /* 原 var(--primary-dark) */
  border-color: var(--c-accent-border);
}

.entry-btn--secondary:hover {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
  box-shadow: var(--sh-2);
}


/* ==========================================================================
 * B. 正文容器与列表
 *
 * ⚠️ .prose 目前是**死代码**：脚本全站扫描 .js/.html/.json/.css 后确认
 *    `class="prose"` 一次都未出现（仅本文件引用），app.js 不输出它。
 *    第三批要么接线、要么删除。app.js 当前的纵向节奏仍来自 style.css 的遗留 margin。
 *    保留它的价值是：一旦接线，节奏规则已就绪且已排掉下面的 specificity 地雷。
 * ========================================================================== */

/* 流式纵向节奏：间距由容器决定，子元素不自带 margin（DESIGN-SPEC §5.7） */
.prose > * + *            { margin-block-start: var(--sp-3); }
.prose > h2               { margin-block-start: var(--sp-8); }
.prose > h3               { margin-block-start: var(--sp-6); }
.prose > h2 + *,
.prose > h3 + *           { margin-block-start: var(--sp-2); }   /* 标题后收紧 */
.prose > *:first-child    { margin-block-start: 0; }
/* 用 :where() 把权重从 (0,1,1) 降到 (0,1,0)：与 .list-detail (0,1,0) 打平后，
   定义在更后的 .list-detail 的 padding-inline-start 才能胜出（24px → 20px）。
   普通 ul/ol 的行为不变。这是拆掉「.prose 里的 .list-detail 被压掉缩进」的地雷。 */
.prose :where(ul, ol)     { padding-inline-start: var(--sp-6); }
.prose li + li            { margin-block-start: var(--sp-1); }

/* 条目下的缩进说明 */
.list-detail {
  padding-inline-start: var(--sp-5);       /* 原 padding-left 20px */
  margin-block-start: var(--sp-1);         /* 原 margin-top 4px */
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
}

/* 带底色条目 */
.list-detail--highlight {
  margin-block-start: var(--sp-2);         /* 原 margin-top 8px */
  padding: var(--sp-2) var(--sp-3);        /* 原 8px 12px */
  background: var(--c-accent-soft);        /* 原 var(--primary-light) */
  color: var(--c-accent-text);
  border-radius: var(--r-sm);              /* 原 6px */
}

/* 圆点列表 */
.bullet-list {
  padding-inline-start: var(--sp-5);       /* 原 padding-left 20px */
  font-size: var(--fs-sm);                 /* 原 14px */
  line-height: var(--lh-loose);            /* 原 2 */
}

/* 两列栅格 */
.grid-2col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-4);                        /* 原 16px */
  margin-block-end: var(--sp-5);           /* 原 margin-bottom 20px */
}

/* §5.6 规则三：grid 子项显式 min-width:0，防止宽内容把子项撑宽、整页横向溢出 */
.grid-2col > * {
  min-width: 0;
}

/* 工具模板框内部零间距修复（§5.7：间距由容器决定）。
   app.js:905-960 输出的 .tool-template-box 子元素依次是 <strong>模板：</strong> 加若干 <div>，
   style.css:488-495 只给了容器自身的 padding，子元素之间 gap=0 → “模板：”标签直接贴着表格/列表。
   取 --sp-2(8px) 而非 --sp-3：工具模板框是密集信息区。
   注：.table-scroll（style.css:508）建立 BFC，表格自身 margin:8px 0（style.css:496）不会塌出，
   故“标签 → 表头”的实际合成间距 = 8 + 8 = 16px（实测见交付报告）。 */
.tool-template-box > * + * {
  margin-block-start: var(--sp-2);
}

/* 同一容器的「边界穿越收口」：style.css:488 给的是遗留底 var(--bg)=#f7fafc（主题盲），
   而本文件把 .list-detail 的字色 token 化成 --c-text-muted → 暗色主题下
   「浅底 + 浅字」实测 1.97:1 / 2.05:1（ember / indigo-night，全量重扫命中）。
   给容器一个自洽的主题表面即可（与 .state-block / .table 同一修法）。 */
.tool-template-box {
  background: var(--c-surface);
  color: var(--c-text);
}

/* <768px 降单列（用 @media：§5.8 明确以“视口宽度 <768px”为条件；
   .grid-2col 自身未声明 container，故不使用 @container） */
@media (max-width: 767px) {
  .grid-2col {
    grid-template-columns: 1fr;
  }
}

/* 证据来源列表 */
.source-list {
  margin: 0;
  padding-inline-start: 0;
  list-style: none;
  font-size: var(--fs-sm);
}

.source-list__item {
  padding-inline-start: var(--sp-3);       /* 原缩进 12px */
  padding-block-end: var(--sp-2);          /* 原 margin-bottom 8px 量级 */
  margin-block-end: var(--sp-2);           /* 原 margin-bottom 6px/8px */
  /* 列表项之间的分隔线：属排版节奏而非轮廓，固定 solid + --c-divider。
     （墨纸的 double 落在 1px 分割线上会渲染成两条细线，是噪音不是主题特征。
       team-lead 2026-10-03 裁决：容器轮廓才走 var(--border-style)。） */
  border-block-end: var(--bw-1) solid var(--c-divider);  /* 原 1px dashed */
}

.source-list__item:last-child {
  padding-block-end: 0;
  margin-block-end: 0;
  border-block-end: none;
}


/* ==========================================================================
 * C. 提示框变体
 * 基类 .alert 在设计规范 §5.8 中标注“已存在于 style.css”，
 * 但实测 style.css **并不存在** .alert 基类（见交付报告“规范问题”一节）。
 * 因此本文件补出最小可用的 .alert 基类，使各变体可独立渲染。
 * ========================================================================== */

.alert {
  padding: var(--sp-4);
  margin-block: var(--sp-4);
  border-radius: var(--r-md);
  /* 例外：§5.6 规则一允许 .alert 左侧强调条写死 solid */
  border-inline-start: var(--bw-3) solid;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  box-shadow: var(--sh-1);
}

/* 统一把原裸 hex（#fff5f5/#742a2a/#fffff0/#975a16/... 等劣化值）换成安全色 token。
   前景用 --c-text 而非 --c-*-text：语义色文字压在同色系浅底上只有 ~6.2-6.8:1（§5.8 C
   原措辞的设计缺陷）；语义色相改由左侧 4px 强调条（--c-danger 等）继续承载，前景改
   --c-text 后全主题 ≥10:1。team-lead 2026-10-03 裁决采用此方案。 */
.alert--danger {
  background: var(--c-danger-soft);
  border-inline-start-color: var(--c-danger);
  color: var(--c-text);
}

.alert--warn {
  background: var(--c-warn-soft);
  border-inline-start-color: var(--c-warn);
  color: var(--c-text);
}

.alert--ok {
  background: var(--c-ok-soft);
  border-inline-start-color: var(--c-ok);
  color: var(--c-text);
}

.alert--info {
  background: var(--c-info-soft);
  border-inline-start-color: var(--c-info);
  color: var(--c-text);
}

.alert--emergency {
  background: var(--c-emergency-bg);
  border-inline-start-color: var(--c-emergency-border);
  color: var(--c-emergency-text);
  font-weight: var(--fw-semibold);
}

.alert--emergency a {
  color: var(--c-emergency-action);
  font-weight: var(--fw-bold);
  text-decoration: underline;
  text-underline-offset: 3px;
}


/* ==========================================================================
 * D. 徽章（对比度达标版，文字/底色全部 ≥7:1）
 * ========================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 2px var(--sp-2);
  border: var(--bw-1) var(--border-style) transparent;
  border-radius: var(--r-full);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  white-space: nowrap;
  vertical-align: middle;
}

.badge--danger {
  background: var(--c-danger-soft);
  color: var(--c-text);                    /* 见 alert 注释：-text 压 -soft 仅 6.80:1 */
  border-color: var(--c-danger-border);
}

.badge--warn {
  background: var(--c-warn-soft);
  color: var(--c-text);
  border-color: var(--c-warn-border);
}

.badge--ok {
  background: var(--c-ok-soft);
  color: var(--c-text);
  border-color: var(--c-ok-border);
}

.badge--info {
  background: var(--c-info-soft);
  color: var(--c-text);
  border-color: var(--c-info-border);
}

.badge--accent {
  background: var(--c-accent-soft);
  color: var(--c-text);                    /* 原 -text 压 -soft 仅 4.55:1 */
  border-color: var(--c-accent-border);
}


/* ==========================================================================
 * E. 证据徽章（核心信任资产，结构见 §5.4）
 * 非颜色线索必须落地：形状（SVG）+ 边框样式（E1 实线 / E2 虚线 / P1 点线）
 * §5.8：E1 的实线必须走 var(--border-style)，不得写死 solid。
 * ========================================================================== */

.evidence-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 2px var(--sp-2) 2px var(--sp-1);
  border: var(--bw-2) var(--border-style) currentColor;
  border-radius: var(--r-full);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  white-space: nowrap;
  vertical-align: middle;
}

.evidence-badge__icon {
  flex: none;
  width: 1em;
  height: 1em;
  display: block;
}

.evidence-badge__code {
  font-family: var(--font-mono);
  font-weight: var(--fw-bold);
}

.evidence-badge__label {
  font-weight: var(--fw-normal);
}

/* E1 · 有循证证据：实心圆点 + 实线边框 */
.evidence-badge--e1 {
  background: var(--c-ev-e1-bg);
  border-color: var(--c-ev-e1-border);
  border-style: var(--border-style);
  color: var(--c-ev-e1-text);
}

/* E2 · 专家共识：空心方框 + 虚线边框（非颜色线索，故意写 dashed） */
.evidence-badge--e2 {
  background: var(--c-ev-e2-bg);
  border-color: var(--c-ev-e2-border);
  border-style: dashed;
  color: var(--c-ev-e2-text);
}

/* P1 · 个人经验：三角（描边）+ 点线边框（非颜色线索，故意写 dotted） */
.evidence-badge--p1 {
  background: var(--c-ev-p1-bg);
  border-color: var(--c-ev-p1-border);
  border-style: dotted;
  color: var(--c-ev-p1-text);
}

/* 窄屏折叠为「仅图标 + 编码」，徽章本身不可隐藏（§5.4 允许；
   完整语义由 .evidence-badge 上的 aria-label 提供） */
@media (max-width: 480px) {
  .evidence-badge__label {
    display: none;
  }
}


/* ==========================================================================
 * F. 表格
 * .table-scroll 已存在于 style.css:508，且只含布局属性（overflow-x:auto 等）、
 * 不含任何颜色/裸 hex，故本文件**不覆盖**它，以免破坏其 overflow-x:auto。
 * ========================================================================== */

/* 主题自洽（2026-10-03 a11y 修复·第 5 处，超出 team-lead 原列 4 处，见交付报告第 6 节）：
   .table 自身无底 → 奇行透明、露出 style.css 的遗留亮底；而本文件给偶行加了主题底
   --c-surface-inset（暗色下变深）。若只上文字色，奇行会变成「浅字压遗留亮底」；
   若只上底不上色，偶行是「遗留深字压主题深底」——两个方向同时配错，实测 1.17:1(ember)/1.20:1(indigo-night)。
   故底与字一并给，使表格内部自洽（底与字同源同主题）。
   注：.tool-template-box th/td（style.css:497-498）权重 (0,1,1) 高于本类，th 的遗留底+字不受影响。 */
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
  background: var(--c-surface);
  color: var(--c-text);
}

.table caption {
  text-align: left;
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
  padding: var(--sp-2) var(--sp-3);
}

.table th,
.table td {
  text-align: left;
  padding: var(--sp-3);
  border-block-end: var(--bw-1) var(--border-style) var(--c-divider);
}

.table thead th {
  background: var(--c-surface-2);
  font-weight: var(--fw-semibold);
}

.table tbody tr:nth-child(even) {
  background: var(--c-surface-inset);
}


/* ==========================================================================
 * G. 骨架与可访问性（2026-10-03 追加，§5.8 G 组）
 * index.html 与 theme.js 已在消费这些类；此前 components.css 只到 F 组，
 * 这些类零样式 → 全部走 UA 默认（跳转链接浮在顶部、主题面板是裸按钮、图标基线错位）。
 * 本组为落地实现。类名以 theme.js 实际输出为准（.is-checked / __swatches 复数）。
 * ========================================================================== */

/* --- G1. 图标：线宽必须由 CSS 兜底 ---
 * js/icons.js 把线宽写成 SVG 表现属性 stroke-width="var(--icon-stroke)"；
 * presentation attribute 里的 var() 跨浏览器支持不一致，可能整条失效（图标变 1px 或消失），
 * 故这里用 CSS 声明同一个值（见 §5.9）。 */
.icon {
  stroke-width: var(--icon-stroke);
  flex: none;
  display: block;
}

/* --- G2. 静态骨架里的 [data-icon] 占位：空占位不塌陷，避免水合后布局跳动 --- */
.icon-slot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: -0.125em;                /* 图标与汉字的光学对齐量级 */
  flex: none;
}
.icon-slot[data-icon-size="16"] { min-width: 16px; min-height: 16px; }
.icon-slot[data-icon-size="18"] { min-width: 18px; min-height: 18px; }
.icon-slot[data-icon-size="20"] { min-width: 20px; min-height: 20px; }
.icon-slot[data-icon-size="22"] { min-width: 22px; min-height: 22px; }
.icon-slot[data-icon-size="28"] { min-width: 28px; min-height: 28px; }
.icon-slot[data-icon-size="48"] { min-width: 48px; min-height: 48px; }

/* --- G3. 仅屏幕阅读器可见文本（禁止 display:none / visibility:hidden，否则退出无障碍树） --- */
.u-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- G4. 跳过导航链接：默认视觉隐藏，聚焦时左上角浮出 --- */
.skip-link {
  position: absolute;
  inset-block-start: var(--sp-4);
  inset-inline-start: var(--sp-4);
  z-index: var(--z-overlay);               /* 必须高于 .header(--z-nav)，否则浮出后被顶栏盖住 */
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  padding: var(--sp-3) var(--sp-4);
  background: var(--c-surface);
  color: var(--c-accent);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-md);
  box-shadow: var(--sh-2);
  text-decoration: none;
}
.skip-link:focus {
  width: auto;
  height: auto;
  overflow: visible;
  clip-path: none;
  white-space: normal;
}

/* --- G5. 文字外观按钮：清掉 UA 的 2px outset 边框 / padding / 不继承的字体 --- */
.link-button {
  border: 0;
  background: none;
  padding: 0;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  color: var(--c-accent-text);
  text-decoration: underline;
  cursor: pointer;
}

/* --- G6. 卡片外观折叠按钮（版权声明）：与 .link-button 相反方向，两者不可合并 --- */
.disclosure-toggle {
  border: 0;
  width: 100%;
  display: block;
  text-align: start;
  font-family: inherit;
  font-size: inherit;
  line-height: var(--lh-normal);
  background: var(--c-surface);
  color: var(--c-text);
  cursor: pointer;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  box-shadow: var(--sh-1);
}
/* 展开态必须给出「非颜色」状态差：内描边环是形状线索（WCAG 1.4.1），灰度下也成立 */
.disclosure-toggle[aria-expanded="true"] {
  box-shadow: inset 0 0 0 var(--bw-2) var(--c-accent);
}

/* --- G7. 城市热线原生 <details>：summary 触控目标 ≥44px ---
 * 修复项：原 span[onclick] 实测触控目标仅 15px。 */
.hotline-more > summary {
  display: list-item;                      /* 保留 ::marker（若用 display:flex 会吃掉它） */
  min-height: 44px;
  padding-block: var(--sp-2);
  cursor: pointer;
}
/* 用 currentColor 而非固定 token：.hotline-more 是**通用**组件，
   让它跟随所在容器的文字色，在任何容器里都自动正确。
   （当前恰好落在 .alert--emergency 里 → 继承白字 → 10.02:1；
     若写死 --c-text-muted 则压在紧急深底上只有 1.03:1，且在别处复用会错。）
   2026-10-03 实测（在真实 .alert--emergency 容器内，RGB 由 CDP 读取）：
     getComputedStyle(summary,'::marker').color = rgb(255,255,255)
     summary 自身 color = rgb(255,255,255)；alert 底 = rgb(127,29,29)（#7f1d1d）→ 10.02:1
     marker 取到的是 currentColor 解析后的白字，与 summary 文字色一致。
   ★ 更正（同日二次实测）：本规则**在 Chrome 154 下是生效的** —— 注入对照规则
     `.hotline-more > summary::marker { color:#00ff00 !important }` 后 computed marker color
     立刻变为 rgb(0,255,0)，撤销后复原。故"未生效"的旧说法作废（此处仅记录过程，勿再引用）。
   ⇒ 结论不变：marker 色 = currentColor = 容器文字色 = 白 → 10.02:1，规则与结论都对，保留。
      写死 --c-text-muted 会压在紧急深底上只剩 1.03:1，且在别处复用会错。
      ⚠️ 第三批：.hotline-more 复用到浅底容器时，需重新实测 marker 是否仍达标。 */
.hotline-more > summary::marker {
  color: currentColor;
}
.hotline-more__list {
  padding-inline-start: var(--sp-3);
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
}

/* --- G8. 顶栏主题按钮（图标按钮，非文字） --- */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  flex: none;
  background: var(--c-surface);
  color: var(--c-text);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-md);
  cursor: pointer;
  box-shadow: var(--sh-1);
  /* §3.7 成对过渡：border-color 与 background 构成对比度配对，必须一起过渡。
     实测若只过渡 border-color：切主题瞬态「旧主题 border 压新主题 surface」最差 1.12:1
     （ink -> indigo-night），边框在 200ms 内不可见。color/background/border-color/box-shadow
     四者同帧插值后，任意时刻都是同一主题的自洽配色。 */
  transition: color var(--dur-2) var(--ease-out),
              background var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}
.theme-toggle:hover {
  border-color: var(--c-border-strong);
  box-shadow: var(--sh-2);
}
.theme-toggle__icon {
  color: var(--c-accent);
}

/* --- G9. 主题浮层 ---
 * 显隐的唯一权威是 HTML 的 hidden 属性（theme.js 直接操作 panel.hidden）。
 * 本批**不做进入过渡**：display:none 的元素无法播放过渡，写了也不生效，
 * 反而会让评审误以为存在动画契约。故本组件无任何 transition / animation / @keyframes。 */
.theme-panel {
  position: fixed;
  inset-block-start: var(--sp-20);
  inset-inline-end: var(--gutter);
  z-index: var(--z-overlay);               /* 高于 .header(--z-nav) */
  width: min(420px, 92vw);                 /* 显式宽度：缺它时 shrink-to-fit 会让 minmax(132px,1fr) 只算出 1 列，
                                              768/1440 视口退化成 166/181px 的窄条（实测） */
  max-width: min(92vw, 560px);
  max-height: calc(100vh - var(--sp-20) - var(--sp-4));   /* 回退：不支持 dvh 的旧 WebView */
  max-height: calc(100dvh - var(--sp-20) - var(--sp-4));  /* 动态视口：移动端地址栏收起后才是可视高度 */
  overflow-y: auto;
  padding: var(--sp-4);
  background: var(--c-surface);
  color: var(--c-text);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-3);
}

/* 显隐唯一权威：hidden 属性。类+属性 = (0,2,0)，权重高于 .theme-panel，
   显式声明以防日后有人给 .theme-panel 加 display 而静默毁掉显隐（无需强制覆盖声明）。 */
.theme-panel[hidden] {
  display: none;
}

/* 注：.is-open 由 theme.js 切换，本文件**不为其提供任何规则**（本批无过渡、无静态差异）。
   仅作为「逻辑上已打开」的纯语义钩子存在（§6.2）。 */

.theme-panel__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: var(--sp-2);
}

.theme-panel__close {
  display: block;
  margin-block-start: var(--sp-3);
}

/* --- G10. 主题项（<button role="radio">） --- */
.theme-option {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-2);
  padding: var(--sp-2);
  font: inherit;                           /* 清 UA：按钮字体不继承父级 */
  text-align: start;                       /* 清 UA 的 text-align:center */
  background: var(--c-surface);
  color: var(--c-text);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-md);
  cursor: pointer;
  box-shadow: var(--sh-1);
  /* §3.7 成对过渡：同 .theme-toggle（border-color 与 background 配对，须一起过渡；
     实测只过渡 border-color 的瞬态最差 1.12:1）。 */
  transition: color var(--dur-2) var(--ease-out),
              background var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}
.theme-option:hover {
  border-color: var(--c-border-strong);
  box-shadow: var(--sh-2);
}
/* 选中态：aria-checked 给 AT、.is-checked 给样式（双轨）；
   不得只靠颜色 —— 内描边环提供形状/边框线索（WCAG 1.4.1）。 */
.theme-option.is-checked {
  border-color: var(--c-accent);
  box-shadow: inset 0 0 0 var(--bw-2) var(--c-accent);
}
/* 「跟随系统」项与 10 套主题区分 */
.theme-option--system {
  border-block-start: var(--bw-2) var(--border-style) var(--c-border-strong);
}
.theme-option__name {
  font-size: var(--fs-xs);                 /* 主题名必须可见（§6.2），不能只有色块 */
  color: var(--c-text);
}
.theme-option__swatches {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  flex: none;
  inline-size: 100%;
}
.theme-option__swatch {
  flex: none;
  inline-size: var(--sp-6);
  block-size: var(--sp-6);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-sm);
  /* 底色由 theme.js 的 injectSwatchStyle() 运行时注入，此处不写死颜色 */
}
.theme-option__swatches--system .theme-option__swatch {
  flex: 1 1 0;                             /* 「跟随系统」：亮半 / 暗半等宽对半 */
  inline-size: auto;
}
.theme-option__glyph {
  flex: none;
  margin-inline-start: auto;
  color: var(--c-text-muted);
}

/* --- G11. 焦点环（outline 版，2026-10-03 由 box-shadow 改版） ---
 * 为什么改用 outline：
 *  ① tokens.css:183-187 的全局 :focus-visible{ outline:none; box-shadow: var(--sh-focus) } 特异性 (0,1,0)，
 *     本文件里带静止态 box-shadow 的组件同为 (0,1,0) 且更靠后加载 → 焦点环被静默覆盖、键盘焦点不可见；
 *  ② .entry-card 的静止态 box-shadow 带强制覆盖声明（style.css:1673/1675/1676/1695），
 *     box-shadow 想压过它只能也写强制覆盖声明，触团队红线。
 * outline 不受 box-shadow 的强制覆盖声明影响；现代 Chrome 的 outline 跟随 border-radius。
 * 几何一致性实测：outline-width 2px + outline-offset 2px 与 --sh-focus 的内环色像素带完全重合
 * （同落在「边框外缘 2px ~ 4px」）；10 套主题 --c-focus 与 --sh-focus 内环色逐字节相同。
 * clarity 例外：其 --sh-focus 内环 spread=5px → --focus-ring-w 覆盖为 3px。
 * 另：本规则不再需要与 inset 环叠加 —— outline 与 inset box-shadow 互不干扰，
 *     .theme-option.is-checked / .disclosure-toggle[aria-expanded="true"] 的 inset 环留在各自原规则里。
 * ★ .video-card（2026-10-03 补，team-lead 裁决 ②）：app.js:1072 把它渲染成
 *   `<a href target="_blank" rel="noopener noreferrer">`，**键盘可达**，此前却**完全没有任何
 *   焦点指示**（聚焦态 outline-style:none）= WCAG 2.4.7 失败。
 *   来源查证（CSSOM 全表枚举 + `a.matches(selectorText)`，含递归 @media）：
 *   **没有任何作者规则**给 .video-card 声明 `outline*` —— 聚焦前的 `outline-style:none` 就是
 *   CSS **初始值**（width 3px = medium、color = currentColor = UA 链接色 rgb(0,0,238)/0px）。
 *   故本条 (0,2,0) 无对手，直接生效；**不需要**写 `.video-list .video-card:focus-visible` 之类
 *   更高权重，也**不需要** !important。
 * ⚠️ 已知残余：style.css:353 与 style.css:1738 的 `transition: all 0.2s`（后者带 !important）
 *   会让 .video-card 的焦点环**从初始值动画出现**（与 G11b 在那 7 个类上修掉的是同一个毛病）。
 *   G11b 的 `:focus-visible{transition:none}` 是 (0,1,0)，压不过 style.css:1738 的 !important；
 *   组件层红线 !important = 0 → 随第三批退役 style.css 时一并删除该 !important。 */
.link-button:focus-visible,
.disclosure-toggle:focus-visible,
.hotline-more > summary:focus-visible,
.theme-toggle:focus-visible,
.theme-option:focus-visible,
.skip-link:focus-visible,
.entry-btn:focus-visible,
.action-btn:focus-visible,
.mobile-toggle:focus-visible,
.nav-item:focus-visible,
.nav-subitem:focus-visible,
.nav-group-title:focus-visible,
.entry-card:focus-visible,
.quick-item:focus-visible,
.search-result-item:focus-visible,
.page-nav-btn:focus-visible,
.video-card:focus-visible {
  outline: var(--focus-ring-w) solid var(--c-focus);
  outline-offset: 2px;
}

/* --- G11b. 焦点态不得参与过渡（2026-10-03 实测） ---
 * 缺陷：style.css 的 7 个交互类写了 `transition: all`（见下表行号），而 outline 的四个分量里
 *   `outline-style` 是**离散**属性、不可插值 → 立刻生效；
 *   `outline-width` / `outline-color` / `outline-offset` 是**可插值**属性 → 被 `transition: all`
 *   从初始值（medium = 3px / currentColor / 0px）过渡到目标值（2px / --c-focus / 2px）。
 * 于是键盘用户每按一次 Tab，看到的是「3px 粗环 + 文字色 + 贴边」动画 200–300ms 缩成
 * 「2px 琥珀环 + 外扩 2px」——既让「焦点环统一」形同虚设，也踩了 §3.7 的同类问题
 * （这次不是"配对属性要一起过渡"，而是"根本不该过渡"）。
 *
 * 来源（style.css，逐一实测命中）：
 *   :106  .nav-item            transition: all 0.2s
 *   :119  .nav-subitem         transition: all 0.2s
 *   :196  .quick-item          transition: all 0.2s
 *   :921  .search-result-item  transition: all 0.2s
 *   :1015 .action-btn          transition: all 0.2s
 *   :1282 .entry-card          transition: all 0.3s ease
 *   :1365 .page-nav-btn        transition: all 0.2s
 * （`.nav-group-title` 经 CSSOM 全表枚举**不存在** transition 规则，其 computed transition = `all 0s`
 *   即初始值；探针里读到的 3px/currentColor/0px 是**静止态**，不是过渡中间态，特此澄清。）
 *
 * 本声明加载在 style.css 之后，且与那些 `transition: all` 同为 (0,1,0)，靠源码顺序稳赢；
 * 只在 :focus-visible 命中时生效，故**非聚焦态**的 hover 过渡不受影响（已实测）。
 *
 * ★ 为什么保持**全局**、不收窄到那 7 个类（team-lead 2026-10-03 裁决，请勿"顺手收窄"）：
 *   ① 「焦点态不参与过渡」是一条**状态规则**，不是针对某几个类的补丁；
 *   ② 收窄版会把组件层硬编码到 style.css **今天**的 `transition: all` 清单上 —— 第三批 style.css
 *      退役后那串选择器就成了悬空引用；将来任何新交互类若被加上 `transition: all`，收窄版会
 *      **静默回归**本缺陷，全局版不会；
 *   ③ 全局版会顺带停掉 .theme-toggle / .theme-option / .entry-btn 在**聚焦期间**的过渡 —— 这是
 *      **净收益不是副作用**：这三个类在聚焦期间能发生的状态变化只有"切主题"，而"切主题那一刻
 *      恰好聚焦在它身上"应当瞬时完成；让它自己慢半拍会造成**它与页面其余部分颜色不同步**，
 *      正是 §3.7 要防的那类问题；
 *   ④ 实测已确认静止态 transition 与修复前逐字节一致、hover 过渡不受影响 —— 收窄的唯一收益
 *      （保住聚焦期间的过渡）恰好是最不该保留的。
 * ⚠️ 已知残余（不在本轮修）：style.css:1738 `.video-card { transition: all 0.2s !important }`
 *   （来源已 CSSOM 枚举确认：style.css:353 与 :1738 两条，后者带 !important）会压过本条 (0,1,0)，
 *   故 **.video-card 补上焦点环之后，环仍会从初始值动画出现**。
 *   组件层红线 !important = 0 → 随第三批退役 style.css 时删掉那条 !important。 */
:focus-visible {
  transition: none;
}

/* --- G12. 移动端：浮层近满宽，栅格降 2 列 --- */
@media (max-width: 767px) {
  .theme-panel {
    inset-block-start: var(--sp-16);
    inset-inline: var(--sp-4);
    width: auto;                           /* 窄屏宽度交给 inset-inline 决定，取消固定 width */
    max-width: none;
  }
  .theme-panel__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* --- G13. 搜索框聚焦指示：收敛为一个、主题感知（2026-10-03，team-lead 裁决②落地） ---
 * 改动前实测（warmwood 与 indigo-night **逐字节相同** = 对主题 100% 免疫）：
 *   .search-box:focus-within  ← style.css:1597-1601
 *     background: white !important;              ← 硬编码白，无法主题化（!important，组件层不与之对抗）
 *     border-color: var(--primary);              ← 遗留 token，10 套主题下恒为 #2563eb
 *     box-shadow: 0 0 0 3px rgba(37,99,235,.1);  ← 硬编码蓝、10% 透明度 = 极弱的"光晕"
 *   同时 input 自身吃到 tokens.css:183-187 全局 :focus-visible 的 --sh-focus（另一色、另一机制）。
 *   ⇒ 一个控件上同时出现两套焦点指示、两种颜色（warmwood = 蓝框+琥珀内环；indigo-night = 蓝框+靛蓝内环）。
 *
 * 本条做三件事：
 *  ① 把外层环换成全站规范的 --sh-focus（几何 = outline 2px + offset 2px，与 G11 的 17 个类完全一致；
 *     --sh-focus 的第一层是 --c-canvas，自带上底色反差，比裸 outline 在浅底上更稳）。
 *  ② 边框随主题走：var(--primary) → var(--c-focus)，消除"蓝框 + 琥珀/靛蓝环"的撞色。
 *  ③ 抑制 input 自身的 --sh-focus 环（(0,3,0) 压过 tokens.css:183-187 的 (0,1,0)），
 *     让这个控件只有一个焦点指示。**⚠️ 耦合警告：③ 依赖 ① 存在。若删掉本条的 :focus-within 规则，
 *     必须同时删掉 input 的 box-shadow:none，否则搜索框会退回"完全无焦点指示"（WCAG 2.4.7 失败）。**
 *
 * 不对抗的（明确留白，属第三批）：style.css:1592/1598 的 background 两处 !important
 *   （--primary-lighter / white）压不动 ⇒ 搜索框在暗色主题下仍是浅底。这与 .header 自身
 *   未主题化是同一个问题（头部整体是第三批范围），不是本条能单独修的。
 * transition：style.css:1595 的 `transition: all .2s` 会让环动画（§7.1⑯ 同类问题）。
 *   本条在**基础规则**上直接 transition:none，入、出两个方向都不动画 ——
 *   比 G11b（只在 :focus-visible 命中时禁，故那 17 个类仍有"消失时淡出"残余）更彻底。
 *   .search-box 无 hover 规则，置 none 无副作用（已核对 style.css 全文，仅 :46/:1591/:1597/:1602/:1605/:1608 六处）。
 * 权重核算：.search-box:focus-within = (0,2,0)，与 style.css:1597 相同，本文件加载在后 → 稳赢；
 *          .search-box input:focus-visible = (0,3,0) > tokens.css 全局 (0,1,0) → 稳赢。均无需 !important。 */
.search-box {
  transition: none;
}
.search-box:focus-within {
  box-shadow: var(--sh-focus);
  border-color: var(--c-focus);
}
.search-box input:focus-visible {
  box-shadow: none;
}

/* --- G14. 首页 hero 图标：恢复显示（2026-10-03，team-lead 裁决①落地） ---
 * 背景：`data/home.json` 的 `hero.icon` 原为空串，`app.js:252` 已有空值守卫（空则不渲染结构）。
 *   本轮把 icon 设为 `books`（见 §9.9 的选型论证），但 **显示不出来** ——
 *   `style.css:1240-1242`（「首页高端样式升级」块）明确写了 `.welcome .icon { display: none }`，
 *   这是一次**刻意的设计决策**（当时决定 hero 不放图标）。
 * 本条 = 有意识地**推翻那一次决策**（用户 2026-10-03 明确要求 hero 要有图标）。
 *   `.welcome .icon` (0,2,0) 同权重、本文件加载在后 → 稳赢，无需 !important。
 * 尺寸/间距仍由 style.css:170 提供（font-size:48px + margin-bottom:12px），
 *   SVG 的 48px 由 app.js 的 icon(name,{size:48}) 落到 width/height 属性，两者互不依赖。 */
.welcome .icon {
  display: block;
}




/* ==========================================================================
 * H. 残余语义类（2026-10-03 追加，§5.8 H 组；app.js 重构的残余语义类）
 * ========================================================================== */

.page-footer {
  text-align: center;
  margin-block-start: var(--sp-6);
}

/* 普通案例块（base）：2026-10-03 第三轮追加的「边界穿越收口」。
   为什么必须动它：a11y 全量重扫（57 探针 × 10 主题）里剩的 24 项 <4.5，有 20 项全部来自本基类——
   style.css:317-331 的基类用遗留 token（--purple / --text-light / --text）+ 固定浅紫渐变底，
   10 套主题下数值**逐字节相同**（.case-title 4.10、.case-source 4.03），是典型「主题盲孤岛」。
   修法与 `--positive` 同源：自洽的底 + 字，逐个子元素显式声明（子孙规则是 (0,2,0)，容器设 color 压不过）。
   取值依据（10 主题实测最差，见交付报告矩阵）：
     .case-title   --c-accent-text on --c-surface = 5.48  ·  .case-content --c-text on --c-surface = 12.99
     .case-source  --c-text-muted  on --c-surface = 6.46
   本块必须写在 `.case-block--positive` 规则**之前**：两者特异性打平，靠源码顺序让修饰符胜出。
   ⚠️ 视觉变更：案例块由「薰衣草渐变」变为「主题表面 + 强调色左条」（与 .state-block/.table 同族）。 */
.case-block {
  background: var(--c-surface);
  border-inline-start-color: var(--c-accent);
  color: var(--c-text);
}

.case-block .case-title   { color: var(--c-accent-text); }
.case-block .case-source  { color: var(--c-text-muted); }
.case-block .case-content { color: var(--c-text); }

/* 正面案例块：本批唯一「主题感知」成员（team-lead 裁决 (a)）。
   1) 可读 > 美观：暗色下会是一块深绿卡片夹在浅紫卡片之间（视觉不统一），但文字可读；
      若退回 --c-text（基类固定浅紫底）则暗色仅 1.04:1 不可读 —— 前者可接受，后者不行。
   2) 不做基类 .case-block token 化：themes.css 不覆盖遗留 token，基类是主题盲的；
      但那是第三批「style.css 整体退役」的范畴，本批动它会波及 48 个内容页的全部案例块。
   3) 让 --positive 内部自洽（底与字同源同主题）是本批唯一正确的边界。
   4) 更正（2026-10-03 a11y 重扫）：上一轮注释写的「内部自洽、文字可读」只对 .case-title 成立，
      对**正文不成立** —— style.css:330/331 以 (0,2,0) 把 .case-source/.case-content 钉成遗留色
      （--text-light / --text），压在暗色主题的深绿底 --c-ok-soft 上实测仅 3.23:1 / 1.05:1。
      故正文必须**逐个子元素**显式声明：容器设 color 没用，会被 (0,2,0) 的子孙规则压过。
      （实测确认：本类 .case-dialogue 只会出现在**基类** .case-block 内，见 app.js:773-780；
        .case-block--positive 的两处渲染 app.js:784/880 只含 .case-title + .case-content，无 .case-dialogue。）
   ⚠️ TODO(第三批)：.case-content / .case-source 是 style.css 拥有的类名，这里是**边界穿越**。
      正解是第三批把 style.css 整体 token 化，届时本条应删除。 */
.case-block--positive {
  background: var(--c-ok-soft);
  border-inline-start-color: var(--c-ok);
}

.case-block--positive,
.case-block--positive .case-content,
.case-block--positive .case-source {
  color: var(--c-ok-text);
}

.case-block--positive .case-title {
  color: var(--c-ok-text);
}

.text-muted {
  color: var(--c-text-muted);
}

.text-center {
  text-align: center;
}


/* ==========================================================================
 * I. 交互元素 UA 重置（§5.8 I 组，2026-10-03 追加，随 app.js 的 div[onclick] → a/button 转换）
 *
 * style.css 里没有任何全局 a / button 规则，所以元素换成 <a>/<button> 后会立刻吃到 UA 默认：
 *   <button>：border:2px outset、background:buttonface、字体不继承父级、text-align:center
 *             （UA 默认 padding 是 1px 6px，但被 style.css:2 的 `*{padding:0}` 作者样式清零 ——
 *              裸 <button> 实测 padding = 0px，故 padding 不在本组需要清 UA 的理由之列）
 *   <a>：color:-webkit-link（蓝）、text-decoration:underline
 *
 * 必须清掉，但绝不能覆盖既有作者规则。反例：写成 button.nav-item（权重 (0,1,1)）会反压
 * style.css 的 .nav-item.active{ color:white }（(0,1,0)）→ 导航当前项掉色。
 *
 * 做法：整条复合选择器包进 :where()，把权重降到 (0,0,0) —— 只赢 UA 默认、输给每一条作者规则。
 *
 * ⚠️ 只能写 :where(a.X, button.X)（整个复合选择器在括号内）。
 *    写成 :where(a, button).X 权重仍是 (0,1,0) —— 那是这个方案唯一致命的写法错误。
 * ⚠️ 不写 display / width：交给既有类（.nav-item 已是 display:flex、.nav-group-title 也是；
 *    栅格子项会自动 blockify，.entry-card 不需要 width:100%）。写 display 反而会在既有类
 *    未声明 display 时引入意外值。
 * ⚠️ padding:0; margin:0 在这里是安全的：权重 0，会被既有类的 padding 覆盖（浏览器实测已证）。
 * ========================================================================== */
:where(a.nav-item,            button.nav-item),
:where(a.nav-subitem,         button.nav-subitem),
:where(a.nav-group-title,     button.nav-group-title),
:where(a.entry-card,          button.entry-card),
:where(a.quick-item,          button.quick-item),
:where(a.search-result-item,  button.search-result-item),
:where(a.page-nav-btn,        button.page-nav-btn) {
  font: inherit;
  text-align: inherit;
  color: inherit;
  text-decoration: none;
  border: 0;
  background: none;
  padding: 0;
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
}


/* --- I2. 导航类宽度补齐（A/B 实测：<button> 的 width:auto 恒为 fit-content） ---
 * 同父容器内 div/a = 239px，button = 92px（.nav-item，实测父容器 240）。
 * 原因：Blink 把 <button> 当表单控件固有尺寸处理，width:auto 恒解析为 fit-content，与 display 值无关。
 * :where() 组故意不写 width（权重 0，写了也会被既有类覆盖），故在此以 (0,1,0) 显式补。
 * （components.css 在 style.css 之后加载，同为 (0,1,0) 时本文件胜出。）
 * 实测差异：.nav-item 缺 147px / .nav-group-title 缺 37.5px / .nav-subitem 缺 81px。 */
.nav-item        { width: 100%; }
.nav-group-title { width: 100%; }
.nav-subitem     { display: block; width: 100%; }   /* 原无 display：button 为 inline-block(158px、高 33px)，div/a 为 block(239px) */


/* ==========================================================================
 * J. 方法标签（补 style.css:285-301 的对比度缺陷；2026-10-03 追加，§5.8 之外的覆盖层）
 * ----------------------------------------------------------------------------
 * 实测：style.css 的 .method-tag 是 color:#fff + .tag-* 的 *-500 档硬编码底 = 2.15–4.13:1，全不达标；
 * 且 data/** 在用的 tag-danger **没有**对应背景规则 → 白字压白卡 1:1，文字完全不可见
 * （data/medication/side-effects.json 的「严重副作用」、data/selfcheck/avoid-misleading.json 的「常见套路」）。
 * 覆盖理由：.method-tag.tag-x = (0,2,0) 高于 style.css 的 .tag-x = (0,1,0)，稳赢。
 * 统一改为「软底 + 深字」，与 .alert / .badge 同一套 --c-*-soft / --c-*-text 语义。
 * ⚠️ 这是**有意的视觉变更**（实心色块 → 软底色块），已获 team-lead 同意。
 * ========================================================================== */
.method-tag { background: var(--c-surface); color: var(--c-text); }
.method-tag.tag-medical,
.method-tag.tag-danger,
.method-tag.tag-symptom   { background: var(--c-danger-soft); color: var(--c-danger-text); }
.method-tag.tag-parent    { background: var(--c-accent-soft); color: var(--c-accent-text); }
.method-tag.tag-psychology,
.method-tag.tag-school,
.method-tag.tag-check,
.method-tag.tag-note      { background: var(--c-info-soft); color: var(--c-info-text); }
.method-tag.tag-behavior,
.method-tag.tag-method    { background: var(--c-ok-soft);    color: var(--c-ok-text); }
.method-tag.tag-warning   { background: var(--c-warn-soft);  color: var(--c-warn-text); }


/* ==========================================================================
 * 受控工具类白名单（§5.7，只允许这 6 个，禁止自造）
 * ========================================================================== */

.flush            { margin: 0; }                          /* 吸收原 margin-bottom:0 */
.flush-block-end  { margin-block-end: 0; }                /* 容器内最后一块取消下边距 */
.text-lg          { font-size: var(--fs-lg); }
.text-sm          { font-size: var(--fs-sm); }
.text-xs          { font-size: var(--fs-xs); }
.text-2xs         { font-size: var(--fs-2xs); }


/* --- G15. 视频作者身份徽章 + 本页作者资质区块（2026-10-03，D5） ---
 * 硬约束（改这块前先读完）：
 * A. 卡片颜色不再锚定，完全跟随主题 token。（R4 修订：原「亮色孤岛」token
 *    重绑块已删除——style.css 已全量主题化，.video-card 用的遗留 token
 *    --white/--text/--text-light/--primary 也已在文件头部 :root 桥接到语义
 *    token，随主题翻转，无需再锚定回 L1 色阶。）
 * B. 本区块绝不声明任何 outline* / transition 属性：.video-card 的焦点环是
 *    独立验收成果（r2_videocard.js PASS 3/3），style.css:1736-1742 还有
 *    transition: all .2s !important 残余。这里只允许声明自定义属性（--c-*）
 *    和新增子元素的样式。
 * 颜色只引用 token，禁止裸 hex。
 * ======================================================================== */

/* 徽章与 11px 作者名对齐（.v-author 在 style.css:358 是 11px，.badge 默认
 * --fs-2xs=12-13px，不缩会盖过作者名） */
.video-card .v-author .badge {
  font-size: 1em;
  padding: 1px var(--sp-2);
  line-height: var(--lh-snug);
}

/* 本页作者资质区块 —— 在卡片【外】，是普通主题元素，不做 token 锚定（约束 A
 * 只针对卡片孤岛）。视觉语言对齐 style.css 的 .video-copyright-notice：
 * 软底 + 左侧竖线 + 单侧圆角 + 紧凑内距 + 12px 字号（全部换成 token 等价物） */
.video-authors {
  margin-top: var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
  background: var(--c-surface-2);
  border-left: 3px solid var(--c-border);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  font-size: var(--fs-2xs);
  line-height: var(--lh-normal);
  color: var(--c-text-muted);
}
.video-authors__title {
  font-weight: var(--fw-medium);
  color: var(--c-text);
  margin-bottom: var(--sp-1);
}
.video-authors__list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.video-author {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-1) 0;
}
.video-author .badge { flex: none; }
.video-author__name {
  font-weight: var(--fw-medium);
  color: var(--c-text);
}
/* 另起一行：长资历文本 flex 满行，避免挤压姓名/徽章 */
.video-author__info {
  flex: 1 1 100%;
  min-width: 0;
  word-break: break-word;
  color: var(--c-text-muted);
  font-size: var(--fs-2xs);
}
@media (max-width: 480px) {
  .video-authors { padding: var(--sp-2) var(--sp-3); }
}

/* ==========================================================================
 * R9 第三批（评审路线图第 3 档 · 项 1-3）
 * 1) 排版节奏：.prose 接线后的大区块间距 + 标题 3:1 节奏
 * 2) 主题人格：::selection / 滚动条 / 标题 accent 短条（token 全部现成，零自创）
 * 3) 骨架屏：替代「正在加载…」静止文字（仅动画 opacity，遵守规范微交互红线）
 * ========================================================================== */

/* --- 1a. 大区块节奏：正文页 .prose 顶层子元素全为大区块，用 --section-gap ---
 * 遗留块 margin 最大 20px < --section-gap 最小值 40px，相邻 collapse 取大者，无叠加风险 */
.prose > section + section,
.prose > div + section,
.prose > section + div,
.prose > div + div {
  margin-block-start: var(--section-gap);
}
/* 头部之后第一个块收紧一档，避免 header→正文之间出现最大间隙 */
.prose > *:first-child {
  margin-block-start: 0;
}

/* --- 1b. 标题节奏：块内 h3 上距 : 下距 ≈ 3:1（--sp-5 : --sp-2 = 20:8） --- */
.prose h3 {
  margin-block: var(--sp-5) var(--sp-2);
}

/* --- 2. 主题人格 --- */
/* 选区：--c-selection-bg/text 十主题全量定义于 themes.css（此前从未使用） */
::selection {
  background: var(--c-selection-bg);
  color: var(--c-selection-text);
}
/* 滚动条：thumb 走 accent，track 透明，随主题换人格 */
html {
  scrollbar-width: thin;
  scrollbar-color: var(--c-accent) transparent;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--c-accent);
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: var(--r-md);
}
::-webkit-scrollbar-thumb:hover { background: var(--c-accent-hover); background-clip: padding-box; }
/* 标题 accent 短条：页面主标题下方 48×3 强调条（对比度零风险——不改变文字颜色） */
.content-header h2::after {
  content: '';
  display: block;
  width: 48px;
  height: 3px;
  margin-top: var(--sp-2);
  border-radius: 2px;
  background: var(--c-accent);
}

/* --- 3. 骨架屏 --- */
.skel-page { padding: var(--sp-4) 0; }
.skel {
  border-radius: var(--r-md);
  background: var(--c-surface-2);
  animation: skel-pulse 1.4s ease-in-out infinite;
}
.skel--crumb  { width: 30%; height: 12px; margin-bottom: var(--sp-6); }
.skel--title  { width: 65%; height: 28px; margin-bottom: var(--sp-3); }
.skel--line   { width: 100%; height: 14px; margin-bottom: var(--sp-2); }
.skel--w70    { width: 70%; }
.skel--block  { width: 100%; height: 96px; margin-top: var(--sp-8); }
.skel--w90    { width: 90%; }
.skel--w60    { width: 60%; }
@keyframes skel-pulse {
  50% { opacity: 0.45; }
}
@media (prefers-reduced-motion: reduce) {
  .skel { animation: none; }
}

/* ==========================================================================
 * R10 第三批（评审路线图第 3 档 · 项 4）：桌面版式 + 右侧自动 TOC
 * .main 为 flex（sidebar + content + toc 三子项）；
 * TOC 仅 ≥1280 显示，≥1440 整体居中（此宽度下三栏总宽 1380 < 视口，不溢出）
 * ========================================================================== */
.toc { display: none; }

@media (min-width: 1280px) {
  .toc {
    display: block;
    position: sticky;
    top: 96px;
    align-self: flex-start;      /* sticky 生效前提：不随 .main stretch 拉满 */
    flex: 0 0 220px;
    width: 220px;
    max-height: calc(100vh - 140px);
    overflow-y: auto;
    padding: var(--sp-4);
    border-left: 2px solid var(--c-divider);
    font-size: var(--fs-xs);
  }
  .toc-title {
    font-weight: var(--fw-semibold);
    color: var(--c-text-muted);
    font-size: var(--fs-2xs);
    margin-bottom: var(--sp-2);
  }
  .toc-link {
    display: block;
    width: 100%;
    text-align: left;
    padding: var(--sp-1) var(--sp-2);
    background: none;
    border: none;
    border-left: 2px solid transparent;
    margin-left: calc(-1 * var(--sp-4) - 2px);   /* 悬停/高亮色条贴容器左缘 */
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
  }
  .toc-link:hover { color: var(--c-text); background: var(--c-surface-2); }
  .toc-link.active {
    color: var(--c-accent);
    border-left-color: var(--c-accent);
    font-weight: var(--fw-medium);
  }
}

@media (min-width: 1440px) {
  .main { justify-content: center; }   /* 1440 下三栏居中，右侧空白变 TOC 资产 */
}

/* TOC 平滑滚动落点预留 sticky 头部高度 */
.prose h3 { scroll-margin-top: 96px; }
@media (prefers-reduced-motion: reduce) {
  .prose h3 { scroll-behavior: auto; }
}


/* ==========================================================================
 * G16 · 家庭现状梳理（#/scan）
 * --------------------------------------------------------------------------
 * 由 js/scan.js 渲染。类名**已冻结**：逐字实现，不改名、不自创同类、不缩写。
 *
 * token 存在性核查（`grep -o -- '--[a-z0-9-]*' css/tokens.css css/themes.css`）：
 *   ✔ 存在：--c-accent --c-surface --c-surface-2 --c-border --c-text --c-on-accent
 *     --c-accent-soft --c-accent-hover --c-accent-border --c-text-muted --c-text-faint
 *     --c-focus --focus-ring-w --sh-1 --sh-2 --sh-focus --r-sm --r-md --r-lg --r-full
 *     --bw-1 --bw-2 --border-style --measure --sp-1…--sp-8 --fs-2xs…--fs-2xl
 *     --lh-normal --lh-relaxed --fw-medium --fw-semibold --fw-bold --dur-1 --dur-2 --ease-out
 *   ✗ **不存在**：--c-text-2 / --c-text-3 → 按语义映射到 --c-text-muted（次要）/
 *     --c-text-faint（最弱）（DESIGN-SPEC §3.1 的真实命名）。
 *   规格里的其它后备分支（999px / --fw-bold / --dur-1 / --sh-focus）**均未启用**，token 都存在。
 *
 * 形态与无障碍（§5.6）：容器边框一律 `var(--bw-*) var(--border-style) var(--c-*)`，
 *   不写死 solid；静止态带 --sh-1；flex/grid 子项显式 min-width:0；
 *   焦点环沿用 §5.8 I 组的统一写法（outline + --focus-ring-w + --c-focus，
 *   `clarity` 主题把 --focus-ring-w 提到 3px，写死 2px 会与它脱节）。
 *   自带背景的容器同时显式声明 color（§5.8「.state-block 教训」：组件不得靠继承取字色）。
 * ========================================================================== */

/* --- 容器与头部 --- */
.scan-wrap {
  max-width: var(--measure);              /* 34em = 正文理想行长；--measure 存在 */
  margin-inline: auto;                    /* 窄容器居中 */
  min-width: 0;                           /* §5.6 规则三 */
}

.scan-head {
  margin-bottom: var(--sp-6);
  min-width: 0;
}

.scan-title {
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  color: var(--c-text);
}

.scan-lead {
  font-size: var(--fs-base);
  color: var(--c-text-muted);             /* 规格写 --c-text-2，该 token 不存在 */
  line-height: var(--lh-relaxed);
}

/* --- 进度（题数制，无时间） --- */
.scan-progress {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-block: var(--sp-5);
}

.scan-progress__track {
  height: 8px;
  min-width: 0;                           /* flex 子项 */
  border-radius: var(--r-full);           /* 存在（999px），无需后备 */
  background: var(--c-surface-2);
  border: var(--bw-1) var(--border-style) var(--c-border);
  overflow: hidden;
}

.scan-progress__fill {
  width: var(--scan-p, 0%);               /* 脚本 setProperty('--scan-p', …) 驱动 */
  height: 100%;                           /* 必要补充：轨道不是 flex，缺此行填充高度会塌成 0 */
  background: var(--c-accent);
  border-radius: inherit;
  /* 缓动走设计系统的 --ease-out（§3.7 默认指数缓出），不用关键字 ease */
  transition: width var(--dur-2) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .scan-progress__fill { transition: none; }
}

.scan-progress__text {
  font-size: var(--fs-sm);
  color: var(--c-text-faint);             /* 规格写 --c-text-3，映射到最弱文字 */
  min-width: 0;
}

/* --- 入口页 --- */
.scan-intro {
  background: var(--c-surface-2);
  color: var(--c-text);                   /* 自带底就必须自带字色（§5.8 .state-block 教训） */
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  min-width: 0;
}

.scan-intro__list {
  margin-block: var(--sp-3);
  padding-inline-start: var(--sp-6);
}

/* 主行动按钮：复用 .entry-btn 视觉、独立命名。border 用透明色 + --border-style，
   与 .entry-btn 完全一致（既清掉 UA 边框，又让墨纸主题的 double 形态语言生效）。 */
.scan-start {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-6);
  background: var(--c-accent);
  color: var(--c-on-accent);              /* 存在，无需另找主色前景 token */
  border: var(--bw-1) var(--border-style) transparent;
  border-radius: var(--r-md);
  cursor: pointer;
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  min-height: 44px;                       /* 触控目标 */
  min-width: 0;
  box-shadow: var(--sh-1);                /* §5.6 规则二 / 与 .entry-btn 一致 */
  /* color 必须进过渡列表，否则切主题 200ms 内出现「新字色 + 旧底色」的低对比闪烁（§3.7） */
  transition: color var(--dur-2) var(--ease-out),
              background var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}

.scan-start:hover {
  background: var(--c-accent-hover);
  box-shadow: var(--sh-2);
}

/* --- 题目 --- */
.scan-q {
  margin-block: var(--sp-6);
  min-width: 0;
}

.scan-q__label {
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);        /* 存在，无需退回 --fw-bold */
  color: var(--c-text);
  margin-bottom: var(--sp-2);
}

.scan-q__hint {
  font-size: var(--fs-sm);
  color: var(--c-text-faint);             /* 规格写 --c-text-3 */
  margin-bottom: var(--sp-4);
}

.scan-opts {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.scan-opt {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-text);                   /* 自带底 → 自带字色 */
  cursor: pointer;
  min-height: 44px;                       /* 触控目标 */
  min-width: 0;                           /* flex 子项（.scan-opts 是 column flex） */
  transition: color var(--dur-2) var(--ease-out),
              background var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}

.scan-opt:hover { background: var(--c-surface-2); }

/* 选中态（:has 路线）：颜色 + 内描边双通道，不单靠颜色（WCAG 1.4.1） */
.scan-opt:has(input:checked) {
  border-color: var(--c-accent);
  background: var(--c-accent-soft);       /* 存在，无需退回 --c-surface-2 */
  box-shadow: inset 0 0 0 var(--bw-2) var(--c-accent);
}

/* 选中态降级（不依赖 :has 的浏览器 / 脚本直接加类）。
   ⚠️ 必须与上一条**分开写成独立规则**：若把两者并进同一个选择器列表，
   不支持 :has 的浏览器会因「列表里有一个无效选择器」而丢弃**整条规则**，降级随之失效。 */
.scan-opt--on {
  border-color: var(--c-accent);
  background: var(--c-accent-soft);
  box-shadow: inset 0 0 0 var(--bw-2) var(--c-accent);
}

/* 内嵌 input 聚焦 → 整行可见环（沿用 I 组统一写法，不用 --sh-focus 以免吃掉静止态阴影语义） */
.scan-opt:focus-within {
  outline: var(--focus-ring-w) solid var(--c-focus);
  outline-offset: 2px;
}

/* 原生控件跟随主题色；flex:none 防止被压缩 */
.scan-opt input {
  flex: none;
  accent-color: var(--c-accent);
}

/* 选中态的非颜色线索之三：文字提重（不依赖 :has，兼容所有环境） */
.scan-opt input:checked ~ .scan-opt__text {
  font-weight: var(--fw-medium);
}

.scan-opt__text {
  font-size: var(--fs-base);
  color: var(--c-text);
  line-height: var(--lh-normal);
  min-width: 0;                           /* 长题干在 375px 下不撑破 */
}

/* --- 导航 --- */
.scan-nav {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-8);
  flex-wrap: wrap;
}

.scan-nav__btn {
  padding: var(--sp-3) var(--sp-5);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-text);
  cursor: pointer;
  min-height: 44px;
  min-width: 0;
  font-size: var(--fs-base);
  transition: color var(--dur-2) var(--ease-out),
              background var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out);
}

.scan-nav__btn:hover {
  background: var(--c-surface-2);
  border-color: var(--c-border-strong);
}

/* 禁用态：opacity 之外保留 cursor 语义（色觉无关） */
.scan-nav__btn:disabled {
  opacity: .5;
  cursor: not-allowed;
}

.scan-nav__btn--primary {
  background: var(--c-accent);
  color: var(--c-on-accent);              /* 主色上的前景色 */
  border-color: transparent;
}

.scan-nav__btn--primary:hover {
  background: var(--c-accent-hover);
  border-color: transparent;
}

/* --- 中途停靠 --- */
.scan-midstop {
  background: var(--c-surface);
  color: var(--c-text);                   /* 自带底 → 自带字色 */
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  box-shadow: var(--sh-1);                /* §5.6 规则二 */
  min-width: 0;
}

/* --- 结果页 --- */
.scan-result {
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
}

.scan-section {
  min-width: 0;                           /* flex/grid 子项 */
}

/* 标题不加任何 ::before 装饰（§5.2 保持克制） */
.scan-section__title {
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  color: var(--c-text);
  margin-bottom: var(--sp-4);
}

.scan-focus {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* 关注点回显：**中性标签**，绝不用色阶表达"程度/严重度"（§0.1 红线一） */
.scan-focus__item {
  padding: var(--sp-2) var(--sp-4);
  background: var(--c-surface-2);
  color: var(--c-text);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  min-width: 0;
}

.scan-card {
  background: var(--c-surface);
  color: var(--c-text);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  box-shadow: var(--sh-1);                /* §5.6 规则二 */
  min-width: 0;
}

/* 说明行：选「左侧细条 + 缩进」而非 italic —— 中文斜体多为伪斜，克制度更差。
   细条属**分隔/引用条**而非轮廓，故按 §5.6 固定 solid。（选择更克制的一种） */
.scan-card__why {
  font-size: var(--fs-base);
  color: var(--c-text-muted);
  border-inline-start: var(--bw-2) solid var(--c-border);
  padding-inline-start: var(--sp-4);
}

.scan-card__list {
  margin-block: var(--sp-3);
  padding-inline-start: var(--sp-6);
  color: var(--c-text);
  line-height: var(--lh-relaxed);
}

.scan-card__grade {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
  font-size: var(--fs-xs);
  color: var(--c-text-faint);             /* 规格写 --c-text-3 */
  flex-wrap: wrap;
}

/* 与 style.css:463 的 .thing-block 叠加使用（脚本同时挂两个类），**只做强调、不改配色**。
   基类自带：background / --r-lg / --sp-6 padding / border-top:4px var(--primary) / 阴影。
   本类只补「左侧 4px 主色强调条」+ 抬升一档阴影，不触碰基类任何既有属性。
   ⚠️ 基类没有声明 border-inline-start-style（默认 none），只给 width/color 强调条不会渲染，
   故按 §5.6 规则一补 `var(--border-style)` —— 这是规格未列、但必须补的一行。 */
.thing-block--primary {
  border-inline-start-width: 4px;
  border-inline-start-style: var(--border-style);
  border-inline-start-color: var(--c-accent);
  box-shadow: var(--sh-2, var(--sh-1));
}

/* --- 带走按钮组（打印时隐藏，见下） --- */
.scan-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}

.scan-action-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  background: var(--c-surface);
  border: var(--bw-1) var(--border-style) var(--c-border);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  color: var(--c-text);
  cursor: pointer;
  min-height: 40px;
  min-width: 0;
  transition: color var(--dur-2) var(--ease-out),
              background var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out);
}

.scan-action-btn:hover {
  background: var(--c-surface-2);
  border-color: var(--c-border-strong);
}

/* --- 焦点环（§5.8 I 组统一写法）---
   本文件此前**没有任何 @media print 段**、也没有用权重压制的先例，
   故这里统一用 outline + --focus-ring-w + --c-focus，不用 --sh-focus
   （避免吃掉 .scan-opt 选中态的内描边与按钮的静止态阴影）。 */
.scan-start:focus-visible,
.scan-nav__btn:focus-visible,
.scan-action-btn:focus-visible {
  outline: var(--focus-ring-w) solid var(--c-focus);
  outline-offset: 2px;
}

/* --- 缓一缓的证据分组标题 ---
   E1/E2 与 P1（站长个人经验）分开列，不混排（闸门 5.3）。
   仅当两组都存在时才由 scan.js 输出。
   颜色统一用 --c-text-muted：--c-text-faint 在 warmwood/moss/clay/sky/
   wisteria 5 套主题下对背景对比度 < 4.5（独立验证实测 3.69–4.48），不能用。 */
.scan-pause__group {
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--c-text-muted);
}

/* --- 打印 ---
   本文件此前无 @media print 先例，且组件层禁止强制覆盖声明 →
   **不使用强制覆盖**，改用 `body .scan-*`（0,1,1）提高权重，
   稳稳压过本文件里 .scan-* 基础规则的 (0,1,0)（tokens/themes/style 均无同名 display 规则）。 */
@media print {
  body .scan-actions,
  body .scan-nav,
  body .scan-progress {
    display: none;
  }

  .scan-wrap { max-width: none; }

  .scan-card,
  .scan-midstop {
    box-shadow: none;                     /* 纸张上阴影是噪点 */
    break-inside: avoid;
  }

  .scan-section { break-inside: avoid; }
  .scan-opt { break-inside: avoid; }      /* 选项文字始终在文档流内，无任何打印规则隐藏它 */

  .scan-result { font-size: 12pt; }

  /* 折叠内容：打印时必须完整可见。
     UA 用 ::details-content{content-visibility:hidden} 隐藏关闭态内容，
     旧的 details{display:block} 对此无效（实测 Chrome 154：非危机打印件
     会整段丢失就医清单）。作者来源优先于 UA 来源，普通声明即可覆盖，
     不需要强制覆盖声明。兜底：scan.js 在 beforeprint 时把全部 <details>
     置为 open，afterprint 还原。 */
  details::details-content { content-visibility: visible; }
  details > summary { list-style: none; }
  /* 就医清单的"点开看完整清单"在纸面上已无意义（内容必然已展开）；
     周卡组的 summary 是卡片标题，必须保留。 */
  body details.disclosure-help > summary { display: none; }
}

/* ==========================================================================
   SEO-H1 等价样式（2026-10 静态预渲染链路）
   --------------------------------------------------------------------------
   为满足「每页恰好一个 <h1>，且其文本 = 该页标题」，本批做了两处标签调整：
     ① 站点名由 <h1> 降级为 <div class="header__brand">；
     ② 内容页主标题 / 首页 hero 标题由 <h2> 升级为 <h1>。
   受保护文件 style.css / themes.css 里的 h1/h2 规则不改，
   这里用 components.css（最后加载）补齐等价声明，保证视觉零回归。
   实测截图比对见 tools/build_static.py 生成的构建报告。
   ========================================================================== */

/* ① 站点名（原 .header h1，现 .header__brand）—— 等价 style.css 的
   .header h1 { color:var(--primary-dark); font-size:var(--fs-xl); font-weight:700 }
   与 768/480 断点下的 font-size:var(--fs-lg)。 */
.header__brand { color: var(--primary-dark); font-size: var(--fs-xl); font-weight: 700; }
@media (max-width: 768px) { .header__brand { font-size: var(--fs-lg); } }
@media (max-width: 480px) { .header__brand { font-size: var(--fs-lg); } }

/* ②a 内容页主标题（原 .content-header h2，现 <h1>）—— 等价 style.css
   .content-header h2 与 components.css 的 .content-header h2::after 短条。 */
.content-header h1 { font-size: var(--fs-xl); margin-bottom: var(--sp-3); color: var(--primary-dark); }
.content-header h1::after {
  content: '';
  display: block;
  width: 48px;
  height: 3px;
  margin-top: var(--sp-2);
  border-radius: 2px;
  background: var(--c-accent);
}
@media (max-width: 768px) { .content-header h1 { font-size: var(--fs-base); } }

/* ②b 首页 hero 标题（原 .welcome h2，现 <h1>）—— 等价 style.css 中
   .welcome h2 的最终生效规则（:178 → :1330 → :1747 逐层覆盖后的合成值）
   及其 ::after 装饰线（:1755）与 768 断点（:1869）。 */
.welcome h1 {
  font-size: var(--fs-2xl);
  font-weight: 800;
  margin: 0 0 var(--sp-4);
  letter-spacing: 1px;
  color: var(--primary-dark);
  /* 局部 z-index:1：仅用于叠在 .welcome::before 装饰圆之上（与原 h2 一致） */
  position: relative;
  z-index: 1;
}
.welcome h1::after {
  content: '';
  display: block;
  width: 72px;
  height: 4px;
  background: linear-gradient(90deg, var(--primary), var(--accent));
  margin: var(--sp-4) auto 0;
  border-radius: var(--r-xs);
}
@media (max-width: 768px) { .welcome h1 { font-size: var(--fs-xl); } }

/* ②c 衬线标题主题（warmwood / moss / clay 的 #content h2 规则）同步到 h1，
   覆盖内容主标题与首页 hero 两处。 */
html[data-theme="warmwood"] #content h1,
html[data-theme="moss"] #content h1,
html[data-theme="clay"] #content h1 { font-family: var(--font-display); }
