/* ==========================================================================
   base.css — 结构与组件（两套皮肤共用）
   颜色/圆角等由 theme-light.css 或 theme-dark.css 提供
   加载顺序：base.css 在前，theme-*.css 在后（后者覆盖变量）
   ========================================================================== */

/* ---------- 1. reset ---------- */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
img,svg{display:block;max-width:100%;height:auto}
button,input,textarea,select{font:inherit;color:inherit}
a{color:inherit;text-decoration:none}
ul,ol{list-style:none}

/* ---------- 2. 设计变量（皮肤会覆盖其中颜色项） ---------- */
:root{
  /* 字体：只用系统字体栈。不引 Google Fonts —— 国内加载慢甚至失败 */
  --font-sans: system-ui,-apple-system,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Segoe UI",sans-serif;
  --font-mono: ui-monospace,SFMono-Regular,Consolas,"Courier New",monospace;

  /* 尺度 */
  --maxw: 1120px;
  --gutter: 24px;
  --sec-y: 96px;       /* 区块上下留白（Vercel 系的大留白基调） */
  --sec-y-sm: 64px;

  --r-pill: 999px;
  --ease: cubic-bezier(.4,0,.2,1);
  --dur: .18s;
  /* 揭示动效专用时长。.18s 是悬停的节奏；12px 的位移放在 .18s 里会像"跳"一下——
     位移越大，时间要越长才显得稳。 */
  --dur-reveal: .42s;
  /* 快起慢收。--ease 是标准缓动（两头都慢），长位移的揭示用它起步会发木。
     只管揭示；悬停一律继续用 --ease。 */
  --ease-out: cubic-bezier(.16,1,.3,1);

  /* 按钮（皮肤可覆盖） */
  --btn-primary-bg:   var(--accent);
  --btn-primary-bg-h: var(--accent-hover);
  --btn-ghost-border: var(--border-strong);

  /* 颜色兜底值（未加载皮肤时也能看）。
     正常都会加载 theme-light.css 或 theme-dark.css，这里只是保险。 */
  --bg:#fff;--bg-sub:#fafafa;--panel:#fff;--panel-hover:#fcfcfc;
  --border:#eaeaea;--border-strong:#d4d4d4;
  --text:#000;--text-dim:#666;--text-faint:#999;
  --accent:#fa6936;--accent-hover:#ec5a26;--accent-text:#1a0d05;
  --accent-ink:#c2410c;--accent-soft:#fff4ef;--accent-hi:#b45309;
  --brand-grad:linear-gradient(90deg,#fdc415 0%,#fd443d 52%,#b8187f 100%);
  --grid-line:rgba(0,0,0,.045);
  --nav-bg:rgba(255,255,255,.8);--nav-bg-solid:#fff;
  --shadow:none;--shadow-lift:0 2px 8px rgba(0,0,0,.06);
  --code-bg:#f5f5f5;
  --r-btn:4px;--r-card:6px;
}

/* ---------- 3. 基础排版 ---------- */
body{
  font-family:var(--font-sans);
  font-size:16px;
  line-height:1.75;
  color:var(--text);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
/* 字距保持 0：负字距是 Vercel 那套拉丁文排版的做法，中文照搬会把字挤在一起。
   （本条的来源见 _incoming/01-理念与框架.md §六：中文绝不用负字距） */
h1,h2,h3,h4{line-height:1.35;font-weight:700;letter-spacing:0}
h1{font-size:clamp(28px,4.6vw,46px)}
h2{font-size:clamp(22px,3vw,30px)}
h3{font-size:17px;font-weight:600}
p{color:var(--text-dim)}
strong,b{font-weight:600;color:var(--text)}

/* ---------- 4. 布局 ---------- */
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter)}
/* 导航是 64px 的 sticky 条，锚点跳转时给目标留出高度，否则标题会被压在导航底下 */
[id]{scroll-margin-top:84px}
.sec{padding:var(--sec-y) 0}
.sec--tight{padding:var(--sec-y-sm) 0}
.sec--sub{background:var(--bg-sub)}
.sec-head{max-width:680px;margin-bottom:44px}
.sec-head p{margin-top:12px;font-size:16px}

/* 极细网格线背景（纯 CSS，不依赖图片） */
.grid-bg{
  background-image:
    linear-gradient(var(--grid-line) 1px,transparent 1px),
    linear-gradient(90deg,var(--grid-line) 1px,transparent 1px);
  background-size:56px 56px;
  background-position:center top;
}

/* ---------- 5. 导航 ---------- */
.nav{
  position:sticky;top:0;z-index:50;
  background:var(--nav-bg-solid);          /* 降级：纯色 */
  border-bottom:1px solid var(--border);
}
/* 玻璃拟态：仅在支持 backdrop-filter 的内核上启用。
   微信/QQ 旧内核会糊掉或直接不生效，因此必须有上面的纯色降级 */
