@charset "utf-8";
/* ============================================================
   天迹 SKYPRINT — 产品页
   设计语言：SKYPRINT / 星空晴夜（不是印刷品，是天空）

   色值一律取自 App 的令牌，不自己发明：
     SharedKit/Sources/SharedKit/Skyprint/Daypart.swift  ← SKDaypartPalette 四时段天幕
     SharedKit/Sources/SharedKit/Skyprint/Tokens.swift   ← 文字、强调色、玻璃、字阶
     Skyprint/Theme/SkyTheme.swift                      ← 天幕合成与 skyInk

   全页只有一种字色（--ink #F2F7FF）。原因不是省事：白字压在 #45759F 上
   是 4.54:1，而 App 的第二档灰 #A9BEDC 压在同一个底色上只有 2.58:1，
   做正文不达标。所以层次一律用字号 / 字重 / 字距 / 行距表达，
   不用 opacity，也不用调灰。

   页面仍分两半（白昼天幕 / 夜阑天幕），但两半共用同一套深色令牌——
   .sky--day 与 .sky--night 只负责画各自的天幕渐变，不再重新赋值令牌，
   视图规则一行不用写两遍。
   ============================================================ */

/* ── 共用令牌 ─────────────────────────────────────────────── */
/* ★ 改颜色之前先读这段：对比度怎么测 ────────────────────────────
   测「文字压在渐变上」的对比度时，背景必须来自**一张没有字的图**：
     ① 先正常截图，拿到每个文字元素的计算字色与矩形；
     ② 再注入 `* { color: transparent !important; text-shadow: none !important; }`
        截第二张（底色、图片、描边全在），逐元素取它矩形区域的中位数 ——
        这张图里没有字形，取到的才是它真正的背景；
     ③ 用 ② 的底色算对比度。
   两种看起来合理、实际会给出假数字的做法，都踩过：
     · 取元素「上方 3–8px 的带」—— 紧贴图片的图注，取到的是**截图底边**，
       报 4.74，真值 14.6；
     · 取元素「整行中位数」—— 密集汉字的笔画占比高，中位数落在字与底之间，
       报 3.42，真值约 12。
   教训同上一条：[data-reveal] 的 opacity:0、grep 的模式失效、这里的取样，
   三次「看起来坏了」都是**测量方法的产物**。先怀疑观察方法，再怀疑产物。 */

/* 这里全部是**夜阑半的默认值**。白昼半在 .sky--day / .masthead 上各自覆盖同一批变量，
   见下面「白昼段配色覆盖」。所以：新加颜色一律走变量，不要在组件里写死，
   否则将来再调天色就得逐条找。 */
:root {
  /* 主字色（夜阑半：白字压深天幕） */
  --ink: #F2F7FF;
  /* 次字色（夜阑半）。当初被迫与 --ink 同值：旧深底上 #A9BEDC 只有 2.58:1。
     夜色板转成 #101B2E → #2C435F 之后，实测 #A9BEDC 压最暗端 9.03:1、压最亮端 5.29:1，
     所以这一半终于可以有序层次。**但只用于元数据**：眉标 / 图注 / 页脚小字 / req 清单。
     正文、标题、清单值一律仍用 --ink —— 那些是主信息，掉一档就变成「次要」了。 */
  --ink-2: #A9BEDC;

  /* 装饰细线。注意这不是控件边界 */
  --line:    rgba(234, 243, 255, 0.14);
  --line-2:  rgba(234, 243, 255, 0.09);
  /* 控件边界必须是实色：白 44% 压在 #45759F 上只有 2.22:1，过不了 1.4.11 的 3:1 */
  --line-strong: #C9DDF2;

  /* 玻璃条（只做装饰性容器，不做交互控件边界） */
  /* 玻璃面用 skyInk 而不是白：白字压 #45759F 只有 4.54:1，任何 ≥1% 的白叠加都会掉到
     4.5 以下（白 6% 实测 4.04:1）。深玻璃同时与 App 的 cardFill(#0F1B30 @ 0.82) 同向。 */
  --glass-fill:   rgba(7, 15, 30, 0.10);
  --glass-stroke: rgba(234, 243, 255, 0.44);

  /* 焦点环与 hover 下划线：默认琥珀（夜阑半 10.96:1 达标） */
  --focus-ring: var(--solar);
  --hover-line: var(--solar);
  /* 色卡描边 */
  --chip-border: rgba(234, 243, 255, 0.34);

  /* 主按钮：琥珀实底 + 墨字。琥珀压 #45759F 是 3.14:1、压夜色 10.96:1，两半都过 3:1 */
  --btn-bg:       #FFC48A;
  --btn-ink:      #070F1E;
  --btn-bg-hover: #FFD6AC;

  /* 次要按钮 hover：背景与边框两个通道一起动 */
  --ghost-hover-bg:     rgba(7, 15, 30, 0.12);
  --ghost-hover-border: #EAF3FF;

  /* 品牌原色 */
  --solar:    #FFC48A;   /* solarAmber：点、线、光晕、实底按钮 */
  --solar-hi: #FFD6AC;   /* solarHi */
  --trail:    #C9DDF2;   /* trailSilver：云轨 */
  --sky-ink:  #070F1E;   /* skyInk：墨底 */

  /* 字体：中文 Sarasa Gothic SC → PingFang SC；数字 Inter → 系统 */
  --font: "Sarasa Gothic SC", "PingFang SC", -apple-system, BlinkMacSystemFont,
          "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif;
  --font-num: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Display",
              "Helvetica Neue", system-ui, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* 版心几何：这一轮不动 */
  --wrap: 1180px;
  --pad: clamp(20px, 5vw, 60px);
  --gutter: clamp(16px, 2.2vw, 32px);

  /* 字阶（对齐 SKType：eyebrow 11 / body 14 / title19 / display51） */
  --fs-eyebrow: 11px;
  --fs-body: clamp(15px, 1.05vw, 16.5px);
  --fs-caption: 13px;
  --fs-value: 14px;
  /* 主张句的字号只定义一次，--sm / --lg 从它等比缩放，不写死 */
  --claim-fs: clamp(24px, 2.6vw, 34px);

  /* 区块节奏：内容删掉四成之后整体放大 8% */
  --sect-pad: clamp(69px, 8.42vw, 121px);

  /* 圆角（对齐 SKGlass.Corner：chip 14 / card 28） */
  --r-chip: 14px;
  --r-card: 28px;
}

