/* =========================================================================
   PRL / PRB / arXiv Daily Articles - 多主题 v6
   - [data-theme="journal"]      = 期刊白（默认）
   - [data-theme="beige"]        = 学术米黄
   - [data-theme="dark"]         = 暖墨（暗色）
   - [data-theme="paper"]        = 复古纸
   - [data-theme="mist"]         = 雾岚       (v5)
   - [data-theme="sage"]         = 苔原       (v5)
   - [data-theme="dune"]         = 沙丘       (v5)
   - [data-theme="space"]        = 深空       (v5)
   - [data-theme="moss"]         = 夜苔       (v5)
   - [data-theme="obsidian"]     = 玄黑       (v6，第 10 套，第 4 套暗色)
   ========================================================================= */

/* ============================================================
   CSS @layer 声明 —— 控制级联顺序（低 specificity → 高 specificity）
   - tokens:      原始设计令牌（:root + 主题覆盖）
   - base:        reset + 元素默认样式
   - themes:      9 套主题 token 覆盖
   - components:  所有组件样式
   - utilities:   工具类（最高优先级）
   ============================================================ */
@layer tokens, base, themes, components, utilities;

@layer tokens {
:root {
  /* —— 主题 1：期刊白（默认 · Nature 风格） —— */
  /* color-scheme（fix audit-2026-10-06 MEDIUM-2）：告诉 UA 渲染原生控件
     （日期选择器、checkbox、下拉、滚动条）用哪套配色。深色主题下不声明
     color-scheme: dark，这些控件仍按浅色画，出现"深色页面 + 白色输入框"。
     浅色主题统一 light。 */
  color-scheme: light;
  --bg:        oklch(98.476% 0.0054 95.1);
  --bg-elev:   oklch(100% 0 0);
  --bg-soft:   oklch(95.753% 0.0067 97.4);
  --bg-hover:  oklch(93.615% 0.0081 98.9);
  --border:    oklch(87.543% 0.0111 95.2);
  --border-soft: oklch(91.821% 0.0109 95.2);
  --ink:       oklch(18.743% 0.0138 243.7);
  --ink-soft:  oklch(35.282% 0.0168 251.8);
  /* fix audit-2026-10-03：此处原为 `oklch(53.5759% 0.0131 252.2).2));` ——
     末尾多出 `.2))` 垃圾字符，整个声明成为非法值，浏览器会丢弃它。
     验证：canvas 实测该串解析失败返回 None；去掉尾巴后得 rgb(109,116,123)，
     与迁移前 .bak 里的 `--ink-mute: #6e747b` 吻合。
     影响面有限（9 个主题块各自重新定义了 --ink-mute，页面正常渲染时被覆盖），
     但在 <html> 尚未写上 data-theme 的那段时间（防闪烁的内联脚本执行前），
     以及任何只落在 :root 上的用法，会退回继承色。
     注意：正因为每个主题块都覆盖了它，test_audit_fixes 的 8.1 主题对比度断言
     结构上抓不到这个坏值 —— :root 被命名为 "paper" 后又被同名主题块覆盖。 */
  --ink-mute:  oklch(53.5759% 0.0131 252.2);
  --accent:    oklch(35.476% 0.16 259.7);
  --accent-soft: oklch(92.137% 0.045 253.3);
  --accent-deep: oklch(26.236% 0.135 259.9);
  --read-bg:   oklch(95.179% 0.04 116);
  --link:      oklch(41.504% 0.185 257.5);
  --selection: oklch(87.637% 0.06 254);
  /* —— 投影刻度（2026-10-24 现代感精修）——
     fix：此前 6 套浅色主题写成 `oklch(L C H) / A` —— alpha 斜杠落在颜色函数**括号外**，
     不是合法的 CSS Color 4 语法（斜杠只在括号内有效）。浏览器实测（computed style）：
     替换进 box-shadow 后整条声明非法、静默回退 `none` —— 浅色主题卡片投影**从未生效过**。
     暗色三主题写的是括号内 `oklch(0% 0 0 / A)`，合法，一直生效。本轮统一语法，
     并把三档升级为「接触影 + 抬升影 + 弥散影」多层刻度：越大的 blur 层 alpha 越低，
     投影色相跟随各主题 --ink（近黑而不纯黑，与冷暖底色不打架）。
     浅色 6 套同此写法（见各主题块），复古纸 alpha 整体 ×1.2 保留「纸下压痕」。 */
  --shadow-sm: 0 1px 2px oklch(18.743% 0.0138 243.7 / 0.05), 0 1px 1px oklch(18.743% 0.0138 243.7 / 0.03);
  --shadow:    0 1px 2px oklch(18.743% 0.0138 243.7 / 0.04), 0 4px 10px -2px oklch(18.743% 0.0138 243.7 / 0.06), 0 12px 24px -6px oklch(18.743% 0.0138 243.7 / 0.05);
  --shadow-lg: 0 2px 4px oklch(18.743% 0.0138 243.7 / 0.05), 0 12px 32px -6px oklch(18.743% 0.0138 243.7 / 0.12), 0 24px 48px -12px oklch(18.743% 0.0138 243.7 / 0.08);
  /* fix audit 2026-10-25 组82：meta theme-color 同步源。顶栏实际底色是
     color-mix(--bg-elev 86%, transparent)（磨砂玻璃），但 theme-color 规范不鼓励
     带 alpha 的值（各浏览器对透明色的系统色处理不一）→ 取其不透明主体
     --bg-elev。自定义属性的计算值会代入 var() 引用，
     getComputedStyle(documentElement).getPropertyValue("--ui-chrome") 直接得到
     当前主题的色串，单源零手抄（组73 口径）；10 个主题块无需各自复制。
     消费方 core/topbar.js:_syncThemeColorMeta（切主题时写两张 meta）。 */
  --ui-chrome: var(--bg-elev);
  /* fix audit 2026-10-25 组82：可交互控件的可见边框（WCAG 1.4.11 非文本对比 ≥3:1）。
     --border 各主题约为 1.3–1.7:1 —— 输入框/图标按钮的边框实际「看不见」。
     55% 墨色混进页面底色后估算：journal ≈3.5:1、暗色方向 ≈3.2:1，双向达标；
     随 --ink/--bg 自动翻转，仍是一行单源。只用于**控件边框**，正文分隔线/卡片
     边框仍用 --border（那是装饰性描边，不适用 1.4.11）。 */
  --border-strong: color-mix(in oklch, var(--ink) 55%, var(--bg));
  --card-accent: var(--accent);

  --c1-bg:oklch(92.137% 0.0178 253.3); --c1-fg:oklch(35.476% 0.0979 259.7);
  --c2-bg:oklch(93.438% 0.0291 82.6); --c2-fg:oklch(43.413% 0.0805 76.1);
  --c3-bg:oklch(92.429% 0.0217 175); --c3-fg:oklch(42.26% 0.0696 172.9);
  --c4-bg:oklch(90.805% 0.0277 309.2); --c4-fg:oklch(39.01% 0.1342 309.1);
  --c5-bg:oklch(90.459% 0.0335 31.6); --c5-fg:oklch(42.303% 0.1393 30.4);
  --c6-bg:oklch(92.919% 0.0377 95.5); --c6-fg:oklch(46.458% 0.0954 95.2);
  --c7-bg:oklch(91.161% 0.0201 154.9); --c7-fg:oklch(42.339% 0.0795 150);
  --c8-bg:oklch(90.472% 0.0295 350.6); --c8-fg:oklch(38.293% 0.1015 352.8);
  /* --c1-bg..--c8-fg 8 套分类色 —— 预留 reserved for category chip palette
     （9 主题 × 8 色 = 72 个声明；当前未在组件中消费，未来与 arxiv-cat-strip 集成）。 */

  --swatch-bg: oklch(98.476% 0.0054 95.1);
  --swatch-accent: oklch(35.476% 0.16 259.7);

  /* 圆角刻度（audit-2026-10-06 补齐；2026-10-24 现代感改版整体调软一档）。
     此前 4 / 7 / 8 / 12 是「工具型界面」的紧刻度；本项目 2026-10-24 起把
     界面外壳（按钮 / 分页 / 顶栏 tab）走向胶囊与圆形（见 components 层），
     内容块（卡片 / 弹窗）需要一条更柔的圆角线来与之呼应：
       sm   6   chip / 输入框 / 小徽章        （原 4）
       base 10  卡片 / 通用控件圆角          （原 7）
       md   14  抬升一层的内容块（分组、面板）（原 8）
       lg   18  弹窗 / 模态（与 --shadow-lg 的浮起高度匹配）（原 12）
     比例近似 ×1.3 递进，与「半径越大、内容块越浮」的层次语义一致。 */
  --radius-sm: 6px;    /* chip / 输入框 / 小徽章 */
  --radius: 10px;      /* 卡片 / 按钮（默认档） */
  --radius-md: 14px;   /* 抬升一层的内容块（收藏分组、筛选面板） */
  --radius-lg: 18px;   /* 弹窗 / 模态（与 --shadow-lg 视觉重量匹配） */
  --radius-pill: 9999px; /* 胶囊（tag / chip / 圆形按钮的塌陷写法） */
  /* 未令牌化的字面值及其理由（2026-10-24 实测复核）：
       50%            ×11+ 正圆（图标按钮 / 圆点），塌缩写法而非刻度档位
       1px / 0        发丝线与直角特例
       0 3px 3px 0    左侧贴边气泡的单侧圆角
       14px 14px 0 0  顶部贴边横幅（窄屏 modal 抽屉化）的单侧圆角
     —— 这四类是有意的形状表达，不属于「缺刻度」，故不进刻度。
     原清单里的「4px = --radius-sm 同值写法」一处（.dp-shortcuts kbd）已随
     本轮回改收进 var(--radius-sm)，刻度与用法不再有同值双写。 */
  /* 顶栏高度（被抽屉定位/高度引用）。JS 在 init() 用 ResizeObserver 把实测高度写回，
     桌面默认 60px、平板默认 60px、手机默认 56px——这里只设桌面默认值。 */
  --topbar-h: 60px;
  /* ---- 字体栈（平台原生）----
     项目硬约束是 file:// 双击即用 + 零运行时依赖，因此**不能用 @font-face 引 webfont**：
     Chrome 把 file:// 页面视作 opaque origin，@font-face 跨源请求被 CORS 拦掉且**静默不生效**
     （页面上不报错、Network 里没有 font 请求、字体悄悄回退）。实测本项目全站 font
     请求数为 0 —— 此前声明的 "Inter" / "Source Serif Pro" / "JetBrains Mono" 从未落地过。

     ui-serif / system-ui / ui-monospace 是 CSS 通用字体族（CSS Fonts 4），让浏览器直接
     取平台"系统 UI 字体"。这是 file:// 场景下唯一 100% 可用、零字节体积的方案。
     CJK 按 macOS → Windows → Linux 顺序回退：ui-serif 在中文系统上通常不覆盖 CJK
     （macOS 的 New York 没有中文字形），必须显式给出宋体族，否则中文会掉到最后一行
     generic serif 上，各平台观感不一致。 */
  --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", "Songti SC", "SimSun",
                "Noto Serif CJK SC", "Source Han Serif SC", serif;
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
               "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
               "Noto Sans CJK SC", "Source Han Sans SC", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Consolas, "Liberation Mono",
               Menlo, "Courier New", monospace;

  /* —— 间距 scale：4px 基准栅格 ——
     此前只有 4/8/12/16/24/32/48/64 八级，且 16→24 直接跳过 20、24→32 跳过 28，
     于是布局里出现大量 14/18/22/26px 这样的"半档"值——栅格一断，节奏就散了。
     这里补全为完整的 4px 栅格（1~6 级每级 4px，之后每级 8px 再 16px），
     任何 padding/margin/gap 都必须取自这里。 */
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-7:  32px;
  --space-8:  40px;
  --space-9:  48px;
  --space-10: 64px;
  --space-11: 80px;
  --space-12: 96px;
  /* 刻度与语义令牌的区别：尺度台阶是**词汇表**，允许有当前没被消费的档位
     （--space-9/10 目前 0 引用，但 48/64px 的间隙是迟早会出现的场景）；
     语义令牌（如 --leading-body）则必须每一条都有人用——定义了却没人引用，
     就是本次重构要消灭的「装饰性令牌」。 */

  /* —— 字号 scale：模数比例（modular scale）——
     比例 1.2（minor third，6:5），基准 14px，半级步长 √1.2 ≈ 1.095。
     选 1.2 而不是更大的比例，是因为这是一个**高密度阅读界面**（侧栏 121 天日期列表、
     卡片 meta 行、13px 的 arXiv 分类串），需要比 1.25 更细的刻度才能既保持
     比例关系、又不把 30 个实际在用的字号压成 6 档（压档必然带来可观的视觉跳变）。

         2xs  14 × 1.2^-1.5 = 10.65   kbd / 计数角标（最小可读下限）
         xs   14 × 1.2^-1   = 11.67   meta / 次要信息
         sm   14 × 1.2^-0.5 = 12.75   密集 UI：侧栏日期、分类 chip
         md   14 × 1.2^0    = 14.00   ★ 基准正文
         lg   14 × 1.2^0.5  = 15.28   次级标题 / 窄屏卡片标题
         xl   14 × 1.2^1    = 16.80   宽屏卡片标题
         2xl  14 × 1.2^1.5  = 18.41   区块标题
         3xl  14 × 1.2^2    = 20.16   空态 / 大按钮文字
         4xl  14 × 1.2^2.5  = 24.19   区块大标题
         5xl  14 × 1.2^3    = 29.03   页面 h1 / 首页大标题

     单位用 rem 而非 px：此前全站 173 处 font-size 全部锁死 px，用户在浏览器里把
     "字号"调到 120% / 200% 对本站**零效果**，违反 WCAG 2.2 SC 1.4.4 Resize Text。
     1rem = 16px 是浏览器默认基准，14px 基准正文 = 0.875rem。

     刻意**不用** clamp()/vw 做流体字号：流体字号让每一级字号在 320→1920px 间持续变化，
     既不可预测也会让模数比例失效（比例只在固定值下才成立）。响应式交给媒体查询。 */
  --text-2xs:  0.6656rem;     /* 10.65px */
  --text-xs:   0.7294rem;     /* 11.67px */
  --text-sm:   0.7969rem;     /* 12.75px */
  --text-md:   0.875rem;      /* 14.00px ★ 基准 */
  --text-lg:   0.955rem;      /* 15.28px */
  --text-xl:   1.05rem;       /* 16.80px */
  --text-2xl:  1.1506rem;     /* 18.41px */
  --text-3xl:  1.26rem;       /* 20.16px */
  --text-4xl:  1.5119rem;     /* 24.19px */
  /* 组87：--text-5xl（29.03px）随首页 .home-header h1 退役——唯一使用者消失，
     刻度表保留到 4xl；未来出现更大的页面级标题时按 1.2³ 反解补回。 */

  /* 行高刻度：5 级。此前全站散落 14 个不同数值（1 / 1.2 / 1.25 / 1.32 / 1.35 /
     1.36 / 1.4 / 1.45 / 1.5 / 1.55 / 1.6 / 1.65 / 1.68 / 1.7 / 1.78），
     每一个都是当年某次局部微调的产物，彼此之间没有任何关系。
     这 5 级是按「与既有值的最大偏差 ≤ 5%（视觉上不可辨）」反解出来的，所以
     收拢成刻度不会带来可见的版式变化。 */
  --leading-none:    1;      /* 图标 / 角标 / 单行控件：不要行高概念 */
  --leading-tight:   1.25;   /* 大标题：字越大行距要越紧，否则标题散架 */
  --leading-heading: 1.4;    /* 小标题 / 卡片标题 */
  --leading-relaxed: 1.55;   /* UI 文本 / meta / 表单 */
  --leading-body:    1.7;    /* ★ 正文 / 摘要 —— 中英混排需要比纯拉丁更松，
                                  否则上一行的下伸部会「顶」到下一行 */

  /* 可读行长（measure）：WCAG / 排版惯例建议单行 45~75 个字符，超过 80 行回
     "锯齿"急剧恶化（每次换行都成为寻找下一行的干扰源）。68ch 落在舒适区中位。
     详情面板收起时正文列不应该无限拉宽——此前 1fr 把卡片撑到 900px+，
     摘要一行能塞进 120+ 字符，正是这里没设上限。 */
  --measure: 68ch;

  /* —— 动画时长 token（3 阶：快/中/慢）——
     iter 113 Phase 2：把所有 transition / animation 时长收敛到这 3 阶。
     - --dur-fast (var(--dur-fast))：hover / focus / 微交互（border 变色、icon 微动）
     - --dur-base (var(--dur-base)) ：常规颜色 / 背景过渡（按钮、卡片、tab）
     - --dur-slow (var(--dur-slow))：布局 / 形变 / 抽屉 / 入场动画
     prefers-reduced-motion 媒体查询会把所有 transition-duration 强制为 0.01ms，
     见文件末尾兜底块。 */
  --dur-fast: 0.15s;
  --dur-base: 0.2s;
  --dur-slow: 0.35s;

  /* —— 缓动函数 ——
     只有两个在用：--ease-std-out（7 处硬编码 cubic-bezier(0.2, 0, 0, 1) 收敛而来，
     卡片过渡 / 抽屉 / 模态入场）与 --ease-out-quint。刻意不补第三条：
     定义的缓动如果没有消费点，就是「装饰性令牌」，正是本次重构要消灭的东西。 */
  --ease-std-out: cubic-bezier(0.2, 0, 0, 1);
  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);

  /* —— 新增：z-index 阶梯 —— */
  --z-base: 1;
  --z-dropdown: 10;
  --z-sidebar: 25;
  --z-topbar: 30;
  --z-modal: 300;
  --z-toast: 9999;
  /* iter 114 Phase 1：补全缺失的 z-index 阶梯 —— 加载遮罩、跳过链接、弹层菜单
     --z-skip-link 50 在 --z-topbar 之上、--z-modal 之下，保证可见但不挡弹窗
     --z-popover 200 在顶栏之上、modal 之下，给 theme-menu 用 */
  --z-loading: 1000;
  --z-skip-link: 50;
  /* fix audit 2026-10-25 组82：.back-to-top 此前借用 --z-skip-link —— 数值恰好
     也要 50，但语义是「浮动操作按钮」，不是「跳过导航链接」。独立档位防未来
     有人调 skip-link 层顺手动了 FAB 的遮挡关系（值不变，零视觉影响）。 */
  --z-fab: 50;
  --z-popover: 200;
  /* 确认弹窗（.prl-confirm-backdrop）必须压在 --z-toast 9999 之上 ——
     「确认删除收藏」和 toast 可能同帧出现，toast 反盖确认框会让用户
     误以为弹窗已经消失（iter 116 的 window.confirm 替换）。 */
  --z-confirm: 10001;

  /* 圆角刻度统一在文件头定义（--radius-sm / --radius / --radius-md /
     --radius-lg / --radius-pill），此处不再重复声明 —— 同名令牌在两个位置
     各写一遍，改了一处忘了另一处就是隐蔽的漂移源。 */

  /* —— 新增：反白文字色 —— */
  --text-on-light-accent: oklch(20.983% 0.0083 84.6);
  --text-on-accent: oklch(97.632% 0.0313 91);

  /* —— iter 114 Phase 1：状态色（success / warning / danger / info）——
     之前 .prl-toast 的 var(--state-warning, oklch(42.303% 0.1393 30.4)) / var(--state-danger, oklch(42.303% 0.1393 30.4))
     是 fallback，--state-* 从未声明，warning 与 danger 共用同一红色（不合语义）。
     现在显式声明 warning 为 amber（oklch(50.865% 0.15 70.4)，AA 5.93:1 on white），danger 为红色。
     state-* 系列颜色都是面向 oklch(100% 0 0) 的浅色；dark / space / moss 主题未来若需要更深色对比可手动调浅色 state-* 配套。 */
  --state-success: oklch(42.339% 0.125 150);
  --state-warning: oklch(50.865% 0.15 70.4);
  --state-danger:  oklch(42.303% 0.17 30.4);

  /* 警告/危险软背景（用于 banner / notice 类淡色底）—— 让 .fav-notice 等
     "软警告"组件能跨主题统一语义。9 主题各自覆盖深色变体。 */
  --state-warning-bg:   oklch(96.19% 0.08 95.6);
  --state-warning-fg:   oklch(41.371% 0.14 45.9);
  --state-warning-edge: oklch(76.859% 0.1647 70.1);
  --state-warning-bar:  oklch(66.584% 0.1574 58.3);
  --state-danger-bg:    oklch(93.564% 0.05 17.7);
  --state-danger-fg:    oklch(39.584% 0.16 25.7);

  /* —— 新增：期刊品牌色（PRL 蓝 / PRB 棕）—— */
  --journal-prl: oklch(41.255% 0.14 260);
  --journal-prb: oklch(41.334% 0.125 56.6);

  /* —— 新增：遮罩色 ——
     黑色叠加（用于浅色主题下压暗/悬停/按压）。按 alpha 从淡到浓排成一条刻度，
     组件层只引用令牌、不写字面值。 */
  --overlay-faint: oklch(0% 0 0 / 0.05);
  --overlay-soft: oklch(0% 0 0 / 0.08);
  --overlay-mid: oklch(0% 0 0 / 0.18);
  --overlay-active: oklch(0% 0 0 / 0.16);
  --overlay-press: oklch(0% 0 0 / 0.25);
  --overlay-strong: oklch(0% 0 0 / 0.4);
  --overlay-modal: oklch(0% 0 0 / 0.5);

  /* —— 新增：白色叠加 ——
     暗色主题下的悬停/选中态需要「提亮」而不是「压暗」，所以是白色 alpha 叠加。
     与上面的黑叠加是两套刻度，不能互相替代（把 0.08 黑用到暗色主题上会让
     元素比背景更暗，视觉上等于没高亮）。 */
  --tint-faint: oklch(100% 0 0 / 0.07);
  --tint-soft: oklch(100% 0 0 / 0.08);
  --tint-mid: oklch(100% 0 0 / 0.1);

  /* —— 新增：确认对话框阴影 ——
     值比 --shadow-lg 更重（弥散层 24px 64px + 0.28 alpha，另加 4px 接触影），因为对话框是浮在最上层、
     背后还有一层 modal 遮罩，需要比普通卡片更强的投影来分离层次。 */
  --shadow-modal: 0 4px 12px oklch(0% 0 0 / 0.12), 0 24px 64px -12px oklch(0% 0 0 / 0.28);
}

  /* —— 打印专用墨色（print palette tokens，fix audit-2026-10-24）——
     纸上恒为白底黑字：浏览器默认不打印背景色，深色主题（dark/space/moss）
     「深底浅字」打印时退化为「白纸上浅字」（对比度 ≈1:1，不可读）。
     字面色放 tokens 层是本层特许；真正盖掉 9 主题值的重映射在 components 层
     @media print 的 :root 里做（层序 components 晚于 themes，同 specificity 后者
     胜），那边全部引用 var(--print-*)，不新增字面色、不破 lint-tokens 零字面 baseline。
     取值口径：ink 族 = 期刊白 :root 默认的中性化版本（纯灰阶，不随屏幕主题漂移）；
     selection = 记号笔黄，打印检索命中词用（配合组件层 print-color-adjust: exact）。 */
  @media print {
    :root {
      --print-ink:         oklch(21% 0.006 250);
      --print-ink-soft:    oklch(34% 0.006 250);
      --print-ink-mute:    oklch(47% 0.006 250);
      --print-link:        oklch(36% 0.14 258);
      --print-bg:          oklch(100% 0 0);
      --print-border:      oklch(78% 0.006 250);
      --print-border-soft: oklch(87% 0.006 250);
      --print-selection:   oklch(93% 0.105 96);
    }
  }

} /* end @layer tokens */

@layer themes {
/* 2026-10-24 现代感精修（9 套主题）：
   - 浅色主题：accent / link / accent-soft / accent-deep / selection / read-bg / state-*
     一律提 chroma（艳一档、L 基本不动）——原值灰蒙、像被雾罩住；软底与选区跟着强调色
     走色而非纯中性。**中性文字梯度刻意不动**：--ink-mute / --bg-soft 处于 AA 刀尖（4.55），
     任何一侧再动就会跌破审计线（audit_contrast.py 会红）。
   - 暗色主题（dark / space / moss）：背景梯度整体压深半档、border 略提——夜色要有
     「夜景色」而不是灰洞；accent / accent-deep 提亮提艳，暗底可读性同步改善。
   - 投影统一三层刻度并修复浅色主题非法斜杠写法（详见 :root 投影注释）。
   - swatch-bg / swatch-accent 与各主题 bg / accent 字面量保持同步（防漂移靠约定，
     主题菜单圆点的对比度由 NON_TEXT 守卫兜底）。c1..c8 分类色与全局令牌未动。 */
[data-theme="beige"] {
  /* —— 主题 2：学术米黄 —— */
  --bg:        oklch(97.003% 0.0082 91.5);
  --bg-elev:   oklch(100% 0 0);
  --bg-soft:   oklch(94.294% 0.0124 91.5);
  --bg-hover:  oklch(94.319% 0.0153 90.2);
  --border:    oklch(89.766% 0.0196 90.6);
  --border-soft: oklch(93.136% 0.014 88.7);
  --ink:       oklch(20.983% 0.0083 84.6);
  --ink-soft:  oklch(40.259% 0.0106 84.6);
  --ink-mute:  oklch(52.58% 0.0099 84.6);
  --accent:    oklch(41.334% 0.135 56.6);
  --accent-soft: oklch(92.58% 0.055 80.2);
  --accent-deep: oklch(32.963% 0.115 54.8);
  --read-bg:   oklch(96.726% 0.045 90.7);
  --link:      oklch(41.255% 0.16 260);
  --selection: oklch(92.147% 0.075 84);
  --shadow-sm: 0 1px 2px oklch(22.21% 0.0059 91.6 / 0.05), 0 1px 1px oklch(22.21% 0.0059 91.6 / 0.03);
  --shadow:    0 1px 2px oklch(22.21% 0.0059 91.6 / 0.04), 0 4px 10px -2px oklch(22.21% 0.0059 91.6 / 0.06), 0 12px 24px -6px oklch(22.21% 0.0059 91.6 / 0.05);
  --shadow-lg: 0 2px 4px oklch(22.21% 0.0059 91.6 / 0.05), 0 12px 32px -6px oklch(22.21% 0.0059 91.6 / 0.12), 0 24px 48px -12px oklch(22.21% 0.0059 91.6 / 0.08);
  --card-accent: var(--accent);

  --c1-bg:oklch(94.644% 0.0143 254.6); --c1-fg:oklch(41.255% 0.0968 260);
  --c2-bg:oklch(92.58% 0.0268 80.2); --c2-fg:oklch(41.334% 0.0784 56.6);
  --c3-bg:oklch(93.681% 0.0168 178.3); --c3-fg:oklch(47.998% 0.067 178.7);
  --c4-bg:oklch(92.922% 0.0205 311.1); --c4-fg:oklch(41.924% 0.1086 307.6);
  --c5-bg:oklch(91.981% 0.0236 27.4); --c5-fg:oklch(48.933% 0.139 29.1);
  --c6-bg:oklch(93.338% 0.0273 93.1); --c6-fg:oklch(52.064% 0.1003 93);
  --c7-bg:oklch(92.497% 0.0144 148.8); --c7-fg:oklch(48.602% 0.0722 151);
  --c8-bg:oklch(91.714% 0.027 340.9); --c8-fg:oklch(44.184% 0.0974 350.5);

  --swatch-bg: oklch(97.003% 0.0082 91.5);
  --swatch-accent: oklch(41.334% 0.135 56.6);

  /* iter 114 Phase 1：状态色覆盖（beige 与 journal 同 — 暖色调暗黄警告 + 暗红 danger） */
  --state-success: oklch(47.998% 0.11 178.7);
  --state-warning: oklch(41.334% 0.135 56.6);
  --state-danger:  oklch(42.303% 0.17 30.4);
}

[data-theme="dark"] {
  /* —— 主题 3：暖墨 —— */
  color-scheme: dark;
  --bg:        oklch(18.4% 0.016 88.8);
  --bg-elev:   oklch(21.9% 0.022 87.6);
  --bg-soft:   oklch(24.8% 0.024 89.9);
  --bg-hover:  oklch(27.4% 0.026 91.8);
  --border:    oklch(33.2% 0.028 80.5);
  --border-soft: oklch(28.6% 0.026 88.8);
  --ink:       oklch(92.232% 0.0264 90.1);
  --ink-soft:  oklch(75.785% 0.0318 90.4);
  --ink-mute:  oklch(63.5% 0.04 88.4);
  --accent:    oklch(76.5% 0.14 74);
  --accent-soft: oklch(31.5% 0.065 77.1);
  --accent-deep: oklch(85.2% 0.115 72.1);
  --read-bg:   oklch(23.2% 0.045 86.6);
  --link:      oklch(76.296% 0.12 257.7);
  --selection: oklch(39% 0.095 73.4);
  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.55), 0 1px 1px oklch(0% 0 0 / 0.35);
  --shadow:    0 2px 4px oklch(0% 0 0 / 0.45), 0 8px 20px -4px oklch(0% 0 0 / 0.4), 0 16px 40px -8px oklch(0% 0 0 / 0.3);
  --shadow-lg: 0 4px 8px oklch(0% 0 0 / 0.45), 0 16px 44px -8px oklch(0% 0 0 / 0.55), 0 32px 72px -16px oklch(0% 0 0 / 0.35);
  --card-accent: var(--accent);

  --c1-bg:oklch(28.391% 0.0406 260.3); --c1-fg:oklch(79.553% 0.0691 251.4);
  --c2-bg:oklch(29.925% 0.0357 65.8); --c2-fg:oklch(75.628% 0.0947 74);
  --c3-bg:oklch(30.049% 0.0302 175); --c3-fg:oklch(78.383% 0.0711 177.4);
  --c4-bg:oklch(27.388% 0.0419 304.6); --c4-fg:oklch(76.429% 0.0824 306.9);
  --c5-bg:oklch(27.675% 0.0414 29.4); --c5-fg:oklch(74.725% 0.0897 31.4);
  --c6-bg:oklch(29.77% 0.0354 94); --c6-fg:oklch(78.005% 0.0941 97.2);
  --c7-bg:oklch(28.273% 0.0307 151.9); --c7-fg:oklch(78.306% 0.0813 153.2);
  --c8-bg:oklch(27.041% 0.0333 342.3); --c8-fg:oklch(73.024% 0.0916 349.8);

  --swatch-bg: oklch(18.4% 0.016 88.8);
  --swatch-accent: oklch(76.5% 0.14 74);

  /* iter 114 Phase 1：暗色主题用浅色状态色 + 反白文字色用 oklch(18.4% 0.016 88.8)
     （与 --accent 同色调，警告 = 琥珀色 oklch(76.5% 0.14 74) 系，AA 通过） */
  --state-success: oklch(78.383% 0.105 177.4);
  --state-warning: oklch(76.5% 0.14 74);
  --state-danger:  oklch(74.725% 0.135 31.4);
  /* 暗色主题下 fav-notice 等软警告背景：用深琥珀底 + 浅琥珀文字 */
  --state-warning-bg:   oklch(27.5% 0.08 53.8);
  --state-warning-fg:   oklch(92.428% 0.1151 95.7);
  /* 组127（全面审查 M8a）：danger 对与上方 warning 对同构补齐——此前四套暗色
     主题只覆写了 warning-bg/-fg，danger-bg/-fg 漏网沿用 :root 浅底版，
     「清空收藏」钮 hover/焦点态在深底上用 L≈39.6% 的暗红（对比度不足）。 */
  --state-danger-bg:    oklch(27.5% 0.07 25.7);
  --state-danger-fg:    oklch(89.6% 0.11 25.7);
  --state-warning-edge: oklch(47.319% 0.1247 46.2);
  --state-warning-bar:  oklch(76.859% 0.1647 70.1);
}