@supports ((backdrop-filter:blur(12px)) or (-webkit-backdrop-filter:blur(12px))){
  .nav{background:var(--nav-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
}
.nav__inner{
  display:flex;align-items:center;gap:28px;
  height:64px;
}
.brand{display:flex;align-items:center;gap:9px;font-weight:700;font-size:16px;white-space:nowrap}
/* 标识图：透明底，宽高比 1.15。定高不定宽，避免拉伸 */
.brand__mark{height:30px;width:auto;flex:0 0 auto;display:block}
/* 品牌英文名，与中文名同排做双语字标。
   压到 13px、降一档色、加一点字距，让它退成脚注位——两个都 16px 700 会互相抢，
   读起来像两个并列的品牌，而不是"同一个名字的两种写法"。
   收在 .brand 的 16px/700 之内，中文名照旧继承，只覆盖英文这一段。
   标记上，英文名和中文名写在同一个 span 里、中间留一个真空格 —— 拆成两个
   flex 子项的话中间没有文本节点，读屏和搜索引擎取到的名字会连成
   "ForgingCat AI小火喵"。
   手机上（≤680px）整个收起，见下面那个断点里的 .brand__latin{display:none}。 */
.brand__latin{font-size:13px;font-weight:600;color:var(--text-dim);letter-spacing:.04em}
.nav__links{display:flex;gap:26px;margin-left:auto}
/* :not(.btn) 不可省。导航里的 CTA 本身是个 .btn，有自己的字色与尺寸；
   不排除的话 .nav__links a 的 (0,1,1) 会压过 .btn--primary 的 (0,1,0)，
   把"橙底深字"改成灰字 —— 实测 #666 压 #fa6936 只有 1.95:1，几乎读不出来。
   这是 render-check.js（真浏览器渲染审计）抓到的，变量表看不出来。 */
.nav__links a:not(.btn){font-size:14.5px;color:var(--text-dim);transition:color var(--dur) var(--ease)}
.nav__links a:not(.btn):hover{color:var(--text)}
.nav__cta{margin-left:4px}

/* 移动端菜单按钮 */
.nav__toggle{
  display:none;margin-left:auto;background:none;border:1px solid var(--border);
  border-radius:var(--r-btn);padding:7px 11px;cursor:pointer;font-size:13px;
}

/* ---------- 6. Hero ---------- */
.hero{padding:clamp(64px,10vw,120px) 0 var(--sec-y)}
.hero__eyebrow{
  display:inline-block;font-size:13px;font-weight:600;letter-spacing:.08em;
  color:var(--text-dim);border:1px solid var(--border);
  border-radius:var(--r-pill);padding:5px 14px;margin-bottom:24px;
}
.hero h1{max-width:16em;margin-bottom:22px}
.hero__sub{font-size:clamp(15px,1.6vw,17.5px);max-width:44em;margin-bottom:34px}
.hero__sub b{color:var(--text)}
.hero__actions{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:26px}
.hero__trust{font-size:13.5px;color:var(--text-faint);display:flex;flex-wrap:wrap;gap:6px 18px}
/* 两句之间的分隔点。没有它，两句话在视觉上会连成一句长话 */
.hero__trust span+span::before{content:"·";margin-right:6px;color:var(--border-strong)}

/* 首屏两栏：左边文字，右边闭环图。
   窄屏单栏，图排在文字下面（DOM 顺序就是文字在前）。
   960px 这个断点和全站其他栅格一致，不另开一档。 */
.hero__grid{display:grid;gap:44px}
.hero__fig svg{display:block;width:100%;height:auto;max-width:400px;margin:0 auto}
@media (min-width:960px){
  .hero__grid{grid-template-columns:minmax(0,1fr) minmax(0,380px);gap:60px;align-items:center}
  .hero__fig svg{margin:0}
}

/* 闭环图的取色：**必须走 CSS 类名**。
   SVG 呈现属性（fill="…"）里写 var(--x) 不生效——
   自定义属性只能在 CSS 声明里解析，呈现属性不算。这个坑踩过一次。 */
.hero__fig text{font-family:inherit;letter-spacing:0}  /* 防止 <text> 拿到默认衬线体 */
.fig-box{fill:var(--panel);stroke:var(--border)}
.fig-line{stroke:var(--border-strong);fill:none}
.fig-head{fill:var(--border-strong)}
.fig-back{stroke:var(--accent-ink);fill:none}
.fig-back-head{fill:var(--accent-ink)}
.fig-cap{fill:var(--accent-ink)}          /* 「越跑越准」——整张图唯一强调的一句 */
.fig-num{fill:var(--accent-ink);font-family:var(--font-mono)}
.fig-t{fill:var(--text)}
.fig-d{fill:var(--text-dim)}

/* 闭环图的循环动效（全站第一条 @keyframes）。
   这张图讲的是"越跑越准"——一个一直转的闭环。静止时它只是张示意图，
   动起来才把"这是个循环"这件事说出来，所以这里的动效不是装饰，
   是在替一段文字干活。

   节奏：一条 6s 时间轴，三格按 0 / 2 / 4s 错峰亮起，回流环在 03 之后
   整条加粗一次，正好接上 01 重新亮起 —— 环闭合。**顺序本身就是语义**，
   所以三格共用同一条时间轴、只用 delay 错开；各写各的时长会越跑越乱。

   ⚠️ 三条硬约束，都不是审美偏好：

   1. **不碰任何 <text> 的 fill / opacity。** _build/render-check.js 在页面
      load 完只等 220ms 就开始量对比度，而这段动画有 6s。文字若在半透明
      或改色的中间态被量到，会报出并不存在的"不达标"；更糟的是某一帧正好
      `opacity:0` 时，会被 render-check 的 `if (parseFloat(cs.opacity) === 0) return;`
      整条跳过 —— 静默漏检。所以动的只有描边和箭头填充，都是形状不是文字。

   2. **整块包在 `no-preference` 里，而不是靠第 457 行那条全局兜底。**
      那条兜底只把 animation-duration 钳到 .01ms，碰上一个
      `iteration-count:infinite` 就等于每 10µs 重播一次：看着像静止，
      compositor 却一直在跑。包在 no-preference 里，不开动画的人连
      keyframes 都不会命中，元素保持上面 .fig-* 里的静止取值。

   3. **颜色只用 --accent-ink（暖色"字"档）。** 静止的 --border 是灰的，
      高亮走到这一格时变暖、走完回到灰。整图唯一的强调色仍是回流环和
      「越跑越准」，这个规矩没被破坏 —— 所以回流环那一下只动 stroke-width、
      不动颜色：黑皮肤里 --accent 与 --accent-ink 是同一个值，靠颜色分不出
      亮没亮，靠粗细两套皮肤才表现一致。 */
@media (prefers-reduced-motion:no-preference){

  /* 高亮"走到"某一格：亮约 1.3s，其余时间熄着 */
  @keyframes fig-pass{
    0%,100%{stroke:var(--border)}
    5%     {stroke:var(--accent-ink)}
    26%    {stroke:var(--accent-ink)}
    36%    {stroke:var(--border)}
  }

  /* 箭头是 fill 不是 stroke，得另写一条 */
  @keyframes fig-pass-fill{
    0%,100%{fill:var(--border-strong)}
    5%     {fill:var(--accent-ink)}
    26%    {fill:var(--accent-ink)}
    36%    {fill:var(--border-strong)}
  }

  /* 回流环：03 亮完之后整条加粗一次，收在 100% 之前 ——
     和 0% 的取值接上，循环处不会有一帧突跳 */
  @keyframes fig-return{
    0%,74%{stroke-width:1.5}
    88%   {stroke-width:3.5}
    98%   {stroke-width:3.5}
    100%  {stroke-width:1.5}
  }

  .fig-box,.fig-line{animation:fig-pass 6s linear infinite}
  .fig-head{animation:fig-pass-fill 6s linear infinite}
  .fig-back{animation:fig-return 6s linear infinite}

  /* 第 2 步晚 2s、第 3 步晚 4s；第 1 步就是 0s，不用写规则 */
  .fig-s2{animation-delay:2s}
  .fig-s3{animation-delay:4s}
}

/* ---------- 7. 按钮 ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;
  height:46px;padding:0 22px;border-radius:var(--r-btn);
  font-size:15px;font-weight:600;cursor:pointer;border:1px solid transparent;
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),color var(--dur) var(--ease);
  white-space:nowrap;
}
.btn--primary{background:var(--btn-primary-bg);color:var(--accent-text)}
.btn--primary:hover{background:var(--btn-primary-bg-h)}
.btn--ghost{background:transparent;border-color:var(--btn-ghost-border);color:var(--text)}
.btn--ghost:hover{border-color:var(--text);background:var(--panel-hover)}
.btn--sm{height:38px;padding:0 16px;font-size:14px}

/* ---------- 8. 卡片网格 ---------- */
.grid{display:grid;gap:16px}
.grid--2{grid-template-columns:repeat(2,1fr)}
.grid--3{grid-template-columns:repeat(3,1fr)}
.grid--4{grid-template-columns:repeat(4,1fr)}

.card{
  background:var(--panel);border:1px solid var(--border);
  border-radius:var(--r-card);padding:26px 24px;
  /* transform 是后加的（悬停抬升），必须并进这一条——不能再写一条 transition：
     后声明的会整条覆盖前一条，先把边框和阴影的动画悄悄干掉。 */
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.card:hover{border-color:var(--border-strong);box-shadow:var(--shadow-lift)}

/* 抬升只给真有悬停指针的设备。
   触屏上 :hover 会在点完之后"粘住"——粘住的边框颜色可以将就，粘住的一张浮起来的
   卡片不能将就。所以只给 transform 加这道门，原有的边框/阴影悬停不动（它们已经这样在线上跑了）。
   只动 translateY：body 上有 overflow-x:hidden，横向的位移/缩放会在视口边缘被切掉。 */
@media (hover:hover){
  .card:hover{transform:translateY(-3px)}
}

/* 卡内链接拿到键盘焦点时，整张卡也亮一下边框。
   刻意不放进上面那个 hover 媒体查询，也刻意不带位移——键盘用户要的是"我在哪"，
   不是动效；带平移反而会让焦点环跟着抖。 */
.card:focus-within{border-color:var(--border-strong)}

.card__num{
  font-family:var(--font-mono);font-size:12px;font-weight:600;
  color:var(--accent-ink);margin-bottom:12px;letter-spacing:.04em;
}
.card h3{margin-bottom:10px}

/* 上面那条只写了 h3，因为其余 8 页的卡片都挂在带 <h2> 的区块下面。
   404.html 是例外：它没有区块标题，卡片直接跟在 <h1> 后头，标题只能是 h2，
   否则 h1 → h3 跳级（check-site.py 的 F6 现在会拦）。

   ⚠️ 光换标签不够。全局 h2 是 clamp(22px,3vw,30px)/700，h3 是 17px/600 ——
   不压回来的话那三张卡的标题会当场变大，改动就"可见"了。所以这里把 h2 的
   字号和字重都拉成和 h3 一样。

   这两行看着像重复，其实是把一件事说清楚了：**卡片标题的字号由组件决定，
   不由标题级别决定**。级别只表达文档结构（h1 之后是第几层），字号是视觉决策。
   哪天卡片挂在更深的地方、标题变成 h4，同样要在这里补一条。 */
.card h2{margin-bottom:10px;font-size:17px;font-weight:600}
.card p{font-size:14.5px}

/* `#start` 左卡标题放大加暖色 —— 这一屏给的是"两条路"，但两条路不是等重的：
   "先自己看 / 免费自测"是零门槛那条，不用预约、不用留联系方式，四个问题自己
   就能走完；右边"直接聊"要占用你的时间。所以让左卡成为这一屏的视觉落点，
   右卡标题保持常规 17px，主次靠字号差拉出来 —— 不是靠再给卡加一层框。

   颜色用 --accent-ink 不用 --accent：后者白底只有 2.94:1，是登记为"只做面、
   不做字"的颜色（见上面 .card__ico 那段）；--accent-ink 白底 5.1:1、暗底 6.4:1，
   两套皮肤都过。

   选择器带上 .card h3 是为了压过 (0,1,1) 那一档 —— 和 §15 的 .card .kpi__l
   同一个理由，虽然这里 h3 那条只设了 margin-bottom、暂时不冲突，但哪天有人给
   .card h3 加字号就会静默失效。 */
.card h3.card__title-lg{font-size:22px;color:var(--accent-ink)}

/* 卡片图标：手绘线性 SVG，24×24 用户单位。
   描边属性全在这一个类上给，子元素 <path> 自动继承（stroke/fill/stroke-width/
   linecap/linejoin 都是继承属性），所以每个图标的标记只剩一行 <path> —— 十个图标
   合计约 1 KB。颜色走 currentColor：SVG 呈现属性里写 var(--x) 不生效（第 6 节踩过）。
   线宽 1.7 对齐 hero 闭环图那支笔（那里 1.5 ÷ 344 视框 × 380px ≈ 1.66 设备像素）。
   静止时用 --text-dim（冷色，结构），悬停才转 --accent-ink。
   不用 --accent：它在白底上只有 2.94:1，是被登记为"只做面、不做字"的颜色。
   图标是纯装饰、不承担表意，所以一律 aria-hidden，也不加 <title>。 */
.card__ico{
  display:block;width:24px;height:24px;margin-bottom:14px;
  color:var(--text-dim);
  fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
  transition:color var(--dur) var(--ease);
}
/* 图标和序号同一行的卡（#how）：否则标题前面会堆三行小字 */
.card__head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px}
.card__head .card__ico,.card__head .card__num{margin-bottom:0}

/* 内联箭头：动的是它，不是整行文字。
   必须单独包一个 span——CSS 选不中一行文字里的某一个字符。
   display:inline-block 是 transform 生效的前提，inline 盒子上 transform 无效。 */
.arw{display:inline-block;transition:transform var(--dur) var(--ease)}

@media (hover:hover){
  .card:hover .card__ico{color:var(--accent-ink)}
  .card:hover .arw{transform:translateX(3px)}
}
/* 通栏卡：跨满整行。
   用在"不属于本网格同一分组"的那一张上——比如 #what 区里，
   前四张是一条流程的四步，第 5 张是一条贯穿全程的底线。
   写死 1 / -1 而不是 nth-child，是因为它随列数变化自动成立：
   ≤960px 变 2 列、≤680px 变 1 列时，"占满该行"依然是对的。 */
.card--wide{grid-column:1 / -1}

/* ---------- 9. 差异点（三条） ----------
   ⚠️ index.html 的 #how / #why 已改用 .grid + .card（与 #what 同一族，见第 8 节）。
   这一节现在只服务三个内页：ai-product-image ×2、service-standard、service-custom。
   其中 ai-product-image 那处每条正文近百字，横排（200px 标签列 + 1fr 正文）比压成
   三列卡片好读得多——所以**不要**把内页也一起卡片化，那是一刀切。 */
.diff{display:grid;gap:0;border-top:1px solid var(--border)}
.diff__item{
  display:grid;grid-template-columns:200px 1fr;gap:32px;
  padding:30px 0;border-bottom:1px solid var(--border);
}
.diff__item h3{margin:0;font-size:17px}
.diff__item p{font-size:15px;margin:0}

/* ---------- 10. 步骤 ---------- */
.steps{counter-reset:s;display:grid;gap:0}
.steps li{
  counter-increment:s;position:relative;
  padding:24px 0 24px 62px;border-top:1px solid var(--border);
}
.steps li:last-child{border-bottom:1px solid var(--border)}
.steps li::before{
  content:counter(s,decimal-leading-zero);
  position:absolute;left:0;top:24px;
  font-family:var(--font-mono);font-size:13px;font-weight:700;
  color:var(--accent-ink);
  width:38px;height:38px;border:1px solid var(--border);
  border-radius:var(--r-pill);display:grid;place-items:center;
}
.steps h3{margin-bottom:6px}
.steps p{font-size:14.5px;margin:0}

/* ---------- 11. 适合谁 ----------
   ⚠️ index.html 的 #who 已改用 .grid + .card。
   这一节现在只服务三个内页的列表，以及它们页尾的「相关」链接组
   （那三组是 <ul class="who"> 装 3 行链接——正是**不能**卡片化的形态，
   撑成三张大卡就散了）。 */
.who li{
  padding:16px 0 16px 26px;position:relative;
  border-bottom:1px solid var(--border);font-size:15px;
}
.who li:last-child{border-bottom:0}
.who li::before{
  content:"";position:absolute;left:0;top:26px;
  width:8px;height:8px;border-radius:var(--r-pill);background:var(--accent-ink);
}
.who li b{color:var(--text)}
.who li span{color:var(--text-dim)}

/* ---------- 12. 案例占位 ---------- */
.placeholder{
  border:1px dashed var(--border-strong);border-radius:var(--r-card);
  padding:34px 28px;background:var(--panel);
}
.placeholder h3{margin-bottom:8px}
.placeholder p{font-size:14.5px;margin:0}

/* ---------- 13. CTA / 企业微信 ---------- */
.cta{
  background:var(--bg-sub);border:1px solid var(--border);
  border-radius:var(--r-card);padding:44px;
  display:grid;grid-template-columns:1fr auto;gap:44px;align-items:center;
}
.cta h2{margin-bottom:12px}
.cta p{max-width:38em}
.cta__actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:22px}
.qr{text-align:center;flex:0 0 auto}
.qr__box{
  width:168px;height:168px;border:1px solid var(--border);border-radius:var(--r-card);
  background:var(--panel);display:grid;place-items:center;overflow:hidden;
  color:var(--text-faint);font-size:12px;line-height:1.5;padding:4px;
}
/* 二维码图片自己带了 4 个模块的静区（见 qrcode-wecom.png 的处理说明），
   所以这里内边距只留 4px —— 再大就是在静区外面又套一圈多余空白。
   168 = 160 图片 + 4 内边距 ×2。改图片尺寸时这里要跟着改。

   **两套皮肤里二维码都保持白底黑块，不要跟着皮肤反色。**
   暗色皮肤下它会是一块白方块，看着突兀 —— 但二维码只能深色块压浅色底，
   反过来的浅块压深底，多数扫码器直接读不出来。突兀是必须的。 */
.qr__box img{display:block;width:100%;height:auto}

/* 二维码外面包了一层 <a>：桌面点图也能跳到添加页。
   目标人群（手机访客）不用点它 —— 他们扫不了自己屏幕上的码，
   所以窄屏下面另有一个按钮，见 .qr__btn。 */
.qr__link{display:inline-block;border-radius:var(--r-card)}
.qr__link:hover .qr__box{border-color:var(--border-strong)}

/* 「一键添加企业微信」按钮。
   出现条件只看 **hover:none**（没有能悬停的指针设备）。

   判据是"这台设备有没有第二块屏可以扫"，那是**设备属性**，不是视口宽度：
     · 桌面／触控笔记本：有鼠标指针 → 拿手机扫屏幕上的码 → 不需要按钮
     · 手机／平板：没有第二块屏 → 扫不了自己 → 必须给可点的链接
   平板横屏 1024px 照样扫不了自己，但它比 680px 宽——所以按宽度判会漏掉它。

   早先我还挂了一条 `≤680px`，理由是"桌面缩窄窗口时方便截图验收"。
   那是**拿验收的方便当需求**，而且是错的：桌面窗口再窄，用户仍然有手机可扫。
   已删。 */
.qr__btn{display:none;width:100%;margin-top:14px}
@media (hover:none){
  .qr__btn{display:inline-flex}
}
.qr__cap{font-size:12.5px;color:var(--text-dim);margin-top:10px}

/* ---------- 14. 页脚 ---------- */
.footer{
  border-top:1px solid var(--border);padding:52px 0 40px;
  background:var(--bg);
}
.footer__top{display:grid;grid-template-columns:1.4fr 1fr;gap:40px;margin-bottom:34px}
.footer__brandline{font-size:16px;font-weight:700;margin-bottom:12px}
.footer__desc{font-size:13.5px;max-width:34em}
.footer__slogan{
  font-size:13.5px;color:var(--text-faint);margin-top:16px;
  font-style:normal;
}
.footer__links{display:flex;flex-wrap:wrap;gap:10px 22px;align-items:flex-start}
.footer__links a{font-size:13.5px;color:var(--text-dim)}
.footer__links a:hover{color:var(--text)}
.footer__bottom{
  border-top:1px solid var(--border);padding-top:22px;
  font-size:12.5px;color:var(--text-faint);
  display:flex;flex-wrap:wrap;gap:6px 16px;align-items:center;
}
.footer__bottom a{color:var(--text-faint)}
.footer__bottom a:hover{color:var(--text-dim)}

/* ---------- 15. 数据与强调 ----------
   暖色预算就花在这里：数字是"引擎在工作"的证据，所以给暖色高光。
   全站暖色像素面积目标 < 5%（可用 _build/check-warm.py 量）

   这一节只管**数字的排版**，不再管布局。三个数字的容器和 #how / #why 用的是
   同一个组合：`.grid grid--3` + 每项 `.card`。数字这一段曾经是页面上唯一
   不带框的内容块（三个数字裸排在底色上），翻到这里就"散"了 —— 页面上其它
   每一块都有卡面，就它没有。改走同一个卡片组件后就齐了，这一节也就不用
   再写一遍栅格。 */

.kpi__n{
  font-size:clamp(30px,4vw,42px);font-weight:700;line-height:1.1;
  color:var(--accent-hi);
  /* 计数动画时数字会从 37 滚上去，而 "1" 和 "8" 在默认的西文字体里不等宽 ——
     不锁等宽的话整行会随数字变化左右抖。tabular-nums 让每个数字占同样的宽。 */
  font-variant-numeric:tabular-nums;
}
.kpi__n small{font-size:15px;font-weight:600;color:var(--text-dim);margin-left:6px}
/* 这行是"口径"，不是说明文字。
   §5.1 的规矩是每个数字都要能被追问"这个数怎么来的"，答得上来才放 ——
   所以 __l 里写的必须是那个答案本身，别改成朗读性的描述。

   选择器写成 `.card .kpi__l` 而不是光一个 `.kpi__l`：卡面里那条
   `.card p{font-size:14.5px}` 是 (0,1,1)，比单类名 (0,1,0) 高一档，
   不加这一层的话口径会被拉成正文大小，"数字是主角、口径是脚注"
   这层关系就没了。 */
.card .kpi__l{font-size:13.5px;color:var(--text-dim);margin-top:8px}

.pill{
  display:inline-block;font-size:12.5px;font-weight:600;
  padding:4px 11px;border-radius:var(--r-pill);
  background:var(--accent-soft);color:var(--accent-ink);
}

/* 渐变文字 —— 降级必须先落地：background-clip:text 不被支持时，
   文字会变成透明色直接消失。所以默认给实色，只在支持时才启用渐变。 */
.grad{color:var(--accent-ink)}
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .grad{
    background:var(--brand-grad);
    -webkit-background-clip:text;background-clip:text;
    color:transparent;-webkit-text-fill-color:transparent;
  }
}

