/* BlockTavern 下载页 — wonder.design 风格设计体系
   参照用户模板：纯黑底、白色渐变标题、玻璃卡片、紫色光晕、Hanken Grotesk/Inter/JetBrains Mono

   ⚠ 这里以前有两行 @import url('https://fonts.googleapis.com/...')，已经删掉：
     1. 它们是渲染阻塞资源，国内连不上时要等超时才首次绘制；
     2. 其中那张 Material Symbols 的 CSS 会重新声明一遍图标字体（font-display: swap），
        「后声明者胜」把 css/icons.css 里自托管的图标字体（block）顶掉 ——
        于是刷新页面时先看到 key / vpn_key 这类图标名文字，过一会儿才变成图标。
     现在全部字体都在 css/fonts.css + css/icons.css 里本地声明。 */

/* ================= 主题层（Phase 1：只加 token，不改任何现有声明） =================
   机制：<html data-theme="light|dark"> —— 由 js/modules/asset-fallback.js 最前面那段
   同步脚本（在 <head> 内、所有 <link rel=stylesheet> 之前、无 defer）写入，默认跟随系统。
   ⚠ 本阶段**没有任何规则引用下面这些新 token**，所以暗色外观逐像素不变（Phase 2 才开始替换）。

   1) 新 token 的「暗色默认值」放在下面这个 :root 里，值 = 现在代码里实际在用的颜色，
      这样 Phase 2 把字面量换成 var() 之后，暗色外观保持不变。
   2) 亮色值只在 :root[data-theme="light"] 里覆盖（选择器权重 0,1,1 > 0,1,0，与顺序无关）。

   ⚠ 刻意「不定义」的悬空 token（今天靠 invalid-at-computed-value-time 退化成继承/currentColor
      恰好正常，补上会当场改变 12 处渲染，**两个主题块里都不要再补**）：
      --text-main · --text-low · --border-strong · --surface-hover · --surface-press
      --danger · --success · --warning · --info · --focus-ring · --divider

   ⚠ --font-sans 属于**另一类**「刻意不定义」：它不是靠 invalid-at-computed-value-time，
      而是每个调用点都自带兜底栈，靠 var() 的 fallback 生效 ——
        css/verify.css:147            var(--font-sans, "Inter", "Hanken Grotesk", system-ui, sans-serif)
        css/layout.css:441            var(--font-sans, var(--font-body, system-ui, sans-serif))
        js/modules/site-switch.js:35  var(--font-sans, system-ui, sans-serif)（注入样式里）
      ★ 三处兜底栈**互不相同**，所以：既不要补定义（一补就会把 site-switch 那条从
        system-ui 换成 Inter 栈 → 亮/暗都出现视觉变化），也不要改名成 --font-body
        （那会把 verify.css 的 "Hanken Grotesk" 与 system-ui 一档整段吃掉）。
        **保持不定义**是唯一「零像素变化」的选择。 */
:root {
    /* 玻璃表面 / 边框（现在写死成 rgba(255,255,255,.0x) 的那 184 处，Phase 2 收敛到这里） */
    --surface-glass: rgba(255, 255, 255, 0.03);
    --surface-glass-hover: rgba(255, 255, 255, 0.06);
    --border-glass: rgba(255, 255, 255, 0.10);

    /* 标题渐变（components.css 的 .wonder-gradient-text 用；暗色=白→灰） */
    --text-gradient-from: #ffffff;
    --text-gradient-to: #a1a1aa;

    /* 遮罩 / 阴影 */
    --overlay-scrim: rgba(0, 0, 0, 0.60);
    --shadow-color: rgba(0, 0, 0, 0.50);

    /* 滚动条（Firefox 用 scrollbar-color，WebKit 用 ::-webkit-scrollbar） */
    --scrollbar-thumb: rgba(255, 255, 255, 0.18);
    /* --scrollbar-track：当前全站无 var() 引用，**刻意保留** —— 它是上面 --scrollbar-thumb
       （css/layout.css:501 在用）的配套值：Firefox 的 scrollbar-color 是
       `<thumb> <track>` 两值简写，缺一不可；且它两主题都刻意取 transparent（轨道不随主题翻）。 */
    --scrollbar-track: transparent;

    /* 强调色之上的文字色（--primary 上的前景） */
    --on-accent: #000000;

    /* 状态色（成功 / 警告 / 危险 / 信息） */
    --status-ok: #4ade80;
    --status-ok-bg: rgba(74, 222, 128, 0.12);
    --status-ok-border: rgba(74, 222, 128, 0.30);
    --status-warn: #fbbf24;
    --status-warn-bg: rgba(251, 191, 36, 0.12);
    --status-warn-border: rgba(251, 191, 36, 0.30);
    --status-danger: #f87171;
    --status-danger-bg: rgba(248, 113, 113, 0.12);
    --status-danger-border: rgba(248, 113, 113, 0.30);
    /* --status-info：当前全站无 var() 引用，**刻意保留** —— 它是 --status-ok / --status-warn /
       --status-danger 这套「状态墨色」的第 4 个成员（另 3 个都在用，--status-info-bg /
       --status-info-border 也在用），单删它会让四色语义家族残缺。 */
    --status-info: #93c5fd;
    --status-info-bg: rgba(147, 197, 253, 0.12);
    --status-info-border: rgba(147, 197, 253, 0.30);

    /* 二维码：**永久固定**（深码浅底），两个主题都不许变 —— 扫不出来就是事故。
       --qr-fg 当前全站无 var() 引用，**刻意保留**：它是 --qr-bg（css/components.css 与
       css/sponsors.css 在用）的**成对语义**另一半，黑码白底必须成套。 */
    --qr-bg: #ffffff;
    --qr-fg: #000000;

    /* ===== 后台面板 / JS 注入样式专用（Phase 5：把 js/*.js 里 injectStyle() 的写死颜色收敛到这里）
       为什么单独一组：后台面板的底色来自「多层半透明叠加」（.admin-card = rgba(15,15,15,.8) 叠在黑 body 上），
       而这些样式是用 JS 注入到 <head> 末尾的，拿不到「父层合成结果」——只能给它们**实色**。
       下面每个暗色值都 = 替换前那个字面量（或它在前一层上的合成值），所以暗色外观逐字节不变。 */
    --admin-frozen-bg: #0c0c0c;          /* 表格冻结列底色：必须**不透明**（横向滚动时被它盖住的单元格不能透出来）。
                                            取值 = 普通列**实际渲染**出的底色：.admin-card 是 rgba(15,15,15,.8) 叠在 body 的
                                            #000 上，Chrome 合成结果 = 0.8×15 + 0.2×0 ≈ 12 → rgb(12,12,12)（canvas 实测一致）。
                                            ⚠ 这里必须放"合成后的不透明值"，不能放 15,15,15：冻结列自己是不透明层，
                                              写 15 就等于把卡片层又叠了一遍 ⇒ 比普通列亮 3 级，出现一条色带（实测 #0f0f0f vs #0c0c0c）。
                                            所以暗色值仍是 #0c0c0c（逐字节不变），与普通列逐级一致。 */
    --admin-frozen-edge: rgba(0, 0, 0, 0.35); /* 冻结列左侧「这边下面是滚动内容」的渐隐阴影 */
    --admin-doc-bg: #141414;             /* 原文编辑 textarea 底色 */
    --admin-ctrl-bg: #222222;            /* 后台小按钮底色 */
    --admin-ctrl-bg-hover: #2e2e2e;      /* 后台小按钮 hover 底色（原来是透明 #2a2a2a 叠在 #1e1e1e 上的视觉结果） */
    --admin-ctrl-border: rgba(255, 255, 255, 0.14);
    --admin-danger-border: rgba(224, 90, 90, 0.45);
    --admin-border-soft: rgba(255, 255, 255, 0.06); /* 页面管理行分隔线（原来是 rgba(255,255,255,.06)，
                                                      与 --border-faint 的 .05 不是同一个值） */
    --admin-glass-box: rgba(255, 255, 255, 0.025);  /* 「有效测试链接」小盒子底（原来写死 .025） */
    /* 页面管理「三态按钮」的边框/底色（原来写死 rgba(...,.55) / rgba(...,.12)，
       比 --status-*-border(.30) 亮一档 —— 为了暗色逐字节不变，按原值单列） */
    --admin-pg-ok-line: rgba(74, 222, 128, 0.55);
    --admin-pg-ok-bg: rgba(74, 222, 128, 0.12);
    --admin-pg-warn-line: rgba(250, 188, 78, 0.55);
    --admin-pg-warn-bg: rgba(250, 188, 78, 0.12);
    --admin-pg-danger-line: rgba(230, 100, 100, 0.55);
    --admin-pg-danger-bg: rgba(220, 80, 80, 0.12);
    /* 页面管理里那条紫色「测试链接」与蓝/琥珀状态色：原来写死 #a5b4fc / #7dd3fc / #ff8a8a，
       它们不在既有 --status-* / --accent-cobalt-* 的取值里（改那个会连带改 verify/sponsors），
       所以按原值单列，亮色下换深色。 */
    --admin-pg-link: #a5b4fc;
    --admin-pg-time: #7dd3fc;
    --admin-pg-time-expired: #ff8a8a;
    --admin-primary-soft: rgba(183, 109, 255, 0.1); /* .aa-upload 底（原写死 .1，与 --primary-bg 的 .12 不同） */
    --admin-text: #e5e2e1;               /* 后台按钮/控件的正文字色（= --text-on-surface，单独取名便于亮色独立调） */
    --admin-on-accent: #ffffff;          /* 后台「主色底」上的字色（暗色主色 --primary 是浅紫，白字是原设计） */
    --admin-text-dim: #9a9a9a;           /* 后台说明文字（比 --text-faint 亮一点） */
    --admin-danger-text: #ef9a9a;
    --admin-scrim: rgba(0, 0, 0, 0.61);  /* 属性弹窗遮罩（原来写死 rgba(0,0,0,.62)，差 1 级） */

    color-scheme: dark;
}