[data-theme="paper"] {
  /* —— 主题 4：复古纸 —— */
  --bg:        oklch(90.723% 0.0439 91.3);
  --bg-elev:   oklch(93.346% 0.05 93.1);
  --bg-soft:   oklch(87.498% 0.0513 89.8);
  --bg-hover:  oklch(89.097% 0.04 88.3);
  --border:    oklch(77.212% 0.0642 91.1);
  --border-soft: oklch(82.633% 0.0653 93.8);
  --ink:       oklch(25.025% 0.0405 70.1);
  --ink-soft:  oklch(39.749% 0.0594 74.2);
  --ink-mute:  oklch(47.834% 0.0721 81.7);
  --accent:    oklch(35.915% 0.135 51.3);
  --accent-soft: oklch(84.298% 0.08 80.4);
  --accent-deep: oklch(25.961% 0.1 52);
  --read-bg:   oklch(89.495% 0.065 91.8);
  --link:      oklch(41.334% 0.12 56.6);
  --selection: oklch(74.592% 0.115 83.8);
  --shadow-sm: 0 1px 2px oklch(29.482% 0.0509 72.4 / 0.06), 0 1px 1px oklch(29.482% 0.0509 72.4 / 0.04);
  --shadow:    0 1px 2px oklch(29.482% 0.0509 72.4 / 0.05), 0 4px 10px -2px oklch(29.482% 0.0509 72.4 / 0.08), 0 12px 24px -6px oklch(29.482% 0.0509 72.4 / 0.07);
  --shadow-lg: 0 2px 4px oklch(29.482% 0.0509 72.4 / 0.07), 0 12px 32px -6px oklch(29.482% 0.0509 72.4 / 0.15), 0 24px 48px -12px oklch(29.482% 0.0509 72.4 / 0.10);
  --card-accent: var(--accent);

  --c1-bg:oklch(87.472% 0.022 118.3); --c1-fg:oklch(30.177% 0.0554 261);
  --c2-bg:oklch(83.594% 0.0561 88.8); --c2-fg:oklch(35.915% 0.0828 51.3);
  --c3-bg:oklch(86.566% 0.0278 145.3); --c3-fg:oklch(33.27% 0.0523 154.9);
  --c4-bg:oklch(84.591% 0.018 17.5); --c4-fg:oklch(31.163% 0.0806 339);
  --c5-bg:oklch(82.903% 0.0491 58.9); --c5-fg:oklch(35.796% 0.1202 32.7);
  --c6-bg:oklch(83.082% 0.0648 95.7); --c6-fg:oklch(35.639% 0.0661 89.2);
  --c7-bg:oklch(85.32% 0.0401 126.2); --c7-fg:oklch(32.911% 0.0713 141.6);
  --c8-bg:oklch(82.799% 0.0273 17.7); --c8-fg:oklch(33.816% 0.0935 12.4);

  --swatch-bg: oklch(90.723% 0.0439 91.3);
  --swatch-accent: oklch(35.915% 0.135 51.3);

  /* iter 114 Phase 1：复古纸主题状态色（暖色调：琥珀 warning + 砖红 danger） */
  --state-success: oklch(48.602% 0.0722 151);
  --state-warning:  oklch(50.56% 0.1017 70.4);
  --state-danger:  oklch(42.303% 0.16 30.4);
}

[data-theme="mist"] {
  /* —— 主题 5：雾岚（晨雾·冷感） —— */
  --bg:        oklch(95.672% 0.01 247.9);
  --bg-elev:   oklch(100% 0 0);
  --bg-soft:   oklch(92.863% 0.0087 247.9);
  --bg-hover:  oklch(90.92% 0.0111 243.7);
  --border:    oklch(86.894% 0.013 244.3);
  --border-soft: oklch(91.299% 0.0104 247.9);
  --ink:       oklch(23.932% 0.0256 251.3);
  --ink-soft:  oklch(39.174% 0.0278 248.5);
  --ink-mute:  oklch(51.51% 0.0198 248.2);
  --accent:    oklch(51.537% 0.14 247.6);
  --accent-soft: oklch(92.336% 0.05 248);
  --accent-deep: oklch(40.086% 0.12 251.2);
  --read-bg:   oklch(93.741% 0.02 241.7);
  --link:      oklch(50.203% 0.16 249.8);
  --selection: oklch(86.974% 0.06 248.1);
  --shadow-sm: 0 1px 2px oklch(23.932% 0.0256 251.3 / 0.05), 0 1px 1px oklch(23.932% 0.0256 251.3 / 0.03);
  --shadow:    0 1px 2px oklch(23.932% 0.0256 251.3 / 0.04), 0 4px 10px -2px oklch(23.932% 0.0256 251.3 / 0.06), 0 12px 24px -6px oklch(23.932% 0.0256 251.3 / 0.05);
  --shadow-lg: 0 2px 4px oklch(23.932% 0.0256 251.3 / 0.05), 0 12px 32px -6px oklch(23.932% 0.0256 251.3 / 0.12), 0 24px 48px -12px oklch(23.932% 0.0256 251.3 / 0.08);
  --card-accent: var(--accent);

  --c1-bg:oklch(92.336% 0.0173 248); --c1-fg:oklch(40.086% 0.0652 251.2);
  --c2-bg:oklch(91.508% 0.0259 84.6); --c2-fg:oklch(43.413% 0.0805 76.1);
  --c3-bg:oklch(91.329% 0.0159 177.1); --c3-fg:oklch(42.26% 0.0696 172.9);
  --c4-bg:oklch(90.805% 0.0277 309.2); --c4-fg:oklch(39.01% 0.1342 309.1);
  --c5-bg:oklch(90.465% 0.0258 35.7); --c5-fg:oklch(42.303% 0.1393 30.4);
  --c6-bg:oklch(92.202% 0.0348 98.1); --c6-fg:oklch(46.458% 0.0954 95.2);
  --c7-bg:oklch(90.145% 0.0168 156.9); --c7-fg:oklch(42.339% 0.0795 150);
  --c8-bg:oklch(90.933% 0.0198 349.1); --c8-fg:oklch(38.293% 0.1015 352.8);

  --swatch-bg: oklch(95.672% 0.01 247.9);
  --swatch-accent: oklch(51.537% 0.14 247.6);

  /* iter 114 Phase 1：雾岚主题状态色（冷色调：靛 warning + 砖红 danger） */
  --state-success: oklch(47.998% 0.115 178.7);
  --state-warning: oklch(43.413% 0.125 76.1);
  --state-danger:  oklch(42.303% 0.17 30.4);
}

[data-theme="sage"] {
  /* —— 主题 6：苔原（鼠尾草·自然） —— */
  --bg:        oklch(95.468% 0.016 119.6);
  --bg-elev:   oklch(98.166% 0.0094 119.6);
  --bg-soft:   oklch(91.879% 0.019 116.6);
  --bg-hover:  oklch(88.673% 0.0233 117.6);
  --border:    oklch(83.866% 0.0291 117.9);
  --border-soft: oklch(88.596% 0.0272 116.1);
  --ink:       oklch(25.117% 0.0229 126.4);
  --ink-soft:  oklch(37.51% 0.028 126.9);
  --ink-mute:  oklch(50.725% 0.0258 126.6);
  --accent:    oklch(50.187% 0.135 125.7);
  --accent-soft: oklch(90.276% 0.06 117);
  --accent-deep: oklch(38.468% 0.12 127.2);
  --read-bg:   oklch(92.511% 0.045 112.6);
  --link:      oklch(44.325% 0.12 126.7);
  --selection: oklch(84.733% 0.085 119.3);
  --shadow-sm: 0 1px 2px oklch(25.117% 0.0229 126.4 / 0.05), 0 1px 1px oklch(25.117% 0.0229 126.4 / 0.03);
  --shadow:    0 1px 2px oklch(25.117% 0.0229 126.4 / 0.04), 0 4px 10px -2px oklch(25.117% 0.0229 126.4 / 0.06), 0 12px 24px -6px oklch(25.117% 0.0229 126.4 / 0.05);
  --shadow-lg: 0 2px 4px oklch(25.117% 0.0229 126.4 / 0.05), 0 12px 32px -6px oklch(25.117% 0.0229 126.4 / 0.12), 0 24px 48px -12px oklch(25.117% 0.0229 126.4 / 0.08);
  --card-accent: var(--accent);

  --c1-bg:oklch(91.07% 0.0098 252.8); --c1-fg:oklch(34.574% 0.0473 258.3);
  --c2-bg:oklch(88.389% 0.0339 88.1); --c2-fg:oklch(43.413% 0.0805 76.1);
  --c3-bg:oklch(89.169% 0.0263 141.8); --c3-fg:oklch(36.943% 0.0689 153.4);
  --c4-bg:oklch(89.07% 0.0155 316); --c4-fg:oklch(35.845% 0.1094 304.5);
  --c5-bg:oklch(86.912% 0.0292 39.3); --c5-fg:oklch(39.353% 0.1217 31);
  --c6-bg:oklch(89.028% 0.0375 100.4); --c6-fg:oklch(41.382% 0.0808 93.8);
  --c7-bg:oklch(87.884% 0.0348 128.9); --c7-fg:oklch(37.326% 0.075 139.6);
  --c8-bg:oklch(87.265% 0.0242 347.3); --c8-fg:oklch(34.389% 0.0893 351.7);

  --swatch-bg: oklch(95.468% 0.016 119.6);
  --swatch-accent: oklch(50.187% 0.135 125.7);

  /* iter 114 Phase 1：苔原主题状态色（自然绿调：深绿 success + 琥珀 warning） */
  --state-success: oklch(37.326% 0.12 139.6);
  --state-warning: oklch(43.413% 0.125 76.1);
  --state-danger:  oklch(42.303% 0.17 30.4);
}

[data-theme="dune"] {
  /* —— 主题 7：沙丘（暖沙·现代） —— */
  --bg:        oklch(94.804% 0.028 83.1);
  --bg-elev:   oklch(97.948% 0.02 88.7);
  --bg-soft:   oklch(91.756% 0.0243 85.8);
  --bg-hover:  oklch(88.52% 0.045 84.6);
  --border:    oklch(85.061% 0.0358 87.1);
  --border-soft: oklch(89.661% 0.0314 86.5);
  --ink:       oklch(24.867% 0.0283 70.6);
  --ink-soft:  oklch(36.035% 0.039 72.3);
  --ink-mute:  oklch(50.838% 0.0403 79.3);
  --accent:    oklch(50.188% 0.15 63.2);
  --accent-soft: oklch(90.306% 0.065 80.6);
  --accent-deep: oklch(44.075% 0.135 66.6);
  --read-bg:   oklch(91.21% 0.05 85.6);
  --link:      oklch(51.136% 0.16 60.2);
  --selection: oklch(83.944% 0.085 84.5);
  --shadow-sm: 0 1px 2px oklch(24.867% 0.0283 70.6 / 0.05), 0 1px 1px oklch(24.867% 0.0283 70.6 / 0.03);
  --shadow:    0 1px 2px oklch(24.867% 0.0283 70.6 / 0.04), 0 4px 10px -2px oklch(24.867% 0.0283 70.6 / 0.06), 0 12px 24px -6px oklch(24.867% 0.0283 70.6 / 0.05);
  --shadow-lg: 0 2px 4px oklch(24.867% 0.0283 70.6 / 0.05), 0 12px 32px -6px oklch(24.867% 0.0283 70.6 / 0.12), 0 24px 48px -12px oklch(24.867% 0.0283 70.6 / 0.08);
  --card-accent: var(--accent);

  --c1-bg:oklch(91.588% 0.0133 251.6); --c1-fg:oklch(35.033% 0.06 263.4);
  --c2-bg:oklch(90.306% 0.0371 80.6); --c2-fg:oklch(45.593% 0.0896 61.7);
  --c3-bg:oklch(90.239% 0.0172 145.4); --c3-fg:oklch(37.045% 0.0645 157.2);
  --c4-bg:oklch(89.533% 0.0207 325.7); --c4-fg:oklch(34.784% 0.0885 313.4);
  --c5-bg:oklch(86.138% 0.0425 32.6); --c5-fg:oklch(39.353% 0.1217 31);
  --c6-bg:oklch(88.272% 0.0494 91.8); --c6-fg:oklch(41.382% 0.0808 93.8);
  --c7-bg:oklch(88.493% 0.0299 126); --c7-fg:oklch(37.326% 0.075 139.6);
  --c8-bg:oklch(87.855% 0.0273 6.2); --c8-fg:oklch(34.229% 0.0871 355.9);

  --swatch-bg: oklch(94.804% 0.028 83.1);
  --swatch-accent: oklch(50.188% 0.15 63.2);

  /* iter 114 Phase 1：沙丘主题状态色（暖沙调：深绿 success + 暖琥珀 warning） */
  --state-success: oklch(37.326% 0.12 139.6);
  --state-warning: oklch(43.413% 0.125 76.1);
  --state-danger:  oklch(42.303% 0.17 30.4);
}

[data-theme="space"] {
  /* —— 主题 8：深空（靛蓝暗色·现代） —— */
  color-scheme: dark;
  --bg:        oklch(18% 0.03 262);
  --bg-elev:   oklch(21.6% 0.034 262.3);
  --bg-soft:   oklch(24.7% 0.03 262.6);
  --bg-hover:  oklch(28% 0.033 262.8);
  --border:    oklch(32.6% 0.045 262.9);
  --border-soft: oklch(27.2% 0.038 265.7);
  --ink:       oklch(89.635% 0.0134 262.4);
  --ink-soft:  oklch(76.165% 0.0219 261.8);
  --ink-mute:  oklch(64% 0.035 258.4);
  --accent:    oklch(71.5% 0.15 255.1);
  --accent-soft: oklch(30% 0.08 260.8);
  --accent-deep: oklch(82.2% 0.1 254.8);
  --read-bg:   oklch(23.4% 0.045 261.4);
  --link:      oklch(74.596% 0.135 253.4);
  --selection: oklch(38% 0.105 261.6);
  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.55), 0 1px 1px oklch(0% 0 0 / 0.35);
  --shadow:    0 2px 4px oklch(0% 0 0 / 0.45), 0 8px 20px -4px oklch(0% 0 0 / 0.4), 0 16px 40px -8px oklch(0% 0 0 / 0.3);
  --shadow-lg: 0 4px 8px oklch(0% 0 0 / 0.45), 0 16px 44px -8px oklch(0% 0 0 / 0.55), 0 32px 72px -16px oklch(0% 0 0 / 0.35);
  --card-accent: var(--accent);

  --c1-bg:oklch(26.387% 0.0391 261); --c1-fg:oklch(79.553% 0.0691 251.4);
  --c2-bg:oklch(27.08% 0.0262 76.4); --c2-fg:oklch(79.9% 0.0732 77.5);
  --c3-bg:oklch(28.265% 0.027 180.2); --c3-fg:oklch(78.377% 0.0716 172.8);
  --c4-bg:oklch(26.582% 0.0484 297.2); --c4-fg:oklch(77.151% 0.0825 304.1);
  --c5-bg:oklch(26.385% 0.0346 19.6); --c5-fg:oklch(75.487% 0.0853 33.7);
  --c6-bg:oklch(28.398% 0.0308 97.2); --c6-fg:oklch(80.86% 0.0709 93);
  --c7-bg:oklch(26.78% 0.0263 162.2); --c7-fg:oklch(78.645% 0.0746 154.2);
  --c8-bg:oklch(26.156% 0.0331 321.9); --c8-fg:oklch(74.272% 0.0789 343.9);

  --swatch-bg: oklch(18% 0.03 262);
  --swatch-accent: oklch(71.5% 0.15 255.1);

  /* iter 114 Phase 1：深空暗色主题用浅色状态色 + 反白文字色 */
  --state-success: oklch(78.377% 0.1 172.8);
  --state-warning: oklch(76.5% 0.14 74);
  --state-danger:  oklch(74.725% 0.135 31.4);
  /* 暗色主题下 fav-notice 等软警告背景 */
  --state-warning-bg:   oklch(19.5% 0.03 47.9);
  --state-warning-fg:   oklch(92.428% 0.1151 95.7);
  --state-danger-bg:    oklch(19.5% 0.05 25.7);  /* 组127 M8a：暗色 danger 对补齐 */
  --state-danger-fg:    oklch(89.6% 0.11 25.7);
  --state-warning-edge: oklch(47.319% 0.1247 46.2);
  --state-warning-bar:  oklch(76.859% 0.1647 70.1);
}

[data-theme="moss"] {
  /* —— 主题 9：夜苔（深森绿暗色·自然） —— */
  color-scheme: dark;
  --bg:        oklch(18.8% 0.022 145.1);
  --bg-elev:   oklch(22.3% 0.024 149.2);
  --bg-soft:   oklch(26% 0.028 148.1);
  --bg-hover:  oklch(29.3% 0.026 145);
  --border:    oklch(34.2% 0.034 147.5);
  --border-soft: oklch(28.4% 0.023 148.2);
  --ink:       oklch(88.393% 0.0232 128.8);
  --ink-soft:  oklch(75.001% 0.0302 128.9);
  --ink-mute:  oklch(65.2% 0.036 126.8);
  --accent:    oklch(75.5% 0.13 134);
  --accent-soft: oklch(29.8% 0.05 144.9);
  --accent-deep: oklch(84.5% 0.105 132.5);
  --read-bg:   oklch(24% 0.03 148);
  --link:      oklch(78.322% 0.12 133.7);
  --selection: oklch(39.2% 0.075 133.9);
  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.55), 0 1px 1px oklch(0% 0 0 / 0.35);
  --shadow:    0 2px 4px oklch(0% 0 0 / 0.45), 0 8px 20px -4px oklch(0% 0 0 / 0.4), 0 16px 40px -8px oklch(0% 0 0 / 0.3);
  --shadow-lg: 0 4px 8px oklch(0% 0 0 / 0.45), 0 16px 44px -8px oklch(0% 0 0 / 0.55), 0 32px 72px -16px oklch(0% 0 0 / 0.35);
  --card-accent: var(--accent);

  --c1-bg:oklch(27.654% 0.0199 230); --c1-fg:oklch(78.816% 0.048 232.5);
  --c2-bg:oklch(26.885% 0.0219 78.8); --c2-fg:oklch(81.817% 0.0599 80.4);
  --c3-bg:oklch(28.125% 0.0325 154.6); --c3-fg:oklch(81.674% 0.0828 159.2);
  --c4-bg:oklch(26.836% 0.0442 290.8); --c4-fg:oklch(74.458% 0.0779 305.6);
  --c5-bg:oklch(27.086% 0.0251 26.9); --c5-fg:oklch(75.781% 0.0774 39.2);
  --c6-bg:oklch(29.079% 0.0242 100.9); --c6-fg:oklch(82.923% 0.0745 97.5);
  --c7-bg:oklch(27.504% 0.0346 141.5); --c7-fg:oklch(82.337% 0.0939 137.5);
  --c8-bg:oklch(26.2% 0.0254 332.1); --c8-fg:oklch(72.325% 0.0699 349.7);

  --swatch-bg: oklch(18.8% 0.022 145.1);
  --swatch-accent: oklch(75.5% 0.13 134);

  /* iter 114 Phase 1：夜苔暗色主题用浅色状态色 + 反白文字色 */
  --state-success: oklch(78.306% 0.115 153.2);
  --state-warning: oklch(76.5% 0.14 74);
  --state-danger:  oklch(74.725% 0.135 31.4);
  /* 暗色主题下 fav-notice 等软警告背景 */
  --state-warning-bg:   oklch(19% 0.025 55.5);
  --state-warning-fg:   oklch(92.428% 0.1151 95.7);
  --state-danger-bg:    oklch(19% 0.05 25.7);  /* 组127 M8a：暗色 danger 对补齐 */
  --state-danger-fg:    oklch(89.6% 0.11 25.7);
  --state-warning-edge: oklch(47.319% 0.1247 46.2);
  --state-warning-bar:  oklch(76.859% 0.1647 70.1);
}

[data-theme="obsidian"] {
  /* —— 主题 10：玄黑（中性纯黑·暗色）——
     与前三套暗色的分野：dark/space/moss 都有一个「底色色相」（暖墨的 88°、
     深空的 262°、夜苔的 145°），玄黑把 chroma 全部归零 —— 纯灰阶底 + 银灰
     强调（accent 也是 C=0，只靠亮度差分层次），唯一的非中性色是 link 的
     微冷调（C=0.012，不足以破坏灰阶观感、又让链接和正文可区分）。
     三套既有暗色的全部色对取值已实算 ≥AA，本主题的 33 组色对
     （PAIRS + NON_TEXT 全集）离线实算最差 5.30（ink-mute/bg-soft），全绿。
     背景梯度压得比 dark（18.4%）更深（14.2% 起）——「玄」即纯黑观感；
     hover/soft/selection 之间的亮度台阶与 dark 一致（≈3-4% 一档），
     保证交互态在纯灰阶下依然可辨。c1..c8 分类角标沿用 dark 的实测值
     （fg 亮度 73-80% 压 26-30% 底，全部 ≥6.1:1）。 */
  color-scheme: dark;
  --bg:        oklch(14.2% 0 0);
  --bg-elev:   oklch(17.8% 0 0);
  --bg-soft:   oklch(21.2% 0 0);
  --bg-hover:  oklch(25% 0 0);
  --border:    oklch(31% 0 0);
  --border-soft: oklch(25.5% 0 0);
  --ink:       oklch(93% 0 0);
  --ink-soft:  oklch(76% 0 0);
  --ink-mute:  oklch(64.5% 0 0);
  --accent:    oklch(82% 0 0);
  --accent-soft: oklch(28% 0 0);
  --accent-deep: oklch(91% 0 0);
  --read-bg:   oklch(19.5% 0 0);
  --link:      oklch(84.5% 0.012 250);
  --selection: oklch(31% 0 0);
  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.55), 0 1px 1px oklch(0% 0 0 / 0.35);
  --shadow:    0 2px 4px oklch(0% 0 0 / 0.45), 0 8px 20px -4px oklch(0% 0 0 / 0.4), 0 16px 40px -8px oklch(0% 0 0 / 0.3);
  --shadow-lg: 0 4px 8px oklch(0% 0 0 / 0.45), 0 16px 44px -8px oklch(0% 0 0 / 0.55), 0 32px 72px -16px oklch(0% 0 0 / 0.35);
  --card-accent: var(--accent);

  --c1-bg:oklch(28.391% 0.0406 260.3); --c1-fg:oklch(79.553% 0.0691 251.4);
  --c2-bg:oklch(29.925% 0.0357 65.8); --c2-fg:oklch(75.628% 0.0947 74);
  --c3-bg:oklch(30.049% 0.0302 175); --c3-fg:oklch(78.383% 0.0711 177.4);
  --c4-bg:oklch(27.388% 0.0419 304.6); --c4-fg:oklch(76.429% 0.0824 306.9);
  --c5-bg:oklch(27.675% 0.0414 29.4); --c5-fg:oklch(74.725% 0.0897 31.4);
  --c6-bg:oklch(29.77% 0.0354 94); --c6-fg:oklch(78.005% 0.0941 97.2);
  --c7-bg:oklch(28.273% 0.0307 151.9); --c7-fg:oklch(78.306% 0.0813 153.2);
  --c8-bg:oklch(27.041% 0.0333 342.3); --c8-fg:oklch(73.024% 0.0916 349.8);

  --swatch-bg: oklch(14.2% 0 0);
  --swatch-accent: oklch(82% 0 0);

  /* 暗色主题状态色与 dark/space/moss 同口径：浅色状态色 + 反白文字色 */
  --state-success: oklch(78.383% 0.105 177.4);
  --state-warning: oklch(76.5% 0.14 74);
  --state-danger:  oklch(74.725% 0.135 31.4);
  /* 暗色主题下 fav-notice 等软警告背景（同 dark 的深琥珀底 + 浅琥珀文字） */
  --state-warning-bg:   oklch(24% 0.05 53.8);
  --state-warning-fg:   oklch(92.428% 0.1151 95.7);
  --state-danger-bg:    oklch(24% 0.06 25.7);  /* 组127 M8a：暗色 danger 对补齐 */
  --state-danger-fg:    oklch(89.6% 0.11 25.7);
  --state-warning-edge: oklch(47.319% 0.1247 46.2);
  --state-warning-bar:  oklch(76.859% 0.1647 70.1);
}

} /* end @layer themes */

/* =========================================================================
   BASE LAYER —— 元素默认值 / reset
   =========================================================================
   此前这段是**裸写在 @layer 之外的**。级联层规则里，「无层」样式的优先级高于
   任何 @layer 内的样式（与 specificity 无关）。后果：
     · 全局 `:focus-visible { outline: 3px solid var(--accent) }` 会压掉
       components 层里 15 处组件级 focus 规则（按钮 2px、输入框自定义框…）；
     · `body { font-size }` 会压掉任何组件对 body 字号的覆盖；
     · `a:hover { text-decoration: underline }` 会压掉组件的链接态。
   包进 base 层后，"组件覆盖基础样式" 才真正成立——这也正是引入 @layer 的目的。
   ========================================================================= */
@layer base {
* { box-sizing: border-box; }
/* fix audit-2026-10-25（组91）：旧版 html,body 同为 height:100%——body 盒被钉死在
   视口高（800px），而内容（如每日页 3300px+）从 body 溢出照常滚动。sticky 的可吸附
   范围以包含块（body 盒）为限，滚过 body 底缘即被一起推走：磨砂玻璃顶栏（2026-10-24
   起 sticky+透底）在长页滚 ~740px 后整个消失，期刊切换/搜索/收藏/已读全部不可达，
   与 .topbar 注释「滚动时正文从顶栏下穿过」的设计意图相反。改 body 为 min-height：
   短页仍撑满视口（底色/布局不变），长页 body 盒随内容生长，顶栏全程吸顶。
   html 保留 height:100%——否则 body 的百分比 min-height 对内容高父级按 0 处理。 */
html { height: 100%; }
html, body { margin: 0; padding: 0; }
body { min-height: 100%; }
::selection { background: var(--selection); color: var(--ink); }


body {
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background var(--dur-base) ease, color var(--dur-base) ease;
}

/* button 的 UA 默认样式带 text-align:center —— 对「整块可点的标题」是灾难：
   .ac-title-link 是 <button class="ac-title-link">，包着一整句论文标题，
   于是每一行都居中，末行左右各差半行，正文的左边界呈锯齿状。
   这不是作者样式写错了（.ac-title 上并没有 text-align:center），是继承自
   UA stylesheet，所以只 grep 作者 CSS 永远找不到。
   统一在 base 层按「按钮标签应当像普通文本一样起始对齐」重置。 */
button { font: inherit; cursor: pointer; border: none; background: none; color: inherit; text-align: start; }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
[hidden] { display: none !important; }

/* —— 自定义滚动条（webkit + Firefox） —— */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: var(--radius-pill);
  border: 2px solid transparent;
  background-clip: padding-box;
  transition: background var(--dur-base);
}
*::-webkit-scrollbar-thumb:hover { background: var(--ink-mute); background-clip: padding-box; }
*::-webkit-scrollbar-corner { background: transparent; }

/* —— 键盘焦点环 —— 鼠标点击不显示，键盘 Tab 才显示（focus-visible 启发式） —— */
/* WCAG 2.2 SC 1.4.11（非文本对比 ≥3:1）+ SC 2.4.7（焦点可见）：
   默认 :focus-visible 用纯 var(--accent) 实色，3px 厚（≥2px 法规下限，
   提升亚像素渲染鲁棒性），offset 2px 避开边框干扰。
   全站 15 处组件级 :focus-visible 已用 var(--accent)，本默认规则统一与之对齐。 */
:focus:not(:focus-visible) { outline: none; }
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
  transition: outline-color var(--dur-fast);
}
/* 文本类输入框用自己的 :focus-within / border-color 框；checkbox/radio 没有
   替代焦点样式，必须保留上面的 3px accent focus 环（WCAG 2.4.7）。 */
input:not([type="checkbox"]):not([type="radio"]):focus-visible { outline: none; }
/* accent-color（fix audit-2026-10-06 MEDIUM-2）：让原生 checkbox / radio 的
   选中态跟随主题 --accent，而不是 UA 默认的蓝色。全站用的是 CSS 变量驱动的
   9 套主题，原生控件若不接管，深色主题下会看到系统蓝。范围限定在根元素上继承，
   避免给每个控件重复写。 */
