/* Veya h5 · 引流站样式
 *
 * 【唯一 token 收纳点】ds v1 色值与 admin.css 同源，h5.* 只收移动尺寸与构图值。
 *
 * 🔴 **有闸守着的是「色值」，不是「一切裸值」**（R15-CSS-08，260802 订正）：
 *   · 强制（`tpl_smoke::gates` 两条，判据在 `veya_model::css_bare`）——
 *     本文件 `:root` 家族之外**一个色值字面量都不许有**（十六进制与
 *     rgb/rgba/hsl 一并认），模板内联 `style="…"` 同样不许有。
 *     理由是硬的：主题三层（浅 / prefers-color-scheme 深 / [data-theme] 手动）
 *     只对 `:root` 里的变量生效，写在规则里的色值深色档下就是错的。
 *   · **不强制**：尺寸/间距/时长这类裸数值。本文件现有 140 处（admin.css 368 处），
 *     绝大多数是 line-height / flex / 1px 边框这类布局微值，判红只会换来一张
 *     几百行的豁免表 —— 那等于没有闸。新增**设计**尺寸仍应进 :root，但那是约定不是闸。
 *
 * ⚠️ 本抬头原写「禁止裸值」而唯一那道闸只认 `#`，承诺与实守差两个数量级
 *   （0 vs 686），且该判据在自己守的这份文件里漏掉两处 `rgba(` —— 现已同时收口。
 *
 * 主题三层（顺序不可调，手动层必须压过媒体查询）：
 *   ① :root 浅值
 *   ② @media(prefers-color-scheme:dark) 下的 :root:not([data-theme='light']) 深值
 *   ③ :root[data-theme='dark'] 手动覆盖
 *   —— 手动**浅**色档没有第四块：② 的 :not() 自己就让它退回 ①。
 */