/* ================= 亮色主题（Phase 1：只备 token；Phase 3 才接切换按钮） ================= */
:root[data-theme="light"] {
    /* ===== 表面 ===== */
    --bg: #ffffff;
    --surface: #f6f6f7;
    --surface-card: #ffffff;
    --surface-low: #f2f2f4;
    --surface-container: #ececef;
    --surface-high: #e4e4e8;

    /* ===== 文本 ===== */
    --text: #14141a;
    --text-muted: #5b5b66;
    --text-on-surface: #26262e;
    /* 亮色 .55 在白底上只有 4.06:1、在 --primary-soft 淡紫底（文档树当前项）上 3.93:1，
       正文级不达标。提到 .62：白底 5.41:1、最差底 #f5effe 4.68:1 ✔。
       暗色值不动（--text-faint 的 :root 暗色仍是 rgba(255,255,255,.5)）。
       ★ 清理记录：原来的三份逐字节副本 --act-faint / --admin-faint / --art-faint 已删除
       定义，全部引用（css/activity.css 50 处 + css/article.css 10 处）改回 var(--text-faint)。 */
    --text-faint: rgba(20, 20, 26, 0.62);

    /* ===== 强调色（亮色下用更深的紫，白字才压得住） ===== */
    --primary: #7c3aed;
    --primary-container: #8b5cf6;
    --glow-purple: rgba(124, 58, 237, 0.18);
    --accent-ink: #ffffff;

    /* ===== 边框 ===== */
    --border-subtle: rgba(20, 20, 26, 0.12);
    --border-faint: rgba(20, 20, 26, 0.07);

    /* ===== 玻璃表面 / 边框（亮色下改为「深色半透明」，白玻璃在白底上会消失） ===== */
    --surface-glass: rgba(20, 20, 26, 0.04);
    --surface-glass-hover: rgba(20, 20, 26, 0.07);
    --border-glass: rgba(20, 20, 26, 0.10);

    /* ===== 标题渐变（**不能是白色**，否则 background-clip:text 的标题在白底上完全消失） ===== */
    --text-gradient-from: #14141a;
    --text-gradient-to: #6b6b78;

    /* ===== 遮罩 / 阴影 ===== */
    --overlay-scrim: rgba(0, 0, 0, 0.45);
    --shadow-color: rgba(20, 20, 26, 0.14);

    /* ===== 滚动条 ===== */
    --scrollbar-thumb: rgba(20, 20, 26, 0.28);
    --scrollbar-track: transparent;

    /* ===== 强调之上的文字色（--primary 是深紫 → 用白字） ===== */
    --on-accent: #ffffff;

    /* ===== 状态色（亮底上换成更深的版本，保证 ≥4.5:1） ===== */
    --status-ok: #14532d;
    --status-ok-bg: rgba(21, 128, 61, 0.10);
    --status-ok-border: rgba(21, 128, 61, 0.28);
    --status-warn: #7c2d12;
    --status-warn-bg: rgba(180, 83, 9, 0.10);
    --status-warn-border: rgba(180, 83, 9, 0.28);
    --status-danger: #991b1b;
    --status-danger-bg: rgba(220, 38, 38, 0.10);
    --status-danger-border: rgba(220, 38, 38, 0.28);
    --status-info: #1d4ed8;  /* 同上：全站无 var() 引用但刻意保留（四色状态家族成员） */
    --status-info-bg: rgba(29, 78, 216, 0.10);
    --status-info-border: rgba(29, 78, 216, 0.28);

    /* 二维码永久固定（同暗色，不随主题） */
    --qr-bg: #ffffff;
    --qr-fg: #000000;

    color-scheme: light;
    --nav-scrolled-bg: rgba(255, 255, 255, 0.85);
    --scrim-soft: rgba(20, 20, 26, 0.10);
    --text-emphasis: rgba(20, 20, 26, 0.92);
    --surface-glass-subtle: rgba(20, 20, 26, 0.05);
    --surface-raised: rgba(20, 20, 26, 0.08);
    --shadow-soft: rgba(20, 20, 26, 0.10);
    --mobile-menu-bg: #ffffff;
    --border-visible: rgba(20, 20, 26, 0.14);
    --border-glass-emphasis: rgba(20, 20, 26, 0.18);
    --surface-inverse: #14141a;
    --surface-inverse-hover: #26262e;
    /* ===== Phase 2-b：components.css 收敛用的 token（亮色值） ===== */
    --surface-glass-faint: rgba(20, 20, 26, 0.03);
    --surface-glass-soft: rgba(20, 20, 26, 0.05);
    --surface-glass-strong: rgba(20, 20, 26, 0.09);
    --surface-code: rgba(20, 20, 26, 0.07);
    --border-glass-strong: rgba(20, 20, 26, 0.22);
    --ring-soft: rgba(20, 20, 26, 0.22);
    --grid-line: rgba(20, 20, 26, 0.055);
    --skeleton-sheen: rgba(20, 20, 26, 0.10);
    --translate-card: rgba(255, 255, 255, 0.72);
    --translate-card-hover: rgba(255, 255, 255, 0.86);
    --badge-surface: rgba(20, 20, 26, 0.05);
    --surface-float: rgba(255, 255, 255, 0.92);
    --surface-sunken: rgba(20, 20, 26, 0.06);
    --shadow-ring: rgba(20, 20, 26, 0.10);
    --shadow-medium: rgba(20, 20, 26, 0.13);
    --shadow-strong: rgba(20, 20, 26, 0.16);
    --scrim-strong: rgba(0, 0, 0, 0.45);
    --cta-inverse-bg: #14141a;
    --cta-inverse-bg-hover: #2a2a2e;
    --cta-inverse-fg: #ffffff;
    --handle-fg: #ffffff;
    --on-media-divider: rgba(255, 255, 255, 0.95);
    --glow-violet-soft: rgba(124, 58, 237, 0.10);
    --glow-violet: rgba(124, 58, 237, 0.12);
    --accent-violet-bg: rgba(124, 58, 237, 0.08);
    --accent-violet-line: rgba(124, 58, 237, 0.30);
    --accent-violet-strong: rgba(124, 58, 237, 0.35);
    --primary-faint: rgba(124, 58, 237, 0.06);
    --primary-soft: rgba(124, 58, 237, 0.08);
    --primary-bg: rgba(124, 58, 237, 0.12);
    --primary-edge-soft: rgba(124, 58, 237, 0.22);
    --primary-edge: rgba(124, 58, 237, 0.25);
    --primary-edge-strong: rgba(124, 58, 237, 0.35);
    --primary-edge-strongest: rgba(124, 58, 237, 0.4);
    --accent-peach: #c2410c;
    --accent-peach-bg: rgba(194, 65, 12, 0.08);
    --accent-peach-line: rgba(194, 65, 12, 0.30);
    --accent-lilac: #7e22ce;
    --accent-alt-bg: rgba(126, 34, 206, 0.08);
    --accent-alt-line: rgba(126, 34, 206, 0.35);
    --on-inverse: #ffffff;
    /* ===== Phase 2-c：verify.css 收敛用的 token（亮色值） ===== */
    --text-strong: #14141a;
    --surface-glass-active: rgba(20, 20, 26, 0.10);
    --border-glass-hover: rgba(20, 20, 26, 0.30);
    --status-none-bg: rgba(20, 20, 26, 0.06);
    --status-none-border: rgba(20, 20, 26, 0.18);
    --accent-cobalt-faint: rgba(124, 58, 237, 0.06);
    --accent-cobalt-bg: rgba(124, 58, 237, 0.08);
    --accent-cobalt-edge: rgba(124, 58, 237, 0.18);
    --accent-cobalt-line: rgba(124, 58, 237, 0.35);
    --accent-cobalt-ink: #5b21b6;

    /* ===== 后台面板 / JS 注入样式专用（与暗色块一一对应，只换值） =====
       暗色那组是「多层半透明叠加后的实色」；亮色下这几层叠加结果是白玻璃，
       直接用白玻璃当底色会让里面的浅灰文字全糊掉（实测 .admin-empty 只有 1.04:1），
       所以这里给**不透明浅色**：文字仍是 --text / --text-muted / --text-on-surface（都是深色）。 */
    --admin-frozen-bg: #fcfcfd;          /* = --admin-card-bg 本身（亮色 .admin-card 是**不透明** #fcfcfd，没有 alpha 层可合成）
                                            ⇒ 冻结列与普通列底色完全相同，不再有一条比整张表深一档的色带。
                                            仍然是**不透明**色（冻结列的不变量）；行 hover 时由
                                            js/article-admin.js 里那条同特异度的 sticky 规则
                                            （`tr:hover td:last-child`，注入在 css 之后 → 平局时它赢）跟着一起变亮，
                                            所以交互态仍然可区分。 */
    --admin-frozen-edge: rgba(20, 20, 26, 0.16); /* 亮色下阴影要用深色，否则浅底上什么都看不见 */
    --admin-doc-bg: #f0f0f3;
    --admin-ctrl-bg: #e3e3e9;
    --admin-ctrl-bg-hover: #d4d4db;
    --admin-ctrl-border: rgba(20, 20, 26, 0.14);
    --admin-danger-border: rgba(220, 38, 38, 0.45);
    --admin-border-soft: rgba(20, 20, 26, 0.10);
    --admin-glass-box: rgba(20, 20, 26, 0.04);
    /* 亮色下按钮底色要实色（半透明彩色在白底上几乎看不见），边框保留品牌色系 */
    --admin-pg-ok-line: rgba(21, 128, 61, 0.55);
    --admin-pg-ok-bg: #e7f6ec;
    --admin-pg-warn-line: rgba(180, 83, 9, 0.55);
    --admin-pg-warn-bg: #fdf1e3;
    --admin-pg-danger-line: rgba(220, 38, 38, 0.55);
    --admin-pg-danger-bg: #fdeaea;
    --admin-pg-link: #4338ca;
    --admin-pg-time: #1d4ed8;
    --admin-pg-time-expired: #b91c1c;
    --admin-primary-soft: rgba(124, 58, 237, 0.10);
    --admin-text: #14141a;
    --admin-on-accent: #ffffff;          /* 亮色主色是深紫 #7c3aed，白字 5.7:1 ✔ */
    --admin-text-dim: #5b5b66;           /* = --text-muted，亮底上才够对比（原 #9a9a9a 只有 2.75:1） */
    --admin-danger-text: #991b1b;
    --admin-scrim: rgba(0, 0, 0, 0.45);

    /* ===== 更新日志「分类胶囊」配色（亮色值 = 标准软标签色板，逐字照用） =====
       行业惯例（GitHub 标签 / 云厂商控制台）的 **soft 软标签**：浅底 + 深字，
       比"纯白字实底"可读得多。前台 changelog.html 与后台「更新日志」面板
       （activity-admin.html 引同一份 css/changelog.css）共用这一套，改一处两边一起变。
       ⚠ 只给更新日志的分类胶囊用，**不要**顺手拿去改 --status-*：那四个是全站语义状态色
         （报名/中签/异常），换了会连带改一堆页面。 */
    --cl-tag-feature-bg: #D1FAE5;   --cl-tag-feature-text: #065F46;
    --cl-tag-fix-bg: #FEE2E2;       --cl-tag-fix-text: #991B1B;
    --cl-tag-improve-bg: #DBEAFE;   --cl-tag-improve-text: #1E40AF;
    --cl-tag-change-bg: #FFF3CD;    --cl-tag-change-text: #92400E;
    /* 安全**刻意与修复同色系但更深一档**（粉底深枣红 vs 浅红底砖红）：
       漏洞通告既要有"红=危险"的警示，又要和普通 bug 修了一眼分得开。
       ⚠ 与「修复」不同色是**有意**的，别为了"统一"把这两行改成一样。 */
    --cl-tag-security-bg: #FECDD3;  --cl-tag-security-text: #881337;
    --cl-tag-notice-bg: #E5E7EB;    --cl-tag-notice-text: #374151;

    /* 时间线圆点（更新日志左侧轨道上的实心点）：**同一色相的中调实色**。
       胶囊是"浅底 + 深字"，点只能取一个色 —— 取底色会在白底上淡到看不见（#FFF3CD 这种），
       取文字色又深得发黑（#065F46/#374151），看着跟胶囊不是一家。
       所以点单独给一档 500 级实色：色相与胶囊一致，实心点在亮底上也清楚。
       ⚠ 改胶囊配色时**顺手核一下圆点**，两行离得近就是为了一起来改。 */
    --cl-dot-feature: #10B981;      --cl-dot-fix: #EF4444;
    --cl-dot-improve: #3B82F6;      --cl-dot-change: #F59E0B;
    --cl-dot-security: #E11D48;     --cl-dot-notice: #6B7280;
}