:root { accent-color: var(--accent); }
} /* end @layer base */

/* =========================================================================
   顶栏
   ========================================================================= */
/* =========================================================================
   noscript 兜底页
   -------------------------------------------------------------------------
   放在 components 层而不是 base 层：base 只该装元素级 reset（* / body / a …），
   带类选择器的整页组件留在 base 会让分层的语义变模糊。

   注：此前这段是**裸写在 @layer 之外**的，位置夹在 base 层结束与 components 层
   开始之间，fix audit-2026-10-06 MEDIUM-1 把它并入下方那个已存在的
   components 层（不新开一层），让层序统一由文件头 @layer 那一行定义。

   配色走 token 而不是写死色值 —— 原注释说「不依赖 JS + CSS var」，这是个误解：
   CSS 自定义属性由 CSS 引擎解析，与 JS 无关。禁 JS 时 <html> 上不会有
   data-theme，于是取到 :root（= 期刊白），与此前写死的三个色值**完全一致**，
   但换成 token 后这份配色不再是一份脱离体系的副本。
   ========================================================================= */
@layer components {
/* noscript 兜底页（此前裸写在层外，2026-10-06 并入 components 层） */
.nojs-banner {
  padding: var(--space-8) var(--space-6);
  text-align: center;
  font-family: var(--font-serif);
  color: var(--ink);
  background: var(--bg);
  line-height: var(--leading-body);
  min-height: 100vh;
  /* audit-2026-10-24 自适应显示：移动浏览器的 100vh = 大视口（URL 栏收起态），
     比可见区高一截——居中排版会把底部内容顶进「看不见」区域。dvh 跟随实际
     可视高度；不支持的浏览器保留上一行 vh（渐进增强，桌面两者相等）。 */
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.nojs-banner h1 { font-size: var(--text-4xl); margin: 0 0 var(--space-3); }
.nojs-banner p  { margin: 0 0 var(--space-4); font-size: var(--text-lg); }
.nojs-banner .nojs-hint { margin: 0; font-size: var(--text-sm); color: var(--ink-mute); }

.topbar {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-3) var(--space-6);
  /* 2026-10-24 现代感改版：顶栏改半透明「磨砂玻璃」。此前 backdrop-filter:
     blur(6px) 一直挂在声明里但对不透明 bg-elev 完全无效（后面没有像素可糊）。
     现在底色压到 86% 不透明度——滚动时正文从顶栏下穿过会带一层柔化残影，
     静止在页顶时与改版前逐像素一致（页面底色 bg 本身就是它的下方内容）。
     86% + 6px blur 是保守值：顶栏文字/图标对比度由 --bg-elev 主导，
     透出的 14% 内容面积在模糊后接近底色本身。 */
  background: color-mix(in srgb, var(--bg-elev) 86%, transparent);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: var(--z-topbar);
  height: 60px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* 2026-10-23 UI 改版：期刊副标题移出顶栏（见 .page-heading），brand 只剩字标。 */
.brand { display: flex; align-items: center; gap: 14px; flex-shrink: 0; min-width: 0; }
/* 2026-10-23：顶栏左上角加站点图标（src/icon.jpg）。
   .brand 里现在是「图标 + 字标」：图标 <img class="brand-icon"> 与字标
   <span class="logo-text"> 都在 .logo 内（2026-10-24 起 .logo 全站是回首页的
   <a>，图标跟着字标一起可点）。.logo 改 inline-flex 居中对齐；图标尺寸用 em ——
   跟字标字号联动，窄屏媒体查询改 .brand .logo 的 font-size 时图标自动跟着缩。 */
.brand .logo {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-serif);
  font-size: var(--text-4xl);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--accent);
  line-height: var(--leading-none);
  text-decoration: none;
  /* audit-2026-10-01 BUG-4：窄屏下 .brand 被 min-width:0 允许压到 min-content，
     而中文可以在任意两字之间断行 → 「文献阅读」被拆成「文献阅 / 读」两行，
     顶栏因此变高、字标看起来像坏掉（实测 390px 必现）。字标是固定品牌名，
     不该换行：nowrap + 不参与压缩；真放不下时 .topbar 的 flex-wrap 会整块换行，
     而不是把品牌名拆开。 */
  white-space: nowrap;
  flex-shrink: 0;
  /* 2026-10-24：按要求去掉 color/transform 过渡 —— 左上角图标与标题不做动画，
     hover 只有瞬时的颜色反馈。 */
}
.brand .brand-icon {
  width: 1.15em;
  height: 1.15em;
  margin-right: 0.42em;
  /* audit-2026-10-23：原 5px 是未登记的半档字面值（不在文件头豁免清单），归到最近刻度 */
  border-radius: var(--radius-sm);
  object-fit: cover;
  flex-shrink: 0;
  display: block;
}
/* 顶栏 brand logo 鼠标悬浮：只做瞬时颜色加深，不上浮、不过渡
   （2026-10-24 起 brand-logo 全站统一为 <a class="logo">；a.logo 选择器保留，
   与泛 .logo 一并覆盖历史渲染/缓存页两种形态。同日按用户要求移除
   translateY(-1px) 上浮与 transition —— 图标和标题保持静止） */
.brand a.logo:hover,
.brand .logo:hover {
  color: var(--accent-deep);
  text-decoration: none;
}
/* 刊名带（2026-10-23 顶部统一改版）：全站页头的第二行，与顶栏同一视觉语言
   （bg-elev + 底部细线 + --space-6 左内边距，与「文献阅读」字标同列）。
   每日页在其下还有 .daily-banner 日期行（同款底色与分隔线），两行共同构成
   「刊头」块；视图页到此为止，正文从 .layout 开始。
   视图页标记在 src/index.html，每日页由 topbar_tpl.render_page_heading 生成，
   两处同构；文案只按期刊（版别），视图用途由正文 content-header h1 表达。 */
.page-heading {
  padding: var(--space-2) var(--space-6);
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
}
.page-heading .title {
  font-family: var(--font-serif);
  font-size: var(--text-md);
  color: var(--ink-soft);
  font-style: italic;
  line-height: var(--leading-none);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: block;
}

/* 期刊切换：纯文字，与首页 section 标题同款；按钮之间用 · 分隔 */
.journal-switch {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  /* 极窄屏下容器宽度紧张：禁止按钮折行，让容器可整体水平滚动或溢出 */
  white-space: nowrap;
  min-width: 0;
}
.journal-switch .journal-btn {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.06em;
  border: 1px solid transparent;
  background: transparent;
  /* 2026-10-24：期刊切换是分段控件（segmented control），胶囊外形让
     active 的 accent-soft 底读起来像"被选中的一段"，比 4px 方角更现代。
     横向 padding 维持 --space-2 不加宽——1024-1200px 顶栏压缩区有
     overflow 扫描测试（bug6），按钮加宽会吃掉压缩余量。 */
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  cursor: pointer;
  transition: background-color var(--dur-base) ease, color var(--dur-base) ease, border-color var(--dur-base) ease;
  /* 防止 320px 顶栏里 "PRL / PRB / arXiv" 被折成两行 */
  white-space: nowrap;
  flex-shrink: 0;
}
.journal-switch .journal-btn:hover {
  color: var(--ink);
  background: var(--bg-hover);
}
/* iter 114 Phase 3：补 :active 按下反馈 */
.journal-switch .journal-btn:active:not(:disabled) {
  transform: scale(0.97);
  transition: transform var(--dur-fast);
}
.journal-switch .journal-btn.active {
  color: var(--ink);
  background: var(--accent-soft);
  border-color: var(--border);
}
/* iter 114 Phase 3 修复：之前用 var(--bg-hover) 会把 active 的 accent-soft 抹平，
   让 hover 后视觉反而比静止态更弱（不合用户预期）。改为加深到 --accent-soft
   的 hover 态，与 .tab-btn.active:hover 保持一致。 */
.journal-switch .journal-btn.active:hover {
  background: color-mix(in srgb, var(--accent-soft) 70%, var(--accent) 30%);
  border-color: var(--accent);
}


.topbar-actions {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-left: auto;
  min-width: 0;
}

/* iter 114 Phase 4：主导航地标（首页 + 期刊切换）
   与 .topbar 同级，靠 flex gap 自然间距，不额外加 padding/margin。 */
.topbar-nav {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

/* iter 114 Phase 4：视图导航（浏览/搜索/收藏/已读）。外层 <nav> 不渲染样式，
   内层 <div role="tablist"> 承接原本 .view-tabs 的 flex 排版。 */
.view-tabs { display: flex; align-items: center; min-width: 0; }
.view-tabs > [role="tablist"] { display: flex; align-items: center; gap: var(--space-1); }

/* iter 114 Phase 4：<search> 是 HTML5 语义元素，默认 display: block，
   需要显式声明 flex 才能保持原有 inline 图标 + input + kbd 的横向排版。 */
search.global-search { display: flex; align-items: center; }

/* 跳到正文链接（a11y）：默认藏到屏幕外，focus 时落到左上角。
   fix audit-2026-10-22 LOW：absolute → fixed。absolute 的 top:12px 相对文档原点，
   页面滚动后 Shift+Tab 回到 skip-link 时它落在视口外（焦点到了但看不见）；
   fixed 让它始终贴视口左上角。 */
.skip-link {
  position: fixed;
  left: -9999px;
  top: 0;
  /* iter 113 audit H3: 原 z-index: 999 高过 modal-backdrop (300)，modal
     打开时按 Tab 触发 skip-link 会在弹窗上面浮现一个小色块。降到 --z-skip-link 50
     让 skip-link 仍在正文/顶栏之上，但低于所有弹窗 / loading / toast。
     iter 114 Phase 1：使用 --z-skip-link token 化。 */
  z-index: var(--z-skip-link);
  padding: var(--space-2) var(--space-3);
  /* fix audit 2026-10-25 组82：WCAG 2.5.5 —— skip-link 是键盘用户第一落点，
     原 padding+行高约 30px 高；拉到 44px 命中高度（flex 让文案垂直居中，
     视觉尺寸变化仅出现在 focus 态）。 */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  background: var(--accent);
  color: var(--bg-elev);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  text-decoration: none;
}
.skip-link:focus,
.skip-link:focus-visible {
  left: var(--space-3);
  top: var(--space-3);
  outline: 2px solid var(--accent-deep);
  outline-offset: 2px;
}

/* iter 114 Phase 4：第二跳过链接（侧栏抽屉），focus 时落在 skip-link 下方。
   不与 .skip-link 重叠；视觉风格复用一套变量，仅偏移 top。
   必须放在 .skip-link:focus 之后（同特异性 0,2,0，源码顺序决定胜负），
   否则 top:44px 被上面的 top:12px 覆盖永不生效。 */
.skip-link--sidebar:focus,
.skip-link--sidebar:focus-visible {
  top: 44px;
}

/* 抽屉式侧栏触发器（仅窄屏显示） */
/* 2026-10-24：顶栏纯图标控件（抽屉开关 / 主题——组83 起「面板切换」退役）与详情面板关闭
   按钮统一正圆 —— 正方形小图标按钮是"工具栏时代"的语言，圆形是当下
   图标控件的通行形状（.radius-pill 在等宽高下即正圆）。 */
.sidebar-toggle {
  display: none;
  width: 36px; height: 36px;
  align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); /* 组82：控件边框 1.4.11（见 --border-strong 注释） */
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  background: var(--bg-elev);
  flex-shrink: 0;
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.sidebar-toggle:hover {
  background: var(--bg-hover);
  color: var(--ink);
  border-color: var(--accent);
}
/* iter 114 Phase 3：补 :active 按下反馈 */
.sidebar-toggle:active {
  background: var(--bg-hover);
  transform: scale(0.95);
  transition: transform var(--dur-fast);
}
.sidebar-toggle .bars {
  display: inline-flex; flex-direction: column;
  gap: var(--space-1); width: 16px;
}
.sidebar-toggle .bars span {
  display: block; height: 2px;
  background: currentColor; border-radius: 1px;
  transition: transform var(--dur-base), opacity var(--dur-base);
}

/* 抽屉侧栏遮罩 */
.sidebar-overlay {
  display: none;
  position: fixed; inset: 0;
  background: var(--overlay-strong);
  z-index: var(--z-sidebar);
  opacity: 0;
  pointer-events: none; /* 关闭时不能吃页面点击 */
  transition: opacity var(--dur-base) ease;
}
.sidebar-overlay.visible {
  opacity: 1;
  pointer-events: auto;
}

.global-search {
  display: flex;
  align-items: center;
  margin-right: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0 var(--space-3);
  background: var(--bg-soft);
  width: 300px;
  max-width: 100%;
  /* 在 1024-1279px 顶栏拥挤时让搜索框优先被压缩，避免把 theme-picker 挤出去。
     min-width: 0 是 flex 容器可压缩的内联尺寸前提。 */
  min-width: 0;
  flex-shrink: 1;
  transition: border-color var(--dur-fast), background var(--dur-fast), box-shadow var(--dur-fast), width var(--dur-base);
}
.global-search:focus-within {
  background: var(--bg-elev);
  border-color: var(--accent);
  /* WCAG 2.2 SC 1.4.11（非文本对比度 ≥3:1）——fix audit-2026-10-06 HIGH-2。
     原实现是 `box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent)`，
     看着像"柔和外发光"，实测 9 套主题下它与相邻色的对比度只有 **1.26–1.43:1**，
     9 套主题**全部**不达标。而且 base 层对文本类输入框显式 `outline: none`
     （style.css 的 `input:not([type=checkbox]):not([type=radio]):focus-visible`），
     真正获得焦点的是内部 input，所以这道外发光是该控件**唯一**的焦点指示，
     没有第二个提示兜底 —— 低对比度等于没有焦点指示。
     改为与全站 `:focus-visible` 完全一致的 3px 实色 accent 环（同样的
     outline + outline-offset: 2px），实测 9 主题 4.93–11.20:1 全部达标。
     仍用 :focus-within 而非 :has(:focus-visible)：后者的浏览器下限是
     Firefox 121，低于本项目 Firefox 117+ 的支持矩阵。 */
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
.global-search input {
  flex: 1; border: none; outline: none; background: transparent;
  padding: var(--space-2) 0; font: inherit; font-size: var(--text-md); color: var(--ink); min-width: 0;
}
.global-search input::placeholder { color: var(--ink-mute); }
/* .icon 现在是 <button>（折叠态下唯一可点的"打开搜索"控件），去掉按钮默认外观，
   视觉尺寸与原 <span aria-hidden> 版本保持完全一致。 */
.global-search .icon {
  color: var(--ink-mute); font-size: var(--text-md); margin: 0 var(--space-2) 0 0;
  background: none; border: 0; padding: 0; font-family: inherit; line-height: var(--leading-none);
  cursor: pointer; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.global-search .icon:hover { color: var(--ink-soft); }
/* 宽屏（>768px）输入框本来就可见，图标只是装饰：点输入框任意位置都能聚焦，
   给这个 8px 宽的字形挂一个可点语义只会制造一个极小的命中区（实测 w=8×h=22）。
   这里让它不吃指针事件，语义与视觉一致；折叠态（≤768px）才是它真正当按钮用
   的地方，那里由下面的 .search-open 规则接管。 */
@media (min-width: 769px) {
  .global-search .icon.search-open { pointer-events: none; cursor: default; }
}
.global-search kbd {
  font-family: var(--font-mono); font-size: var(--text-2xs);
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 1px 5px; color: var(--ink-mute); margin-left: 6px;
}

.tab-btn {
  padding: 7px var(--space-3);
  min-height: 34px;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  /* 组108：「卡片阅读」入口让 .tab-btn 首次穿在 <a> 上——base 层
     a:hover { text-decoration: underline } 会命中它；components 层声明
     压过 base 层（层序），显式关下划线（.home-reader-cta 同款口径）。
     纯按钮页面此属性无对象，零视觉波及。 */
  text-decoration: none;
  /* 2026-10-24：顶栏导航（首页 / 搜索 / 收藏 / 已读）统一胶囊形，
     active 的实心 accent 块由"方块印章"变"胶囊标签"，与期刊分段控件同语汇。 */
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  transition: background-color var(--dur-base) ease, color var(--dur-base) ease, border-color var(--dur-base) ease;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* 防止 view-tab 在 1024-1279px 顶栏被挤压时文字换行成"浏/览"竖排 */
  white-space: nowrap;
  flex-shrink: 0;
}
.tab-btn:hover { background: var(--bg-hover); color: var(--ink); }
/* iter 114 Phase 3：补 :active 按下反馈（之前只有 hover，键盘 / 触屏用户缺触感反馈） */
.tab-btn:active:not(:disabled) { transform: scale(0.97); transition: transform var(--dur-fast); }
/* active + hover 同时命中时不能回退到普通 hover 态（否则激活标签看起来像没激活）。
   用更深的 accent-deep 表达"激活状态下被指针悬停"——与 .journal-btn.active:hover 一致。 */
.tab-btn.active:hover { background: var(--accent-deep); color: var(--text-on-accent); border-color: var(--accent-deep); }
.tab-btn.active {
  background: var(--accent);
  color: var(--text-on-accent);
  border-color: var(--accent);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--accent-deep) 60%, transparent);
}
/* 仅深色主题需要把 active Tab 文字改成深色（浅色 accent 上白字更清楚）
   mist/sage/dune 是浅色主题 + 深色 accent——文字保持白色 */
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .tab-btn.active,
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .tab-btn.active:hover { color: var(--text-on-light-accent); }

/* 主题切换（下拉选择器） */
.theme-picker {
  position: relative;
  margin-left: var(--space-1);
}
.theme-toggle {
  /* position: relative 保留：触屏命中区扩展的透明 ::before（见文件尾
     .theme-toggle::before 列表）仍需锚在本按钮上。 */
  position: relative;
  width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  /* 组96（2026-10-25）：边框整体撤掉（含 2026-10-24 正圆化、组82 控件边框
     对本按钮的覆盖）——裸图标最低调；圆角仅服务 hover 底色形状。 */
  border: none;
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  font-size: var(--text-lg);
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.theme-toggle:hover {
  background: var(--bg-hover); /* 组96：border-color 变线随边框退役 */
  color: var(--ink);
}
/* iter 114 Phase 3：补 :active 按下反馈（小图标按钮 scale 稍大） */
.theme-toggle:active {
  background: var(--bg-hover);
  transform: scale(0.92);
  transition: transform var(--dur-fast);
}
/* 组96（2026-10-25）：右下角主题色角标（.theme-toggle::after 8px 圆点）退役——
   它是 ◐ 字符时代的「当前主题指示器」；调色板图标语义自足，菜单里选中项
   也有勾选态，按钮上再叠一颗彩点纯属重复。 --swatch-accent 变量族保留
   （主题菜单 .theme-option .swatch 预览点仍在使用）。 */

.theme-menu {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  min-width: 200px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: var(--z-popover);
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* audit-2026-10-24 自适应第二轮：横屏矮视口（812×375 / 667×375 / 844×390）
     实测菜单整块 372px 高，向下弹出后 bottom=427~475 超视口底且
     overflowY:visible → 末尾几个主题选项不可见不可点。135px 预留 =
     最坏情况顶栏两行(~103) + 弹出偏移 8 + 底部呼吸 24。桌面/竖屏手机
     视口高 ≥844 → calc 值远大于内容高，不产生裁剪；headless dvh==vh，
     基线零影响。overflow-y:auto 让矮视口下菜单自身可滚动到全部选项。 */
  max-height: calc(100vh - 135px);
  max-height: calc(100dvh - 135px);
  overflow-y: auto;
  overscroll-behavior: contain;
  animation: themeMenuIn var(--dur-fast) ease;
}
@keyframes themeMenuIn {
  from { opacity: 0; transform: translateY(-4px); }
}

/* fix audit-2026-10-23 HIGH：主题块选择器 [data-theme="x"] 是属性选择器，会命中
   **自带 data-theme 属性的 .theme-option 本身**（HTML 里每个选项都带
   data-theme="dark" 等）——9 个主题块的整套 custom property 直接落在对应选项上，
   color: var(--ink-soft) 拿到的是**目标主题**的 ink-soft，而不是当前页面主题的。
   实测（Playwright + CDP matched rules）：
   - 期刊白页面打开菜单：暖墨/深空/夜苔 3 个选项文字是目标主题的亮色（oklch 75%），
     压白底 2.1:1，肉眼发灰几乎不可读；
   - 暖墨页面打开菜单：反过来 6 个浅色主题选项是深字压深底 1.5~1.9:1。
   修复：每个选项从父元素 inherit 这几个文字相关变量——父链（topbar-actions 等）
   没有任何元素被主题块命中，inherit 拿到的就是**当前页面主题**的值，
   与菜单底色（同样是页面主题的 bg-elev）天然配对。9 主题全组合实算 ≥7.4:1。
   只重置 .theme-option 引用到的 7 个变量（含 hover/active/check/swatch-border），
   色块预览用的 --swatch-bg/--swatch-accent 是元素级 inline 定义，不受影响。 */
.theme-option {
  --ink: inherit;
  --ink-soft: inherit;
  --bg-hover: inherit;
  --accent: inherit;
  --accent-soft: inherit;
  --accent-deep: inherit;
  --border: inherit;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--ink-soft);
  text-align: left;
  width: 100%;
  transition: background var(--dur-fast), color var(--dur-fast);
  font-family: var(--font-sans);
}
.theme-option:hover { background: var(--bg-hover); color: var(--ink); }
.theme-option:focus-visible {
  background: var(--bg-hover); color: var(--ink);
  /* 用 2px 而非 -2px 偏移：负偏移会把环画在元素内，对带 border-radius 的
     小元素会与圆角剪切贴边；正偏移留出 2px 间隙更清晰 */
  outline: 3px solid var(--accent); outline-offset: 2px;
}
.theme-option:active { transform: scale(0.98); }
.theme-option.active {
  background: var(--accent-soft);
  color: var(--accent-deep);
  font-weight: 600;
}
.theme-option .swatch {
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 1px solid var(--border);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
}
.theme-option .swatch::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--swatch-bg, oklch(100% 0 0));
}
.theme-option .swatch::after {
  content: "";
  position: absolute;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--swatch-accent, var(--accent));
  z-index: var(--z-base);
}
.theme-option .check {
  margin-left: auto;
  color: var(--accent);
  font-size: var(--text-md);
  opacity: 0;
}
.theme-option.active .check { opacity: 1; }

/* =========================================================================
   主体布局
   ========================================================================= */
.layout {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  min-height: calc(100vh - var(--topbar-h, 60px));
}

.sidebar {
  border-right: 1px solid var(--border);
  background: var(--bg-elev);
  overflow-y: auto;
  /* audit-2026-10-22 LOW：sticky 偏移统一走 --topbar-h（窄屏块早已用变量），
     顶栏变两行布局（高度 >60px）时侧栏不再被顶栏压住一截 */
  max-height: calc(100vh - var(--topbar-h, 60px));
  position: sticky;
  top: var(--topbar-h, 60px);
  padding-bottom: var(--space-6);
  transition: background var(--dur-base) ease, border-color var(--dur-base) ease,
              transform var(--dur-slow) var(--ease-std-out);
}

.sidebar-header {
  padding: var(--space-4) var(--space-5) var(--space-2);
  font-family: var(--font-serif);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-mute);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.sidebar-header .count {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-mute);
}

.sidebar-month {
  padding: var(--space-3) var(--space-5) var(--space-1);
  font-family: var(--font-serif);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-soft);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  position: sticky;
  top: 0;
  background: linear-gradient(var(--bg-elev) 75%, transparent);
}
.sidebar-month .month-total {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: 400;
  color: var(--ink-mute);
  text-transform: none;
  letter-spacing: 0;
}

.date-list { list-style: none; margin: 0; padding: 0; }
.date-item {
  /* 布局/交互样式（flex、padding、cursor）在 .date-item-btn 上——a11y 2026-10-23：
     li 回归纯 listitem（axe list 规则），交互由内嵌 <button> 承担。
     li 保留状态视觉（active 左边条 / hover 底色 / 文字色），hover 穿透到子级
     button 时 li 自身 :hover 同样命中，视觉与旧版逐像素一致。 */
  border-left: 2px solid transparent;
  color: var(--ink-soft);
  font-size: var(--text-sm);
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
  margin: 1px 0;
}
.date-item-btn {
  display: flex; justify-content: space-between; align-items: center;
  width: 100%;
  padding: 7px var(--space-5) 7px var(--space-6);
  background: none; border: 0;
  font: inherit; color: inherit; text-align: left;
  cursor: pointer;
}
.date-item:hover { background: var(--bg-hover); color: var(--ink); }
.date-item.active {
  background: var(--accent-soft);
  color: var(--accent-deep);
  border-left-color: var(--accent);
  font-weight: 600;
}
.date-item .day-label { font-family: var(--font-serif); display: flex; align-items: baseline; gap: 6px; flex: 1; min-width: 0; }
.date-item .day-num { font-variant-numeric: tabular-nums; font-weight: 500; min-width: 26px; flex-shrink: 0; }
.date-item .day-week { font-size: var(--text-2xs); color: var(--ink-mute); font-weight: 400; flex-shrink: 0; }
.date-item.active .day-week { color: var(--accent); }
.date-item .article-count {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  color: var(--ink-soft); /* iter 113 audit C1: ink-mute on bg-soft 普遍 < 4.5 (WCAG AA)，改 --ink-soft */
  font-variant-numeric: tabular-nums;
  background: var(--bg-soft);
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  flex-shrink: 0;
  margin-left: 6px;
}
.date-item.active .article-count { background: var(--accent); color: var(--text-on-accent); }
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .date-item.active .article-count { color: var(--text-on-light-accent); }
.date-item .today-dot {
  display: inline-block; width: 5px; height: 5px;
  background: var(--accent); border-radius: 50%; margin-left: var(--space-1);
  flex-shrink: 0;
}
/* audit-2026-10-23：原 .date-item.archived / .archived-arrow 5 条规则已删——
   「窗口外日期双轨」（windowed 模式 + ↗ 跳转一等公民化前）于 2026-10-22 退役，
   browse.js 从不生成 archived class，test_daily_routing / test_audit_fixes 还
   在反向断言其不存在（n_archived == 0）。规则永不匹配，属已退役机制残留。 */

.filter-form {
  padding: var(--space-3) var(--space-5);
  display: flex; flex-direction: column; gap: var(--space-3);
}
.filter-form label {
  font-size: var(--text-2xs); color: var(--ink-mute);
  letter-spacing: 0.06em; text-transform: uppercase; font-weight: 600;
}
.filter-form input[type="text"],
.filter-form input[type="date"] {
  font: inherit; font-size: var(--text-sm);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-strong); /* 组82：控件边框 1.4.11（见 --border-strong 注释） */
  border-radius: var(--radius-sm);
  background: var(--bg-soft);
  color: var(--ink);
  outline: none; width: 100%;
  transition: border-color var(--dur-fast), background var(--dur-fast);
  /* 触控目标 ≥36px */
  min-height: 38px;
}
.filter-form input:focus { border-color: var(--accent); background: var(--bg-elev); }
/* audit-2026-10-22 MED：base 层杀掉了文本输入框的 outline（691 行），这里的
   焦点指示此前只有 1px border 变色——正是 global-search 在 audit HIGH-2 修过
   的同款问题（低对比 = 没有焦点指示，WCAG 2.2 SC 1.4.11）。补同款 3px 实色
   accent 环；用 :focus-visible 避免鼠标点击也出环。 */
.filter-form input:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 1px;
}
/* iter 114 Phase 3：filter form 缺 :disabled 视觉（浏览器对 <input> 默认无样式）。
   [已删 · audit-2026-10-22] select:disabled 分支：全项目无 <select> 元素。 */
.filter-form input:disabled {
  cursor: not-allowed;
  opacity: 0.5;
  background: var(--bg-soft);
  color: var(--ink-mute);
}
.filter-form input:disabled:hover {
  border-color: var(--border-strong); /* 组82：与 base 边框同步（此行是「hover 不改回 accent」的复位声明） */
  background: var(--bg-soft);
}
.filter-form .checkbox-row {
  display: flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-sm); color: var(--ink-soft);
  text-transform: none; letter-spacing: 0; font-weight: 400;
  cursor: pointer;
  /* 触控目标 ≥38px：checkbox 视觉 13px，但整个 label-row 是 44px，点击区域足够 */
  padding: var(--space-2) 0;
  min-height: 44px;
}
.filter-form .checkbox-row input { margin: 0; }
.filter-form .date-pair { display: flex; gap: 6px; }
.filter-form .date-pair input { flex: 1; min-width: 0; }
.filter-form input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(0.4);
}

/* =========================================================================
   arxiv 主分类筛选 chips 条
   - 在 arxiv 主页（日期网格）和 arxiv 每日页（文章列表）顶部共用
   - 多选 OR 关系，点 chip 切换 in/out；点「全部」清空
   ========================================================================= */
