/* ══════════════════════════════════════════════════════════════════════════
   Yarrow 改版 · 色彩令牌
   定稿 2026-07-27

   ══════════════════════════════════════════════════════════════════════════
   2026-07-29 方向确定：**老式单色液晶读数**（LCD readout）。
   这不是一层皮，是整套系统的组织隐喻，下面每条决定都从它推出来。
   它也顺带给「等宽字做展示字」这个早先的赌注补上了真正的理由 ——
   液晶读数天生是等宽的。
   ══════════════════════════════════════════════════════════════════════════

   系统原则（不要在实现时偷偷破坏这四条）：

   1. **只有四级明度。** 灭（玻璃）/ 淡（栅格）/ 中（填充）/ 全（文字）。
      真实 STN 液晶是 1 bit，Game Boy 是 4 级。**级数本身就是气质** ——
      十级读起来是印刷品，四级才读起来是液晶。
      下面的 --g0..--g9 是**量化别名层**，十个名字映射到四个真实颜色，
      这样组件侧一行都不用改，而「只有四级」这件事在一处就能验证。

   2. **最深的一档不是墨。** 全 = L18（#2B2D31），对玻璃 10.43。
      真实液晶段码压在玻璃上只有 6–8:1，连全亮都还是深灰 ——
      「不用纯黑白」这条因此不是妥协，是液晶的性格。

   3. **点阵栅格是显示基底，不是背景纹理。**
      ⚠️ 这一条**推翻了本文件原来的纸纹注释**（原文写「这是纹理不是网格，
      尺度必须小到读起来是纸的材质，而不是一套承诺内容会对齐它的结构」）。
      液晶恰恰相反：最识别性的特征是**你能看见没被点亮的格子**，
      而内容必须落在格子上。所以间距与行高取 6px 的倍数。

   4. **液晶上没有「灰字」。** 段码只有亮和灭，所以所有文字原则上都是「全」，
      次要信息靠**字号更小、位置更靠边、大写等宽**区分，不靠减淡。
      「中」是填充档，本不写字、不画容器边框（3.57 过不了小字 AA）。

      ── 例外台账（截至 2026-07-30，共 2 处）─────────────────────────

      【1】`.mast-tag`（导航条右下的小标语，12px）走「中」档：
           对玻璃 3.57，比 AA 差 0.93。
           **四级的结构性代价在这里现形：3.57 与 10.43 之间是空的。**
           十级时还有 5.82 / 9.71 可用。再要「淡一点的字」只有三条路 ——
           字号提到 24px 以上、加第五档（破坏本原则 1）、或记一笔欠账。
           这里选的是记欠账。

      【2】`.product-label span`（产品分类小标签，9.5px）用 `opacity:.6`：
           声明色是「全」#DEE0E3，叠 0.6 后实际呈现 #96989C，对深色带底 4.77。
           **这是一个真正的第五色**，落在「中 2.92」和「全 10.43」之间的空档里。
           AA 门槛 4.5，4.77 通过，但余量只有 0.27 —— 再降就掉下去。

      ⚠️ 两处的性质不同，别混为一谈：
         【1】是**对比度欠账**（低于 AA），【2】是**色数超编**（没超 AA）。
         但两处都指向同一个结构性缺陷：**四级之间没有中间地带**，
         而「让某个东西淡一点」是设计里最常见的需求。
         现在的应对是靠 opacity 临时兑出中间值 —— 这不可持续。
         **再出现第三处，就该正式讨论加第五档，而不是继续记账。**

      ⚠️ 以下**不算**本原则的例外，别误记进台账：
         · hero 背景视频（`.hero-video`）—— 视频是**素材层**不是界面层。
           四级管界面元素（字、线、填充块），连续调素材从窗口里透过来，
           本来就不在辖区内。这是**划边界**，不是破例：界面四级，素材不限。
           实测结论见 landing.css 的 HERO 背景视频 一节。
         · hero 雾化换条的 blur / opacity、步进器的擦除 —— 全是过渡态，见原则 5。
         · `.mast-copy h1`（导航栏那句，30px）走「中」档 ——
           30px 属于 AA 的「大字」，门槛 3.0，3.57 **通过**，不欠账。
           它和【1】用同一个颜色但判定不同，差别只在字号跨过了 24px 那条线。

   5. **四级管静止态，不管过渡态。**（2026-07-30 定，起因是 hero 的雾化换条）
      设计侧选了模糊淡出做大字切换。模糊天生产生上百级中间灰 ——
      实测那个效果全程用到 261 种颜色，和「只有四级」正面冲突。

      解决办法不是破例，是**划清这条规矩的辖区**：

        静止态（可读、可点、可截图的那一刻）── 严格四级，一色不多
        过渡态（正在动的那几百毫秒）      ── 不限，模糊 / alpha / 插值都行

      理由：量化约束的是**可读性的构造**，而过渡态没有人在读它。
      一个人不会盯着 0.6 秒的中间帧判断字色，他判断的是停下来之后的样子。
      同一条逻辑之前已经用过一次 —— 视频是素材层不是界面层（见上一条）。

      ⚠️ 这条**不是**「动效里可以随便来」的通行证。两条硬边界：
         · 过渡必须收敛到一个合法的静止态（模糊必须归零，alpha 必须归 1 或 0）
         · 不允许「停在中间态」—— 半糊的字、半透明的块，都算静止态违规
         凡是能被截图截到的稳定画面，一律按四级判。

   彩色：目前**缺席**，`--ac-*` 由灰阶占位。方向已定 ——
   单色液晶上的颜色不来自显示本身，来自**另一个光源**（指示灯 / 背光 / 滤色片）。
   玻璃是冷的，所以指示灯必须是暖的（琥珀 / 红 / 信号绿）。
   这与「灰阶色相取自主题色补色」独立推出的结论一致，两条路撞在了一起。

   浅色为主，**不做暗色模式** —— 但有「深色带」：部分区块整幅反色
   （见文件末尾 `.sec-dark`）。物理上对应**负显液晶**（亮段压在暗玻璃上），
   不是主题切换，是版面节奏，用户切不了。
   ══════════════════════════════════════════════════════════════════════════ */