/* ---------- 16. 工具类 ---------- */
.dim{color:var(--text-dim)}
.center{text-align:center}
.mt-l{margin-top:44px}

/* 跳到主要内容（无障碍） */
.skip{
  position:absolute;left:-9999px;top:0;z-index:100;
  background:var(--accent);color:var(--accent-text);
  padding:10px 18px;border-radius:0 0 var(--r-btn) 0;
}
.skip:focus{left:0}

/* 键盘焦点可见（无障碍必需） */
:focus-visible{
  outline:2px solid var(--accent-ink);
  outline-offset:3px;
  border-radius:3px;
}

/* 尊重系统的"减少动效"设置
   ⚠️ 这条**只钳制 duration，不钳制 delay**。
   所以错峰（0/60/120ms）绝不能做成 CSS 的 transition-delay / animation-delay——
   开了"减少动效"的用户会看到：先隐形 120ms，再"啪"一下出现。那正好是这条规则
   想避免的结果。错峰放在 main.js 里，整段跳过。 */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{transition-duration:.01ms!important;animation-duration:.01ms!important}
}

/* ---------- 17. 长文页（法务 / 条款类） ----------
   法务页的阅读方式和首页相反：首页是扫，法务页是逐条读。
   所以这里只做一件事——把行宽压到 44em 以内，其余全部让位给正文。 */