.arxiv-cat-strip {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border-soft);
  align-items: center;
}
.arxiv-cat-strip-label {
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin-right: 6px;
  user-select: none;
}
.arxiv-cat-chip {
  display: inline-flex; align-items: center; gap: 6px;
  /* audit-2026-10-24：chip 内的 .sr-only（量词「 篇」）是 position:absolute。
     chip 若保持 static，sr-only 的定位上下文一路逃到 body/ICB——**不受本 chip 行
     （overflow-x:auto 滚动容器）裁剪**，其 1px 盒子直接计入 documentElement
     scrollWidth：≤720px 单行滚动形态下 19 个 chip 把整页撑出 ~1650px 幽灵横向
     滚动（空白可平移区 + 底部整页滚动条，chrome 实测 scrollWidth 2021）。
     加 relative 把 sr-only 收进 chip 的裁剪链，幽灵滚动归零、chip 行自身滚动不变。 */
  position: relative;
  padding: 7px var(--space-3);
  font: inherit; font-size: var(--text-xs); line-height: var(--leading-heading);
  /* 2026-10-24：chip 从"描边白盒"改"柔和填充"——19 个分类一排全部带边框时
     边框线互相竞争、视觉噪音大；无边框软底（bg-soft）让 chips 读作一组标签，
     选中态（accent-soft + accent 边框）反而更突出。border 仍占 1px 透明位，
     hover/active 换边框色时盒宽不变、不抖动。 */
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--bg-soft);
  color: var(--ink-soft);
  cursor: pointer;
  transition: background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast);
  user-select: none;
  white-space: nowrap;
  /* 触控目标 ≥32px：原 5px padding ≈ 28px，移动端容易误触 */
  min-height: 32px;
}
.arxiv-cat-chip:hover {
  background: var(--bg-hover);
  border-color: var(--accent);
  color: var(--ink);
}
.arxiv-cat-chip.active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-deep);
  font-weight: 600;
}
.arxiv-cat-chip.all-chip { font-weight: 600; }
.arxiv-cat-chip-count {
  display: inline-block;
  font-size: var(--text-2xs);
  font-weight: 500;
  /* 用 ink-soft 而非 ink-mute：暗色主题 mute 略低于 WCAG AA 4.5。
     2026-10-24：chip 本体改成 bg-soft 软底后，计数角标与之反相——
     由 bg-soft 改画 bg-elev（"浅窗嵌在软底里"），所有 9 主题
     ink-soft / bg-elev ≥ 4.5 成立（与卡片正文同一色对）。 */
  color: var(--ink-soft);
  background: var(--bg-elev);
  border-radius: var(--radius-pill);
  padding: 1px 7px;
  margin-left: 1px;
}
.arxiv-cat-chip.active .arxiv-cat-chip-count {
  background: var(--bg-elev);
  color: var(--accent-deep);
}
/* 暗色主题：active chip 浅底 + 深字依然可读，但 background-soft 角标偏暗需要微调 */
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .arxiv-cat-chip-count {
  background: var(--tint-soft);
  color: var(--ink-soft);
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .arxiv-cat-chip.active .arxiv-cat-chip-count {
  background: var(--overlay-press);
  color: var(--ink);
}
/* 移动端：缩 padding + 字号，chips 改横向单行滚动。
   19 个主分类在 390px 宽下换行会占 7 行（约 500px），把当日文章全挤到
   折叠线以下。改成单行横向滚动（标签筛选的常规形态），chips 带高度
   从 ~500px 降到一行 ~40px。右侧渐隐提示"还能往右滑"。 */
@media (max-width: 720px) {
  .arxiv-cat-strip {
    padding: 10px 14px;
    gap: 6px;
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* 右侧渐隐：末位 chip 不贴边，同时暗示还有可滑内容 */
    mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent);
  }
  .arxiv-cat-strip::-webkit-scrollbar { display: none; }
  .arxiv-cat-strip-label { display: none; } /* 标签占空间，窄屏隐藏 */
  .arxiv-cat-chip {
    font-size: var(--text-2xs);
    padding: var(--space-1) 9px;
    flex: 0 0 auto;   /* 不参与压缩，否则 chip 会被挤扁 */
  }
  .arxiv-cat-chip-count { font-size: var(--text-2xs); padding: 1px 5px; }
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .filter-form input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(0.7);
}

.filter-tip {
  padding: var(--space-3) var(--space-5) var(--space-4);
  font-size: var(--text-xs);
  /* iter 114 Phase 3 修复：var(--ink-mute) 在 paper 主题下对 --bg-elev 对比度 ≈ 3.4:1，
     不达 WCAG AA 4.5:1。改为 --ink-soft（paper 5a4220 vs f3e9c8 ≈ 7.2:1 通过）。 */
  color: var(--ink-soft);
  line-height: var(--leading-relaxed);
  border-top: 1px solid var(--border-soft);
}
.filter-tip kbd {
  font-family: var(--font-mono); font-size: var(--text-2xs);
  background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 0 var(--space-1); color: var(--ink-soft);
}

.collection-list { list-style: none; margin: 0; padding: 0; }
.collection-item {
  padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--border-soft);
  cursor: pointer; font-size: var(--text-sm); transition: background var(--dur-fast);
}
.collection-item:hover { background: var(--bg-hover); }
.collection-item:focus-visible {
  background: var(--bg-hover);
  outline: 3px solid var(--accent); outline-offset: 2px;
}
.collection-item .ci-title {
  color: var(--ink); font-family: var(--font-serif);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; line-height: var(--leading-heading); margin-bottom: var(--space-1);
}
.collection-item .ci-meta {
  color: var(--ink-mute); font-size: var(--text-2xs); font-family: var(--font-mono);
  display: flex; align-items: center; gap: 6px;
}
.collection-item .ci-meta .unread-dot {
  display: inline-block; width: 5px; height: 5px;
  background: var(--accent); border-radius: 50%;
}

/* =========================================================================
   内容区
   ========================================================================= */
.content {
  padding: var(--space-7) var(--space-8) var(--space-11);
  min-width: 0;
  /* 可读行长上限。实测（Playwright，1280 视口、详情面板收起）：
       .layout  = 260px | 1020px | 0px
       .content = 1020px → 卡片 940px → 14px 摘要单行约 130 字符
     超过 ~80 字符后，每次换行都变成寻找下一行的干扰源，行尾参差急剧恶化——
     这是排版里最一致的一条经验规则（45~75 字符，理想 ~66）。
     修后 .content 638px / 卡片 558px / 约 80 字符，多出来的空间变成左右对称的页边距。
     面板展开时列本来就窄，封顶自然不生效。

     width:100% 不能省：.content 是 grid item，只写 margin-inline:auto 会让
     justify-self 从 stretch 退化成 fit-content，盒子改由 max-content 决定宽度。
     320px 视口下 max-content 里的 nowrap 标题（h1 + .kb-hint 都带 nowrap）
     撑到 548px，实测横向溢出 228px。写死 width:100% 后，used width =
     min(100%, max-width)，auto margin 只负责居中已封顶的盒子。 */
  width: 100%;
  max-width: calc(var(--measure) + 2 * var(--space-8));
  margin-inline: auto;
}
/* 首页是三栏并排的扫读布局（.home-grid repeat(3, 1fr)），不是单列阅读栏 ——
   套上行长上限会把三栏挤成三条窄缝，首页操作行直接被卡片裁掉。 */
body[data-page="home"] .content { max-width: none; }
/* fix audit 2026-10-25 组82：首页抽屉控件是死控件——renderHomePage 把 #sidebar
   置空并 hidden=true（首页没有日期导航可放），窄屏的抽屉开关与「跳到侧栏」
   跳过链接点开后只有一面空墙；app.js:openSidebar 已对空抽屉静默 return（组82），
   JS 不再响应，这里把 affordance 与 tab 停靠点一并撤掉（display:none 移出焦点序）。
   单源依据：body[data-page] 由服务端模板写死、router._syncChrome 软导航镜像同步
   （组66 ①），冷启动/软导航一致，CSS-only 无需扩镜像面。
   特异性 0,2,1 > ≤1024 媒体块 .sidebar-toggle{display:inline-flex} 的 0,1,0。 */
body[data-page="home"] .sidebar-toggle,
body[data-page="home"] .skip-link--sidebar { display: none; }

/* ---- 四个列表视图（browse / search / favorites / read）：宽屏铺满 ---------
   上面的行长上限（--measure ≈ 68ch → 638px）是给「连续阅读的散文栏」设计的。
   这四个视图是卡片列表：卡片是块状条目（标题 / 作者 / 摘要 / 操作行），不是
   段落。1280+ 屏上中间列可达 1300px+，套 638px 上限的结果是页面右侧留出
   一大片空白、整页只有中间一条窄缝——看起来像「没做完」，而不是阅读排版。

   这里做两件事：
   ① 放开 .content 的行长上限（仅 ≥1024px：窄屏仍是单列阅读栏，别放开）；
   ② .article-list 由单列 flex 换成自适应多列 grid（每列 ≥420px 才起新列），
      宽度被卡片列宽吃掉，行长仍由列宽控制，不会退化成一行 130 字符的长条。

   选择器用 body[data-view]：data-page 只在 per-view HTML 上注入
   （浏览页 HTML 故意不带 data-page，见 build_pages.inject_body_data_page），
   data-view 由 JS 从 state.view 同步（app.js _syncBodyDataset），
   四个视图 + 每日页都能准确命中；首页走自己的 .home-grid 三栏，不在此列。 */
@media (min-width: 1024px) {
  body[data-view="browse"] .content,
  body[data-view="search"] .content,
  body[data-view="favorites"] .content,
  body[data-view="read"] .content { max-width: none; }
}
body[data-view="browse"] .article-list,
body[data-view="search"] .article-list,
body[data-view="favorites"] .article-list,
body[data-view="read"] .article-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr));
  gap: 14px;
  align-items: start;
}

/* fix audit-2026-10-25 组89：「关于」页正文被外层散文行长帽误伤。
   上面 .content 的 max-width ≈ 68ch + 2*--space-8 ≈ 718px 是给「连续阅读的
   散文栏」设计的；.about-page 自限的 720px 正好被这顶帽子压成死值——宽屏上
   关于页实际永远只有 ~718px，右侧留大片空白。about 不是散文单栏：短导语 +
   特性列表 + 步骤 + 快捷键表 + dl 双列的混合内容，正文档位应由 .about-page
   自己的 max-width 控制。这里只在 ≥1024px 摘掉 .content 的帽子（与组82 四
   列表视图宽屏铺满同理），窄屏不放开——手机/平板仍是单列阅读栏。
   选择器用 body[data-page="about"]：about 是独立视图页（整页加载，组85 根级
   化），data-page 由 build_pages 构建期静态写入，冷启动首帧即命中，不依赖
   JS 的 _syncBodyDataset 时序。 */
@media (min-width: 1024px) {
  body[data-page="about"] .content { max-width: none; }
}
/* fix iter 108（audit MAJOR M7）：skip-link target #content 加 tabindex=-1 后可以接收
   焦点，但 section 不是真正的可交互元素，不应显示 focus 环。focus-visible 限定为键盘
   focus，鼠标点进来不显示。 */
.content:focus { outline: none; }
.content:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: -2px; }

/* audit-2026-10-23：#sidebar 也加了 tabindex=-1（skip-link「跳到侧栏」需要
   焦点能落进去，否则只滚动不换焦点，对键盘/读屏用户等于没跳）。焦点环规则
   与 #content 保持一致：鼠标点击不显示，键盘 focus-visible 才显示。 */
.sidebar:focus { outline: none; }
.sidebar:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: -2px; }

/* =========================================================================
   右侧详情面板（宽屏 ≥1280px）
   组83：面板显隐纯由文章开关驱动——点文章 openDetail 展开，
   关闭（× / Esc / 软导航页首复位）即收起并清空（detail-hidden）。
   welcome 态（统计 / 快捷键 / 最近阅读）与顶栏「面板切换」按钮（含
   prl.paneHidden.v1 持久化）已退役；介绍类内容由「关于」视图页承接。
   ========================================================================= */
.detail-pane {
  display: none;
}

@media (min-width: 1280px) {
  .layout {
    grid-template-columns: 260px minmax(0, 1fr) 400px;
    transition: grid-template-columns var(--dur-slow) var(--ease-std-out);
  }
  @media (prefers-reduced-motion: reduce) {
    .layout { transition: none; }
  }
  .detail-pane {
    /* 面板改成 flex 列：顶部一条 chrome 行（.detail-pane-head，右上角关闭按钮）
       + 下方独立滚动区（.detail-pane-inner）。滚动区从 .detail-pane 挪进 inner
       之后，关闭按钮常驻面板右上角，不再随正文滚走。 */
    display: flex;
    flex-direction: column;
    position: sticky;
    /* audit-2026-10-22 LOW：同侧栏规则，sticky 偏移走 --topbar-h 变量。
       注意：注释里别写"点+sidebar"的选择器形式——test_audit_fixes #27.1 的
       块扫描正则会从注释文本误匹配到下一个 {，多算一个侧栏块。 */
    top: var(--topbar-h, 60px);
    align-self: start;
    max-height: calc(100vh - var(--topbar-h, 60px));
    background: var(--bg-elev);
    border-left: 1px solid var(--border);
    padding: var(--space-4) var(--space-6) var(--space-8);
    transition: opacity var(--dur-base), padding var(--dur-base), border-color var(--dur-base);
  }
  /* chrome 行：左侧标题 + 右侧关闭按钮。整行做工具条（标题 + 控件 +
     一条细分隔线），不要只剩一个孤零零的 × 悬在空行里 —— 那样看着像
     渲染漏了左半边。分隔线让这行读起来是"面板头"，而不是正文上方的
     一段空白。 */
  .detail-pane-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    min-height: 32px;
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--border-soft);
  }
  .dp-pane-title {
    font-family: var(--font-sans);
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    color: var(--ink-mute);
    white-space: nowrap;
  }
  .detail-pane-inner {
    flex: 1 1 auto;
    /* min-height:0：flex 子项默认 min-height:auto，不置 0 的话 inner 会被内容
       撑到自然高度、溢出 max-height 而不是自己滚动 */
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    /* 隐藏滚动条但保留滚动能力（不挡视觉） */
    scrollbar-gutter: stable;
    opacity: 1;
    transition: opacity var(--dur-fast);
  }
  .detail-pane-inner::-webkit-scrollbar { width: 8px; }
  .detail-pane-inner::-webkit-scrollbar-track { background: transparent; }
  .detail-pane-inner::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: var(--radius-pill);
    border: 1px solid transparent;
    background-clip: padding-box;
  }
  .detail-pane-inner::-webkit-scrollbar-thumb:hover { background: var(--ink-mute); }

  /* 面板被手动收起：grid 收缩、内容区铺满 */
  .layout.detail-hidden {
    grid-template-columns: 260px minmax(0, 1fr) 0;
  }
  .layout.detail-hidden .detail-pane {
    display: none;
    opacity: 0;
    padding-left: 0;
    padding-right: 0;
    border-left-color: transparent;
    pointer-events: none;
  }
  .layout.detail-hidden .detail-pane-inner { opacity: 0; }

  /* fix audit-2026-10-24 组75：首页（sidebar-hidden）展开详情面板时的列组合。
     `.layout.sidebar-hidden { grid-template-columns: 1fr; }`（文件后面）会把首页
     打成单列——面板列若可见会被挤到隐式第二行整幅铺底。这里给
     「首页 + 面板展开」单独开一列组合：内容列 + 面板列，无侧栏列。
     特指度 (0,3,0) > sidebar-hidden / detail-hidden 两条 (0,2,0)，按层叠天然胜出，
     无需 !important（同文件 Phase 2 口径）。收起态走 detail-hidden→单列不变。 */
  .layout.sidebar-hidden:not(.detail-hidden) {
    grid-template-columns: minmax(0, 1fr) 400px;
  }
}

/* 超宽屏（≥1700px）— 加大中间列与右侧面板宽度 */
@media (min-width: 1700px) {
  .layout {
    grid-template-columns: 280px minmax(0, 1fr) 440px;
  }
  .layout.detail-hidden {
    grid-template-columns: 280px minmax(0, 1fr) 0;
  }
  /* 组75：首页面板展开在超宽屏同样要两列（面板列随基线加宽到 440px） */
  .layout.sidebar-hidden:not(.detail-hidden) {
    grid-template-columns: minmax(0, 1fr) 440px;
  }
}

/* 顶栏「首页」按钮 + body[data-page="home"] 的特殊样式：
   首页不展示日期导航，所以 .layout 跳过分栏，单列填满。
   兼容性：JS 在 renderHomePage() 里给 .layout 加 .sidebar-hidden，
   不依赖任何具体 HTML 结构变化。 */
.layout.sidebar-hidden {
  /* Phase 2：移除 !important。Phase 1 引入 @layer 让 .layout 规则按层叠顺序自然 override。 */
  grid-template-columns: 1fr;
}

/* Journal logo tag (组83 起 3 处共用：.sjg-logo / .cjg-logo / .ac-journal-tag；原 .dps-logo 随 welcome 态退役)
   —— PRL/PRB 期刊缩写小徽章。背景色由 [data-journal="prl|prb"] 切换 var(--journal-prl|prb) */
.sidebar-journal-group .sjg-logo,
.content-journal-group .cjg-logo,
.ac-journal-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-weight: 600;
  border-radius: var(--radius-sm);
  color: var(--text-on-accent);
  flex-shrink: 0;
}
/* audit-2026-10-24：arxiv 徽章在 sjg/cjg 分组头曾缺 [data-journal="arxiv"] 规则——
   白字（base 的 --text-on-accent）直接落进浅色分组头，≈1.07:1 近乎不可见，
   与 10-23 修 .ac-journal-tag 的同源 bug；那轮只补了 ac-journal-tag 一处。
   按中性灰模式补齐（bg-soft + border-soft + ink-soft，9 主题 ≥4.5），比
   ac-journal-tag 的裸 bg-soft 多一圈描边，免得与卡面糊在一起。
   （组83：原三组之一 .dp-journal-stat .dps-logo 随 welcome 态退役，现剩 sjg/cjg） */
.sidebar-journal-group[data-journal="arxiv"] .sjg-logo,
.content-journal-group[data-journal="arxiv"] .cjg-logo {
  background: var(--bg-soft);
  border: 1px solid var(--border-soft);
  color: var(--ink-soft);
}

/* =========================================================================
   「关于」视图页（组83，/{j}/about.html，views/about.js renderAbout）
   - 无侧栏长文（layout.sidebar-hidden），正文宽度由 .about-page 自限
     （组89：720px → 880px，并摘除 ≥1024px 下 .content 的散文帽，见上方
     「组89 关于页宽屏档位」注释——此前 720px 被外层 ~718px 行长帽压成死值）；
   - 快捷键表沿用退役 .sh-keys 的立体键帽观感，类名换 ap-* 前缀，与面板
     文章态 dp-* 旧名划清（welcome 链样式已随组83 整删）。
   ========================================================================= */
.about-page {
  max-width: 880px;
  margin: 0 auto;
}
/* 组119：整页正文抬一档（14 → 15.28px）——站点基准 --text-md 为密集文章
   列表而设，关于页全是条目/短段落阅读内容；下级未显式声明字号的块
   （步骤 / 快捷键行 / dl）一律继承。独立成行块而非并入上方基块：104.6
   锚钉死基块整块字面量（含右花括号），追加声明须另起（热文件零扰动）。 */
.about-page {
  font-size: var(--text-lg);
}
.about-page .ap-title {
  font-family: var(--font-serif);
  font-size: var(--text-4xl);
  font-weight: 700;
  color: var(--ink);
  margin: var(--space-4) 0 var(--space-3);
}
.about-page .ap-lede {
  font-size: var(--text-xl);
  line-height: var(--leading-relaxed);
  color: var(--ink-soft);
  margin: 0;
}
/* 组126：署名从页首移到页尾作 colophon——顶部只剩 标题→导语 干净开场，
   作者信息与「数据与版本」同侧收尾（border-top 与正文分隔，书籍版权页
   惯例）。度量随位置改：原 margin space-3（紧咬导语）→ space-7（与末节
   同距）+ padding-top 让分隔线与文字呼吸。 */
.about-page .ap-author {
  margin: var(--space-7) 0 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-soft);
  font-size: var(--text-md);
  color: var(--ink-mute);
}
/* 组126：scroll-margin-top 补 `?` 定位落点——focusShortcuts 对节 scrollIntoView
   (block:start)，而顶栏 sticky 高 --topbar-h，小节标题原本藏进顶栏底下。 */
.about-page .ap-section {
  margin-top: var(--space-7);
  scroll-margin-top: calc(var(--topbar-h, 60px) + var(--space-3));
}
.about-page .ap-section h3 {
  font-family: var(--font-serif);
  font-size: var(--text-2xl);
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border-soft);
}
.about-page .ap-section h3:focus-visible {
  outline: 2px solid var(--accent-deep);
  outline-offset: 2px;
}
.about-page .ap-features {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}
/* 组119：条目卡片化——bg-soft 底 + 细描边，圆点 ::before 退役（卡片本身
   已是分组边界，再叠圆点是双重标记）；每条拆 卖点词（.ap-feat-key，加粗
   一行小标题）+ 说明（.ap-feat-desc），扫读时先读词再读句。 */
.about-page .ap-features li {
  padding: var(--space-3) var(--space-4);
  background: var(--bg-soft);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  color: var(--ink-soft);
  line-height: var(--leading-relaxed);
}
.about-page .ap-feat-key {
  display: block;
  margin-bottom: 1px;
  font-weight: 600;
  color: var(--ink);
}
.about-page .ap-steps {
  list-style: none;
  /* 组123 的双栏合并节呼吸距随组126 拆回两节退役——节间距由 .ap-section
     margin-top 统一承载 */
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}
.about-page .ap-steps li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  color: var(--ink-soft);
  line-height: var(--leading-relaxed);
}
.about-page .ap-step-num {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 组119：序号徽章随正文抬档 24 → 28px（lg 行盒 ~23.7px，徽章略高
     半眼好找步序），字号同步 --text-md */
  width: 28px;
  height: 28px;
  margin-top: 1px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent-deep);
  font-family: var(--font-mono);
  font-size: var(--text-md);
  font-weight: 700;
}
.about-page .ap-note {
  font-size: var(--text-md);
  color: var(--ink-mute);
  margin: 0 0 var(--space-3);
}
.about-page .ap-kbd-list {
  list-style: none;
  margin: 0;
  /* 组124：键位全表卡片化（与功能卡同语汇 border-soft + radius-md）——
     键位列左置后表体自成一块，不再借整行拉伸占位。
     组126：拆节撤双栏后按内容宽收拢居左（fit-content 自带 available 钳制，
     窄屏自然回 100%），卡片不再横贯整页 */
  width: fit-content;
  padding: var(--space-1) var(--space-4);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
}
.about-page .ap-kbd-row {
  display: flex;
  align-items: center;
  /* 组124：撤 justify-content: space-between——宽容器下描述被甩到最左、
     键帽到最右，中间隔上千像素（用户报「文字和快捷键分得太开」）；
     改键位列左置定宽、描述紧跟，即 GitHub/VSCode 键位表惯例 */
  gap: var(--space-4);
  /* 组119：行高随字号抬档一起加（8 → 12px 竖向呼吸），字号不再单独声明——
     继承 .about-page 的 lg（窄屏档见文末 ≤768 块降为 md） */
  padding: var(--space-3) 0;
  color: var(--ink-soft);
}
.about-page .ap-kbd-row + .ap-kbd-row { border-top: 1px dashed var(--border-soft); }
.about-page .ap-kbd-desc { flex: 1; }
.about-page .ap-kbd-keys {
  display: inline-flex;
  gap: var(--space-1);
  flex-shrink: 0;
  /* 组124：键位列定宽 = 双键帽 30×2 + 间隙 space-1 + 余量，五行的描述
     左缘对齐成一条直线（最宽组合是 ←/→ 与 j/k 两枚键帽） */
  min-width: 76px;
}
.about-page kbd {
  display: inline-block;
  font-family: var(--font-mono);
  /* 组119：行内键帽改相对字号（0.82em），随所在行字号伸缩——步骤行 lg
     下 ≈12.5px，不再钉死 xs 显小 */
  font-size: 0.82em;
  line-height: var(--leading-none);
  color: var(--ink);
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  padding: 3px var(--space-2);
  min-width: 24px;
  text-align: center;
}
.about-page .ap-kbd-keys kbd {
  /* 组119：快捷键表的键帽是表的「值列」，抬到 --text-md 与描述行同视重 */
  min-width: 30px;
  padding: 4px var(--space-3);
  font-size: var(--text-md);
}
.about-page code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--bg-soft);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 1px 5px;
  word-break: break-all;
}
/* 组126：dl 卡片化——本页三块内容（功能卡 / 键位表 / 数据表）同语汇收尾
   （border-soft + radius-md，键位列左置后全表自成一块的同一逻辑）。行间
   虚线分隔与键位表同款：grid 两列无「整行」元素可挂线，故 dt 与其后继 dd
   各加 border-top，列间距处留缝不连（两列结构本就有沟，读起来仍是一行）。 */
.about-page .ap-dl {
  display: grid;
  grid-template-columns: 6.5em 1fr;
  gap: var(--space-3) var(--space-4);
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
}
.about-page .ap-dl dt:not(:first-child),
.about-page .ap-dl dt:not(:first-child) + dd {
  border-top: 1px dashed var(--border-soft);
  padding-top: var(--space-3);
}
.about-page .ap-dl dt { font-weight: 600; color: var(--ink); }
.about-page .ap-dl dd {
  margin: 0;
  color: var(--ink-soft);
  line-height: var(--leading-relaxed);
}
/* 组89 宽屏档：about 的条目类内容（特性列表）可读性由「条宽」控制而非行长，
   容器放宽不伤阅读——≥1280 给到 1080px；特性列表换自适应多列（组82 卡片列表
   同款配方：每列 ≥380px 才起新列，880~1080px 容器下恰好两列，不退化成横贯全宽
   的长线条目）。dl 保持单列。组124 曾在合并节 ≥1024 起双栏（.ap-sh-grid
   左三步右全表）；组126 按用户令拆回两节纵向排布，双栏撤销——键位卡
   fit-content 内容宽居左，宽容器下由 .ap-section 节距控制节奏。 */
@media (min-width: 1024px) {
  .about-page .ap-features {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr));
    column-gap: var(--space-6);
  }
}
@media (min-width: 1280px) {
  .about-page { max-width: 1080px; }
}
/* fix audit-2026-10-25 组104：超宽屏正文再加封顶档（用户报「关于页内容显示
   可以再宽一些，左右留太多」，追问澄清=指页内内容本身）。组89 摘帽后封顶停在
   1080px——1440 窗口单侧 180px、1920 屏 ~420px、2560 屏 ~740px，整页读起来
   仍是一条居中窄带。本页没有连续长段（导语一句、步骤三行、快捷键五行、dl
   四项均为短条目型内容），行长由条目结构而非容器控制，组89 已论证放宽不伤
   阅读，故只补封顶档、不动任何子块度量。1700/2560 两档复用组100 已登记断点；
   1440 为新增断点，已登记进 lint-tokens BREAKPOINTS。1280 档保持组89 原值
   1080 不动 → 375/768/1280 三档视觉基线零波及，免重建。
   特性列表列数随容器自适应（每列 ≥380 起新列）：1240/1360 档 = 3 列
   （397/437px）；1560 档刻意留在 4 列门槛（4×380+3×24=1592）之下——
   组119 起 7 条按 3+3+1 收尾，不碎成 382px 的超窄第四列。 */
@media (min-width: 1440px) {
  .about-page { max-width: 1240px; }
}
@media (min-width: 1700px) {
  .about-page { max-width: 1360px; }
}
@media (min-width: 2560px) {
  .about-page { max-width: 1560px; }
}
@media (max-width: 768px) {
  /* 组119：窄屏同步抬一档（标题 2xl→3xl、快捷键行 sm→md），正文经
     .about-page 基块继承 lg，不再降档 */
  .about-page .ap-title { font-size: var(--text-3xl); }
  .about-page .ap-kbd-row { font-size: var(--text-md); }
  .about-page .ap-dl { grid-template-columns: 1fr; gap: var(--space-1) 0; }
  .about-page .ap-dl dt { margin-top: var(--space-3); }
  /* 组126：单列态分隔线只跟条目头（dt），dd 不再挂线否则线落在 dt 与
     自己的内容之间；dt 侧 border + padding-top 保留为条目分隔 */
  .about-page .ap-dl dt:not(:first-child) + dd { border-top: 0; padding-top: 0; }
}

/* =========================================================================
   收藏 / 已读 视图：跨期刊分类显示
   - 侧栏里按期刊分组的小标题（紧凑）
   - 主区里按期刊分组的大标题（醒目，带色条 + logo + 副标题）
   ========================================================================= */

/* 侧栏里的期刊分组小标题 */
.sidebar-journal-group {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5) 6px;
  margin-top: var(--space-1);
  font-family: var(--font-serif);
  font-size: var(--text-2xs);
  font-weight: 600;
  color: var(--ink-soft);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-top: 1px solid var(--border-soft);
}
.sidebar-journal-group:first-of-type {
  border-top: none;
  margin-top: 0;
}
.sidebar-journal-group .sjg-logo {
  font-size: var(--text-2xs);
  letter-spacing: 0.05em;
  padding: 2px 7px;
}
.sidebar-journal-group[data-journal="prl"] .sjg-logo { background: var(--journal-prl); }
.sidebar-journal-group[data-journal="prb"] .sjg-logo { background: var(--journal-prb); }
.sidebar-journal-group .sjg-label {
  flex: 1;
}
.sidebar-journal-group .sjg-count {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  color: var(--ink-mute);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}

/* 主区里的期刊分组大标题：左色条 + 期刊 logo + 期刊全名 + 数量 */
.content-journal-group {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) 0 var(--space-3);
  margin: var(--space-6) 0 var(--space-3);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border-soft);
  position: relative;
}
.content-journal-group:first-of-type {
  margin-top: var(--space-1);
}
.content-journal-group .cjg-bar {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  border-radius: 0 3px 3px 0;
}
.content-journal-group[data-journal="prl"] .cjg-bar { background: var(--journal-prl); }
.content-journal-group[data-journal="prb"] .cjg-bar { background: var(--journal-prb); }
/* audit-2026-10-24：arxiv 分组此前没有色条（三刊都可能出组头，收藏/已读跨刊视图）。
   纯装饰元素按 ink-mute 中性灰补齐，避免 arxiv 组头左侧秃一块。 */
.content-journal-group[data-journal="arxiv"] .cjg-bar { background: var(--ink-mute); }
.content-journal-group .cjg-logo {
  font-size: var(--text-sm);
  letter-spacing: 0.08em;
  padding: var(--space-1) var(--space-2);
  margin-left: 14px;
}
.content-journal-group[data-journal="prl"] .cjg-logo { background: var(--journal-prl); }
.content-journal-group[data-journal="prb"] .cjg-logo { background: var(--journal-prb); }
.content-journal-group .cjg-text { flex: 1; min-width: 0; }
.content-journal-group .cjg-name {
  font-family: var(--font-serif);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.01em;
}
.content-journal-group .cjg-meta {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-mute);
  margin-top: 2px;
}