/* ── 白昼段配色覆盖（App 转正后的浅天幕）────────────────────
   天幕 #7FB2D8 → #DCEBF5，所以这一段里的字必须翻成墨蓝，否则白字压浅蓝不可读。
   **只覆盖变量，不动组件** —— 组件里所有颜色都走 var()，所以这一段改一次就够。

   .masthead 也挂在这里：它在 .sky 之外（书眉在 <main> 之前），但视觉上就是天幕的顶，
   取色必须与天幕 0% 完全一致，否则页面最上方会出现一条深色横杠。

   --ink-2 取 skyInk2 #17293F，**与 App 同一套值**：App 里「压在天上」的次文字就是
   skyInk2，而 #44566E 是「卡片内」的次文字 —— 两个值本来就分开，别混。
   实测压最深那段天幕 #7FB2D8：#070F1E 天上主 8.45 / #17293F 天上次 6.50 /
   #44566E 卡片次 3.31（不达标）。天幕是渐变的，字可能落在任何一段，所以按最深端取值。 */
.sky--day,
.masthead {
  --ink: #070F1E;                          /* skyInk：压在天上的主文字 */
  --ink-2: #17293F;                        /* skyInk2：压在天上的次文字（6.50:1 @ #7FB2D8） */
  --line: rgba(7, 15, 30, 0.16);
  --line-2: rgba(7, 15, 30, 0.10);
  --line-strong: #2E3E52;                  /* 控件边界：压在浅天幕上 ≥4.7:1 */
  --glass-fill: rgba(255, 255, 255, 0.55);
  --glass-stroke: rgba(7, 15, 30, 0.28);
  --ghost-hover-bg: rgba(255, 255, 255, 0.45);
  --ghost-hover-border: #070F1E;
  /* 焦点环与 hover 下划线不能在浅底上用琥珀（#FFC48A 压 #7FB2D8 只有 1.5:1，
     焦点环过不了 3:1）。换成墨蓝，同时保留下划线的「位置」这条非颜色通道。 */
  --focus-ring: #070F1E;
  --hover-line: #070F1E;
  --chip-border: rgba(7, 15, 30, 0.28);
}

/* ── 天幕 ─────────────────────────────────────────────────
   白昼：浅天幕（App 转正后的 day 色板）#7FB2D8 → #DCEBF5
   夜阑：App 转正后的夜色板 #101B2E → #2C435F（上→下）。
        ⚠️ 方向与旧值相反：旧的 #1E3048 → #111C30 是「上浅下深」，
        新的是「上深下浅」—— 别只换两个 hex，方向一起顺过来，
        否则页面和 App 的天光是反的（这里踩过一次）。 */
.sky--day {
  /* 故意写渐变最暗的一端：白昼段是深字压浅底，最坏情况出现在最暗那段天幕上 */
  background-color: #7FB2D8;
  background-image: linear-gradient(180deg, #7FB2D8 0%, #DCEBF5 100%);
}
.sky--night {
  position: relative;
  background-color: #101B2E;   /* 最暗的一端，白字压它最保险，审计按它算 */
  background-image: linear-gradient(180deg, #101B2E 0%, #2C435F 100%);
}

/* 渐变防色带。实测（Chromium 1440×900，天幕中段 1×800 竖条逐行取色）：
   Chrome 自带抖动，同色 run 的平均长度 1.13px，但局部会粘出 13–40px 的平台，
   所以在 .sky 上压一层 opacity .016 的极轻噪点，把平台打散。
   —— 用 ::after 而不是 ::before，因为 .sky--night::before 已经是星点层。 */
.sky { position: relative; }
.sky::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .016;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* 噪点层必须压在内容下面 */
.sky > * { position: relative; z-index: 1; }

/* 星点。App 的 showsStars 只有 night 为 true（day / dawn / dusk 全是 false），
   所以只有夜阑这半有星，白昼半不许有。这一页只留静态的一层，密度压到刚好
   能被看见——它是品牌的一部分，不是装饰。 */
.sky--night::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.55;
  background-repeat: repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='412' height='412'%3E%3Cg fill='%23EAF3FF'%3E%3Ccircle cx='28' cy='44' r='1' opacity='.62'/%3E%3Ccircle cx='176' cy='18' r='.7' opacity='.38'/%3E%3Ccircle cx='330' cy='72' r='.9' opacity='.5'/%3E%3Ccircle cx='96' cy='168' r='.7' opacity='.34'/%3E%3Ccircle cx='252' cy='138' r='1.1' opacity='.66'/%3E%3Ccircle cx='388' cy='206' r='.7' opacity='.32'/%3E%3Ccircle cx='42' cy='286' r='.9' opacity='.46'/%3E%3Ccircle cx='204' cy='322' r='.7' opacity='.36'/%3E%3Ccircle cx='318' cy='288' r='1' opacity='.54'/%3E%3Ccircle cx='132' cy='392' r='.7' opacity='.3'/%3E%3C/g%3E%3C/svg%3E");
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 24px;
  overflow-x: clip;
  /* = 夜阑天幕末端 = 页脚色，页面两端都不会露出别的底 */
  background: #2C435F;
}

body {
  margin: 0;
  background: #2C435F;
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.74;
  letter-spacing: 0;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

::selection { background: rgba(255, 196, 138, 0.45); color: var(--sky-ink); }

img { max-width: 100%; height: auto; }

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

/* 焦点环：琥珀在两半都过 3:1（白昼半 3.14、夜阑半 10.96） */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: 12px; top: -60px;
  z-index: 20;
  padding: 10px 16px;
  border-radius: var(--r-chip);
  background: var(--btn-bg);
  color: var(--btn-ink);
  font-size: 12px;
  letter-spacing: 0.08em;
  transition: top .2s ease;
}
.skip-link:focus { top: 12px; }

/* 不许拆词：中文按字断行，遇到「分开」这类两字词会被劈开
   —— text-wrap: balance 只平衡行长，不保护词的完整性 */
.nw { white-space: nowrap; }

/* ── 版心与栅格 ─────────────────────────────────────────── */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
}