.page-head{padding:56px 0 30px;border-bottom:1px solid var(--border)}
.page-head h1{font-size:clamp(26px,3.4vw,36px);margin-bottom:14px}
.page-head .meta{font-size:13.5px;color:var(--text-faint)}
/* 页头导语：场景页/服务页用。比正文大一档、行宽压住，读完就知道这页在说什么 */
.page-head .lead{font-size:17px;line-height:1.75;max-width:40em;margin-top:14px}

.doc{max-width:44em;padding:44px 0 72px}
@media (min-width:1000px){.doc{padding-left:calc(var(--gutter) + 8px)}}

.doc h2{font-size:19px;margin:40px 0 12px;padding-top:4px}
.doc h2:first-child{margin-top:0}
.doc h3{font-size:16px;margin:28px 0 10px}
.doc p{margin:0 0 14px}
.doc b,.doc strong{color:var(--text)}

/* reset 里 ul,ol{list-style:none} 是给导航/卡片用的，
   正文列表要吃回来，否则法务条款会变成一串没有标记的段落 */
.doc ul,.doc ol{margin:0 0 16px;padding-left:24px}
.doc li{margin-bottom:9px}
.doc ul li{list-style:disc}
.doc ol li{list-style:decimal}
.doc li::marker{color:var(--text-faint)}