:root {
    /* ===== 表面（模板 Material-3 风格令牌） ===== */
    --bg: #000000;
    --surface: #131313;
    --surface-card: #161616;
    --surface-low: #1c1b1b;
    --surface-container: #201f1f;
    --surface-high: #2a2a2a;

    /* ===== 文本 ===== */
    --text: #ffffff;
    --text-muted: #a1a1aa;
    --text-on-surface: #e5e2e1;
    --text-faint: rgba(255, 255, 255, 0.5);

    /* ===== 强调色（模板：淡紫主色 + 紫光） ===== */
    --primary: #ddb7ff;
    --primary-container: #b76dff;
    --glow-purple: rgba(168, 85, 247, 0.4);
    --accent-ink: #000000;

    /* ===== 边框 ===== */
    --border-subtle: rgba(255, 255, 255, 0.1);
    --border-faint: rgba(255, 255, 255, 0.05);

    /* ===== 字体（模板字体栈） ===== */
    --font-display: "Hanken Grotesk", sans-serif;
    --font-body: "Inter", sans-serif;
    --font-mono: "JetBrains Mono", monospace;

    /* ===== 字号（模板字号刻度） ===== */
    --text-body-md: 16px;
    --text-caption: 12px;

    /* ===== 圆角 ===== */
    --radius-sm: 0.5rem;      /* rounded-lg / xl */
    --radius: 1rem;           /* rounded-2xl */
    --radius-lg: 1.5rem;      /* rounded-3xl */
    --radius-pill: 9999px;

    /* ===== 布局节奏（模板 spacing） ===== */
    --container-max: 1440px;
    --margin-desktop: 64px;
    --margin-mobile: 20px;
    /* 页面顶部间距（v=34）：**「固定层底边（导航栏 + 导航栏下方的横幅）」→ 页面首个内容块
       （hero 的徽标 / 标题）顶边** 的距离。四个公开页面各写各的 padding-top（首页 96、
       新闻/赞助 0、活动 40+16）导致同一个位置四种距离，用户报「就不能统一一下吗」✗ ——
       现在只有这一个令牌说话：各页 hero 的 padding-top 一律 = var(--page-top-gap)，
       与上边缘的距离因此在桌面 / 手机、有横幅 / 无横幅下都一致（详见 css/layout.css 的 .main 让位）。
       取值 40px：站点间距刻度（8 的倍数）的一档，实测「不是太远也不是太近」的那一档
       （首页原来是 96 = 太远，新闻/赞助是 0 = 贴死）。 */
    --page-top-gap: 40px;

    /* ===== 动效（模板 easing） ===== */
    --ease: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-out: cubic-bezier(0.19, 1, 0.22, 1);
    --transition-fast: 150ms ease;
    --transition: 300ms var(--ease);
    --nav-scrolled-bg: rgba(0, 0, 0, 0.6);
    --scrim-soft: rgba(0, 0, 0, 0.25);
    --text-emphasis: rgba(255, 255, 255, 0.95);
    --surface-glass-subtle: rgba(255, 255, 255, 0.04);
    --surface-raised: rgba(255, 255, 255, 0.1);
    --shadow-soft: rgba(0, 0, 0, 0.08);
    --mobile-menu-bg: #000000;
    --border-visible: rgba(255, 255, 255, 0.12);
    --border-glass-emphasis: rgba(255, 255, 255, 0.16);
    --surface-inverse: #fff;
    --surface-inverse-hover: #ececec;
    /* ===== Phase 2-b：components.css 收敛用的 token（暗色值 = 替换前的原字面量） ===== */
    --surface-glass-faint: rgba(255, 255, 255, 0.02);
    --surface-glass-soft: rgba(255, 255, 255, 0.05);
    --surface-glass-strong: rgba(255, 255, 255, 0.10);
    --surface-code: rgba(255, 255, 255, 0.08);
    --border-glass-strong: rgba(255, 255, 255, 0.20);
    --ring-soft: rgba(255, 255, 255, 0.18);
    --grid-line: rgba(255, 255, 255, 0.035);
    --skeleton-sheen: rgba(255, 255, 255, 0.09);
    --translate-card: rgba(25, 25, 25, 0.4);
    --translate-card-hover: rgba(35, 35, 35, 0.6);
    --badge-surface: rgba(22, 22, 22, 0.3);
    --surface-float: rgba(32, 31, 31, 0.8);
    --surface-sunken: rgba(0, 0, 0, 0.35);
    --shadow-ring: rgba(0, 0, 0, 0.28);
    --shadow-medium: rgba(0, 0, 0, 0.55);
    --shadow-strong: rgba(0, 0, 0, 0.6);
    --scrim-strong: rgba(0, 0, 0, 0.7);
    --cta-inverse-bg: #ffffff;
    --cta-inverse-bg-hover: #e5e5e5;
    --cta-inverse-fg: #000000;
    --handle-fg: #1c1c1c;
    --on-media-divider: rgba(255, 255, 255, 0.95);
    --glow-violet-soft: rgba(168, 85, 247, 0.15);
    --glow-violet: rgba(168, 85, 247, 0.18);
    --accent-violet-bg: rgba(183, 109, 255, 0.08);
    --accent-violet-line: rgba(183, 109, 255, 0.35);
    --accent-violet-strong: rgba(183, 109, 255, 0.5);
    --primary-faint: rgba(221, 183, 255, 0.06);
    --primary-soft: rgba(221, 183, 255, 0.08);
    --primary-bg: rgba(221, 183, 255, 0.12);
    --primary-edge-soft: rgba(221, 183, 255, 0.22);
    --primary-edge: rgba(221, 183, 255, 0.25);
    --primary-edge-strong: rgba(221, 183, 255, 0.35);
    --primary-edge-strongest: rgba(221, 183, 255, 0.4);
    --accent-peach: #ffb59e;
    --accent-peach-bg: rgba(255, 181, 158, 0.08);
    --accent-peach-line: rgba(255, 181, 158, 0.35);
    --accent-lilac: #d9a8e8;
    --accent-alt-bg: rgba(140, 80, 180, 0.1);
    --accent-alt-line: rgba(180, 100, 220, 0.45);
    --on-inverse: #111;
    /* ===== Phase 2-c：verify.css 收敛用的 token（暗色值 = 替换前的原字面量） =====
       --text-strong：verify 的代码块正文色（原来靠「未定义 → fallback #f2f2f2」侥幸生效，
       这里正式定义；全仓只有 verify.css 用它，不会影响别处）。
       --status-none-*：verify 的「无状态」灰胶囊（不在 --status-* 四色语义里，单列）。
       --accent-cobalt-*：verify 与 sponsors 都在用的钴紫 rgba(124,92,255,…) 家族
       （--primary-* / --accent-violet-* 是另一套紫，RGB 不同，故不能混用）。 */
    --text-strong: #f2f2f2;
    --surface-glass-active: rgba(255, 255, 255, 0.12);
    --border-glass-hover: rgba(255, 255, 255, 0.28);
    --status-none-bg: rgba(161, 161, 170, 0.08);
    --status-none-border: rgba(161, 161, 170, 0.30);
    --accent-cobalt-faint: rgba(124, 92, 255, 0.05);
    --accent-cobalt-bg: rgba(124, 92, 255, 0.07);
    --accent-cobalt-edge: rgba(124, 92, 255, 0.16);
    --accent-cobalt-line: rgba(124, 92, 255, 0.35);
    --accent-cobalt-ink: #c6bcff;

    /* ===== 更新日志「分类胶囊」配色（暗色值） =====
       亮色那套是给白底调的（浅底 #D1FAE5 + 深字 #065F46）；照搬到 #161616 的卡片上，
       浅底会亮成一块发光板、和暗色玻璃质感打架。所以暗色只保留**同一个色相**，
       换成「低透明度同色底 + 亮同色字」—— 与暗色 --status-* 的取法一致，两张主题读起来才是一套。
       ⚠ 只服务更新日志分类胶囊，别拿去改 --status-*（那是全站语义状态色）。 */
    --cl-tag-feature-bg: rgba(74, 222, 128, 0.14);   --cl-tag-feature-text: #6ee7a8;
    --cl-tag-fix-bg: rgba(248, 113, 113, 0.14);      --cl-tag-fix-text: #fca5a5;
    --cl-tag-improve-bg: rgba(96, 165, 250, 0.14);   --cl-tag-improve-text: #93c5fd;
    --cl-tag-change-bg: rgba(251, 191, 36, 0.14);    --cl-tag-change-text: #fcd34d;
    /* 安全：比「修复」更深一档的玫红（亮色是 #FECDD3/#881337 的暗色对应），
       既保住"红=危险"的警示，又能和普通 bug 修了一眼分开。**别与 fix 那行改成一样**。
       ⚠ 暗色下尤其要小心：修复那档是 #fca5a5（偏白的浅珊瑚），安全必须明显更"玫红"才分得开，
         所以字用 400 级 #fb7185（对比度约 5.7:1）、底再深一点 0.20；
         曾经写成 #fda4af（玫红-300）—— 和 #fca5a5 并排几乎分不出，别再改回去。 */
    --cl-tag-security-bg: rgba(244, 63, 94, 0.20);   --cl-tag-security-text: #fb7185;
    --cl-tag-notice-bg: rgba(161, 161, 170, 0.14);   --cl-tag-notice-text: #d4d4d8;

    /* 时间线圆点（暗色）：亮底上取 500 级实色，暗底上取胶囊文字色那一档的亮色，
       否则实心点压在半透明卡片上会糊成一团暗色。色相与胶囊严格一致。 */
    --cl-dot-feature: #6ee7a8;      --cl-dot-fix: #fca5a5;
    --cl-dot-improve: #93c5fd;      --cl-dot-change: #fcd34d;
    /* 安全的点比修复深一档（#f43f5e vs #fca5a5）：浅珊瑚与玫红并排才一眼分得开 */
    --cl-dot-security: #f43f5e;     --cl-dot-notice: #d4d4d8;
}

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    scroll-behavior: smooth;
    scroll-padding-top: 96px;
}

body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    position: relative;
    /* clip 与 hidden 效果一致，但不会破坏 position: sticky 子元素的吸附行为 */
    overflow-x: clip;
    background-color: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: var(--text-body-md);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

a {
    color: inherit;
    text-decoration: none;
    transition: color var(--transition-fast);
}

button,
input,
textarea,
select {
    font: inherit;
    border: 0;
    background: none;
    cursor: pointer;
}

img {
    display: block;
    max-width: 100%;
}

code {
    font-family: var(--font-mono);
}

::selection {
    background: rgba(183, 109, 255, 0.4);
    color: #ffffff;
}

a:focus-visible,
button:focus-visible,
.faq-question:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track {
    background: var(--bg);
}

::-webkit-scrollbar-thumb {
    background: var(--surface-high);
    border-radius: var(--radius-pill);
}

::-webkit-scrollbar-thumb:hover {
    background: var(--primary-container);
}

/* Material Symbols 尺寸工具（模板用法） */
.material-symbols-outlined {
    font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
    line-height: 1;
}

.md-16 { font-size: 16px; width: 16px; height: 16px; }
.md-18 { font-size: 18px; width: 18px; height: 18px; }
.md-20 { font-size: 20px; width: 20px; height: 20px; }
.md-24 { font-size: 24px; width: 24px; height: 24px; }

/* ============ 减少动态效果（无障碍） ============ */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .reveal {
        opacity: 1;
        transform: none;
    }
}

/* ============ 骨架屏（Skeleton） ============
   异步数据到达前的占位块，带「微光扫过」动画；数据就绪后由 JS 整体替换为真实内容。
   基类只提供底色 + 扫光，尺寸变体在各页面 CSS 里按真实内容对齐。 */
.skeleton {
    position: relative;
    overflow: hidden;
    background: var(--surface-low);
    border-radius: 6px;
    color: transparent !important;
    pointer-events: none;
}

.skeleton::after {
    content: '';
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.06), transparent);
    animation: skeleton-shimmer 1.4s var(--ease) infinite;
}

@keyframes skeleton-shimmer {
    100% { transform: translateX(100%); }
}

/* --- Phase 2d：赞助页专用 token（暗色值 = 替换前的原字面量）--- */
:root {
    /* 徽章渐变末端：暗色 = 原 --primary-container 暗色值（逐字节不变），亮色单列以避开
       共享 --primary-container（它的亮色值被后台头像/logo 的黑色文字依赖，见 Phase 2d 汇报）*/
    --sp-badge-grad-end: #b76dff;
    --sp-income: #c4b5fd;
    --sp-expense: #fca5a5;
    --sp-subsidy: #fcd34d;
    --sp-ok-text: #86efac;
    --sp-m-wechat-line: rgba(134, 239, 172, 0.3);
    --sp-m-wechat-bg: rgba(34, 197, 94, 0.08);
    --sp-m-alipay: #93c5fd;
    --sp-m-alipay-line: rgba(147, 197, 253, 0.3);
    --sp-m-alipay-bg: rgba(59, 130, 246, 0.08);
    --sp-m-qq-line: rgba(252, 211, 77, 0.3);
    --sp-m-qq-bg: rgba(234, 179, 8, 0.08);
    --sp-gold-line: rgba(252, 211, 77, 0.6);
    --sp-gold-bg: rgba(252, 211, 77, 0.08);
    --sp-silver: #d1d5db;
    --sp-silver-line: rgba(209, 213, 219, 0.5);
    --sp-silver-bg: rgba(209, 213, 219, 0.06);
    --sp-bronze: #fdba74;
    --sp-bronze-line: rgba(253, 186, 116, 0.5);
    --sp-bronze-bg: rgba(253, 186, 116, 0.06);
    --sp-border-strong: rgba(255, 255, 255, 0.15);
    --sp-danger-solid: #be2d41;
    --sp-accent-line: #7c5cff;
    --sp-on-strong: #1a1426;

}

/* --- Phase 2d：赞助页专用 token 的亮色值（均按亮底对比度挑选）--- */
:root[data-theme="light"] {
    --sp-badge-grad-end: #7c3aed;
    --sp-income: #6d28d9;
    --sp-expense: #b91c1c;
    --sp-subsidy: #92400e;
    --sp-ok-text: #15803d;
    --sp-m-wechat-line: rgba(21, 128, 61, 0.35);
    --sp-m-wechat-bg: rgba(21, 128, 61, 0.08);
    --sp-m-alipay: #1d4ed8;
    --sp-m-alipay-line: rgba(29, 78, 216, 0.35);
    --sp-m-alipay-bg: rgba(29, 78, 216, 0.08);
    --sp-m-qq-line: rgba(146, 64, 14, 0.35);
    --sp-m-qq-bg: rgba(146, 64, 14, 0.08);
    --sp-gold-line: rgba(146, 64, 14, 0.45);
    --sp-gold-bg: rgba(146, 64, 14, 0.08);
    --sp-silver: #374151;
    --sp-silver-line: rgba(55, 65, 81, 0.45);
    --sp-silver-bg: rgba(55, 65, 81, 0.06);
    --sp-bronze: #9a3412;
    --sp-bronze-line: rgba(154, 52, 18, 0.45);
    --sp-bronze-bg: rgba(154, 52, 18, 0.06);
    --sp-border-strong: rgba(20, 20, 26, 0.18);
    --sp-danger-solid: #b91c1c;
    --sp-accent-line: #6d28d9;
    --sp-on-strong: #ffffff;
/* Phase 2d 补：赞助页阴影（亮色值并入本亮色块，暗色值另起 :root）*/
    --sp-shadow-soft: rgba(20, 20, 26, 0.10);
}

:root {
    --sp-shadow-soft: rgba(0, 0, 0, 0.3);
}

/* --- Phase 2d 收尾：sponsors.css 剩余字面量 → token（暗色值 = 替换前的原字面量）--- */
:root {
    --sp-gold-line-soft: rgba(252, 211, 77, 0.4);
    --primary-edge-hover: rgba(221, 183, 255, 0.45);
    --primary-glow: rgba(221, 183, 255, 0.3);
    --sp-shadow-lift: rgba(0, 0, 0, 0.45);
    --sp-hero-fade-to: rgba(255, 255, 255, 0.55);
}