:root {
  /* —— ds v1 色（与 admin.css 同源，勿各自演化）—— */
  --veya-primary: #FF8A6B;
  /* 🔴 WCAG AA：caption 12px 的文本要 ≥4.5:1。原值 #F26A4E 在奶油底上只有 2.83:1
     （primary #FF8A6B 更低，2.16:1）—— 这个 token **只用于 color、从不作背景/边框**
     （按钮走 grad-peach + on-accent），所以直接压深是安全的修法，
     不必新增 link-ink 之类的第二个 token。
     深色档**无需改**：#F2846C 在 #2A1F22/#362A2D 上是 6.29/5.43，本来就达标。
     由 tpl_smoke::gates 的对比度断言守着，别改回浅色。

     🔴 **「按钮不受影响」只说明压深本 token 不改按钮外观，不等于按钮达标**
     （R15-WA-01 订正：这句真话此前被放在会读成「按钮已清过」的位置上）。两笔账，一结一开：
       · ✅ **已结（R11-AY04，260802）**：白字压 grad-peach **旧值**起点 #FF9E8A = 2.00:1、
         中点 #F8846C = 2.47、止点 #F26A4E = 3.02 → `.btn-primary` / `.lock-cta` /
         `.rd-btn-next` / `.chip-on` 四类主 CTA 全部不达 AA。渐变已换 #D53F27 → #A82914
         （白字 4.60 / 5.68 / 7.02，全段过 4.5）；`.chip-on` 是 10px 小字，另走描边式。
         ⚠️ 本行原把中点写成 **#F98A6C = 2.36**：那个色**两端算不出来**（真中点是 #F8846C，
         白字 2.47）—— 一个凭空多出来的十六进制值在这儿挂了很久，谁拿它复算都会对不上。
       · ✅ **已结（R15-WA-02，260804）**：本 token 压在 `--veya-primary-light`(#FFE7DC)
         胶囊底上只有 **4.07:1**，不达 AA。**没有压深本 token**（它是全站链接与强调色，
         消费点遍布本文件与 admin.css —— 数别写死，自查
         `grep -c "var(--veya-primary-dark)" h5/static/h5.css admin/ui/static/admin.css`），
         而是新增了下面的 `--veya-chip-fg` 专供那批小字件。
     gates.rs 的对比度断言守的是本 token 在 bg/surface 上那一档，**不覆盖上面两种底**。 */
  --veya-primary-dark: #D73210;
  --veya-primary-light: #FFE7DC;
  /* 🔴 **这不是第二个品牌色**（R15-WA-02，260804 定）：它只有一个用途 ——
     「坐在 `--veya-primary-light` 上的小字件」的前景。`--veya-primary-dark` 在那个底上
     只有 4.07:1（AA 正文要 4.5），而底色单靠改浅解决不了：#D73210 的 WCAG 相对亮度
     L = 0.16766 ⇒ 底要过 4.5 得 L ≥ 0.92946，而页面底 #FFF6EF 自己才 0.93404，
     胶囊在视觉上会直接消失（#FFF0EA 只有 4.34、#FFF3EE 只有 4.44，都不够）。
     ⇒ 只能动前景。取值 #A82914 = `--veya-grad-peach` 的止端，与新渐变同源、不是凭空多一个色。
     实算 #A82914 on #FFE7DC = **5.92:1** ✅。
     深色档取 #F2846C（= 深色档 primary-dark）on #3A2723 = 5.55 ✅，本来就达标，两档同形即可。
     ⚠️ **禁止铺到别处**：判据是「背景是 --veya-primary-light」，不是「想要更深一点」。
     铺开它就是 D0 第 3 条「同一件事多种做法」。
     🔴 **锁在这三处**（全部反向验证过；本轮**没有**动 `tools/dev/guards.sh`）：
       · `h5/src/tpl_smoke/contrast.rs`
         `胶囊底上的前景色必须达_aa_4_5`（色值现读本文件 · 下限 4.5 · 自带纯黑压纯白=21.00 正控 ·
         反向断言 primary-dark 仍不达标 ⇒ 它哪天自己达标了这条会红，提醒删掉本 token）
         与 `primary_light_底上不许再配_primary_dark_前景`（**形状锁**，扫本文件全部 CSS 块）；
       · `admin/ui/src/tpl_smoke/shell.rs` `chip_fg_在三份_css_上必须同值`（h5 / admin / ds-bundle）；
       · 双端 `ChipContrastTest(s)`（各 4 条，取运行时真值并与本文件跨端对拍）。 */
  --veya-chip-fg: #A82914;
  --veya-bg: #FFF6EF;
  --veya-surface: #FFFFFF;
  --veya-text: #4A3A34;
  --veya-text-sub: #846A5F;
  --veya-divider: #EFE6DE;
  --veya-green: #8FBE9E;
  --veya-milk: #F3E1CE;
  --veya-gold: #C9A36A;
  --veya-ink-on-green: #31402C;
  --veya-on-accent: #FFFFFF;
  /* R11-AY04（260802）：旧值 #FF9E8A → #F26A4E 见上面 primary-dark 那段实算。
     新值白字全段 4.60 / 5.68 / 7.02，且渐变自身对页面底的边界从 1.87 / 2.83 抬到
     4.31 / 6.58（WCAG 1.4.11 非文本要 3:1 —— 旧值连按钮轮廓都不可辨）。
     浅深两档共用一条：深底 #2A1F22 上边界 3.47 ≥ 3，给深色单独提亮反而会让白字掉回 3.x。
     验收上限：**任一端 WCAG 相对亮度 L ≤ 0.1833**（#D53F27 实测 0.1785）。
     🔴 起端旧值 #FF9E8A 同时是深色档 --veya-primary、止端旧值 #F26A4E 同时是下一行
        --veya-elev-card 的投影底色 —— 两处本轮都不动，**禁止全局替换这两个色**。 */
  --veya-grad-peach: linear-gradient(135deg, #D53F27, #A82914);
  --veya-elev-card: 0 14px 30px -18px rgba(242, 106, 78, 0.20);
  --veya-primary-a25: rgba(255, 138, 107, 0.25);
  --veya-card-outline: transparent;
  /* 「完结」胶囊的字色。**不是 text-sub**（R15-WA-04）：text-sub(#846A5F) 压在
     milk(#F3E1CE) 上只有 3.91:1，而这枚胶囊是 10px/600 的小字，AA 要求 4.5:1
     —— 并排的 .badge-serial（ink-on-green 压 green）是 5.28:1，同一行里一个达标一个不达标。
     取 #6B554C = 5.44:1，刻意贴着 serial 那档：既过线，又仍明显淡于正文 text(8.46:1)，
     「完结 = 次要信息」的层级不变。改这个值前先跑 `完结胶囊字色必须达_wcag_aa_对比度`。 */
  --veya-badge-done-ink: #6B554C;

  --veya-serif: 'Noto Serif SC', 'Songti SC', Georgia, serif;
  --veya-sans: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Noto Sans SC', system-ui, sans-serif;

  /* —— 字号档 —— */
  --veya-h5-type-title-md: 16.5px;
  --veya-h5-type-body: 13px;
  /* ⚠️ 输入框专用档，**不得低于 16px**：iOS Safari 聚焦 <16px 的输入框会强制放大整页
     （既定行为，无法关闭）。既不能改 --veya-h5-type-body（那是全局正文字号，
     一改波及整站），也不能用 maximum-scale=1/user-scalable=no 关缩放（破坏无障碍）。 */
  --veya-h5-type-input: 16px;
  --veya-h5-type-caption: 12px;
  --veya-h5-type-tag: 10px;
  /* 全文搜索结果的正文片段 —— 介于 body(13) 与 title-md(16.5) 之间，需比正文略大以便
     在一屏多条结果里扫读。此前是 `.ft-snip` 里的裸 14px，是全站唯一不在本档表里的
     字号（R15-CSS-08）：不在档里意味着调字号时它不会跟着走，而没有任何东西会提醒。 */
  --veya-h5-type-snip: 14px;
  /* 批5 新增（design 批5 patch，共 4 枚）。面包屑与 S7 标签胶囊用。 */
  --veya-h5-crumb-h: 32px;
  --veya-h5-crumb-gap: 6px;
  --veya-h5-crumb-mid-max: 38vw;
  --veya-h5-tagchip-max-w: 160px;

  /* —— 间距档 —— */
  --veya-h5-space-page: 16px;
  --veya-h5-space-item: 12px;
  --veya-h5-space-card-gap: 13px;
  --veya-h5-space-shelf: 18px;

  /* —— 圆角档 —— */
  --veya-h5-radius-cover: 12px;
  --veya-h5-radius-chip: 16px;
  --veya-h5-radius-badge: 10px;
  --veya-h5-radius-button: 18px;

  /* —— 顶栏 —— */
  --veya-h5-header-h: 52px;
  --veya-h5-hit: 44px;

  /* —— 搜索框 —— */
  --veya-h5-field-h: 36px;
  --veya-h5-field-r: 18px;
  --veya-h5-search-btn: 32px;
  --veya-h5-search-inset: 2px;

  /* —— 分类横滚 —— */
  --veya-h5-cat-h: 46px;
  --veya-h5-chip-h: 30px;
  --veya-h5-chip-pad-x: 12px;
  --veya-h5-fade-w: 32px;
  /* 书卡内标签横滚：间距 + 右缘淡出宽度（比分类窄，卡内空间小） */
  --veya-h5-tag-gap: 6px;
  --veya-h5-tag-fade-w: 20px;

  /* —— 书卡 —— */
  --veya-h5-cover-ratio: 2 / 3;
  --veya-h5-gold-inset: 5px;
  /* 水印字号 = 封面宽度的 49%（cqw，不是 % —— % 会按父级字号算，实测渲成 6px 全糊） */
  --veya-h5-wm-scale: 49cqw;
  /* 封面上的两层压字（R15-CSS-08：原先是写死在规则里的 rgba，是本文件仅有的两处漏网）。
     🔴 **刻意不给深色档变体**：这两个值压在**客户端生成的封面色块**上，而那块底色
     取自书名哈希（`crates/veya-model/src/cover.rs` 的调色板），不随主题换挡 ——
     给它们加深色变体会让白水印在浅色调色板上消失。谁要动，先看那份调色板。 */
  --veya-h5-cover-wm-ink: rgba(255, 255, 255, 0.16);
  --veya-h5-cover-kw-shadow: 0 1px 6px rgba(0, 0, 0, 0.18);
  --veya-h5-info-gap: 4px;

  /* —— 徽章 / 分页 / 空态 —— */
  --veya-h5-badge-h: 18px;
  --veya-h5-badge-pad-x: 7px;
  --veya-h5-pager-h: 40px;
  --veya-h5-pager-pad-x: 16px;
  --veya-h5-halo-d: 72px;

  /* —— 筛选栏（S2）—— */
  --veya-h5-filter-pad-b: 12px;

  /* —— S4 详情 —— */
  --veya-h5-cover-lg-w: 120px;
  --veya-h5-cover-lg-h: 180px;
  --veya-h5-type-title-lg: 22px;
  --veya-h5-chitem-h: 44px;
  --veya-h5-chitem-r: 9px;

  /* —— S5 阅读页（正文排版是重心）—— */
  --veya-h5-type-reader: 16.5px;
  --veya-h5-reader-line: 33px;
  --veya-h5-reader-indent: 2em;
  --veya-h5-para-gap: 8px;
  --veya-h5-reader-pad: 20px;
  --veya-h5-reader-max-w: 38em;
  --veya-h5-reader-btn-h: 44px;

  /* —— S6 付费墙 —— */
  --veya-h5-lock-card-w: 300px;
  --veya-h5-lock-card-r: 20px;

  /* —— 富书卡（对齐 app BookCard，booklist handoff）—— */
  --veya-h5-bkcard-r: 20px;
  --veya-h5-bkcard-pad: 13px;
  --veya-h5-bkcard-gap: 14px;
  --veya-h5-bkcover-w: 80px;
  --veya-h5-bkcover-h: 108px;
  --veya-h5-bk-name: 16.5px;
  --veya-h5-bk-intro: 11.5px;

  /* —— Brief12 全文搜索（片段卡 / 高亮 / 状态）—— */
  --veya-h5-ft-card-r: 16px;
  --veya-h5-ft-card-pad-y: 14px;
  --veya-h5-ft-card-pad-x: 16px;
  --veya-h5-ft-gap: 13px;
  --veya-h5-ft-ava: 36px;
  --veya-h5-ft-snip-lh: 1.75;
  --veya-h5-ft-hl-r: 3px;
  --veya-h5-ft-lowconf-r: 12px;
  --veya-h5-ft-lowconf-pad-y: 10px;
  --veya-h5-ft-lowconf-pad-x: 14px;
  /* 命中高亮 / 灰阶引导底与字（随主题切换，见下方深色块）*/
  --veya-h5-ft-hl: rgba(255, 138, 107, 0.22);
  --veya-h5-ft-mute-bg: rgba(74, 58, 52, 0.06);
  --veya-h5-ft-mute-fg: rgba(74, 58, 52, 0.35);
}

@media (prefers-color-scheme: dark) {
  /* 🔴 `:not([data-theme='light'])` 不是修饰，是这一层能被手动浅色档压过的**全部**机制。
     去掉它，就必须另写一整块 `:root[data-theme='light']` 把浅值再抄一遍才压得回来 ——
     那 20 行副本原先就在下面，260802 删掉了（R15-CSS-03…10#1）。
     漏改的形态是静默的：只有「系统深色 + 用户手动点浅色」这一条路径会错，
     开发机跟随系统时永远看不到。由 tpl_smoke::gates 的
     `手动浅色档不得以副本形式回归` 守着。 */
  :root:not([data-theme='light']) {
    --veya-primary: #FF9E8A;
    --veya-primary-dark: #F2846C;
    --veya-primary-light: #3A2723;
    --veya-chip-fg: #F2846C;
    --veya-bg: #2A1F22;
    --veya-surface: #362A2D;
    --veya-text: #DCC7BC;
    --veya-text-sub: #B49B92;
    --veya-divider: #3F3033;
    --veya-milk: #3A302B;
    --veya-ink-on-green: #22331F;
    --veya-elev-card: 0 14px 30px -14px rgba(10, 6, 7, 0.55);
    --veya-primary-a25: rgba(255, 158, 138, 0.25);
    /* 深色下卡片靠提亮描边而非阴影脱离背景 */
    --veya-card-outline: rgba(255, 255, 255, 0.07);
    --veya-badge-done-ink: var(--veya-text);
    --veya-h5-ft-hl: rgba(255, 158, 138, 0.26);
    --veya-h5-ft-mute-bg: rgba(255, 255, 255, 0.08);
    --veya-h5-ft-mute-fg: rgba(255, 255, 255, 0.35);
  }
}

/* 手动覆盖层：必须在媒体查询之后，否则切换钮按不动 */
:root[data-theme='dark'] {
  --veya-primary: #FF9E8A;
  --veya-primary-dark: #F2846C;
  --veya-primary-light: #3A2723;
  --veya-chip-fg: #F2846C;
  --veya-bg: #2A1F22;
  --veya-surface: #362A2D;
  --veya-text: #DCC7BC;
  --veya-text-sub: #B49B92;
  --veya-divider: #3F3033;
  --veya-milk: #3A302B;
  --veya-ink-on-green: #22331F;
  --veya-elev-card: 0 14px 30px -14px rgba(10, 6, 7, 0.55);
  --veya-primary-a25: rgba(255, 158, 138, 0.25);
  --veya-card-outline: rgba(255, 255, 255, 0.07);
  --veya-badge-done-ink: var(--veya-text);
  --veya-h5-ft-hl: rgba(255, 158, 138, 0.26);
  --veya-h5-ft-mute-bg: rgba(255, 255, 255, 0.08);
  --veya-h5-ft-mute-fg: rgba(255, 255, 255, 0.35);
}


* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--veya-bg);
  color: var(--veya-text);
  font-family: var(--veya-sans);
  font-size: var(--veya-h5-type-body);
  -webkit-text-size-adjust: 100%;
}