.doc table{width:100%;border-collapse:collapse;margin:0 0 18px;font-size:14.5px}
.doc th,.doc td{border:1px solid var(--border);padding:10px 13px;text-align:left;vertical-align:top}
.doc th{background:var(--bg-sub);font-weight:600;color:var(--text)}
.doc td{color:var(--text-dim)}

.doc code{
  font-family:var(--font-mono);font-size:.9em;
  background:var(--code-bg);padding:1px 5px;border-radius:3px;color:var(--text);
}
.doc a{color:var(--accent-ink);text-decoration:underline;text-underline-offset:3px}
.doc a:hover{text-decoration-thickness:2px}
.doc u{text-underline-offset:3px}

/* 一句话摘要 —— 整页都是条款，先给人一个 30 秒能读完的出口。
   左侧色条用 --accent-ink 而不是 --accent：这里是文字旁边的线，
   要和文字一个量级的可读性，不是装饰。 */
.doc .summary{
  border-left:3px solid var(--accent-ink);background:var(--bg-sub);
  padding:18px 22px;margin:0 0 30px;border-radius:0 var(--r-card) var(--r-card) 0;
  font-size:14.5px;line-height:1.8;
}
.doc .summary .k{display:block;font-weight:600;color:var(--text);margin-bottom:6px}
.doc .summary p:last-child{margin-bottom:0}