/* 定位点在左，标题从第 4 栏起 —— 这一条就是「不盲目对齐」的骨架 */
.grid > .eyebrow { grid-column: 1 / span 3; }
.grid > .claim   { grid-column: 4 / span 8; }
.grid > .body    { grid-column: 4 / span 5; }
.grid > .body--tail { grid-column: 4 / span 5; }
.grid > .notes,
.grid > .callout { grid-column: 4 / span 5; }
/* 带行末标签的清单要放得开：六行 #more 的值都是整句，5 栏只有 460px，会折成两行半 */
.grid > .notes--tag { grid-column: 4 / span 8; }
.grid > .spec    { grid-column: 4 / span 8; }
.grid > .lines   { grid-column: 4 / span 8; }
.grid > .cta     { grid-column: 4 / span 5; }
/* 节末小字：与正文同起第 4 栏，但不跟正文一样收到 5 栏——
   它是能一口气读完的一句陈述，宽一点反而更像注脚而不像第二段正文。 */
.grid > .fineprint { grid-column: 4 / span 8; margin-top: clamp(18px, 2vw, 26px); }

/* 图文并列：文字块整体算一个栅格项，图版不参与行高计算。
   早期用 grid-row: 2 / span 3 让图版跨行——align-self:start 不改变轨道尺寸，
   图版的高度照样摊到每一行上，段落之间就撑出空洞。 */
.grid--aside > .text {
  grid-column: 1 / span 8;
  grid-row: 1;
  min-width: 0;
  /* 内部再切一道 8 小栏：8 栏宽 + 同一个 gutter 反解出来的小栏，
     宽度正好等于大栅格的 59px，所以「标题从第 4 栏起」与其它区块严丝合缝。 */
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
  /* 文案变短之后，文字块贴着图版顶端会留下大片空洞；
     垂直居中让两侧重心对齐，行高不变。 */
  align-self: center;
}
.grid--aside > .text > .eyebrow { grid-column: 1 / span 3; }
.grid--aside > .text > .claim,
.grid--aside > .text > .body,
.grid--aside > .text > .callout,
.grid--aside > .text > .notes { grid-column: 4 / span 5; }

.grid--aside > .grid__aside {
  grid-column: 9 / span 4;
  grid-row: 1;
  align-self: start;
  margin-top: clamp(8px, 2vw, 34px);
}

/* 镜像：图在左、文在右 */
.grid--mirror.grid--aside > .text {
  display: block;
  grid-column: 6 / span 7;
}
.grid--mirror.grid--aside > .grid__aside {
  grid-column: 1 / span 4;
  margin-top: clamp(0px, 1vw, 14px);
}

.text > :first-child { margin-top: 0; }
.text > :last-child { margin-bottom: 0; }

/* 双栏 */
.grid--split > .col-text { grid-column: 1 / span 5; }
.grid--split > .col-aside { grid-column: 8 / span 5; margin-top: clamp(20px, 4vw, 64px); }

/* ── 字号与文本 ───────────────────────────────────────────
   全站只有一种字色。层次靠字号 / 字重 / 字距 / 行距，四样都用上。 */
.eyebrow {
  margin: 0 0 clamp(16px, 2vw, 26px);
  font-family: var(--font);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: none;   /* 加了它会把 iOS 写成 IOS */
  color: var(--ink-2);
}

h1, h2, h3 {
  font-family: var(--font);
  font-weight: 600;
  color: var(--ink);
  /* 新版浏览器生效，旧版自动忽略 */
  text-wrap: balance;
  letter-spacing: -0.02em;
  line-height: 1.12;
}

.claim {
  margin: 0 0 clamp(18px, 2.2vw, 28px);
  font-size: var(--claim-fs);
  line-height: 1.14;
  letter-spacing: -0.02em;
}
/* 相对主张句等比缩放，不写死第二套 clamp */
.claim--sm { font-size: calc(var(--claim-fs) * 0.78); line-height: 1.26; }
.claim--lg { font-size: calc(var(--claim-fs) * 1.5); line-height: 1.1; }

.body {
  margin: 0;
  max-width: 44ch;   /* 中文按字宽算，一行三十来字，读起来不回头 */
  color: var(--ink);
  font-size: var(--fs-body);
  line-height: 1.74;
  text-wrap: pretty;
}
.body--tail { margin-top: 1em; }
.body + .body { margin-top: 1em; }

/* ── 书眉 ───────────────────────────────────────────────── */
.masthead {
  position: relative;
  /* 与白昼天幕渐变的 0% 同色，接缝不可见。天幕转浅色后这里必须同步，
     否则页面最上方是一条深色横杠。 */
  background: #7FB2D8;
  border-bottom: 1px solid var(--line);
}
.masthead__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  padding-block: 20px;
}
.brand {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  justify-self: start;
  /* 必须显式上色：不写就继承 body 的 --ink 字面值（白），
     而白昼半的 --ink 已被覆盖成墨蓝 —— 自定义属性不会自动改「继承来的 color」。
     实测漏这行时「天迹」是 2.11:1。 */
  color: var(--ink);
}
.brand__zh {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.06em;
}
.brand__en {
  font-family: var(--font-num);
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--ink);
  /* 不加 uppercase：品牌字本来就写成全大写 SKYPRINT，别让 CSS 再去动它 */
}
.nav {
  display: flex;
  gap: clamp(14px, 2.2vw, 30px);
  justify-self: center;
}
.nav a {
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--ink);
  padding-block: 4px;
  border-bottom: 1px solid transparent;
  transition: border-color .25s ease;
}
.nav a:hover { border-bottom-color: var(--hover-line); }
.masthead__cta {
  justify-self: end;
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--ink);
  padding-bottom: 3px;
  border-bottom: 1px solid var(--line-strong);
  transition: border-color .25s ease;
}
.masthead__cta:hover { border-bottom-color: var(--hover-line); }