a {
  color: inherit;
  text-decoration: none;
}

/* 🔴 全站键盘焦点环（R15-WA-15）。
   四类可聚焦元素（.bk 书卡 / .ft-card 片段卡 / .theme-sw / .tag-rel .tag-chip）本来就
   声明了 `outline: 1px solid var(--veya-card-outline)` 当描边用 —— 那是**无条件**声明，
   会把 UA 的 :focus-visible 焦点环整个压掉，且浅色档该 token 是 transparent、
   深色档是 7% 白（聚焦前后一模一样）⇒ 键盘用户在首页按 Tab 看不出光标走到哪本书。
   这里给出全站统一的焦点表达，与 .hd-search:focus-within 同族（2px 主色边 + 3px 光晕）
   —— 那处是同文件里**已经做对了一次**的范本，本规则把它推广到其余可聚焦元素。
   用 :focus-visible 而非 :focus：鼠标点书卡不该冒出焦点环。
   ⚠️ 选择器必须带元素名（a/button/summary）—— 裸 `:focus-visible` 与 `.bk` 同权重，
   而 `.bk` 写在后面会赢，等于这条规则白写。 */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible {
  outline: 2px solid var(--veya-primary);
  outline-offset: 2px;
  box-shadow: 0 0 0 3px var(--veya-primary-a25);
}

/* 屏幕阅读器专用文本：视觉不占位，读屏与语音控制照读。
   用于给「只有图标 + 裸数字」的元素补文字标签（.bk-stat 的热度/收藏 = R15-WA-07），
   以及给可及名不自足的 summary 补前缀（排序/搜索类型 = R15-WA-11）。
   ⚠️ 不用 `display:none` / `visibility:hidden` —— 那两种会把节点一并移出无障碍树。 */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* 跳过导航（R15-WA-17）。h5 是整页刷新的 SSR 站，每换一页键盘用户都要重新
   Tab 过顶栏 + 分类横滚 + 20 张书卡里的链接才够得到正文。默认藏在视口外，
   仅在被聚焦时落到左上角。位置写死 8px 是有意的：它不参与设计体系排版。 */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 50;
  padding: 8px var(--veya-h5-space-page);
  border-radius: var(--veya-h5-radius-button);
  background: var(--veya-surface);
  color: var(--veya-text);
  font-size: var(--veya-h5-type-body);
  font-weight: 600;
  box-shadow: var(--veya-elev-card);
}

.skip:focus {
  left: 8px;
  top: 8px;
}

.wrap {
  padding: 0 var(--veya-h5-space-page);
}

/* ============ 顶栏 = app 书城搜索栏（书名▾ + 搜索框 + 最热▾） ============ */
.hd {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--veya-h5-header-h);
  padding: 8px var(--veya-h5-space-page);
  background: var(--veya-surface);
  border-bottom: 1px solid var(--veya-divider);
}

/* 站标：全站常驻的回首页入口。
   flex-shrink:0 —— 搜索框（flex:1）负责收缩，站标不许被挤变形。
   窄屏下它吃掉的宽度是必要成本：详情页/阅读页此前根本没有回首页的路径。 */