/* 精简导航：法务页只有"返回首页 + CTA"两项，不需要折叠菜单。
   必须显式覆盖 680px 下 .nav__links{display:none} —— 否则手机上
   链接被藏了却又没有汉堡按钮，等于点不到。 */
.nav--simple .nav__links{display:flex;gap:20px;margin-left:auto;align-items:center}

/* ---------- 18. 正文内链 ----------
   全站 a{color:inherit;text-decoration:none} 是给按钮和导航用的。
   但场景页/服务页的正文里也有链接（相关页、卡内跳转），
   不标出来的话读者根本不知道那能点。这里只给正文内链加上可点的样子，
   按钮和导航不受影响。

   :not(.btn) 不可省，理由同 .nav__links a（见第 7 节上面的注释）：
   卡片里也可能放按钮（首页"先自己看 / 直接聊"那两张卡就有）。不加的话
   .card a 的 (0,1,1) 会压过 .btn 系列的 (0,1,0)，把橙底深字改成橙字加下划线 ——
   浅色皮肤实测 1.76:1、暗色 1:1，等于读不出来。同样是 render-check.js 抓到的。 */
.link,
.who li a,
.card a:not(.btn){
  color:var(--accent-ink);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:3px;
}
.link:hover,
.who li a:hover,
.card a:not(.btn):hover{text-decoration-thickness:2px}
/* .who li b{color:var(--text)} 会把链接里的加粗压回正文色，这里让它跟着链接走 */
.who li a b{color:inherit}
/* 卡片/差异点里的"看看这个 →"，单独占一行，不要挤在正文末尾 */
.card .link,
.diff__item .link{display:inline-block;margin-top:12px;font-size:14px;font-weight:600}

/* ---------- 19. 响应式 ----------
   注意：自测（diagnose.html）的样式在文件**末尾的 §20**，它自带媒体查询、
   不在这节里。见该节开头的说明。 */
@media (max-width:960px){
  :root{--sec-y:72px;--sec-y-sm:52px}
  /* 导航在 681–960px 这一段最挤：品牌右边四条链接 + CTA 都还在，又还没到 680px
     的折叠点。双语字标加进品牌后这一段余量被吃光（实测 681px 余 0px，纯靠像素级
     刚好撑着，换一套字体回退就会溢出），所以在这一段把两处间距收一收还回去。
     960px 以上空间充足，不必收。 */
  .nav__inner{gap:18px}
  .nav__links{gap:18px}
  .grid--4{grid-template-columns:repeat(2,1fr)}
  .grid--3{grid-template-columns:repeat(2,1fr)}
  .diff__item{grid-template-columns:1fr;gap:8px}
  .cta{grid-template-columns:1fr;gap:30px;padding:34px 26px}
  .qr{text-align:left}
  .footer__top{grid-template-columns:1fr;gap:28px}
}
@media (max-width:680px){
  :root{--gutter:18px;--sec-y:60px}
  .nav__links{
    display:none;position:absolute;top:64px;left:0;right:0;
    flex-direction:column;gap:0;padding:8px 0;
    background:var(--nav-bg-solid);border-bottom:1px solid var(--border);
  }
  .nav__links.is-open{display:flex}
  .nav__links a:not(.btn){padding:12px var(--gutter)}
  .nav__cta{margin:8px var(--gutter) 4px}
  .nav__toggle{display:inline-block}
  /* 手机上收起品牌英文名，只留中文名。
     首页在 ≤680px 会把四条锚点链接折进菜单、品牌因此拿到整行，放得下；
     但另外 7 页是 nav--simple，窄屏也保持「返回首页 + CTA」内联，
     实测 320px 下品牌到右侧元素只剩约 18px，而英文名要吃约 107px。
     与其按页分别处理，不如统一：手机一律只显示中文名。 */
  .brand__latin{display:none}
  .grid--2,.grid--3,.grid--4{grid-template-columns:1fr}
  .kpi{grid-template-columns:1fr;gap:0}
  .kpi > div{padding:16px 0;border-bottom:1px solid var(--border)}
  .kpi > div:last-child{border-bottom:0}
  .hero__actions .btn{flex:1 1 100%}
  /* 窄屏这两句必然分行，分隔点会掉到第二行行首看着像错字，去掉 */
  .hero__trust span+span::before{content:none}
  .steps li{padding-left:52px}
  .footer__bottom{flex-direction:column;align-items:flex-start}

  /* 法务页的精简导航：不能跟着折叠，因为这里没有汉堡按钮 */
  .nav--simple .nav__links{
    display:flex;position:static;flex-direction:row;gap:14px;
    padding:0;background:none;border:0;
  }
  .nav--simple .nav__links a:not(.btn){padding:0;font-size:14px}
  .nav--simple .nav__cta{margin:0}

  .page-head{padding:36px 0 22px}
  .doc{padding:32px 0 56px}
  .doc .summary{padding:15px 17px}
}

/* ---------- 20. 自测（diagnose.html 专用） ----------
   放在文件末尾、而不是插在 §19 前面：插进去就得把 §19 及之后的编号全部顺延，
   纯属 churn；追加在尾部不动任何现有规则，节内的媒体查询也天然排在 §19 之后
   （同优先级下后者胜）。

   全部走现有 token，**不新增任何颜色** —— 所以黑白两套皮肤自动成立，
   不需要各写一遍（这是本文件一贯的做法：颜色只来自 token）。

   （§21「颜色模式按钮」按同样的理由追加在本节之后。）

   ⚠️ 这个自测**不调任何 AI、不发任何请求**，是纯前端规则逻辑。这不是"省事"：
   一旦做成「访客提交 → 我们服务器跑 AI → 返回结果」，就构成面向公众提供
   生成式 AI 服务，要在属地网信办做登记。所以这一节里**不允许出现任何外部资源
   引用**（字体、图标、背景图都不行）—— 加了就等于把那条约束破了。 */

/* `hidden` 属性靠 UA 样式表的 display:none 生效，而下面几个元素我们自己设了
   display，会把它盖掉，所以在作用域里显式兜一条。
   JS 没跑起来时靠的就是它：题目清单显示、答题区不显示。 */
.quiz [hidden]{display:none}