/* ── 首屏 ───────────────────────────────────────────────── */
.hero__grid { row-gap: clamp(34px, 4.6vw, 60px); }
.hero__copy { grid-column: 1 / span 7; }
.hero__plate {
  grid-column: 9 / span 4;
  margin-top: clamp(0px, 3.4vw, 54px);
}

.hero__title {
  margin: 0;
  font-size: clamp(40px, 6.4vw, 84px);
  line-height: 1.02;
  letter-spacing: -0.025em;
}
/* 主屏截图未就位期间：文案块从 7 栏放宽到 9 栏，右侧不再留一块空场。
   图回来后删掉 .hero__grid--solo 这个类名即可，其余规则不用动。 */
.hero__grid--solo .hero__copy { grid-column: 1 / span 9; }
.hero__lede {
  margin: clamp(20px, 2.4vw, 30px) 0 0 clamp(0px, 3vw, 46px);
  max-width: 31em;
  color: var(--ink);
  font-size: clamp(15.5px, 1.4vw, 18px);
  line-height: 1.72;
}

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px clamp(16px, 2.2vw, 34px);
  margin-top: clamp(40px, 5.4vw, 78px);
  padding-top: 16px;
  border-top: 1px solid var(--line-2);
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--ink-2);
}

/* ── 区块节奏（有意不统一，全部由 --sect-pad 派生） ─────── */
.sect {
  position: relative;
  padding-block: var(--sect-pad);
  border-top: 1px solid var(--line-2);
}
.sect--first { border-top: 0; padding-top: clamp(52px, 6.05vw, 86px); }
/* 夜阑的第一个区块不画分隔线：那条线正好落在天幕由黄昏转夜的位置，
   会被读成「接缝」。 */
.sky--night > .sect:first-of-type { border-top: 0; }

#design   { padding-block: calc(var(--sect-pad) * 1.10); }
#precip   { padding-block: calc(var(--sect-pad) * 0.94); }
#trend    { padding-block: calc(var(--sect-pad) * 1.18); }
#alert    { padding-block: calc(var(--sect-pad) * 0.95); }
#details  { padding-block: calc(var(--sect-pad) * 1.03); }

.sect--download {
  padding-block: calc(var(--sect-pad) * 1.25);
  border-top: 1px solid var(--line);
}

/* ── 黄昏过渡带 ───────────────────────────────────────────
   App 的时间插值（SKSkyBlend）：日落前 45 分钟 = day 色板 → 日落后 15 分钟
   = dusk 色板 → 日落后 90 分钟 = night 色板。日落时刻落在带内 60/135
   = 44.44%。三个停机点就是这三个色板的地平线色；中间的插值由浏览器按 sRGB
   通道做，与 App 的 mix()（RGB 分量线性插值）是同一套算法，所以这里能逐像素
   复现 App 的时间曲线——不要加减停机点，也不要改这三个色值。 */
/* 黄昏带：三个停机点就是 App 的时间插值，一个都不要动、也不要加中间点。
   App 的 SKSkyBlend 在日落 -45m → +15m → +90m 之间做 RGB 分量线性插值，
   与 CSS 默认的 sRGB 插值是同一套算法，所以三个点就能逐行复现，加中间点只会
   引入自己的采样误差。44.44% = 60/135，只有在这个位置「转折」才落在日落上。
   实测（1440×900，带高 306px、612 设备行）：与 App 解析曲线逐行对齐 max ΔE2000 = 0.781
   （< 1.0 = 不可辨），带内相邻行 max 0.866、ΔE≥1 占 0%，两条接缝单步 ΔE = 0.0000。
   这里若硬切，白昼末端直接跳到夜色，单步 ΔE 会非常大 —— 现在是把它摊成几百步。
   （具体 ΔE 数值随色板变化，不再写死，免得又是一条过期注释。）
   ⚠️ 带内**不需要**噪点层：三通道在 306px 里分别跨 53/69/87 个 LSB，几乎每行换色，
   实测最长同色平台只有 1.5 CSS px。别「顺手」加一层——那会给带内引入约 0.3 ΔE
   的固定偏置，把上面那个 0.781 顶大。 */