:root[data-theme="light"] {
    --sp-gold-line-soft: rgba(146, 64, 14, 0.45);
    --primary-edge-hover: rgba(124, 58, 237, 0.45);
    --primary-glow: rgba(124, 58, 237, 0.20);
    --sp-shadow-lift: rgba(20, 20, 26, 0.16);
    --sp-hero-fade-to: rgba(20, 20, 26, 0.62);
}
/* Phase 2e 补：文档站专用（docs/css/style.css）
   --primary-line        爱发电/主色描边档 .5（文档 TOC 按钮展开态、正文链接下划线）
   --docs-float-bg       文档站漂浮控件底（暗色半透明深底 / 亮色半透明浅底；文字用 var(--text) 会跟着翻 ✗）
   --docs-float-bg-soft  同上，稍弱一档（圆形小按钮 .62）
   暗色值 = 被替换的原字面量（逐字节相同 ✗）；亮色值按实际叠加挑，保证文字可读 ✔ */
:root {
    --primary-line: rgba(221, 183, 255, 0.5);
    --docs-float-bg: rgba(0, 0, 0, 0.72);
    --docs-float-bg-soft: rgba(0, 0, 0, 0.62);
}

:root[data-theme=light] {
    --primary-line: rgba(124, 58, 237, 0.5);
    --docs-float-bg: rgba(255, 255, 255, 0.92);
    --docs-float-bg-soft: rgba(255, 255, 255, 0.88);
}

/* Phase 2g：文档站页头专用 token（只服务 docs/css/style.css 的 .docs-hero，两个主题都定义 ✔）
   背景：窄屏（≤900px）的 .docs-hero 是**粘在导航栏下方的毛玻璃条**，原先直接借
   var(--scrim-strong)（亮色 = rgba(0,0,0,.45)）—— 那是给「整屏遮罩」用的档位，
   压在白色正文上合成出 #8c8c8c 的中灰，亮色下灰得刺眼 ✗（用户实测反馈）。
   ⚠ --scrim-strong 是**全站共享** token（其它页的遮罩/菜单都在用），不能改它的亮色值 ✔
   → 另起一个只给文档页头的档位，两主题各一份：
     --docs-hero-bg         页头毛玻璃底色（**浅色/淡**的那一层，不是遮罩）
     --docs-hero-chip-bg    页头里两个控制件（目录 / 本页目录）的胶囊底
     --docs-hero-chip-bg-strong  上面那个的**强一档**（「本页目录」占用，用于拉开层级）
     --docs-hero-chip-border     胶囊描边
   暗色值 = 改动前的原字面量等价值（外观不变 ✗）；亮色值按「浅底 + 合成后算对比度」挑 ✔ */
:root {
    --docs-hero-bg: rgba(0, 0, 0, 0.72);
    --docs-hero-chip-bg: rgba(255, 255, 255, 0.06);
    --docs-hero-chip-bg-strong: rgba(255, 255, 255, 0.12);
    --docs-hero-chip-border: rgba(255, 255, 255, 0.18);
}

:root[data-theme=light] {
    --docs-hero-bg: rgba(255, 255, 255, 0.86);
    --docs-hero-chip-bg: rgba(20, 20, 26, 0.07);
    --docs-hero-chip-bg-strong: rgba(20, 20, 26, 0.12);
    --docs-hero-chip-border: rgba(20, 20, 26, 0.18);
}

/* ============================================================================
   Phase 2f：活动页「前台」专用 token（只服务 css/activity.css 的前台段）
   规则同前几批：暗色值 = 被替换的原字面量（逐字节相同 → 暗色外观不变 ✗）；
   亮色值按「白底 + 实际叠加合成」重挑，正文级 ≥4.5:1 ✔（对比度按合成后的颜色算，
   不把 rgba(...,.1) 当不透明 ✗）。

   ★ 三组跨主题恒定（两个主题块里写同一个值，故意不翻 ✗）：
     --act-overlay-chip-* / --act-badge-*  压在活动封面**照片**上的深色胶囊
         （图是任意亮度的照片，亮色主题下同样必须深底亮字，否则角标糊在图上 ✗）
     --act-on-inverse / --act-chip-inset   深色胶囊、预览区上的前景与内高光
     --act-figure-shadow / --act-badge-shadow / --act-pre-bg   阴影与代码块底

   ★ 状态色统一（规则 5）：.activity-badge.* / .query-result .qr-winner /
     .join-done-title / .rg-error-quote 的文字改用已存在的 --status-ok|warn|danger
     （含 -bg/-border）—— 亮色值由 base.css 既有的状态色块提供。
     .ac-badge.*（封面胶囊）例外：它的底是**固定深色**，用 --status-* 的亮色值
     会掉到 1.1:1 ✗，故单列 --act-badge-fg-*（暗=原亮色，亮=原亮色不变）。 */
:root {
    /* --- 活动列表卡片 --- */
    --act-card-bg: rgba(25, 25, 25, 0.4);
    --act-card-bg-2: rgba(25, 25, 25, 0.45);
    --act-card-bg-hover: rgba(32, 32, 32, 0.6);

    /* --- 主色（爱发电紫 #ddb7ff 家族）描边 / 底 --- */
    --act-accent-line: rgba(221, 183, 255, 0.25);
    --act-accent-line-soft: rgba(221, 183, 255, 0.16);
    --act-accent-edge: rgba(221, 183, 255, 0.22);
    --act-accent-line-hover: rgba(221, 183, 255, 0.35);
    --act-accent-line-strong: rgba(221, 183, 255, 0.45);
    --act-accent-wash: rgba(221, 183, 255, 0.06);
    --act-note-bg: rgba(221, 183, 255, 0.07);
    --act-icon-bg: rgba(221, 183, 255, 0.12);
    --act-chip-strong-bg: rgba(221, 183, 255, 0.14);
    --act-icon-line: rgba(221, 183, 255, 0.18);
    --act-icon-line-strong: rgba(221, 183, 255, 0.2);
    --act-chip-strong-line: rgba(221, 183, 255, 0.3);
    --act-ticket-line: rgba(221, 183, 255, 0.4);
    --act-ticket-bg: rgba(221, 183, 255, 0.05);
    --act-example-head-bg: rgba(221, 183, 255, 0.08);
    --act-tab-active-bg: rgba(221, 183, 255, 0.10);
    --act-badge-open-bg: rgba(221, 183, 255, 0.12);
    --act-badge-open-line: rgba(221, 183, 255, 0.3);
    --act-joined-line: rgba(221, 183, 255, 0.42);

    /* --- 中性半透明白（卡片内嵌块 / 控件 / 交互档；hover 与 active 必须能区分）--- */
    --act-surface-faint: rgba(255, 255, 255, 0.025);
    --act-info-bg: rgba(255, 255, 255, 0.03);
    --act-row-bg: rgba(255, 255, 255, 0.035);
    --act-input-bg: rgba(255, 255, 255, 0.04);
    --act-btn2-bg-soft: rgba(255, 255, 255, 0.05);
    --act-img-bg: rgba(255, 255, 255, 0.05);
    --act-chip-bg: rgba(255, 255, 255, 0.06);
    --act-btn2-bg: rgba(255, 255, 255, 0.07);
    --act-code-bg: rgba(255, 255, 255, 0.08);
    --act-btn2-active-bg: rgba(255, 255, 255, 0.09);
    --act-btn2-hover-bg: rgba(255, 255, 255, 0.14);
    --act-btn2-hover-line: rgba(255, 255, 255, 0.28);

    /* 主色文字（= 原 --primary）：亮色 --primary #7c3aed 落在淡紫卡底上只有 4.42:1 ✗，
       活动页正文/图标改用更深的 #5b21b6（与 base.css 既有 --accent-cobalt-ink 同值，实测 ≥4.9:1 ✔）*/
    --act-accent-ink: #ddb7ff;

    /* --- 深色底 / 深色浮层（跨主题不变，压图用）--- */
    --act-pre-bg: rgba(0, 0, 0, 0.4);
    --act-badge-shadow: rgba(0, 0, 0, 0.5);
    --act-figure-shadow: rgba(0, 0, 0, 0.45);
    --act-overlay-chip-bg: rgba(10, 8, 16, 0.74);
    --act-chip-inset: rgba(255, 255, 255, 0.07);
    --act-badge-fg: rgba(255, 255, 255, 0.82);
    --act-on-inverse: #ffffff;
    --act-btn2-fg: #ffffff;
    --act-tab-active-fg: #ffffff;

    /* --- 封面状态胶囊：固定深底，文字沿用原亮色（两个主题同值）--- */
    --act-badge-fg-ok: #4ade80;
    --act-badge-fg-warn: #fbbf24;
    --act-badge-fg-done: #cbd5e1;
    --act-badge-fg-closed: #fca5a5;
    --act-badge-line-ok: rgba(74, 222, 128, 0.5);
    --act-badge-line-warn: rgba(251, 191, 36, 0.5);
    --act-badge-line-done: rgba(203, 213, 225, 0.38);
    --act-badge-line-closed: rgba(252, 165, 165, 0.5);

    /* --- 中奖名次（前三名，两主题同值）--- */
    --act-rank-top-ink: #c4b5fd;
    --act-rank-top-line: rgba(168, 85, 247, 0.55);

    /* --- 兑换指南安全提醒条（深琥珀底 + 亮琥珀字）--- */

    /* --- 报名弹窗提示条底（与 --status-warn-* 同色系，单独一档 0.08）--- */
    --act-notice-bg: rgba(251, 191, 36, 0.08);

    /* --- 详情页「活动信息」卡渐变三段 --- */
    --act-card-info-a: rgba(221, 183, 255, 0.10);
    --act-card-info-b: rgba(221, 183, 255, 0.02);
    --act-card-info-c: rgba(255, 255, 255, 0.03);
}

/* --- Phase 2f 亮色值（按白底实际叠加重挑；正文级 ≥4.5:1）--- */
:root[data-theme="light"] {
    --act-card-bg: rgba(20, 20, 26, 0.035);
    --act-card-bg-2: rgba(20, 20, 26, 0.04);
    --act-card-bg-hover: rgba(20, 20, 26, 0.065);

    --act-accent-line: rgba(124, 58, 237, 0.30);
    --act-accent-line-soft: rgba(124, 58, 237, 0.20);
    --act-accent-edge: rgba(124, 58, 237, 0.28);
    --act-accent-line-hover: rgba(124, 58, 237, 0.45);
    --act-accent-line-strong: rgba(124, 58, 237, 0.55);
    --act-accent-wash: rgba(124, 58, 237, 0.08);
    --act-note-bg: rgba(124, 58, 237, 0.07);
    --act-icon-bg: rgba(124, 58, 237, 0.12);
    --act-chip-strong-bg: rgba(124, 58, 237, 0.14);
    --act-icon-line: rgba(124, 58, 237, 0.20);
    --act-icon-line-strong: rgba(124, 58, 237, 0.26);
    --act-chip-strong-line: rgba(124, 58, 237, 0.34);
    --act-ticket-line: rgba(124, 58, 237, 0.45);
    --act-ticket-bg: rgba(124, 58, 237, 0.06);
    --act-example-head-bg: rgba(124, 58, 237, 0.08);
    --act-tab-active-bg: rgba(124, 58, 237, 0.14);
    --act-badge-open-bg: rgba(124, 58, 237, 0.12);
    --act-badge-open-line: rgba(124, 58, 237, 0.34);
    --act-joined-line: rgba(124, 58, 237, 0.45);

    --act-surface-faint: rgba(20, 20, 26, 0.03);
    --act-info-bg: rgba(20, 20, 26, 0.035);
    --act-row-bg: rgba(20, 20, 26, 0.04);
    --act-input-bg: rgba(20, 20, 26, 0.045);
    --act-btn2-bg-soft: rgba(20, 20, 26, 0.05);
    --act-img-bg: rgba(20, 20, 26, 0.06);
    --act-chip-bg: rgba(20, 20, 26, 0.06);
    --act-btn2-bg: rgba(20, 20, 26, 0.07);
    --act-code-bg: rgba(20, 20, 26, 0.08);
    --act-btn2-active-bg: rgba(20, 20, 26, 0.10);
    --act-btn2-hover-bg: rgba(20, 20, 26, 0.12);
    --act-btn2-hover-line: rgba(20, 20, 26, 0.22);

    --act-accent-ink: #5b21b6;

    /* 预览/浮层区：亮色下改成浅底，`--text-muted` 代码字在浅底上 5.8:1 ✔ */
    --act-pre-bg: rgba(20, 20, 26, 0.05);

    /* 报名弹窗提示条：亮色下用更深的琥珀字 + 更淡的琥珀底（按叠加挑） */
    --act-notice-bg: rgba(180, 83, 9, 0.08);

    /* 次级按钮 hover/active 的文字必须跟着翻（暗色原值 #fff，亮色下要深墨） */
    --act-btn2-fg: #14141a;

    /* 兑换 Tab 选中态：底已变浅紫，白字只剩 1.2:1 ✗ → 亮色下用深紫字（按浅紫底实测 ≥4.5:1） */
    --act-tab-active-fg: #4c1d95;

    --act-card-info-a: rgba(124, 58, 237, 0.10);
    --act-card-info-b: rgba(124, 58, 237, 0.03);
    --act-card-info-c: rgba(20, 20, 26, 0.03);
}