.quiz{
  max-width:880px;margin:0 auto;
  background:var(--panel);border:1px solid var(--border);
  border-radius:var(--r-card);padding:38px 36px;
}

/* --- 无 JS 时的题目清单（JS 跑起来后整块隐藏）。
       它同时是"题目唯一的出处"，脚本读的就是这段结构，
       所以这里的排版不是草稿，是真正的降级正文。 --- */
.quiz__qs h2{font-size:20px;margin-bottom:24px}
.quiz__item{margin-bottom:24px}
.quiz__item:last-child{margin-bottom:0}
.quiz__item h3{font-size:16px;margin-bottom:10px}
.quiz__item ul{list-style:none;display:flex;flex-wrap:wrap;gap:10px}
.quiz__item li{
  border:1px solid var(--border-strong);border-radius:var(--r-btn);
  padding:9px 14px;font-size:14.5px;color:var(--text-dim);
}

/* --- 答题区 --- */
/* 进度条的文本等价物：光一根 3px 的条说不出"第几题 / 共几题"，加一行字。 */
.quiz__count{font-family:var(--font-mono);font-size:12px;font-weight:600;
  color:var(--text-dim);letter-spacing:.04em;margin-bottom:8px}
.quiz__bar{height:3px;background:var(--border);border-radius:2px;overflow:hidden;margin-bottom:30px}
/* 填充走 --accent-ink 而不是 --accent：3px 的细线本来就是"字"不是"面"，
   而 --accent 这种中亮度橙压在 --border(#eaeaea) 上只有 2.45:1（浅色皮肤下
   换更深的轨道反而更贴，1.98）。--accent-ink 是 4.30:1，暗色 5.35:1。
   同样是 render-check.js 的渲染审计暴露的：变量表上看不出这两档会不一样。 */
.quiz__bar i{display:block;height:100%;width:0;background:var(--accent-ink);
  transition:width var(--dur) var(--ease)}

.quiz__q{font-size:22px;margin:0 0 20px}
/* 题干上的焦点环要去掉：它是脚本移过去的（见 main.js 第 7 段），不是用户 Tab
   过来的，画一圈反而像"这里可以点"。键盘用户 Tab 到的是下面的选项按钮。 */
.quiz__q:focus{outline:none}

.quiz__opts{display:flex;flex-wrap:wrap;gap:12px}
/* 选项按钮复用 .btn .btn--ghost，但必须覆盖两条：
   · .btn 写死了 white-space:nowrap —— 像「已经跑成固定流程，换个人做结果也一样」
     这种长选项在窄屏会被撑出容器
   · .btn 写死了 height:46px —— 一旦换行，文字会从按钮里溢出来
   所以高度改 auto + min-height，并放开换行。 */
.quiz__opt{
  text-align:left;white-space:normal;height:auto;min-height:46px;padding:11px 18px;
}

/* --- 结果 --- */
.quiz__eyebrow{
  font-family:var(--font-mono);font-size:12px;font-weight:600;
  color:var(--accent-ink);letter-spacing:.04em;margin-bottom:12px;
}
.quiz__result h2{font-size:clamp(22px,3vw,28px);margin-bottom:12px}
.quiz__why{font-size:15px;color:var(--text-dim)}
.quiz__why b{color:var(--text)}

.quiz__recall{margin-top:22px;padding-top:18px;border-top:1px solid var(--border)}
.quiz__recall>p{font-size:13.5px;color:var(--text-faint);margin-bottom:9px}
.quiz__recall ul{list-style:none;display:flex;flex-wrap:wrap;gap:8px 22px}
.quiz__recall li{font-size:14px;color:var(--text-dim)}
.quiz__recall li b{color:var(--text);font-weight:600}

/* 「下一步」「服务线」两块用左侧一道暖色细线标记，**不做成卡面** ——
   这块面板本身就是一层卡面，里面再套卡面就成了盒子套盒子。
   2px 的线对暖色预算的贡献可以忽略。 */
.quiz__box{border-left:2px solid var(--accent-ink);padding:2px 0 2px 16px;margin-top:22px}
.quiz__box h3{font-size:16px;margin-bottom:6px}
.quiz__box p{font-size:14.5px;color:var(--text-dim)}
.quiz__box .link{font-size:14.5px}

.quiz__actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:26px}

.quiz__note{max-width:880px;margin:20px auto 0;font-size:13.5px;color:var(--text-dim)}
.quiz__note b{color:var(--text-dim)}

@media (max-width:680px){
  .quiz{padding:26px 20px}
  .quiz__q{font-size:19px}
  .quiz__item li{width:100%}
  /* 窄屏选项整行 —— 半行半行的按钮在手机上按不准 */
  .quiz__opt{width:100%;justify-content:flex-start}
}

/* ---------- 21. 颜色模式按钮（全站） ----------
   三态循环：跟随系统 → 深色 → 浅色 → 跟随系统。
   文案由 main.js 第 8 段写入（按钮初始写"跟随系统"，defer 脚本一跑就改成真实态），
   这里只管长相。皮肤切换本身在 theme-init.js 里，本节不含任何换肤逻辑。

   背景用 --panel 而不是 --accent：暖色像素是被盯着的预算（check-warm.py < 5%），
   一个常驻按钮要是吃掉几个百分点就没法解释了。描边用 --border-strong，
   悬停才把描边换成 --accent —— 1px 的一圈，暖色占比可忽略。

   无 JS 时 display:none：它点了不会有任何反应，显示出来只会骗人。
   .js 类由 theme-init.js 在首绘前挂到 <html> 上。
   prefers-reduced-motion 不用在这里另写 —— 本文件 §16 那条
   *{transition-duration:.01ms!important} 是通配的，自动覆盖。 */