.dusk {
  position: relative;
  height: clamp(280px, 34vh, 420px);
  background-color: #DCEBF5;          /* 带内最亮的一端，审计按它算 */
  background-image: linear-gradient(180deg,
      #DCEBF5 0%,        /* = 白昼半末端（新 day 地平线）。必须与 .sky--day 的 100% 同值，
                             否则浅天幕接深黄昏带会出现一条硬边 */
      #7A5F6B 44.44%,    /* = 日落那一刻（新黄昏色板的地平线端） */
      #101B2E 100%);     /* = 夜阑半首端，必须等于 .sky--night 的 0%，否则接缝出硬边 */
  overflow: hidden;
}
.dusk__arc {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  color: var(--trail);
  opacity: 0.7;
}
/* 太阳压在云轨上，而且必须压在两个「同一件事」的坐标上：
     x = 62%（= 893/1440，path 在 viewBox 里的锚点横坐标）
     y = 44.44%（= 日落时刻在 App 插值窗口 60/135 里的位置，path 在 x=893 处的 y 已同步改成 160 = 44.44%×360）
   preserveAspectRatio="none" 让 x 随宽度等比缩放，所以这两个数在任何宽度都成立。
   不许为了「好看」挪它——旧值 42.2%（y=152）会让太阳比日落在视觉上早三分钟。 */
.dusk__sun {
  position: absolute;
  left: 62%;
  top: 44.44%;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  background: var(--solar-hi);
  box-shadow:
    0 0 10px 2px rgba(255, 196, 138, 0.95),
    0 0 44px 16px rgba(255, 196, 138, 0.40),
    0 0 120px 52px rgba(255, 196, 138, 0.16);
}
/* 放在带内下三分之一：那里底色已在 #53404B 以下，白字 ≥ 8.8:1 */
.dusk__note {
  position: absolute;
  left: 0;
  right: 0;
  bottom: clamp(18px, 3vw, 34px);
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.16em;
  color: var(--ink);
}

/* ── 四时天色色板 ─────────────────────────────────────────
   纯 CSS，不引图片。四段色值就是 SKDaypartPalette 的四个 SKDaypart，
   是这一页所有背景色的出处，所以它本身就是「设计语言」的证据。
   纵向间距不写在这里：色板现在住在 #design 的两栏里，与上一块的间距
   由 .pair-row 的 margin-top 统一负责，避免两处同时管一件事。 */
.skybars {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--gutter);
}
.skybars__item {
  display: flex;
  flex-direction: column;
  gap: 9px;
  min-width: 0;
}
.skybars__chip {
  display: block;
  height: clamp(88px, 12vw, 148px);
  border-radius: var(--r-chip);
  /* 描边不能用 --line（白 14%）：它会与色卡自己的渐变合成，四张卡上几乎看不见边，
     而「白天」那张的天顶 #25406E 与本节天幕（#25406E——#45759F 的中段）本来就同色，
     没有边就会被读成一块脏斑。34% 才够把色卡与天空分开，同时不抢成「选中态」。 */
  border: 1px solid var(--chip-border);
  background-image: linear-gradient(180deg, var(--sky-top), var(--sky-bottom));
}
.skybars__name {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink);
}
.skybars__hex {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.skybars__note {
  margin: 14px 0 0;
  max-width: 44ch;
  font-size: 13px;
  line-height: 1.68;
  color: var(--ink-2);
}

/* ── 图版（深色截图压在天空上，不需要手机壳） ───────────── */
.plate {
  margin: 0;
  min-width: 0;
}
.plate img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--sky-ink);
  box-shadow: 0 22px 50px -30px rgba(7, 15, 30, 0.62);
}
.plate figcaption {
  margin-top: 10px;
  font-size: var(--fs-caption);
  line-height: 1.6;
  color: var(--ink-2);
  letter-spacing: 0.01em;
  display: flex;
  align-items: baseline;
  gap: 9px;
}
/* 云轨小刻度替代原来的「——」：一段 1px 的线，比破折号干净 */
.plate figcaption::before {
  content: "";
  flex: 0 0 14px;
  height: 1px;
  background: var(--line-strong);
  transform: translateY(-3px);
}
/* 图注里的前缀（聚合 / 分开 / 二级页）：靠字重和字距区分，不另开字色 */
.plate figcaption em {
  font-style: normal;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--ink);
  flex: 0 0 auto;
}

/* 两栏：左色板 2×2 / 右手机图版。
   删掉那张 1560×700 的对照图之后，右侧只剩 430px 宽的图，左侧空出约 690×1024，
   所以把色板与图版合成同一条栅格，让左栏把那片空场吃回来。
   色板原来待在自己的 .wrap 里、靠 margin-top 与上一块拉开距离；两栏合并之后
   这个间距落在栅格容器 .pair-row 上——若落在左栏（.pair-row__text）里，
   色板会整体往下推 68px，左栏顶线就与右侧手机图差一截。 */
.pair-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(280px, 30vw, 430px);
  gap: clamp(28px, 4vw, 72px);
  align-items: start;
  /* 与上一块的间距落在栅格容器上，不能落在左栏里——落在左栏会把色板整体往下推 68px，
     左栏顶端就比右侧手机图低一截，两栏的顶线对不上。 */
  margin-top: clamp(40px, 5vw, 68px);
}
.pair-row__text { min-width: 0; }
/* 两栏里色板走 2×2：4 栏在 572px 的列宽下每格只有 128px，色卡会退化成细长条，
   色值那行还会折行。2×2 之后每格 270px，色卡本身也顺势加高，左栏高度才追得上
   右侧 963 高的手机图（顶端仍严格对齐，不居中、不拉伸）。 */
.pair-row .skybars { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.pair-row .skybars__chip { height: clamp(96px, 20vw, 280px); }

/* 截图缺位期间，色板从 .pair-row 里搬出来单独占一条通栏（图版不在，两栏会空掉右边）。
   通栏下 4 栏 × 265px 正好，不必再拉高色卡；.skybars 的默认 4 栏就是这里用的。
   图回来后把这层壳撤掉、改回 .pair-row 即可。 */
.skybars-wrap { margin-top: clamp(40px, 5vw, 68px); }

/* 4 栏在 390px 下每格只有 78px，色值那行会被「→」劈成三段，所以窄屏回到 2×2 */
/* ── 产品截图（05 印迹 / 06 海洋）───────────────────────────── */
/* 官网此前没有一张真机截图，这两节第一次用图。

   三个决定：
   1. **整屏**而不是裁卡片。裁出来的图没有状态栏、没有背景天幕，
      看着像设计稿；整屏才有「这是真在跑」的分量。
   2. 圆角 26 + 一圈 --line 描边 + 深投影。截图本身是深色，直接贴在
      深色天幕上会糊在一起，描边负责把它「切」出来。
   3. 固定 width/height 属性 + lazy。三张图各 80KB 左右，
      但首屏不该为下面两节付这笔带宽 —— 高度写死是为了不跳版。 */
.shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 20px;
  margin: 30px 0 4px;
  align-items: start;
}

/* 只有一张图时不铺满整行：潮汐那张单独放，撑满会大得离谱 */
.shots--single {
  grid-template-columns: minmax(0, 340px);
}

.shots figure {
  margin: 0;
}

.shots img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 26px;
  border: 1px solid var(--line);
  background: #0B1424;
  box-shadow: 0 26px 60px rgba(4, 10, 22, 0.46);
}

.shots figcaption {
  margin-top: 12px;
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: 0.02em;
  text-align: center;
  color: var(--ink);
  opacity: 0.72;
}

@media (max-width: 560px) {
  .shots { grid-template-columns: 1fr; }
  .shots--single { grid-template-columns: 1fr; }
}