/* [已删 · audit-2026-10-22 HIGH] 原「深色主题徽章字色」覆盖块：把字色改成
   --text-on-light-accent（近黑 oklch 21%），但 --journal-prl/prb 是不随主题
   变化的固定深色（oklch 41%）——深字压深底 ≈2.2:1 不可读，与注释宣称的
   「更亮的字色」意图相反。徽章底色不变 → 基础规则的近白 --text-on-accent
   在 9 个主题下都正确，无需任何暗色覆盖。 */

/* 面板里：文章详情视图 */
.dp-article .dp-header {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--space-3); margin-bottom: var(--space-3);
}
/* Section pill (3 处共用：.dp-article / .article-card / .modal-header)
   —— PRL/PRB section 缩写标签，pill 形等宽字 */
.dp-article .dp-section,
.article-card .ac-section,
.modal-header .mh-section {
  font-family: var(--font-mono);
  white-space: nowrap;
  border-radius: var(--radius-pill);
  letter-spacing: 0.04em;
  flex-shrink: 0;
}
.dp-article .dp-section {
  font-size: var(--text-2xs);
  padding: 3px var(--space-2);
}
.article-card .ac-section {
  font-size: var(--text-2xs);
  padding: 3px var(--space-2);
  font-variant-numeric: tabular-nums;
  margin-top: 3px;
  /* 颜色在卡片渲染时已写入内联 style，运行时不变 → 不要 transition（纯开销） */
}
.modal-header .mh-section {
  font-size: var(--text-xs);
  padding: var(--space-1) var(--space-2);
}
/* 详情面板右上角的关闭按钮（面板 chrome 行，2026-10-23 新增）
   —— 原先是文章正文头部（.dp-header）里的 .dp-close，与面板 chrome 按钮
   在同一列上下相邻、看起来像重复控件，已合并为这一个。 */
.dp-pane-close {
  /* 32px —— 与详情面板内 .dp-actions .icon-btn(min-width: 32px) 和全站
     .icon-btn(min-height: 32px) 的触控目标一致；此前 28px 比同屏按钮小一圈。 */
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill); /* 2026-10-24：纯图标控件圆形化（同 .sidebar-toggle） */
  color: var(--ink-mute);
  font-size: var(--text-2xl);
  line-height: var(--leading-none);
  padding: 0;
  background: var(--bg-elev);
  flex-shrink: 0;
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.dp-pane-close:hover {
  background: var(--bg-hover); color: var(--ink); border-color: var(--accent);
}
.dp-pane-close:active { transform: scale(0.95); }
.dp-pane-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.dp-article .dp-title {
  font-family: var(--font-serif);
  font-size: var(--text-2xl);
  font-weight: 600;
  line-height: var(--leading-tight);
  letter-spacing: 0.003em;
  color: var(--ink);
  margin: 0 0 var(--space-2);
  /* 400px 窄栏里论文标题常排 3~4 行，末行常只剩一两个词（"in Cooling"）。
     text-wrap: balance 把各行长度拉平；浏览器不认这个值时自动退化成默认排版。 */
  text-wrap: balance;
  /* audit-2026-10-22 LOW：长 DOI / 无空格串折行而非被 overflow-x:hidden 硬裁 */
  overflow-wrap: anywhere;
}
.dp-article .dp-authors {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  line-height: var(--leading-heading);
  margin: 0 0 var(--space-4);
  overflow-wrap: anywhere;
}
.dp-article .dp-abstract {
  font-family: var(--font-serif);
  font-size: var(--text-md);
  line-height: var(--leading-body);
  color: var(--ink);
  margin: 0 0 var(--space-4);
  /* pretty：摘要末行常只剩一两个词，pretty 会在换行点里择优 */
  text-wrap: pretty;
  /* audit-2026-10-22 LOW：同 dp-title，长公式串/URL 折行不硬裁 */
  overflow-wrap: anywhere;
}
/* Abstract 排版标签（3 处共用：.dp-article .dp-abstract / .ac-abstract / .modal-body）
   —— PRL 摘要里常见的 italic / bold / small-caps / MathML 标签。 */
.dp-article .dp-abstract i,
.dp-article .dp-abstract em,
.ac-abstract i,
.ac-abstract em,
.modal-body i,
.modal-body em { font-style: italic; }
.dp-article .dp-abstract b,
.dp-article .dp-abstract strong,
.ac-abstract b,
.ac-abstract strong,
.modal-body b,
.modal-body strong { font-weight: 600; }
.dp-article .dp-abstract span.sc,
.ac-abstract span.sc,
.modal-body span.sc { font-variant: small-caps; font-size: 0.92em; }
.dp-article .dp-abstract math,
.dp-article .dp-abstract mtext,
.dp-article .dp-abstract mn,
.dp-article .dp-abstract mi,
.ac-abstract math,
.ac-abstract mtext,
.ac-abstract mn,
.ac-abstract mi,
.modal-body math,
.modal-body mtext,
.modal-body mn,
.modal-body mi { font-family: var(--font-serif); }
.dp-article .dp-footer {
  display: flex; align-items: center; gap: var(--space-2);
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
  flex-wrap: wrap;
}
.dp-article .dp-footer .dp-meta {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--text-xs);
  color: var(--ink-mute);
  /* 元信息独占一行（flex-basis: 100%）。
     此前 meta 与操作按钮同行：详情面板内容宽 341px，操作按钮占 132px，
     meta 只剩 200px —— 「Phys. Rev. Lett. 137, 110404 · 2026 年 09 月 11 日 · 周五」
     只能折成两行，且断点落在「2026 年」/「09 月 11 日」中间（实测 meta 高 36px、
     第二行从「09 月」起头）。独占一行后实测整串 285px < 341px，单行放得下，
     断行问题从根上消失；操作按钮顺势落到第二行右对齐。 */
  flex: 1 1 100%; min-width: 0;
  display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.dp-article .dp-footer .dp-actions {
  display: flex; gap: 6px; align-items: center; flex-shrink: 0;
  /* meta 独占一行后，按钮行靠右 —— 与卡片 .ac-footer .actions 的排布一致 */
  margin-left: auto;
}
/* 详情面板里的图标按钮（仅字符无文字）尺寸稍小、min-width 固定，避免"原文 ↗" 撑宽整行 */
.dp-article .dp-actions .icon-btn {
  min-width: 32px;
  justify-content: center;
  padding: var(--space-1) var(--space-2);
}
.dp-article .dp-actions .icon-btn:not([data-action]):not(.read):not(.fav) {
  /* 含文字的按钮（原文 ↗）放宽一点 */
  padding: var(--space-1) var(--space-2);
  min-width: 0;
}

.content-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  border-bottom: 1px solid var(--border);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-6);
  gap: var(--space-4);
  /* 空间真的不够时，让「N 篇」整体掉到第二行，而不是把标题和快捷键提示压扁。
     配合下面 h1 / .kb-hint 的 nowrap，构成「宁可换行也不逐字断行」的结构性保证：
     中文可以在任意两字之间断行，flex item 默认 min-width:auto 又让它可以缩到
     min-content，于是宽度一紧张就出现「上一日」竖成一列、日期劈成两行的字标
     （见 .kb-hint 处注释）。1280px 及以上不会触发（实测 940px 可用 vs 620px 需求）。 */
  flex-wrap: wrap;
}
.content-header h1 {
  font-family: var(--font-serif);
  font-size: var(--text-4xl);
  font-weight: 600;
  margin: 0;
  letter-spacing: 0.003em;
  line-height: var(--leading-tight);
  color: var(--ink);
  /* 日期是一个整体，不该在「09 月」和「11 日」之间断开。与 .brand 用同一条理由。
     前提是 .date-nav 自己也允许换行（见其 flex-wrap）——否则 nowrap 在极窄屏
     会把整行顶出容器，实测 320px 下 date-nav 横向溢出 24px。
     两处必须成对：nowrap 负责「不逐字拆」，date-nav 的 wrap 负责「放不下就换行」。 */
  white-space: nowrap;
}
.content-header .meta {
  color: var(--ink-mute); font-size: var(--text-sm);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

.date-nav { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; }
.date-nav-btn {
  width: 32px; height: 32px;
  /* 圆形按钮是固定尺寸的导航控件，不参与压缩——被压成椭圆比换行难看得多 */
  flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); /* 组82：控件边框 1.4.11（见 --border-strong 注释） */
  border-radius: 50%;
  color: var(--ink-soft); font-size: var(--text-md);
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast), transform var(--dur-fast);
}
.date-nav-btn:hover:not(:disabled) {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  transform: scale(1.06);
}
.date-nav-btn:active:not(:disabled) { transform: scale(0.96); }
.date-nav-btn:disabled { opacity: 0.35; cursor: not-allowed; }

.content-header .kb-hint {
  display: inline-flex; align-items: center; gap: var(--space-1);
  font-size: var(--text-xs); color: var(--ink-soft);
  font-family: var(--font-mono);
  margin-left: 10px;
  padding-left: 10px;
  border-left: 1px solid var(--border-soft);
  /* fix audit-2026-10-03：这条是「中文逐字断行」的重灾区。
     .kb-hint 是 .date-nav 的 flex item，里面既有 <kbd> 也有纯文本节点
     「上一日 · 」「下一日」；匿名 flex item 可以在任意两字之间断行，而
     flex item 默认 min-width:auto 允许它一路缩到 min-content（≈1 个字宽）。
     一旦 .date-nav 的可用宽度低于自然宽度（约 620px），实测：
       header 940px → h1 1 行 / kb-hint 1 行（正常）
       header 560px → h1 2 行 / kb-hint 2 行
       header 420px → h1 2 行 / kb-hint 4 行（「下一」+「日」）
     headless Chromium 自带字体偏窄，1280px 下有 320px 余量所以测不出来；
     但同一份代码在 Electron 宿主（更宽的 CJK 字形）里当场就崩了 ——
     这类「只在真实宿主成立」的缺陷不要用「我这边是好的」结案。
     nowrap + shrink-0 让它保持一行，放不下时交给父级 .content-header 换行。 */
  white-space: nowrap;
  flex-shrink: 0;
}
.content-header .kb-hint kbd {
  font-family: var(--font-mono); font-size: var(--text-2xs);
  background: var(--bg-soft); border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm); padding: 1px 5px; color: var(--ink);
  display: inline-block;
}

.search-summary {
  font-size: var(--text-sm); color: var(--ink-mute);
  margin-bottom: 18px; font-family: var(--font-serif);
  font-style: italic;
  /* 用户可能粘贴一长串无空格文本（URL / DOI / 哈希），需要可断行防撑破布局。
     overflow-wrap: anywhere 比 break-word 更激进，连一个超长无空格 token 也会断。 */
  overflow-wrap: anywhere;
}
.search-summary b { color: var(--ink); font-weight: 600; font-style: normal; }

.search-highlight {
  background: var(--selection);
  color: var(--ink);
  padding: 0 1px;
  border-radius: var(--radius-sm);
}

/* =========================================================================
   文章卡片
   ========================================================================= */
.article-list { display: flex; flex-direction: column; gap: 14px; }

.article-card {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5) var(--space-3);
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur-base), box-shadow var(--dur-base), background var(--dur-base);
  position: relative;
  overflow: hidden;
  /* 组78：光标跟随 affordance——hover 的浮起+阴影+左侧色条已把整卡声明成
     "可打开"，JS 侧 card.js click 兜底也已落地（空白/正文/作者点卡任意处
     开详情，卡内活体选区时不劫持）。此前 cursor 是文本 I 形，指向与行为
     错位；选字复制不受 cursor:pointer 影响。 */
  cursor: pointer;
  animation: cardFadeIn var(--dur-slow) var(--ease-std-out) both;
  /* 视口外卡片跳过布局+绘制，长列表 scrolling FPS 提升 30-50%。
     contain-intrinsic-size 给一个估算高度（PRL/PRB 平均卡 ~220px），
     浏览器用这个作为占位高度，避免滚动条抖动。 */
  content-visibility: auto;
  contain-intrinsic-size: 0 220px;
}
@keyframes cardFadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* 切 view / 翻页时不再重跑 cardFadeIn：避免合成层抖动 + 切换的"刷新感"。
   首屏渲染的 .article-list 不带 no-card-anim，卡片仍跑动画；之后 renderContent
   重渲时给列表加 no-card-anim 停掉动画。（fix audit-2026-10-22 LOW：原注释提到
   的 body.first-paint class 在 JS 里并不存在，是注释漂移。） */
.article-list.no-card-anim .article-card { animation: none; }
.article-card::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--card-accent);
  opacity: 0;
  transition: opacity var(--dur-base), width var(--dur-base);
}
.article-card:hover {
  /* 2026-10-25：移除 hover 上浮 translateY(-2px)——位移会带动整张卡含文字一起移动，
     悬停瞬间文字跳动干扰阅读。hover 态改由边框变色 + 投影抬升表达（文字不动）。 */
  border-color: var(--card-accent);
  box-shadow: var(--shadow);
}
.article-card:hover::before { opacity: 1; width: 4px; }

.article-card.read {
  background: var(--read-bg);
}
.article-card.read::before { opacity: 0.45; width: 2px; }
/* 组79（2026-10-25）：撤销 `.article-card.read:hover` 提亮回 --bg-elev 的规则——
   hover 把已读底色换成未读卡底色，视觉上"变回未读"，干扰扫读定位。
   悬停反馈仍由 .article-card:hover 的边框/阴影表达。
   （本修复第一版因未提交被 9630e92 批的内存副本冲掉，此次入库固化。） */
.article-card.read .ac-title { color: var(--ink-soft); }
.article-card.read .ac-authors { color: var(--ink-mute); }

/* Stub 占位卡片：本 HTML 没加载该期刊数据时的 fallback。
   用虚线左边条 + 浅灰背景 + 斜体提示，让用户一眼看出"这不是完整数据，点跳走查看"。 */
.article-card.stub {
  background: var(--read-bg, oklch(97.558% 0.0026 106.4));
  border-style: dashed;
}
.article-card.stub::before {
  background: repeating-linear-gradient(
    to bottom,
    var(--ink-mute, oklch(68.3% 0 0)) 0,
    var(--ink-mute, oklch(68.3% 0 0)) 4px,
    transparent 4px,
    transparent 8px
  );
  opacity: 0.5;
}
.article-card.stub .ac-title { font-style: italic; color: var(--ink-soft); }
.article-card.stub .ac-authors { font-style: italic; }

.ac-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: 6px;
}
.ac-title {
  font-family: var(--font-serif);
  font-size: var(--text-2xl);
  font-weight: 600;
  margin: 0;
  line-height: var(--leading-tight);
  letter-spacing: 0.003em;
  flex: 1;
  /* 防 PRB / arXiv 等长无空格 token（如 DOI / 标识符 / 公式串）撑爆卡片 */
  min-width: 0;
  overflow-wrap: anywhere;
}
.ac-title-link {
  color: var(--ink);
  cursor: pointer;
  background-image: linear-gradient(transparent calc(100% - 1px), var(--accent) 1px);
  background-size: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--dur-slow), color var(--dur-fast);
  /* 链接里同样要允许断行，否则 a 默认 white-space: normal 但 inline 容器无法约束宽度 */
  overflow-wrap: anywhere;
  /* 组78：与 .dp-title / .mh-title 同约定——两行标题按权重均分，避免第二行
     只吊一个词的孤行。 */
  text-wrap: balance;
}
.ac-title-link:hover {
  color: var(--accent);
  text-decoration: none;
  background-size: 100% 100%;
}
.ac-title-link:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); }

.ac-authors {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--ink-soft);
  font-size: var(--text-md);
  margin: 0 0 var(--space-2);
  line-height: var(--leading-heading);
  overflow-wrap: anywhere;
  /* 组78：作者串常占两三行，pretty 只收拾末行孤词，不像 balance 重排各行宽度。 */
  text-wrap: pretty;
}

.ac-abstract {
  color: var(--ink-soft);
  font-size: var(--text-md);
  line-height: var(--leading-body);
  margin: var(--space-1) 0 var(--space-3);
  font-family: var(--font-serif);
}
/* clamp 模式才裁切：未 clamp 时（如已展开）必须让全文可见 */
.ac-abstract.clamp {
  display: -webkit-box;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* MathML 等排版标签的样式已合并到上方的「Abstract 排版标签」共用规则块 */
/* 展开/收起按钮已移出 .ac-abstract（避免被 overflow:hidden 一并裁掉，
   长摘要的"展开"按钮就永远看不见）。.abstract-toggle 现在是 .ac-abstract
   兄弟元素，匹配下面的规则。 */
.abstract-toggle {
  display: inline-block;
  margin: -6px 0 var(--space-2);          /* 紧贴摘要下沿、给 footer 留间距 */
  color: var(--link);
  font-size: var(--text-sm);
  cursor: pointer;
  user-select: none;
  font-style: normal;
  font-family: var(--font-sans);
  transition: color var(--dur-fast), transform var(--dur-fast);
  /* 触控目标：上下 padding 加大，使"展开/收起"链接 ≥34px */
  padding: var(--space-2) var(--space-1);
  min-height: 34px;
}
.abstract-toggle:hover { text-decoration: underline; }
.abstract-toggle:active { color: var(--accent-deep); transform: translateY(1px); }
.abstract-toggle:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.ac-footer {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  /* 空间不够时让操作行整体换到第二行。缺这条时 .actions 会被 .article-card 的
     overflow:hidden 直接裁掉——首页三栏（每栏仅 ~300px）里 arXiv 栏的
     meta 更长（`cs.CR · 13:45 UTC` + `arXiv:2609.11552`），1024px 下实测
     「原文 ↗」按钮被裁掉 13px、整颗按钮点不到。 */
  flex-wrap: wrap;
  font-size: var(--text-xs);
  color: var(--ink-mute);
  border-top: 1px solid var(--border-soft);
  padding-top: 10px;
  margin-top: var(--space-1);
}
/* min-width:0 让 meta 可以压到比 min-content 更窄（它自身 flex-wrap:wrap 会换行），
   缺 min-width:0 时 flex item 默认 min-width:auto，整条 meta 拒绝收缩，把 .actions
   顶出卡片被裁。
   注意只加 min-width，**不要**加 flex:1 1 auto —— 那会让 meta 主动撑满整行，
   把操作行挤到第二行，1280px 下原本单行放得下的 footer 反而变高两行（实测首页
   视觉基线 3.5% 差异）。保持 flex 默认的 0 1 auto：有空间时操作行仍与 meta 同行。 */
.ac-footer .pub-info { font-family: var(--font-serif); font-style: italic; display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
/* shrink-0：三个按钮是卡片的主要操作，宁可换行也绝不被压扁/裁掉 */
.ac-footer .actions { margin-left: auto; display: flex; gap: var(--space-1); flex-shrink: 0; }

/* 收藏 / 已读视图的卡片上多出的小期刊标签（避免用户混淆 PRL / PRB） */
.ac-journal-tag {
  font-size: var(--text-2xs);
  letter-spacing: 0.05em;
  padding: 2px 6px;
}
.ac-journal-tag[data-journal="prl"] { background: var(--journal-prl); }
.ac-journal-tag[data-journal="prb"] { background: var(--journal-prb); }
/* fix audit-2026-10-23 HIGH：arXiv 卡片的期刊标签此前没有底色规则——
   近白文字（--text-on-accent）直接压白卡片底，实测 ≈1.07:1，「ARXIV」
   三个字母几乎隐形（首页三栏 / 收藏 / 已读视图均受影响；对照 PRL/PRB
   徽章深蓝/深红底 8.2:1）。arXiv 标签改用「浅灰底 + 深字」方案而非再添
   一个固定深底色：arXiv 无官方品牌色，深底会与下方分类角标（--c*-fg
   彩色系）争夺注意力；灰底黑字与 .arxiv-id 的 bg-soft/ink-soft 同一套
   中性色语言。9 主题下 bg-soft 都随主题走，字色用 --ink-soft 同源，
   实算最差 theme(dune) 6.1:1 ≥ 4.5。 */
.ac-journal-tag[data-journal="arxiv"] {
  background: var(--bg-soft);
  color: var(--ink-soft);
}
/* audit-2026-10-22 HIGH：此处原有暗色覆盖把字色改成 --text-on-light-accent
   （深字压深底 ≈2.2:1），已删——字色统一走 1937 行共享规则的近白 --text-on-accent。
   上面的 arxiv 分支用的是会随主题翻转的中性色对，同样不需要暗色覆盖。 */

/* arXiv ID 小标识（卡片 / 详情面板 / 弹窗共用）：等宽字体 + 浅底 + 点击复制反馈 */
.arxiv-id {
  /* fix audit 2026-10-25 组82：复制控件从 <span role=button> 升级为真 <button>
     （util.js:arxivCardMetaParts——Enter/Space/表单语义/命中区交给 UA）。
     以下是按钮态必需的 UA 外观中和，其余声明逐字保留（span 用法若回归也兼容）。 */
  border: 0;
  appearance: none;
  -webkit-appearance: none;
  text-align: inherit;
  font-family: var(--font-mono); /* 同时中和按钮的 UA 字体 */
  display: inline-block;
  font-style: normal;   /* 覆盖 .pub-info / .dp-meta / .footer-meta 的 italic */
  font-size: var(--text-xs);
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  background: var(--bg-soft);
  color: var(--ink-soft);
  cursor: pointer;
  user-select: none;
  transition: background-color var(--dur-fast), color var(--dur-fast);
}
.arxiv-id:hover { background: var(--accent-soft); color: var(--accent); }
.arxiv-id:active { transform: scale(0.97); }
.arxiv-id:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.arxiv-id.copied { background: var(--accent); color: var(--text-on-accent); }
/* 3 个暗色主题的 --accent 偏浅（深空 oklch(70.624% 0.0835 255.1) 等），白字对比度不足 → 改用深色字 */
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .arxiv-id.copied { color: var(--text-on-light-accent); }

.icon-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 6px var(--space-2);
  font-size: var(--text-xs);
  color: var(--ink-soft);
  border: 1px solid var(--border-strong); /* 组82：控件边框 1.4.11（见 --border-strong 注释） */
  /* 2026-10-24：卡片操作按钮（收藏 / 已读 / 原文）胶囊化。padding 不加——
     .ac-footer 换行/裁切有三条结构锚点测试（bug7.1-7.3），按钮加宽会吃掉
     1024px 首页三栏的余量。favPop 缩放动画在胶囊形上同样成立。 */
  border-radius: var(--radius-pill);
  background: var(--bg-elev);
  transition: background-color var(--dur-base) ease, color var(--dur-base) ease, border-color var(--dur-base) ease,
              transform var(--dur-fast);
  white-space: nowrap;
  /* 触控目标 ≥34px：原 4px padding + 12px 文字 ≈ 24px，触摸时容易误触邻居 */
  min-height: 34px;
}
.icon-btn:hover {
  background: var(--bg-hover);
  color: var(--ink);
  text-decoration: none;
  transform: translateY(-1px);
}
.icon-btn:active { transform: translateY(0); }
/* 组78：收藏 / 已读两态只差几个字（"☆ 收藏"↔"★ 已收藏" 11.6px、
   "○ 标记已读"↔"✓ 已读" 21.6px），切换时 .actions 行宽抖动，窄栏里
   相邻按钮肉眼可见地横移。按两态实测最大宽度预占 + 内容居中；行整体
   仍靠左。只作用于 .article-card——详情面板 / 弹窗的按钮文案与尺寸
   另有约束（.dp-actions min-width:32px），不碰；@media (hover:none)
   的 44×44 热区走 ::before，与 min-width 无冲突。 */
.article-card .icon-btn.fav,
.article-card .icon-btn.read {
  justify-content: center;
}
.article-card .icon-btn.fav { min-width: 68px; }
.article-card .icon-btn.read { min-width: 78px; }
/* 收藏 / 已读开关的「已激活」外观。
   类名跟着 data-action 走：卡片是 fav / read，详情面板是 fav-detail /
   read-detail，弹窗是 fav-modal —— 三处按钮都由 _renderToggleBtn 渲染，
   class = action 名。旧版只写了 .fav / .read，于是面板与弹窗里的按钮
   永远拿不到激活样式（已收藏的条目在面板里看不出收藏状态）。 */
.icon-btn.fav.active,
.icon-btn.fav-detail.active,
.icon-btn.fav-modal.active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-deep);
  animation: favPop var(--dur-slow) var(--ease-std-out);
}
@keyframes favPop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.12); }
  100% { transform: scale(1); }
}
.icon-btn.read.active,
.icon-btn.read-detail.active {
  background: color-mix(in srgb, var(--read-bg) 60%, var(--accent-soft));
  border-color: var(--accent);
  color: var(--accent-deep);
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .icon-btn.read.active,
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .icon-btn.read-detail.active {
  background: color-mix(in srgb, var(--read-bg) 70%, var(--accent-soft));
  color: var(--accent);
}

/* =========================================================================
   收藏视图 — 本地存储说明横幅、导出/导入工具栏、toast
   ========================================================================= */

.content-header .ch-left {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  min-width: 0;
}

/* fix audit-2026-10-03：ch-left 里的 .meta 不能沿用全局的 nowrap。
   .content-header .meta 的 nowrap 是为「17 篇」这类**数字**服务的（配
   tabular-nums 保持不跳动）；但 home 页塞进去的是一整句
   当时的文案「… · 每刊 5 篇 · 全本地静态站」（现已改为「数据每日更新」）——实测宽 332px。
   ch-left 是 h1(148) + gap(12) + meta(332) 的一行，合计 492px：
     320px 视口 → .content 可用 296px → 右边缘超出 22px
     480px 视口 → .content 可用 456px → 右边缘超出 29px
   两条都会让整页出现横向滚动条（项目自己的 h-overflow 测试从 320 扫到 1440）。

   放在基础层而不是 @media (max-width:479px) 里：先试过 media query 版本，
   结果 480~500 那一档（可用宽 456~476 < 492）又溢出 —— **按断点打补丁必然漏档**。
   宽度无关的写法是「这句本来就可能很长，所以永远允许换行」：
   宽屏下可用宽远大于 332px，它仍然只占一行，1280 / 1440 视觉基线不受影响。
   数字型 .meta（浏览页的「17 篇」）不在 .ch-left 里，不受这条影响。 */
.content-header .ch-left .meta { white-space: normal; }

.fav-toolbar {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}
.fav-toolbar .icon-btn { padding: 5px var(--space-3); }

/* fav-toolbar 的「危险」按钮（清空）— 用边框区分，不直接用红色（避免突兀） */
.fav-toolbar-danger {
  color: var(--ink-soft);
}
.fav-toolbar-danger:hover {
  /* iter 114 Phase 1：用 --state-danger-fg / --state-danger-bg 取代硬编码 oklch(50.542% 0.1905 27.5) */
  color: var(--state-danger-fg);
  border-color: var(--state-danger-fg);
  background: var(--state-danger-bg);
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .fav-toolbar-danger:hover {
  /* 深色主题：--state-danger-fg 现由暗色 token 自带浅色值（组127 M8a 补齐后
     这句承诺才成立；bg 换 12% 透明染底，避免 :root 的近白粉底在暗色页炸屏） */
  color: var(--state-danger-fg);
  border-color: var(--state-danger-fg);
  background: color-mix(in srgb, var(--state-danger-fg) 12%, transparent);
}
/* 键盘 Tab 进入时焦点环：与 hover 红色对齐，2px outline + offset 避开文字 */
.fav-toolbar-danger:focus-visible {
  outline: 3px solid var(--state-danger-fg);
  outline-offset: 2px;
}

/* 已读侧栏：按阅读日期分组的小标题（今天/昨天/本周早些/具体日期） */
.read-day-group {
  padding: var(--space-2) var(--space-4) var(--space-1);
  margin-top: 6px;
  font-size: var(--text-2xs);
  font-weight: 600;
  color: var(--ink-mute);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  border-top: 1px solid var(--border-soft);
}
.read-day-group:first-of-type { border-top: none; margin-top: 0; }
.read-day-group + .collection-list { margin-top: 0; }

.fav-notice {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  padding: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-5) 0;
  /* iter 114 Phase 1：从硬编码 amber 调色板 → 语义化 --state-warning-* token */
  background: var(--state-warning-bg);
  /* 2026-10-24：满饱和琥珀描边读起来像 2010s 的「bootstrap alert」——
     边框收到 50% 半透明（琥珀线浮在琥珀底上而不是一道硬框），圆角升到
     --radius；左侧 4px 状态条保留（语义色条是这个组件的辨识点）。
     文字/底色（state-warning-fg / bg）这对 WCAG 组合未动。 */
  border: 1px solid color-mix(in srgb, var(--state-warning-edge) 50%, transparent);
  border-left: 4px solid var(--state-warning-bar);
  border-radius: var(--radius);
  font-size: var(--text-sm);
  line-height: var(--leading-body);
  color: var(--state-warning-fg);
}
.fav-notice .fn-icon {
  flex-shrink: 0;
  font-size: var(--text-xl);
  line-height: var(--leading-body);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--state-warning-bar);
}
/* ES_ICONS 里的 SVG 没显式 width/height，默认渲染 300×150 撑破容器；这里显式约束。
   SVG 颜色继承父 .fn-icon 的 currentColor（ES_ICONS 内部已用 stroke="currentColor"） */
.fav-notice .fn-icon svg {
  width: 17px; height: 17px;
  display: block;
}
.fav-notice.compact .fn-icon svg { width: 15px; height: 15px; }

/* 紧凑型（用于浏览默认页等不希望霸屏的位置） */
.fav-notice.compact {
  padding: var(--space-2) var(--space-3);
  margin: 0 0 var(--space-4) 0;
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  background: var(--state-warning-bg);
  /* 2026-10-24：跟随 .fav-notice 主规则的半透明描边（见其注释）。 */
  border-color: color-mix(in srgb, var(--state-warning-edge) 50%, transparent);
  border-left-width: 3px;
  color: var(--state-warning-fg);
}
.fav-notice.compact .fn-icon { font-size: var(--text-lg); line-height: var(--leading-relaxed); }

/* 深色主题下用深色警告底（moss 也是深色主题，单独漏掉会显示亮黄底） */
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .fav-notice,
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .fav-notice.compact {
  background: var(--state-warning-bg);
  /* 2026-10-24：与主规则/compact 的半透明描边对齐（此前这里是满饱和 edge，
     三个暗色主题会盖回硬框）。 */
  border-color: color-mix(in srgb, var(--state-warning-edge) 50%, transparent);
  border-left-color: var(--state-warning-bar);
  color: var(--state-warning-fg);
}