/* 亮色块里「与暗色相同」的那批：显式再写一遍（防误改，读起来也清楚 ✔） */
:root[data-theme="light"] {
    --act-badge-shadow: rgba(0, 0, 0, 0.5);
    --act-figure-shadow: rgba(0, 0, 0, 0.45);
    --act-overlay-chip-bg: rgba(10, 8, 16, 0.74);
    --act-chip-inset: rgba(255, 255, 255, 0.07);
    --act-badge-fg: rgba(255, 255, 255, 0.82);
    --act-on-inverse: #ffffff;
    --act-badge-fg-ok: #4ade80;
    --act-badge-fg-warn: #fbbf24;
    --act-badge-fg-done: #cbd5e1;
    --act-badge-fg-closed: #fca5a5;
    --act-badge-line-ok: rgba(74, 222, 128, 0.5);
    --act-badge-line-warn: rgba(251, 191, 36, 0.5);
    --act-badge-line-done: rgba(203, 213, 225, 0.38);
    --act-badge-line-closed: rgba(252, 165, 165, 0.5);
    --act-rank-top-ink: #c4b5fd;
    --act-rank-top-line: rgba(168, 85, 247, 0.55);
}
/* ============================================================================
   Phase 2g：活动页「后台段」专用 token（只服务 css/activity.css 后台段 +
   css/sponsors.css 的两处交接项）
   规则与前几批一致：暗色值 = 被替换的原字面量（逐字节相同 → 暗色外观不变）；
   亮色值按「白底 + 实际叠加合成」重挑，正文级 ≥4.5:1。

   ★ 状态色统一（规则 4）：#fbbf24 / #4ade80 / #f87171 / #22c55e 的**卡片前景与淡底**
     用法改用既有 --status-warn|ok|danger|info（暗色逐字节相同；亮色值由 base.css
     既有状态色块提供，正文级 ≥4.5:1）。压在**固定深色胶囊/深底**上的同名色**不并入**，
     单列 --admin-badge-fg-*（同一行的 --admin-danger-bg-soft / --admin-danger-line
      全站无 var() 引用，已按死 token 清理删除；--admin-danger-line 的取值与**仍在使用**的
      --admin-danger-line-soft 逐字节相同，删除不改变任何渲染）。

   ★ 交互态不合并（规则 2）：中性表面按 base/hover/active 分档，每档一个 token
     （0.02/0.022/0.025/0.03/0.035/0.04/0.05/0.06/0.07/0.08/0.09/0.12/0.13/0.2）；
     主色描边分档 0.22/0.28/0.3/0.32/0.34/0.38/0.4/0.5，不做 Δ≤0.02 的合并
     （原 0.25 那一档 --admin-primary-edge 全站无 var() 引用，已按死 token 清理删除）。
     这里没有 Δ≤0.02 的合并对：唯一同值的一对是
     --admin-badge-fg-danger / --admin-badge-fg-warn（不同角色的同色常量），
     逐字节等价，不构成视觉变化。
     （同批删除的还有：--admin-ok-bg-soft（与 --admin-ok-bg 同值同语义、无引用）、
      --admin-maint-line-soft、--admin-warn-ink-bright、--admin-gray-ink ——
      --admin-gray-ink 与仍在用的 --admin-neutral-ink 取值逐字节相同。） */
:root {
    /* --- 后台骨架：顶栏 / 侧栏 / 卡片 / 登录卡 / 压暗层 --- */
    --admin-topbar-bg: rgba(5, 5, 5, 0.92);
    --admin-sidebar-bg: rgba(8, 8, 8, 0.55);
    --admin-card-bg: rgba(15, 15, 15, 0.8);
    --admin-login-card-bg: rgba(16, 16, 16, 0.85);
    --admin-overlay-deep: rgba(0, 0, 0, 0.42);
    --admin-overlay-scrim: rgba(0, 0, 0, 0.35);
    --admin-overlay-shadow: rgba(0, 0, 0, 0.55);
    --admin-table-head-bg: #17151c;

    /* --- 半透明中性表面（按 base/hover/active 分档；不合并交互态）--- */
    --admin-surface-faintest: rgba(255, 255, 255, 0.02);
    --admin-surface-faint: rgba(255, 255, 255, 0.022);
    --admin-surface-soft: rgba(255, 255, 255, 0.025);
    --admin-surface-base: rgba(255, 255, 255, 0.03);
    --admin-surface-raised: rgba(255, 255, 255, 0.035);
    --admin-surface-input: rgba(255, 255, 255, 0.04);
    --admin-surface-chip: rgba(255, 255, 255, 0.05);
    --admin-surface-soft-strong: rgba(255, 255, 255, 0.06);
    --admin-surface-code: rgba(255, 255, 255, 0.07);
    --admin-surface-strong: rgba(255, 255, 255, 0.08);
    --admin-surface-stronger: rgba(255, 255, 255, 0.09);
    --admin-surface-hover: rgba(255, 255, 255, 0.12);
    --admin-surface-prone: rgba(255, 255, 255, 0.13);
    --admin-surface-hover-line: rgba(255, 255, 255, 0.2);

    /* --- 反相实心按钮（白底黑字 / 灰 hover）--- */
    --admin-inverse-bg: #ffffff;
    --admin-inverse-fg: #000000;
    --admin-avatar-fg: #000000;
    --admin-inverse-hover: #e7e7e7;

    /* --- 原生下拉 option（原生控件不吃主题继承，显式给两套值）--- */
    --admin-option-bg: #1e1e1e;
    --admin-option-fg: #f2f2f2;

    /* --- 后台主色（爱发电紫 #ddb7ff 家族）底 / 描边 / 焦点环 --- */
    --admin-primary-bg: rgba(221, 183, 255, 0.05);
    --admin-primary-chip-bg: rgba(221, 183, 255, 0.08);
    --admin-primary-icon-bg: rgba(221, 183, 255, 0.07);
    --admin-primary-faint-bg: rgba(221, 183, 255, 0.02);
    --admin-primary-bg-strong: rgba(221, 183, 255, 0.1);
    --admin-primary-bg-stronger: rgba(221, 183, 255, 0.14);
    --admin-primary-focus-ring: rgba(221, 183, 255, 0.1);
    --admin-primary-line: rgba(221, 183, 255, 0.22);
    --admin-primary-line-strong: rgba(221, 183, 255, 0.3);
    --admin-primary-line-stronger: rgba(221, 183, 255, 0.34);
    --admin-avatar-bg: rgba(221, 183, 255, 0.12);
    --admin-primary-on: #0b0a10;

    /* --- 后台正文前景 --- */
    --admin-fg-disabled: #6b6b73;
    --admin-fg-placeholder: #4e4e55;
    --admin-neutral-ink: #9ca3af;
    --admin-info-ink: #8ecbff;

    /* --- 后台信息色 --- */
    --admin-sky-ink: #7dd3fc;
    --admin-ok-bright: #22c55e;
    --admin-ok-fg-soft: #86efac;
    --admin-danger-solid: #e5484d;
    --admin-danger-fg: #ffffff;
    --admin-danger-soft-ink: #fca5a5;
    --admin-badge-fg-danger: #fecaca;
    --admin-badge-fg-danger-soft: #fed7aa;
    --admin-badge-fg-warn: #fde68a;
    --admin-check-ink: #7ee2b8;
    --admin-maint-ink: #fabc4e;
    --admin-orange-ink: #fb923c;
    --admin-red-solid: #ef4444;

    /* --- 红：高/严重风险、确认删除 --- */
    --admin-red-focus: rgba(239, 68, 68, 0.18);
    --admin-red-bg: rgba(239, 68, 68, 0.07);
    --admin-red-line: rgba(239, 68, 68, 0.32);
    --admin-red-bg-strong: rgba(239, 68, 68, 0.12);
    --admin-red-line-strong: rgba(239, 68, 68, 0.35);
    --admin-danger-bg: rgba(248, 113, 113, 0.08);
    --admin-danger-bg-strong: rgba(248, 113, 113, 0.12);
    --admin-danger-line-strong: rgba(248, 113, 113, 0.45);
    --admin-badge-danger-bg: rgba(248, 113, 113, 0.28);
    --admin-danger-bg-faint: rgba(248, 113, 113, 0.06);
    --admin-danger-bg-050: rgba(248, 113, 113, 0.05);
    --admin-danger-line-035: rgba(248, 113, 113, 0.35);
    --admin-danger-line-soft: rgba(252, 165, 165, 0.45);

    /* --- 绿 / 薄荷 / 琥珀 / 橙 / 蓝 / 灰 状态底 --- */
    --admin-ok-bg: rgba(74, 222, 128, 0.1);
    --admin-ok-bg-faint: rgba(74, 222, 128, 0.08);
    --admin-ok-line-soft: rgba(74, 222, 128, 0.25);
    --admin-ok-line-strong: rgba(74, 222, 128, 0.45);
    --admin-check-bg: rgba(52, 211, 153, 0.12);
    --admin-check-line: rgba(52, 211, 153, 0.3);
    --admin-gray-bg: rgba(156, 163, 175, 0.1);
    --admin-gray-line: rgba(156, 163, 175, 0.3);
    --admin-orange-line: rgba(251, 146, 60, 0.4);
    --admin-orange-bg-soft: rgba(251, 146, 60, 0.07);
    --admin-orange-bg: rgba(251, 146, 60, 0.12);
    --admin-orange-line-strong: rgba(251, 146, 60, 0.32);
    --admin-orange-badge-bg: rgba(251, 146, 60, 0.26);
    --admin-maint-bg: rgba(250, 188, 78, 0.1);
    --admin-maint-line: rgba(250, 188, 78, 0.32);
    --admin-warn-bg-hint: rgba(251, 191, 36, 0.09);
    --admin-warn-bg-row: rgba(251, 191, 36, 0.06);
    --admin-warn-line-soft: rgba(251, 191, 36, 0.25);
    --admin-warn-line-strong: rgba(251, 191, 36, 0.45);
    --admin-badge-warn-bg: rgba(251, 191, 36, 0.22);
    --admin-blue-line: rgba(56, 189, 248, 0.45);
    --admin-blue-bg: rgba(56, 189, 248, 0.1);

    /* --- 有限编辑：禁用字段 --- */
    --admin-disabled-bg: #0e0e10;
    --admin-disabled-line: #232326;

    /* --- 安全事件标签按钮（可点筛选：hover / active 分档）--- */
    --admin-chip-hover-line: rgba(255, 255, 255, 0.55);
    --admin-chip-active-bg: rgba(138, 92, 255, 0.22);
    --admin-chip-active-line: #8a5cff;
    --admin-chip-active-fg: #e9d7ff;
    --admin-chip-active-ring: rgba(138, 92, 255, 0.25);
}

/* ============================================================================
   Phase 2g：亮色值。**必须排在本文件所有裸 :root 之后** —— base.css 的历史结构是
   「亮色块在前、若干裸 :root 在后」，裸 :root 会反超同特异度的亮色块
   （:root[data-theme="light"] 0,1,1 > :root 0,1,0，但两者写在同一个块序列里时
   仍然遵循「后出现者胜」对**同特异性**的情形；这里亮色块写在最后最稳）。 */