@media (max-width: 700px) {
  .skybars-wrap .skybars { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.plate--md, .plate--sm, .plate--wide, .plate--tall { width: 100%; }

.plate--cap { align-self: start; }

/* 三机横排：故意高低不齐 */
.rail {
  display: flex;
  gap: clamp(18px, 2.6vw, 40px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  margin-top: clamp(26px, 3.4vw, 44px);
  padding-block: 8px 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.rail::-webkit-scrollbar { height: 2px; }
.rail::-webkit-scrollbar-thumb { background: var(--line); }
.plate--rail {
  flex: 0 0 clamp(180px, 25vw, 300px);
  scroll-snap-align: start;
}
.plate--rail:nth-child(1) { margin-top: 24px; }
.plate--rail:nth-child(2) { margin-top: 0; }
.plate--rail:nth-child(3) { margin-top: 40px; }

/* 卡本体裁切件（aggregated 1140×632、typhoon 1206×420）：宽高比与手机整屏完全不同。
   ① 圆角必须收小 —— 28px 压在一个 167px 高的横条上会把卡自己的圆角啃掉一圈，
      它自带的圆角按 1140→300px 缩放后只有 10px 左右；
   ② 横排里垂直居中 —— 同排的手机屏 650px 高、裁切件只有 170px，贴顶会像缺了一块；
      同时把 nth-child 那套高低错落撤掉，错落的前提是三个一样高的东西。
   这两条要排在 .plate--rail:nth-child 之后，靠顺序压过它们（同特异性）。 */
.plate--crop img { border-radius: var(--r-chip); }
/* 选择器带上 .rail 是为了压过上面那套 .plate--rail:nth-child(n) 的错落偏移：
   那条规则的 specificity 与 .plate--rail.plate--crop 相同，却排在后面，
   不加这一层的话 margin-top 会被它改回 24/0/40。 */
.rail .plate--rail.plate--crop { align-self: center; margin-top: 0; }

/* 窄屏一次只看得到一张图，居中就变成「卡片浮在一大块空场中间」——
   390px 下卡片高 167px、相邻手机屏高 650px，它上方会空出近 300px，
   看起来像图没加载。窄屏改成与相邻手机屏的顶线对齐。 */
@media (max-width: 900px) {
  .rail .plate--rail.plate--crop { align-self: flex-start; margin-top: 0; }
}

/* ── 清单：条目之间一条细线，没有任何项目符号 ───────────── */
.notes {
  margin: clamp(24px, 2.8vw, 36px) 0 0;
  padding: 0;
  list-style: none;
}
.notes li {
  display: grid;
  grid-template-columns: 7.2em minmax(0, 1fr);
  gap: 0.9em;
  padding: 12px 0;
  border-top: 1px solid var(--line-2);
  font-size: var(--fs-value);
  line-height: 1.7;
  color: var(--ink);
}
.notes li:last-child { border-bottom: 1px solid var(--line-2); }
.notes li b {
  font-weight: 600;
  font-size: var(--fs-value);
  color: var(--ink);
  letter-spacing: 0.01em;
}
.notes--wide { margin-top: 0; }
.notes--wide li { grid-template-columns: 6.4em minmax(0, 1fr); }

/* 引文：玻璃条 + 一条 2px 琥珀强调线 */
.callout {
  margin: clamp(26px, 3.2vw, 40px) 0 0;
  padding: 14px 18px;
  border: 1px solid var(--glass-stroke);
  border-left: 2px solid var(--solar);
  border-radius: 0 var(--r-chip) var(--r-chip) 0;
  background: var(--glass-fill);
}
.callout__text {
  display: block;
  font-size: clamp(15px, 1.4vw, 17px);
  line-height: 1.66;
  color: var(--ink);
  letter-spacing: 0.01em;
}
.callout__from {
  display: block;
  margin-top: 7px;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--ink);
}

/* 行式表（预警）。它和上面的正文分属两个 .wrap，必须自己带上间距，
   否则第一条分隔线会紧贴段落末行，看着像给正文画了下划线。 */
.lines { margin-top: clamp(20px, 2.4vw, 30px); }
.lines__row {
  display: grid;
  grid-template-columns: 9em minmax(0, 1fr);
  gap: 1em;
  padding: 14px 0;
  border-top: 1px solid var(--line-2);
}
.lines__row:last-child { border-bottom: 1px solid var(--line-2); }
.lines__k {
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--ink);
  padding-top: 3px;
}
.lines__v { font-size: var(--fs-value); line-height: 1.72; color: var(--ink); }

/* ── 行末标签「高级版」 ───────────────────────────────────
   它是陈述，不是促销：不加边框、不加底色、不加圆角。一旦有了壳，那枚字会被读成
   价签，而这一版要的是「这条属高级版」这句事实本身。
   字色必须是 --ink，不许换次一档灰：第二档灰 #A9BEDC 压在白昼渐变上只有 2.58:1，
   11px 小字连 4.5:1 都到不了。字号与字距沿用 .fineprint 那一套（11 / .06em）。
   不加 font-weight：小字号加粗会被读成强调，这里不需要强调。 */
.tag {
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink);
  /* 一律不折行：标签一旦拆成「高级／版」，就不再是标签 */
  white-space: nowrap;
  align-self: baseline;
}

/* 三列：名词 / 值 / 标签。第二列写成 minmax(0, 1fr)，句再长也只压自己，
   不会把第三列挤到行外（1fr 的自动最小尺寸是内容宽度，长句会顶破栅格）。 */
.notes--tag li { grid-template-columns: 7.2em minmax(0, 1fr) auto; }
.lines--tag .lines__row { grid-template-columns: 9em minmax(0, 1fr) auto; }

/* 规格表：两栏，避免一条道排到底 */
.spec {
  margin: clamp(26px, 3.2vw, 40px) 0 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: clamp(24px, 4vw, 64px);
}
.spec__row {
  display: grid;
  grid-template-columns: 8.2em minmax(0, 1fr);
  gap: 0.8em;
  padding: 13px 0;
  border-top: 1px solid var(--line-2);
}
.spec dt {
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--ink);
  padding-top: 3px;
}
.spec dd {
  margin: 0;
  font-size: var(--fs-value);
  line-height: 1.68;
  color: var(--ink);
}