/* fav-notice 内的关闭按钮：右上角 ×，与正文对齐、足够大的触控目标 */
.fav-notice .fn-text { flex: 1; min-width: 0; }
.fav-notice .fn-close {
  flex-shrink: 0;
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: none; background: transparent;
  color: inherit;
  font-size: var(--text-2xl); line-height: var(--leading-none);
  cursor: pointer;
  opacity: 0.6;
  transition: opacity var(--dur-fast), background var(--dur-fast);
  -webkit-tap-highlight-color: transparent;
}
.fav-notice .fn-close:hover { opacity: 1; background: var(--overlay-soft); }
.fav-notice .fn-close:active { background: var(--overlay-active); }
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .fav-notice .fn-close:hover {
  background: var(--tint-mid);
}
/* 极窄屏：fn-text 允许换行，关闭按钮保持右上 */
@media (max-width: 380px) {
  .fav-notice { font-size: var(--text-xs); }
  .fav-notice .fn-icon { font-size: var(--text-lg); line-height: var(--leading-relaxed); }
}

/* button.link-style：外观像链接但语义是按钮。
   用于替代 href="#" 锚点（避免漏 preventDefault 时 scroll-to-top）。
   保持文字色 / 下划线与正文链接一致，仅去掉 button 默认边框 / 背景。 */
.link-style {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  /* 触摸目标 ≥24px，但视觉保持紧凑内联文字感 */
  min-height: 24px;
}
.link-style:hover { color: var(--accent-deep); }
.link-style:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.sidebar-fav-hint {
  padding: 0 var(--space-5) var(--space-3);
  font-size: var(--text-xs);
  color: var(--ink-mute);
  font-family: var(--font-mono);
  line-height: var(--leading-relaxed);
  /* 修复 #CRIT-2026-09-21：display:flex + CJK word-break:normal 会让每个汉字独占一行。
     改为 block + word-break:keep-all + overflow-wrap:normal，
     三者必须同时设：去掉任何一个都会被浏览器默认行为（CJK 按字断）覆盖。
     之前误加 overflow-wrap:anywhere 又把 keep-all 覆盖了 → 仍逐字断行。 */
  display: block;
  word-break: keep-all;
  overflow-wrap: normal;
  hyphens: none;
}
.sidebar-fav-hint a,
.sidebar-fav-hint button.link-style {
  color: var(--accent);
  text-decoration: none;
  font-family: inherit;
  font-size: inherit;
}
.sidebar-fav-hint a:hover,
.sidebar-fav-hint button.link-style:hover { text-decoration: underline; }
/* SVG 图标：内联 SVG 无 width/height 会默认 100%×100% 拉伸到父容器，
   在 sidebar 窄容器里把警告三角放大到 ~200px。固定 14×14 像素 + 软色
   父元素已改为 block，这里用 inline-flex 保证 SVG 居中且不破坏文字流 */
.sidebar-fav-hint .fn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px; height: 14px;
  margin-right: var(--space-1);
  color: var(--ink-mute);
  vertical-align: -2px;
  flex-shrink: 0;
}

/* 收藏 / 已读侧栏在「一条记录都没有」时的紧凑引导行。
   之前侧栏和主区各渲染一个完整的 empty-state（同一个 ☆ 图标 + 同一句
   引导话），一屏里出现两块一模一样的空态。现在主区保留完整空态（大
   图标 + 完整说明 + 可点击的引导），侧栏只留一行轻量提示 —— 侧栏是
   导航区，不需要再抢一次视觉重心。 */
.sidebar-empty-note {
  padding: 0 var(--space-5) var(--space-4);
  font-size: var(--text-xs);
  color: var(--ink-mute);
  line-height: var(--leading-relaxed);
  /* 同 .sidebar-fav-hint：CJK 必须 keep-all，否则浏览器按字断行 */
  word-break: keep-all;
  overflow-wrap: normal;
  hyphens: none;
}

/* =========================================================================
   弹窗
   ========================================================================= */
.modal-backdrop {
  position: fixed; inset: 0;
  background: var(--overlay-modal);
  display: flex; align-items: center; justify-content: center;
  z-index: var(--z-modal); padding: var(--space-8) var(--space-5);
  animation: fadeIn var(--dur-fast) ease;
}
@keyframes fadeIn { from { opacity: 0; } }
.modal {
  background: var(--bg-elev);
  /* --radius-lg 的定义就是「弹窗 / 模态」——此前这里用 --radius(7px)，
     和同样属于弹窗的 .prl-confirm-dialog(--radius-lg) 对不齐。 */
  border-radius: var(--radius-lg);
  transition: background-color var(--dur-base) ease;
  max-width: 760px; width: 100%;
  max-height: 88vh;
  /* audit-2026-10-24 自适应显示：平板（769-1023，走此基线 modal）浏览器同样
     有 URL 栏，100vh/88vh 会算进收起态大视口；dvh 渐进增强，桌面两者相等。 */
  max-height: 88dvh;
  overflow-y: auto;
  box-shadow: var(--shadow-lg);
  animation: modalIn var(--dur-base) var(--ease-std-out);
  border: 1px solid var(--border);
}
@keyframes modalIn {
  from { transform: translateY(12px) scale(0.97); opacity: 0; }
  to   { transform: translateY(0)    scale(1);    opacity: 1; }
}

.modal-header {
  padding: var(--space-6) var(--space-7) var(--space-4);
  border-bottom: 1px solid var(--border-soft);
  display: flex; justify-content: space-between; align-items: flex-start; gap: 14px;
  min-width: 0;
}
.modal-header .mh-title {
  font-family: var(--font-serif);
  font-size: var(--text-3xl); font-weight: 600;
  line-height: var(--leading-heading); margin: 0; letter-spacing: 0.005em;
  overflow-wrap: anywhere;
  min-width: 0;
  /* 同 .dp-title：长标题在窄屏下拉平各行，避免末行孤零零一两个词 */
  text-wrap: balance;
}
.modal-header .mh-meta {
  font-family: var(--font-serif);
  font-style: italic; color: var(--ink-soft);
  font-size: var(--text-md); margin-top: var(--space-2);
}
.modal-close {
  font-size: var(--text-3xl); color: var(--ink-mute);
  padding: 0; line-height: var(--leading-none);
  width: 36px; height: 36px;
  margin-top: -2px;
  border-radius: var(--radius-sm);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.modal-close:hover { color: var(--ink); background: var(--bg-hover); }
/* iter 114 Phase 3：补 :active 按下反馈 */
.modal-close:active {
  background: var(--bg-hover);
  transform: scale(0.95);
  transition: transform var(--dur-fast);
}

.modal-body {
  padding: var(--space-5) var(--space-7) var(--space-6);
  font-size: var(--text-md); line-height: var(--leading-body);
  color: var(--ink);
  font-family: var(--font-serif);
  /* pretty：避免摘要末行只剩一个单词（孤字行） */
  text-wrap: pretty;
}
.modal-body p { margin: 0 0 0.6em; }
.modal-body p:last-child { margin-bottom: 0; }
/* 弹窗摘要里的排版标签已合并到「Abstract 排版标签」共用规则块 */

.modal-footer {
  padding: var(--space-3) var(--space-7);
  border-top: 1px solid var(--border-soft);
  display: flex; justify-content: space-between; align-items: center;
  background: var(--bg-soft);
}
.modal-footer .footer-meta {
  font-size: var(--text-xs); color: var(--ink-soft); /* iter 113 audit C1: modal-footer 是 --bg-soft 背景，ink-mute 普遍 < 4.5 */
  font-family: var(--font-serif); font-style: italic;
  display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.modal-footer .footer-actions { display: flex; gap: var(--space-2); }

/* =========================================================================
   加载、错误、空状态、回到顶部
   ========================================================================= */
/* 加载遮罩：perf 2026-10-23 改为**按需显示**。旧版默认全屏可见、init() 完成
   后 fade 350ms——数据内联页渲染近乎瞬时，遮罩反而成了每次页面切换的
   「闪一下全屏底色」的来源（用户诉求：切页不要有刷新感）。现在：
   - 默认 display:none（不占布局、不挡点击、屏幕阅读器也不朗读）；
   - app.js init() 开头武装 150ms 定时器，超时仍未就绪（favorites/read 要
     外链全量数据、或慢网络）才加 .visible 亮出 spinner；
   - init 完成 _teardownLoadingOverlay() 直接移除节点（不再有 350ms fade）；
   - showFatal() 失败路径手动加 .visible 强制亮出错误横幅。
   .hidden 类保留（旧页面 DOM 兼容 + 测试 wait_for_loaded 判据），语义 =
   强制隐藏。 */
.loading {
  position: fixed; inset: 0;
  display: none; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--space-4); background: var(--bg);
  z-index: var(--z-loading);
}
.loading.visible:not(.hidden) {
  display: flex;
}
.loading.hidden { display: none; }
.loading-spinner {
  width: 40px; height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 8%, transparent);
}
@keyframes spin { to { transform: rotate(360deg); } }
.loading-text {
  font-family: var(--font-serif);
  color: var(--ink-soft); font-size: var(--text-md); font-style: italic;
}
.loading-progress { font-family: var(--font-mono); color: var(--ink-mute); font-size: var(--text-xs); }

.empty-state {
  text-align: center;
  padding: var(--space-11) var(--space-6) var(--space-12);
  color: var(--ink-mute);
  display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
}
.empty-state .es-icon {
  width: 64px;
  height: 64px;
  display: inline-flex;
  align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-deep);
  margin-bottom: var(--space-1);
}
.empty-state .es-icon svg {
  width: 30px;
  height: 30px;
  display: block;
}
.empty-state .es-title {
  font-family: var(--font-serif);
  font-size: var(--text-xl);
  color: var(--ink-soft);
  font-style: italic;
  margin-top: 2px;
  /* balance：标题两行时上下两行字数尽量均衡，避免「XX / XX」式孤字行 */
  text-wrap: balance;
}
.empty-state .es-hint {
  font-size: var(--text-sm);
  color: var(--ink-mute);
  max-width: 380px;
  line-height: var(--leading-body);
  /* pretty：浏览器尽量避免行尾孤字。旧版默认换行会把
     「…只保存在浏览器缓存中」的「中」字单独甩到下一行，一屏里
     出现一个光秃秃的单字行。balance（标题也用）同理。 */
  text-wrap: pretty;
}
.empty-state .es-suggestions {
  display: flex; flex-wrap: wrap; gap: 6px; justify-content: center;
  margin-top: var(--space-1);
}
.empty-state .es-suggestions button {
  padding: 7px var(--space-3);
  font-size: var(--text-xs);
  font-family: var(--font-sans);
  color: var(--accent-deep);
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
  border-radius: var(--radius-pill);
  transition: background var(--dur-fast), color var(--dur-fast), transform var(--dur-fast);
  cursor: pointer;
  /* 触控目标 ≥32px：4px padding + 12px 文字 ≈ 24px，移动端容易误触 */
  min-height: 32px;
}
.empty-state .es-suggestions button:hover {
  background: var(--accent);  color: var(--text-on-accent);
  transform: translateY(-1px);
}
.empty-state .es-suggestions button:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 2px;
}
/* iter 114 Phase 3：补 :active 按下反馈（hover 已 translateY(-1px) 上浮） */
.empty-state .es-suggestions button:active:not(:disabled) {
  transform: translateY(0) scale(0.97);
  background: var(--accent);
  color: var(--text-on-accent);
  transition: transform var(--dur-fast);
}
/* 深色主题下 active accent 是浅色——文字仍要深色才能看清 */
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .empty-state .es-suggestions button:hover {
  color: var(--text-on-light-accent);
}

/* Phase 4 重构（iter 109）：搜索 0 结果时挂的"扩大搜索范围"按钮 —
   PRL/PRB 主页是 windowed K=30 天，按一下加载全量数据（~1.4/3.0 MB）并重搜。
   视觉比 .es-suggestions 按钮更醒目（边线 + 主色填充），让用户清楚这是数据扩展操作。*/
.expand-search-btn {
  margin-top: 14px;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  font-family: var(--font-sans);
  /* audit-2026-10-22 HIGH：静止态曾是 accent-deep 字压 accent 底（同色相深压深
     ≈1.4:1，6 个浅色主题全中招），与 hover 态的反白逻辑对齐——主色填充按钮
     统一用 --text-on-accent；暗色主题由下方覆盖换成 --text-on-light-accent。 */
  color: var(--text-on-accent);
  background: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 60%, transparent);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--dur-fast), transform var(--dur-fast);
  min-height: 34px;
}
.expand-search-btn:hover:not(:disabled) {
  background: var(--accent-deep);
  color: var(--text-on-accent);
  transform: translateY(-1px);
}
/* iter 114 Phase 3：补 :active 按下反馈 */
.expand-search-btn:active:not(:disabled) {
  transform: translateY(1px);
  background: var(--accent-deep);
}
.expand-search-btn:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 2px;
}
.expand-search-btn:disabled {
  opacity: 0.65;
  cursor: wait;
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .expand-search-btn {
  color: var(--text-on-light-accent);
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .expand-search-btn:hover:not(:disabled) {
  color: var(--text-on-light-accent);
}
.expand-search-note {
  margin-top: var(--space-3);
  font-size: var(--text-xs);
  color: var(--ink-mute);
  font-style: italic;
}

/* ---------- arXiv 日期分页（主页 arxiv 顶栏切换后的入口页） ---------- */
/* arxiv.html 主页：分页日期列表 + 跳每日静态页
   日期卡复用 .article-card 样式（与 PRL/PRB 文章卡视觉一致），
   这里只追加分页控件 + 日期卡细节微调。*/
.arxiv-date-card { cursor: pointer; }
.arxiv-date-card .ac-wd { color: var(--ink-mute); font-weight: 400; font-size: 0.92em; }

/* 分页控件（顶部 + 底部共用）
   既用于 arxiv 主页的「日期列表分页」，也用于每日页的「文章列表分页」 */
.pagination {
  display: flex; align-items: center; justify-content: center;
  gap: 6px; flex-wrap: wrap;
  margin: var(--space-4) 0;
  font-family: var(--font-sans);
}
.page-btn {
  min-width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 var(--space-2);
  background: var(--bg-elev);
  border: 1px solid var(--border-strong); /* 组82：控件边框 1.4.11（见 --border-strong 注释） */
  border-radius: var(--radius-pill); /* 2026-10-24：分页数字按钮胶囊化（active 实心 accent 更柔和） */
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast), transform var(--dur-fast);
}
.page-btn:hover:not(:disabled) {
  background: var(--bg-hover);
  border-color: var(--accent);
  color: var(--ink);
}
.page-btn:active:not(:disabled) { transform: scale(0.96); }
.page-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent); /* 与品牌 logo 文字同色，所有主题下都可见 */
  font-weight: 600;
  cursor: default;
}
/* dark / space / moss 主题下 accent 是浅色，active 文字要深色才能看清 */
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .page-btn.active {
  color: var(--text-on-light-accent);
}
.page-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.page-dots {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 24px; height: 34px;
  color: var(--ink-mute);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  user-select: none;
}
@media (max-width: 640px) {
  .page-btn { min-width: 34px; height: 34px; font-size: var(--text-xs); padding: 0 7px; }
  .page-dots { height: 34px; }
}

/* ---------- 每日静态页（prl/ / prb/ / arxiv/ 下的 {date}.html）横幅 ----------
   位于顶栏和主区之间，app.js 不会触碰这块区域（renderContent 只重写 #content，
   renderSidebar 只重写 #sidebar）。因此可以在模板里静态写 prev/next 链接。 */
.daily-banner {
  /* 2026-10-23 顶部统一：日期行与刊名带同宽同底色（不再居中卡片 + 上浮间距），
     两行拼成完整刊头；全宽、左内边距与顶栏同列。 */
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-3);
  margin: 0;
  padding: var(--space-4) var(--space-6);
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
  font-family: var(--font-sans);
}
.daily-banner-nav {
  display: flex; align-items: center; gap: var(--space-3);
  flex-wrap: wrap;
}
.daily-banner-date {
  /* 与视图页 .content-header h1 同字号（页面主标题只有一处、同一规格） */
  font-family: var(--font-serif);
  font-size: var(--text-4xl); font-weight: 600;
  margin: 0; line-height: var(--leading-tight);
  color: var(--ink);
  letter-spacing: .003em;
  min-width: 220px; text-align: center;
}
.daily-banner-btn {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 6px var(--space-3);
  font-size: var(--text-sm); color: var(--ink-soft);
  background: var(--bg-soft);
  border: 1px solid var(--border-strong); /* 组82：控件边框 1.4.11（见 --border-strong 注释） */
  border-radius: var(--radius-pill); /* 2026-10-24：上一日/下一日胶囊化，与顶栏控件同语汇 */
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast), transform var(--dur-fast);
}
/* fix audit 2026-10-25 组82：翻页胶囊此前唯一按压缩痕的是 .date-nav-btn（scale
   0.96）；同为「点了就跳」的日横幅按钮无任何 :active 反馈，触屏上点了像没响应。
   补同语汇的 scale（transition 行已纳入 transform）。 */
.daily-banner-btn:active:not(.disabled) { transform: scale(0.96); }
.daily-banner-btn:hover {
  background: var(--bg-hover);
  border-color: var(--accent);
  color: var(--ink);
  text-decoration: none;
}
.daily-banner-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.daily-banner-btn.disabled {
  opacity: 0.4; cursor: not-allowed; pointer-events: none;
  background: transparent;
}
.daily-banner-meta {
  display: flex; align-items: center; gap: 14px;
  font-size: var(--text-sm); color: var(--ink-mute);
}
/* 2026-10-23：.daily-banner-home（回主页按钮）已下线 —— 当时顶栏 brand-logo
   指向同一 URL，两个同源入口重复。（2026-10-24 起 brand-logo 全站改回首页，
   回期刊入口由顶栏当前刊按钮承担；下线理由对当时形态仍成立。） */
.daily-banner-count {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
@media (max-width: 720px) {
  /* 窄屏横幅改成 grid：日期与篇数同一行，上一日 / 下一日各贴左右。
     原来 meta（篇数）width:100% 会被 flex-wrap 挤到独立一行 —— 手机上
     「17 篇」孤零零挂在右下角，和上面的日期/翻日按钮都对不上，像是漏排的。
     grid-template-areas 让「日期 … 篇数」和「上一日 …… 下一日」各占一行。
     .daily-banner-nav 用 display:contents 把 prev/date/next 提升成 grid item
     （不改 HTML 结构，视图页 / 每日页共用同一份模板）。 */
  .daily-banner {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "date  count"
      "prev  next";
    align-items: center;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-3) 18px;
  }
  .daily-banner-nav { display: contents; }
  .daily-banner-date {
    grid-area: date;
    font-size: var(--text-xl);
    min-width: 0;
    text-align: left;
  }
  .daily-banner-meta {
    grid-area: count;
    width: auto;
    justify-self: end;
  }
  /* nav 里第一个 / 最后一个子元素分别是上一日 / 下一日按钮
     （日期是中间的 <h1>）。用 first/last 而不是 nth-of-type ——
     上一日可能是 <a>、下一日可能是 <span class="disabled">，标签类型不一致，
     nth-of-type 会串位。 */
  .daily-banner-nav > .daily-banner-btn:first-child { grid-area: prev; justify-self: start; }
  .daily-banner-nav > .daily-banner-btn:last-child  { grid-area: next; justify-self: end; }
}

.error-banner {
  margin: var(--space-3) 0; padding: 14px 18px;
  background: color-mix(in srgb, oklch(48.933% 0.139 29.1) 14%, var(--bg-elev));
  border: 1px solid color-mix(in srgb, oklch(48.933% 0.139 29.1) 40%, var(--border));
  border-radius: var(--radius);
  color: color-mix(in srgb, oklch(48.933% 0.139 29.1) 80%, var(--ink));
  font-size: var(--text-sm); line-height: var(--leading-relaxed);
}
.error-banner code {
  background: var(--overlay-faint);
  padding: 1px 5px; border-radius: var(--radius-sm); font-family: var(--font-mono);
  /* audit-2026-10-22 LOW：长命令 / 路径折行，不撑破 banner */
  overflow-wrap: anywhere;
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .error-banner {
  background: color-mix(in srgb, oklch(74.725% 0.0897 31.4) 14%, var(--bg-elev));
  border-color: color-mix(in srgb, oklch(74.725% 0.0897 31.4) 36%, var(--border));
  color: color-mix(in srgb, oklch(74.725% 0.0897 31.4) 85%, var(--ink));
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .error-banner code {
  background: var(--tint-faint);
}

/* =========================================================================
   组83 退役：「?」快捷键帮助弹窗（.shortcut-help / #shortcut-backdrop）——
   外壳双份（src/index.html + server/render/build_html.py）同批删除，快捷键
   全表单源移至「关于」视图页（views/about.js；键帽样式见上方 about 视图节的
   .ap-kbd-*）。历史注（audit-2026-10-23：.shortcut-btn 死规则已删、顶栏从未
   渲染鼠标入口、`?` 为唯一打开方式）随本段一并归档。
   ========================================================================= */

.back-to-top {
  position: fixed; right: var(--space-7); bottom: var(--space-7);
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--bg-elev);
  border: 1px solid var(--border-strong); /* 组82：控件边框 1.4.11（见 --border-strong 注释） */
  color: var(--ink-soft); font-size: var(--text-2xl);
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow);
  z-index: var(--z-fab); /* 组82：独立语义档位（值=原 --z-skip-link，零视觉变化） */
  opacity: 0; transform: translateY(8px);
  transition: opacity var(--dur-base), transform var(--dur-base), background var(--dur-fast), color var(--dur-fast);
  pointer-events: none;
}
.back-to-top.visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
/* fix audit 2026-10-25 组82：窄屏抽屉打开时 FAB 浮在遮罩上方（同为 fixed、
   --z-fab 50 < --z-modal 但抽屉是 .sidebar 布局内件，遮罩压不住它）——右下那颗
   圆钮正好挡在抽屉旁的可见内容上，点它 = 穿透遮罩滚页面，抽屉还开着。
   抽屉开着就收起 FAB（body.sidebar-open 由 app.js 开合，与 openSidebar 同源）。
   特异性 0,2,1 > .back-to-top.visible 0,2,0。 */