.hd-logo {
  flex: 0 0 auto;
  /* 🔴 R15-WA-14：文字本身只有 ≈20px 高，命中区不足（WCAG 2.2 SC 2.5.8 要 24×24，
     移动端实践取 44）。`--veya-h5-hit: 44px` 这个 token 早就定义了、却**全文件零引用**
     —— 用 token 表达的规则没有任何东西执行它。这里是它的第一个消费方。
     顶栏 min-height 52px、上下 padding 8px ⇒ 44px 正好放得下，不改任何几何。 */
  display: inline-flex;
  align-items: center;
  min-height: var(--veya-h5-hit);
  font-size: var(--veya-h5-type-title-md);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--veya-primary);
  text-decoration: none;
}

.hd-logo:active {
  opacity: 0.7;
}

/* 搜索胶囊：书名▾ + 放大镜 + 输入框，一体化 pill（对齐 app 2a） */
.hd-search {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--veya-h5-space-item);
  height: var(--veya-h5-field-h);
  padding: 0 var(--veya-h5-space-item);
  border: 1px solid var(--veya-divider);
  border-radius: var(--veya-h5-field-r);
  background: var(--veya-bg);
}

.hd-search:focus-within {
  border: 2px solid var(--veya-primary);
  box-shadow: 0 0 0 3px var(--veya-primary-a25);
}

/* 类型胶囊「书名▾」（对齐 app：primaryLight 底 primaryDark 字） */
/* 搜索类型下拉（对齐 app：胶囊 + 菜单 + 选中打勾）。
   ⚠️ 曾是不可点的 `<span>`，画着箭头却点不动 —— 现为 <details>，无 JS 也可展开选中。 */
.hd-type {
  flex: none;
  position: relative;
}

.hd-type-sum {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: var(--veya-h5-chip-h);
  padding: 0 var(--veya-h5-chip-pad-x);
  border-radius: var(--veya-h5-radius-chip);
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
  font-size: var(--veya-h5-type-caption);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}

.hd-type-sum::-webkit-details-marker {
  display: none;
}

.hd-type-pop {
  position: absolute;
  left: 0;
  top: calc(100% + 4px);
  z-index: 30;
  display: flex;
  flex-direction: column;
  min-width: 116px;
  padding: 4px;
  border-radius: var(--veya-h5-radius-chip);
  background: var(--veya-surface);
  box-shadow: var(--veya-elev-card);
  outline: 1px solid var(--veya-card-outline);
}

.hd-type-opt {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border-radius: 8px;
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text);
  white-space: nowrap;
  cursor: pointer;
}

/* radio 只作提交载体，视觉用「选中打勾」表达（对齐 app 菜单） */
.hd-type-opt input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.hd-type-opt span {
  flex: 1;
}

.hd-type-ck {
  flex: none;
  visibility: hidden;
  color: var(--veya-primary-dark);
}

.hd-type-opt.on {
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
  font-weight: 600;
}

.hd-type-opt.on .hd-type-ck {
  visibility: visible;
}

/* 选中态跟着 radio **实时**走（禁 JS 也生效）。
   服务端渲染的 `.on` 只反映「上次导航时的类型」——无词时刻意不提交，
   用户点了选项页面毫无变化 = 看起来切不动。下面两条把选中态交给 :has(:checked)：
   ① 先中和服务端 `.on`（仅当确有 checked 时，即支持 :has 的浏览器）
   ② 再点亮真正被选中的那个
   不支持 :has() 的老浏览器会整体丢弃这两条规则，退回服务端 `.on`，不会出现零选中。 */
.hd-type-pop:has(input:checked) .hd-type-opt.on {
  background: transparent;
  color: var(--veya-text);
  font-weight: 400;
}

.hd-type-pop:has(input:checked) .hd-type-opt.on .hd-type-ck {
  visibility: hidden;
}

.hd-type-opt:has(input:checked) {
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
  font-weight: 600;
}

.hd-type-opt:has(input:checked) .hd-type-ck {
  visibility: visible;
}

/* 🔴 键盘可见性（R15-WA-16①）。radio 被 `opacity:0` 压成不可见 ⇒ 它自己的焦点环
   也是 0 不透明度，而外层此前无任何聚焦表达 ⇒ Tab 进下拉后屏上一个像素都不动。
   焦点环画在**外层 label** 上（radio 本身不可见，画在它身上等于没画）。
   `:focus-within` 而非 `:has(:focus-visible)`：radio 只可能被键盘聚焦
   （`pointer-events:none`，鼠标点的是 label），不存在鼠标误触发。 */
.hd-type-opt:focus-within {
  outline: 2px solid var(--veya-primary);
  outline-offset: -2px;
}

.hd-go {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--veya-h5-search-btn);
  height: var(--veya-h5-search-btn);
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--veya-text-sub);
  cursor: pointer;
}

.hd-input {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  background: transparent;
  color: var(--veya-text);
  font-family: inherit;
  /* ⚠️ 必须 ≥16px，否则 iOS Safari 一聚焦就放大整页。见 token 处说明。 */
  font-size: var(--veya-h5-type-input);
}

.hd-input:focus {
  outline: none;
}

.hd-input::placeholder {
  color: var(--veya-text-sub);
  /* placeholder 视觉沿用正文档，避免 16px 输入字号把提示语撑得过重 */
  font-size: var(--veya-h5-type-body);
}

/* 清空钮：有词才渲染（模板控），真链接、禁 JS 可用 */
.hd-clear {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--veya-h5-search-btn);
  height: var(--veya-h5-search-btn);
  margin-right: calc(-1 * var(--veya-h5-search-inset));
  border-radius: 50%;
  color: var(--veya-text-sub);
}

/* 排序胶囊「最热▾」（对齐 app 2b）：<details> 无 JS 原生下拉 */
.hd-sort {
  flex: none;
  position: relative;
}

.hd-sort summary {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: var(--veya-h5-field-h);
  padding: 0 var(--veya-h5-chip-pad-x);
  border-radius: var(--veya-h5-radius-chip);
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
  font-size: var(--veya-h5-type-caption);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}

.hd-sort summary::-webkit-details-marker {
  display: none;
}

.hd-sort-pop {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 30;
  display: flex;
  flex-direction: column;
  min-width: 90px;
  padding: 4px;
  border-radius: var(--veya-h5-radius-chip);
  background: var(--veya-surface);
  box-shadow: var(--veya-elev-card);
  outline: 1px solid var(--veya-card-outline);
}

.hd-sort-pop a {
  padding: 8px 10px;
  border-radius: 8px;
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text);
}

.hd-sort-pop a.on {
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
  font-weight: 600;
}

/* 主题切换 = 页脚胶囊钮。
   ⚠️ 原为右上固定浮层（.theme-fab），已移除 —— 它逼得顶栏留 padding-right 给它让位，
   全站每屏的搜索框都因此被削掉一块宽度，代价与「切深浅色」这个低频操作不相称。 */
.theme-sw {
  display: none;
  align-items: center;
  gap: 6px;
  height: var(--veya-h5-chip-h);
  padding: 0 var(--veya-h5-chip-pad-x);
  border: 0;
  border-radius: var(--veya-h5-radius-chip);
  background: var(--veya-surface);
  box-shadow: var(--veya-elev-card);
  outline: 1px solid var(--veya-card-outline);
  outline-offset: -1px;
  color: var(--veya-text-sub);
  font-size: var(--veya-h5-type-caption);
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.12s ease;
}

.theme-sw:active {
  transform: scale(0.96);
}