:root[data-theme="light"] {
    --admin-topbar-bg: rgba(255, 255, 255, 0.9);
    --admin-sidebar-bg: #fafafa;
    --admin-card-bg: #fcfcfd;
    --admin-login-card-bg: #ffffff;
    --admin-overlay-deep: rgba(255, 255, 255, 0.7);
    --admin-overlay-scrim: rgba(20, 20, 26, 0.05);
    --admin-overlay-shadow: rgba(20, 20, 26, 0.16);
    --admin-table-head-bg: #f2f2f4;

    --admin-surface-faintest: rgba(20, 20, 26, 0.02);
    --admin-surface-faint: rgba(20, 20, 26, 0.022);
    --admin-surface-soft: rgba(20, 20, 26, 0.025);
    --admin-surface-base: rgba(20, 20, 26, 0.03);
    --admin-surface-raised: rgba(20, 20, 26, 0.035);
    --admin-surface-input: rgba(20, 20, 26, 0.04);
    --admin-surface-chip: rgba(20, 20, 26, 0.05);
    --admin-surface-soft-strong: rgba(20, 20, 26, 0.06);
    --admin-surface-code: rgba(20, 20, 26, 0.07);
    --admin-surface-strong: rgba(20, 20, 26, 0.08);
    --admin-surface-stronger: rgba(20, 20, 26, 0.09);
    --admin-surface-hover: rgba(20, 20, 26, 0.12);
    --admin-surface-prone: rgba(20, 20, 26, 0.13);
    --admin-surface-hover-line: rgba(20, 20, 26, 0.2);

    --admin-inverse-bg: #14141a;
    --admin-inverse-fg: #ffffff;
    --admin-avatar-fg: #ffffff;
    --admin-inverse-hover: #2a2a30;

    --admin-option-bg: #ffffff;
    --admin-option-fg: #14141a;

    --admin-primary-bg: rgba(124, 58, 237, 0.06);
    --admin-primary-chip-bg: rgba(124, 58, 237, 0.08);
    --admin-primary-icon-bg: rgba(124, 58, 237, 0.07);
    --admin-primary-faint-bg: rgba(124, 58, 237, 0.03);
    --admin-primary-bg-strong: rgba(124, 58, 237, 0.1);
    --admin-primary-bg-stronger: rgba(124, 58, 237, 0.14);
    --admin-primary-focus-ring: rgba(124, 58, 237, 0.12);
    --admin-primary-line: rgba(124, 58, 237, 0.28);
    --admin-primary-line-strong: rgba(124, 58, 237, 0.38);
    --admin-primary-line-stronger: rgba(124, 58, 237, 0.42);
    --admin-avatar-bg: rgba(124, 58, 237, 0.12);
    --admin-primary-on: #ffffff;

    --admin-fg-disabled: rgba(20, 20, 26, 0.55);
    --admin-fg-placeholder: rgba(20, 20, 26, 0.42);
    --admin-neutral-ink: #52525b;
    --admin-info-ink: #1d4ed8;

    --admin-sky-ink: #0369a1;
    --admin-ok-bright: #15803d;
    --admin-ok-fg-soft: #15803d;
    --admin-danger-solid: #c0202a;
    --admin-danger-fg: #ffffff;
    --admin-danger-soft-ink: #991b1b;
    --admin-badge-fg-danger: #991b1b;
    --admin-badge-fg-danger-soft: #9a3412;
    --admin-badge-fg-warn: #7c2d12;
    --admin-check-ink: #15803d;
    --admin-maint-ink: #92400e;
    --admin-orange-ink: #c2410c;
    --admin-red-solid: #dc2626;

    --admin-red-focus: rgba(220, 38, 38, 0.18);
    --admin-red-bg: rgba(220, 38, 38, 0.07);
    --admin-red-line: rgba(220, 38, 38, 0.35);
    --admin-red-bg-strong: rgba(220, 38, 38, 0.1);
    --admin-red-line-strong: rgba(220, 38, 38, 0.4);
    --admin-danger-bg: rgba(220, 38, 38, 0.07);
    --admin-danger-bg-strong: rgba(220, 38, 38, 0.1);
    --admin-danger-line-strong: rgba(220, 38, 38, 0.5);
    --admin-badge-danger-bg: rgba(220, 38, 38, 0.22);
    --admin-danger-bg-faint: rgba(220, 38, 38, 0.07);
    --admin-danger-bg-050: rgba(220, 38, 38, 0.06);
    --admin-danger-line-035: rgba(220, 38, 38, 0.4);
    --admin-danger-line-soft: rgba(220, 38, 38, 0.4);

    --admin-ok-bg: rgba(21, 128, 61, 0.1);
    --admin-ok-bg-faint: rgba(21, 128, 61, 0.08);
    --admin-ok-line-soft: rgba(21, 128, 61, 0.28);
    --admin-ok-line-strong: rgba(21, 128, 61, 0.45);
    --admin-check-bg: rgba(21, 128, 61, 0.1);
    --admin-check-line: rgba(21, 128, 61, 0.3);
    --admin-gray-bg: rgba(20, 20, 26, 0.08);
    --admin-gray-line: rgba(20, 20, 26, 0.22);
    --admin-orange-line: rgba(194, 65, 12, 0.45);
    --admin-orange-bg-soft: rgba(194, 65, 12, 0.07);
    --admin-orange-bg: rgba(194, 65, 12, 0.12);
    --admin-orange-line-strong: rgba(194, 65, 12, 0.38);
    --admin-orange-badge-bg: rgba(194, 65, 12, 0.22);
    --admin-maint-bg: rgba(146, 64, 14, 0.1);
    --admin-maint-line: rgba(146, 64, 14, 0.36);
    --admin-warn-bg-hint: rgba(180, 83, 9, 0.1);
    --admin-warn-bg-row: rgba(180, 83, 9, 0.07);
    --admin-warn-line-soft: rgba(180, 83, 9, 0.32);
    --admin-warn-line-strong: rgba(180, 83, 9, 0.5);
    --admin-badge-warn-bg: rgba(180, 83, 9, 0.2);
    --admin-blue-line: rgba(3, 105, 161, 0.45);
    --admin-blue-bg: rgba(3, 105, 161, 0.1);

    --admin-disabled-bg: #f2f2f4;
    --admin-disabled-line: #dcdce1;

    --admin-chip-hover-line: rgba(20, 20, 26, 0.5);
    --admin-chip-active-bg: rgba(124, 58, 237, 0.18);
    --admin-chip-active-line: #7c3aed;
    --admin-chip-active-fg: #4c1d95;
    --admin-chip-active-ring: rgba(124, 58, 237, 0.25);
}

/* --- Phase 2g：赞助页交接项（后台容器变白后必须跟着翻）--- */
:root {
    --sp-danger-soft-line: rgba(252, 165, 165, 0.4);
    --sp-danger-soft-bg: rgba(248, 113, 113, 0.1);
}

:root[data-theme="light"] {
    --sp-danger-soft-line: rgba(153, 27, 27, 0.4);
    --sp-danger-soft-bg: rgba(153, 27, 27, 0.08);
}
/* ============================================================================
   Phase 2h：文章页专用 token（只服务 css/article.css 的 .art-* / .artd-*）
   规则与前几批一致：暗色值 = 被替换的原字面量（逐字节相同 → 暗色外观逐像素不变）；
   亮色值按「白底 + 实际叠加合成」重挑，正文级 ≥4.5:1（对比度按合成后的颜色算，
   不把 rgba(...,.05) 当不透明）。

   ★ 交互态不合并（规则 2）：中性表面 base/hover/active 分档，
     0.02/0.03/0.04/0.05/0.06/0.07/0.08/0.10/0.12/0.14/0.18/0.20/0.28 各一档。
     能对上 base.css 既有 token 且**暗色值逐字节相同**的，直接复用（下面各组有注）；
     对不上的（0.07 / 0.14 / 0.34 / 0.10 / 0.18 / 0.22 / 0.24 / 0.75 / 0.3 / 0.4 …）单列 --art-*。

   ★ 状态色（规则 4）：文章页的「成功」文字色 #4ade80 与 base.css 既有 --status-ok
     暗色值逐字节相同 → 并入 --status-ok（亮色由既有状态色块给 #14532d，正文级达标）。
     其余橙/红/绿档（#f5c97b / #ff8a8a / #7ed0a5 / #ef9a9a / rgba(255,179,71,…) /
     rgba(74,222,128,.24|.75|.07) / rgba(248,113,113,.24|.75|.07) / rgba(76,175,125,…) /
     rgba(224,110,110,…) / #5aa9e6 / #4caf7d / #e0a33e）**不并入** --status-*
     家族：它们的暗色值（含 alpha 档）与 --status-* 并不相同，并入即改变暗色外观
     （规则 2 不允许把 Δ≠0 的两色合一），故各给独立 --art-* token。

   ★ 跨主题恒定（两个主题块里写同一个值，故意不翻）：这批颜色的载体**不是页面底色**，
     而是「任意亮度的东西」——压在封面照片上的角标/遮罩/阴影、视频黑底、图片灯箱。
     亮色主题下把它们翻成浅色会当场不可读（与 Phase 2f 的 --act-overlay-chip-*、
     --act-pre-bg 同理）：
       --art-overlay-chip-*   封面图左上/右上角标（分类 / 置顶 / 归档）
       --art-chip-fg-*        同上角标的文字/描边（底是固定深色）
       --art-hero-veil*       封面图上压字的压暗渐变
       --art-hero-shadow*     封面标题的文字阴影
       --art-hero-meta        封面元信息文字（压在图/渐变上）
       --art-media-bg         视频播放器黑底（信箱边必须是黑的）
       --art-lb-*             图片灯箱（整屏 88% 黑幕 + 深色控件 + 缩略图条）

   ★ 浮动目录开关/抽屉（--art-float-* / --art-drawer-*）**翻主题**：
     .artd-toc-toggle 是 JS 追加到 <body> 的元素，读不到 .artd-page 上的 --art-accent，
     原来的 `var(--text, #eee)` 在亮色下会算出「深墨字 + 原深色底」（≈1.2:1，实测坏掉），
     所以这里给它们成套的两主题值；暗色值与替换前逐字节相同。
   ========================================================================== */
:root {
    /* --- 列表页：筛选条 / 卡片 / 分页 / 空状态 / 骨架屏 --- */
    --art-surface-hover: rgba(255, 255, 255, 0.07);      /* 卡片外控件 hover 底（0.06 已被 --surface-glass-hover 占用）*/
    --art-card-bg: rgba(25, 25, 25, 0.45);               /* .art-card / .art-skeleton 底 */
    --art-card-bg-hover: rgba(30, 30, 30, 0.62);         /* .art-card:hover 底 */
    --art-card-line-hover: rgba(221, 183, 255, 0.34);    /* .art-card:hover 描边（0.4 是另一档，见 --primary-edge-strongest）*/
    --art-block-bg: rgba(25, 25, 25, 0.4);               /* 扩展块卡底（手风琴/图集/对比/数据卡）*/
    --art-primary-bg: rgba(221, 183, 255, 0.10);         /* 选中胶囊底（--primary-bg 是 0.12，不许合并）*/
    --art-primary-chip-bg: rgba(221, 183, 255, 0.18);    /* 选中胶囊里的计数徽章底 */
    --art-primary-line: rgba(221, 183, 255, 0.3);        /* 主题色描边兜底（--art-accent-line 未定义时的回退）*/
    --art-cover-glow: rgba(183, 109, 255, 0.14);         /* 无封面时的紫光兜底渐变 */
    --art-hero-glow: rgba(183, 109, 255, 0.18);          /* 详情页封面兜底渐变 */
    --art-code-bg: rgba(0, 0, 0, 0.4);                   /* 代码块底（--surface-sunken 是 0.35，不许合并）*/
    --art-cover-shadow: rgba(0, 0, 0, 0.45);             /* card 模式主图投影 */

    /* --- 主色描边/淡底（爱发电紫 #ddb7ff 家族；能与既有 token 逐字节相同的已直接复用）--- */
    --art-ghost-hover-line: rgba(221, 183, 255, 0.6);
    --art-ghost-hover-bg: rgba(221, 183, 255, 0.16);
    --art-callout-line: rgba(221, 183, 255, 0.18);
    --art-callout-info-line: rgba(221, 183, 255, 0.22);
    --art-callout-bg: rgba(221, 183, 255, 0.07);

    /* --- 琥珀 warn（归档条 / warn 提示框 / 时间线 warn 点）--- */
    --art-warn-ink: #f5c97b;
    --art-warn-line: rgba(255, 179, 71, 0.3);
    --art-warn-bg: rgba(255, 179, 71, 0.07);
    --art-warn-dot: #e0a33e;
    --art-callout-warn-line: rgba(255, 179, 71, 0.24);
    --art-callout-warn-edge: rgba(255, 179, 71, 0.75);
    --art-callout-warn-bg: rgba(255, 179, 71, 0.08);
    --art-callout-warn-text: rgba(245, 201, 123, 0.86);

    /* --- 绿 ok（复制成功 / success 提示框 / 对比卡 pro / 数据卡上升 / info 点）--- */
    --art-copy-ok-line: rgba(74, 222, 128, 0.4);
    --art-copy-ok-bg: rgba(74, 222, 128, 0.1);
    --art-callout-ok-line: rgba(74, 222, 128, 0.24);
    --art-callout-ok-edge: rgba(74, 222, 128, 0.75);
    --art-callout-ok-bg: rgba(74, 222, 128, 0.07);
    --art-callout-ok-text: rgba(160, 230, 180, 0.86);
    --art-ok-ink: #7ed0a5;
    --art-ok-line: rgba(76, 175, 125, 0.45);
    --art-ok-bg: rgba(76, 175, 125, 0.1);
    --art-ok-dot: #4caf7d;
    --art-info-dot: #5aa9e6;

    /* --- 红 danger / 对比卡 con / 数据卡下降 --- */
    --art-danger-ink: #ff8a8a;
    --art-danger-line: rgba(255, 107, 107, 0.3);
    --art-danger-bg: rgba(255, 107, 107, 0.05);
    --art-callout-danger-line: rgba(248, 113, 113, 0.24);
    --art-callout-danger-edge: rgba(248, 113, 113, 0.75);
    --art-callout-danger-bg: rgba(248, 113, 113, 0.07);
    --art-callout-danger-text: rgba(255, 168, 168, 0.86);
    --art-bad-ink: #ef9a9a;
    --art-bad-line: rgba(224, 110, 110, 0.45);
    --art-bad-bg: rgba(224, 110, 110, 0.1);
    --art-dot-ring: rgba(0, 0, 0, 0.45);                 /* 时间线圆点外的那圈「挖空」环 */

    /* --- 浮动目录开关 + 抽屉（翻主题；暗色值 = 替换前原字面量）--- */
    --art-float-bg: rgba(24, 24, 24, 0.96);
    --art-float-bg-hover: rgba(38, 38, 38, 1);
    --art-float-fg: #ffffff;
    --art-float-accent: #ddb7ff;                         /* = 暗色 --primary；该元素读不到 --art-accent */
    --art-float-shadow: rgba(0, 0, 0, 0.45);
    --art-drawer-bg: rgba(18, 18, 18, 0.97);
    --art-drawer-shadow: rgba(0, 0, 0, 0.5);

    /* --- 跨主题恒定（压封面照片 / 视频黑底 / 灯箱）--- */
    --art-overlay-chip-bg: rgba(0, 0, 0, 0.6);
    --art-overlay-chip-line: rgba(255, 255, 255, 0.10);
    --art-overlay-chip-line-strong: rgba(255, 255, 255, 0.14);
    --art-chip-fg-muted: #a1a1aa;
    --art-chip-fg-faint: rgba(255, 255, 255, 0.5);
    --art-chip-fg-accent: #ddb7ff;
    --art-chip-line-accent: rgba(221, 183, 255, 0.4);
    --art-chip-line-accent-soft: rgba(221, 183, 255, 0.3);
    --art-hero-veil: linear-gradient(to top,
        rgba(0, 0, 0, 0.9) 0%,
        rgba(0, 0, 0, 0.66) 42%,
        rgba(0, 0, 0, 0.28) 72%,
        rgba(0, 0, 0, 0.34) 100%);
    --art-hero-veil-blur: radial-gradient(120% 130% at 50% 45%, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.72) 78%);
    --art-hero-shadow: rgba(0, 0, 0, 0.55);
    --art-hero-shadow-blur: rgba(0, 0, 0, 0.7);
    --art-hero-meta: rgba(255, 255, 255, 0.82);
    --art-media-bg: #000000;
    --art-lb-scrim: rgba(0, 0, 0, 0.88);
    --art-lb-caption: #d8d8d8;
    --art-lb-btn-bg: rgba(20, 20, 20, 0.72);
    --art-lb-btn-bg-hover: rgba(45, 45, 45, 0.9);
    --art-lb-btn-fg: #fff;
    --art-lb-btn-line: rgba(255, 255, 255, 0.22);
    --art-lb-btn-line-hover: rgba(255, 255, 255, 0.45);
    --art-lb-thumb-bg: rgba(255, 255, 255, 0.06);
    --art-lb-thumb-line: rgba(255, 255, 255, 0.28);
    --art-lb-thumb-line-hover: rgba(255, 255, 255, 0.6);
    --art-lb-thumb-on: #8a5cff;
    --art-lb-thumb-on-ring: rgba(138, 92, 255, 0.35);
}