body.sidebar-open .back-to-top { opacity: 0; pointer-events: none; }
.back-to-top:hover {
  background: var(--accent);
  color: var(--text-on-accent);
  border-color: var(--accent);
  /* 2026-10-24：悬停时上浮 2px + 抬一层投影——浮动操作按钮的
     "可按下"反馈（.visible 已把 transform 纳入 transition，动画免费）。
     2026-10-25：卡片 hover 上浮因文字跳动已移除，本按钮是悬浮控件、
     无正在阅读的正文，保留上浮。 */
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .back-to-top:hover { color: var(--text-on-light-accent); }

/* =========================================================================
   响应式 — 抽屉式自适应
   断点：
     - 桌面（默认，≥1024px）：双栏 280px + flex 主区
     - 平板（768-1023px）：侧栏变抽屉，顶栏紧凑
     - 手机（<768px）：同抽屉 + 顶栏进一步精简、卡片堆叠
     - 小手机（<480px）：极致紧凑，弹窗全屏
   ========================================================================= */

/* ---------- 平板：1023px 以下侧栏转抽屉 ---------- */
@media (max-width: 1023px) {
  .layout { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed;
    top: var(--topbar-h);
    left: 0;
    width: 300px;
    max-width: 86vw;
    max-height: calc(100vh - var(--topbar-h));
    height: calc(100vh - var(--topbar-h));
    /* audit-2026-10-24 自适应显示：抽屉是 fixed 浮层，100vh（大视口）会把
       抽屉底部（日期列表末端）压进移动端 URL 栏下；dvh 随可见视口收高。
       放在 vh 行之后 = 渐进增强，桌面/基线环境 dvh == vh，零像素变化。 */
    max-height: calc(100dvh - var(--topbar-h));
    height: calc(100dvh - var(--topbar-h));
    z-index: var(--z-sidebar);
    border-right: 1px solid var(--border);
    /* 组127 L18：删 border-bottom:none ——全文件没有任何 .sidebar 规则设过
       border-bottom，这条复位无的放矢 */
    box-shadow: 0 12px 40px var(--overlay-mid);
    transform: translateX(-100%);
    /* 适配刘海屏底部 */
    padding-bottom: max(24px, env(safe-area-inset-bottom));
    /* 组116（WCAG 2.4.3）：关闭态抽屉只是被 translateX 挪出屏幕，内容仍可 Tab——
       375px 实测每日页收起抽屉内 121 个可聚焦节点连吃 Tab（focus 黑洞）、
       搜索页连日期 input 也进黑洞。openSidebar 的 trapFocus 只护开启态，
       关闭态由 CSS visibility:hidden 收口：不可聚焦也不可读屏。
       transform 过渡照常播放（visibility 延迟 --dur-slow 才翻，滑出动画
       不被打断）；.open 用 transition-delay:0s 让 visibility 立即翻回
       visible，滑入第一帧即渲染。 */
    visibility: hidden;
    transition: background var(--dur-base) ease, border-color var(--dur-base) ease,
      transform var(--dur-slow) var(--ease-std-out), visibility 0s linear var(--dur-slow);
  }
  .sidebar.open {
    transform: translateX(0);
    visibility: visible;
    transition-delay: 0s;
  }
  .sidebar-overlay { display: block; }
  .sidebar-overlay.visible { pointer-events: auto; }

  /* 抽屉开启时禁止 body 滚动 */
  body.sidebar-open { overflow: hidden; }

  .sidebar-toggle { display: inline-flex; }

  /* 组116：「跳到侧栏」skip-link 的目标是 #sidebar，≤1023 抽屉关闭态被
     visibility:hidden 收口后 Enter 跳过去只是把焦点丢进不可见容器（等于丢失）。
     home 页早有同款 display:none 先例（home 不渲染侧栏）；窄屏抽屉态同理由
     「顶栏侧栏按钮」承担跳转职责，skip-link 退场（桌面 ≥1024 常驻不受影响）。 */
  .skip-link--sidebar { display: none; }

  .content { padding: var(--space-6) 22px var(--space-11); }

  /* 顶栏紧凑 */
  .topbar { gap: var(--space-3); padding: var(--space-3) 18px; }
  /* 组127（全面审查 L19）：原注释写「≤768px 不显示副标题」，但这条规则实际在
     ≤1023 抽屉块里——平板宽度同样隐藏 .page-heading（顶栏只有字标）。注释随现值订正。 */
  .page-heading { display: none; }
  .global-search { width: 160px; margin-right: var(--space-2); }
  .global-search kbd { display: none; }
  /* 期刊按钮 ≥36px 触控 */
  .journal-switch { padding: 3px var(--space-1); }
  .journal-switch .journal-btn { padding: 5px var(--space-3); min-height: 36px; }
}

/* ---------- 手机：768px 以下顶栏精简 ---------- */
@media (max-width: 768px) {
  /* 顶栏高度收缩后大致 56px；JS 在 init() 用 ResizeObserver 把实测值写回 --topbar-h。
     抽屉定位/高度依赖此变量（见 ≤1023 块），所以顶栏变两行时抽屉能跟着下移。 */
  :root { --topbar-h: 56px; }

  /* 顶栏：两行布局
     第一行：sidebar-toggle + brand（flex:1 撑开）+ journal-switch
     第二行：topbar-actions（搜索图标 + 浏览/搜索/收藏/已读 + 主题，宽 100% 横向滚动兜底） */
  .topbar {
    flex-wrap: wrap;
    height: auto;
    min-height: var(--topbar-h);
    padding: var(--space-2) var(--space-3);
    gap: var(--space-2);
  }
  /* fix audit-2026-10-25 组94：窄屏下滑自动收起顶栏、上滑即回显（class 由
     core/init.js bindTopbarStash 拨动）。sticky 元素滚动中不占流内空间，
     translateY(-100%) 按自身盒高平移——两行（421-768）还是三行（≤420 字标
     恢复后）都正确，--topbar-h 无需参与。reduced-motion 由文件末尾全局块
     把 transition-duration 强制归零，此处不再单独守卫。 */
  .topbar { transition: transform 0.22s ease; }
  .topbar.topbar-stashed { transform: translateY(-100%); }
  /* 抽屉展开时 body overflow:hidden 锁死滚动，永远等不到「上滑」事件——
     此状态下兜底强制可见（收起态顶栏若仍藏着你，抽屉里的出口就没人看着了）。 */
  body.sidebar-open .topbar.topbar-stashed { transform: none; }
  .brand .logo { font-size: var(--text-3xl); }
  /* audit-2026-10-04 BUG-5：`.brand { flex: 1; min-width: 0 }` 让 brand 盒子被压到
     比 .logo 还窄（390px 实测：brand 71.14px < logo 自然宽 85.45px）。因为 .logo
     是 `flex-shrink: 0`，它不会跟着缩，于是**溢出 brand 盒子**并向右压到
     .topbar-nav 上 —— 表现为「文献阅读」被「首页」按钮盖住 8px（两两重叠实测
     OVERLAP 8x20px，360/414/430px 不复现，只有 390px 这类中间宽度中招）。
     修法：brand 不再参与压缩，让它保持内容宽度（min-width: max-content），
     多余空间由 nav 之后的元素消化；nav 自身 min-width:0 仍可被压缩，
     真放不下时 .topbar 的 flex-wrap 会把第二行整块换行。
     min-width 用 max-content 而非硬编码 px：logo 字号随断点变（--text-2xl/3xl），
     写死数值会在另一档字号下再次失配。 */
  .brand { flex: 0 0 auto; min-width: max-content; }
  /* audit-2026-10-24 自适应触控：.logo 是回首页的 <a>（2026-10-24 起全站
     统一；当时仅每日页），窄屏只有
     图标（21~23px 见方）——低于 WCAG 2.5.8 AA 的 24×24 下限，触屏难命中。
     ::before 把命中区撑到 36×36（与同排 .sidebar-toggle / .theme-toggle 同
     规格），不改布局：左右各借 ≤7px，正好落在顶栏 gap 8px 的空隙里，不会
     抢汉堡按钮的区域。透明伪元素无视觉，像素基线零影响。 */
  .brand a.logo { position: relative; }
  .brand a.logo::before {
    content: "";
    position: absolute;
    inset: 50% 50%;
    width: max(36px, calc(100% + 14px));
    height: 36px;
    transform: translate(-50%, -50%);
  }
  .journal-switch { flex-shrink: 0; }
  .topbar-actions {
    width: 100%;
    flex-shrink: 0;
    margin-left: 0;
    gap: 6px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .topbar-actions::-webkit-scrollbar { display: none; }

  /* 搜索框变图标按钮，展开成全宽下拉 */
  .global-search {
    width: 36px;
    padding: 0;
    border-color: transparent;
    background: transparent;
    margin-right: 0;
    overflow: hidden;
    justify-content: center;
    transition: width var(--dur-base) ease, background var(--dur-fast), border-color var(--dur-fast),
                padding var(--dur-base) ease, box-shadow var(--dur-fast);
    flex-shrink: 0;
  }
  .global-search input,
  .global-search .icon + input + kbd { display: none; }
  .global-search .icon { display: inline-flex; margin: 0; font-size: var(--text-lg); }
  /* 折叠态下 .global-search 整体只有 36×28，图标本身更小 —— 用 ::before 把命中区
     撑到 44×44（与本文件其它触屏按钮同一套做法）。只在折叠态生效：展开后 input
     已占满整行，再加透明命中区会盖住输入框左侧。 */
  .global-search:not(.expanded) .icon { position: relative; }
  .global-search:not(.expanded) .icon::before {
    content: "";
    position: absolute;
    inset: 50% 50%;
    width: 44px; height: 44px;
    transform: translate(-50%, -50%);
    background: transparent;
  }
  /* 展开：浮动覆盖整个第二行（不挤压其他 tab-btn/主题按钮）。
     topbar-actions 已是 width:100% 第二行，定位用它做参考。 */
  .topbar-actions { position: relative; }
  .global-search.expanded {
    position: absolute;
    /* 水平内缩 14→30px、上下留 5px：第二行左右各有 24px 的 mask-image 渐隐
       （见下方 data-scroll-state 组），旧值下胶囊边缘 + 3px 焦点环正好落进
       渐隐带，两端被"啃掉"、焦点环看着断成两截。30px = 24px 渐隐带
       + 5px 环外扩（outline 3 + offset 2）+ 1px 余量。 */
    inset: 5px 30px;
    width: auto;
    padding: 0 var(--space-3);
    border-color: var(--accent);
    background: var(--bg-elev);
    justify-content: flex-start;
    /* 与上面 .global-search:focus-within 同一约定：3px 实色 accent 环
       （WCAG SC 1.4.11 ≥3:1）。窄屏下这条规则会覆盖默认样式，必须同步改，
       否则移动端仍是 18% 混色环 = 1.26–1.43:1 的不合规版本。 */
    outline: 3px solid var(--accent);
    outline-offset: 2px;
    z-index: var(--z-dropdown);
  }
  .global-search.expanded input,
  .global-search.expanded .icon,
  .global-search.expanded kbd { display: inline-block; }
  .global-search.expanded .icon { margin-right: var(--space-2); }

  /* 标签栏简化（保证触控 ≥38px，第二行横向滚）
     min-height 是关键：tab-btn 仅靠 padding+字号在 12.5px 字号下高度只有 ~24px，
     设 min-height 后无论字号多大都不会太小（Apple HIG ≥44px 是理想值，
     但 5 个 tab + 主题按钮 + 搜索图标横向排在小屏会很挤，38px 是折中） */
  .tab-btn { padding: 7px var(--space-3); font-size: var(--text-sm); flex-shrink: 0; min-height: 38px; }
  .theme-picker { flex-shrink: 0; }
  .theme-toggle { width: 36px; height: 36px; }

  /* 第二行横向滚动 + 左右边缘淡出渐变（mask-image）提示用户可滚。
     滚动时由 JS 更新 data-scroll-state 进一步收缩遮罩，避免视觉上"被截"的错觉 */
  .topbar-actions {
    mask-image: linear-gradient(to right, transparent 0, oklch(0% 0 0) 24px, oklch(0% 0 0) calc(100% - 24px), transparent 100%);
    -webkit-mask-image: linear-gradient(to right, transparent 0, oklch(0% 0 0) 24px, oklch(0% 0 0) calc(100% - 24px), transparent 100%);
    padding-left: var(--space-2);
    padding-right: var(--space-2);
    /* 给 mask 渐变留出位置，否则滚动内容会被遮住部分视觉空间 */
  }
  .topbar-actions[data-scroll-state="start"] {
    mask-image: linear-gradient(to right, oklch(0% 0 0) 0, oklch(0% 0 0) calc(100% - 24px), transparent 100%);
    -webkit-mask-image: linear-gradient(to right, oklch(0% 0 0) 0, oklch(0% 0 0) calc(100% - 24px), transparent 100%);
  }
  .topbar-actions[data-scroll-state="end"] {
    mask-image: linear-gradient(to right, transparent 0, oklch(0% 0 0) 24px, oklch(0% 0 0) 100%);
    -webkit-mask-image: linear-gradient(to right, transparent 0, oklch(0% 0 0) 24px, oklch(0% 0 0) 100%);
  }
  .topbar-actions[data-scroll-state="idle"] {
    mask-image: none;
    -webkit-mask-image: none;
  }
  /* audit-2026-10-22 HIGH：主题菜单打开时必须摘掉 mask——.theme-menu 是
     topbar-actions 内的绝对定位弹层，弹出在第二行下方 = 落在 mask 绘制区外，
     被整体裁成透明（菜单 display:flex、几何正确，但完全不可见不可点，
     移动端主题切换因此不可用）。:has() 特异性 (0,3,0) 压过上面三条
     data-scroll-state 规则。 */
  .topbar-actions:has(.theme-menu:not([hidden])) {
    mask-image: none;
    -webkit-mask-image: none;
    /* audit-2026-10-24：10-22 那次只摘了 mask，但本行 3661 还有 overflow-x:auto
       （visible 配 auto 时 overflow-y 也按 auto 计）——.theme-menu 是相对本行定位的
       绝对弹层，弹到第二行（38px 高）外就整块被滚动盒裁剪：DOM 在、display:flex、
       几何正确，但 375px 实测菜单区域 elementFromPoint 命中的是正文卡片，移动端
       主题菜单依旧不可见不可点，且 417px 的 scrollHeight 还给第二行掺出一条
       看不见尽头的纵向幽灵滚动。打开菜单的同一时刻连 overflow 一起放行；
       ≤420px 第二行内容本就不需要横滚（337px 装得下 4 tab+主题钮），代价≈0。 */
    overflow: visible;
  }

  .content { padding: 18px var(--space-4) 90px; }

  /* 主区标题在手机上下堆叠 */
  .content-header { flex-direction: column; align-items: flex-start; gap: 10px; }
  .content-header h1 { font-size: var(--text-3xl); }
  .content-header .kb-hint { display: none; }   /* 触屏用户用不到 j/k，节省空间 */

  /* 抽屉跟随顶栏高度（用 CSS 变量，不再硬编码） */
  .sidebar {
    width: min(86vw, 320px);
  }

  /* fav-notice 在窄屏紧凑一些 */
  .fav-notice { padding: 10px 14px; font-size: var(--text-sm); line-height: var(--leading-relaxed); }
  .fav-notice .fn-icon { font-size: var(--text-lg); line-height: var(--leading-relaxed); }

  /* modal：≤767px 统一 bottom-sheet（避免普通弹窗在窄屏被截）
     横屏手机的进一步适配见 @media (max-height: 500px) 块 */
  .modal-backdrop {
    padding: 0;
    align-items: flex-end;
  }
  .modal {
    max-width: 100%;
    width: 100%;
    max-height: 92vh;
    /* audit-2026-10-24 自适应显示：bottom-sheet 贴底对齐，100vh 大视口下
       92vh 会把顶部裁到 URL 栏后面；dvh 随可见高度。桌面 dvh == vh 零变化。 */
    max-height: 92dvh;
    border-radius: 14px 14px 0 0;
    animation: modalInMobile var(--dur-slow) var(--ease-std-out);
  }
  @keyframes modalInMobile {
    from { transform: translateY(100%); opacity: 0.6; }
    to   { transform: translateY(0);    opacity: 1; }
  }
  .modal-header { padding: 18px 22px 14px; }
  .modal-header .mh-title { font-size: var(--text-2xl); }
  .modal-body { padding: var(--space-4) 22px var(--space-5); }
  .modal-footer {
    padding: var(--space-3) var(--space-4);
    gap: var(--space-2);
    /* 适配刘海屏 home indicator */
    padding-bottom: max(12px, env(safe-area-inset-bottom));
  }
  .modal-footer .footer-meta { font-size: var(--text-xs); }

  /* 卡片在手机端更紧凑 */
  .article-card { padding: 14px var(--space-4) var(--space-3); }
  .ac-abstract { font-size: var(--text-sm); }

  /* 卡片底部按钮变紧凑（确保触控 ≥38px） */
  .ac-footer { flex-wrap: wrap; gap: var(--space-2); padding-top: var(--space-2); }
  .ac-footer .pub-info { width: 100%; margin-bottom: 2px; }
  .ac-footer .actions { width: 100%; flex-wrap: wrap; }
  .icon-btn { padding: var(--space-2) var(--space-3); font-size: var(--text-xs); min-height: 38px; }
  /* 组78：紧凑 padding 下两态实测最大 74.0 / 83.2px，桌面档 68/78 兜不住，再钉一档 */
  .article-card .icon-btn.fav { min-width: 76px; }
  .article-card .icon-btn.read { min-width: 86px; }
  .date-nav-btn { width: 40px; height: 40px; }

  /* 回到顶部按钮位置调整，避免遮挡内容 */
  .back-to-top { right: var(--space-4); bottom: var(--space-4); width: 44px; height: 44px; }
}

/* 横屏手机 / 窄高视窗：modal 全屏 + sidebar 更窄 */
@media (max-width: 920px) and (max-height: 500px) {
  .modal-backdrop { padding: 0; }
  .modal { max-height: 100vh; max-height: 100dvh; border-radius: 0; }
}

/* ---------- 小手机：480px 以下极致紧凑 ---------- */
@media (max-width: 479px) {
  .topbar { padding: var(--space-2) 10px; gap: 6px; }
  .brand .logo { font-size: var(--text-3xl); }
  /* BUG-5 续：brand 改成 flex:0 0 auto 后不再被压缩，390px 下 nav 会被挤到第二行
     （顶栏实测从 103px 涨到 145px，多占 42px 垂直空间）。这里把 nav 的横向开销
     收回来，让第一行重新装得下：gap 12→8、期刊按钮 padding 12→9px。
     触控高度不变（min-height 仍由 768 档的 36px 兜底）。 */
  .topbar-nav { gap: var(--space-2); }
  .topbar-nav .journal-btn { padding: 5px 9px; }
  /* fix audit-2026-10-25 组94：最小屏恢复站点字标（用户令「网站标题还是需要保留显示」）。
     2026-10-23 曾在此用 clip 隐藏 .logo-text 把顶栏压回 2 行（390px 实测 140 vs 103px，
     第一行需 36+117+221+12+28=414px 才装得下整条）。代价是手机上站点名整体消失，
     观感像换了一个站——不可接受。恢复后顶栏钉在顶部时多占一行（375 实测 ~141px），
     垂直空间由本批新增的「下滑自动收起」（≤768 块 .topbar-stashed）换回：
     栏越高，收起越值得。clip 一并撤销后 logo 的可访问名称回到文本本身，
     不再依赖隐藏文本撑名称。 */
  .sidebar-toggle { width: 36px; height: 36px; }
  .theme-toggle { width: 36px; height: 36px; }
  .tab-btn { padding: 5px var(--space-2); font-size: var(--text-xs); }

  .content { padding: 14px var(--space-3) 90px; }
  .content-header h1 { font-size: var(--text-2xl); }

  /* ch-left 在小屏允许换行（title + 日期导航不会挤在一起） */
  .content-header .ch-left { flex-wrap: wrap; gap: var(--space-2); }

  /* section 徽章放标题下 */
  .ac-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }
  .ac-section { margin-top: 0; align-self: flex-start; }
  /* 2026-10-24 窄屏密度：衬线标题在 ≤479 仍是 18.4px，390px 宽的手机上一张卡
     标题占 3~4 行、整卡近两屏，列表信息密度塌；首页聚合卡却是 14px——同一站
     两种卡片观感。降到 text-lg，≤380 再降 text-md 与首页卡片同规。 */
  .ac-title { line-height: var(--leading-heading); font-size: var(--text-lg); }
  .ac-authors { margin-bottom: var(--space-2); }
  /* audit-2026-10-22 MED：必须写成 .ac-abstract.clamp——基础裁切规则是
     .ac-abstract.clamp（0,2,0，2427 行），单写 .ac-abstract（0,1,0）特异性
     输掉，4 行意图此前从未生效（实际永远 5 行）。 */
  .ac-abstract { line-height: var(--leading-relaxed); }
  .ac-abstract.clamp { -webkit-line-clamp: 4; line-clamp: 4; }
  /* fix audit-2026-10-25 组93 窄屏可读性：卡片角标（PRL 编号 110404 / arXiv
     分类 cs.RO）走 --text-2xs=10.6px 等宽字，375/390 手机实测肉眼难辨小号数字。
     提到 text-xs（与弹窗 .mh-section 同档），卡片/独立阅读页两处角标统一。
     选择器带 .article-card/.dp-article 前缀是为压过基础规则的同特异性（后者
     在文件前部），media 块内按文件序后者胜。 */
  .article-card .ac-section,
  .dp-article .dp-section { font-size: var(--text-xs); }

  /* fix audit-2026-10-25 组111 窄屏可读性收口（组93 未竟的同族）：手机上还
     活着的 10.6px 角标/计数小字——卡片期刊角标 .ac-journal-tag（首页/收藏/
     已读/搜索卡上的 PRL/PRB/ARXIV 白字徽章，组93 注释明言「收藏/已读视图的
     卡片上多出的小期刊标签」，与 .ac-section 同判据）、抽屉刊组徽章
     .sjg-logo、抽屉头与月份行右侧计数「N 篇 / N 天」（.count /
     .month-total）。全部提到 xs：与同块内 cjg-logo 的 ≤479 档同值，
     「越窄屏字越小」的方向就此抹平。基础规则特异性与本块同为选择器原形、
     位置在前，media 块内按文件序后者胜。 */
  .ac-journal-tag,
  .sidebar-journal-group .sjg-logo,
  .sidebar-header .count,
  .sidebar-month .month-total { font-size: var(--text-xs); }

  /* fix audit-2026-10-25 组111：卡片上 arXiv ID 复制钮实测 121×20（padding
     1px 上下），低于 WCAG 2.5.8 的 24px 下限且无 ::before 外扩（组82 的 44px
     名单未含它）。抬 min-height：全局 border-box 下 padding 已含在内，外观
     仅 +4px；.pub-info 是 inline-flex + align-items:center，加高自动居中、
     不推挤同行。::before 方案不可用——它落在收藏/日期等可点行中间会与他物
     命中区重叠误触（组82 注释同款教训，列表项用真实 min-height）。 */
  .arxiv-id { min-height: 24px; }

  /* 弹窗已在 ≤767px 走 bottom-sheet；这里只补 padding 微调 */
  .modal-header { padding: 18px 18px 14px; }
  .modal-body { padding: var(--space-4) 18px var(--space-5); }
  .modal-footer { padding: var(--space-3) 18px; flex-wrap: wrap; gap: 10px; }

  .filter-form { padding: var(--space-3) var(--space-4); }
  .sidebar-month, .date-item-btn { padding-left: 18px; padding-right: var(--space-4); }
  .sidebar-header { padding: 14px var(--space-4) var(--space-2); }

  /* 每日页横幅 ≤479px：布局由 ≤720px 的 grid 规则接管（日期 + 篇数一行，
     上一日 / 下一日一行），这里只做更紧的 padding 与按钮尺寸。
     旧的列布局（日期独占一行 + 翻日按钮一行 + 篇数再一行）会把「N 篇」
     甩到第三行，读起来像漏排的元素。 */
  .daily-banner {
    /* ≤479px 由「四角对齐」改「两行居中」：≤720 的 grid 把日期/篇数/
       上一日/下一日钉到四个角，手机上中间空一大段；最新一天「下一日」
       置灰时右端孤悬一枚灰胶囊，像漏排。改回 flex：nav 仍是 display:contents
       （≤720 处已设），prev/日期/next/count 四个提升项按 order 重排成
       「日期 篇数 / ‹上一日 下一日›」两行、各自行内居中。
       ::after 是占满整行的零高断行块（order 落在 count 之后、按钮之前）——
       没有它，360/390 行宽足够时 prev 会挤回第一行、next 单独掉到第三行
       （实测三行、横幅涨到 109px）。断行后翻页对永远成行成对。
       320px 实测：日期+篇数 ≈285 ≤ 内容宽 296，第一行放得下。 */
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    text-align: center;
    padding: var(--space-3) var(--space-3);
    gap: 0 var(--space-2);
  }
  .daily-banner::after {
    /* 断行块自带两行间距（容器 row-gap=0，否则断行块自己占一行、
       上下各来一次 row-gap，横幅白涨 8px） */
    content: "";
    flex-basis: 100%;
    height: var(--space-2);
    order: 1;
  }
  .daily-banner-date { order: -2; text-align: center; }
  .daily-banner-meta { order: -1; width: auto; }
  .daily-banner-nav > .daily-banner-btn { order: 2; }
  .daily-banner-btn {
    padding: var(--space-2) var(--space-3); font-size: var(--text-sm);
    min-height: 36px;
  }

  /* 跨期刊分组（收藏/已读视图）—— 在小屏紧凑 */
  .content-journal-group { gap: 10px; padding: 14px 0 10px; margin: 18px 0 10px; }
  .content-journal-group .cjg-logo { padding: 3px var(--space-2); font-size: var(--text-xs); margin-left: 10px; }
  .content-journal-group .cjg-name { font-size: var(--text-md); }
  /* fix audit-2026-10-25 组93：原此行把分组头 meta（「N 篇 · 最近更新 …」）
     降到 2xs=10.6px——低于桌面基础 text-xs，越窄屏字越小，手机上收藏/已读分组头
     副行反而最难读。撤掉降档，继承基础 xs。 */

  /* fix audit-2026-10-25 组93：抽屉提示条「导出备份」（collection.js
     _buildSidebarHint → .sidebar-fav-hint .link-style）375 实测 47×24——
     踩在基础 min-height:24 的 WCAG 下限上，触屏点按偏小。padding+等量负
     margin 把命中区撑到 ~36×63：负 margin 抵消占位，排版零位移、外观不变；
     横向 −8px 落在 .sidebar-fav-hint 自身 20px 内边距里，不与他物争。
     min-height 需一并抬到 36——全局 border-box 下它原先吞掉 12px padding
     （实测 30px），抬后 36px 达标。 */
  .sidebar-fav-hint .link-style {
    padding: 6px 8px;
    margin: -6px -8px;
    min-height: 36px;
  }
}

/* ---------- 极窄屏：380px 以下（iPhone SE 2 / 12 mini / 13 mini 等） ---------- */
@media (max-width: 380px) {
  /* 顶栏元素再缩一档，避免被截 */
  .topbar { padding: var(--space-2) 10px; gap: 5px; }
  .brand .logo { font-size: var(--text-2xl); }
  /* 同 BUG-5：logo 字号在这档更小，brand 仍必须以内容宽度为准，不能被压窄到
     比 logo 还窄（否则换行/溢出问题在这档复发）。 */
  .brand { flex: 0 0 auto; min-width: max-content; }
  .journal-switch .journal-btn { padding: var(--space-1) 9px; font-size: var(--text-2xs); min-height: 34px; }
  .sidebar-toggle { width: 36px; height: 36px; }
  .theme-toggle { width: 36px; height: 36px; }
  .tab-btn { padding: 6px var(--space-2); font-size: var(--text-xs); }

  .content { padding: var(--space-3) 10px 90px; }
  /* 原为 text-3xl——与 ≤479 档的 text-2xl 倒挂（屏越窄标题越大），
     修正为同值下调档，档位回到单调。 */
  .content-header h1 { font-size: var(--text-2xl); }

  /* 卡片 */
  .article-card { padding: var(--space-3) 14px 10px; }
  .ac-title { font-size: var(--text-md); }
  /* audit-2026-10-22 MED：同上，.clamp 提权让 3 行意图真正生效 */
  .ac-abstract.clamp { -webkit-line-clamp: 3; line-clamp: 3; }

  /* 弹窗 padding 收紧 */
  .modal-header { padding: var(--space-4) var(--space-4) var(--space-3); }
  .modal-body { padding: 14px var(--space-4) 18px; }
  .modal-footer { padding: 10px var(--space-4); gap: var(--space-2); }

  /* 每日页横幅更紧凑（行距由 ≤479 块的 ::after 断行块承担，
     这里只留列距；改回两值会把行距翻倍） */
  .daily-banner { padding: 10px var(--space-3); gap: 0 var(--space-2); }
  .daily-banner-btn { padding: 7px 10px; font-size: var(--text-xs); }

  /* 分页按钮更紧凑（≤640px 已是 30px；这里再压） */
  .page-btn { min-width: 32px; height: 32px; font-size: var(--text-xs); padding: 0 5px; }
  .page-dots { height: 28px; min-width: 18px; font-size: var(--text-xs); }

  /* fav-toolbar 按钮更紧凑 */
  .fav-toolbar .icon-btn { padding: 6px var(--space-2); font-size: var(--text-xs); }

  /* 空状态垂直空间收紧 */
  .empty-state { padding: var(--space-8) var(--space-4) 50px; }
  .empty-state .es-icon { width: 52px; height: 52px; }
  .empty-state .es-icon svg { width: 24px; height: 24px; }

  /* 抽屉在小屏留点边距，避免完全顶满 */
  .sidebar { width: min(90vw, 320px); }
}

/* ---------- 窄顶栏适配：标签栏在窄屏下变可滚动 ---------- */
@media (max-width: 1023px) {
  .topbar-actions { flex-shrink: 1; }
  .topbar-actions .tab-btn { white-space: nowrap; }
}

/* ---------- 桌面/平板窄边：769-1200px 顶栏让一步（BUG-6 + BUG-8）----------
   两个症状，同一个根因（顶栏在 769-1100 是单行不换行，而内容比可用宽度多零点
   几像素，内层 [role=tablist] 又是 min-width:auto 的刚性 flex item）：
   - 1024-1038px：溢出 6px，肉眼可见横向滚动条（BUG-6）
   - 769px：溢出 0.61px，但 documentElement.scrollWidth 上取整成 770 > 769，
     同样出现 1px 横向滚动条（BUG-8，纯亚像素 round 问题，截图完全看不出来）
   根因：.view-tabs 允许收缩（min-width:0），但内层 [role="tablist"] 没声明
   min-width，默认 min-width:auto 解析成 min-content —— 4 个定宽 tab 缩不下去。

   修法只压缩顶栏 actions，不动 1023 的侧栏断点：1024 是常见桌面宽度，侧栏应
   保持静态两栏而不是退回抽屉，只让顶栏让步。范围原取 769-1100：769 以上顶栏都
   是单行不换行（≤768 才 wrap 成两行），1100 以上有富余——组108 加 chip 后
   富余账收窄，上界随迁 1200（本块末注有账）。
   不影响 375 / 768 / 1280 三个视觉基线视口。
   2026-10-25 站点总标题更名「GUAN 文献阅读」：字标 +19px 把 769 下界的余量
   吃穿（重新溢出 1px），tab-btn 横向 padding 11→10px 让出 6px 余量复原。
   组108 续（2026-10-25）：主导航加「卡片阅读」入口（+~64px，nav 是
   min-width:max-content 刚性件）→ 1024 档 .topbar-nav 内溢 13px、chip 溢出
   nav 盒压进搜索框领地（组84 幽灵绘制同型病灶）。本带继续向 actions 要空间：
   搜索框 168→144（−24px）、view tab 横向 padding 10→8（4 枚 ×2 侧 ×2px
   =−16px），合计 −40px，1024 下界余量回到 ~27px。769-1023 两行带第二行同获
   富余不受损。上界 1100→1200：chip +74px 的账在 1101-1180 同样成立——探针
   实测旧上界下 1101 内溢 40px（reader-entry×global-search 交叠 16x36）、
   1150 内溢 23px；让一步配方随宽度线性失效点实测在 ~1185，取整封到 1200。
   ≥1280（视觉基线视口）零波及。 */
@media (min-width: 769px) and (max-width: 1200px) {
  .global-search { width: 144px; margin-right: var(--space-2); }
  .global-search kbd { display: none; }
  .topbar-actions { gap: var(--space-1); }
  .view-tabs > [role="tablist"] { gap: 2px; }
  .view-tabs .tab-btn { padding: 6px 8px; }
}

/* ---------- 769-1023px：顶栏两行化（fix audit-2026-10-25 组 84）----------
   组83 加第 4 个 view tab「关于」(+47.5px) 后，本带「单行塞八件」崩坏：
   汉堡/字标/首页+3 刊按钮/搜索框/4 view tabs/主题钮 ≈1020px 刚性内容塞不进
   769-1023 单行。实测三症状、每日页/prl-main/home 三页一致：documentElement
   溢出 27px（769 档确定性红，BUG-8 口径 0 才为绿）；「关于」被裁到视口外点
   不到（right=795.6 > 769）；期刊组被 min-content 压成 163px 盒后按钮幽灵
   绘制叠在搜索框上（水平重叠 168px）——与 ≤768 的 BUG-5（brand 幽灵压 nav）
   同病。修法即 ≤768 已验证的配方扩到本带：.topbar flex-wrap + height:auto，
   brand / topbar-nav 以 min-width:max-content 退出压缩队列，topbar-actions
   整体换行为第二行；两行各 margin-left:auto 右缘对齐（第一行 = 汉堡+字标+
   期刊组，第二行 = 搜索框+view tabs+主题）。--topbar-h 由 detail.js 既有
   _topbarRO 实测回写（119px），抽屉/banner 的 sticky 偏移自动跟随，84.R3b
   锚定这条同步链。1024-1200 单行靠让步档压缩仍装得下（组108 加 chip 后实测
   富余 ~27px），上面既有让步档不动；375 / 768 / 1280 三个视觉基线视口零影响。 */
@media (min-width: 769px) and (max-width: 1023px) {
  .topbar { flex-wrap: wrap; height: auto; min-height: var(--topbar-h); }
  .brand { min-width: max-content; }
  .topbar-nav { flex-shrink: 0; min-width: max-content; margin-left: auto; }
  .topbar-actions { margin-left: auto; }
}

/* ---------- 横屏手机 / 窄窗口的优化 ---------- */
@supports (padding: max(0px)) {
  @media (max-width: 768px) {
    /* 用 env(safe-area-inset-*) 适配刘海屏 */
    .topbar { padding-left: max(14px, env(safe-area-inset-left)); padding-right: max(14px, env(safe-area-inset-right)); }
    .content { padding-bottom: max(90px, calc(80px + env(safe-area-inset-bottom))); }
    .back-to-top { bottom: max(16px, env(safe-area-inset-bottom)); right: max(16px, env(safe-area-inset-right)); }
  }
}

/* =========================================================================
   尊重用户的减少动画偏好
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .icon-btn:hover { transform: none; }
  .date-nav-btn:hover:not(:disabled) { transform: none; }
  /* 2026-10-24：.brand .logo:hover 的 translateY 上浮与 transition 已整体移除
     （iter 114 的 reduced-motion 兜底规则随之退役——基础规则不再动，无需再拦）。
     2026-10-25：.article-card:hover 的 transform:none 兜底同样退役——hover 上浮
     已从基础规则移除（位移带动文字跳动、干扰阅读）。 */
  .empty-state .es-suggestions button:hover { transform: none; }
  .expand-search-btn:hover:not(:disabled) { transform: none; }
  /* fix audit-2026-10-22 LOW：上面的全局 0.001ms 规则把 loading spinner 也冻成
     静止圆环——加载态"看起来卡住了"。给 spinner 保留一个慢速旋转（2.4s 一圈，
     对前庭敏感用户足够温和），用 !important + 更高 specificity 盖过 * 规则。 */
  .loading-spinner { animation: spin 2.4s linear infinite !important; }
}

/* =========================================================================
   三刊聚合首页（home.html）
   - body[data-page="home"] 走 .home-* 布局
   - 三栏 grid + 每栏 5 张完整卡（复用 .article-card，自带 journal-aware 颜色）
   - 1023px 以下转单栏；380px 以下极致紧凑
   组87（2026-10-25）：页首 .home-header（h1「三刊每日聚合」+「共 N 篇 · 数据
   每日更新」）连同其三条规则块退役——文案与顶栏刊名带、三栏 hs-meta 三重重复
   （见 views/home.js 同组注释）；原占位由 #content 顶部的 .home-section-header
   行高直接接班，无需补间距。h2.hs-name 见下方 margin 中和注释。
   ========================================================================= */
.home-section { display: flex; flex-direction: column; min-width: 0; }
/* audit-2026-10-23：原 margin-top: 28px 是栅格承诺（任何 padding/margin/gap 必须取自
   --space 刻度）内唯一的半档违例——24→32 之间本无 28 档，这正是文件头注释要消灭的形态。
   归到 --space-6；视觉差 4px/处，实测 108 项基线 diff ≤0.012% 全在 1% 阈内，无需重生成。 */
.home-section + .home-section { margin-top: var(--space-6); }