/* 无 JS 时切换钮不渲染（默认 display:none，由内联脚本放出来） */
.js .theme-sw {
  display: inline-flex;
}

.theme-sw .ic-sun {
  display: none;
}

:root[data-theme='dark'] .theme-sw .ic-sun {
  display: block;
}

:root[data-theme='dark'] .theme-sw .ic-moon {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .theme-sw .ic-sun {
    display: block;
  }

  :root:not([data-theme='light']) .theme-sw .ic-moon {
    display: none;
  }
}

/* ============ 分类横滚（纯 CSS，无 JS 侦测） ============ */
.cat {
  position: relative;
  height: var(--veya-h5-cat-h);
}

.cat-track {
  display: flex;
  align-items: center;
  gap: var(--veya-h5-space-item);
  height: 100%;
  padding: 0 var(--veya-h5-space-page);
  overflow-x: auto;
  scrollbar-width: none;
}

.cat-track::-webkit-scrollbar {
  display: none;
}

.chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: var(--veya-h5-chip-h);
  padding: 0 var(--veya-h5-chip-pad-x);
  border-radius: var(--veya-h5-radius-chip);
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
  font-size: var(--veya-h5-type-tag);
  font-weight: 500;
  white-space: nowrap;
}

/* 右缘渐隐：覆在轨上但不吃点击 */
.cat-fade {
  position: absolute;
  right: 0;
  top: 0;
  width: var(--veya-h5-fade-w);
  height: 100%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--veya-bg));
}

/* ============ 区块 ============ */
.sec {
  margin-top: var(--veya-h5-space-shelf);
}

.sec-hd {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--veya-h5-space-item);
}

.sec-title {
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  font-weight: 700;
}

.sec-more {
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

/* ============ 书卡 ============ */
/* 竖向书卡列表（对齐 app：横卡纵向堆叠，不再是 3 列网格） */
.booklist {
  display: flex;
  flex-direction: column;
  gap: var(--veya-h5-space-card-gap);
}

/* 富书卡：封面(左) + 信息体(右)，对齐 app BookCard */
.bk {
  display: flex;
  align-items: flex-start;
  gap: var(--veya-h5-bkcard-gap);
  padding: var(--veya-h5-bkcard-pad);
  border-radius: var(--veya-h5-bkcard-r);
  background: var(--veya-surface);
  box-shadow: var(--veya-elev-card);
  outline: 1px solid var(--veya-card-outline);
  outline-offset: -1px;
}

.bk-cover {
  flex: none;
  width: var(--veya-h5-bkcover-w);
  height: var(--veya-h5-bkcover-h);
  aspect-ratio: auto;
}

.bk-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--veya-h5-info-gap);
}

.bk-hd {
  display: flex;
  align-items: flex-start;
  gap: var(--veya-h5-space-item);
}

/* 标签横滚（照 .cat-track 范式）。⚠️ 曾是 `overflow:hidden` —— 超宽标签被切掉且够不着。
   淡出遮罩在 wrap 上（绝对定位），放进 .bk-tags 会随内容一起滚走。 */
.bk-tags-wrap {
  position: relative;
  min-width: 0;
}

.bk-tags {
  display: flex;
  gap: var(--veya-h5-tag-gap);
  overflow-x: auto;
  scrollbar-width: none;
}

.bk-tags::-webkit-scrollbar {
  display: none;
}

/* 渐变终点是**卡片底色**（--veya-surface），不是页面底色 —— 用错会露出色差 */
.bk-tags-fade {
  position: absolute;
  right: 0;
  top: 0;
  width: var(--veya-h5-tag-fade-w);
  height: 100%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--veya-surface));
}

.bk-tags .tag {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: var(--veya-h5-chip-h);
  padding: 0 var(--veya-h5-chip-pad-x);
  border-radius: var(--veya-h5-radius-chip);
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
  font-size: var(--veya-h5-type-tag);
  white-space: nowrap;
}

