/* ============================================================
   v2-local.css —— 本地补丁，接在 v2-shell.css / v2-home.css 后面
   ============================================================
   规矩：**设计稿抄来的东西一律进 v2-shell/v2-home，本地改动一律进这里。**
   分开放是为了下次同步设计稿时一眼分得清哪些是抄的、哪些是我们加的。

   本文件分两段：
     【全站】外壳补丁 + token 修正 —— 每一页都吃到
     【首页】页面组件补丁 —— 一律带 `body.page-home` 前缀

   ⚠️ **加规则前先问：这个 class 别的页面用不用？**
   `.section-title` 有 30 个模板在用、`.pagination` 6 个、`.filter-item` 5 个、
   `.data-chip` 3 个。往全站段里写这类规则 = 悄悄改掉半个站，
   2026-08-11 就是这么把每一页的标题从 28px 压成 17px 的（沛伶原话「点进去都是乱的」）。
   ============================================================ */

/* ════════════════════════ 全站 ════════════════════════ */

/* ---------- 0. 拆掉旧顶栏布局留下的两条 ---------- */

/* main.css:322 的 `.main { max-width:1200px; margin:0 auto; padding:24px 28px }`
   是为**顶栏时代**写的——那时 `.main` 是页面唯一的居中容器。
   现在 `.main` 是侧栏右边那一整根柱子，这三条会把顶栏和内容再往里缩 28px、
   往下压 24px，实测比设计稿整体偏移了一格（header 落在 y=44 而不是 y=22）。 */
.main { max-width: none; margin: 0; padding: 0; }

/* `.skip-link` 在 main.css 里是 `position:fixed; top:-60px`，设计稿那份是
   `position:absolute; top:-100px`——两份都藏得住，但 fixed 那份聚焦时会盖住顶栏。 */
.skip-link { position: absolute; }

/* ⚠️ 外壳的**继承环境**要和设计稿一致，这条比看起来重要得多。

   设计稿的 body 没写 font-size / line-height，所以整份外壳继承的是浏览器默认
   16px / normal；main.css 的 body 是 `15px / 1.75`。1.75 这个行高一路继承进侧栏，
   于是（实测 1440 宽逐个量的）：

       .nav-item   稿 36px 高 → 本地 41px      九项累计差 45px
       .nav-divider 稿 y=372  → 本地 y=405
       .nav-menu    稿 680px  → 本地 674px（被挤到滚动）

   一眼看过去就是「左边那列尺寸不对、比设计稿松垮」（沛伶原话）。
   **只改外壳容器**，不动 main.css 的 body——别的页面的正文还要靠 1.75 撑可读性。
   首页的 .content 也一起改：设计稿的卡片自己都写了 line-height，继承 normal 才对得上。 */
.sidebar, .header, .mobile-menu, .mobile-tab-bar, .cmdk-overlay,
body.page-home .content { font-size: 16px; line-height: normal; }

/* 顶栏右侧那三颗的尺寸也是 main.css 压着设计稿（同样是逐个量出来的）：
   `.theme-toggle` main.css 写死 36×36、设计稿是 padding 撑出来的 38×32；
   `.btn` main.css padding 8×20 / 600 字重、设计稿 6×14 / 400。
   差的这 4px 会把整条顶栏从 64px 撑到 66px。 */
.theme-toggle { width: auto; height: auto; padding: 6px 10px; font-size: 16px; border-radius: var(--radius-sm); }
.btn { padding: 6px 14px; font-weight: 400; gap: 6px; }
.header-search { font-size: 16px; }
.header-right { margin-left: 0; }
/* 侧栏下拉在 main.css 里是带圆角的**浮层**（.nav-dropdown .dropdown-menu，0-2-0），
   设计稿是内嵌展开、无圆角。选择器要跟它一样长才盖得住。 */
.nav-dropdown .dropdown-menu { border-radius: 0; }
/* 命令面板 / 底部 tab / Toast 的几处零头，同样是 main.css 的旧值 */
.cmdk-header .cmdk-icon { font-size: 18px; }
.cmdk-body { padding: 0; }
.cmdk-all { font-weight: 400; }
.mobile-tab-bar .tab-search { font-size: 10px; padding: 6px 10px; }
.toast { line-height: normal; }

/* main.css:3336 `.patent-head { padding: var(--sp-4) var(--sp-5) }` 引用的
   `--sp-5` **全站从来没定义过**，于是整条 padding 作废、图纸头的字贴在边框上
   （/cars/ 那个「车型库」标题实测就是这么和副标题叠在一起的）。
   补上这一格：8px 网格里 4 和 6 之间就是 20px。 */
:root { --sp-5: 20px; }

/* ---------- A. 设计稿用了但没定义的 ---------- */