.home-section-header {
  display: flex; align-items: baseline; gap: var(--space-2);
  padding: 0 2px var(--space-2);
  border-bottom: 1px solid var(--border-soft);
  margin-bottom: var(--space-3);
}
.home-section-header .hs-text {
  flex: 1; min-width: 0;
}
.home-section-header .hs-name {
  font-family: var(--font-serif);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--ink);
  /* 组87：div → h2 后中和 UA 默认外边距，行内几何与 div 时代逐像素一致
     （原 h1 所在的 .home-header 块已退役，本条是全页唯一标题元素）。 */
  margin: 0;
}
.home-section-header .hs-meta {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: var(--text-xs);
  color: var(--ink-mute);
  margin-left: 6px;
}
.home-section-header .hs-more {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  color: var(--ink-mute);
  text-decoration: none;
  white-space: nowrap;
  padding: 3px var(--space-2);
  border-radius: var(--radius-sm);
  transition: background var(--dur-fast), color var(--dur-fast);
  flex-shrink: 0;
}
.home-section-header .hs-more:hover {
  background: var(--bg-hover);
  color: var(--accent);
}
.home-section-header .hs-more:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* 栏底「更多」出口（组 81 · 2026-10-25）：滚到三栏底部时就近跳回刊页，
   与栏头 .hs-more 同 href、不同形态——居中胶囊，比栏头的小字链接更像一个
   按钮。DOM 上该类只出现在 .home-section-footer 里，栏头作用域的
   `.home-section-header .hs-more` 规则不会串到这里；打印隐藏由 @media print
   的裸 .hs-more 选择器覆盖（导航链上纸即死控件）。 */
.home-section-footer {
  display: flex;
  justify-content: center;
  margin-top: var(--space-3);
}
.home-section-more {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--link);
  text-decoration: none;
  white-space: nowrap;
  padding: var(--space-1) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.home-section-more:hover {
  background: var(--bg-hover);
  color: var(--accent);
  border-color: var(--accent);
}
.home-section-more:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* 桌面：横向三栏并排；每栏独立的 article-list（垂直堆卡片） */
.home-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
  align-items: start;
  /* fix audit-2026-10-23：桌面三栏不再无界放宽。实测卡片宽随视口线性增长
     （1440→443px、1700→529px、2048→645px、2560→816px），摘要单行字符数
     63→82→104→132 —— 与 .content 行长上限（45~75 字符，理想 ~66）完全脱轨，
     2560px 下卡内文字变成两条 132 字符的长横线。与 ≤1023px 单列分支同样
     用「封顶 + margin-inline:auto」：多出的空间变成两侧对称留白，行长
     恒定 ≈84 字符（上限比 75 稍宽，三栏扫读卡片是块状条目而非连续散文）。 */
  max-width: 1660px;
  margin-inline: auto;
}
/* 组87：原 body[data-page="home"] .home-header 居中规则随页首块退役——
   .home-grid 自身已带 max-width:1660px + margin-inline:auto（上方），三栏
   与视口再无第二段需要同轴的内容。 */
.home-grid > .home-section { margin-top: 0; }
.home-grid > .home-section + .home-section { margin-top: 0; }
.home-grid .article-list { gap: 10px; }
.home-grid .article-card { padding: 14px 18px 11px; }
.home-grid .article-card .ac-title { font-size: var(--text-md); }
.home-grid .article-card .ac-abstract { font-size: var(--text-sm); -webkit-line-clamp: 4; }

/* 平板：1023px 以下三栏转单栏 */
@media (max-width: 1023px) {
  .home-grid {
    grid-template-columns: 1fr;
    gap: var(--space-5);
    /* 单列时恢复行长上限。桌面三栏各 ~390px（约 47 字符）本来就在舒适区，
       但 1023px 以下塌成单列后卡片会一路撑到 736px —— 实测 768px 视口下
       摘要单行 91 字符，超过 75 的舒适上限。居中后两侧留白，比让行长失控好。 */
    max-width: calc(var(--measure) + 2 * var(--space-6));
    margin-inline: auto;
  }
}

/* fix audit-2026-10-25 组100：宽屏整版缩放档——首页三栏在 ≥1740px 触到
   1660px 封顶后，此前视口再宽只剩两侧留白增长，1920 与 3440 画面一模一样，
   「大屏」与「小屏」零差别（用户令优化宽屏自适应）。
   机制选 `zoom`（CSS Viewport 1 标准化后 Chrome 128+/FF 126+/Safari 一直支持；
   旧引擎降级为封顶现状，graceful）：缩放 .home-grid 子树内的**全部**长度
   （rem 字号刻度 + px 卡 padding/gap/角标），字号与栅格上限同比放大，
   「每行字符数」不变——行长 84 字符的老承诺原样成立，物理尺寸却随屏幕长大。
   为什么不改 :root 令牌表：自定义属性在定义处（:root）一次性求值后按
   computed value 继承，把 var(--type-scale) 写进 --text-* 的定义里，后代改
   --type-scale 不会触发重算——想让每页独立缩放只剩「逐 token 重列 calc」一条
   手抄路，正是组80 禁掉的形态。zoom 一行顶八行且 px 硬编码一并覆盖。
   顶栏 / 详情面板是 .home-grid 的兄弟子树，不在缩放面内；详情面板展开时
   内容列被压回 1fr 可用宽（封顶只设上界不强制），无溢出。
   档位锚定：1700px = 已登记 2xl 超宽断点（1660 封顶 + 80 padding ⇒ 1740px
   起冻结，从 1700 起步长衔接无跳变）；2560px = 4K/大屏第二档（lint-tokens
   登记表同步新增）。 */
@media (min-width: 1700px) {
  .home-grid { zoom: 1.05; }
}
@media (min-width: 2560px) {
  .home-grid { zoom: 1.12; }
}

/* 极窄屏：380px 以下极致紧凑 */
@media (max-width: 380px) {
  .home-section-header .hs-name { font-size: var(--text-md); }
  .home-grid .article-card { padding: var(--space-3) 14px 10px; }
  .home-grid .article-card .ac-title { font-size: var(--text-md); }
}

/* =========================================================================
   触屏设备：去掉 hover 触发的位移/动画，避免误触
   ========================================================================= */
@media (hover: none) {
  .article-card:hover { box-shadow: var(--shadow-sm); border-color: var(--border); }
  .article-card:hover::before { opacity: 0; width: 3px; }
  .icon-btn:hover { transform: none; }
  .date-nav-btn:hover:not(:disabled) { transform: none; }
  /* 组127（全面审查 L18）：删 .theme-toggle:hover { transform:none } ——主题切换钮
     的 :hover 从组96 起只改 background/color/border，基线根本没有 transform 态，
     这条「撤销」是空操作；旁边的 icon-btn/date-nav 同款守卫是有效的，别被它骗了。 */
  /* 触屏上的点击反馈用 :active 而非 :hover */
  .article-card:active { transform: scale(0.995); }
  .icon-btn:active { background: var(--bg-hover); }
}

/* =========================================================================
   触屏设备：icon 按钮的命中区扩大到 ≥44×44（WCAG 2.5.5 / Apple HIG）
   用 ::before 不可见 hit area 技术——视觉尺寸不变，按钮实际可点区域扩到 44。
   桌面 hover 设备不受影响（@media (hover: none) 限定）。
   fix iter 108（audit MAJOR M4 a11y）。
   ========================================================================= */
@media (hover: none) {
  /* 组82 追加 .date-nav-btn(32px)/.page-btn(34px)/.global-search .icon.search-open
     （折叠态放大镜实测 8×22——触屏主路径三个高频件此前都在 44 线下）。
     .shortcut-btn::before 一行随元素本体删除（audit-2026-10-23 已删
     .shortcut-btn 全系列规则，#shortcut-btn 元素全仓不存在，纯死声明）。 */
  .icon-btn,
  .fav-notice .fn-close,
  .modal-close,
  .dp-pane-close,
  .theme-toggle,
  .sidebar-toggle,
  .date-nav-btn,
  .page-btn,
  .global-search .icon.search-open {
    position: relative;
  }
  .icon-btn::before,
  .fav-notice .fn-close::before,
  .modal-close::before,
  .dp-pane-close::before,
  .theme-toggle::before,
  .sidebar-toggle::before,
  .date-nav-btn::before,
  .page-btn::before,
  .global-search .icon.search-open::before {
    content: "";
    position: absolute;
    inset: 50% 50%;
    width: 44px; height: 44px;
    transform: translate(-50%, -50%);
    /* 透明 hit area，不影响视觉 */
    background: transparent;
  }

  /* audit-2026-10-22 MED：触屏主路径上三个高频控件此前不到 44px——
     date-item（抽屉里 121 天日期导航 ≈31px）、arxiv-cat-chip（arxiv 主筛
     控件 32px）、journal-btn（触屏笔记本 >1023px 时仅 ~26px）。
     列表项用真实 min-height（::before 扩展会让相邻条目命中区重叠误触）；
     journal-btn 在固定 60px 顶栏里真实加高会顶破布局，沿用 ::before 扩展。 */
  .date-item-btn { min-height: 44px; }
  .arxiv-cat-chip { min-height: 44px; }
  .journal-btn { position: relative; }
  .journal-btn::before {
    content: "";
    position: absolute;
    inset: 50% 50%;
    width: 44px; height: 44px;
    transform: translate(-50%, -50%);
    background: transparent;
  }

  /* fix audit-2026-10-25 组111 iOS 聚焦缩放防护：iOS Safari 对字号 <16px 的
     文本类控件聚焦时**强制放大整页**（且不可逆——用户要双指捏回来），顶栏被
     推出视口、展开态搜索框只剩半屏宽。站点刻意不用 viewport
     maximum-scale/user-scalable=no（禁用页面缩放是 WCAG 1.4.4 反模式），
     标准解法就是触屏下把输入控件字号抬到 16px 阈值。名单＝全站文本类 input
     穷举（grep '<input'）：顶栏搜索框（展开态；折叠态 display:none 不触发）
     + 搜索页筛选表单的作者/刊号文本框与起止日期框。桌面 hover 设备整块不
     生效，14px/12.75px 视觉与 VR 基线零波及；range/checkbox 不触发聚焦缩放，
     不入名单。 */
  .global-search input,
  .filter-form input[type="text"],
  .filter-form input[type="date"] { font-size: 16px; }
}

/* =========================================================================
   小细节：抽屉打开时禁止 main 区滚动；统一顶栏/抽屉的圆角
   关键：sidebar 自身要保持可点击——之前 .layout 整体 pointer-events:none 会继承到子元素
   ========================================================================= */
/* 抽屉打开时仅屏蔽 .layout 内部 content 区，sidebar 和 detail-pane 自己仍要可点 */
body.sidebar-open .layout > :not(.sidebar):not(.detail-pane) { pointer-events: none; }
body.sidebar-open .topbar { pointer-events: auto; }
body.sidebar-open .sidebar { pointer-events: auto; }

/* =========================================================================
   Toast（PRL.Core.A11y.toast）— 顶部居中，自动消失，aria-live 同步
   kind: info / success / warning / error（颜色由 --accent / state token 派生）
   原定义在 src/css/_typography.css（iter 113 引入），但该文件未被
   inline_index 复制进线上渲染管线，导致 toast 触发时元素无样式。
   本修复（iter 113 收尾）将规则搬进 style.css 末尾，
   同步删除 _typography.css 与 lint-tokens.py 白名单残留。
   ========================================================================= */
.prl-toast {
  position: fixed;
  top: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-toast);
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  max-width: min(90vw, 560px);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-elev);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius, 7px);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  animation: prl-toast-in var(--dur-base) var(--ease-out-quint, ease-out);
}

/* iter 114 Phase 1 修复：warning fallback 从 oklch(42.303% 0.1393 30.4)（与 danger 同红的 bug）改为 oklch(50.865% 0.1017 70.4)（琥珀 AA）。
   --state-* 现已在 :root 与所有 9 主题显式声明，fallback 留作 JS 禁掉或主题未加载时的最后兜底。 */
.prl-toast--success { border-left: 4px solid var(--state-success); }
.prl-toast--info    { border-left: 4px solid var(--accent); }
.prl-toast--warning { border-left: 4px solid var(--state-warning); }
.prl-toast--error   { border-left: 4px solid var(--state-danger); }

/* audit-2026-10-22 LOW：长路径 / 长 URL 提示文本折行，不撑破 toast */
.prl-toast__text { flex: 1 1 auto; overflow-wrap: anywhere; }

/* iter 114 Phase 5：toast 类型图标。
   WCAG 2.2 SC 1.4.1 Use of Color：不单独靠颜色（左边条）传达状态，
   视觉加上语义图标让色盲 / 黑白打印用户也能区分 success/info/warning/error。
   图标继承左边条同色 token，保持视觉一致性。 */
.prl-toast__icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: var(--text-md);
  font-weight: 700;
  line-height: var(--leading-none);
  border-radius: 50%;
  color: var(--bg-elev);
}
.prl-toast--success .prl-toast__icon { background: var(--state-success); }
.prl-toast--info    .prl-toast__icon { background: var(--accent); }
.prl-toast--warning .prl-toast__icon { background: var(--state-warning); }
.prl-toast--error   .prl-toast__icon { background: var(--state-danger); }

.prl-toast__action {
  flex: 0 0 auto;
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm, 4px);
  font-size: var(--text-sm, 12px);
  cursor: pointer;
}
.prl-toast__action:hover { background: var(--bg-hover); }

.prl-toast__close {
  flex: 0 0 auto;
  background: transparent;
  border: 0;
  color: var(--ink-soft);
  font-size: var(--text-3xl);
  line-height: var(--leading-none);
  cursor: pointer;
  padding: 0 var(--space-1);
}
.prl-toast__close:hover { color: var(--ink); }

@keyframes prl-toast-in {
  from { opacity: 0; transform: translate(-50%, -8px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* 尊重 prefers-reduced-motion：去掉入场动画 */
@media (prefers-reduced-motion: reduce) {
  .prl-toast { animation: none !important; }
}

/* [已删 · audit-2026-10-22 LOW] iter 114 Phase 5 的骨架屏样式（.skeleton-list /
   .skeleton-card / @keyframes skeleton-shimmer + reduced-motion 适配）：
   全仓 grep 确认 src/js、src/index.html、build_html.py、build_pages.py 均无
   生产者——这是一段从未接入运行时的死 CSS，唯一引用是
   test_phase5_skeleton.py 断言「CSS 里存在这些选择器」（测试反向锁定死代码，
   已一并删除）。140ms 的搜索防抖也不值得上骨架屏。 */

} /* end @layer components */

/* =========================================================================
   UTILITIES LAYER —— 单职责工具类
   -------------------------------------------------------------------------
   放在 components 之后 = 优先级最高，用 !important 之外的方式覆盖组件。
   规则：工具类只做一件事，且必须能在组件里用纯 CSS 达到同样效果时才写。
   ========================================================================= */
@layer utilities {
/* 视觉隐藏但保留给屏幕阅读器（sr-only）。
   此前 core/a11y.js 用 el.style.cssText 内联写死了这一整串；抽成类之后：
     · 同一份实现可复用，不再有第二处副本
     · 用 clip-path: inset(50%) 取代 clip: rect(0,0,0,0)（后者已废弃，
       且在部分浏览器上对 overflow:hidden 的裁剪不完全）
   1px + overflow:hidden 保留是为了让部分 AT 仍能触发选择/查找。 */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
} /* end @layer utilities */

/* =========================================================================
   以下到文件末尾此前是**裸写在 @layer 之外**的（forced-colors 块 + Confirm Modal
   + 各自的 HCM / reduced-motion 适配），fix audit-2026-10-06 MEDIUM-1：全部收进
   components 层。

   为什么必须收：级联层规则里「无层」样式的优先级**高于任何 @layer 内的样式**
   （与 specificity 无关）。这正是本文件 @layer base 注释里记录过的同一个坑 ——
   当初全局 `:focus-visible` 因为裸写而压掉了 components 层里 15 处组件级 focus
   规则，修正方式就是把它包进 base。Confirm Modal 是后来 iter 116 新加的，
   当时没跟上，于是又踩了一次：`.prl-confirm__btn { font: inherit; border: … }`
   无层，会压掉 base 层的 button reset；将来任何「调整层序」或「往 base 加规则」
   的改动，对这块的连锁影响都不可预测。

   收进 components 后：层序重新由 `@layer tokens, base, themes, components,
   utilities` 这一行唯一定义，组件规则与其它组件规则处在同一优先级层级。
   ========================================================================= */
@layer components {
/* =========================================================================
   iter 114 Phase 2：forced-colors 模式支持（WCAG 2.2 SC 1.4.1）
   ----------------------------------------------------------------------------
   Windows High Contrast / forced-colors 模式下，浏览器用系统色（CanvasText、
   ButtonFace、LinkText 等）替换作者样式，保证可见性。本块在此模式下：
   1. 用 CanvasText 替换 --accent，避免系统色下的低对比问题
   2. active 状态加 2px CanvasText border，让纯色背景在 HCM 下能看见选中
   3. 阴影 / 渐变在 forced-colors 下会被自动剥离，无需显式 reset
   依据：W3C WCAG 2.2 Understanding 1.4.1、WAI-ARIA APG "High Contrast"、USWDS。
   ========================================================================= */
@media (forced-colors: active) {
  /* 焦点环用系统色，避免 9 主题 accent 在 HCM 下失真 */
  :focus-visible {
    outline: 3px solid CanvasText !important;
    outline-offset: 2px;
  }

  /* tab / journal 按钮 active 态：HCM 下用 system 边框代替背景色 */
  .tab-btn.active,
  .journal-switch .journal-btn.active {
    border: 2px solid CanvasText;
    background: ButtonFace;
    color: ButtonText;
    forced-color-adjust: none;
  }

  /* audit-2026-10-22 MED：这三类控件的选中态同样只靠 accent-soft 背景表达，
     HCM 抹平背景后选中不可辨——补同款系统色边框：
     .arxiv-cat-chip.active（arxiv 分类筛选）、.icon-btn.fav.active /
     .icon-btn.read.active（卡片收藏/已读）、.date-item.active（侧栏当前日期） */
  .arxiv-cat-chip.active,
  .icon-btn.fav.active,
  .icon-btn.read.active,
  .date-item.active {
    border: 2px solid CanvasText;
    forced-color-adjust: none;
  }

  /* toast 边框用系统色 */
  .prl-toast {
    border: 1px solid CanvasText;
    background: Canvas;
    color: CanvasText;
  }
  .prl-toast--success,
  .prl-toast--warning,
  .prl-toast--error,
  .prl-toast--info {
    /* HCM 下类型区分靠 icon（Phase 5 加），border-left 仍保留 CanvasText */
    border-left: 4px solid CanvasText;
  }

  /* 顶栏 backdrop / 抽屉遮罩用 system 背景 */
  .sidebar-overlay {
    background: Canvas;
    opacity: 0.7;
  }

  /* 卡片 stub 虚线边框在 HCM 下统一为 CanvasText */
  .article-card.stub {
    border-color: CanvasText;
  }

  /* arxiv-id 复制成功态：HCM 下用 CanvasText 强调 */
  .arxiv-id.copied {
    background: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }

  /* 禁用按钮状态：HCM 用系统 grayText */
  .icon-btn:disabled,
  .page-btn:disabled,
  .date-nav-btn:disabled,
  .expand-search-btn:disabled {
    color: GrayText;
    border-color: GrayText;
  }
}

/* ===== Confirm Modal（iter 116 audit MED #11） =====
   替换 views/read.js + views/favorites.js 的 window.confirm() —
   后者阻塞 UI 线程且无 ARIA dialog 语义。位置独立于 #modal-backdrop
   （后者是文章详情专用），类前缀 prl-confirm-* 避免命名冲突。 */
.prl-confirm-backdrop {
  position: fixed;
  inset: 0;
  background: var(--overlay-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: var(--z-confirm); /* 高于 #modal-backdrop（--z-modal: 300）与 --z-toast，避免被遮 */
  animation: prl-confirm-fade var(--dur-fast) ease-out;
}

.prl-confirm-dialog {
  background: var(--bg, oklch(100% 0 0));
  color: var(--ink, oklch(18.4% 0.016 88.8));
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-modal);
  padding: var(--space-6);
  min-width: 280px;
  max-width: min(420px, calc(100vw - 32px));
  animation: prl-confirm-pop var(--dur-fast) cubic-bezier(0.34, 1.56, 0.64, 1);
  border: 1px solid var(--border-soft);
}

.prl-confirm__title {
  margin: 0 0 var(--space-3);
  font-size: var(--text-xl);
  font-weight: 600;
  line-height: var(--leading-heading);
}

.prl-confirm__msg {
  margin: 0 0 var(--space-5);
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
  color: var(--ink-soft, oklch(40.91% 0 0));
  word-break: break-word;
}

.prl-confirm__actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-end;
}

.prl-confirm__btn {
  font: inherit;
  font-size: var(--text-md);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: transparent;
  color: inherit;
  cursor: pointer;
  min-height: 36px;
  min-width: 64px;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}

.prl-confirm__btn:focus-visible {
  outline: 3px solid var(--accent, oklch(56.859% 0.2023 259.7));
  outline-offset: 2px;
}

.prl-confirm__btn:hover {
  background: var(--bg-elev, oklch(0% 0 0 / 0.04));
}

.prl-confirm__btn--ok {
  background: var(--accent);
  color: var(--text-on-accent);
  border-color: var(--accent);
}

.prl-confirm__btn--ok:hover {
  filter: brightness(0.92);
  background: var(--accent);
}

/* dark/space/moss 三主题 accent 是浅色（oklch(75.628% 0.0947 74) 等），白字对比度不足——
   与 .tab-btn.active 同一约定：这些主题下用 --text-on-light-accent。 */
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .prl-confirm__btn--ok {
  color: var(--text-on-light-accent);
}

.prl-confirm__btn--danger {
  background: var(--state-danger);
  border-color: var(--state-danger);
  color: var(--text-on-accent);
}

/* audit-2026-10-22 MED：dark/space/moss 下 --state-danger 是浅红（oklch ~75%），
   近白字压浅红 ≈2.1:1——与 --ok 按钮同一约定换深色字（这条此前漏配）。 */
:where([data-theme="dark"], [data-theme="space"], [data-theme="moss"], [data-theme="obsidian"]) .prl-confirm__btn--danger {
  color: var(--text-on-light-accent);
}

.prl-confirm__btn--danger:hover {
  filter: brightness(0.92);
  background: var(--state-danger);
}

@keyframes prl-confirm-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes prl-confirm-pop {
  from { transform: scale(0.94); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

/* HCM 下：背景用 Canvas，文字用 CanvasText，按钮边框强制 Highlight 焦点环 */
@media (forced-colors: active) {
  .prl-confirm-backdrop {
    background: var(--overlay-modal);
    forced-color-adjust: none;
  }
  .prl-confirm-dialog {
    background: Canvas;
    color: CanvasText;
    border: 1px solid CanvasText;
  }
  .prl-confirm__btn {
    background: ButtonFace;
    color: ButtonText;
    border: 1px solid ButtonText;
    forced-color-adjust: none;
  }
  .prl-confirm__btn--ok,
  .prl-confirm__btn--danger {
    background: Highlight;
    color: HighlightText;
    border-color: HighlightText;
  }
  .prl-confirm__btn:focus-visible {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}

/* prefers-reduced-motion: 去掉弹窗动画，避免前庭功能敏感用户不适 */
@media (prefers-reduced-motion: reduce) {
  .prl-confirm-backdrop,
  .prl-confirm-dialog {
    animation: none;
  }
}
/* =========================================================================
   打印样式（audit-2026-10-22 LOW）
   研究员打印/存 PDF 文献列表是真实场景：隐藏所有导航与交互件，只留正文列表；
   卡片去阴影去边框色块，白底省墨。收进 components 层与全文件层序约定一致。
   ========================================================================= */
@media print {
  /* 交互壳（导航 / 按钮 / 横幅 / 弹层控件）不上纸：它们承载的信息正文里都有。
     翻日按钮、导出工具栏、收藏提示、「展开摘要」在纸上都是死控件；卡片的
     收藏/已读是 <button>（原文是 <a href>，保留并附 URL，见下方 ::after）。 */
  .topbar, .sidebar, .detail-pane, .back-to-top,
  .sidebar-toggle, .skip-link, .prl-toast, .loading,
  .prl-confirm-backdrop, .error-banner,
  .daily-banner-nav, .hs-more, .abstract-toggle,
  .fav-toolbar, .fav-notice, .modal-close,
  .article-card .actions button { display: none !important; }
  /* 组82 补：browse 翻日历条 / j·k 键盘提示 / 分页器 / arXiv 分类筛选条——
     全部是交互壳，纸上信息已由日期标题、卡数、正文本身承载。
     单独成条：上方五行为 test_audit_fixes 67.1c 的字符串锁（跨行连续），别并。 */
  .date-nav, .kb-hint, .pagination, .arxiv-cat-strip { display: none !important; }
  .layout { display: block; }
  /* 白底黑字：用 tokens 层的 --print-* 盖掉 9 主题墨色（本层晚于 themes 层，
     同 :root specificity 后层胜；不写 !important、不写新字面色）。 */
  :root {
    color-scheme: light;
    --ink: var(--print-ink);
    --ink-soft: var(--print-ink-soft);
    --ink-mute: var(--print-ink-mute);
    --link: var(--print-link);
    --bg: var(--print-bg);
    --bg-soft: var(--print-bg);
    --bg-elev: var(--print-bg);
    --bg-hover: var(--print-bg);
    --border: var(--print-border);
    --border-soft: var(--print-border-soft);
    --selection: var(--print-selection);
  }
  .article-card {
    box-shadow: none;
    /* 用 --border 而非字面色：lint-tokens 业务层零字面色 baseline。
       打印时浏览器强制白底，--border 在 9 个主题里都是中灰，纸上可读。 */
    border: 1px solid var(--border);
    break-inside: avoid;
  }
  .article-card::before { display: none; }
  .ac-abstract.clamp { -webkit-line-clamp: unset; line-clamp: unset; max-height: none; }
  /* 实底彩色件必须连底色一起印：白字 / 浅字离开彩底就是纸上隐身。
     .ac-section 的底色走内联 var(--cN-bg/fg)（9 主题各自定义，暗主题 fg 为浅色），
     期刊 logo 徽章底为实色，检索命中词底为高亮色——都属于这一类。 */
  .ac-section, .ac-journal-tag, .sjg-logo, .cjg-logo,
  .search-highlight {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  /* 把交互链接带不走的原文地址印出来：「原文 ↗」→ 原文（https://doi.org/…） */
  .actions a.icon-btn::after {
    content: "（" attr(href) "）";
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    color: var(--ink-mute);
    word-break: break-all;
  }
  /* 开着详情弹窗打印：从「定屏浮层」降级为跟随列表排到纸上的正文。
     只改定位与遮罩底、绝不动 display——关闭态靠 [hidden]{display:none!important}
     （无层规则）兜住，这里若写 display 会把关着的弹窗印出来。 */
  #modal-backdrop { position: static; background: none; padding: 0; }
  #modal { position: static; max-height: none; box-shadow: none; border: none; width: auto; }
}

/* ---------- 组97：首页「卡片阅读」入口 banner（曾自称组96，撞号让号） ----------
   DOM 见 views/home.js——.home-grid 首子元素跨全宽。配色全部走主题变量
   （10 主题零新规则），链上裸 .hs-more 已被上方 @media print 隐藏列表覆盖。
   组127（全面审查 L20）：整块从 @layer 外收进本尾段 components 层——无层样式
   优先级**高于任何层内规则**（与本文件 757/4615 两处注释记的是同一个坑），
   裸写在外的后果是下方 @media (max-width:640px) 之类响应式覆盖若哪天被移进
   层内就会被本块无声压制；层内收拢后层序回归 `@layer` 声明行的统一口径。
   已全文件核对：.home-reader-cta/.hrc-* 无任何层内同名竞争选择器，搬动零像素差。 */
.home-reader-cta {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line, transparent));
  border-radius: var(--radius-lg);
  background:
    linear-gradient(120deg,
      color-mix(in srgb, var(--accent) 12%, transparent),
      color-mix(in srgb, var(--accent) 3%, transparent) 55%,
      transparent);
  color: var(--ink);
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.home-reader-cta:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow);
}
.home-reader-cta:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
.hrc-icon {
  flex: none;
  display: inline-flex;
  color: var(--accent);
}
.hrc-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-right: auto;
  min-width: 0;
}
.hrc-title {
  font-size: var(--text-xl);
  font-weight: 700;
  line-height: 1.3;
}
.hrc-sub {
  font-size: var(--text-sm);
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}
.hrc-go {
  flex: none;
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--accent);
  transition: transform 0.15s;
}
.home-reader-cta:hover .hrc-go { transform: translateX(3px); }
@media (prefers-reduced-motion: reduce) {
  .home-reader-cta:hover .hrc-go { transform: none; }
}
@media (max-width: 640px) {
  .home-reader-cta { padding: var(--space-3) var(--space-4); }
  .hrc-sub { font-size: var(--text-xs); }
}

} /* end @layer components（此前无层的尾段，2026-10-06 收拢） */

/* =========================================================================
   跨文档视图过渡（perf 2026-10-23）—— 切页不再有「白屏刷新感」
   全站是整页导航的 MPA：旧版切页 = 旧页瞬间消失 → 白屏 → 新页渲染。
   @view-transition { navigation: auto } 让支持跨文档过渡的浏览器
   （Chrome / Edge 126+）在整页导航时做旧页→新页交叉淡化；配合每日页的
   Speculation Rules 预渲染与 bfcache，切换呈现为一次 150ms 的柔和淡入。
   不支持的浏览器（Firefox / Safari 现状）整组忽略，行为与旧版一致，零回归。
   放在 @layer 之外：view-transition 伪元素不参与业务级联，无层样式优先级最高，
   也不会被任何主题层覆盖。 */
@view-transition {
  navigation: auto;
}
::view-transition-old(root),
::view-transition-new(root) {
  /* UA 默认交叉淡化偏慢（约 250ms+），压到 150ms：足够遮掉「瞬间消失」的
     生硬感，又不拖慢本就被预渲染加速到近瞬时的导航。 */
  animation-duration: 150ms;
  animation-timing-function: ease-out;
}
@media (prefers-reduced-motion: reduce) {
  /* 前庭敏感用户：关闭跨页淡化，退回瞬时切换（与站内核减动画约定一致） */
  @view-transition {
    navigation: none;
  }
}