/* --- Phase 2h 亮色值（排在本文件所有裸 :root 之后；正文级按白底叠加合成挑 ≥4.5:1）--- */
:root[data-theme="light"] {
    --art-surface-hover: rgba(20, 20, 26, 0.08);
    --art-card-bg: rgba(20, 20, 26, 0.035);
    --art-card-bg-hover: rgba(20, 20, 26, 0.075);
    --art-card-line-hover: rgba(124, 58, 237, 0.38);
    --art-block-bg: rgba(20, 20, 26, 0.035);
    --art-primary-bg: rgba(124, 58, 237, 0.10);
    --art-primary-chip-bg: rgba(124, 58, 237, 0.14);
    --art-primary-line: rgba(124, 58, 237, 0.34);
    --art-cover-glow: rgba(124, 58, 237, 0.14);
    --art-hero-glow: rgba(124, 58, 237, 0.16);
    --art-code-bg: rgba(20, 20, 26, 0.05);
    --art-cover-shadow: rgba(20, 20, 26, 0.16);

    --art-ghost-hover-line: rgba(124, 58, 237, 0.6);
    --art-ghost-hover-bg: rgba(124, 58, 237, 0.16);
    --art-callout-line: rgba(124, 58, 237, 0.22);
    --art-callout-info-line: rgba(124, 58, 237, 0.28);
    --art-callout-bg: rgba(124, 58, 237, 0.06);

    --art-warn-ink: #7c2d12;
    --art-warn-line: rgba(146, 64, 14, 0.45);
    --art-warn-bg: rgba(180, 83, 9, 0.10);
    --art-warn-dot: #92400e;
    --art-callout-warn-line: rgba(146, 64, 14, 0.40);
    --art-callout-warn-edge: rgba(146, 64, 14, 0.75);
    --art-callout-warn-bg: rgba(180, 83, 9, 0.08);
    --art-callout-warn-text: #7c2d12;

    --art-copy-ok-line: rgba(21, 128, 61, 0.45);
    --art-copy-ok-bg: rgba(21, 128, 61, 0.10);
    --art-callout-ok-line: rgba(21, 128, 61, 0.40);
    --art-callout-ok-edge: rgba(21, 128, 61, 0.75);
    --art-callout-ok-bg: rgba(21, 128, 61, 0.08);
    --art-callout-ok-text: #14532d;
    --art-ok-ink: #14532d;
    --art-ok-line: rgba(21, 128, 61, 0.45);
    --art-ok-bg: rgba(21, 128, 61, 0.10);
    --art-ok-dot: #15803d;
    --art-info-dot: #1d4ed8;

    --art-danger-ink: #991b1b;
    --art-danger-line: rgba(220, 38, 38, 0.40);
    --art-danger-bg: rgba(220, 38, 38, 0.07);
    --art-callout-danger-line: rgba(220, 38, 38, 0.40);
    --art-callout-danger-edge: rgba(220, 38, 38, 0.75);
    --art-callout-danger-bg: rgba(220, 38, 38, 0.08);
    --art-callout-danger-text: #991b1b;
    --art-bad-ink: #991b1b;
    --art-bad-line: rgba(220, 38, 38, 0.45);
    --art-bad-bg: rgba(220, 38, 38, 0.10);
    --art-dot-ring: rgba(255, 255, 255, 0.90);

    --art-float-bg: rgba(255, 255, 255, 0.96);
    --art-float-bg-hover: #f2f2f4;
    --art-float-fg: #14141a;
    --art-float-accent: #6d28d9;
    --art-float-shadow: rgba(20, 20, 26, 0.16);
    --art-drawer-bg: rgba(255, 255, 255, 0.97);
    --art-drawer-shadow: rgba(20, 20, 26, 0.18);
}

/* 跨主题恒定那批：亮色块里显式再写一遍（防误改，读起来也清楚） */
:root[data-theme="light"] {
    --art-overlay-chip-bg: rgba(0, 0, 0, 0.6);
    --art-overlay-chip-line: rgba(255, 255, 255, 0.10);
    --art-overlay-chip-line-strong: rgba(255, 255, 255, 0.14);
    --art-chip-fg-muted: #a1a1aa;
    --art-chip-fg-faint: rgba(255, 255, 255, 0.5);
    --art-chip-fg-accent: #ddb7ff;
    --art-chip-line-accent: rgba(221, 183, 255, 0.4);
    --art-chip-line-accent-soft: rgba(221, 183, 255, 0.3);
    --art-hero-veil: linear-gradient(to top,
        rgba(0, 0, 0, 0.9) 0%,
        rgba(0, 0, 0, 0.66) 42%,
        rgba(0, 0, 0, 0.28) 72%,
        rgba(0, 0, 0, 0.34) 100%);
    --art-hero-veil-blur: radial-gradient(120% 130% at 50% 45%, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.72) 78%);
    --art-hero-shadow: rgba(0, 0, 0, 0.55);
    --art-hero-shadow-blur: rgba(0, 0, 0, 0.7);
    --art-hero-meta: rgba(255, 255, 255, 0.82);
    --art-media-bg: #000000;
    --art-lb-scrim: rgba(0, 0, 0, 0.88);
    --art-lb-caption: #d8d8d8;
    --art-lb-btn-bg: rgba(20, 20, 20, 0.72);
    --art-lb-btn-bg-hover: rgba(45, 45, 45, 0.9);
    --art-lb-btn-fg: #fff;
    --art-lb-btn-line: rgba(255, 255, 255, 0.22);
    --art-lb-btn-line-hover: rgba(255, 255, 255, 0.45);
    --art-lb-thumb-bg: rgba(255, 255, 255, 0.06);
    --art-lb-thumb-line: rgba(255, 255, 255, 0.28);
    --art-lb-thumb-line-hover: rgba(255, 255, 255, 0.6);
    --art-lb-thumb-on: #8a5cff;
    --art-lb-thumb-on-ring: rgba(138, 92, 255, 0.35);
}

/* --- Phase 2h 补：门 2 实测暴露的亮色可读性缺口（暗色值 = 亮色替换前的原 token，逐字节不变）---
   --art-hero-fg    .artd-hero-title 的前景：它只在 banner/blur 封面模式出现，身下永远是
                    固定的 --art-hero-veil + 任意封面照片 ⇒ 两个主题都必须用亮字。
                    暗色值 = --text 的暗色值（#ffffff），逐字节不变。
   ★ 清理记录：原来的 --art-faint（亮 0.62 / 暗 rgba(255,255,255,.5)）与 --text-faint
     在两主题下**逐字节相同**，已按死 token 清理删除定义；原先用它的 10 处（下图注 /
     代码语言 / 上下篇标签 / 相关时间…）全部改回 var(--text-faint)，可读性不变
     （--text-faint 的亮色值本身就是 rgba(20,20,26,.62)，≈5.0:1 ✔）。
   --art-primary-ink 站点主色当**文字**：亮色 --primary #7c3aed 落在淡紫胶囊/淡色卡底上
                    只有 4.36~4.94:1，改用更深的 #5b21b6（≈6.9:1 ✔）；
                    暗色值 = #ddb7ff（= --primary 的暗色值，逐字节不变）。 */
:root {
    --art-hero-fg: #ffffff;
    --art-primary-ink: #ddb7ff;
}

:root[data-theme="light"] {
    --art-hero-fg: #ffffff;
    --art-primary-ink: #5b21b6;
}
/* ============================================================================
   Phase 6：打印（@media print）与 Windows 高对比度（@media (forced-colors: active)）
   —— 本段是**纯追加**：全部规则都装在两个 at-rule 里，屏幕媒体下一个字节都不生效，
      因此屏幕渲染逐像素不变（由 headless Chrome 双端口快照对比实测验证）。

   为什么追加在 css/base.css（而不是新建 css/print.css）：base.css 已被全部 10 个页面加载，
   新建文件就得给 10 个页面补 <link> —— 漏一个页面就漏一套打印样式，且多出 10 个 ?v= 噪声。

   ① @media print —— 打印结果干净可读
      · 强制白底黑字：打印**不跟随** <html data-theme="dark">。做法不是逐个组件覆盖，
        而是用四条 `*`（含 ::before/::after）规则按固定顺序重排「底色 / 文字色 / 渐变形填充色 /
        边框色」，四条都带 !important（权重必须能压过站内的 id/多类选择器，否则暗色底清不掉）：
          1) * { background: transparent !important }  —— 清掉一切底色与渐变
          2) * { color: #000 !important }              —— 把继承来的文字色与 var(--text) 一起压成黑
          3) * { -webkit-text-fill-color: #000 !important } —— 标题的 background-clip:text 渐变字
                                                          （color 是 transparent）打印时还原成实心黑字
          4) * { border-color: #000 !important }       —— 再把可见边框统一成黑
        第 5 条 * { box-shadow/text-shadow: none } 同理（阴影发光在纸上只会糊成灰块）。
        顺序敏感：先清底、再定字、最后定边框；之后才允许具体结构覆盖（同为 !important → 后出现者胜）。
        安全性：这五条只写在 @media print 内，屏幕渲染完全不受影响（实测见交付说明）。
      · 隐藏页面外壳：导航栏 / 移动菜单 / 站点横幅 / 站内切换条 / 返回顶部 / 预览角标 /
        灯箱与浮层 / 视频控件 / 骨架屏与加载层 / 页脚订阅表单 / 后台顶栏与侧栏与操作按钮。
      · 保留正文语义：标题、段落、列表、表格、代码块、引用、图片（.art-figure img 强制不裁切、
        不缩放）与文章正文里的链接文字。
      · 打印友好：卡片/表格行/代码块/引用不跨页断开；标题不孤行；正文链接在文字后补出
        href（**只对文章正文 .artd-body 生效**，导航/按钮/图标链接不加，避免噪声）。
      ⚠ color-scheme: light 同时给出：让 UA 按浅色画原生控件与页面画布。

   ② @media (forced-colors: active) —— Windows 高对比度下不丢边界与焦点
      系统会强制替换作者颜色，所以关键是「不能只靠颜色传达信息」：给原本靠**半透明底色**区分
      （暗色下 border 合成后对比度只有约 1.1:1）的卡片/输入框/按钮/徽标/分区补 1px 系统色边框，
      并保证焦点可见。下面用的 ButtonBorder / CanvasText / Highlight / ButtonFace / LinkText
      在 forced-colors 下是**正确用法**（会被系统替换成用户实际选的系统色）。
      覆盖清单见段内注释；**没有**做全站适配（只覆盖关键件，见交付说明）。
   ============================================================================ */