.bk-intro {
  font-size: var(--veya-h5-bk-intro);
  line-height: 1.55;
  color: var(--veya-text-sub);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bk-stats {
  display: flex;
  gap: var(--veya-h5-bkcard-gap);
  margin-top: auto;
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.bk-stat {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.bk-stat svg {
  width: 13px;
  height: 13px;
}

.bk-stat-hot svg {
  color: var(--veya-primary-dark);
}

.bk-stat-col svg {
  color: var(--veya-primary);
}

.cover {
  position: relative;
  /* 水印要按**封面宽度**取字号（49cqw），故这里必须建容器上下文 */
  container-type: inline-size;
  aspect-ratio: var(--veya-h5-cover-ratio);
  border-radius: var(--veya-h5-radius-cover);
  overflow: hidden;
  box-shadow: var(--veya-elev-card);
  outline: 1px solid var(--veya-card-outline);
  outline-offset: -1px;
}

/* 金线内框 */
.cover::before {
  content: '';
  position: absolute;
  inset: var(--veya-h5-gold-inset);
  border: 1px solid var(--veya-gold);
  border-radius: calc(var(--veya-h5-radius-cover) - var(--veya-h5-gold-inset));
  pointer-events: none;
}

/* 右下水印首字，溢出裁切 */
.cover-wm {
  position: absolute;
  right: -4%;
  bottom: -8%;
  font-family: var(--veya-serif);
  font-weight: 700;
  font-size: var(--veya-h5-wm-scale);
  line-height: 1;
  color: var(--veya-h5-cover-wm-ink);
}

.cover-kw {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--veya-h5-space-item);
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  color: var(--veya-on-accent);
  text-shadow: var(--veya-h5-cover-kw-shadow);
  text-align: center;
}

/* 连载/完结徽章：卡内信息体行内（对齐 app StatusBadge，连载中=green底墨字） */
.badge {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: var(--veya-h5-badge-h);
  padding: 0 var(--veya-h5-badge-pad-x);
  border-radius: var(--veya-h5-radius-badge);
  font-size: var(--veya-h5-type-tag);
  font-weight: 600;
  white-space: nowrap;
}

.badge-serial {
  background: var(--veya-green);
  color: var(--veya-ink-on-green);
}

.badge-done {
  background: var(--veya-milk);
  color: var(--veya-badge-done-ink);
}

.bk-name {
  flex: 1;
  min-width: 0;
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-bk-name);
  font-weight: 700;
  line-height: 1.3;
  color: var(--veya-text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bk-author {
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ============ 空态 / 故障态 ============ */
.halo-box {
  padding: calc(var(--veya-h5-space-shelf) * 2) 0;
  text-align: center;
}

.halo {
  width: var(--veya-h5-halo-d);
  height: var(--veya-h5-halo-d);
  margin: 0 auto var(--veya-h5-space-item);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--veya-primary-light);
  color: var(--veya-primary);
}

.halo-title {
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  font-weight: 700;
}

.halo-sub {
  margin-top: var(--veya-h5-info-gap);
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  height: var(--veya-h5-pager-h);
  margin-top: var(--veya-h5-space-shelf);
  padding: 0 var(--veya-h5-pager-pad-x);
  border-radius: var(--veya-h5-radius-button);
  background: var(--veya-grad-peach);
  color: var(--veya-on-accent);
  font-weight: 700;
}

/* ============ 分页器 ============ */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--veya-h5-space-item);
  margin: var(--veya-h5-space-shelf) 0;
}

/* 批 2 定稿：surface 底 + 1px divider 描边。
   ⚠️ 批 1 组件卡的 primaryLight 实底版**已作废**，别照那份改回去。 */
.pager-btn {
  display: inline-flex;
  align-items: center;
  height: var(--veya-h5-pager-h);
  padding: 0 var(--veya-h5-pager-pad-x);
  border: 1px solid var(--veya-divider);
  border-radius: var(--veya-h5-radius-button);
  background: var(--veya-surface);
  color: var(--veya-text);
  font-size: var(--veya-h5-type-body);
}

.pager-num {
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
  font-variant-numeric: tabular-nums;
}

/* ============ 页脚 ============ */
.ft {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--veya-h5-space-item);
  margin-top: var(--veya-h5-space-shelf);
  padding: var(--veya-h5-space-shelf) var(--veya-h5-space-page);
  border-top: 1px solid var(--veya-divider);
  text-align: center;
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.ft-copy {
  margin: 0;
}

/* ============ 筛选栏（S2） ============ */
.filter {
  padding-bottom: var(--veya-h5-filter-pad-b);
}

/* 分类 chip 选中态 —— **描边式，不是渐变实底**（R11-AY04 改版，原为批 2 的实底+白字）。
   为什么这一处不跟着新渐变走：它是全站字号最小的一处强调件（10px/700），AA 门槛 4.5:1
   与正文同档，而 10px 白字压任何一条能称为「蜜桃」的渐变都只是擦线过。改描边后
   前景与描边同取 primary-dark：浅档 #D73210 on 页面底 #FFF6EF = 4.52，
   深档 #F2846C on #2A1F22 = 6.29；1.5px 描边本身同样是这两个数，过 1.4.11 的 3:1。
   · `background: transparent` 而不是 var(--veya-bg)：.filter/.cat/.cat-track 一路无底，
     透到 body 就是页面底，且深色档自动跟着换 —— 写死 bg 变量在手动主题层下会多一处要同步。
   · 不加 box-shadow：原来那句 `var(--veya-elev-chip)` 是给「浮起来的实底胶囊」用的，
     描边式底下透着页面底，再挂一层橘色辉光就是悬浮阴影落在透明件上。该 token 随之
     零消费方，已一并删除（GS21 会红）。
   · 高度不受影响：文件顶部 `* { box-sizing: border-box }` + `.chip` 写死 height:30px，
     加边框只吃内高。**但宽度会比未选态多 3px** —— width 是 auto，border-box 管不着它。
     这是知情的：切分类是整页跳转（模板里是 `<a href>`）不是原地切换，看不到抖动，
     且设计样张本身就是「未选无框 / 选中有框」并排的这个样子。 */
.chip-on {
  background: transparent;
  border: 1.5px solid var(--veya-primary-dark);
  color: var(--veya-primary-dark);
  font-weight: 700;
}

/* ============ 搜索统计行（S3） ============ */
.stats {
  padding: var(--veya-h5-space-item) 0;
  color: var(--veya-text-sub);
}

.stats strong {
  color: var(--veya-primary-dark);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ============ Brief12 全文搜索（片段卡 / 高亮 / 状态） ============ */
/* 低置信通条 */
.ft-lowconf {
  display: flex;
  align-items: center;
  gap: var(--veya-h5-space-item);
  margin: var(--veya-h5-space-item) 0;
  padding: var(--veya-h5-ft-lowconf-pad-y) var(--veya-h5-ft-lowconf-pad-x);
  border-radius: var(--veya-h5-ft-lowconf-r);
  background: var(--veya-primary-light);
  color: var(--veya-text);
  font-size: var(--veya-h5-type-caption);
}
.ft-lowconf svg {
  flex: none;
  color: var(--veya-primary-dark);
}

/* 片段卡列表 */
.ft-list {
  display: flex;
  flex-direction: column;
  gap: var(--veya-h5-ft-gap);
}

.ft-card {
  display: block;
  padding: var(--veya-h5-ft-card-pad-y) var(--veya-h5-ft-card-pad-x);
  border-radius: var(--veya-h5-ft-card-r);
  background: var(--veya-surface);
  box-shadow: var(--veya-elev-card);
  outline: 1px solid var(--veya-card-outline);
  outline-offset: -1px;
  transition: transform 0.12s ease;
}
.ft-card:active {
  transform: scale(0.98);
}

.ft-top {
  display: flex;
  align-items: center;
  gap: var(--veya-h5-space-item);
}

/* 首字头像（版 A）：36 圆 · 封面哈希渐变 + 首字 serif 白 */
.ft-ava {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--veya-h5-ft-ava);
  height: var(--veya-h5-ft-ava);
  border-radius: 50%;
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  color: var(--veya-on-accent);
}

.ft-meta {
  min-width: 0;
}

.ft-book {
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  font-weight: 700;
  color: var(--veya-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ft-author {
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.ft-chap {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--veya-h5-space-item);
  font-size: var(--veya-h5-type-body);
  color: var(--veya-text-sub);
}
.ft-chap svg {
  flex: none;
}

.ft-snip {
  margin-top: 8px;
  font-size: var(--veya-h5-type-snip);
  line-height: var(--veya-h5-ft-snip-lh);
  color: var(--veya-text);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 命中高亮：底色 + 加粗，字色不变（与搜索高亮同族） */
.ft-hl {
  background: var(--veya-h5-ft-hl);
  border-radius: var(--veya-h5-ft-hl-r);
  font-weight: 600;
  color: inherit;
  padding: 0 1px;
}

/* 词过短灰阶引导态 */
.ft-shorthint .halo {
  background: var(--veya-h5-ft-mute-bg);
  color: var(--veya-h5-ft-mute-fg);
}
.ft-shorthint .halo-title {
  color: var(--veya-text-sub);
}

/* 未搜索态热门词（判断② 定稿：加，8 枚两行封顶） */
.hot {
  padding-top: var(--veya-h5-space-shelf);
}

.hot-hd {
  margin-bottom: var(--veya-h5-space-item);
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.hot-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--veya-h5-space-item);
}

/* ============ S4 书籍详情 ============ */
.bd-head {
  display: flex;
  gap: var(--veya-h5-space-page);
  padding-top: var(--veya-h5-space-shelf);
}

.bd-cover {
  flex: none;
  width: var(--veya-h5-cover-lg-w);
  height: var(--veya-h5-cover-lg-h);
}

.bd-meta {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--veya-h5-info-gap);
}

/* ⚠️ h1 不截断：书名是本页最重要的 SEO 信号，宁可折行 */
.bd-title {
  margin: 0;
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-lg);
  font-weight: 700;
  line-height: 1.3;
}

.bd-author {
  color: var(--veya-text-sub);
}

/* 标签横滚（照列表卡片 .bk-tags 范式）——原来是 flex-wrap 换行 + take(4) 截断，
   多标签的书后面几个既看不见也够不着。淡出遮罩在 wrap 上，放进 .bd-tags 会随内容滚走。 */
.bd-tags-wrap {
  position: relative;
  min-width: 0;
  margin-top: var(--veya-h5-info-gap);
}

.bd-tags {
  display: flex;
  gap: var(--veya-h5-info-gap);
  overflow-x: auto;
  scrollbar-width: none;
}

.bd-tags::-webkit-scrollbar {
  display: none;
}

/* 渐变终点是**页面底色**（--veya-bg），详情页头部无 surface 卡片；用 surface 会露色差 */
.bd-tags-fade {
  position: absolute;
  right: 0;
  top: 0;
  width: var(--veya-h5-tag-fade-w);
  height: 100%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--veya-bg));
}