:root {

  /* ── 四级 · H215° S7% ───────────────────────────────────────────────
     色相 H215（钢蓝）—— 钢、石墨、阴天的色相。
     真实正显液晶的玻璃偏绿（偏振片 + 液晶层），这里选中性冷灰是刻意的：
     偏绿更「复古电子」，冷灰更「仪器 / 咨询」。渲染对比过，见
     曾用一份亮度对比页选定（候选 C = 现在这套）。

     ⚠️ 色相仍是临时的。真主题色定下来后要按它的补色重算
        —— 灰阶的色相是从主题色推出来的，不是各自挑的。
        已推出的约束：**要玻璃落在冷区，指示灯就必须是暖色** ——
        冷灰（H190–270）的补色在暖区（H10–90）。            */

  --off:  #DEE0E3;   /* L88  灭 · 玻璃 / 页面底                    1.00  */
  --dim:  #B3B7BD;   /* L72  淡 · 点阵栅格 · 发丝线 · 容器边框      1.52  */
  --fill: #6D747E;   /* L46  中 · 填充块 · 图表柱 · disabled        3.57  */
  --on:   #2B2D31;   /* L18  全 · 所有文字 · 强分隔               10.43  */

  /* ── 量化别名层 ──────────────────────────────────────────────────────
     十个旧名字映射到上面四个真实颜色。这样 landing.css（64 处语义别名 +
     9 处裸 --gN）一行都不用改，而「整站只有四个颜色」在这一处就能验证。

     ⚠️ --g5 / --g6 / --g7 全部并入「全」—— 这是四级最大的可见后果：
        **文字失去了按明度分层的能力。** 原来的「最弱文字 / 正文辅助 /
        强调文字」三档现在同色。这不是漏改，是第 4 条原则的直接结果：
        液晶上没有灰字，层级改由字号、位置、大小写承担。
        所以调层级请动 font-size / letter-spacing / 大写，不要回头加明度档。 */

  --g0: var(--off);    /* 纸 · 页面底                                     */
  --g1: var(--off);    /* 原「区块交替」→ 并入玻璃；交替改由深色带承担      */
  --g2: var(--off);    /* 原「淡填充」→ 并入玻璃                          */
  --g3: var(--dim);    /* 容器边框                                        */
  --g4: var(--dim);    /* 图表网格 · 次要线 · 链接下划线                   */
  --g5: var(--on);     /* ⚠ 原「最弱文字」→ 与正文同色                     */
  --g6: var(--on);     /* ⚠ 原「正文辅助」→ 与正文同色                     */
  --g7: var(--on);     /* ⚠ 原「强调文字」→ 与正文同色                     */
  --g8: var(--on);     /* 近墨                                            */
  --g9: var(--on);     /* 主文字 · 标题                                    */

  /* ── 主题色 · 目前由灰阶占位 ─────────────────────────────────────────
     ⚠️ 这四档全部写成 `var(--gN)` 而不是字面色值，这是**刻意的**：
        深色带（`.sec-dark`）里 --g0..--g9 会整条反向重映，
        写成别名的话主题色档位会跟着自动反转，不用为深色带单独配一套。
        真主题色进来时把右边换成实际色值，并给 .sec-dark 补一套反色档位。

     出现清单（超出这个清单请先讨论）：
       ~~logo 星芒中心点~~ ← 已随更名移除。Yarrow 的标识是单色的。
         **这一格空了** —— 「关键位置一小点彩色点题」少了 logo 这个天然位置。
       导航激活下划线 / 主按钮箭头块 /
       概率标尺高端及其派生的图表高概率区 / 榜单第一名进度条 /
       正文荧光高亮 / focus 环 / 链接 hover
     整屏目标面积 ≈ 1.5%。wordmark 不用彩色，用 --g9。             */

  --ac-wash: var(--g2);   /* 高亮底、::selection、下拉 hover 底             */
  --ac-base: var(--g8);   /* 填充、图表峰值                                 */
  --ac-deep: var(--g9);   /* 描边、focus 环                                 */
  --ac-text: var(--g9);   /* 彩色文字、hover 文字                           */

  /* ⚠️ 彩色缺席带来的两个已知退化，别当成 bug：
     1. hover / active 态与常态**只差下划线和字重**，颜色区分不了。
        原来「黄多了一层『你正在跟它互动』的语义」，现在这层语义没有载体。
     2. 主按钮的箭头块不能再用 --ac-base —— 按钮底是 --text（g9），
        箭头块 g8 压在 g9 上几乎看不见。已改为用 --paper 做反色块
        （见 landing.css `.btn-pri .a`）。真主题色进来后应改回主题色。 */

  /* ── 朱批 · 稀有标记 ─────────────────────────────────────────────────
     不是告警红，是氧化铁 / 朱砂那种批注红。
     出现清单：负 IV / 未命中 / 校准离群点 / 需要人看一眼的东西。
     整屏目标面积 < 0.3%。

     ⚠️ 原注释说「色相 9°，与黄同属暖系不打架」—— 黄没了，这个理由失效。
        现在朱批红是整站唯一有色相的东西，反而变成了事实上的彩色。
        彩色缺席期间它会比预期显眼，真主题色定下来后要重查两者的色相距离。 */

  --rd-wash: #F9DFDB;   /* 底色                          纸上 1.15 · 仅填充 */
  --rd-mid:  #E36853;   /* 图表离群点                     纸上 3.00 · 大字  */
  --rd-text: #CB3A21;   /* 负值文字                       纸上 4.59 · AA    */
  --rd-deep: #A12F1A;   /* 强调                           纸上 6.51 · AA    */

  /* ── 语义别名 · 组件里用这一层，不要直接写 --gN ──────────────────── */

  --paper:      var(--g0);
  --surface:    var(--g1);
  --surface-2:  var(--g2);

  --text:       var(--g9);
  --text-2:     var(--g7);
  --text-mute:  var(--g6);
  --text-faint: var(--g5);
  --text-invert:var(--g0);

  /* 线现在只有两档，不是三档 ——
     ⚠️ --hair 原来是 color-mix(--g9 8%)，那会产生**第五个颜色**。
        四级系统里不存在半透明：液晶单元只有几个状态，没有 8% 这一档。
        所以 hair 与 rule 合并，都用「淡」。真要再分一层，
        应该靠**虚线 / 点线**（栅格能表达的东西），不是靠透明度。 */
  --hair: var(--dim);    /* 表格行分隔、内部网格                            */
  --rule: var(--dim);    /* 容器边框、区块分隔                              */
  --edge: var(--on);     /* 表头下划线、强分隔                              */

  --focus: var(--ac-deep);

  /* ── 字体 ────────────────────────────────────────────────────────────
     两个家族，分工明确：

     Azeret Mono  展示 + 所有小标签。整站的性格全在它身上。
                  选等宽字做展示字是刻意的 —— Yarrow 满屏是概率数字，
                  表格数字对齐本来就是功能刚需；而八个参考站的等宽字
                  都只用在 9–12px 的小标签上，把它提上来是块空地。
     Lexend       只做正文（2026-07-29 由 Inter Tight 换来）。
                  它不是中性字 —— 是按阅读效率研究设计的：字怀开、
                  默认字距松、字形偏宽。所以有两条落地要求：

                  · **不要给它收负字距。** 松的默认字距是它的设计意图，
                    收紧会抵消掉换字体的理由。原来正文有 -.005em，已去掉。
                  · **行宽一律用 ch 而不是 px。** Lexend 比 Inter Tight 宽，
                    同字号下同一个 px 宽度能装的字符更少。ch 随字体缩放，
                    所以「一行 60 个字符」这个意图跨字体成立。
                    但物理宽度会变宽 —— 所有 ch 行宽都套了 min(…, 100%)
                    以防撑出栏位。

     字重轴已收口（2026-07-30 实测后改，不是估的 ——
     剥掉注释遍历所有 font-weight 声明得到）：

       Azeret Mono  轴 200..500   实际用到 200 / 250 / 300 / 350 / 400 / 450 / 500
       Lexend       轴 300..500   实际用到 300 / 400

     ⚠️ 这条替换了原来那句「目前引用全部 100..900，项目收口后再剔」——
        已经剔完了，见 index.html 的字体 <link>。
     ⚠️ 同时纠正原注释里一处错：它写「正文用到 300/400/500」，
        但 500 全都是 `.mono`（Azeret 的小标签），**Lexend 实际只到 400**。
        Lexend 轴仍留到 500 是给以后的正文小标签留一档 ——
        卡死在 400 的话，加一个 500 会悄悄退化成合成字重（浏览器自己拉粗，
        笔画会脏），而合成字重不报错、只是变丑，很难发现。
     ⚠️ 斜体整轴已去掉：全站 font-style 出现 0 次，
        而原来的 `ital,...;1,300..500` 会让 Google 多发一个完整的斜体字体文件。
        这是当时唯一一处「一整个文件的浪费」。                        */

  --font-display: 'Azeret Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-mono:    var(--font-display);      /* 小标签与展示字同源，只有两个家族 */
  --font-body:    'Lexend', ui-sans-serif, system-ui, -apple-system, sans-serif;

  /* 等宽字做展示字必须处理的两件事：
     1) 每个字符等宽 → 大字号下横向铺得很开，字距要收负值
     2) 小字号下笔画容易糊 → 标签的字重要比展示字高一档            */
  --disp-tracking: -.05em;   /* 60px 以上 */
  --disp-tracking-md: -.035em;
  --label-weight: 500;
  /* 小标签的第二档。2026-07-30 加 —— .product-label span（产品分类）要更淡，
     原先硬编码 400，现在有名字了。两档的分工：
       500 用于承担导航/功能的小标签（.mono 默认）
       400 用于纯分类、可扫读不必读的小标签 */
  --label-weight-soft: 400;

  /* ── 圆角 ────────────────────────────────────────────────────────────
     单一尺度。这套系统靠线和留白分层，不靠圆角，所以只留一档且很小。 */
  --radius: 3px;

  /* ── 点阵栅格 · 显示基底 ─────────────────────────────────────────────
     ⚠️ 这里取代了原来的「16px 纸纹」。两者是不同的东西，别混：

       纸纹（已作废）  16px 描边方格，读作纸的材质。原注释明确写着
                      「不是一套承诺内容会对齐它的结构」。
       点阵栅格（现在） 6px 节距的**点**，读作液晶的显示单元。
                      **内容必须落在格子上** —— 间距与行高取 6 的倍数。

     为什么是点不是线：线网会读成图表网格（一套坐标系），
     点阵才读成显示单元。这是液晶最识别性的特征 ——
     **你能看见没被点亮的那些格子。**

     刻意写成字面值：不套 var()、不套 calc()。
     嵌套自定义属性再塞进 gradient，部分内嵌预览 / 老 WebKit 会整条失效，
     表现为「浏览器里有网格、预览面板里没有」。
     调强弱就改点的颜色（现在是「淡」#B3B7BD）；调密度就改 6px。   */
  /* ── 动效 ─────────────────────────────────────────────────────────
     2026-07-30 从 landing.css 移过来。之前放在版面文件里没有道理 ——
     这个文件已经收了 --disp-tracking、--cell 这类度量，动效没理由被排除。
     JS 侧不重复写这两个值，而是从 CSS 量（见 heroRotate 的 fogMs）。 */
  --fog:   12px;    /* hero 雾化换条的模糊半径 */
  --fog-t: .62s;    /* 雾化时长。改它必须回去重算轮播周期 PERIOD */
  /* hero 背景视频换段的交叉淡化时长（2026-08-01）。
     比文字的雾化长一截是刻意的：文字先落定，底再换完，
     读起来是「地面在已经稳住的字下面缓慢换过去」。
     两者同时结束反而会显得整屏一起跳。
     ⚠️ 这个值 JS 侧不写第二份，从 CSS 量（见 heroRotate 的 vidMs）。 */
  --vid-t: 1.1s;

  --cell: 6px;
  /* 压在**连续调素材**（hero 视频）上的点色。原来硬编码在 landing.css 里，
     2026-07-30 提上来 —— 不然从这个文件看会以为全站只有四个颜色，而它是第五个。
     推导：页面基底是「淡」压在「玻璃」上，强度 1.52；视频平坦底色实测约 206，
     要保持同样的 1.52 就得压深两阶 → H215 S7% L66。
     跨底色时对齐的是**对比度**，不是色值 —— 与深色带反色同一个方法。
     ⚠️ 这个可以用 var() 引用（见 landing.css 的 .sec-hero::after），
        因为那是普通属性里的一层 var()，不是「自定义属性里嵌 var() 再塞进 gradient」
        —— 后者才是上面那条警告说的失效场景。 */
  --dot-media: #A2A7AE;
  --grid: radial-gradient(circle at center, #B3B7BD .6px, transparent .7px);
  --grid-size: 6px 6px;
}

/* ══════════════════════════════════════════════════════════════════════
   点阵栅格的落地规则 —— 只有一条，别在别处开例外
   ══════════════════════════════════════════════════════════════════════
   栅格铺在整页上（一整块屏），任何自带边框的容器盖一层不透明玻璃色，
   把栅格挡在外面。所以：
     · 空旷区域（hero、区块标题、叙事段落）→ 看得见显示单元，不空
     · 数据面板（图表、表格、卡片、输入框）→ 面板内平整，不干扰读数
   加新组件时不用单独处理：只要它有边框，给它 background:var(--paper) 即可。

   ⚠️ 与作废的纸纹的区别：栅格是**基底**，内容要落在格子上。
      所以新组件的行高与内外边距请取 var(--cell)（6px）的倍数。
   ══════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════
   概率标尺 —— 浅灰 → 墨（彩色缺席期的临时形态）
   Yarrow 的核心对象是概率，所以色标是一等品牌资产，UI 与图表共用。

   ⚠️ 方向反了，这是彩色缺席的直接后果，不是笔误。
      原来是「0% 深灰 → 55% 浅灰 → 100% 黄」：高概率**亮**且有颜色。
      彩色没了以后，浅底上唯一还能推的方向是**变深**，
      所以现在是「0% 极浅 → 55% 中灰 → 100% 墨」：高概率**深**。
      代价：高概率区和正文墨色同色，「这是数据」和「这是文字」在标尺末端分不开。
      真主题色回来后要把 100% 端换回主题色，方向也跟着掰回来。
   ══════════════════════════════════════════════════════════════════════ */

/* ⚠️ 标尺也要量化 —— 连续渐变会把四级又变回无级，整套液晶感就没了。
   用 hard stop（同色两次）做出三段台阶，不做插值：
     0–33%   灭  低概率 = 没点亮
     33–66%  淡
     66–90%  中
     90–100% 全  高概率 = 全亮
   这不只是视觉选择：概率本来就该读成「档」而不是连续色，
   离散台阶反而比渐变更好读数。 */
:root {
  --scale: linear-gradient(90deg,
    #DEE0E3 0%,   #DEE0E3 33%,
    #B3B7BD 33%,  #B3B7BD 66%,
    #6D747E 66%,  #6D747E 90%,
    #2B2D31 90%,  #2B2D31 100%);
}

/*  参考实现（TS）—— 返回四级中的一档，不插值
    export function probabilityLevel(p: number): string {
      const OFF='#DEE0E3', DIM='#B3B7BD', FILL='#6D747E', ON='#2B2D31';
      if (p < 0.33) return OFF;
      if (p < 0.66) return DIM;
      if (p < 0.90) return FILL;
      return ON;
    }
*/

/* ══════════════════════════════════════════════════════════════════════
   两条落地约定
   ══════════════════════════════════════════════════════════════════════ */

/* 1 · 链接没有彩色。系统里没有蓝，链接靠下划线区分。
       ⚠️ hover 原本转黄，现在主题色缺席 —— hover 只能靠「下划线转墨、字色转墨」
          这点差别撑着，比原来弱得多。这是彩色缺席的退化项之一。 */
a {
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px solid var(--g4);
  padding-bottom: 1px;
}
a:hover {
  color: var(--ac-text);
  border-bottom-color: var(--ac-deep);
}

/* 2 · 选中态。原来是整站黄出现频率最高的地方，现在退成淡灰。 */
::selection { background: var(--ac-wash); }

/* 焦点环不用系统蓝，走 --focus（现指向 --ac-deep = 墨） */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

/* ══════════════════════════════════════════════════════════════════════
   深色带 · .sec-dark
   ══════════════════════════════════════════════════════════════════════
   物理上这是**负显液晶**：亮段压在暗玻璃上。所以它不是「另一套配色」，
   是同一块屏幕的反相 —— 四级两端对调即可，不新增任何颜色。

   Landing 的版面节奏靠「深浅交替」，不是靠满幅色块的浅浅交替 ——
   旧结论「不用色块交替」说的是 g0↔g1 只有 1.08 对比、硬切换看不出来，
   那条仍然成立（而且现在 g0/g1/g2 已经**是同一个颜色**了，
   浅浅交替连做的可能都没有）。深↔浅是另一回事：反差 10.43，一眼分得开。

   **不用纯黑白做强对比**：暗玻璃 L18、字 L88，反差 10.43。
   纯黑白是 21.0，真实 STN 液晶是 6–8 —— 我们落在中间偏液晶那侧。

   实现方式：反向重映 --g0..--g9，**并且把语义别名整层重新声明一遍**。

   ⚠️⚠️ 第二步不是冗余，是必需的。这里踩过一次，别再踩：
   **自定义属性里的嵌套 var() 在声明处就被解析掉了。**
   `--text: var(--g9)` 写在 :root，它的计算值当场变成字面量 #17181A，
   然后以**字面量**往下继承。所以在 .sec-dark 里重映 --g9，
   对已经在 :root 解析完的 --text / --text-mute / --hair … 完全无效。

   症状极具欺骗性：landing.css 里 9 处**裸写** var(--gN) 的地方（边框、线）
   会正确反转，而 64 处走语义别名的**文字**全都还是深色 ——
   看上去像「改了一部分、漏了一部分」，实际是机制本身不成立。

   所以规矩是：**在 .sec-dark 里加了 --gN，就必须把所有引用 --gN 的
   派生令牌一起重新声明。** 下面那一整块别删。
   ══════════════════════════════════════════════════════════════════════ */

.sec-dark {
  /* 负显液晶：**同一套四级倒过来用**，不另配一套。
     灭 = 正显的「全」，全 = 正显的「玻璃」，两端直接对调。

     「淡」不是简单取中间档，是**按「与底色的对比相同」反求**的：
     正显里栅格对玻璃是 1.52，所以负显里也要 1.52 → L29（#45494F）。
     若图省事直接沿用正显的「淡」，在暗底上对比会变成 3.4，栅格会吵得多。
     「中」两带共用 —— 它本来就在中间，对两个底色分别是 3.57 / 2.92。       */
  --off:  #2B2D31;   /* 灭 · 暗玻璃（= 正显的「全」）              1.00  */
  --dim:  #45494F;   /* L29  淡 · 点阵栅格 · 发丝线                1.52  */
  --fill: #6D747E;   /* 中 · 填充块（与正显同一个值）              2.92  */
  --on:   #DEE0E3;   /* 全 · 所有文字（= 正显的「玻璃」）         10.43  */

  /* ── 量化别名层也要整层重声明 ──────────────────────────────────────
     ⚠️⚠️⚠️ 这个坑在本项目里犯到第三次了，`checkBands()` 每次都是靠它抓出来的：
     第一次漏了派生令牌、第二次漏了 .sec-dark 的 --hair、
     第三次（就是这里）只声明了四级、漏了 --g0..--g9 这一层 ——
     结果 34 处文字与底色**完全同色**（对比 1.00）。

     原因永远是同一条：**嵌套 var() 在声明处就被解析成字面量。**
     `--g9: var(--on)` 写在 :root，计算值当场固化成浅色带的 #2B2D31，
     往下继承的是那个字面量。所以在 .sec-dark 里改 --on 对它无效，
     而 #2B2D31 恰好又是深色带的底色 —— 字直接消失在背景里。

     规矩（贴在这里，别再自己推一遍）：
     **在 .sec-dark 里改了任何一层，它下游的每一层都要重声明。**
     现在是三层：四级 → --gN 别名 → 语义/主题色派生。三层都在下面。 */

  --g0: var(--off);    --g1: var(--off);    --g2: var(--off);
  --g3: var(--dim);    --g4: var(--dim);
  --g5: var(--on);     --g6: var(--on);     --g7: var(--on);
  --g8: var(--on);     --g9: var(--on);

  /* ── 语义与主题色派生 ──────────────────────────────────────────────
     顺序无关：同一元素上 var() 之间互相引用由继承和级联决定，不看书写顺序。 */

  --paper:      var(--g0);
  --surface:    var(--g1);
  --surface-2:  var(--g2);

  --text:       var(--g9);
  --text-2:     var(--g7);
  --text-mute:  var(--g6);
  --text-faint: var(--g5);
  --text-invert:var(--g0);   /* 深色带里「反白」= 反成深色 */

  /* ⚠️ 这三行以前漏改过一次：:root 里 --hair 已经从 color-mix 改成「淡」了，
     这里却还留着旧的半透明写法 —— 深色带于是多出一个第五色。
     改任何一层派生令牌，**两处都要改**。 */
  --hair: var(--dim);
  --rule: var(--dim);
  --edge: var(--on);

  --ac-wash: var(--g2);
  --ac-base: var(--g8);
  --ac-deep: var(--g9);
  --ac-text: var(--g9);
  --focus:   var(--ac-deep);

  /* --fill 已在本块顶部重新声明（中档两带共用），不需要再映射一次 */

  /* 栅格用本带的「淡」档打点 —— 与正显对底色的对比相同（都是 1.52），
     所以两带的栅格看起来一样弱。节距共用 --grid-size，不在这里重定义。
     同样刻意写字面值，理由见上文点阵一节。                          */
  --grid: radial-gradient(circle at center, #45494F .6px, transparent .7px);

  background-color: var(--off);        /* 用 background-color，不用 background 简写 */
  background-image: var(--grid);       /* —— 简写会把栅格一起冲掉                   */
  background-size: var(--grid-size);   /* radial-gradient 打点必须配节距            */
  color: var(--on);
}

/* 深浅之间不需要再画分隔线 —— 颜色变化本身就是边界，
   再压一道 --edge 的墨线会在交界处糊成一团。 */
.sec-dark            { border-top-color: transparent; }
.sec-dark + .sec     { border-top-color: transparent; }
.sec-dark + .sec-dark{ border-top: 1px solid var(--rule); }  /* 万一连着两段深的 */