/* 设计稿门头/数据带上到处写着 class="tnum"，却没有对应规则——
   它想要的显然是等宽数字。这些数会随筛选变化，不等宽会左右跳。 */
.tnum { font-variant-numeric: tabular-nums; }

/* 只给读屏器的文字。此前全站没定义过它，于是核验章里那句
   「已核验：N 家独立来源报道过同一事件」是**真的画在页面上**的（改版 ⑰ 带进来的）。 */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ---------- C. 本地独有模块 ---------- */

/* Django messages。设计稿是静态页，没有这一块。 */
.flash-stack { display: flex; flex-direction: column; gap: 6px; }
.flash {
    padding: 10px 16px; border-radius: var(--radius-sm);
    font-size: var(--fs-sm); border: 1px solid;
}
.flash-ok { background: var(--green-light); color: var(--green); border-color: var(--green); }
.flash-error { background: var(--red-light); color: var(--red); border-color: var(--red); }

/* 移动端菜单里的退出表单：设计稿那颗是裸 button，本地是 form 包着的 */
.mobile-menu form { margin: 0; }
.mobile-menu form button { width: 100%; }

/* ---------- D. token 修正（设计稿的对比度漏网） ---------- */

/* `--ink4` 在设计稿里既当装饰色又当小字色。实测（页面上真取 getComputedStyle 算的，
   不是查表）：**10px 小字 35 处，3.41:1**，AA 要 4.5。它盖着门头小字、五个工位、
   热力图品牌名、每张卡的来源和时间，外壳这边还盖着侧栏落款和页脚。

   这个坑本仓库踩过一次、也解过一次：main.css 的注释里写着「ink-3 从 #8A8578
   调暗到 #726D60」，理由一模一样。这里沿用同一个值，色相不动，只压明度：
       日间 #8A8578 → #726D60   3.41 → 4.78
       夜航 #7A7468 → #8A8478   4.03 → 4.81
   注意 `--ink4`（无划线）是设计稿那套 token，跟 main.css 的 `--ink-4`（有划线）
   是两个不同的名字，改这个不影响老页面。 */