.bd-tags .tag {
  flex: none;
  white-space: nowrap;
}

.tag {
  display: inline-flex;
  align-items: center;
  height: var(--veya-h5-badge-h);
  padding: 0 var(--veya-h5-badge-pad-x);
  border-radius: var(--veya-h5-radius-badge);
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
  font-size: var(--veya-h5-type-tag);
}

.bd-stats {
  display: flex;
  margin-top: var(--veya-h5-space-shelf);
  border: 1px solid var(--veya-divider);
  border-radius: var(--veya-h5-radius-cover);
  background: var(--veya-surface);
}

.bd-stat {
  flex: 1;
  padding: var(--veya-h5-space-item) 0;
  text-align: center;
}

.bd-stat + .bd-stat {
  border-left: 1px solid var(--veya-divider);
}

.bd-stat-n {
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.bd-stat-l {
  margin-top: var(--veya-h5-info-gap);
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.bd-intro {
  font-size: var(--veya-h5-type-body);
  line-height: 1.7;
  white-space: pre-wrap;
}

/* 目录：2 列 */
.toc {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--veya-h5-space-item);
}

.toc-item {
  display: flex;
  align-items: center;
  height: var(--veya-h5-chitem-h);
  padding: 0 var(--veya-h5-space-item);
  border-radius: var(--veya-h5-chitem-r);
  background: var(--veya-surface);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.toc-item:hover {
  background: var(--veya-primary-light);
  color: var(--veya-chip-fg);
}

/* ============ S5 阅读页 ============ */
.reader {
  max-width: var(--veya-h5-reader-max-w);
  margin: 0 auto;
  padding: var(--veya-h5-reader-pad);
}

.reader h1 {
  margin: 0 0 var(--veya-h5-space-shelf);
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-lg);
  font-weight: 700;
  line-height: 1.3;
}

/* 正文：sans（决策 1 —— serif 会触发大量字体分片）
   缩进 2em + 克制段间距 8px（决策 2，两者并用）
   ⚠️ 深色行高维持 33 不增（批 3 判定②） */
.reader p {
  margin: 0 0 var(--veya-h5-para-gap);
  font-size: var(--veya-h5-type-reader);
  line-height: var(--veya-h5-reader-line);
  text-indent: var(--veya-h5-reader-indent);
  text-align: left;
  /* 全文片段卡锚点跳转（#p{idx}）落点：留出顶栏高度、命中段轻高亮，纯 CSS 无 JS */
  scroll-margin-top: var(--veya-h5-cat-h);
}

.reader p:target {
  background: var(--veya-h5-ft-hl);
  border-radius: var(--veya-h5-ft-hl-r);
}

.rd-nav {
  display: flex;
  gap: var(--veya-h5-space-item);
  max-width: var(--veya-h5-reader-max-w);
  margin: var(--veya-h5-space-shelf) auto;
  padding: 0 var(--veya-h5-reader-pad);
}

/* 四态共用底座：占位也占同样的位，导航条不塌 */
.rd-btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--veya-h5-reader-btn-h);
  border-radius: var(--veya-h5-radius-button);
  border: 1px solid var(--veya-divider);
  background: var(--veya-surface);
  font-size: var(--veya-h5-type-body);
}

.rd-btn-next {
  flex: 1.4;
  border-color: transparent;
  background: var(--veya-grad-peach);
  color: var(--veya-on-accent);
  font-weight: 700;
}

/* 占位：不可点，也不描边 —— 但仍占位，否则末章导航会突然缩一格 */
.rd-btn-off {
  border-color: transparent;
  background: transparent;
  color: var(--veya-text-sub);
}

.rd-nav-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--veya-h5-space-item);
  padding: var(--veya-h5-space-item) var(--veya-h5-space-page);
  border-bottom: 1px solid var(--veya-divider);
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.rd-nav-top a {
  color: var(--veya-primary-dark);
}

/* ============ S6 付费墙 ============ */
.lock {
  max-width: var(--veya-h5-lock-card-w);
  margin: calc(var(--veya-h5-space-shelf) * 3) auto;
  padding: calc(var(--veya-h5-space-shelf) * 1.5) var(--veya-h5-space-page);
  border-radius: var(--veya-h5-lock-card-r);
  background: var(--veya-surface);
  box-shadow: var(--veya-elev-card);
  outline: 1px solid var(--veya-card-outline);
  outline-offset: -1px;
  text-align: center;
}

.lock-icon {
  width: var(--veya-h5-halo-d);
  height: var(--veya-h5-halo-d);
  margin: 0 auto var(--veya-h5-space-item);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--veya-primary-light);
  color: var(--veya-primary);
}

.lock-title {
  margin: 0;
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-lg);
  font-weight: 700;
}

.lock-desc {
  margin: var(--veya-h5-space-item) 0 0;
  color: var(--veya-text-sub);
  line-height: 1.6;
}

.lock-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--veya-h5-reader-btn-h);
  margin-top: var(--veya-h5-space-shelf);
  border-radius: var(--veya-h5-radius-button);
  background: var(--veya-grad-peach);
  color: var(--veya-on-accent);
  font-weight: 700;
}

.lock-alt {
  display: block;
  margin-top: var(--veya-h5-space-item);
  color: var(--veya-primary-dark);
  font-size: var(--veya-h5-type-caption);
}

/* 页面 h1（批5·项目 D）。首页/搜索页此前零 heading —— 权重最高的页面缺主题信号。
   ⚠️ 可见但不抢戏：字号与分节标题同档（title-md），不放大、不加色块。 */
.page-h1 {
  margin: 0;
  padding: var(--veya-h5-space-item) var(--veya-h5-space-page);
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  font-weight: 700;
  color: var(--veya-text);
}

/* 面包屑（批5·项目 B）。全站此前零面包屑 —— SERP 里显示的是裸 URL 而非
   「Veya阅读 › 书名 › 章节」。左对齐单行，**不换行不横滚**（换行会把页顶撑乱）。 */
.crumb {
  display: flex;
  align-items: center;
  gap: var(--veya-h5-crumb-gap);
  min-height: var(--veya-h5-crumb-h);
  padding: 0 var(--veya-h5-space-page);
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
  white-space: nowrap;
  overflow: hidden;
}

/* 阅读页：沿用 .rd-nav-top 的原有几何（上下 item 内距 + 下缘发丝线） */
.crumb-reader {
  padding: var(--veya-h5-space-item) var(--veya-h5-space-page);
  border-bottom: 1px solid var(--veya-divider);
}