@media print {
    /* --- 打印专用色：color-scheme: light 让 UA 用浅色画布/原生控件 --- */
    html {
        color-scheme: light;
    }

    /* --- 底色/背景图/阴影全部归零（顺序敏感：先清底，再定字，最后定边框） ---
       ⚠ 这四条**必须带 !important**：通配符选择器权重是 0，而站内大量规则用 id/多类选择器
          （如 #pg-preview-badge 的内联样式、.admin-card 的双类组合）声明底色 ——
          实测：不带 !important 时 `* { background: transparent }` 会被这些规则盖掉，
          暗色主题打印出来仍是一张黑页（这正是本段要修的问题本身）。
       ⚠ 通配符 !important 只写在 @media print 内，屏幕渲染完全不受影响。 */
    *,
    *::before,
    *::after {
        background: transparent !important;
        box-shadow: none !important;
        text-shadow: none !important;
        -webkit-print-color-adjust: economy;
        print-color-adjust: economy;
    }

    *,
    *::before,
    *::after {
        color: #000 !important;
    }

    /* 标题渐变字（components.css 的 .wonder-gradient-text 用 background-clip:text）：
       底色被清掉后 color 是 transparent，必须用 -webkit-text-fill-color 还原成实心黑字，
       否则打印出来是一行空白。 */
    *,
    *::before,
    *::after {
        -webkit-text-fill-color: #000 !important;
    }

    *,
    *::before,
    *::after {
        border-color: #000 !important;
    }

    /* --- 说明：上面 4 组通配符之后，才允许具体的结构覆盖（同为 !important 时后出现者胜） --- */

    /* --- 页面外壳：一律不打印 --- */
    :where(.navbar),
    :where(.navbar-inner),
    :where(.mobile-menu),
    :where(.bt-banners),
    :where(.bt-banner),
    :where(#site-nav),
    :where(#site-chrome),
    :where(.site-switch-bar),
    :where(.lang-toggle),
    :where(.nav-menu-btn),
    :where(.scroll-progress),
    :where(.to-top),
    :where(.toast),
    :where(#toast),
    /* 文档站（docs/index.html，共享本文件）的左侧目录栏：打印时它是残留的一列 */
    :where(.docs-sidebar),
    /* 页面切换预览角标（js/page-guard.js 注入，内联样式，只能按 id 关） */
    :where(#pg-preview-badge),
    /* 浮层 / 弹窗 / 灯箱 / 视频控件 */
    :where(.dl-overlay),
    :where(.dl-dialog),
    :where(.art-lightbox),
    :where(.docs-lightbox),
    :where(.aa-overlay),
    :where(.sp-overlay),
    :where(.share-overlay),
    :where(.ad-container),
    /* 骨架屏与加载层 */
    :where(.skeleton),
    :where(.notice-skeleton),
    :where(.artd-loading),
    /* 交互式目录浮标（正文里的静态目录 .artd-toc 保留） */
    :where(.artd-toc-toggle),
    /* 页脚订阅表单（打印出来没有意义，只留文案与链接） */
    :where(.newsletter-form),
    :where(.newsletter-msg),
    /* 后台：顶栏 / 侧栏 / 导航菜单 / 操作按钮与横幅 */
    :where(.admin-topbar),
    :where(.admin-sidebar),
    :where(.admin-menu),
    :where(.admin-bar-actions),
    :where(.admin-ops),
    :where(.admin-actions),
    :where(.admin-alert),
    :where(.admin-logout),
    :where(.admin-session),
    :where(.admin-image-actions),
    :where(.bulk-bar),
    :where(.select-cell),
    :where(.row-check),
    :where(input),
    :where(select),
    :where(textarea),
    :where(input[type="checkbox"]),
    :where(input[type="radio"]),
    /* 纯装饰件 */
    :where(.fluid-glow),
    :where(.showcase-glow),
    :where(.showcase-handle),
    :where(.showcase-divider),
    :where(.dl-card-watermark),
    :where(.badge-dot),
    :where(.cta-overlay) {
        display: none !important;
    }

    /* --- 打印布局：去掉为「固定外壳」预留的让位高度，正文从纸张顶部开始 --- */
    html {
        background: #fff !important;
    }

    body {
        background: #fff !important;
        color: #000 !important;
        min-height: 0 !important;
    }

    :where(.main) {
        padding-top: 0 !important;
    }

    /* 后台：侧栏被隐藏后主内容必须回到满宽（.admin-shell 是两栏栅格） */
    :where(.admin-shell) {
        display: block !important;
        padding: 0 !important;
        margin: 0 !important;
    }

    :where(.admin-content) {
        width: auto !important;
        max-width: none !important;
        margin: 0 !important;
        padding: 0 !important;
    }

    :where(.admin-app) {
        padding: 0 !important;
        margin: 0 !important;
    }

    /* --- 保留正文语义：图片别裁切、别缩放；表格与代码块给可见边界（原来靠底色区分，
           底色被清掉后必须有边框，否则表格会连成一片） --- */
    img {
        max-width: 100% !important;
        height: auto !important;
        object-fit: contain !important;
        page-break-inside: avoid;
        break-inside: avoid;
    }

    :where(.art-figure) img,
    :where(.artd-body) img,
    :where(.showcase-img) {
        object-fit: contain !important;
        max-height: none !important;
    }

    table {
        border-collapse: collapse !important;
        width: 100% !important;
    }

    :where(th),
    :where(td) {
        border: 1px solid #000 !important;
        padding: 4px 8px !important;
    }

    :where(pre),
    :where(code),
    :where(blockquote),
    :where(.notice-card),
    :where(.archived-note) {
        border: 1px solid #000 !important;
        background: #fff !important;
    }

    :where(pre) {
        padding: 8px 10px !important;
    }

    :where(blockquote) {
        padding: 6px 12px !important;
    }

    /* --- 断页规则 --- */
    :where(h1),
    :where(h2),
    :where(h3),
    :where(h4),
    :where(h5),
    :where(h6) {
        break-after: avoid;
        page-break-after: avoid;
        break-inside: avoid;
    }

    :where(p),
    :where(li),
    :where(blockquote),
    :where(pre),
    :where(figure),
    :where(.art-figure),
    :where(.dl-card),
    :where(.wonder-card),
    :where(.status-card),
    :where(.docs-card),
    :where(.feature-tile),
    :where(.mods-card),
    :where(.faq-item),
    :where(.notice-card),
    :where(.admin-card),
    :where(.admin-table tr),
    :where(.artd-related-card),
    :where(.player-slot),
    :where(table),
    :where(tr) {
        break-inside: avoid;
        page-break-inside: avoid;
    }

    :where(a) {
        text-decoration: underline;
    }

    /* --- 打印时把正文链接的 URL 补在文字后（**只对文章正文**；导航/按钮/图标链接不加，
           否则整页都是地址噪声）。站外链接标注完整地址，站内链接标注路径。 --- */
    :where(.artd-body) a[href^="/"]::after {
        content: " (" attr(href) ")";
        font-size: 0.85em;
        word-break: break-all;
    }

    :where(.artd-body) a[href^="http"]::after {
        content: " (" attr(href) ")";
        font-size: 0.85em;
        word-break: break-all;
    }

    /* --- 后台表格：冻结列/表头底色在纸上无意义，去掉粘性定位（避免只打出一行表头） --- */
    :where(.admin-table th) {
        position: static !important;
    }
}

/* ============================================================================
   forced-colors：Windows 高对比度
   覆盖（有系统色边框 + 焦点可见）：
     · 卡片/容器：.dl-card .wonder-card .status-card .docs-card .feature-tile .mods-card
       .notice-card .player-slot .archived-note .cta-card .artd-related-card
       .admin-card .admin-display-box .admin-table th/td .aa-preview-box
     · 输入控件：.admin-input .admin-textarea .admin-select .newsletter-input
     · 按钮：[type=button|submit|reset] .wonder-button .wonder-button-secondary .btn-solid
       .btn-ghost .nav-icon .nav-menu-btn .theme-toggle .to-top .bt-banner-close
     · 徽标/胶囊：.badge .chip .hero-badge .status-badge .qr-badge .ac-badge .activity-badge
       .brand-version .admin-badge
     · 分区/顶栏/页脚/浮层：.admin-topbar .admin-sidebar .footer .navbar .dl-dialog .aa-dialog
     · 焦点：a/button/input/select/textarea/summary/[tabindex] 的 :focus-visible 用 Highlight 描边
   未覆盖（诚实说明）：docs 子站（docs/css/style.css 与 css/base.css 不共享，本次不动）、
     页面上没有列到的少数装饰性小图标按钮、canvas/内联 SVG 内部的绘制内容（系统替换不了
     绘制内容，只能靠作者自己加描边，本次不做）。
   forced-color-adjust: none 只在下面**三处**使用，且都写了理由；其余一律交给系统替换。
   ⚠ 本段全部规则只存在于 @media (forced-colors: active) 内，普通渲染一个字节都不生效。 */

@media (forced-colors: active) {
    /* ① 原本「无边框、靠半透明底色区分」的卡片/容器：补 1px 系统边框。
          不写 !important —— 本段在 base.css 末尾，同特异性下后出现者胜即可；
          刻意避开 :where()，是为了让权重与组件自身的单类选择器**相同**（0,1,0），
          纯粹靠「后出现」取胜，语义清楚且不越权。 */
    .dl-card,
    .wonder-card,
    .status-card,
    .docs-card,
    .feature-tile,
    .mods-card,
    .notice-card,
    .player-slot,
    .archived-note,
    .cta-card,
    .artd-related-card,
    .admin-card,
    .admin-display-box,
    .aa-preview-box,
    .art-figure {
        border: 1px solid ButtonBorder;
    }

    /* 表格：单元格分隔线在系统配色下必须显形（原来靠 rgba 白/黑半透明底） */
    .admin-table th,
    .admin-table td,
    .artd-body table th,
    .artd-body table td {
        border: 1px solid ButtonBorder;
    }

    /* ② 输入控件：高对比度下输入框必须看得出边界（原本靠极淡底色） */
    .admin-input,
    .admin-textarea,
    .admin-select,
    .newsletter-input,
    input[type="text"],
    input[type="password"],
    input[type="email"],
    input[type="number"],
    input[type="search"],
    input[type="url"],
    select,
    textarea {
        border: 1px solid ButtonBorder;
    }

    /* ③ 按钮：实心按钮（.btn-solid / .wonder-button）原本只有底色、没有边框，
          系统把底色替掉后按钮与背景会连成一片 —— 补系统边框。
          ⚠ forced-color-adjust: none 用在这里：.btn-solid / .wonder-button 的文字色是
          **作者定义的「反相色」**（--admin-inverse-fg / --on-accent），在系统强制替换下会与
          被替换后的底色撞色（实测同色），导致按钮文字消失。这里只对这两个实心按钮
          保留作者的文字/底色，并显式给出系统边框与文字色，保证「按钮可见 + 文字可读」。 */
    .btn-solid,
    .wonder-button,
    .wonder-button-secondary,
    .btn-ghost,
    .btn,
    .btn-primary,
    .btn-secondary,
    .nav-icon,
    .nav-menu-btn,
    .theme-toggle,
    .to-top,
    .bt-banner-close,
    button[type="submit"],
    button[type="button"] {
        border: 1px solid ButtonBorder;
    }

    .btn-solid,
    .wonder-button {
        forced-color-adjust: none;
        border: 1px solid ButtonBorder;
        background: ButtonFace;
        color: ButtonText;
    }

    /* ④ 徽标 / 胶囊：只用底色区分的小标签，补边框才看得出是「一个块」 */
    .badge,
    .chip,
    .hero-badge,
    .status-badge,
    .qr-badge,
    .ac-badge,
    .activity-badge,
    .brand-version,
    .admin-badge,
    .act-badge {
        border: 1px solid ButtonBorder;
    }

    /* ⑤ 分区骨架：顶栏/侧栏/页脚/导航/对话框 —— 靠底色分层的部分补系统边框 */
    .admin-topbar,
    .admin-sidebar,
    .navbar,
    .footer,
    .dl-dialog,
    .aa-dialog,
    .mobile-menu {
        border: 1px solid ButtonBorder;
    }

    /* ⑥ 焦点可见：forced-colors 下 outline 用 Highlight 才不会被吃掉。
          ⚠ 只写 :focus-visible（键盘/程序聚焦），鼠标点击不触发 —— 屏幕渲染不受影响。
          ⚠ forced-color-adjust: none 用在这里：outline-color 在强制替换下会被系统改写，
          导致原本「靠颜色区分的焦点环」与周围同色；显式声明后焦点环一定是 Highlight。 */
    a:focus-visible,
    button:focus-visible,
    input:focus-visible,
    select:focus-visible,
    textarea:focus-visible,
    summary:focus-visible,
    [tabindex]:focus-visible,
    .faq-question:focus-visible {
        forced-color-adjust: none;
        outline: 2px solid Highlight;
        outline-offset: 2px;
    }

    /* ⑦ 装饰性水印/发光在强制配色下没有意义，直接不画（避免在纯色底上糊一块灰） */
    .dl-card-watermark,
    .fluid-glow,
    .showcase-glow,
    .showcase-pattern {
        display: none;
    }
}