:root { --ink4: #726D60; }
[data-theme="dark"] { --ink4: #8A8478; }

/* `--on-red` 是设计稿夜航块**唯一漏掉的一个 token**：它的 :root 里写了 `#fff`，
   夜航块里 21 个 token 全翻了面，就这一个没跟上。而 :root 和 [data-theme="dark"]
   特异性相同、设计稿那份排在 main.css 后面 —— 于是连 main.css 早就定好的
   `--on-red: #1E1C18` 也被这个 :root 覆盖掉了，**顺带影响到别的页面**。
   结果：夜航模式下所有红底角标是白字压浅珊瑚，2.99:1。 */
[data-theme="dark"] { --on-red: #1E1C18; }
/* 顺着 --on-red 修完剩最后一格：夜航的 --red-deep #C86048 压深墨 4.23:1，差 0.27。
   往亮里挪 6 阶（#CE664E）到 4.56:1，肉眼看不出来。 */
[data-theme="dark"] { --red-deep: #CE664E; }

/* 金底上的字：设计稿一律 `#fff`，实测 **2.25:1**。
   本仓库早就为同一件事定过 `--on-gold: #1E1C18`（main.css 注释：「金底上的字色，
   深浅两套主题都用深墨」），这里沿用，8.0:1。
   只挑**外壳里**的两颗（站名方块、主按钮）；页面里的那几处在下面首页段。

   ⚠️ **这是本次唯一一处看得出来的「没照抄」**：按钮上的字从白色变深墨。
   要退回设计稿原样，把这条和首页段那条一起删掉即可（然后主按钮回到 2.25:1）。 */
.btn-primary, .logo-icon { color: var(--on-gold); }
/* 跳过链接（键盘用户按 Tab 第一个拿到的东西）也是金底白字 1.9:1。
   无障碍入口自己不可读，比别处更说不过去。 */
.skip-link { color: var(--on-gold); }

/* ---------- 字阶：把设计稿压小的两档还回来（#632） ----------
   v2-shell.css 档头自己记着这笔账：「--fs-xs 12px→11px · --fs-sm 14px→13px …
   要改回来在 v2-local.css 里改，别动这里」——这里就是改回来。

   为什么值得偏离设计稿：11px 在本站不是角标专用，它盖着新闻卡摘要、判定说明、
   免责声明这些**整句中文**；规则库的中文字号表写着 11px 只许放 2–3 字短状态。
   答辩是投影播放，11px 中文在投影上会糊成一团。

   只动这两个 token（各 +1px），不动 --fs-base（15px 是正文，设计稿的行长按它排的，
   动它会整页重排）。真截图对过 1440 / 390 两个宽度，卡片没换行、没溢出。 */
:root { --fs-xs: 12px; --fs-sm: 14px; }


/* ════════════════════ 只在首页（body.page-home） ════════════════════ */
/* 下面每一条都**必须**带 body.page-home 前缀——这些 class 在别的模板里也有，
   不带前缀就会像 2026-08-11 那次一样把二级页全改坏。 */

/* ---------- 把设计稿的值从 main.css 手里抢回来 ---------- */
/* v2-home.css 排在 main.css 后面，同特异性它赢。**但 main.css 里有一批更特异的
   旧规则**（`.magazine-grid .news-card:first-child h3` 是 0-3-1，设计稿那条只有 0-1-1），
   排后面也盖不掉。逐条是拿设计稿和本地两边 getComputedStyle 对着 diff 出来的：

     .news-card-body h3          稿 14px 无衬线   ← main.css 给了 17px 衬线
     首图卡 :first-child          稿 和别的卡一样   ← main.css 让它通栏 + 28px 大标题
     .card-summary               稿 12px          ← main.css 13px
     .card-meta                  稿 10px / gap10  ← main.css 11px / gap12
     .hot-rank.top-1/2/3         稿 红/金实心角标  ← main.css 金字号 22px

   头条卡通栏那条尤其明显：设计稿的信息流是**齐整的双列**，
   main.css 会把第一张拉成通栏大卡，一眼就不是同一个版式了。 */
body.page-home .magazine-grid .news-card:first-child { grid-column: auto; }
body.page-home .magazine-grid .news-card:first-child .news-card-thumb { height: 130px; }
body.page-home .magazine-grid .news-card:first-child h3,
body.page-home .magazine-grid .news-card:first-child.no-cover .news-card-body h3,
body.page-home .news-card.no-cover .news-card-body h3,
body.page-home .news-card-body h3 { font-family: var(--sans); font-size: 14px; font-weight: 600; }
body.page-home .magazine-grid .news-card:first-child.no-cover .news-card-body { padding: 14px 16px; }
body.page-home .news-card.no-cover .news-card-body .card-summary,
body.page-home .news-card-body .card-summary { font-size: 12px; }
/* color 也要抢：main.css 这条挂的是**它自己那套** `--ink-4`（中划线名，#8A8578），
   跟设计稿的 `--ink4`（无划线名）是两个 token。不接管的话上面把 --ink4 调暗
   等于白调——首页最密的那层小字仍然停在 3.41:1。 */
body.page-home .news-card-body .card-meta { font-size: 10px; gap: 10px; color: var(--ink4); }
body.page-home .ticker-delta.d-flat { color: var(--ink3); }
/* 热榜前三：设计稿是实心色块，main.css 那版是「金色大数字」——
   两种视觉语言，摆在同一张卡里只能留一种。
   红底上的字走 `--on-red`（日间白、夜航深墨）而不是写死 #fff。 */
body.page-home .hot-rank.top,
body.page-home .hot-rank.top-1 { background: var(--red); color: var(--on-red); font-size: 11px; opacity: 1; }
body.page-home .hot-rank.top-2 { background: var(--red-deep); color: var(--on-red); font-size: 11px; opacity: 1; }
body.page-home .hot-rank.top-3 { background: var(--gold); color: var(--on-gold); font-size: 11px; opacity: 1; }
body.page-home .blocked-tape { color: var(--on-red); }
body.page-home .lane-go, body.page-home .pagination .current { color: var(--on-gold); }
/* 同一笔账剩下的四颗金底（#631 扫全站时找出来的，和上面三条同因同解）：
   热榜第三名角标（一、二名是红底走 --on-red，就第三名是金底）、早报播放键、
   送检按钮、头版大图上的分类标签。都是 1.9:1，改完 8.0:1。 */
body.page-home .trending-item:nth-child(3) .trending-rank,
body.page-home .brief-row .play,
body.page-home .deck-go,
body.page-home .hero-overlay .tag { color: var(--on-gold); }
/* 排名角标和倾向净值在 main.css 里走衬线数字（Fraunces），设计稿走无衬线；
   数据角标在 main.css 里带 1px 描边，设计稿是纯色块无边。 */
body.page-home .hot-rank, body.page-home .ticker-delta { font-family: var(--sans); }
body.page-home .data-chip { border: none; }

/* 剩下这一批是把整页每个 class 拿两边 getComputedStyle 逐个对出来的尾巴
   （沛伶：「其他字体大小和间距那些都不一样」）。都是 main.css 的旧值压着设计稿：

     .ticker-strip   多了 margin-top:16px  —— 倾向屏和门头之间白白多出一档
     .ticker-badge   letter-spacing .66px  —— 药丸被撑宽
     .ticker-item    13px（稿继承 16px，字号由内部两个 span 各自定）
     .section-title  line-height 1.3（稿 normal）
     .card-meta      margin 0（稿 margin-top:auto —— 元信息该贴在卡片底边）
     .q-badge/.hot-rank  line-height 被写死，药丸高度对不上
   `.card-meta` 那条最显眼：不贴底的话，摘要长短不同的卡片，来源和时间会各停在
   各自的高度上，一排卡片的下沿就参差了。 */
body.page-home .ticker-strip { margin: 0; }
/* 卡片里角标那一排：设计稿靠 .news-card-body 的 gap:6px 拉开，main.css 又额外
   给了 margin-bottom:8px —— 每张卡多出 8px，一排卡片下来就明显松了。 */
body.page-home .data-chips { margin-bottom: 0; }
body.page-home .ticker-badge { letter-spacing: normal; gap: normal; }
body.page-home .ticker-viewport { border-radius: 0; }
body.page-home .ticker-item { font-size: 16px; }
body.page-home .section-title { line-height: normal; }
body.page-home .news-card-body .card-meta { margin-top: auto; }
body.page-home .q-badge, body.page-home .hot-rank,
body.page-home .img-credit { line-height: normal; letter-spacing: normal; }

/* ---------- 真数据带来的状态（设计稿的静态示例里不存在） ---------- */

/* 新闻卡缩略图里的官图署名。设计稿的卡片缩略图是纯 emoji，没有这一格；
   本地是真官图，**出处必须跟着图走**（#464）。 */
body.page-home .news-card-thumb { position: relative; background: var(--line); }
body.page-home .news-card-thumb .img-credit { right: 6px; bottom: 4px; }

/* 题图第二档：按事件类型的矢量图示（static/covers/，设计稿 assets/covers 搬来的）。

   **用 contain 不用 cover**：图位是 130px 高的宽扁块（约 2.9:1），原图 480×270（1.78:1），
   cover 会把上下各裁掉约 39px——实测把「智能驾驶」标签、那把锁、「降价」药丸全裁没了，
   剩下半张看不懂的图。改成 contain 让整张图完整可见。

   代价是两侧要留白，所以**图位底色要跟每张图自己那块满幅底色对上**（下面六条），
   对不上就会在图两边露出两条别的颜色的边，比裁掉还难看。 */
body.page-home .news-card-thumb .cover-illus {
    width: 100%; height: 100%; object-fit: contain; display: block;
}
body.page-home .news-card-thumb.illus-recall  { background: #FBEFE0; }
body.page-home .news-card-thumb.illus-price   { background: #FDEDE6; }
body.page-home .news-card-thumb.illus-launch  { background: #FBF3DC; }
body.page-home .news-card-thumb.illus-policy  { background: #F1EFE7; }
body.page-home .news-card-thumb.illus-smart   { background: #EEF2EC; }
body.page-home .news-card-thumb.illus-generic { background: #F4F1E8; }
/* 夜航模式下这六块浅底会在深色页面上炸成六个亮方块。压一档亮度即可——
   不做反相：图里那台车、那把锁是深墨画的，反相就成了白线飘在浅底上。 */
[data-theme="dark"] body.page-home .news-card-thumb.illus { filter: brightness(.55) saturate(.8); }
/* 「图示」角标：**它是这一层的诚信开关**。这站的立意是不造假，把一张画的图
   悄悄摆在新闻照片的位置上，评委问一句「这是那台车吗」就答不上来。
   两个字、压深底，和官图署名共用一个位置和样式。 */
body.page-home .news-card-thumb .illus-mark { letter-spacing: .08em; }

/* 热力图要够样本才出（media_brand_matrix 判 ready）。不出的时候头版独占整行，
   否则 1.5fr 的头版旁边留一块 1fr 的空白。 */
body.page-home .front-row.front-solo { grid-template-columns: 1fr; }

/* 头版大图：设计稿写的是 `height:100%; min-height:330px`。
   在 grid 里 `height:100%` 依赖父级高度，而父级高度又由内容决定——
   循环之下 img 用自然高度把整块撑到几屏高（改版 ⑰ 实测踩过，整页被顶飞）。
   固定高 + object-fit:cover 才是可预测的，长相和设计稿一致。 */
body.page-home .fp-hero-img { height: 380px; min-height: 0; }
@media (max-width: 1100px) { body.page-home .fp-hero-img { height: 260px; } }
/* 头版没真图时也走图示。大图位是 1.6:1 左右、图 1.78:1，contain 就够，
   底色同样按类型对齐（跟卡片那六条一个道理）。
   注意 `.fp-hero-img::after` 那层压暗渐变照旧——标题压在图上要读得清。 */
body.page-home .fp-hero-img .cover-illus { width: 100%; height: 100%; object-fit: contain; }
body.page-home .fp-hero-img.illus-recall  { background: #FBEFE0; }
body.page-home .fp-hero-img.illus-price   { background: #FDEDE6; }
body.page-home .fp-hero-img.illus-launch  { background: #FBF3DC; }
body.page-home .fp-hero-img.illus-policy  { background: #F1EFE7; }
body.page-home .fp-hero-img.illus-smart   { background: #EEF2EC; }
body.page-home .fp-hero-img.illus-generic { background: #F4F1E8; }
/* 图示上的「图示」角标要躲开右下角的年检章和图注位 */
body.page-home .fp-hero-img .illus-mark { right: 8px; bottom: 6px; z-index: 3; }

/* 倾向屏的条数：设计稿的 ticker 只有品牌和净值两格，本地多一格「N 条」
   （净值背后有多少条判定，不摆出来那个小数就是不可核的）。 */
body.page-home .ticker-item .ticker-num { color: var(--ink4); }

/* 返修区那一行：设计稿是个跳转链接 `.repair-line`，本地是 `<details>` 的 summary
   （#18 验收要求「可手动展开」，见 home.html 那段注释）。
   收起时要长得和设计稿那一行一模一样，所以把 `.folded-low summary` 的玻璃卡样式
   让位给 repair-line 的虚线条，并去掉默认的三角标记。 */
body.page-home .folded-low > summary.repair-line {
    display: flex; align-items: center; gap: 9px;
    margin-top: 12px; padding: 9px 14px;
    border-radius: var(--radius-sm); border: 1px dashed var(--line);
    background: var(--card); font-size: 11px; color: var(--ink4);
    list-style: none; cursor: pointer;
}
body.page-home .folded-low > summary.repair-line::-webkit-details-marker { display: none; }
body.page-home .folded-low > summary.repair-line:hover { border-color: var(--gold); color: var(--gold-text); }
/* 展开后那句「展开看被折叠的 ›」要改口，否则展开着还写着「展开」 */
body.page-home .folded-low[open] > summary.repair-line em { visibility: hidden; position: relative; }
body.page-home .folded-low[open] > summary.repair-line em::before {
    content: '收起 ‹'; visibility: visible; position: absolute; right: 0; white-space: nowrap;
}

/* ---------- 设计稿的暗色漏网 ---------- */
/* 设计稿有一批**没跟着主题翻面**的写死颜色。它那份静态页只有 5 个筛选 chip、
   也没人在夜航模式下看过，所以没暴露；本地首页有 14 个 chip 摊在明面上，
   一切暗色立刻现形。逐条是量出来的对比度，不是目测：
       .filter-item        底色恒为 rgba(255,255,255,.4) → 暗色下 1.63:1（读不出来）
       .type-chip 政策/智驾  字色写死深蓝/深紫          → 暗色下 2.51:1
       .lane-row input     同 filter-item 那个白底      → 输入框在暗色下是一条亮带
   本站的规矩是**拿实测对比度说话**（tools/contrast_check.py）。 */
[data-theme="dark"] body.page-home .filter-item,
[data-theme="dark"] body.page-home .lane-row input { background: rgba(255, 255, 255, 0.06); }
[data-theme="dark"] body.page-home .folded-low summary { background: rgba(36, 33, 28, 0.5); }
[data-theme="dark"] body.page-home .type-chip.type-policy,
[data-theme="dark"] body.page-home .chip-type.type-policy { color: #9CBEDC; background: rgba(106, 142, 176, .16); }
[data-theme="dark"] body.page-home .type-chip.type-autonomous,
[data-theme="dark"] body.page-home .chip-type.type-autonomous { color: #C7B0DC; background: rgba(138, 110, 160, .18); }
/* 设计稿夜航块里那条 `.pagination span { background: … !important }` 把**当前页**
   那颗金色药丸也一起吃掉了（!important 压过 .pagination .current），
   于是夜航模式下当前页 1.02:1、完全看不出停在第几页。 */
[data-theme="dark"] body.page-home .pagination .current { background: var(--gold) !important; }
/* 本地新增的 .brief-row 和返修行走的是 var(--card)（已跟着主题翻），但描边还是浅色 */
[data-theme="dark"] body.page-home .brief-row,
[data-theme="dark"] body.page-home .repair-line { border-color: var(--line); }

/* 未核验章：跟已核验章同一枚章的两个章面（沛伶：「反正就是要有章」）。
   金色留给「已核验」——金是这个站的肯定色，未核验用中性墨线，
   **不用红**：红在本站是「未过检/被拦下」的意思，一条只是没交叉核到的新闻
   挂红章会被读成「这是假的」，那是两件完全不同的事。 */
body.page-home .fp-seal-open .ro { fill: rgba(250, 248, 244, .92); stroke: var(--ink3); }
body.page-home .fp-seal-open .ri,
body.page-home .fp-seal-open .rl { stroke: var(--ink3); opacity: .5; }
body.page-home .fp-seal-open .sm,
body.page-home .fp-seal-open .ss { fill: var(--ink2); }

/* ════════════════════════ 数据总览 /stats/ ════════════════════════ */

/* 改版⑱（d701160）把 `sidebar.css` 整份删了换成 v2-* 外壳，但这一页的两组
   图形样式只住在那份文件里，跟着一起没了：热力图退化成一张裸数字表、语料结构
   退化成两串纯文字行。模板一个字没改，所以测试也没红——**丢的是"看得见"的那半**。
   下面是从 `d701160^:static/css/sidebar.css` 原样搬回来的，外加两处补：
     · 新加的 `.heat-x-*` 高亮描边（main.css:3849）在裸表上是唯一的视觉，
       搬回底色后它才回到"在色块上再描一圈"的本意；
     · 条形图和色块补进场动画——这两块原来是死的，改版前后都没动过，
       但它是这一页仅剩的静态图形，滚到了才长出来比一上来就摆在那里好读。 */

/* ---- 媒体 × 品牌 倾向净值热力图 ----
   透明度承担「强度」这一个语义，色相承担「正/负」——一个视觉通道只编码一件事。
   样本不足的格子用中性灰，和「净值接近 0」在视觉上分得开：前者是没数据，
   后者是有数据但不偏，混成一个颜色就是在骗读者。 */
.heat-table { border-collapse: separate; border-spacing: 3px; width: 100%; min-width: 560px; }
.heat-table th {
    font-size: var(--fs-xs); font-weight: 600; color: var(--ink-3);
    text-align: center; padding: 2px 4px; white-space: nowrap;
}
.heat-table th.heat-src { text-align: right; padding-right: 8px; color: var(--ink-2); }
.heat-cell {
    text-align: center; padding: 7px 4px; border-radius: 5px;
    font-size: var(--fs-xs); font-weight: 700; font-variant-numeric: tabular-nums;
    cursor: default;
}
.heat-pos { background: color-mix(in srgb, var(--gold) calc(var(--a) * 100%), transparent); color: #3a2e00; }
.heat-neg { background: color-mix(in srgb, var(--red) calc(var(--a) * 100%), transparent); color: #4a1a0f; }
.heat-none { background: var(--line-2, var(--line)); color: var(--ink-3); font-weight: 400; }
[data-theme="dark"] .heat-pos,
[data-theme="dark"] .heat-neg { color: #F0E8D4; }
.heat-key { display: inline-block; width: 11px; height: 11px; border-radius: 3px; vertical-align: -1px; margin-right: 4px; }

/* ---- 语料结构两张条形图：难看的分布照实画，它是「为什么要扩源」的证据 ---- */
.shape-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.shape-h { font-size: var(--fs-sm); font-weight: 700; color: var(--ink-2); margin-bottom: 10px; }
.shape-row { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
.shape-lb { flex: 0 0 68px; font-size: var(--fs-xs); color: var(--ink-3); text-align: right; }
.shape-bar { flex: 1; height: 18px; border-radius: 4px; background: var(--line-2, var(--line)); overflow: hidden; }
.shape-bar i { display: block; height: 100%; background: var(--gold); opacity: .75; border-radius: 4px; }
.shape-bar i.cross { background: var(--ink-4); opacity: .55; }
.shape-n { flex: 0 0 84px; font-size: var(--fs-xs); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.shape-n em { font-style: normal; color: var(--ink-3); }
.shape-note {
    margin-top: 14px; padding: 10px 14px; border-left: 3px solid var(--gold);
    background: var(--gold-wash); border-radius: 0 6px 6px 0;
    font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.85;
}
@media (max-width: 768px) { .shape-grid { grid-template-columns: 1fr; } }

/* ---- 进场：条子从左长出来、色块淡入 ----
   宽度写在 style="width:N%" 的行内，动画只能走 transform，不然会覆盖行内值。
   `prefers-reduced-motion` 一律直接到位——这一页的图是证据，不是表演。 */
@media (prefers-reduced-motion: no-preference) {
    .shape-bar i { transform-origin: left center; animation: shape-grow .9s cubic-bezier(.22,1,.36,1) both; }
    .shape-row:nth-child(3) .shape-bar i { animation-delay: .06s; }
    .shape-row:nth-child(4) .shape-bar i { animation-delay: .12s; }
    .shape-row:nth-child(5) .shape-bar i { animation-delay: .18s; }
    .heat-cell { animation: heat-in .5s ease both; }
    .heat-table tr:nth-child(2) .heat-cell { animation-delay: .05s; }
    .heat-table tr:nth-child(3) .heat-cell { animation-delay: .10s; }
    .heat-table tr:nth-child(4) .heat-cell { animation-delay: .15s; }
    .heat-table tr:nth-child(5) .heat-cell { animation-delay: .20s; }
    .heat-table tr:nth-child(6) .heat-cell { animation-delay: .25s; }
    .heat-table tr:nth-child(7) .heat-cell { animation-delay: .30s; }
}
@keyframes shape-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes heat-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ════════════════════════ 半年记 /story/ ════════════════════════ */

/* **背景没了的真因不在这一页，在外壳。**
   `v2-shell.css:384` 给 `.content` 写了 `overflow-y:auto`（设计稿里内容区是自己
   带滚动条的一栏）。sticky 是**相对最近的滚动容器**粘的：`.content` 因此成了
   /story/ 那块 `.story-stage` 的滚动祖先，而它自己 clientHeight == scrollHeight
   （实测 5376 == 5376，真正在滚的是 window）——滚动祖先永远不动，sticky 就永远
   不触发，舞台跟着页面一起滚走。于是第一屏还看得见星空公路，往下就只剩
   `.story-wrap` 那层 `#080c1e` 纯色底。canvas 一直在画，只是被滚出视口了。

   /story/ 是通栏叙事页，本来就不需要内容区自带滚动条（#518 已把 `.story-wrap`
   从 `width:100vw` 改成 `width:100%`，横向溢出的老毛病也一起没了），
   所以这一页直接把 `.content` 退回普通块。**只改这一页**：别的页面还靠
   那条 `overflow-y` 兜住宽表格的横滚。 */
body.page-story .content { overflow: visible; }

/* 舞台粘在视口顶，浮动顶栏（sticky top:20px, z-index:20）压在它上面。
   顶栏是浅色毛玻璃 + 深色字，盖在夜景上就是一块糊掉的补丁——实测「每篇稿件
   过五个工位」和「长辈模式」在 03 章那屏几乎看不见。整条顶栏改深色玻璃 +
   浅色字：不是为了好看，是这一页的顶栏本来读不出字。
   ⚠️ 每一处都得点名写：v2-shell 给 `.creed`/`.elder-toggle-btn`/`.btn-outline`
   各自写死了 `color`，只在 `.header` 上改 color 继承不下去。 */
body.page-story .header {
    background: rgba(14, 18, 38, 0.62) !important;
    border-color: rgba(255, 255, 255, 0.14);
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.32);
}
body.page-story .header,
body.page-story .header .creed,
body.page-story .header .creed span,
body.page-story .header .elder-toggle-btn,
body.page-story .header .theme-toggle,
body.page-story .header .btn-ghost,
body.page-story .header .user-name { color: rgba(255, 255, 255, 0.80); }
body.page-story .header .creed b { color: #fff; }
body.page-story .header .creed .sep { color: rgba(255, 255, 255, 0.40); }
body.page-story .header .header-search {
    background: rgba(255, 255, 255, 0.10);
    border-color: rgba(255, 255, 255, 0.18);
    color: rgba(255, 255, 255, 0.80);
}
body.page-story .header .header-search input { color: #fff; }
body.page-story .header .header-search input::placeholder { color: rgba(255, 255, 255, 0.55); }
body.page-story .header .header-search kbd {
    background: rgba(255, 255, 255, 0.10); border-color: rgba(255, 255, 255, 0.20);
    color: rgba(255, 255, 255, 0.65);
}
body.page-story .header .elder-toggle-btn,
body.page-story .header .theme-toggle,
body.page-story .header .btn-outline { border-color: rgba(255, 255, 255, 0.24); }
body.page-story .header .btn-outline { color: #fff; }
/* 注册那颗是金底黑字，夜色里本来就够跳，不动。 */

/* 顶栏上方那 20px 的缝（见文末「外壳」一节）在这一页要黑，不是奶油色 */
body.page-story .header::before { background: #080c1e; }

/* 通栏：`.content` 有 16px 的 gap 和 4px 右内距，叙事页两侧留白会露出奶油底，
   夜景就被框成了一张卡片。这一页让它顶到内容列的边。 */
body.page-story .story-wrap { margin-right: -4px; }

/* ════════════════════════ 外壳：顶栏上方那道缝 ════════════════════════ */

/* `.header` 是 `sticky; top:20px`（v2-shell.css:290）——它上面那 20px 是
   **透空的**，正文滚上去会从缝里穿过去（实测 /stats/ 滚到第二屏，卡片正文
   有一行浮在顶栏上方）。拿一条跟页面同色的固定挡板把缝堵上，z-index 夹在
   正文(1) 和顶栏(20) 之间。
   ⚠️ 挡板挂在 `.header` 自己身上、用 **absolute**——第一版写成 `.main::before`
   + `position:fixed`，fixed 的 `left:0` 是**视口**左边不是内容列左边，于是那条
   挡板横穿整个屏幕，把侧栏上方那 20px 也涂了（实测顶上多一条黑边）。
   挂在 header 上：宽度天然等于内容列，跟着 sticky 一起走，也自动继承层级。
   底色抄 v2-shell.css:115/124 的 body 值，那两个是写死的十六进制、没有 token。 */
@media (min-width: 769px) {
    .header::before {
        content: ''; position: absolute;
        left: -1px; right: -1px; top: -21px; height: 21px;
        background: #F2EFE8;
        pointer-events: none;
    }
    [data-theme="dark"] .header::before { background: #141210; }
}

/* ════════════════════════ 进站仪式：压掉转速表期的遗留 ════════════════════════ */

/* `v2-shell.css:908–924` 那一段是**设计稿转速表版**的遗留：`.startup-tacho`
   已经随改版 ⑭ 换成抬杆、模板里一个字都没有了（StartupCeremonyTests 钉着它
   不许出现在 HTML 里），但同一段里的 `.startup-odometer` / `.startup-label`
   还活着，而且排在 main.css 之后——于是：
     · 累计数字被染回 `var(--ink)` 黑色（设计稿那版数字就是黑的，抬杆版收在金数字上）
     · 「累计已检 · 检测线就绪」被当成 tacho 版的站名标签，套上 18px / 金色 /
       letter-spacing 4px / uppercase，一句中文说明被拉成一排散字
   v2-shell 是「抄设计稿」的文件不动它（`docs/UI落地施工单.md` 的纪律），
   本地改动一律压在这里。 */
.startup-overlay { gap: 0; }
.startup-odometer {
    font-size: 42px; font-weight: 900;
    color: var(--gold-text); font-family: var(--font-display);
}
.startup-label {
    font-size: var(--fs-xs); font-weight: 400; color: var(--ink-3);
    letter-spacing: .04em; text-transform: none;
}

/* ════════════════════════ 首页门头右侧 ════════════════════════ */

/* 实测（1440 宽逐个量的）改之前的样子：
     .mb-item 甲「28 / 最近一批 · 08-09」宽 101px
     .mb-item 乙「798 / 返修区」        宽  53px
   两列各自右对齐、宽度差近一倍，数字落不到任何一条共用轴上；期号那行
   （x=1315 w=82）虽然是**垂直居中**的，却跟数字行、标签行两条基线都不对，
   卡在中间——看着就是「右边一堆东西各站各的」。

   根因已经在模板/视图那边治掉了（两个数改成同窗口同口径，标签一齐收短成
   四个字）。这里只补排版的三件：
     ① 两列给同一个 min-width，数字和标签一起靠右，两栏才对得起来；
     ② 期号跟数字组之间加一道竖分隔线 + 描边胶囊，让它从「飘在最右的裸文字」
        变成成组的一块；
     ③ 期号跟数字组的间距拉开到 16px，别贴着。
   ⚠️ 不加设计稿那对 ‹ › 翻期按钮：那是纯前端假翻页（点了只改文字、翻不出
   内容），当初就是**故意**没抄的，理由写在 home.html 门头那段注释里。 */
body.page-home .mast-board { gap: 16px; }
body.page-home .mb-item { min-width: 76px; }
body.page-home .mast-issue {
    padding: 5px 11px;
    border: 1px solid var(--line);
    border-radius: 999px;
    white-space: nowrap;
}
/* 竖线走 border-left + 负 margin，不新起一个空元素 */
body.page-home .mast-issue::before {
    content: '';
    align-self: stretch;
    border-left: 1px solid var(--line);
    margin: -5px 11px -5px -11px;
}
body.page-home .mast-issue #issue-label { color: var(--ink3); text-decoration: none; }
body.page-home .mast-issue a#issue-label:hover { color: var(--gold-text); }
@media (max-width: 900px) {
    /* 窄屏门头会换行，胶囊那道竖线跟着换行就成了一条悬空的线 */
    body.page-home .mast-issue::before { display: none; }
}
@media (max-width: 600px) {
    /* 入库状态可能是一整句停摆说明；让它独占一行并正常折行，不能反向撑宽页面。 */
    body.page-home .mast-board { flex-wrap: wrap; }
    body.page-home .mast-issue {
        width: 100%;
        min-width: 0;
        white-space: normal;
    }
    body.page-home .mast-pulse {
        min-width: 0;
        white-space: normal;
    }
}

/* 计算器页「相关观点」链接卡的 hover 描边。
   原来写在标签上：onmouseover="this.style.borderColor='var(--gold)'"。
   CSP 的 script-src 没放 'unsafe-inline'，行内处理器一律不执行——
   而这本来就是纯样式，交给 :hover 比交给 JS 更对。 */
.opinion-link:hover { border-color: var(--gold); }