/* ⚠️ 判断⑤：可点级用 primaryDark 而非 primary —— caption 12 在奶油底上
   primary 仅 2.16:1 不达标。
   ✅ **本条欠账已还**（R15-WA-05 订正）：primaryDark 早在 260722 压深过一轮，
   现值在 --veya-bg 上实算 4.52、在 surface 上 4.82，两档都过 AA 线 4.5，
   并由 gates.rs 的断言守着。原注释记的「3.3 / todolist #41」是压深前的旧数，
   留着会让人以为这里还欠着 —— 而**真正还欠着的是另一处**：同一 token 落在
   --veya-primary-light 胶囊底上只有 4.07（见 :root 处 R15-WA-01/02 注释），
   那是设计决策 todolist #33。 */
.crumb a {
  color: var(--veya-primary-dark);
  text-decoration: none;
  flex: 0 0 auto;
}

/* 书名级：阅读页空间紧张时**先截它**，把宽度让给章节名 */
.crumb-mid {
  max-width: var(--veya-h5-crumb-mid-max);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 末级 = 当前页，不可点。详情页是书名（截断）、阅读页是章节名（尽量保全） */
.crumb-cur {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--veya-text-sub);
}

/* 分隔符：判断⑩ 取 textSub 不取 divider（深色下 divider 对底几乎不可见） */
.crumb-sep {
  flex: 0 0 auto;
  color: var(--veya-text-sub);
}

/* ============ S7 标签聚合页（批5·项目 A） ============ */
.tag-head {
  padding: var(--veya-h5-space-page);
}

/* h1 必须含标签词，**不截断**可折行 —— 本屏命中长尾词全靠它 */
.tag-h1 {
  margin: 0;
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  font-weight: 700;
  line-height: 1.45;
  color: var(--veya-text);
}

.tag-count {
  margin: var(--veya-h5-space-item) 0 0;
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.tag-count strong {
  font-weight: 700;
  color: var(--veya-primary-dark);
}

/* 相关标签横滚：复用 .cat/.cat-track/.cat-fade 范式，只调外边距 */
.tag-rel {
  margin-top: var(--veya-h5-space-item);
}

/* 胶囊取 .bk-tags .tag 的横滚档（h30）而非 .bd-tags 静态档（h18）——
   滚动轨里 h18 命中区不足（design 判断⑦）。
   🔴 R15-WA-12/13：这条注释写下了，但块里**一个 height 都没落**，
   继承的正是它自己判过「命中区不足」的 .tag 静态档 h18。下面三行是补上的落码 ——
   h30 + 横滚档内距，与 .bk-tags .tag 逐值一致。 */
.tag-rel .tag-chip {
  height: var(--veya-h5-chip-h);
  padding: 0 var(--veya-h5-chip-pad-x);
  border-radius: var(--veya-h5-radius-chip);
  max-width: var(--veya-h5-tagchip-max-w);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* 深色靠提亮描边成立，浅色下该 token 是透明 —— 零新 token（design 判断⑧） */
  outline: 1px solid var(--veya-card-outline);
  outline-offset: -1px;
}

/* 🔴 R15-WA-15 残留：上面那条是**复合类选择器**（0-2-0），权重高于全局的
   `a:focus-visible`（0-1-1）⇒ 它的无条件 `outline` 会把焦点环整个压掉，
   而浅色档该 token 恰是 transparent ⇒ 键盘用户 Tab 到相关标签时**屏上一个像素都不动**。
   全站四个焦点环受害者里另外三个（.bk / .ft-card / .theme-sw）已被那条全局规则救回，
   只有这一个因为选择器权重更高而漏网。补一条同等权重的覆写。 */
.tag-rel .tag-chip:focus-visible {
  outline: 2px solid var(--veya-primary);
  outline-offset: 2px;
  box-shadow: 0 0 0 3px var(--veya-primary-a25);
}

/* ============ 页脚政策入口 ============ */
/* 与 .ft-copy 同为页脚行；分隔点用 span 而非 `::before` 内容，
   免得读屏把「·」念出来（它是纯装饰）—— 故 aria-hidden 由 .ft-dot 的 speak 无法做到，
   改用 margin 撑出间距、字符本身不可聚焦，读屏顺序仍是「隐私政策 用户协议」。 */
.ft-legal {
  margin: 0;
}

.ft-legal a {
  color: var(--veya-text-sub);
  text-decoration: underline;
}

.ft-dot {
  margin: 0 var(--veya-h5-space-item);
  color: var(--veya-divider);
}

/* ============ 长文档页（隐私政策 / 用户协议） ============ */
/* 复用阅读器的字号与行高 token：这两页就是长正文，另起一套排版 token 等于给
   「正文该多大」这件事第二个答案（禁止硬编码那条的原意）。 */
.doc {
  padding: var(--veya-h5-space-shelf) var(--veya-h5-space-page);
  font-size: var(--veya-h5-type-body);
  line-height: 1.85;
  color: var(--veya-text);
}

.doc-h1 {
  margin: 0 0 var(--veya-h5-space-item);
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-lg);
  line-height: 1.3;
  color: var(--veya-text);
}

.doc-meta {
  margin: 0 0 var(--veya-h5-space-shelf);
  padding: var(--veya-h5-space-item);
  border-radius: var(--veya-h5-radius-badge);
  background: var(--veya-surface);
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

.doc-sec {
  margin-bottom: var(--veya-h5-space-shelf);
}

.doc-h2 {
  margin: var(--veya-h5-space-shelf) 0 var(--veya-h5-space-item);
  font-family: var(--veya-serif);
  font-size: var(--veya-h5-type-title-md);
  line-height: 1.4;
  color: var(--veya-text);
}

.doc-h3 {
  margin: var(--veya-h5-space-item) 0 var(--veya-h5-space-item);
  font-size: var(--veya-h5-type-body);
  font-weight: 700;
  color: var(--veya-text);
}

.doc p {
  margin: 0 0 var(--veya-h5-space-item);
}

.doc-ul {
  margin: 0 0 var(--veya-h5-space-item);
  padding-left: var(--veya-h5-space-shelf);
}

.doc-ul li {
  margin-bottom: var(--veya-h5-info-gap);
}

/* 集合名/字段名等标识符：等宽 + 弱底，让「这是代码里的名字」与正文一眼分开。
   不做可点击，也不加 outline —— 它不是控件。 */
.doc code {
  padding: 0 var(--veya-h5-search-inset);
  border-radius: var(--veya-h5-search-inset);
  background: var(--veya-surface);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--veya-h5-type-caption);
  color: var(--veya-text-sub);
}

/* `.doc-todo` 已于 260808 删除：11 处待填条款全部由所有者定案填完，
   privacy/terms 里再无 <mark class="doc-todo"> ⇒ 这条样式零消费方。
   🔴 将来若又出现待定条款，**连样式一起加回来**，别只加 mark 标签 ——
   那样它会渲染成一段和正文一模一样的文字，「还没定」就被伪装成「已经这么定了」，
   而那正是当初加这条样式要防的事。 */

.doc-foot {
  margin: var(--veya-h5-space-shelf) 0 0;
  padding-top: var(--veya-h5-space-item);
  border-top: 1px solid var(--veya-divider);
  font-size: var(--veya-h5-type-caption);
}

.doc-foot a {
  color: var(--veya-primary);
}