/* 三档并列（数据源）：默认两栏会把第三项单独甩到下一行左半边，
   读起来像"彩云 vs 混合"配对、和风落单。三档是平级选项，改成整行三条。 */
.spec--tri { grid-template-columns: minmax(0, 1fr); }
.spec--tri .spec__row { grid-template-columns: 8.2em minmax(0, 1fr); }
.spec--tri dt { color: var(--ink); }
.spec--tri dd { max-width: 34em; }
/* 三条之后紧跟署名段，末行补一道下边线，否则读起来像还没说完 */
.spec--tri .spec__row:last-child { border-bottom: 1px solid var(--line-2); }

/* 表格后面直接跟正文时（目前只有 #source 的署名段），必须把两者分开。
   .body 自身 margin 是 0，紧贴上一条的下边线会读成「表格的第四行」——
   而那句是署名/法律声明，不是数据行，视觉上必须自成一段。 */
.spec + .body { margin-top: clamp(20px, 2.4vw, 28px); }

/* ── 下载区 ─────────────────────────────────────────────── */
.cta { margin-top: clamp(26px, 3.2vw, 40px); }
.cta--wide { max-width: 34em; }

.cta__row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 13px 22px;
  border-radius: var(--r-chip);
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background-color .25s ease, border-color .25s ease, color .25s ease;
}
.btn--lg { padding: 15px 27px; font-size: 14px; }

/* 主按钮：两半都是琥珀实底墨字。琥珀压 #45759F 3.14:1、压夜色 10.96:1，
   作为控件边界都过 3:1，所以不再需要「白昼墨底亮字」那套分支。 */
.btn--primary {
  background: var(--btn-bg);
  border: 1px solid var(--btn-bg);
  color: var(--btn-ink);
}
.btn--primary:hover {
  background: var(--btn-bg-hover);
  border-color: var(--btn-bg-hover);
}

/* 次要按钮：背景透明，边界用实色银蓝（--line-strong）。
   不能用 rgba 凑透明度——白 44% 压在 #45759F 上只有 2.22:1。 */
.btn--ghost {
  background: transparent;
  border: 1px solid var(--line-strong);
  color: var(--ink);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  backdrop-filter: blur(14px) saturate(1.1);
}
.btn--ghost:hover {
  background: var(--ghost-hover-bg);
  border-color: var(--ghost-hover-border);
}

.store-slot { margin-top: 14px; }

.store-pill {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  border: 1px solid var(--glass-stroke);
  border-radius: 999px;
  background: var(--glass-fill);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink);
}
/* main.js 在 LINKS.appStore 有值时会在 .store-pill 里插入一个空的 span.store-pill__dot
   （图标 CSS 已删）。空 span 本身零宽，但 flex gap 会把它算进去，多出 9px 空档。 */
.store-pill > span:empty { display: none; }

/* main.js 在 LINKS.appStore 有值时会把这条换成可点的链接。
   文字仍是 --ink，只用琥珀描边表示「可点了」——琥珀承载文字在白昼半只有 3.14:1。 */
.store-pill--live {
  border-color: var(--solar);
  color: var(--ink);
  transition: background-color .25s ease;
}
.store-pill--live:hover { background: var(--ghost-hover-bg); }

/* 不加「·」分隔符：flex 换行时行首行尾都会挂着一个孤零零的点。
   改用纯间隔，靠字距和留白分项。 */
.req {
  display: flex;
  flex-wrap: wrap;
  gap: 6px clamp(14px, 1.8vw, 24px);
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink-2);   /* 元数据：降一档（下载区适配清单） */
}

.fineprint {
  margin: 10px 0 0;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink);
}

/* ── 页脚 ───────────────────────────────────────────────── */
/* 页脚**永远**是夜阑那一端（底色写死 #2C435F），所以它必须自带一套夜空令牌，
   不能靠「恰好被包在 .sky--night 里」继承上色。原因和 .brand 那条一样：
   自定义属性不会改「继承来的 color」——在 index.html 里它本来就在 .sky--night 内，
   一切正常；但 privacy.html 整页转成白昼之后，页脚会拿到墨蓝字压深底 #2C435F，
   实测 1.3:1。这里显式声明一次，两个页面都不再依赖 DOM 位置。
   值取自 :root 的夜阑默认值，不改任何现有渲染。 */
.colophon {
  --ink: #F2F7FF;
  --ink-2: #A9BEDC;
  --line: rgba(234, 243, 255, 0.14);
  --line-2: rgba(234, 243, 255, 0.09);
  --line-strong: #C9DDF2;
  --hover-line: var(--solar);
  --focus-ring: var(--solar);

  position: relative;
  /* = 夜阑天幕渐变的末端，接缝不可见 */
  background: #2C435F;
  border-top: 1px solid var(--line);
  padding-block: clamp(32px, 3.8vw, 50px);
}
.colophon__inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 16px clamp(20px, 3vw, 44px);
}
.colophon__brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  /* 和 .brand 同一类问题：这里原本靠 body 继承上色，是**全页最后一个**没有显式 color 的
     文字节点。今天解析出来只有它一个，补上之后没有任何文字靠 body 兜底了。
     当前值等于继承值，渲染不变。 */
  color: var(--ink);
}
.colophon__note {
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink-2);   /* 元数据：降一档 */
}
.colophon__links {
  display: flex;
  flex-wrap: wrap;          /* 页脚现在七项，390px 下一行排不下，必须允许折行 */
  gap: clamp(14px, 2vw, 26px);
  justify-self: end;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink);
}
.colophon__links a:hover { border-bottom: 1px solid var(--solar); }

/* ── 进场 ───────────────────────────────────────────────── */
/* ⚠️ 验截图的人先看这里：带 data-reveal 的元素在淡入前是 opacity: 0。
   如果截整页图之前没有把该区域真正滚进视口并等 1 秒以上，截出来就是「空白」——
   而 DOM 里元素在、图的 naturalWidth 也正常，看起来像「排版塌了」，实际只是没淡入。
   判断「空白」之前先过四道闸：态（测的是哪一份产物）→ 存在于否 → 属性是否正常
   → 可见性/动画是否收敛。前三道全过才是真坏了。这条踩过一次，代价是一整轮误判。 */