.color-mode{
  display:none;
  position:fixed;
  right:16px;
  bottom:calc(16px + env(safe-area-inset-bottom, 0px));
  z-index:60;                    /* 高于 .nav(50)，低于 .skip(100) */
  align-items:center;
  padding:8px 13px;
  border:1px solid var(--border-strong);
  border-radius:999px;
  background:var(--panel);
  color:var(--text-dim);
  font:inherit;
  font-size:12.5px;
  line-height:1;
  white-space:nowrap;
  cursor:pointer;
  box-shadow:var(--shadow);
  transition:color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.js .color-mode{display:inline-flex}
.color-mode:hover{color:var(--text);border-color:var(--accent)}

/* 这里原来有一条 `.color-mode:focus-visible{outline:2px solid var(--accent);
   outline-offset:2px}` —— 2026-10-10 删掉，让它回到 §16 那条全站统一的 :focus-visible。

   删的理由是它违反了本文件自己的规矩：--accent 是"只做面、不做字"的颜色（见 §8 里
   .card__ico 与 .card h3.card__title-lg 那两段注释，以及 check-site.py 的 H_PAIRS 上方
   那段）。它压白底只有 2.94:1，不够。而**焦点环是 2px 的细线，属于"字"、不属于"面"**
   —— 全站唯一一处拿"面"色去画细线的，就是这一行。改走 --accent-ink 之后：
   浅色皮肤 5.18:1、深色 6.77:1，两套都过 WCAG 1.4.11 要求的 3:1。

   为什么是整条删掉、而不是只把颜色换成 --accent-ink：全站焦点样式只该有一份。
   留一条"只为改个颜色"的覆盖，下次谁动了 §16 那条它也不会跟着动，等于埋第二份。
   删掉之后 .color-mode 自动继承 §16 的 `outline:2px solid var(--accent-ink);
   outline-offset:3px` —— 胶囊形状不受影响，因为 border-radius:999px 写在下面
   .color-mode 主规则里，同为 (0,1,0) 特异性、源文件顺序更靠后，仍是它赢。

   check-site.py 的 H2 现在盯着这条：把 --accent 写回 outline 就报 BLOCK。
   （上面 :hover 那行的 border-color 用的是 --accent，有意留着：它是悬停时的装饰描边，
     且悬停同时把文字转成 --text，状态不靠这条线识别，不构成"用面色画字"。） */

/* 触屏窄屏：给右下角的胶囊让位。
   实测（375×667、hasTouch=true、扫描全页每个滚动位置取最大交叠）：
   「一键添加企业微信」那条整行按钮（.qr__btn，只在 hover:none 出现）在
   scrollY≈7200 处被胶囊压住右边 49×30 px，占它面积的 13.6% —— 那一段会变成
   死区，点下去切换的是皮肤而不是加微信。这是手机上最重要的一条转化按钮。

   ⚠️ 让位必须靠**收窄宽度**，不能靠 padding-right：padding 仍在按钮的可点区域内，
   照样抢点击，只是文字看着挪开了而已（第一版就是这么写错的）。
   64px > 实测需要的 49px，留了余量。 */
@media (hover:none) and (max-width:680px){
  .qr__btn{width:calc(100% - 64px)}
}

/* ---------- 22. Cookie 同意条（全站） ----------
   为什么是"前置同意"，而不是"提示一下、告诉你上哪儿关"：本站**唯一**的外部请求
   就是百度统计（main.js 第 4 段），它会写 Cookie、记录 IP 与设备类型。按《个人信息
   保护法》第十三条，这类处理要以**同意**为合法性基础，而不是事后给一个退出方式。
   所以统计脚本在访客点过「允许统计」之前**根本不加载**——这条同意条是那个开关本身，
   不是一张告示。**改样式可以，别把它改成"关掉即视为同意"。**

   默认带 hidden（写在 HTML 里），由 main.js 摘掉。无 JS 时它不出现，而统计也不会加载
   ——两边是同一个判断，不会出现"条子没显示、统计照跑"。`hidden` 属性本身靠 UA 样式表
   的 display:none 生效，但 .cookie 下面设了 display，所以要像 §20 的 .quiz[hidden]
   那样再声明一次，否则 hidden 会失效（那个坑踩过）。

   位置：左下角悬浮。桌面靠 left/right 分开不会撞右下角的 .color-mode 胶囊，但
   **320px 下会撞**，所以宽度算式里预留了那道胶囊的位置；窄屏干脆整体抬到胶囊上方
   整行铺开（见本节末尾），免得挤成一根 180px 宽的细柱。 */
.cookie{
  position:fixed;
  left:16px;
  bottom:calc(16px + env(safe-area-inset-bottom, 0px));
  z-index:55;                    /* 高于 .nav(50)，低于 .color-mode(60) */
  display:block;
  width:min(420px, calc(100vw - 134px));
  padding:16px 18px;
  border:1px solid var(--border-strong);
  border-radius:14px;
  background:var(--panel);
  box-shadow:var(--shadow), var(--shadow-lift);
  color:var(--text);
  font-size:13.5px;
  line-height:1.62;
}
.cookie[hidden]{display:none}
.cookie__t{margin:0 0 6px;font-weight:600;font-size:14px}
.cookie__d{margin:0;color:var(--text-dim)}
.cookie__d a{color:var(--accent-ink)}   /* 内链同 §18：文字一律走 *-ink，--accent 只做面 */
.cookie__a{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px}

/* 页脚里那个「Cookie 设置」是 <button>（它不跳页，只把同意条叫回来重选），
   而 §14 的 .footer__links a 只管 <a>。这里补按钮那一份，样子和链接对齐。
   为什么值得单开一个入口：《个保法》第十五条要求撤回同意**便捷**，
   让人自己去浏览器里清存储不算便捷。 */
.footer__links button{
  background:none;
  border:0;
  padding:0;
  font:inherit;
  font-size:13.5px;
  color:var(--text-dim);
  cursor:pointer;
}
.footer__links button:hover{color:var(--text)}

/* 窄屏：抬到右下角那颗胶囊（高约 32px）上方，整行铺开。 */
@media (max-width:560px){
  .cookie{
    left:12px;
    right:12px;
    width:auto;
    bottom:calc(60px + env(safe-area-inset-bottom, 0px));
  }
}

/* ---------- 23. 发邮件：地址可见 + 一键复制（全站） ----------
   为什么地址必须露出来：`mailto:` 是交给系统默认邮件程序的，**没装客户端的机器
   点了什么都不会发生**（不报错、不提示）。2026-10-20 实测首页「发邮件」按钮
   点击无反应。所以地址自己写出来，并且点一下就能复制。
   flex:0 0 100% 让它独占一行（父级 .cta__actions 是 flex）。
   ⚠️ 这个 flex 值别改成内联 style —— B1 规则会扫内联样式里的 "100%" 并报 BLOCK。 */
.cta__mail{
  flex:0 0 100%;
  margin-top:-4px;
  font-size:12.5px;
  color:var(--text-dim);   /* 不能用 --text-faint：#999 对白底只有 2.85:1，render-check 会报 */
  -webkit-user-select:all;user-select:all;
  word-break:break-all;
}