html.js [data-reveal] {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity 0.8s cubic-bezier(0.16, 0.84, 0.44, 1),
    transform 0.8s cubic-bezier(0.16, 0.84, 0.44, 1);
}
html.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}
html.js .rail [data-reveal]:nth-child(2) { transition-delay: 0.08s; }
html.js .rail [data-reveal]:nth-child(3) { transition-delay: 0.16s; }

/* ── 响应式 ─────────────────────────────────────────────── */
@media (max-width: 1080px) {
  .hero__copy { grid-column: 1 / span 8; }
}

@media (max-width: 900px) {
  body { line-height: 1.72; }

  /* 栅格退化为单栏纵向，但保留「定位点—正文」的层级差 */
  .grid { display: block; }
  /* 单栏时那道 8 小栏的内栅格必须撤掉，否则 121px 的标签栏会把字挤爆 */
  .grid--aside > .text { display: block; }

  .grid > .eyebrow,
  .grid .text > .eyebrow { margin-bottom: 14px; }
  .grid > .claim,
  .grid .text > .claim { margin-bottom: 18px; }
  .grid > .grid__aside,
  .grid--aside > .grid__aside { margin-top: clamp(32px, 6.5vw, 52px); }

  .grid > .notes,
  .grid > .callout,
  .grid > .spec,
  .grid > .lines,
  .grid > .cta { margin-top: clamp(24px, 5.6vw, 38px); }

  .grid--split > .col-text { margin-top: 0; }
  .grid--split > .col-aside { margin-top: clamp(28px, 5.6vw, 44px); }

  .spec { grid-template-columns: minmax(0, 1fr); }

  .masthead__inner {
    grid-template-columns: 1fr auto;
    row-gap: 10px;
    padding-block: 15px;
  }
  .nav {
    grid-column: 1 / -1;
    grid-row: 2;
    justify-self: start;
    overflow-x: auto;
    padding-bottom: 4px;
    width: 100%;
  }
  .masthead__cta { grid-row: 1; grid-column: 2; }

  .hero__plate { margin-top: clamp(30px, 6vw, 46px); width: min(72%, 380px); }
  .hero__lede { margin-left: 0; }

  /* 两栏退成单栏：色板在上、图版在下（grid 自动按 DOM 顺序排）。
     单栏里图版不能吃满整行——963 高的原图在 900px 宽下会被拉到 1700 高。 */
  .pair-row { grid-template-columns: minmax(0, 1fr); margin-top: clamp(32px, 6.5vw, 52px); }
  .pair-row > .plate { width: min(74%, 430px); }

  .plate--rail:nth-child(1) { margin-top: 14px; }
  .plate--rail:nth-child(3) { margin-top: 26px; }

  .dusk__note { font-size: 10px; }

  .colophon__inner { grid-template-columns: 1fr; gap: 10px; }
  .colophon__links { justify-self: start; }
}

@media (max-width: 560px) {
  .notes li { grid-template-columns: 6em minmax(0, 1fr); }
  .lines__row { grid-template-columns: 6.4em minmax(0, 1fr); }
  .spec__row { grid-template-columns: 7em minmax(0, 1fr); }
  .cta__row { flex-direction: column; align-items: stretch; }
  .btn { justify-content: center; }
  .hero__plate { width: 100%; }
  .plate--rail { flex-basis: 74vw; }
  .plate img { border-radius: 20px; }
  .skybars__hex { font-size: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.js [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
  * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* ── 正文内链 ───────────────────────────────────────────────
   链接在深色天幕上不能只靠颜色区分（白字 + 琥珀底只有 3.14:1，做正文不够），
   所以用下划线这一条非颜色通道。hover 把线换成琥珀，等于把「可点」再说一遍。 */
.body a,
.prose a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--line-strong);
}
.body a:hover,
.prose a:hover { border-bottom-color: var(--solar); }

/* ── 页脚补充行：来源署名与备案号 ─────────────────────────
   备案号是合规展示项，不是导航，所以单独一行、不挤进 __links。
   空值时整行 hidden（未备案前不许出现空占位）。 */
.colophon__meta {
  margin-top: clamp(20px, 2.4vw, 28px);
  padding-top: clamp(16px, 1.8vw, 22px);
  border-top: 1px solid var(--line-2);
  display: grid;
  gap: 7px;
  font-size: 11px;
  line-height: 1.7;
  letter-spacing: 0.06em;
  color: var(--ink-2);   /* 元数据：降一档 */
}
.colophon__meta a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line-2); }
.colophon__meta a:hover { border-bottom-color: var(--solar); }
.colophon__icp[hidden] { display: none; }

/* ── 行末标签的窄屏写法 ─────────────────────────────────────
   标签在任何断点下都不许消失（05 的两行、06 的一行、09 的六行都靠它说「这条要钱」）。
   窄屏不 display:none，也不硬塞三列：把标签挪到值下面一行、左对齐在第 2 栏，
   名词列同时收窄，句子仍有 230px 左右，比压成两行半的窄条好读。
   这两条必须排在上面 @media (max-width: 560px) 之后 —— 同特异性，靠顺序取胜。 */
@media (max-width: 560px) {
  /* 5.4em（=75.6px @14px）装不下「空气质量地图」六个字，会折成「空气质量地／图」，
     所以名词列放到 6.2em（86.8px）：六个字刚好一行，值仍剩 250px。 */
  .notes--tag li { grid-template-columns: 6.2em minmax(0, 1fr); row-gap: 3px; }
  .lines--tag .lines__row { grid-template-columns: 5em minmax(0, 1fr); row-gap: 3px; }
  .notes--tag .tag,
  .lines--tag .tag { grid-column: 2; }
}

/* QQ 群兜底那行：群号 + 复制按钮，窄屏自动换行。
   2026-11-06 加，配合 index.html 里 data-copy-text 的按钮。 */
.cta__fallback {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
