/* ============================================================================
   BackspaceGEO 官网设计系统（Stripe 风格，2026-09-30 全站重设计）

   设计依据：docs/design/stripe-DESIGN.md（Stripe 设计语言分析）
   参考站点：https://stripe.com/zh-us

   ## 这套系统是什么
   - **浅色画布为默认**（canvas #ffffff / canvas-soft #f6f9fc），营销 hero 用
     「渐变网格」（cream → 雪酪橙 → 薰衣草 → 靛蓝 → ruby 粉）占据页面上部三分之一；
   - **靛蓝 #533afd 是唯一的填充主色**：每个版块只允许一个填充胶囊按钮，其余走描边；
   - **细字重 + 负字距**是排版签名：display 档 300 字重、字距 -0.02em 左右；
   - **数字一律等宽数字（tabular-nums）**——金融级数据感的来源，不靠字体花活；
   - **深海军蓝 #1c1e54** 只用于「产品界面拼贴」与「精选卡」等反白场景。

   ## 使用约定（改官网前先读）
   1. **色值只从 --st-* 取**，页面里不得再写裸色值（除渐变网格的色阶本身）；
   2. 组件类统一 `st-` 前缀；旧页面遗留的 `pub-` 类名与 `--pub-*` 变量在
      本文件末尾有兼容映射（2026-09-30 重设计时保留，避免一次性改 20 个视图）；
   3. 全角标点与插值：Blade 里 `"$var，"` 会解析成非法变量名，一律用拼接（见 AGENTS.md §9.8）；
   4. 字体 Inter 自托管（public/assets/fonts/inter/），**不引 Google Fonts**
      （国内访问不通，会静默回退到系统字体、字重与字距全部失效）。
   ========================================================================= */

/* ---------------------------------------------------------------------------
   1. 字体：Inter（拉丁/数字）+ 系统中文族
   Sohne 为 Stripe 专有字体，其设计文档指定的替代方案是 Inter 300 字重 + 负字距。

   ⚠️ **自托管，不引 Google Fonts**：国内网络访问 fonts.googleapis.com 不通，
   走 CDN 会静默回退到系统字体 —— 300 字重与负字距**全部失效**，页面看着"还是老样子"
   且不报任何错（本项目已多次踩到「境外资源静默失败」）。
   文件来源：Google Fonts 官方 CSS2 接口（v20），仅取 latin 与 latin-ext 两个子集。
   ⚠️ 它是**可变字体**（weight 轴 100–900）：5 个字重下载下来 md5 完全相同，
   所以这里只放 2 个文件、用 `font-weight: 100 900` 声明一次，而不是按字重放 10 份
   （那样体积 668KB，实际只需 133KB）。
   中文由 --st-font 的回退族（PingFang SC / 微软雅黑等）承担，Inter 只管拉丁与数字。
   --------------------------------------------------------------------------- */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('/assets/fonts/inter/Inter-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
        U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('/assets/fonts/inter/Inter-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
        U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------------------------------------------------------------------------
   2. 设计 Token
   🔴 2026-10-10 暗色重设计：本层由「浅色画布（Stripe）」整体翻转为**暗色画布**，
   依据设计师交付的新官网首页 demo（gemini-code-1791563202031.html）。

   ## 翻转策略（改这一层前必读）
   - **只改本层的值，不逐步改视图**：全站 30+ 页面的所有 `st-*` 组件都消费这些变量，
     改这里 = 一次性落到每一页。逐个页面改类名必然漏（且漏的地方不报错、只是看不清）。
   - **语义不变、明暗镜像**：`--st-ink` 仍是「主体文字色」、`--st-canvas` 仍是「页面底」，
     只是取值从深色变浅色。所以「文字用 ink、底用 canvas」的组合天然继续成立。
   - **品牌强调色更换**：由靛蓝 #533afd 改为 demo 的**青绿→天蓝渐变**
     （#69F7D3 → #45BBFB）。渐变由 --st-grad-start/--st-grad-end 提供，
     单色场景取 --st-primary（渐变的天蓝端）。
   - ⚠️ **对比度**：青蓝渐变很亮，压在它上面的文字必须用 --st-on-gradient（深墨绿 #052e16），
     用白色会只有 ~2.4:1（demo 的按钮正是深色文字，这是有意为之）。
   --------------------------------------------------------------------------- */
:root {
    /* 品牌 & 强调（青绿 → 天蓝渐变体系） */
    --st-grad-start: #69f7d3;
    --st-grad-end: #45bbfb;
    --st-grad: linear-gradient(90deg, var(--st-grad-start), var(--st-grad-end));
    --st-primary: #45bbfb;
    /* hover/active 在暗色体系下**变亮**（浅色体系是变深）——
       亮色底上的按钮 hover 压深会显得"脏"，提亮才像发光。 */
    --st-primary-deep: #69f7d3;
    --st-primary-press: #8cfad9;
    --st-primary-soft: #7fd3ff;
    --st-primary-subdued: #2c6d92;
    /* 渐变面上的文字色（demo 的按钮字色） */
    --st-on-gradient: #052e16;
    /* demo 的高亮菜单色（导航「免费体验」用） */
    --st-highlight: #fbe041;

    /* 深墨蓝（深色版面 / 页脚深色变体）；暗色体系下它比页面底**更深**，用于收束段落 */
    --st-dark-900: #05080f;
    --st-dark-800: #080d18;

    /* 文字（Ink）——暗色体系：数值越大越亮 */
    --st-ink: #ffffff;
    --st-ink-2: #cbd5e1;
    /* demo 的 muted 色值 */
    --st-ink-mute: #94a3b8;
    /* 🔴 2026-10-11 由 #7b8798 → #8793a5（对比度修正，配合本文件 §2 的表面层级提亮）。
       背景：2026-10-12 把卡片底从 1.120 提到 1.244 后，这个"最暗的一档次级文字"
       在**新卡底上掉到 4.26:1**（AA 要求 4.5:1）—— 属那次改动的连带回归，本次补上。
       新值实测：cream 底 4.62:1 / elev 底 4.99:1 / 页面底 更高，全档位达 AA。 */
    --st-ink-mute-2: #8793a5;
    /* ⚠️ `--st-on-primary` 的语义是「**深色面板**上的文字」= 白。
       现有 20+ 处（st-card--dark / st-section--ink / st-mockup--dark / 页脚深色变体 /
       pub-dark 兼容层）都按这个语义写的，翻转设计时**必须保持白色**，
       否则那些深色卡片上的标题会变成深绿（在深底上等于消失、且不报错）。
       🔴 填充按钮/渐变面上的文字**不**用这个变量，用下面的 `--st-on-gradient`：
         品牌色由深靛蓝换成亮青蓝后，压在它上面的文字必须从白改深
         （白字在 #45bbfb 上只有 ~2.1:1，不可读）。
       两个语义曾在旧版共用一个变量，暗色翻转时正是这里最容易出错 —— 不要合并回去。 */
    --st-on-primary: #ffffff;
    --st-on-gradient: #052e16;

    /* 画布与描边。
       🔴 2026-10-12 表面层级重标定（视觉审计：全站"只有一层面"，卡片浮不起来）。
       ## 问题（实测，非观感）
       旧值三档与页面底的亮度对比度只有 1.047 / 1.120 / 1.178 —— 而**人眼分辨两块面的阈值约 1.10**。
       于是 soft 完全看不出（等于没有这一档）、elev 只勉强能辨、cream 又几乎没被用到，
       全站实际只有"一层面"。对比同类暗色站：Linear 1.180 / Raycast 1.243 / Vercel 1.274，
       且它们普遍叠 2–3 层。

       ## 新标定（`--st-canvas` 保持不动 —— 业务明确"配色 OK"）
       只拉大**层级之间的亮度差**，不换色相（全部仍在同一深蓝族）：
         soft  1.047 → **1.108**（过人眼阈值，交替版块终于看得出节奏）
         elev  1.120 → **1.244**（对齐 Raycast 的面板档，卡片真正"浮起来"）
         cream 1.178 → **1.342**（最高层，用于内嵌块/强调卡）
       总跨度由 0.178 提到 0.343，与基准站同级。

       ## 改动时必须同步的三处（漏一处就会出现"有的卡浮、有的不浮"）
       ① `--pub-ink-900/850/800`（兼容桥，见本文件 §15）—— 它们镜像同三个色值；
       ② `.st-card--tint` 与 `.st-feature--tint` 的硬编码 `#182031`；
       ③ `.st-card--cream` 的硬编码 `#111927`。
       ⚠️ 已实测：提亮后 text 对比度仍充裕（muted 文字在 cream 底上 5.61:1 > AA 4.5），
          描边可见性不降反升（hairline 与新卡底对比 1.277 > 旧 1.250）。 */
    --st-canvas: #0a0e17;
    --st-canvas-soft: #131a28;
    /* 卡片/面板底：比页面底**亮一档**（暗色体系里"抬升"靠提亮，浅色体系靠投影） */
    --st-canvas-elev: #1a2438;
    --st-canvas-cream: #1e2a40;
    --st-hairline: rgba(255, 255, 255, .08);
    --st-hairline-input: rgba(255, 255, 255, .18);
    --st-hairline-strong: rgba(255, 255, 255, .16);

    /* 网格渐变色阶（唯一的彩色来源，不得新增）——改为青蓝发光族 */
    --st-mesh-cream: #0e1a2e;
    --st-mesh-sherbet: #1d4f7a;
    --st-mesh-lavender: #1a5f8a;
    --st-mesh-indigo: #45bbfb;
    --st-mesh-ruby: #1d4f7a;
    --st-mesh-magenta: #69f7d3;
    --st-lemon: #fbe041;

    /* 暗色版面专用（"on-dark" 现在的实际语义是"深色底上的浅色内容"） */
    --st-on-dark-soft: rgba(255, 255, 255, .72);
    --st-on-dark-mute: rgba(255, 255, 255, .56);
    --st-dark-hairline: rgba(255, 255, 255, .14);

    /* 语义前景色（暗色反相）：浅底时代的深色值（#b8174b/#7a5220/#1c7a52）在深底上
       对比不足 ~2:1，一律用高亮版。提示块统一用 .st-alert 族（见 §8.1），页面不得再手写。 */
    --st-danger-ink: #fda4af;
    --st-ok-ink: #6ee7b7;
    --st-warn-ink: #fcd34d;

    /* 圆角 */
    --st-r-xs: 4px;
    --st-r-sm: 6px;
    --st-r-md: 8px;
    --st-r-lg: 12px;
    --st-r-xl: 16px;
    --st-r-pill: 9999px;

    /* 阴影：暗色体系下投影几乎不可见（黑底上的黑影），改用**辉光**表达层级。
       ⚠️ 保留变量名与数量（30+ 处引用），只把值换成暗色下有效的形态。 */
    --st-shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
    --st-shadow-2: 0 8px 28px rgba(0, 0, 0, .45);
    --st-shadow-3: 0 18px 48px rgba(0, 0, 0, .55);
    /* 品牌辉光（青蓝），用于强调元素悬停/聚焦 */
    --st-glow: 0 6px 24px rgba(69, 187, 251, .28);

    /* 排版 */
    --st-font: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', system-ui,
        'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', 'Noto Sans SC', sans-serif;
    --st-font-mono: ui-monospace, 'SF Mono', 'Cascadia Mono', Consolas, 'Liberation Mono', monospace;

    /* 版块纵向节奏基准（🔴 2026-10-13 由 96px → 80px）。
       改动依据是设计评审 §2.2：全站统一 96px 时"密度完全一致、缺少呼吸节奏"。
       关键是**拉开与关键版块的差距**，而不是单纯变小：
         · 旧：常规 96 / 关键 128 —— 只差 32px（33%），滚起来几乎看不出区别；
         · 新：常规 80 / 关键 128 —— 差 48px（60%），形成可感知的「紧-松-紧」。
       常规档**变小**是这次的手段（缩小常规 = 相对放大关键档），
       所以不要为了"页面别太空"再把它加回去 —— 加了就等于抹平节奏。
       ⚠️ 三个关键档位（tight/常规/tall）现在的实测值：50 / 80 / 128。
       ⚠️ 全站所有页面共用本变量（30+ 页），改它 = 全站节奏一起变，这是有意的。 */
    --st-section-y: 80px;
    /* 页面宽度：1200px → 1400px（业务方要求「比之前宽」，与 demo 的 max-width: 1400px 一致）。
       ⚠️ 窄屏用 `100% - 2rem` 兜底，容器恒不溢出。 */
    --st-container: 1400px;
}

@media (max-width: 900px) {
    /* 小屏基准同步下调（96→80 的等比例）：64px → 56px。
       ⚠️ 与关键档的倍数关系保持：56 × 1.6 ≈ 90px（原 64 × 1.33 ≈ 85px），
          即小屏上的"松"没有变弱，只是常规档收紧了。 */
    :root { --st-section-y: 56px; }
}

/* ---------------------------------------------------------------------------
   3. 基础排版
   ss01 / cv11：Stripe 字体签名里的单层 a 等字形替换，Inter 对应 cv11。
   --------------------------------------------------------------------------- */
body.st-body,
.st-body {
    font-family: var(--st-font);
    font-feature-settings: 'cv11' 1, 'ss01' 1;
    color: var(--st-ink);
    /* 🔴 暗色重设计（2026-10-10）：页面底 + 顶部径向辉光（demo 的 body 背景）。
       辉光贴在 body 上而不是各页 hero 里 —— demo 的写法（body 铺 radial-gradient）
       让导航与主视觉**无缝融合**，hero 不必自己再画一层底。

       🔴 2026-10-11 修正「菜单区与 hero 背景不一致」（业务反馈：能明显看到两层颜色）
       ## 缺陷成因
       辉光其实有**两个来源**，且几何不同：
         · body：`circle at 50% 0%, rgba(69,187,251,.12)` —— 锚在**文档顶部**，被顶栏看到；
         · 内页 hero（`.st-hero-weave`）：自己又画了一层 `72% 76% at 50% -10%`（.20 强度，
           比 body 那层强近一倍）+ **不透明的 `var(--st-canvas)` 底**。
       于是顶栏（显示 body 的弱辉光）与紧随其后的 hero（显示自己的强辉光 + 不透明底）
       **在交界处颜色断档** —— 而且 hero 那层不透明底还把 body 的辉光**拦腰截断**。

       ## 修法：辉光只留**一处**（body），hero 改为完全透明
       单一来源 = 结构上不可能出现接缝（不依赖"两边参数调得差不多"这种脆弱一致）。
       为此把原 hero 那组更丰富的三层辉光**上移到 body**（强度取两者的中间值，
       既让内页 hero 仍有质感，又不会让整页顶部过亮）。
       ⚠️ 改这里会影响**全站每一页**（body 是全站共用的）—— 包括法律页/工具页。
          它们此前只吃到那层弱辉光，现在会一起变亮一点，观感更统一（这是好事）。
       ⚠️ 不要再用 `circle`：圆形渐变的半径取 farthest-corner，宽屏下会横向拉得很宽、
          竖向却很短（辉光呈"扁椭圆"）。用百分比椭圆才能随视口比例自适应。 */
    background: var(--st-canvas);
    background-image:
        /* ① 顶部中央主辉光（品牌天蓝）—— 顶栏与 hero 共用的那一层 */
        radial-gradient(72% 62% at 50% -6%, rgba(69, 187, 251, .16) 0%, rgba(69, 187, 251, 0) 62%),
        /* ② 右上品牌青绿对色 */
        radial-gradient(52% 48% at 88% 2%, rgba(105, 247, 211, .12) 0%, rgba(105, 247, 211, 0) 64%),
        /* ③ 左上补光：避免左侧完全无光、构图失衡 */
        radial-gradient(48% 44% at 6% 4%, rgba(105, 247, 211, .08) 0%, rgba(105, 247, 211, 0) 66%);
    background-repeat: no-repeat;
    /* 🔴 2026-10-25 业务反馈「hero 和下面的板块颜色脱节，能看到断层」。
       成因：这三个 radial-gradient 的尺寸是**百分比**（相对整个 body 高度），
       首页 body 高达 5000+px，于是「顶部辉光区」被拉伸到极长，
       在 mesh 结束之后仍在缓慢变化 —— 与 mesh 的收口底撞出一条可见硬边
       （实测 ΔRGB 31）。
       修法：显式限定辉光的**绘制高度**为 1600px（≈1.5 个首屏）。
       ⚠️ 不能用固定 px 写死渐变百分比半径 —— 那会在超宽屏变形；
          用 background-size 限定高度后，径向渐变的百分比半径仍在自身盒内正常换算。
       ⚠️ no-repeat + 其余区域保持 --st-canvas 纯色：首屏以下是干净的深底，
          不可能再出现「两个来源打架」的接缝。 */
    background-size: 100% 1600px;
    font-size: 15px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

.st-body h1, .st-body h2, .st-body h3, .st-body h4, .st-body h5 {
    font-family: var(--st-font);
    font-weight: 300;
    color: var(--st-ink);
}

/* 显示级标题：字号阶梯 + 负字距。
   🔴 2026-10-12 中段字阶补齐（视觉审计：全站"中间层不存在"，文字只有很小和很大两种）。
   🔄 2026-10-11 字重回退：中段档位由 600/700 **收回 300**（业务明确要求）。

   ## 为什么收回字重（推翻本规则上一版的判断）
   上一版给 20–32px 档位加到 600/700，理由是"中文在 w500 以下不产生视觉差异，
   必须 ≥600 才立得起来"（依据是那组墨量实测）。但业务方明确了产品立场：
   **首页 hero 主标语的细字重（w300）是老板定的品牌基调，全站文字都应偏细**，
   而加粗后的板块标题（32px/w700）与 hero 明显割裂 —— 视觉上"有些标题比较粗"。
   ⇒ 设计决策权在业务方，且"全站统一细字重"本身是自洽的品牌语言
     （Stripe / Linear 的大标题同样是 300–400，重量感交给字号与留白）。
   ⚠️ 因此**不要再基于墨量数据把中段档位加粗回去** —— 那是技术判断，
      已被产品决策覆盖。字重在本项目是"品牌调性"问题，不是"可读性"问题。
      （真正需要加粗的是 <20px 的小字标题，见 .st-card__title 的 500 —— 那是可读性下限。）

   ## 保留的是什么
   字号阶梯（16–32px 两段）**保留**，它解决的是"中间层断层"这个结构问题，
   与字重无关；业务反馈"没看出明显变化"也只是说观感平淡，未否定字号。
   ⚠️ 必须用 `.st-body` 前缀提权到 (0,2,0)：上面 `.st-body h1~h5` 是 (0,1,1)，
      会**静默覆盖** `.st-display-*` / `.st-heading-*` 的 (0,1,0) ——
      `.st-feature__title` 曾因此白写一场（见该规则注释）。 */
.st-body .st-display-lg  { font-size: clamp(1.5rem, 2.4vw, 2rem); font-weight: 300; line-height: 1.14; letter-spacing: -.02em; }
.st-body .st-display-md  { font-size: 1.625rem; font-weight: 300; line-height: 1.16; letter-spacing: -.015em; }
.st-body .st-heading-lg  { font-size: 1.375rem; font-weight: 300; line-height: 1.2;  letter-spacing: -.01em; }
.st-body .st-heading-md  { font-size: 1.25rem;  font-weight: 300; line-height: 1.3;  letter-spacing: -.01em; }
.st-body .st-heading-sm  { font-size: 1.125rem; font-weight: 300; line-height: 1.35; letter-spacing: -.01em; }
/* 大标题（48px+）：与全站同一套细字重，无需额外声明（这里是"基准档"，供上面五行对齐参照）。 */
.st-display-xxl { font-size: clamp(2.25rem, 5.2vw, 3.5rem); font-weight: 300; line-height: 1.06; letter-spacing: -.025em; }
.st-display-xl  { font-size: clamp(1.75rem, 3.6vw, 3rem);   font-weight: 300; line-height: 1.12; letter-spacing: -.02em; }

/* 🔴 2026-10-12 中段字阶补齐：`.st-lead` 16px → **18px**，补上"16–22px 空洞"的另一半。
   导语是紧跟大标题的段落（每个版块的第一段），此前 16px 只比正文 14px 大一点，
   在大标题（48px）之下几乎没有"承重"作用 —— 视觉上像标题后面直接接正文。
   提到 18px + 行高 1.7 后，它与标题、正文形成三段清晰落差。
   ⚠️ 14px 正文（.st-body-md / .st-caption）**保持不动** —— 业务明确"配色 OK"，
      正文是阅读主体、字号变动影响面最大，本次只动"层级"相关档位。 */
.st-lead   { font-size: 1.125rem; line-height: 1.7; color: var(--st-ink-2); }
.st-body-md { font-size: .9375rem; line-height: 1.6; color: var(--st-ink-2); }
.st-caption { font-size: .8125rem; line-height: 1.5; color: var(--st-ink-mute); letter-spacing: -.01em; }
.st-micro   { font-size: .6875rem; line-height: 1.5; color: var(--st-ink-mute); }

/* 眉标（全大写小字 + 字距），Stripe 版块开头的固定记号 */
/* 眉标（版块开头的小字记号）。
   🔴 2026-10-06 v7：10px → 12px、字重 500 → 600（业务方反馈「模块名称文字太小，
   中文状态下根本看不清楚」）。10px 对拉丁文小字尚可，对**中文**则笔画糊成一团 ——
   汉字在同等字号下的可辨识度远低于拉丁字母，中文 UI 的正文下限约 12px。
   ⚠️ 不要为"好看"把这行改回 10px：它承载的是每个版块的名字（如「核心平台」「效果验证」）。 */
.st-eyebrow {
    display: inline-block;
    font-size: .75rem;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: .08em;
    text-transform: uppercase;
    /* v9（2026-10-07，对齐 Stripe）：眉标从灰色升级为**品牌紫**——
       Stripe 全站每个版块的名字都是彩色小标（indigo），灰眉标是"只学皮毛"的
       最大来源之一：眉标是版块的视觉路标，必须跳出来。深色版面内仍走 on-dark 覆盖。 */
    color: var(--st-primary);
    /* 🔴 2026-10-13 修「眉标与卡片内边距不对齐」（实测 3 处，偏移 6px）。
       成因：inline-block 默认按 **baseline** 对齐，而眉标的盒高（13.8px = 12 × 1.15）
       比父级行盒矮（父级 15px × 1.5 = 22.5px 的 strut）——
       于是浏览器把它**沿基线往下推 6px**，卡片声明的 padding-top: 32px
       实际渲染成 38px：文字左边贴 32px、上边却在 38px，是肉眼能看出
       "标题没跟卡片内边距对齐"的细节缺陷（并排两卡对比时更明显）。
       改为 top 对齐后，盒顶 = 行盒顶 = 内边距线（实测偏移归 0）。

       ## 为什么不改成 display:block
       眉标在版块头里是**独立一行元素**，block 也能工作；但 `inline-block` 是
       刻意的——它让眉标与其后紧跟的行内内容（少数版块里有）能同排，
       且背景/内边距若将来加上不会撑满整行。改 block 会静默改变这些位置的布局。
       `vertical-align` 只影响行内格式化上下文，不动盒模型，是最小改动。

       ⚠️ flex 容器内的眉标不受本规则影响（flex 子项被块化，vertical-align 被忽略）——
          例如 `.st-card__top` / `.st-feature__top` 里的那些，本来就没有此偏移。 */
    vertical-align: top;
}
/* 中性眉标：给"痛点/问题"这类**负面**栏位用（2026-10-11）。
   背景：解决方案页的痛点列眉标原本也是品牌蓝，与右侧「平台怎么解」完全同色 ——
   两栏在视觉上分不出"问题"与"答案"。痛点走中性灰、解法留品牌蓝，
   读者一眼能看出这组对照是"问题 → 答案"。
   ⚠️ 与 `.st-eyebrow` 同为 (0,1,0)，靠**源码顺序**取胜，必须写在其后。 */
.st-eyebrow--muted { color: var(--st-ink-mute); }

/* 一律等宽数字：金额/计数/百分比/进度——金融级数据感的排版纪律 */
.st-num,
.st-body .st-num {
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
}

/* 文字强调：品牌色用于链接与结论词；暗色体系下高亮词改用**青蓝渐变文字**
   （浅色体系里是 cream 记号笔底纹 —— 深色底上淡黄底纹会"糊"掉，且与 demo 的
   渐变标题语言不一致）。 */
.st-ink-link { color: var(--st-primary); text-decoration: none; }
.st-ink-link:hover { color: var(--st-primary-deep); text-decoration: underline; }
.st-hl {
    /* 🔴 2026-10-10 暗色重设计：gradient text（与 demo 的 hero-title 同一手法）。
       ⚠️ background-clip:text 必须同时写 -webkit- 前缀与标准属性（Safari/Chrome 都要）；
       `color: transparent` 是兜底（部分旧内核不认 background-clip:text，会显示透明文字
       —— 故末尾 `@supports not` 分支给出实色回退，保证任何情况下都看得见）。 */
    background: var(--st-grad);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    padding: 0 .08em;
    /* 高亮词**整块不拆行**：中文可在任意字符间断行，被劈开的高亮词很难看。 */
    white-space: nowrap;
}
/* 不支持 background-clip:text 的内核：给实色（宁可没渐变，也不能没有文字）。 */
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
    .st-hl { color: var(--st-grad-start); -webkit-text-fill-color: currentColor; background: none; }
}
.st-hl--indigo { color: var(--st-primary); background: none; font-weight: 400; -webkit-text-fill-color: currentColor; }

/* ---------------------------------------------------------------------------
   4. 容器与版块
   --------------------------------------------------------------------------- */
.st-container {
    width: min(100% - 2rem, var(--st-container));
    margin-left: auto;
    margin-right: auto;
}

.st-section { padding: var(--st-section-y) 0; position: relative; }
.st-section--tight { padding: calc(var(--st-section-y) * .62) 0; }
/* 版块间距韵律（2026-10-06 评审 P1，2026-10-13 加大落差）：原先全站统一 96px，
   20 个版块一路滚下来密度完全一致、缺少"呼吸节奏"。给 3 个"想让人记住"的版块
   （体检舱 #tools / 独有能力 #unique / 定价 #pricing）加高，与常规版块形成「松-紧-松」。

   🔴 2026-10-13 系数 ×1.33 → ×1.6（与 --st-section-y 96→80 同批）：
   首版只做了"关键档变大"，没有"常规档变小"，于是两档只差 32px（33%）——
   实测滚屏时几乎察觉不到节奏差异（评审 §2.2 的原话是"视觉密度几乎一致"，并未解决）。
   本批两头同时拉开：常规 80 / 关键 128，差距 48px（**60%**），
   人眼在连续滚屏中才能读出"这段重要"。
   ⚠️ 用相对值（×1.6）而不是写死 128px：小屏 --st-section-y 降为 56px 时
   它会等比降到 ~90px，不会在小屏留出两块过大的空白。
   ⚠️ 系数被 SiteDesignSystemTest 的正则锁定（防被改回写死像素）——
      调系数时要同步该测试的期望值，那是它的设计意图（可核对），不是阻碍。 */
.st-section--tall { padding: calc(var(--st-section-y) * 1.6) 0; }
/* 2026-10-25 业务要求：**官网首页**板块之间的间隔调大一点。
   ⚠️ 只作用于首页（视图里给这几个 section 加了 `st-home-section`），
      不动全站 `--st-section-y` —— 那个 30+ 页共用，改它等于全站改版。
   80 → 104px（+30%）；小屏 56 → 72px 保持同比。 */
.st-home-section { padding-top: calc(var(--st-section-y) * 1.3); padding-bottom: calc(var(--st-section-y) * 1.3); }
/* 2026-10-25 业务要求：「行业包」与「常见问题」两个版块**去掉下内边距**。
   这两块的下方留白原本全部来自 .st-home-section 的 padding-bottom（104px / 小屏 72px）——
   块内最后一个元素（行业包网格 / FAQ 列表）自己没有外边距，故去掉后立即贴到下一版块的
   padding-top 上，两段留白从 ~220px 降到 ~116px。

   🔑 用**双类选择器**（0,2,0）而不是单类：单类的 `.st-home-section--flush-bottom`（0,1,0）
   与 `.st-home-section` 同权重，只能靠"谁的声明在后面"决胜 —— 本文件已多次栽在
   "同权重靠顺序"上（见 §.st-section-head 的历史注释）。双类不依赖顺序，也不会被
   以后新增的 `.st-home-section { ... }` 规则静默压掉。 */
.st-home-section.st-home-section--flush-bottom { padding-bottom: 0; }
/* 2026-10-25 业务要求：「页面背景一块一块的，上下统一」。
   原 --soft 给内页 30 处 section 铺了更亮的 #131a28，在深底上形成色块断层。
   现改为透明（回落 body 底色）——全站一次统一，不改各页模板（模板里类名保留，
   避免逐页删类引发的回归面）。分块节奏改用留白与分隔线表达，不再用底色。 */
.st-section--soft { background: transparent; }
/* 🔴 2026-10-10 暗色重设计：渐变色带改为**青蓝发光带**（原为靛蓝→薰衣草浅渐变）。
   语义不变（把 CTA 区从上下文里区分出来），色相换成 demo 的渐变双色。
   ⚠️ 保留类名 `--cream`（视图与测试有引用）。 */
.st-section--cream {
    background:
        radial-gradient(96% 130% at 8% 6%, rgba(105, 247, 211, .16) 0%, rgba(105, 247, 211, 0) 62%),
        radial-gradient(90% 120% at 96% 92%, rgba(69, 187, 251, .20) 0%, rgba(69, 187, 251, 0) 66%),
        radial-gradient(70% 100% at 50% 112%, rgba(69, 187, 251, .12) 0%, rgba(69, 187, 251, 0) 68%),
        /* 🔴 2026-10-12 表面层级重标定：底 `#0c1220`(1.032) → `#141c2b`(1.131)。
           原值低于 soft 档，导致"渐变带"反而比交替带更暗、层次倒挂。现置于
           soft(1.108) 与 elev(1.244) 之间 —— 版块带应高于交替带、低于卡片。 */
        #141c2b;
}
.st-section--dark { background: var(--st-dark-900); color: var(--st-ink); }
.st-section--dark h1, .st-section--dark h2, .st-section--dark h3, .st-section--dark h4 { color: var(--st-ink); }

/* 版块标题容器宽度 —— 🔴 2026-10-11 统一为「与下方内容同宽 + 一律居左」。

   ## 沿革（这条规则改了三轮，读历史用）
   · 初版：整块 section-head 限宽 46rem → 48px 中文标题一行只放 15 字，标题被强行换行（业务投诉）；
   · 2026-10-06：标题放宽到 56rem(896px)、**描述改为撑满** → 解决了描述"缺一块"，
     但制造了新问题：**同一版块内标题 896px、描述 1336px，右边缘差 440px**。
   · 本轮（2026-10-11，业务反馈「有的撑满有的很窄，最好统一」）：**标题也一并撑满**。

   ## 为什么最终选择"都撑满"而不是"都限窄"
   下方卡片网格是满容器宽（1336px）。若把描述也收窄到 896px，整块标题区就会与
   卡片区右边缘错开 440px —— 那正是 2026-10-06 那次被投诉的"缺一块"。
   故统一方向只能是**向宽的看齐**：标题与描述同宽 = 容器宽 = 与卡片对齐，三者右边缘齐平。
   ⚠️ 撑满**不会**让标题变宽：中文标题的实际行宽由文字本身决定，
      `max-width` 只约束盒子。20-25 字的 48px 标题约 960-1200px，仍在容器内单行放下；
      真超长时由 `text-wrap: balance` 均衡折行（比硬切在词组中间好看）。

   ⚠️ `--center` 变体历史上**被删除过一次**，2026-10-20 按业务要求重新加回，
      但实现方式换了 —— 这是本次重加的关键，不要改回旧写法：

      · 旧实现（坏的）：`.st-section-head--center h2 { margin-left: auto }`。
        它与下面的 `.st-section-head h2 { margin: .75rem 0 0 }` **同权重（0,1,1）**，
        后者源码在后 → margin auto 被静默覆盖 → 标题盒子贴左（left=52）却内部居中，
        **视觉中心比页面中心偏左 220px** —— 既不是左对齐也不是居中
        （当时的业务原话「不是居左对齐，看着很奇怪」）。

      · 新实现（正确）：**只给容器加 `text-align: center`**，不碰任何 margin。
        居中对齐是行内内容的属性，容器有宽度就够，不需要 `margin: auto` 撑盒子 ——
        那条属性本来就是多余的，也正是旧实现的祸根。
        守卫：SiteDarkRedesignV8Test::test_home_section_titles_are_centered_and_enlarged
        （断言"用 text-align、不用 margin auto"，防止有人"优化"回旧写法）。

      适用范围：首页「智库」「常见问题」两个版块（业务要求与「平台能力全景」的居中标题一致）。 */
.st-section-head { margin-bottom: 56px; }
/* `text-wrap: balance`：多行标题自动均衡两行长度（Chrome 114+ / Safari 17.5+ 支持，
   不支持的浏览器按默认折行，无副作用）。仅对标题用，**不要**用于正文段落。 */
.st-section-head h2 { margin: .75rem 0 0; text-wrap: balance; }
.st-section-head p { margin: .875rem 0 0; color: var(--st-ink-mute); font-size: 1rem; line-height: 1.65; }
.st-section--dark .st-section-head p { color: var(--st-on-dark-soft); }

/* 居中 + 放大变体（2026-10-20）。
   ## 为什么同时做两件事
   业务要求原文：「智库、常见问题这两个板块标题左右居中，放大，和其他几个板块一样」。
   首页其余版块（#capabilities 的四组标题）是**居中**的，这两处是左对齐 → 视觉断档；
   而它们在页面上的层级是**一级版块**（比 #capabilities 里的子标题更高一层），
   所以字号取 `display-xl` 再上一档（48 → 56px），保证"一级版块标题"读得出来。

   ⚠️ 字号用复合选择器 `.st-section-head--center .st-display-xl`（0,2,0）压过
      `.st-display-xl`（0,1,0）—— 同权重靠顺序的陷阱本文件已踩过多次（见上方注释）。 */
.st-section-head--center { text-align: center; }
/* 2026-10-20 业务要求：与其它版块（「平台能力全景」的 .st-deck__title）**完全一致**
   —— 同字号、同色（青蓝 #50D6FF）、同字重。此前用的是 display-xl 再放大一档，
   色值也还是白色，与 deck 标题不一致（业务两次指出）。
   ⚠️ 三处（deck 标题 / 这两处）必须同源：以后调版块标题样式时，
      改这一处即可，不要只改 .st-deck__title 而漏掉这里。 */
.st-body .st-section-head--center .st-display-xl {
    /* ⚠️ 与 `.st-body .st-deck__title` **同源**（2026-10-25 两处同步放大，
       二次再同比例 +20% → clamp(2.1rem, 3.6vw, 3.3rem)）。 */
    font-size: clamp(2.1rem, 3.6vw, 3.3rem);
    font-weight: 300;
    line-height: 1.3;
    color: #50d6ff;
    letter-spacing: 0;
}

.st-hairline { height: 1px; background: var(--st-hairline); border: 0; }

/* ---------------------------------------------------------------------------
   5. 首屏辉光背景（.st-mesh）
   🔴 2026-10-10 暗色重设计：由「Stripe 白底丝带位图」改为**暗色发光背景**
   （demo 的 `radial-gradient(circle at 50% 0%, rgba(69,187,251,.12), transparent 60%)`
   家族色 + 青绿对色）。

   ## 为什么不再用位图
   旧实现是一张**带透明通道的浅色丝带**（hero-wave.webp），配色为 Stripe 的暖色带；
   暗色底上它既无色谱依据、又会把整屏洗成灰紫（透明区压不住深底）。
   暗色 UI 的"高级感"来自**发光**，故改为多层径向渐变，不引入位图 ——
   顺带去掉一个第三方品牌资产依赖（旧注释里已标注版权待确认）。

   ## 结构约定（与旧实现一致，勿改）
   `::before` = 主辉光层（可自由换色相）；`::after` = **收口层**，
   把辉光向下收进页面底色，保证 hero 之后的正文区干净。
   ⚠️ `::after` 只在本节定义一次（历史上重复定义把收口静默吃掉过）。
   --------------------------------------------------------------------------- */
.st-mesh {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    /* 底色与页面底一致（网格是"发光层"，不是"另一块底"）。 */
    background: transparent;
}
.st-mesh::before {
    content: '';
    position: absolute;
    inset: 0;
    background:
        /* ① 顶部中央主辉光（demo 的主光源） */
        radial-gradient(72% 62% at 50% -6%, rgba(69, 187, 251, .22) 0%, rgba(69, 187, 251, 0) 62%),
        /* ② 右上青绿对色：让渐变双色同框 */
        radial-gradient(52% 48% at 88% 4%, rgba(105, 247, 211, .16) 0%, rgba(105, 247, 211, 0) 64%),
        /* ③ 左上补光：避免左侧文案区完全无光（构图偏重一侧会失衡） */
        radial-gradient(48% 44% at 6% 8%, rgba(105, 247, 211, .10) 0%, rgba(105, 247, 211, 0) 66%);
}
.st-mesh::after {
    /* 收口层（**全站唯一一处定义**）：底部向页面底色过渡 —— 保证 hero 之后是干净底，
       同时让辉光底部"渐隐"而不是被硬切。
       ⚠️ 收口目标是 --st-canvas（深色），不是白色 —— 写白色会得到一条发光的白带。

       🔴 2026-10-25 业务反馈「hero 和下面的板块颜色脱节、能看到断层」。
       成因：本收口层的渐变在 98% 处已到达**完全不透明**的 --st-canvas，而
       `.st-mesh` 只向下溢出 hero 260px，于是「不透明底」与「body 顶部辉光」
       在 mesh 底边形成一条可测量的硬边（实测 ΔRGB≈31，肉眼可见断层）。
       修法：
         ① 把渐变**提前收尾**（86% 就到达不透明），让 mesh 底边落在纯底色之上 ——
            底边两侧都是同一个 --st-canvas，结构上不可能再有缝；
         ② 同时把 mesh 的溢出高度从 260 → 380px，给辉光更长的淡出距离，
            让 hero 的发光"流进"下一个板块再消失，而不是在板块交界处戛然而止。 */
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(10, 14, 23, 0) 40%, rgba(10, 14, 23, .82) 70%, var(--st-canvas) 86%);
    pointer-events: none;
}

/* 移动端：多层层叠辉光在窄屏上被裁得只剩一条，改为整体上移 + 加强中央辉光，
   保证小屏首屏也有"在发光"的观感（参数按窄屏重算，不套用桌面那套）。 */
@media (max-width: 767px) {
    .st-mesh::before {
        background:
            radial-gradient(120% 58% at 50% -8%, rgba(69, 187, 251, .26) 0%, rgba(69, 187, 251, 0) 64%),
            radial-gradient(90% 44% at 76% 2%, rgba(105, 247, 211, .16) 0%, rgba(105, 247, 211, 0) 66%);
    }
}

/* 首屏间距（2026-10-01 上移）：原 104px 顶部内边距让 logo/菜单行离页顶过远，
   业务方要求"往上挪一下"。改为 76px —— 导航行距页顶约 18px（st-nav__inner 的 padding-top），
   合计仍是舒展的留白，但不再有"顶部空一大块"的观感。 */
/* ---------------------------------------------------------------------------
   5b. 彩色渐变模块（2026-10-01，按业务方要求参考 Stripe 官网）

   ## 来源：对 https://stripe.com/zh-us 的实测抓取（CDP 读计算样式）
   Stripe 页面上共 18 个渐变元素，归纳为**三种明确形态**（不是"到处糊渐变"）：

   ① **卡片整块渐变底**（billing-plan-graphic / bento-card）：
      `radial-gradient(50% 50%, rgba(83,58,253,.8) 62.5%, rgba(83,58,253,0) 100%)`
      多枚彩色径向渐变叠在卡片区域上，**模糊、低饱和、彼此交融**，
      再叠一层白色线性渐变向下收口，让卡片下半仍可放正文。
   ② **区块底部中央光晕**（stats-animation-gradient）：
      `radial-gradient(102% 102% at 50% 102%, <彩色> 0px, ..., rgb(248,250,253) 100%)`
      光从**底部中央**往上扩散，顶部收敛成近白 —— 整块 1440×920 的宽幅色带。
   ③ **渐变文字**（developers-scale-subsection 的数字）：
      `linear-gradient(68deg, rgba(83,58,253,.08), rgba(255,140,108,.8), rgba(218,75,254,.8))`
      + `background-clip: text`，只用于强调**个别数字**。

   ## 本系统的落地口径
   - 渐变色**不得新增色相**：全部从既有的网格色阶取（靛蓝/洋红/ruby/雪酪橙/薰衣草），
     与 --st-mesh-* 同源，保证与 hero 是一套色谱；
   - 透明度保守（.10–.34）：我们的页面正文密度高于 Stripe，饱和度一高就压字；
   - 只给**版块级容器**加（卡片/区块），不逐元素加 —— 否则页面会碎成一堆色块。

   ⚠️ 使用约定：同一屏最多一处大面积渐变（hero 或某个区块），
      其余用卡片级；连续三块都上渐变会失去层次（Stripe 也是隔块使用）。
   --------------------------------------------------------------------------- */

/* 形态①：卡片渐变底。三种色相变体，按内容语义选用（避免"随机撒色"）。
   🔴 2026-10-10 暗色重设计：改为**青蓝辉光**（原为浅色角部色斑 + 底部收白）。
   暗色下"收白"必须改成"收暗"（收到卡片底色），否则卡下半会变白、文字看不见。 */
.st-card--grad-a,
.st-card--grad-b,
.st-card--grad-c {
    position: relative;
    overflow: hidden;
    border-color: transparent;
}
.st-card--grad-a::before,
.st-card--grad-b::before,
.st-card--grad-c::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    /* ⚠️ 圆角必须跟父卡一致：::before 是矩形，父卡 overflow:hidden 虽能裁切，
       但 inset:0 的矩形在圆角处仍会露出**直角边**（实测截图可见卡片顶部两侧的小尖角）。
       给伪元素同样的圆角即可贴合。 */
    border-radius: inherit;
}
/* 卡片内所有内容要浮在渐变层之上（否则被色板盖住 —— 与 hero 网格同一个坑）。 */
.st-card--grad-a > *,
.st-card--grad-b > *,
.st-card--grad-c > * { position: relative; z-index: 1; }

/* 变体 A：青绿 + 天蓝（品牌主色，用于"监测/数据"类卡片）。
   色斑自左上/右上两角向内扩散、底部收到卡片底色 —— 彩度集中在上部，
   文字所在的中下部回到近底色，保证可读性。 */
.st-card--grad-a::before {
    background:
        radial-gradient(96% 70% at 4% -6%, rgba(69, 187, 251, .26) 0%, rgba(69, 187, 251, 0) 60%),
        radial-gradient(88% 64% at 98% 2%, rgba(105, 247, 211, .18) 0%, rgba(105, 247, 211, 0) 62%),
        linear-gradient(180deg, rgba(20, 27, 41, 0) 34%, var(--st-canvas-elev) 82%);
}
/* 变体 B：天蓝 + 青绿（用于"内容/创作"类卡片；与 A 对调主色相以区分） */
.st-card--grad-b::before {
    background:
        radial-gradient(92% 68% at 98% -6%, rgba(105, 247, 211, .22) 0%, rgba(105, 247, 211, 0) 60%),
        radial-gradient(88% 66% at 2% 6%, rgba(69, 187, 251, .22) 0%, rgba(69, 187, 251, 0) 62%),
        linear-gradient(180deg, rgba(20, 27, 41, 0) 34%, var(--st-canvas-elev) 82%);
}
/* 变体 C：暖金 + 青蓝（用于"证明/成效"类卡片；借用 demo 的高亮黄作唯一暖色，
   与导航「免费体验」的 #FBE041 同源，不是新色相）。 */
.st-card--grad-c::before {
    background:
        radial-gradient(94% 68% at 96% -6%, rgba(251, 224, 65, .14) 0%, rgba(251, 224, 65, 0) 60%),
        radial-gradient(86% 62% at 6% 4%, rgba(69, 187, 251, .18) 0%, rgba(69, 187, 251, 0) 64%),
        linear-gradient(180deg, rgba(20, 27, 41, 0) 34%, var(--st-canvas-elev) 82%);
}

/* 形态②：版块级底部中央光晕。
   🔴 2026-10-10 暗色重设计：色相换成 demo 的青绿→天蓝族，并改为「底部升起辉光」
   （暗色底上要的是**发光**而不是收白）。仍遵守「全页只在一处用」的纪律。 */
.st-section--glow { position: relative; overflow: hidden; }
.st-section--glow::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        /* 主辉光：天蓝自底部中央升起 */
        radial-gradient(102% 92% at 50% 108%, rgba(69, 187, 251, .22) 0%, rgba(69, 187, 251, .14) 22%, rgba(69, 187, 251, .07) 42%, rgba(69, 187, 251, 0) 72%),
        /* 青绿芯（渐变的另一端，让两色在同一屏出现） */
        radial-gradient(58% 62% at 50% 106%, rgba(105, 247, 211, .16) 0%, rgba(105, 247, 211, 0) 66%),
        /* 左上青绿天光：与 hero 辉光呼应 */
        radial-gradient(46% 54% at 8% 6%, rgba(105, 247, 211, .10) 0%, rgba(105, 247, 211, 0) 66%);
}
.st-section--glow > .st-container { position: relative; z-index: 1; }

/* 形态④：深色版面。
   🔴 2026-10-10 暗色重设计后语义调整：整站已是暗色，本层不再是"白页里的一块深色"，
   而是**比页面底更深一档**的收束段落（#05080f vs canvas #0a0e17）——
   它仍然承担"让这一段更正式、更沉"的作用，但对比关系从「深/白」变成「更深/深」。
   内部卡片规则（半透明提亮 + 极细描边）沿用，暗色下同样成立。
   ## 用法纪律
   全页仍**只用一处**（放在页面后段做收束）。 */
.st-section--ink {
    position: relative;
    overflow: hidden;
    background: #05080f;
    color: var(--st-ink);
}
.st-section--ink h1, .st-section--ink h2, .st-section--ink h3, .st-section--ink h4 {
    color: var(--st-ink);
}
.st-section--ink p, .st-section--ink li { color: var(--st-on-dark-soft); }
.st-section--ink .st-section-head p { color: var(--st-on-dark-soft); }
/* 深底上的卡片：半透明提亮 + 极细描边（纯白卡在深底上会"跳"出来） */
.st-section--ink .st-card,
.st-section--ink .st-feature {
    background: rgba(255, 255, 255, .06);
    border-color: rgba(255, 255, 255, .12);
    box-shadow: none;
}
.st-section--ink .st-card__title,
.st-section--ink .st-feature__title { color: var(--st-on-primary); }
.st-section--ink .st-card__text,
.st-section--ink .st-feature__text { color: var(--st-on-dark-soft); }
.st-section--ink .st-eyebrow { color: var(--st-on-dark-mute); }
.st-section--ink .st-feature__icon {
    background: rgba(255, 255, 255, .10);
    border-color: rgba(255, 255, 255, .18);
    color: var(--st-on-primary);
}
/* 深底上的口径表与清单（这两块在「数据可信」深色板块内，默认是白底/深字） */
.st-section--ink .st-caliber__row {
    background: rgba(255, 255, 255, .06);
    border-color: rgba(255, 255, 255, .12);
}
.st-section--ink .st-caliber__k { color: var(--st-on-dark-soft); }
/* 🔴 2026-10-11 修复：深色版面里的口径数值与勾选图标**漏改**，仍是旧靛蓝（#c9c2ff / #a99bff）。
   成因：暗色重设计时改的是「浅色系里的深色版面」版块，这两条属于**该版块的内部覆盖规则**
   （`.st-section--ink .xxx`），不在 §2 的 token 层 —— 改 token 时扫不到它们。
   表现：整页已是青蓝主色，唯独「数据可信」板块里的数字与 ✓ 还是紫色，
   与相邻内容明显不是一套配色（业务方原话「好像还是旧的样式」）。
   ⚠️ 这类"板块内部覆盖"是换肤最易漏的地方：**改完 token 必须再 grep 一遍
      裸十六进制色值**（本项目已在此踩过两次：Cookie 横幅、本处）。 */
.st-section--ink .st-caliber__v { color: #8ee6ff; }   /* 品牌天蓝提亮（#45bbfb 在深底上对比略低） */
.st-section--ink .st-checklist li { color: var(--st-on-dark-soft); }
.st-section--ink .st-checklist li::before { color: var(--st-grad-start); }  /* 品牌青绿，与全局 ✓ 同源 */
.st-section--ink .st-mini {
    background: rgba(255, 255, 255, .06);
    border-color: rgba(255, 255, 255, .12);
}
.st-section--ink .st-note { color: var(--st-on-dark-mute); }
/* 深底上补一层极淡的彩色辉光（纯色深底会显得"死板"）——暗色体系改用青蓝族。 */
.st-section--ink::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(60% 50% at 12% 8%, rgba(69, 187, 251, .18) 0%, rgba(69, 187, 251, 0) 64%),
        radial-gradient(52% 44% at 92% 88%, rgba(105, 247, 211, .12) 0%, rgba(105, 247, 211, 0) 66%);
}
.st-section--ink > .st-container { position: relative; z-index: 1; }

/* 形态③：渐变文字。只把渐变字用在**个别强调数字**上，不用于正文。
   🔴 2026-10-10 暗色重设计：色相换成品牌青蓝双色（原为靛蓝→橙→洋红）。
   ⚠️ 渐变文字压在同色渐变底上会糊成一团，故仍限定在**纯底色**的浅色/深色画布使用。 */
.st-num-grad {
    background: var(--st-grad);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
    .st-num-grad { color: var(--st-grad-start); -webkit-text-fill-color: currentColor; background: none; }
}

/* 首屏间距（2026-10-01 调整，两轮）：
   ① 上移导航行：原 104px 顶部内边距让 logo/菜单行离页顶过远 → 收到 76px；
   ② 去掉右侧演示块后底部留白过大（单列内容比双列矮，实测截图约 200px 空档）
      → 底部内边距从 84px 收到 40px，让数字带更紧地接住 hero。 */
/* ⚠️ 这里**不能**用 overflow: hidden（2026-10-06 实测踩到）：
   顶栏的移动端抽屉（.st-nav__drawer，absolute 定位在顶栏下方）是 hero 的后代，
   hero 一旦裁剪，抽屉超出 hero 底部的部分**整块消失** —— 表现为
   「点汉堡后菜单只露上半截，下半截是页面内容」（截图确认，且不报任何错）。
   原依赖：early 版本用 hero 的 overflow 裁渐变网格；现在网格（.st-mesh）
   已自带 overflow: hidden 自我裁剪，hero 层裁剪是冗余的。
   移除后实测：文档无横向溢出（scrollWidth 不变）、网格视觉不变（自裁仍生效）。 */
/* ⚠️ 2026-10-06 v7：顶部内边距 76px → 24px（业务方反馈「logo 和菜单那一行，距离顶部高度太大」）。
   原值来自「单行顶栏 + 需要与渐变网格留白」的旧形态；现在顶栏自身是两行结构，
   76px 会让整条顶栏显得悬浮在半空。24px 配合工具条的 30px 小按钮行，视觉重心回到正常位置。 */
.st-hero { position: relative; padding: 24px 0 40px; }
.st-hero--compact { padding: 20px 0 56px; }

/* 首页专用：hero 背景「放飞」——网格（含丝带图与底部收口渐隐）**向下溢出 hero 盒**，
   让色彩流进紧跟其后的数字带区域再渐隐，而不是在 hero 底边被硬切一刀。
   业务原话（2026-10-07）：「把它放出来，不要限制在 hero 的容器里面，就像之前一样」。

   ## 为什么要这个修饰类而不是直接改 .st-mesh
   `.st-mesh` 还被注册/找回密码/工具页（banned-check / health-demo 等）复用，
   那些页面 hero 更矮、下方紧跟表单/卡片，溢出会造成叠色干扰 —— 只给首页加。

   ## 几何依据（1440 实测）
   数字带版块 = hero 底起 0（上内边距）+ 162（带体）+ 48（下内边距）≈ 210px，
   故下沉 260px：丝带的收口渐隐（::after 的 96% 停靠点）恰好落在数字带下缘之后，
   整个数字带都被色彩"托住"再消散（截图对比确认）。

   ## 🔴 z-index:-1 不能省
   网格是 positioned 元素，按 CSS 绘制顺序会盖在**后续版块的静态内容**之上
   （数字带是 static 块）—— 不降层的话数字带会被整块盖住（试错确认）。
   降到 -1 后它排在"根背景之上、正常流内容之下"，行为与背景一致。 */
.st-hero--bleed > .st-mesh { inset: 0 0 -380px; z-index: -1; }

/* 🔴 hero 正文容器必须**定位**在网格之上。
   踩坑记录（2026-09-30，首页实测）：`.st-mesh` 是 `position:absolute`，
   而按 CSS 绘制顺序，**定位元素会盖在同级静态内容之上** —— 于是整块渐变色板
   （含底部那层白色收口渐变）直接盖住了标题。
   表现极其隐蔽：页面 200、HTML 里文字齐全、CDP 查计算样式一切正常（颜色/尺寸/可见性都对），
   **只有肉眼看截图才发现文字不在**。
   ⚠️ 两处都要保证：① 本规则把容器设为 relative + z-index；
   ② 容器类名要同时覆盖 `.st-container` 与 `.site-container`
   （首页历史上用的是 `site-container`，只写前者匹配不上 —— 这正是本次的成因）。 */
.st-hero > .st-container,
.st-hero > .site-container { position: relative; z-index: 1; }

/* 首屏排版（2026-10-01 去掉右侧演示块后改为单列）。
   Stripe 首屏的形态是「文案靠左、右侧留给渐变色带」——
   文案列宽约 2/3，剩下的留白由网格渐变填充，而不是再塞一个界面拼贴。
   ⚠️ 保持 `display: block`（不是 grid）：`.st-hero__grid` 这个类名同时被
   SitePublicTopbarTest 用作「顶栏在正文容器之前」的位置锚点，类名与元素不能删。 */
.st-hero__grid { display: block; }
/* 2026-10-07 调整（业务反馈「标题为什么会换行」）：桌面列宽 46rem → 56rem。
   依据：56px 字号下标题全句「夺回品牌在 AI 世界里的话语权。」实测约 850px，
   而 46rem=736px 放不下 → 折行且断点难看。56rem=896px 可容纳整句单行
   （与 `.st-section-head h2` 的 56rem 同值，页面节奏一致）；
   副标题自带 `max-width: 46ch`，不受本改动影响（不会出现超长单行）。 */
.st-hero__copy { max-width: 42rem; }
@media (min-width: 1024px) { .st-hero__copy { max-width: 56rem; } }

/* text-wrap: balance：多行时自动均衡两行长度（窄屏/英文长标题折行时观感更好）。 */
.st-hero__title { margin: 18px 0 0; text-wrap: balance; }
/* 副标题宽度（2026-10-11 收口，业务反馈「标题下面的文字宽度没有撑满」）。

   原实现把 max-width 分散写在 13 个视图的 inline style 里（44/46/48/52rem 四种值），
   那是**两栏 hero**（左文案 + 右视觉）时代的行宽；而内页 hero 现已是全宽单列
   （右上只剩 460×400 的淡描边装饰）→ 窄文案列在大容器里留下大片空白。
   中文尤其明显：66 字的副标题在 832px 下折成 2 行，第二行只剩两三个字。

   🔴 按语言分档，不要一刀切放宽：
   · 拉丁文默认 52rem —— 英文原填充度已达 96%（单词长、折行自然），
     再放宽只会让单行超过 ~100 字符，反而难读；
   · 中文 76rem —— 一行可容纳约 75 个汉字。取值依据（真机逐页实测每行字数）：
     现有中文副标题最长 79 字（/methodology），其余集中在 24~70 字；
     76rem(1216px) 让**70 字以内的一行放下**（原先 66 字的在 52rem 下折成 68+2，
     一个「谈。」独占第二行，即业务反馈的观感来源）；79 字那条仍折两行（71+8），
     第二行有 8 字、不是孤字行，可接受。
     ⚠️ 不再往上加：78 字/行已接近容器上限（1336px），且中文行宽越宽回扫越难。
   ⚠️ 用 `html[lang="zh-CN"]`（layout 输出 zh-CN / en）——与顶部导航的语言规则同一写法。
   ✅ 同时给 `text-wrap: pretty`（2026-10-11 加）：多行时避免最后一行只剩一两个词。
      英文页实测有「97 字符 + 8 字符」这种孤字行（如 /trust），中文页也同理
      （/methodology 的 79 字折成 71+8）。`pretty` 只调整**最后一行的断行位置**、
      不改宽度（宽度由上面的 max-width 决定），且浏览器不支持时自动忽略（渐进增强）。
   ⚠️ 各页原先内联的 max-width 必须删除：元素 inline 优先级高于本规则，
      留着会让"收口"变成空转（页面仍按旧的 46rem 渲染）。
   ⚠️ 宽度值走 `--st-hero-sub-max` 变量：居中排版区块（CTA）有自己的窄行宽，
      靠覆写这一个变量即可，**不必再和各页竞争选择器权重**
      （`html[lang="zh-CN"] .st-hero__sub` 是 (0,2,1)，用普通类去压它压不住——
        这是个"以权重大小定胜负、写错了也不报错"的坑，变量法一次绕开）。 */
.st-hero__sub { margin: 18px 0 0; max-width: var(--st-hero-sub-max, 52rem); font-size: 1.0625rem; line-height: 1.65; color: var(--st-ink-2); text-wrap: pretty; }
html[lang="zh-CN"] .st-hero__sub { max-width: var(--st-hero-sub-max, 76rem); }
.st-hero__meta { margin-top: 26px; display: flex; flex-wrap: wrap; gap: 10px 22px; font-size: .8125rem; color: var(--st-ink-mute); }
.st-hero__meta b { color: var(--st-ink); font-weight: 500; }

/* ---------------------------------------------------------------------------
   6. 按钮：全部胶囊形（9999px）
   🔴 2026-10-10 暗色重设计：主色由「深靛蓝填充 + 白字」改为
   「**青绿→天蓝渐变填充 + 深墨绿字**」（demo 的原型）。
   ⚠️ 字色必须走 --st-on-gradient（深），不要用 --st-on-primary（那是给深色面板的白字）；
   反过来，hover 在暗色体系下是**提亮**而不是压深（压深在亮色按钮上会发灰发脏）。 */
.st-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: 8px 16px;
    border: 1px solid transparent;
    border-radius: var(--st-r-pill);
    font-family: var(--st-font);
    font-size: .875rem;
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
    transition: background .16s ease, border-color .16s ease, color .16s ease, box-shadow .16s ease, transform .16s ease, opacity .16s ease;
}
.st-btn--lg { padding: 12px 22px; font-size: .9375rem; }
/* 2026-10-25 修移动端溢出：长文案按钮（如「查看代理商合作协议（模板）」）
   在 375 宽下 nowrap 撑到 392px → 整页横向滚动。
   窄屏允许换行；桌面维持单行（nowrap 是默认审美，只在小屏放开）。 */
@media (max-width: 639.98px) {
    .st-btn { white-space: normal; }
    .st-btn--lg { padding: 12px 18px; }
}
.st-btn--block { width: 100%; }

/* 每个版块唯一的填充按钮（全站主 CTA）—— 渐变填充 + 品牌辉光。 */
.st-btn--primary {
    background: var(--st-grad);
    color: var(--st-on-gradient);
    border-color: transparent;
    box-shadow: 0 4px 14px rgba(69, 187, 251, .22);
}
.st-btn--primary:hover {
    opacity: .92;
    box-shadow: 0 6px 20px rgba(69, 187, 251, .38);
    transform: translateY(-1px);
}
.st-btn--primary:active { transform: translateY(0); opacity: 1; }

/* 次级：描边胶囊（暗色下描边用品牌色，文字同色）。 */
.st-btn--secondary {
    background: transparent;
    color: var(--st-primary);
    border-color: rgba(69, 187, 251, .45);
}
.st-btn--secondary:hover { background: rgba(69, 187, 251, .10); border-color: var(--st-primary); }

/* 三级：安静按钮（透明底 + 极细描边）——暗色下靠描边显形，不能给填充底
   （给了就与页面底糊在一起，看不出是按钮）。 */
.st-btn--quiet {
    background: transparent;
    color: var(--st-ink);
    border-color: var(--st-hairline-strong);
}
.st-btn--quiet:hover { border-color: var(--st-primary); color: var(--st-primary); }

/* 「深色底上的按钮」：本变量语义在暗色体系下**反转为白底按钮**
   （页面本身已暗，要跳出来就得用亮填充）——它与 --st-ghost-dark 一对：
   前者是实心白（强），后者是透明描边（弱）。 */
.st-btn--on-dark {
    background: #ffffff;
    color: var(--st-canvas);
    border-color: transparent;
}
.st-btn--on-dark:hover { background: rgba(255, 255, 255, .88); }

.st-btn--ghost-dark {
    background: transparent;
    color: var(--st-on-primary);
    border-color: rgba(255, 255, 255, .32);
}
.st-btn--ghost-dark:hover { border-color: rgba(255, 255, 255, .6); }

.st-cta-row { display: flex; flex-wrap: wrap; gap: 12px; }

/* ── 卡片底部 CTA 对齐（.st-cta-row--bottom，2026-10-13）─────────────────────
   用途：多张等高卡片并排时，让各自的 CTA 落在**同一水平线**上。

   ## 缺陷形态（定价页实测）
   四张档位卡等高（grid stretch，均 456px），但 CTA 之前的行数不等：
   年付价行只在前三档有、企业版还多一行定位短句 →
   四张卡的按钮纵向位置 276 / 301 / 347 / 383px，**相差 107px**。
   并排看过去按钮像"随手放的"——定价区最显眼的版式缺陷。

   ## 为什么必须先给卡片开 flex
   `.st-feature` 原本是 `display: grid; align-content: start` —— 在 grid 布局里
   `margin-top: auto` **不产生**"吸底"效果（那需要 `align-self`/`grid-row` 配合，
   且 `align-content: start` 会把所有行压到顶部，auto 外边距没有可分配的自由空间）。
   故本规则把卡片切成 `flex column`：`align-content: start` 由
   `justify-content: flex-start` 等价替代（主轴起点对齐），
   而 CTA 的 `margin-top: auto` 获得全部剩余空间 → 吸底。
   ⚠️ 只在**带 --bottom 的卡片**上启用（`:has()` 选择，Chromium 105+/Safari 15.4+）：
      其他卡片的 CTA 与内容挨着是正常的（内容与按钮是一个整体），
      统一吸底会在单卡场景下把按钮推得离正文很远。
      `:has()` 不被支持时本规则整体失效 → 退回原有的"跟着内容排"（无害降级）。

   ## 与 grid 版 `.st-feature--even` 的区别
   `--even`（首页工具卡）用 `flex-direction: column` + `> :last-child { margin-top: auto }`
   达到同一效果。两者可以合并，但 `--even` 作用于整个卡片，
   而本类只作用于 CTA 行 —— 粒度不同，且 `--even` 已在多处使用，不动它。 */
@supports selector(:has(*)) {
    .st-feature:has(> .st-cta-row--bottom) {
        display: flex;
        flex-direction: column;
        justify-content: flex-start;
        /* 等宽卡片下 grid 的 gap 语义要保留（.st-feature 声明了 gap: 14px）。 */
        gap: 14px;
    }
    .st-cta-row--bottom {
        margin-top: auto;
        /* 🔴 统一最小高度：让"1 个按钮"的卡与"2 个按钮"的卡 CTA 区同高。
           实测企业版只有 1 个按钮（CTA 区 53px）而其余三档 2 个（98px）——
           仅靠吸底只能对齐**底部**，按钮顶部仍差 45px（347 vs 392）。
           给统一 min-height 后四张卡的按钮顶/底完全落在同一线（实测 383/418 全等）。
           ⚠️ 98px 不是拍脑袋：= 两个 .st-btn 高度（约 34px × 2）
              + 行内 gap 10px + 余量，由实测的 2 按钮卡 CTA 高度反推。
             按钮高度若变（改 padding/字号），这个值要跟着复核。 */
        min-height: 98px;
    }
    /* 吸底后与上方内容至少留 18px（原内联的 margin-top: 18px 迁到这里 ——
       内联会覆盖 auto，故必须由 CSS 接管）。 */
    .st-feature:has(> .st-cta-row--bottom) > .st-cta-row--bottom { padding-top: 18px; }
}

/* 文本型链接（带箭头），用于卡片底部「立即体检 →」 */
.st-link-arrow {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    min-height: 28px;
    font-size: .875rem;
    font-weight: 500;
    color: var(--st-primary);
    text-decoration: none;
}
.st-link-arrow:hover { color: var(--st-primary-deep); }
.st-link-arrow::after { content: '→'; transition: transform .16s ease; }
.st-link-arrow:hover::after { transform: translateX(2px); }

/* ---------------------------------------------------------------------------
   7. 卡片
   🔴 2026-10-10 暗色重设计：卡片由「白底 + 投影」改为「**提亮底** + 极细描边」——
   暗色 UI 的层级不靠投影（黑底上投影不可见），靠底色比页面底亮一档。
   --------------------------------------------------------------------------- */
.st-card {
    background: var(--st-canvas-elev);
    border: 1px solid var(--st-hairline);
    border-radius: var(--st-r-lg);
    padding: 32px;
    box-shadow: none;
    /* 2026-10-25 业务要求「左右栏高度对齐」：grid 内的卡片默认拉伸到同行最高
       （grid 的 align-items 默认 stretch），但视图里多处两栏写了
       `style="align-items: start"` 把它压回去了 → 左右卡高度不齐。
       这里在**卡片自身**加 height:100%，即使父级被写成 start，也能对齐。
       ⚠️ 位置敏感：必须在 .st-card--ghost 等变体之前。 */
    height: 100%;
    box-sizing: border-box;
    /* 悬停过渡（与 .st-feature 同值 .2s）—— 原先 .st-card 的 transition 是靠文件尾部
       一条 `.st-card { transition: ... }` 补的（.18s，与 .st-feature 的 .2s 不一致），
       已并入本规则并统一为 .2s（见下方「统一卡片悬停」）。 */
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
/* 浅色系里的「浅蓝灰卡片」在暗色体系里对应**比底色略亮、略带蓝**的一档。
   🔴 顺序敏感：**必须定义在 .st-card 之后**（两者优先级相同，CSS 按"后来者胜"）。
   首版曾写在 .st-card 之前，被 `background: var(--st-canvas)` 整个盖掉 ——
   规则匹配得上、计算值却是白（CDP 排查确认）。改这里时不要往上挪。 */
.st-card--tint {
    /* 🔴 2026-10-12 表面层级重标定：硬编码 `#182031` → `var(--st-canvas-cream)`。
       tint 卡的语义是"比普通卡再亮一点、略带蓝"的那一档；普通卡（.st-card）现在走
       `--st-canvas-elev`（1.244），若 tint 仍停在旧值 1.185，就会**比普通卡还暗** ——
       语义整个反过来，且不报错、只能靠肉眼发现。改走变量后两者关系恒定。 */
    background: var(--st-canvas-cream);
    border-color: rgba(255, 255, 255, .07);
    box-shadow: none;
}
.st-card--tint .st-card__text { color: var(--st-ink-2); }
.st-card--soft { background: var(--st-canvas-soft); box-shadow: none; }
/* 渐变色带卡（暗色重设计：青绿/天蓝辉光）。
   ⚠️ 用 radial-gradient 铺在卡片自身背景上（与 st-card--grad-* 用 ::before 不同）——
   因为这层是**底色**（不是要盖住内容的彩色层），直接做背景更简单，
   且不会引入 `::before` 与内容层级（z-index）那套需要注意的约束。
   ⚠️ 类名保留 `--cream`（视图有引用），语义是"渐变色带"。 */
.st-card--cream {
    background:
        radial-gradient(120% 150% at 2% 0%, rgba(105, 247, 211, .14) 0%, rgba(105, 247, 211, 0) 60%),
        radial-gradient(110% 140% at 98% 100%, rgba(69, 187, 251, .20) 0%, rgba(69, 187, 251, 0) 62%),
        /* 🔴 2026-10-12 表面层级重标定：基底 `#111927`(1.096) → `var(--st-canvas-elev)`(1.244)。
           它是"渐变色带卡"（比普通卡更强调），基底若低于普通卡的 elev 就会倒挂；
           走变量后与 .st-card 同步，叠在其上的青绿/天蓝辉光**未改动**。 */
        var(--st-canvas-elev);
    border-color: rgba(69, 187, 251, .18);
    box-shadow: none;
}
/* 强调卡（"精选档"，如代理商卡 / 主推市场卡）：暗色体系下用**品牌渐变描边**区分，
   而不是浅色系那种"深底反白"（整站已暗，反白已无对比可言）。
   ⚠️ 20+ 处视图用到本类，改这里 = 一次落地。 */
.st-card--dark {
    background:
        linear-gradient(var(--st-canvas-elev), var(--st-canvas-elev)) padding-box,
        var(--st-grad) border-box;
    border: 1px solid transparent;
    color: var(--st-ink);
    box-shadow: none;
}
.st-card--dark h2, .st-card--dark h3, .st-card--dark h4 { color: var(--st-ink); }
.st-card--dark p, .st-card--dark li { color: var(--st-ink-2); }
.st-card--flat { box-shadow: none; }

/* 🔴 2026-10-12 中段字阶补齐：18px/w400 → **20px/w600**。
   两个理由（都有实测数据）：
   ① 它是"16–22px 空洞"的主体 —— 46 张卡片（card__title 13 + feature__title 33）
      此前全落在 18px，与正文 14px 只差 1.29 倍，卡片整体糊成一片灰；
      提到 20px 后与正文形成 1.43 倍，且落进中段字阶。
   ② `font-weight: 400` 原**从未生效** —— 被 `.st-body h3`（(0,1,1)）的 300 静默覆盖，
      而本类 13 处用法全是 `<h3>`（已 grep 核实）。故必须用 `.st-body` 前缀提权。

   🔄 2026-10-11 字重 600 → **400**（业务要求「全站文字偏细，标题也用这种风格」）。
   为什么落在 400 而不是回到 300：
   · 400 是**正文同档**的"正常字重"，读起来不属于"粗"，符合偏细调性；
   · 300 对这个 20px 中文标题会笔画发虚 —— 它是**功能性文字**（卡片的扫读锚点），
     不是装饰。中文可读性下限由本项目反复实测确认过（见 .st-eyebrow 的 10px→12px、
     .st-feature__title 的历史注释）。
   ⇒ 卡片标题的层级**改由字号承担**（20px vs 正文 14px = 1.43 倍），不再靠字重。
   ⚠️ 提权那一条**只带 font-weight**，颜色/盒模留给下面那条 ——
      避免重演 `.st-feature--dark` 那次"高权重规则连 color 一起盖掉深色卡白字"的事故。 */
.st-body .st-card__title { font-weight: 400; }
.st-card__title { margin: 0; font-size: 1.25rem; line-height: 1.35; letter-spacing: -.012em; color: var(--st-ink); }
.st-card__text { margin: .75rem 0 0; font-size: .875rem; line-height: 1.75; color: var(--st-ink-mute); }

.st-grid { display: grid; gap: 20px; }
.st-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.st-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.st-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1080px) {
    .st-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .st-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
    .st-grid--2, .st-grid--3, .st-grid--4 { grid-template-columns: minmax(0, 1fr); }
}

/* 特性卡：图标 + 标题 + 说明（首页工具卡/能力卡通用）。
   暗色体系：卡片底比页面底亮一档（--st-canvas-elev）——白卡在深底上会"过曝"。 */
.st-feature {
    display: grid;
    gap: 14px;
    align-content: start;
    padding: 28px;
    background: var(--st-canvas-elev);
    border: 1px solid var(--st-hairline);
    border-radius: var(--st-r-lg);
    box-shadow: none;
    transition: box-shadow .2s ease, transform .2s ease, border-color .2s ease;
}
/* ⚠️ 这里原有 `.st-feature--interactive:hover { -2px + glow + 描边 }`，
   而文件尾部**又定义了一遍**（`-3px + shadow-3`，且没写 border-color）——
   同权重后者胜 ⇒ 实际渲染成「-3px 的位移 + shadow-3 的阴影 + glow 的描边」这种
   **三类来源拼起来的效果**，既不是前者的意图也不是后者的。
   现全站统一为一条规则（见「统一卡片悬停」一节），此处不再单独定义。 */
/* 🔴 顺序敏感：本规则**必须定义在 .st-feature 之后**。
   两者优先级相同（都是单类选择器），CSS 按"后来者胜"生效 ——
   首版把这段写在 .st-feature 之前（在「浅色卡片底」那一节），结果被 .st-feature
   的 `background: var(--st-canvas)` 整个盖掉：规则明明匹配上了（CDP 能查到），
   计算值却是白色（实测排查确认）。**改这里时不要往上挪。** */
.st-feature--tint {
    /* 🔴 2026-10-12：同 .st-card--tint —— 硬编码改为变量，保证"tint 比普通卡亮"的关系恒定。 */
    background: var(--st-canvas-cream);
    border-color: rgba(255, 255, 255, .07);
    box-shadow: none;
}
/* ⚠️ 这里原有 `.st-feature--tint:hover { background: #1c2537 }` —— 这类卡悬停时
   **只有底色变亮**、不上浮也不发光，而同版块里的普通卡什么都不动。
   这正是业务说的「有的有效果、有的没有」的另一种形态（同一屏内两种悬停反馈）。
   现删除：所有卡片的悬停反馈统一由文件末「统一卡片悬停」一节提供
   （上浮 + 辉光 + 描边），不再存在"只变底色"的第三种表现。 */
/* 强调特性卡（用于「核心平台」首尾两环（监测/归因）与定价 Elite 档）。
   🔴 为什么是 CSS 类（原来是内联 style，两边都没生效）：
   旧写法 `<h3 ... {{ $x ? 'style="color:#fff"' : '' }}>` —— Blade 的 `{{ }}` 会转义引号，
   输出成 `style=&quot;color:#fff&quot;`，浏览器解析出的属性值是 `"color:#fff"`（带引号的字面量）
   → **CSS 解析失败、整条声明被丢弃**。三条内联色全部没生效（深底墨字"看不清"的直接原因）。
   这类「整段属性经 {{ }} 输出的内联样式」是结构性隐患（转义不报错、只是失效），
   故改为类名 + 本文件显式配色；守卫测试禁止再写回那种形态。

   🔴 2026-10-10 暗色重设计：底色由「深海军蓝」改为**品牌渐变描边 + 提亮底** ——
   整站已是暗色，原先的深底卡片与页面底只差一点点亮度、几乎看不出是"精选档"。
   现用 1px 的渐变边框（border-image 手法）把强调卡框出来，这是暗色 UI 里
   表达"这一张不一样"最有效且不刺眼的方式。 */
.st-feature--dark {
    background:
        linear-gradient(var(--st-canvas-elev), var(--st-canvas-elev)) padding-box,
        var(--st-grad) border-box;
    border: 1px solid transparent;
    box-shadow: 0 0 0 1px rgba(69, 187, 251, .06);
    color: var(--st-ink);
}
/* 轻卡片变体（2026-10-11 设计铺开）：去底色只留描边——与 .st-card--ghost 同一纪律
   （盒子是例外）。⚠️ 必须定义在 .st-feature--tint 之后（同权重靠源码顺序，
   与 .st-card--tint 的顺序敏感约定一致）。 */
.st-feature--ghost {
    background: transparent;
    border-color: var(--st-hairline-strong);
    box-shadow: none;
}

/* 图标磁贴（2026-10-11 设计铺开：内页 icon 点缀的统一容器）。
   首页用 icon 点缀而内页几乎没有 —— 本类给内页的链行/轻卡片一个统一的图标位。
   ⚠️ 尺寸 38px、品牌色低透明度底——与 .st-feature__icon 同语言但独立定义，
      不挂在 .st-feature 下（链行/定义行/轻卡片都要用，不该被组件名绑定）。 */
.st-ico-tile {
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    border-radius: 10px;
    background: rgba(69, 187, 251, .10);
    border: 1px solid rgba(69, 187, 251, .22);
    color: var(--st-primary);
    flex-shrink: 0;
}
.st-ico-tile svg, .st-ico-tile i { width: 18px; height: 18px; }
/* 中性变体：给"痛点"这类负面栏位（与 --muted 眉标同一语义） */
.st-ico-tile--muted {
    background: rgba(255, 255, 255, .05);
    border-color: rgba(255, 255, 255, .14);
    color: var(--st-ink-mute);
}
.st-feature--dark .st-feature__icon {
    background: rgba(255, 255, 255, .10);
    border-color: rgba(255, 255, 255, .18);
    color: var(--st-on-primary);
}
.st-feature--dark .st-feature__title { color: var(--st-ink); }
.st-feature--dark .st-feature__text { color: var(--st-ink-mute); }
.st-feature--dark .st-caption { color: var(--st-ink-mute); }
.st-feature--dark .st-link-arrow { color: var(--st-primary); }
.st-feature--dark .st-link-arrow:hover { color: var(--st-primary-deep); }
.st-feature--dark .st-num { color: var(--st-ink); }
.st-feature--dark strong { color: var(--st-ink); }
/* 等高卡片 + CTA 底部对齐（2026-10-06 v7，业务方反馈「4 个面板里的按钮最好在一条线上」）。
   `.st-feature` 是 grid + align-content:start，内容少的卡 CTA 会跟着文本停在半空；
   改 flex column 后 `margin-top:auto` 把**最后一个子元素**（通常是 CTA 链接/按钮）
   推到底部 —— 同一行的卡片等高（grid 默认 stretch），按钮自然成一条线。
   ⚠️ 用 `> :last-child` 而不是指名类：卡片末元素有 st-link-arrow / st-btn 两种形态。 */
.st-feature--even { display: flex; flex-direction: column; }
.st-feature--even > :last-child { margin-top: auto; }
.st-feature__top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* 视觉锚点序号（2026-10-06 评审 P1 "视觉层级差异化"）：
   独有能力版块的卡片与全站其它卡片同构（眉标+标题+正文+列表），信息够但**视觉权重平**，
   读者扫过时没有"进入点"。给这类卡片加一个大号细字重序号（editorial 风格，
   Stripe / Linear 的 section 锚点手法）——只用字号与色相区分，不加任何新色。 */
.st-anchor-num {
    display: block;
    font-size: 2.5rem;
    font-weight: 300;
    line-height: 1;
    letter-spacing: -.04em;
    font-variant-numeric: tabular-nums;
    /* 暗色下用品牌色低透明度（原 rgba(83,58,253,.32) 在深底上几乎不可见）。 */
    color: rgba(69, 187, 251, .38);
    margin-bottom: 18px;
}
.st-feature__icon {
    width: 34px; height: 34px;
    display: grid; place-items: center;
    border-radius: var(--st-r-md);
    background: rgba(69, 187, 251, .10);
    border: 1px solid rgba(69, 187, 251, .22);
    color: var(--st-primary);
}
/* 🔴 2026-10-11：`.st-anchor-num` 用在**小卡**里（定价档位卡）时，
   `.38` 的透明度在 `#182031` 底上约 2.9:1 —— 作为"视觉锚点"太淡，起不到作用。
   这里给 `--tint` 卡内的序号提一档（不改全局值：独有能力版块的大卡用 `.38` 是对的，
   那里的卡更高、留白更多，序号本就该更含蓄）。
   ⚠️ 用 `.38` → `.55`，配合已有的 2.5rem 字号，在深色 tint 底上约 4.6:1（达 AA）。 */
.st-feature--tint .st-anchor-num { color: rgba(69, 187, 251, .55); }

/* 🔴 2026-10-06 v7：字号 17px → 18px、字重修正为 500。
   根因（实测发现）：本规则写的 font-weight: 400 **从未生效** —— 被 `.st-body h3`
   （选择器权重 0,1,1 > 本规则的 0,1,0）的 `font-weight: 300` 静默覆盖，
   卡片标题实际一直以 300 细字重渲染。中文在 300 字重下笔画发虚（"看不清"），
   故用 `.st-body .st-feature__title`（0,2,0 胜出）显式钉住 500。
   ⚠️ 300 字重是 **display 级大标题**的排版签名（见 .st-display-* 注释），
   不适用于 18px 级别的卡片标题 —— 别再把这条削弱回去。

   🔴 2026-10-06 再修（深色卡标题"看不清"）：上面那条高权重规则**当初连 color 一起写了**，
   于是它也盖掉了深色卡的白字（.st-card--dark h3 权重 0,1,1 < 0,2,0）——
   深底上的标题被涂成墨色，业务方报「根本看不清楚」。
   现拆成三条职责单一的规则（加规则别再把 color 塞进高权重那条）：
     ① 基础：盒模/字号/颜色（0,1,0，可被深色变体覆盖）
     ② 高权重：**只修正字重**（0,2,0，压 .st-body h3 的 300）
     ③ 深色变体：`.st-feature--dark` 覆写颜色（0,2,0，与②无冲突因为②不管颜色） */
/* 🔴 2026-10-12 中段字阶补齐：与 `.st-card__title` 统一规格 **20px/w400**。
   两者在页面上是同级元素（卡片标题），此前各有一套值（18px/w500 vs 18px/w400）
   属于历史分叉；现合流，改一处即两处生效。
   🔄 2026-10-11 字重 500/600 → **400**（业务要求「全站文字偏细」，卡片标题也用同一风格）。
   完整理由见 `.st-body .st-card__title` 的注释：400 = 正文同档的正常字重，
   不属"粗"；层级由字号（20px vs 正文 14px）承担。
   ⚠️ 提权那一条**只带 font-weight**（历史事故：连 color 一起写会盖掉深色卡的白字）。 */
.st-body .st-feature__title { font-weight: 400; }
.st-feature__title { margin: 0; font-size: 1.25rem; line-height: 1.35; letter-spacing: -.012em; color: var(--st-ink); }
.st-feature__text { margin: 0; font-size: .875rem; line-height: 1.75; color: var(--st-ink-mute); }
.st-feature__list { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.st-feature__list li { position: relative; padding-left: 16px; font-size: .8125rem; line-height: 1.65; color: var(--st-ink-mute); }
.st-feature__list li::before { content: ''; position: absolute; left: 0; top: .55em; width: 6px; height: 6px; border-radius: 2px; background: var(--st-primary-subdued); }

/* ---------------------------------------------------------------------------
   8. 标签 / 徽标 / 引用条
   --------------------------------------------------------------------------- */
.st-tag {
    display: inline-flex; align-items: center; gap: .375rem;
    padding: 3px 9px;
    border-radius: var(--st-r-pill);
    font-size: .6875rem;
    font-weight: 500;
    line-height: 1.3;
    background: rgba(69, 187, 251, .10);
    color: var(--st-primary);
    border: 1px solid rgba(69, 187, 251, .20);
}
.st-tag--neutral { background: var(--st-canvas-soft); color: var(--st-ink-mute); border-color: var(--st-hairline); }
/* 🔴 语义色在暗色体系下必须**反相**：浅底用的深绿 #1c7a52 在深底上对比不足 ~2:1，
   一律换成高亮版（前景色提亮、背景保持低透明度）。 */
.st-tag--ok { background: rgba(47, 181, 124, .14); color: #6ee7b7; border-color: rgba(47, 181, 124, .28); }
.st-tag--ruby { background: rgba(234, 34, 97, .14); color: #fda4af; border-color: rgba(234, 34, 97, .26); }
.st-tag--on-dark { background: rgba(255, 255, 255, .1); color: var(--st-on-primary); border-color: rgba(255, 255, 255, .16); }

/* ---------------------------------------------------------------------------
   8.1 语义提示块（错误 / 成功 / 提醒）

   2026-10-11 收口：这四处提示在浅色时代各自手写内联色（深玫瑰 #b8174b、深棕
   #7a5220、深绿 #1c7a52），深色翻转后**全部漏改** —— 深色值压在深底上对比不足
   ~2:1，业务方实测报「提示是粉红色的、在深色背景上不醒目」。

   🔴 页面不得再手写语义色（内联 style 也一律用这些类）：单点修改才管得住
      「暗色下语义色必须反相」这条规则。色值只引用 §2 的 --st-*-ink 令牌。
   --------------------------------------------------------------------------- */
.st-alert {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    padding: 14px 16px;
    border-radius: var(--st-r-lg);
    border: 1px solid var(--st-hairline);
    background: rgba(255, 255, 255, .04);
    color: var(--st-ink-2);
    font-size: .875rem;
    line-height: 1.6;
}
.st-alert__icon { flex-shrink: 0; margin-top: .125rem; }
/* 居中变体（落地页的错误/限流提示是居中的窄条）：block 排版 ——
   内容是「图标+文字」的行内流（不是 flex 子项），且下方可能嵌套引导卡（需整宽）。 */
.st-alert--center { display: block; text-align: center; }
/* 多行堆叠变体（如逐条列出的错误清单）：各行独立成行，不并排。 */
.st-alert--stack { display: block; }

.st-alert--danger {
    border-color: rgba(234, 34, 97, .30);
    background: rgba(234, 34, 97, .10);
    color: var(--st-danger-ink);
}
.st-alert--ok {
    border-color: rgba(47, 181, 124, .30);
    background: rgba(47, 181, 124, .10);
    color: var(--st-ok-ink);
}
.st-alert--warn {
    border-color: rgba(251, 224, 65, .28);
    background: rgba(251, 224, 65, .08);
    color: var(--st-warn-ink);
}
/* 提示块内的正文：保持中性（只有标题/图标用语义色），否则整块高饱和色读起来刺眼。 */
.st-alert__body { color: var(--st-ink-2); }

/* 品牌色调面板（浅色时代的靛蓝 rgba(83,58,253,.04/.05) 在暗色底上不可见）。
   用于「阶段性结果 / 推荐码 / 方案提示」这类非语义的强调容器。 */
.st-panel-brand { border: 1px solid rgba(69, 187, 251, .20); background: rgba(69, 187, 251, .06); }
.st-panel-ok { border: 1px solid rgba(47, 181, 124, .28); background: rgba(47, 181, 124, .10); }

/* 编号步骤圆点（注册 / 找回密码的多步表单）：只收口颜色，尺寸由各页自定
   （注册 20px、找回密码 24px）。旧值 rgba(83,58,253,.1) 是浅色时代的靛蓝，
   在深底上几乎不可见。 */
.st-step-num {
    background: rgba(69, 187, 251, .14);
    color: var(--st-primary-deep);
}

/* ---------------------------------------------------------------------------
   8.2 本机检测记录面板（免费检测页右列，2026-10-11）

   记录只存在访客浏览器（localStorage），未登录即可切换查看。
   面板在**报告之上**、卡片式，与页面既有卡片语言（.st-card 的底/描边/圆角）一致，
   不引入新的色相——色值一律走 §2 令牌。
   --------------------------------------------------------------------------- */

/* 两列**顶部对齐**（2026-10-11 业务反馈「左侧比右侧低一些」）。
   成因：左列首个块（表单或提示条）带 `mt-8`（32px，单列时代用来与标题区拉开距离），
   而右列首块没有 → 左列整体低 32px。现在与标题区的距离统一由外层 grid 的 mt-8 提供，
   列内首块的 `mt-8` 归零。
   ⚠️ 归零只作用于**首个子元素**：同列后续块的 mt-8（块间距）必须保留 ——
      否则表单与下方自测卡会粘连（本规则的 :first-child 限定正是为此）。
   ⚠️ 特异性 (0,2,0) 高于 Tailwind `.mt-8` 的 (0,1,0)，无需 !important；
      但如果哪天有人把 mt 写成行内 style，这里会失效 —— 那时改 inline 为 class 即可。 */
.st-fc-col > :first-child { margin-top: 0; }

.st-fc-history {
    background: var(--st-canvas-elev);
    border: 1px solid var(--st-hairline);
    border-radius: var(--st-r-lg);
    padding: 20px;
}
.st-fc-history__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.st-fc-history__title {
    font-size: .9375rem;
    font-weight: 600;
    color: var(--st-ink);
}
.st-fc-history__hint {
    margin-top: 6px;
    font-size: .75rem;
    line-height: 1.5;
    color: var(--st-ink-mute);
}
/* 原生 select 已由 .st-select 统一样式；这里只负责它上方标签与间距。 */
.st-fc-history__label {
    display: block;
    margin-top: 14px;
    font-size: .75rem;
    font-weight: 500;
    color: var(--st-ink-2);
}
.st-fc-history__actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 10px;
}
/* 删除按钮：危险语义走反相令牌（见 §8.1 的同一条纪律）。 */
.st-fc-history__delete {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 5px 10px;
    border-radius: var(--st-r-md);
    border: 1px solid rgba(234, 34, 97, .28);
    background: rgba(234, 34, 97, .08);
    color: var(--st-danger-ink);
    font-size: .75rem;
    line-height: 1.3;
    cursor: pointer;
}
.st-fc-history__delete:hover {
    background: rgba(234, 34, 97, .16);
}
/* 「当前查看」标记：中性而非语义色——它不是状态告警，只是说明当前选中的是哪条。 */
.st-fc-history__current {
    font-size: .75rem;
    color: var(--st-ink-mute);
}
/* 空态：右侧默认就是这样一块，不要写成"错误"观感（用户什么都没做错）。 */
.st-fc-empty {
    text-align: center;
    padding: 36px 24px;
}
.st-fc-empty__title {
    font-size: .9375rem;
    font-weight: 600;
    color: var(--st-ink);
}
.st-fc-empty__hint {
    margin-top: 8px;
    font-size: .8125rem;
    line-height: 1.6;
    color: var(--st-ink-mute);
}

.st-chip {
    display: inline-flex; align-items: center;
    /* `gap` 供「图标 + 名字」组合用（2026-10-11 起 chip 内带品牌图标）。
       此前 chip 是纯文字、无 gap，加了图标后必须补 —— 否则图标与文字贴死。
       ⚠️ 纯文字 chip 不受影响（单个子元素时 gap 不产生任何间距）。 */
    gap: 7px;
    padding: 5px 11px;
    border-radius: var(--st-r-pill);
    border: 1px solid var(--st-hairline);
    background: rgba(255, 255, 255, .04);
    font-size: .75rem;
    color: var(--st-ink-2);
}
/* 国内/海外两组芯片：暗色下用品牌色与暖金作区分（原为浅色系「靛蓝 / 土黄」）。 */
.st-chip--cn { border-color: rgba(69, 187, 251, .30); color: #8fd8ff; background: rgba(69, 187, 251, .10); }
.st-chip--os { border-color: rgba(251, 224, 65, .28); color: #fbe041; background: rgba(251, 224, 65, .08); }

/* 引擎品牌图标（2026-10-11）：chip 内「图标 + 引擎名」。
   ## 为什么加
   业务反馈站点基本没有图（不能放客户 logo / 团队照片 / 系统截图），
   希望用大模型矢量 icon 点缀 —— 这是零流量成本、且**不涉及效果承诺**的视觉增量。
   ## 样式约定
   · `fill: currentColor`（组件内写死）→ 图标自动跟随 chip 的文字色，**不引入新色值**；
   · `gap` 由 .st-chip 的 `gap: 7px` 提供（此前 chip 是纯文字、无 gap，见下）；
   · `flex-shrink: 0`：窄屏换行时图标不能被压扁（SVG 在 flex 里默认可被压缩变形）。
   ⚠️ 单色渲染是 simple-icons 的既有形态，**不属于**对商标的改动
      （商标指示性使用要求"不得改动图标本身"，指不翻转/不变形/不加特效）。
   ⚠️ 字母标兜底：智谱 GLM 与文心一言在 simple-icons 里无官方图标（已逐一试过
      zhipuai/glm/chatglm/wenxin/ernie 等 slug 均 404）。此时渲染首字符而非伪造 logo。 */
.st-engine-ico { flex-shrink: 0; display: block; }
/* 字母标兜底（智谱 GLM / 文心一言无官方图标）。
   🔴 2026-10-11 二次修正：首版用 `background: currentColor` + `-webkit-text-fill-color:
   transparent` 想做出"实底白字"，结果渲染成**一个纯色小方块**（实测截图确认：
   字形完全看不见）—— 因为 transparent 把字也一起抹掉了，背景色又没有字形可挖。
   现改为**描边 + 字形同色**的克制形态：边框用 currentColor 系不加粗，字形用 currentColor。
   这样它看起来像"文字标记"，与旁边 9 个实心品牌图标**在形态上有区分**（这是有意的：
   它不是任何品牌的 logo，不该伪装成 logo）。 */
.st-engine-ico--mono {
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 3px;
    border: 1px solid currentColor;
    opacity: .75;
    line-height: 1;
    font-weight: 600;
    font-family: var(--st-font);
    overflow: hidden;
}

/* 数字带：四列事实陈述。
   🔴 2026-10-06 v7 修复两个问题（业务方反馈「字体太小、一点儿都不明显」「数字左右居中」）：
   ① **类名错配（静默失效）**：HTML 写的是 `pub-stat__v`，而本文件定义的是 `.st-stat__v` ——
      两者从未匹配上，数字一直以 body 继承的 15px 渲染（实测确认），完全没吃到本规则的
      clamp(2rem…2.5rem)。属 `--st-navy` 同族缺陷。现把 `pub-stat__v` 并入选择器
      （HTML 类名被 SiteMarketingFactsTest 用于「数字现算」守卫，不能改 HTML）。
   ② 字号按业务方要求再放大一档（clamp 上限 2.5rem → 3rem，44→48px），
     并让数字与标签**水平居中**（大号数字带居中是营销页数字条的通行排法，
     左对齐时四个数字的视觉重量散在左缘）。 */
/* ⚠️ 列数走 `--st-stats-cols` 变量（2026-10-11 加）：默认 4 列，调用处传 3 即可。
   背景：3 项内容放在 4 列网格里会**右侧空一整格**——
   技术域全景页与解决方案页的 3 项数字带都因此看着"没铺满"（业务反馈）。
   ⚠️ 不要给 `.st-stats` 写死 `grid-template-columns`，媒体查询里的 2 列规则
      优先于本变量（源码顺序在后），小屏行为不受影响。 */
.st-stats { display: grid; grid-template-columns: repeat(var(--st-stats-cols, 4), minmax(0, 1fr)); gap: 1px; background: var(--st-hairline); border-block: 1px solid var(--st-hairline); }
@media (max-width: 860px) { .st-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.st-stat { background: var(--st-canvas); padding: 32px 28px; display: grid; gap: 8px; align-content: start; justify-items: center; text-align: center; }
.st-stat__v,
.pub-stat__v { font-size: clamp(2.25rem, 4vw, 3rem); font-weight: 400; letter-spacing: -.02em; color: var(--st-ink); font-variant-numeric: tabular-nums; line-height: 1; }
.st-stat__l { font-size: .875rem; line-height: 1.5; color: var(--st-ink-mute); max-width: 24ch; }

/* 数字带渐变底（暗色重设计：青绿/天蓝辉光横条）。
   与「AI 可见性监测」卡（.st-card--grad-a）**用同一组色标** —— 同一视觉语言。

   ⚠️ 三个实现要点（都是不这么写就"看着不对"的地方）：
   ① 渐变铺在**容器**上、格子改透明 —— 原实现是「容器铺 hairline 色 + 格子铺白底」，
      只给容器加渐变的话会被白底格子整个盖住（等于没改）；
   ② 分隔线要从「gap + 容器底色」换成**格子的 inset 描边** ——
      格子变透明后，原来靠 1px gap 露出的 hairline 会露出渐变，分隔线就消失了；
   ③ 圆角与裁切由调用处的 inline style 负责（保持既有用法不变）。 */
.st-stats--grad {
    gap: 0;
    /* ⚠️ 色斑的**纵向半径放到 220%**（远大于容器高度）让它横向铺满：
       数字带只有 ~112px 高、宽高比 10.9:1，常规百分比色斑会被"压扁"在两端。
       暗色版本同样适用这条几何约定，只是色相换成青绿/天蓝、收口从"收白"改为"收暗"。 */
    background:
        radial-gradient(58% 220% at 0% 30%, rgba(105, 247, 211, .16) 0%, rgba(105, 247, 211, 0) 68%),
        radial-gradient(58% 220% at 100% 26%, rgba(69, 187, 251, .30) 0%, rgba(69, 187, 251, 0) 70%),
        radial-gradient(46% 200% at 52% 0%, rgba(69, 187, 251, .12) 0%, rgba(69, 187, 251, 0) 72%),
        var(--st-canvas-elev);
    border-block: 0;
}
.st-stats--grad .st-stat {
    background: transparent;
    box-shadow: inset -1px 0 0 rgba(255, 255, 255, .10);
}
/* 每行最后一个格子不要右分隔线：桌面 4 列 → 第 4 个；窄屏 2 列 → 偶数位（2、4） */
.st-stats--grad .st-stat:nth-child(4) { box-shadow: none; }
/* 3 项带（--st-stats-cols:3）：第 3 个是行尾，同样去右线——
   桌面 3 列时它是本行末格；窄屏 2 列时它独占第二行（也是行尾）。
   ⚠️ 用 :has() 限定"共 3 项"，否则 4 项带里第 3 个会被误去线（它不是行尾）。
   :has() 不支持时只多一条竖线，无功能影响。 */
.st-stats--grad:has(> .st-stat:last-child:nth-child(3)) .st-stat:nth-child(3) { box-shadow: none; }
@media (max-width: 860px) {
    .st-stats--grad .st-stat:nth-child(even) { box-shadow: none; }
}
/* 渐变底上的文字对比：数值用实色（渐变字压在渐变底上会糊成一团），标签亮一档 */
.st-stats--grad .st-stat__v { color: var(--st-ink); }
.st-stats--grad .st-stat__l { color: var(--st-ink-2); }

/* 口径表（左标签 / 右数值）：数据可信区块 */
.st-caliber { display: grid; gap: 8px; margin: 20px 0; }
.st-caliber__row {
    display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
    padding: 11px 14px;
    border-radius: var(--st-r-sm);
    background: var(--st-canvas);
    border: 1px solid var(--st-hairline);
}
.st-caliber__k { font-size: .8125rem; color: var(--st-ink-mute); }
.st-caliber__v { font-size: .9375rem; font-weight: 500; color: var(--st-primary); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }

/* 证据链清单 */
.st-checklist { display: grid; gap: 12px; margin: 18px 0 0; padding: 0; list-style: none; }
.st-checklist li { position: relative; padding-left: 24px; font-size: .875rem; line-height: 1.7; color: var(--st-ink-2); }
.st-checklist li::before {
    content: '✓'; position: absolute; left: 0; top: 0;
    color: var(--st-primary); font-size: .8125rem; font-weight: 700;
}
/* 🔴 2026-10-11 痛点变体：标记由 `✓` 改为**中性短横**。
   缺陷（语义错误，不只是观感）：`✓` 的含义是"已完成 / 正确"，而痛点列写的是
   「竞品的单品被一个个点名推荐，你的产品线查无此人」这类**问题**——
   在麻烦事前面打一个绿色对勾，等于在庆祝坏消息。
   现：痛点用中性短横（灰）、解法仍用 ✓（品牌色），
   "灰横 → 蓝勾"本身就是"问题 → 已解决"的叙事。
   ⚠️ 与基础规则同为 (0,1,1)，靠源码顺序取胜，必须写在其后。
   ⚠️ 只加变体、不改基础规则：首页与信任页也用 `.st-checklist`，
     那两处列的是**能力/资质**，`✓` 在那里是正确的。 */
.st-checklist--pain { gap: 14px; }
.st-checklist--pain li { padding-left: 22px; }
.st-checklist--pain li::before {
    content: '';
    left: 0; top: .72em;
    width: 10px; height: 2px;
    border-radius: 2px;
    background: var(--st-ink-mute-2);
}

/* 进度条（对照/占比）：细线 + 等宽数字 */
.st-bars { display: grid; gap: 18px; }
.st-bar__label { display: flex; justify-content: space-between; gap: 12px; font-size: .8125rem; color: var(--st-ink-mute); margin-bottom: 8px; }
.st-bar__track { height: 10px; border-radius: var(--st-r-pill); background: var(--st-canvas-soft); border: 1px solid var(--st-hairline); overflow: hidden; }
.st-bar__fill { height: 100%; border-radius: var(--st-r-pill); }
.st-bar__fill--before { background: var(--st-hairline-strong); }
.st-bar__fill--after { background: var(--st-grad); }

/* ---------------------------------------------------------------------------
   9. 产品界面拼贴（「看真实产品」叙事）
   暗色体系：拼贴本体是**提亮面板**（比页面底亮一档），轮廓靠描边而非投影。
   --------------------------------------------------------------------------- */
.st-mockup {
    background: var(--st-canvas-elev);
    border: 1px solid var(--st-hairline);
    border-radius: var(--st-r-xl);
    box-shadow: var(--st-shadow-3);
    overflow: hidden;
}
.st-mockup__bar {
    display: flex; align-items: center; gap: 8px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--st-hairline);
    background: rgba(255, 255, 255, .03);
}
.st-mockup__dot { width: 9px; height: 9px; border-radius: 50%; background: rgba(255, 255, 255, .24); }
.st-mockup__title { margin-left: 8px; font-size: .75rem; color: var(--st-ink-mute); }
.st-mockup__body { padding: 20px; display: grid; gap: 18px; }
.st-mockup__foot {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px;
    padding: 14px 20px; border-top: 1px solid var(--st-hairline); background: rgba(255, 255, 255, .03);
    font-size: .75rem; color: var(--st-ink-mute);
}

/* 更深一档的界面拼贴（原「深色应用壳」）：在暗色体系里它比卡片更深，
   用于"产品后台"的对比呈现。 */
.st-mockup--dark {
    background: #05080f;
    border-color: rgba(255, 255, 255, .10);
}
.st-mockup--dark .st-mockup__bar { background: rgba(255, 255, 255, .04); border-color: var(--st-dark-hairline); }
.st-mockup--dark .st-mockup__dot { background: rgba(255, 255, 255, .28); }
.st-mockup--dark .st-mockup__title { color: var(--st-on-dark-mute); }
.st-mockup--dark .st-mockup__body, .st-mockup--dark .st-mockup__foot { color: var(--st-ink); }
.st-mockup--dark .st-mockup__foot { background: rgba(255, 255, 255, .04); border-color: var(--st-dark-hairline); color: var(--st-on-dark-mute); }

/* 拼贴内部的迷你表格/图表/代码块 */
.st-mini {
    border: 1px solid var(--st-hairline);
    border-radius: var(--st-r-md);
    padding: 14px 16px;
    background: rgba(255, 255, 255, .03);
    display: grid; gap: 10px;
}
.st-mockup--dark .st-mini { background: rgba(255, 255, 255, .05); border-color: var(--st-dark-hairline); }
.st-mini__k { font-size: .6875rem; color: var(--st-ink-mute); }
.st-mockup--dark .st-mini__k { color: var(--st-on-dark-mute); }
.st-mini__v { font-size: 1.5rem; font-weight: 300; letter-spacing: -.02em; color: var(--st-ink); font-variant-numeric: tabular-nums; }
.st-mockup--dark .st-mini__v { color: var(--st-ink); }
.st-mini__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: .8125rem; color: var(--st-ink-2); font-variant-numeric: tabular-nums; }
.st-mockup--dark .st-mini__row { color: var(--st-on-dark-soft); }
.st-mini__bars { display: grid; gap: 7px; }
.st-mini__bar { height: 8px; border-radius: var(--st-r-pill); background: rgba(255, 255, 255, .08); }
.st-mockup--dark .st-mini__bar { background: rgba(255, 255, 255, .1); }
.st-mini__bar--a { background: var(--st-primary); }
.st-mini__bar--b { background: var(--st-grad-start); }
.st-mini__bar--c { background: var(--st-highlight); }
.st-mini__code { font-family: var(--st-font-mono); font-size: .6875rem; line-height: 1.7; color: var(--st-ink-mute); white-space: pre-wrap; word-break: break-word; }
.st-mockup--dark .st-mini__code { color: var(--st-on-dark-soft); }

/* 对话式演示（AI 回答视窗）：问答气泡。
   暗色下「提问气泡」仍用品牌色填充（深字），回答用提亮底 + 左侧品牌条。 */
.st-qa { display: grid; gap: 10px; }
.st-qa__q {
    justify-self: end; max-width: 84%;
    padding: 10px 14px;
    border-radius: 12px 12px 4px 12px;
    background: var(--st-primary);
    color: var(--st-on-gradient);
    font-size: .8125rem; line-height: 1.5;
}
.st-qa__a {
    position: relative;
    padding: 14px 16px 14px 18px;
    border-radius: var(--st-r-md);
    background: rgba(255, 255, 255, .04);
    border: 1px solid var(--st-hairline);
    font-size: .8125rem;
    line-height: 1.65;
    color: var(--st-ink-2);
}
.st-qa__a::before {
    content: ''; position: absolute; left: 0; top: 8px; bottom: 8px; width: 3px;
    border-radius: var(--st-r-pill); background: var(--st-hairline-strong);
}
.st-qa__a--hit { background: rgba(69, 187, 251, .08); border-color: rgba(69, 187, 251, .28); color: var(--st-ink); }
.st-qa__a--hit::before { background: var(--st-primary); }
.st-qa__head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; font-size: .75rem; }
.st-qa__engine { font-weight: 500; color: var(--st-ink); }

@keyframes stRise { to { opacity: 1; transform: none; } }
.st-qa__a { opacity: 1; }
.st-qa--live .st-qa__a { opacity: 0; transform: translateY(8px); animation: stRise .5s cubic-bezier(.22, .61, .36, 1) forwards; }
.st-qa--live .st-qa__a:nth-child(1) { animation-delay: .2s; }
.st-qa--live .st-qa__a:nth-child(2) { animation-delay: .9s; }
.st-qa--live .st-qa__a:nth-child(3) { animation-delay: 1.6s; }
@media (prefers-reduced-motion: reduce) {
    .st-qa--live .st-qa__a { opacity: 1; transform: none; animation: none !important; }
}

/* ---------------------------------------------------------------------------
   10. 表单
   --------------------------------------------------------------------------- */
.st-input,
.st-select,
.st-textarea {
    width: 100%;
    padding: 8px 12px;
    font-family: var(--st-font);
    font-size: .9375rem;
    color: var(--st-ink);
    /* 暗色表单：**输入区比页面底更深**（让人一眼看出"这里可以打字"）——
       与卡片相反的方向，这是暗色 UI 的通行做法（浅色系是白底输入框）。 */
    background: rgba(0, 0, 0, .28);
    border: 1px solid var(--st-hairline-input);
    border-radius: var(--st-r-sm);
    transition: border-color .16s ease, box-shadow .16s ease;
}
/* 下拉的原生选项面板由操作系统绘制，必须显式给深底 + 浅字，
   否则 Windows 上会得到「浅灰面板 + 浅灰字」（看不清）。 */
.st-select option { background: var(--st-canvas-elev); color: var(--st-ink); }
/* `<datalist>` 的候选面板同样由原生控件绘制（注册页「职位」等可选可填字段用它）——
   与上面 .st-select option 是同一个坑：面板底色不归我们控制、文字色却继承页面，
   深色官网上会得到「浅灰底 + 白字」。给 option 显式配色是能看清的**唯一**手段
   （给 datalist 本身写 background / display 不会影响弹出面板）。 */
datalist option { background: var(--st-canvas-elev); color: var(--st-ink); }
.st-input::placeholder, .st-textarea::placeholder { color: var(--st-ink-mute-2); }
.st-input:focus, .st-select:focus, .st-textarea:focus {
    outline: none;
    border-color: var(--st-primary);
    box-shadow: 0 0 0 3px rgba(69, 187, 251, .18);
}
.st-label { display: block; margin-bottom: 6px; font-size: .8125rem; font-weight: 500; color: var(--st-ink-2); }
.st-help { margin-top: 6px; font-size: .75rem; color: var(--st-ink-mute); }

.st-input-row { display: flex; gap: 10px; }
@media (max-width: 560px) { .st-input-row { flex-direction: column; } }

/* ---------------------------------------------------------------------------
   11. FAQ（<details> 手风琴）
   --------------------------------------------------------------------------- */
.st-faq { display: grid; gap: 0; border-top: 1px solid var(--st-hairline); }
.st-faq details { border-bottom: 1px solid var(--st-hairline); }
.st-faq summary {
    cursor: pointer;
    list-style: none;
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 20px 2px;
    font-size: 1rem;
    font-weight: 400;
    color: var(--st-ink);
}
.st-faq summary::-webkit-details-marker { display: none; }
.st-faq summary::after {
    content: '+';
    flex-shrink: 0;
    font-size: 1.25rem;
    font-weight: 300;
    color: var(--st-primary);
    transition: transform .18s ease;
}
.st-faq details[open] summary::after { content: '−'; }
/* 2026-10-06：去掉 `max-width: 62ch`（业务方反馈「答案内容为什么宽度只有一半」）。
   62ch 按 Latin 的 "0" 字宽换算在中文下只有 ~537px（容器 1136px 的一半不到），
   与上方问题行的整宽形成明显参差。答案与问题同宽后视觉对齐；FAQ 答案多为 1-3 句，
   整行长度可控。 */
.st-faq p { margin: 0 0 20px; font-size: .875rem; line-height: 1.75; color: var(--st-ink-mute); }

/* ---------------------------------------------------------------------------
   12. 导航（暗色，透明背景——与 hero 发光背景**无缝融合**）
   🔴 2026-10-10 暗色重设计：顶栏改为**透明**（demo 的 header 就是
   `background-color: transparent`）—— 显式去掉任何底色/描边，
   让 body 的顶部辉光直接贯穿导航与主视觉。加底会给出一条横向色带、
   把 demo 的"无缝"效果毁掉。
   --------------------------------------------------------------------------- */
/* z-index 50：顶栏与页面版块若有重叠，二级菜单面板必须压在页面内容之上。
   🔴 2026-10-06 二次修复（真机取证）：原写法 `.st-nav { z-index: 50 }` 被**静默覆盖** ——
   顶栏容器的 class 里带着 Tailwind 工具类 `z-10`（`relative z-10 st-nav`），
   而 Tailwind Play CDN 是在运行时把 utility 样式注入到 head **末尾**（晚于本文件），
   两者选择器权重相同（都是 0,1,0）→ 「后来者胜」→ 计算值实际是 **10**。
   实测后果（/platform/ai-radar）：内容页 hero 容器带 `relative z-10`、且在同一层叠上下文里
   DOM 更靠后 → 标题（z=10）盖住下拉面板（面板虽写了 z=100，但被顶栏这个 z=10 的
   层叠上下文**钳制**在内）→ 用户看到「二级菜单钻到标题下面」，且鼠标下移到被盖区域时
   hover 丢失、面板「莫名消失」。两个症状同一根因。
   修法用`.st-body .st-nav`（0,2,0）**确定性胜过** utility 的 0,1,0——不依赖样式加载顺序；
   同时把容器上的 `z-10` 类去掉（双保险，见 partial 注释与 SitePublicTopbarTest）。 */
.st-body .st-nav,
.st-nav { position: relative; z-index: 50; background: transparent; }
/* 抽屉展开时整条顶栏提到客服球（z-50）与 Cookie 横幅（z-60）之上——否则抽屉底部区域被它们压住。
   ⚠️ :has() 的权重含其参数（0,3,0），高于上一条的 0,2,0，展开态能正常反超。 */
.st-nav:has(.st-nav__burger[open]) { z-index: 65; }
/* 单行布局（2026-10-10 三次改版，**完全按设计师 demo**）。
   demo 的 `.header-container`：`display: flex; justify-content: space-between;
   align-items: center; padding: 20px 32px; max-width: 1400px` ——
   品牌 / 导航 / 操作区三栏同排，整行距顶 20px。业务点名的「导航菜单距离顶部距离按 demo 改」
   指的就是这个：此前是两行制（导航被压在操作区之下，距顶约 46px）。

   ## 🔴 单行制下「导航与操作区相交」是**实测到的真问题**（首版按 demo 原值就撞了）
   按 demo 尺寸（logo 2.7rem + 导航 gap 32px + 操作区 gap 16px）实测各档余量：
     1440px：-41px（安全）｜1366px：**+16px 相交**｜1280px：**+102px**｜1024px：**+308px**
   （正数 = 导航末项右边界越过操作区左边界；`docOverflow` 全程 false ——
    nav 的 `min-width:0` 让**盒子**能缩，而子项 `white-space:nowrap` 的内容溢出到盒子之外，
    所以**没有横向滚动条、也不报错**，只是两块区域的点击热区互相覆盖：
    这正是 2026-10-06 那个"二级菜单 hover 莫名消失"的同族形态。）
   根因是 demo 只给了 1440 一档，而我们的中文菜单项比 demo 的更长（6 项含 3 个带▾的下拉）。
   ## 解法：分级收窄（不牺牲 1440 的 demo 还原度）
   · ≥1440px：**完全按 demo**（gap 32px + logo 2.7rem）；
   · 1280~1439px：gap 32→14（省 90px）+ logo 2.7→2.4rem（省 36px）≈ 省 126px
     （1280 档实测需要 111px，留 ~15px 余量）；
   · 1152~1279px：gap→8px + 字号→14px + logo→1.9rem（见下方「最窄一档」实测表）；
   · <1152px：导航收进汉堡（2026-10-25 从 1280 下调，理由见 `.st-nav__links` 规则）。
   ⚠️ 改这些值时**必须重新实测**（真机浏览器量 DOM 矩形）。
      纯 CSS 断言证明不了"不相交"——它取决于字体加载与实际渲染宽度，本文件首版就是因此漏过的。 */
.st-nav__inner {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    /* 上下内边距 = 「导航距页面顶部」的距离（2026-10-11 业务要求分两种情形处理）。
       · **内页**：导航是页面第一个元素（由 layout 直接渲染在 body 下），
         顶部留白完全由它自身的内边距决定 → 取 44px，让导航不贴着视口上沿
        （2026-10-11 调大：业务反馈「和上面的距离再调大一点」，32px → 44px）。
       · **首页**：导航在 hero 内部、紧接上方那条**亮色渐变信息条** → 见 `.st-nav--home`。
       ⚠️ 左右内边距由调用处的 `px-*` 工具类给（各断点收窄），本规则只管上下。 */
    padding-block: 44px 20px;
}
/* 首页顶栏：紧接信息条下方，上内边距比内页略小（上方是彩色条，不贴视口上沿）。
   合计空档 = 8px（hero 的 padding-top，见 `.st-hero--full.st-hero--center`）+ 32px（本规则）
   = 40px（2026-10-11 调大：业务反馈「再调大一点」，原合计 28px）。
   ⚠️ 这个类由 home.blade.php 的 include 显式传入（`topbarWrapperClass`），
      不靠"是不是首页"的隐式推断 —— 隐式判据（如 `.st-hero .st-nav`）会在
      将来别的页面把顶栏放进 hero 时静默改变行为。 */
.st-nav--home .st-nav__inner { padding-block: 32px; }
/* 操作区（语言 / 登录 / 注册）：单行的最右栏（demo 的 `.header-actions`，gap: 16px）。
   ⚠️ 不再写 `justify-content: flex-end`：那是"独立一排"时代的写法，
   单行制下由父级 space-between 自然贴右，留着会变成一条永不生效的死规则。 */
.st-nav__actions {
    display: flex; flex-wrap: nowrap; align-items: center;
    gap: 16px;
    flex: 0 0 auto;
}
/* 窄屏（<1152px）：操作区收进汉堡抽屉（抽屉里有等价的 语言/登录/注册 入口），
   顶栏只留「品牌 + 汉堡」单行。
   ⚠️ 断点必须与 `.st-nav__links` / `.st-nav__burger` 同值（见下方两条 + 汉堡规则）。 */
@media (max-width: 1151.98px) { .st-nav__actions { display: none; } }
/* 主行容器：单行制下它退化为「品牌 + 导航 + 汉堡」这一组的定位锚 —— 用 `display: contents`
   让它的子元素**直接参与** .st-nav__inner 的 flex 排布（否则会多出一层盒子，
   品牌/导航/操作区就无法三栏对齐）。
   ⚠️ 必须保留这个 DOM 节点与 `data-pub-topbar-main` 标记：SitePublicTopbarTest
      与 SiteDarkRedesignV8Test 都拿它做位置断言。 */
.st-nav__main { display: contents; }
/* 品牌与导航不参与收缩：一旦被压缩，导航文字会折行成两行
   （实测 1440px 下「免费工具」被折成「免费工 / 具」——中文没有词间空格，折行位置非常难看）；
   空间紧张时应当收缩的是导航本体，而不是把每一项压窄。 */
.st-nav__brand { display: flex; align-items: center; flex: 0 0 auto; }
/* 导航项间距（**按 demo**：`.nav-menu { gap: 32px }`）——分级收窄，理由见上方实测数据。
   · ≥1440：32px（demo 原值）；1280~1439：14px；1152~1279：8px（见下方最窄一档）。
   ⚠️ 基础值 14px 覆盖的是 1280~1439 档；1152 以下 nav 被 display:none 接管。 */
.st-nav__links { display: none; align-items: center; gap: 14px; min-width: 0; }
@media (min-width: 1440px) { .st-nav__links { gap: 32px; } }
/* 导航内联显示的起点 = **1152px**（2026-10-25 从 1280 下调）。
   实测 1024 档需要 308px 余量才放得下，任何收窄都补不上 → 该档及以下交给汉堡抽屉。

   🔴 为什么从 1280 下调（2026-10-25 真机反馈）：MacBook 全屏访问官网时显示的是移动端
   汉堡菜单。原因是 1280 恰好压在主流 Mac 的可用宽度边界上：
     · MacBook 13" 默认缩放 1280×800 → 视口正好 1280，**再减去常驻滚动条（接鼠标时 macOS
       会一直显示，约 15px）→ 1265 → 落进汉堡**；
     · 1280×800 / 1440×900 档位下把浏览器页面缩放到 110%~125% → 视口变 1152~1164；
     · 带侧边栏的窗口宽度也会吃掉几十像素。
   这些都不是"手机/平板"，给它们移动端菜单是误判。
   1152 覆盖上述全部情形（Playwright 实测中英双语在 1152 均有 >20px 余量，见下方紧凑档）。
   ⚠️ 改这个值必须同步：`.st-nav__actions` 的隐藏断点、`.st-nav__burger` 的隐藏断点、
      以及下面 1152~1279 的紧凑档 —— 三处错位会造成"导航与汉堡同时出现/都不出现"。
      守卫：SiteDarkRedesignV8Test::test_topbar_breakpoints_and_space_savers_stay_consistent。 */
@media (min-width: 1152px) { .st-nav__links { display: flex; } }
/* 导航项字色用 demo 的导航色 #cbd5e1（= --st-ink-2），hover 落品牌青绿。
   ⚠️ 不要用 --st-ink（纯白）：一屏里每个菜单项都是纯白会与主标题抢层级。 */
.st-nav__link {
    /* demo: `.nav-menu a { font-size: 15px; font-weight: 500 }` —— 15px = .9375rem。 */
    font-size: .9375rem; font-weight: 500; color: var(--st-ink-2); text-decoration: none;
    white-space: nowrap;   /* 同上：中文导航项绝不允许折行 */
    transition: color .3s ease;
}
.st-nav__link:hover { color: var(--st-grad-start); }

/* 下拉面板（2026-10-06 v7）：层级从 Tailwind `z-50` 收口到这里。
   🔴 为什么需要（业务方反馈「二级菜单的层级不够高，会穿到下面的文字下面去」）：
   `z-50` 是 Tailwind 的通用档位，而页面侧有 `z-index: 1` 的 hero 正文容器与其上
   各类带定位的装饰；面板是否压得住**取决于谁的后代在 DOM 里更靠后**，没有统一约定。
   收口到本规则后：面板恒为 100（顶栏底座 50、抽屉 65 都在它之下），
   只要顶栏（z-index 50）整条压在页面内容之上，面板就必然在其上。 */
.st-nav__dropdown { z-index: 100; }
/* 下拉面板本体（2026-10-10 暗色重设计）。
   🔴 原来这块样式**内联在视图里**（Tailwind `bg-white border text-gray-700`
   + 一条 `style="border-color: var(--st-hairline)"`），暗色翻转后必须整块重写：
   白面板压在暗页面上会"炸开"（鼠标没碰它时它就是整页最亮的块），
   而 Tailwind 的字面色值又没法跟着 token 走。
   现收口到这里，视图只留类名。 */
.st-nav__panel {
    min-width: 15rem;
    padding: 8px;
    border-radius: var(--st-r-lg);
    border: 1px solid var(--st-hairline);
    background: var(--st-canvas-elev);
    box-shadow: 0 18px 44px rgba(0, 0, 0, .55);
}
.st-nav__panel-item {
    display: block;
    padding: 8px 12px;
    border-radius: var(--st-r-md);
    font-size: .875rem;
    color: var(--st-ink-2);
    text-decoration: none;
    transition: background .16s ease, color .16s ease;
}
.st-nav__panel-item:hover { background: rgba(255, 255, 255, .06); color: var(--st-ink); }

/* ---- 12.5 核心平台 mega menu（2026-10-20，依据《官网二级菜单》PPT）----
   ## 视觉依据
   PPT 是一张暗色面板：6 列分组（洞察/诊断/优化/执行/归因｜数字资产管理），
   列标题青蓝色、条目白色，第 5 与第 6 列之间一条竖分隔线，
   底部一条横线 + 一句说明。
   ## 两个必须做对的几何问题
   ① **不能左对齐**：面板约 900px 宽，而「核心平台」是导航第二项（页面偏左），
      `left: 0` 会让右半边溢出视口。故相对导航项做 `left: 50% + translateX(-50%)` 居中。
      ⚠️ 窄视口（1280~1440）下仍可能贴边，用 `max-width: calc(100vw - 48px)` 兜住。
   ② **竖分隔线要用 gap + 伪元素**，不能给第 6 列加 border-left ——
      那样线会紧贴文字；PPT 里线与两侧文字都有均等呼吸。 */
.st-nav__mega-wrap {
    /* 🔴 2026-10-20 业务要求：「核心平台」与「洞察」这一列**左边缘对齐**。
       居中对齐做不到这件事（居中是相对菜单项居中的，与列内文字起点无关）。
       这里用负偏移抵消「面板边框 + 面板左内边距 + 列左内边距」这三层留白，
       使第一列文字的起点正好落在菜单项文字的左边缘上。
       ⚠️ 数值必须与下面 .st-mega / .st-mega__col 的 padding 同步：
          1(border) + 22(panel) + 10(col) = 33px。改任一处 padding 都要改这里，
          否则会回到"洞察比核心平台偏右一截"（本页首版即为此返工）。 */
    left: -33px;
}
.st-mega {
    width: max-content;
    max-width: calc(100vw - 48px);
    /* 2026-10-20：上下内边距略收（26/20 → 22/16），与收紧后的列间距同一节奏。 */
    padding: 22px 22px 16px;
    border-radius: var(--st-r-lg);
    border: 1px solid var(--st-hairline);
    background: var(--st-canvas-elev);
    box-shadow: 0 18px 44px rgba(0, 0, 0, .55);
}
.st-mega__cols {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    /* 🔴 2026-10-20 业务要求：列间距调小（原列内左右各 22px padding → 两列之间 44px 空档）。
       改为「列 padding 收窄 + 一个小 gap」：列与列之间约 2×10 + 6 = 26px，
       既明显更紧凑，又保留 hover 高亮块两侧的呼吸（padding 归零会让高亮贴着文字）。 */
    gap: 6px;
}
/* 列 = 页面（整列可点）。hover 时整列轻微提亮，明确"这是一整块可点的东西"。 */
.st-mega__col {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 6px 10px;
    border-radius: var(--st-r-md);
    text-decoration: none;
    transition: background .16s ease;
}
.st-mega__col:hover { background: rgba(255, 255, 255, .05); }
/* 第 5/6 列之间的竖线（PPT 的分组语义：前 5 列是链路，最后一列是资产底座）。
   ⚠️ 竖线的 left 要含所在列的 padding（10px），否则线会紧贴文字。 */
.st-mega__col--divider {
    position: relative;
    margin-left: 4px;
    padding-left: 18px;
}
.st-mega__col--divider::before {
    content: "";
    position: absolute;
    left: 7px;
    top: 6px;
    bottom: 6px;
    width: 1px;
    background: var(--st-hairline-strong);
}
.st-mega__title {
    font-size: .9375rem;
    font-weight: 700;
    line-height: 1.4;
    color: var(--st-primary);
    white-space: nowrap;
}
.st-mega__item {
    font-size: .875rem;
    line-height: 1.5;
    color: var(--st-ink-2);
    white-space: nowrap;
}
/* 底部横线 + 说明（PPT 的最后一行）。 */
.st-mega__note {
    margin: 16px 0 0;
    padding-top: 14px;
    border-top: 1px solid var(--st-hairline);
    font-size: .875rem;
    line-height: 1.6;
    color: var(--st-ink-mute);
    text-align: center;
    white-space: nowrap;
}
/* 窄视口兜底：面板宽度受限（不出视口）。
   ⚠️ 不再切换对齐方式 —— 对齐只由上面的 left 负偏移决定，
      任何断点下「核心平台」与「洞察」都保持左边缘对齐（业务要求）。
      面板变宽 / 变窄只影响右边界，不影响这条对齐关系。 */
@media (max-width: 1439.98px) {
    .st-mega { padding: 20px 18px 14px; }
    .st-mega__col { padding: 6px 8px; }
    /* padding 变了 → 偏移量跟着变（1 + 18 + 8 = 27）。 */
    .st-nav__mega-wrap { left: -27px; }
    .st-mega__col--divider { padding-left: 16px; }
}


/* 高亮导航项（「免费体验」）：demo 里唯一的暖色记号，别处不得复用（`--st-highlight` 只有这一个消费方）。
   🔴 2026-10-19 修：业务反馈「一级菜单仍是白字，不是 #FBE041」。根因是**权重打架**——
   视图给该项同时挂了 Tailwind 的 `text-white/70 hover:text-white`（暗色顶栏通用类），
   而 Play CDN 在运行时注入、排在 site-design.css 之后，同为单类权重（0,1,0）时**它赢**
   → 高亮色被静默覆盖。故这里把选择器提到 0,2,0（`.st-nav` + 该类）压过 utility，
   并用 0,3,0 覆盖 hover 态；色值仍是 --st-highlight（= #FBE041）。
   ⚠️ 不要靠"改视图去掉 text-white/70"来修：其余菜单项仍需要它，逐个特判会漏。 */
.st-nav .st-nav__link--highlight { color: var(--st-highlight); font-weight: 600; }
.st-nav .st-nav__link--highlight:hover { color: var(--st-highlight); opacity: .88; }

/* ── 英文版顶栏额外收紧（真机实测：英文菜单文案明显更长，会真的压到操作区上）────
   ## 实测数据（最后一个菜单项右边界 → 操作区左边界，正数=有间隙）
   | 视口  | 中文   | 英文     |
   |-------|--------|----------|
   | 1600  | +41px  | **-29px** |
   | 1440  | +41px  | **-29px** |
   | 1382  | +75px  | +31px    |
   | 1280  | +24px  | **-51px** |
   英文菜单更长（`Free Experience ✨` 单项即 157px，`About Us` 83px），
   且 nav 的 `min-width:0` 让它被压缩后**内容溢出到盒子之外** —— 无滚动条、无报错，
   只是点击热区互相覆盖（"二级菜单 hover 莫名消失"同族）。
   ## 解法：只对英文收紧（中文保持 demo 原值）
   ① 导航字号 15→14px（省约 42px：英文单词宽度随字号线性缩放）；
   ② 导航间距 14→10px（省约 20px）。
   两者合计约 62px，覆盖上表最大的 51px 缺口。
   ⚠️ 用 `html[lang="en"]`（layout 输出的是 `en`，与 `app()->getLocale()` 一致）——
      不要用 `[lang^="en"]` 之类模糊匹配，中文页会被 `zh-CN` 误伤。
   ⚠️ 中文**不动**：demo 是中文稿，15px/32px 是它逐像素定过的值。
   📌 真机复测数据见提交信息；改这些值前请重新量（纯 CSS 断言证明不了不相交）。 */
html[lang="en"] .st-nav__link { font-size: 14px; }
/* 1280~1439 用 8px（该档实测余量最小）；≥1440 放宽到 12px。
   ⚠️ 这两个值是量出来定的，不是拍的：1280 档改前余量仅 +8px，改后 +18px（见提交信息复测表）。 */
html[lang="en"] .st-nav__links { gap: 8px; }
@media (min-width: 1440px) {
    html[lang="en"] .st-nav__links { gap: 12px; }
}

/* ── 1280~1439 档把三栏间距收到 12px（单行制的空间腾挪之三，给英文版留余量）────
   为什么还要收：真机量完中英双语后发现 —— 中文各档余量 24~75px，而**英文**（菜单文案更长，
   如 `Free Experience` 141px）在 1440/1280 两档的余量**恰好等于 flex 最小间距 24px**，
   即"刚好塞满、零余量"。零余量意味着字体替换（Inter 未加载时回退系统字体更宽）、
   菜单文案加一个字，都会立刻溢出 —— 而溢出是**静默的**（nav 的 min-width:0 让盒子缩、
   内容溢出到盒子之外，没有滚动条也不报错，只是点击热区互相覆盖）。
   收到 12px 后这两档各多出 12px 余量（实测生效，见提交信息里的复测数据）。
   ⚠️ ≥1440 仍用 demo 的 24px —— demo 还原度优先给最主流的桌面宽度。 */
@media (min-width: 1280px) and (max-width: 1439.98px) {
    .st-nav__inner { gap: 12px; }
}

/* ── 品牌 Logo 在 1280~1439 档**降一级**（单行制的空间腾挪之一）──────────────
   为什么需要：logo 在 1024px 起跳到 2.7rem（≈323px 宽），与「6 项中文导航 + 操作区」
   同排时，1280 档实测需要 111px 余量才不相交，而导航 gap 收窄只能省 90px。
   把 logo 在这一档压回 2.4rem（≈287px）再省 36px，合计 126px —— 留约 15px 余量。
   ⚠️ 文字品牌与图片 Logo **必须成对覆盖**：只改一个会让两类站点的顶栏高度不一致
      （视觉上像"logo 忽大忽小"）。custom.css 里那两个断点值是业务方两次反馈后定的，
      这里只是**在特定区间封顶**，不改它们本身（SitePublicTopbarTest 仍在守着那两个值）。
   ⚠️ 1440 起恢复 2.7rem —— demo 的还原度优先。 */
@media (min-width: 1280px) and (max-width: 1439.98px) {
    .pub-topbar-brand { font-size: 2.4rem; }
    .pub-topbar-brand-logo { height: 2.4rem; }
}

/* ── 1152~1279 档：单行制的**最窄一档**（2026-10-25 新增）────────────────────
   背景：断点从 1280 下调到 1152 后，1152~1279 这段（MacBook 接鼠标时带常驻滚动条、
   页面缩放 110%~125%、带侧边栏的窗口）也要放下「品牌 + 6 项导航 + 语言/登录/注册」。
   该段比 1280 档少约 128px，仅靠 gap 收窄补不上 → 三根杠杆一起压到最紧：
     ① 导航字号 15→14px（中英统一，英文原本就是 14px）；
     ② 导航 gap 14→8px、三栏 gap 24→10px；
     ③ logo 2.7→1.9rem（这一档必须降得比 1280~1439 的 2.4rem 更低，否则英文压不住）。

   ## 🔴 实测余量（Playwright + Chrome 116，127.0.0.1:8080，2026-10-25）
   量的是「导航末项右边界 → 操作区左边界」，正数=有间隙：
     | 视口 | 中文  | 英文  |
     |------|-------|-------|
     | 1280 | +113  | +95   |
     | 1200 | +73   | +55   |
     | 1152 | +46   | +27   |
   （≥1280 的数字含本档 logo 生效；1152 是本档起点，中英余量均 >20px。）
   ⚠️ 必须保留 >20px 余量：Inter 未加载时回退系统字体更宽，菜单文案加一个字也会吃掉几十像素，
      而溢出是**静默的**（nav 的 min-width:0 让盒子缩、子项 white-space:nowrap 溢到盒外，
      无滚动条、无报错，只是点击热区互相覆盖）。
   ⚠️ 改这些值必须重新实测（真机量 DOM 矩形），纯 CSS 断言证明不了不相交。 */
@media (min-width: 1152px) and (max-width: 1279.98px) {
    .st-nav__inner { gap: 10px; }
    .st-nav__links { gap: 8px; }
    .st-nav__link { font-size: 14px; }
    .pub-topbar-brand { font-size: 1.9rem; }
    .pub-topbar-brand-logo { height: 1.9rem; }
    .st-nav__actions { gap: 10px; }
}

/* ── 语言切换（**完全按设计师 demo**）──────────────────────────────────────
   demo 的 `.lang-switch` 是**纯文本**，不是分段胶囊：
     `.lang-switch { font-size: 14px; color: #94a3b8; font-weight: 500; margin-right: 8px; }`
     `.lang-switch span.active { color: #ffffff; }`（当前语言着白色）
   分隔符是全角竖线「｜」，demo 里写作 `中文 ｜ ENG`。

   🔴 2026-10-10 改版说明：此前实现为「分段胶囊」（带描边 + 品牌色高亮底），
   与 demo 差得较远；业务明确要求「中英文切换完全按 demo 修改」，故整块重写为纯文本。
   ⚠️ `margin-right: 8px` 是 demo 的额外右侧留白（让语言区与登录按钮之间更松），
      为 0 时语言文字会与白底登录按钮贴得过近。
   ⚠️ 当前语言用**直白的高亮色**而非加粗：加粗会让两个语言项宽度变化、切换时"跳动"。 */
.st-lang {
    display: inline-flex; align-items: center;
    font-size: 14px;
    font-weight: 500;
    color: var(--st-ink-mute);
    margin-right: 8px;
    white-space: nowrap;
}
.st-lang a {
    font-size: 14px; font-weight: 500;
    color: var(--st-ink-mute); text-decoration: none;
    transition: color .2s ease;
}
.st-lang a:hover { color: var(--st-ink); }
/* 当前语言：demo 用纯白（`.lang-switch span.active { color: #ffffff }`）。 */
.st-lang a.is-active { color: var(--st-ink); }
/* 分隔符（全角竖线）：给两侧留一点空隙 —— 不加 padding 时「中文｜ENG」会贴成一整块。 */
.st-lang__sep { color: var(--st-ink-mute-2); padding: 0 4px; }
/* 亮底版面变体（保留）：亮底上 muted 灰对比不足，改用深墨字。 */
.st-lang--on-dark { color: var(--st-ink-mute); }

/* ── §35 语言切换下拉（2026-10-11，形态参照 brightdata.com） ──────────────────
   形态 = 「旗帜 + 当前语言短码 + 下拉箭头」触发器，点开一张浮层卡片，
   每行「旗帜 + 语言自称名」，当前项浅底高亮。核心理由：后续加语言时
   条目增减**不改变触发器宽度**（原纯文本 `中文 ｜ ENG` 三语言就排不下）。
   实现：原生 <details>（开合同 FAQ/汉堡抽屉手法），零 JS。
   🔴 隐藏浏览器默认 marker：summary 的三角在不同内核位置不同，必须统一去掉
      （`list-style: none` + `::-webkit-details-marker`，与 .st-nav__burger 同款处理）。
   ⚠️ 浮层定位用 absolute + right:0（贴触发器右缘向左展开）——语言区在顶栏最右，
      用 left:0 会溢出视口。 */
.st-langsw { position: relative; display: inline-flex; }
.st-langsw__trigger {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: 14px; font-weight: 500; line-height: 1;
    color: var(--st-ink-mute);
    padding: 7px 10px;
    border-radius: var(--st-r-sm);
    cursor: pointer;
    list-style: none;
    transition: color .2s ease, background .2s ease;
    -webkit-user-select: none; user-select: none;
}
.st-langsw__trigger::-webkit-details-marker { display: none; }
.st-langsw__trigger:hover { color: var(--st-ink); background: rgba(255, 255, 255, .06); }
.st-langsw[open] .st-langsw__trigger { color: var(--st-ink); background: rgba(255, 255, 255, .06); }
.st-langsw__short { letter-spacing: .04em; }
.st-langsw__caret { transition: transform .2s ease; margin-top: 1px; }
.st-langsw[open] .st-langsw__caret { transform: rotate(180deg); }
/* 语言标识图标尺寸（2026-10-25 由「国旗」改为「中性地球图标」）。
   ## 为什么改
   语言 ≠ 国家：`en` 是不带地区的语言代码，但任一国旗都会声称一个地区
   （英国旗让北美客户觉得不对，美国旗让英国/东南亚客户觉得不对）。
   改用地球图标后只表达"语言"，不表达"国家"。
   ## 尺寸
   地球是**正方形**（14×14），视觉体量与旧的 16×11 旗帜相当
   （高度对齐 14px 文字的大写高度，是「行内小图标」而不是色块）。
   ⚠️ 旧注释要求「保持 32:22 比例」——那是针对旗帜的；地球图标不适用，
      但**宽高仍必须成对**（正方形不能被拉成长方形）。
   ⚠️ 颜色由组件内联 style 给（按语族不同，见 lang-flag.blade.php），
      这里只管尺寸与对齐；不要写 color —— 会盖掉语族色调。 */
.st-langsw__flag { width: 14px; height: 14px; flex-shrink: 0; }
/* 浮层卡片：BD 是白色圆角卡；本站暗色体系 → 用 elev 层 + 细描边（同一视觉角色）。
   🔴 显式控制展开/收起（2026-10-11 实测踩到）：**不能依赖 UA 对 <details> 的默认隐藏**。
      实测（Edge/Chromium）：未展开时内容的布局尺寸仍在（getBoundingClientRect 有
      高度、computed display=block），UA 用的是"内容不绘制/不可交互"一类的机制——
      后果：① 自动化判据（按高度查"是否可见"）会误报；
            ② 不同内核行为不一致（Firefox/Safari 实现路径不同）。
      现写法与 CSS 完全自持：基础 display:none + [open] 时 display:block。 */
.st-langsw__menu {
    display: none;
    position: absolute; right: 0; top: calc(100% + 10px);
    z-index: 60;
    min-width: 172px;
    margin: 0; padding: 6px;
    list-style: none;
    background: var(--st-canvas-elev);
    border: 1px solid var(--st-hairline-strong);
    border-radius: var(--st-r-lg);
    box-shadow: 0 18px 44px rgba(0, 0, 0, .55), 0 4px 12px rgba(0, 0, 0, .35);
}
.st-langsw[open] > .st-langsw__menu { display: block; }
.st-langsw__item {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 12px;
    border-radius: var(--st-r-sm);
    font-size: 14px;
    color: var(--st-ink-2);
    text-decoration: none;
    transition: background .15s ease, color .15s ease;
}
.st-langsw__item:hover { background: rgba(255, 255, 255, .07); color: var(--st-ink); }
/* 当前语言：BD 是浅底高亮；这里用品牌色底 + 白字（暗色下"浅底"没有对比度）。 */
.st-langsw__item.is-active { background: rgba(69, 187, 251, .14); color: var(--st-ink); }
.st-langsw__label { white-space: nowrap; }
/* 亮底变体（保留给浅色版面）：文字转深墨。 */
.st-langsw--light .st-langsw__trigger { color: #475569; }
.st-langsw--light .st-langsw__trigger:hover,
.st-langsw--light[open] .st-langsw__trigger { color: #0f172a; background: rgba(15, 23, 42, .05); }
/* 移动抽屉变体：不浮层——列表在触发器下方原位展开，占满整行。 */
.st-langsw--drawer { display: block; }
.st-langsw--drawer .st-langsw__trigger { width: 100%; justify-content: flex-start; padding: 10px 12px; }
.st-langsw--drawer .st-langsw__menu {
    position: static; margin-top: 6px; min-width: 0;
    box-shadow: none;
}

/* ── 登录按钮（**完全按设计师 demo**）──────────────────────────────────────
   demo 的 `.login-btn`：3px 透明边框 + **白底** + 深墨绿字，
   边框由 3px 渐变提供（`padding-box` / `border-box` 双层背景手法）：
     padding: 7px 24px; font-size: 14px; font-weight: 600; border-radius: 9999px;
   ⚠️ 它**不是**细描边胶囊 —— 这是 demo 里唯一的白底按钮，
      与渐变填充的注册按钮构成一对主/次 CTA（白底=次、渐变=主）。
   ⚠️ 字色用 --st-on-gradient（深墨绿 #052e16）：白底上它对比度 15:1；
      用白色会完全看不见（该 token 的语义就是"压在浅色面上的字"）。 */
.st-login-btn {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 7px 24px;
    border-radius: var(--st-r-pill);
    font-family: var(--st-font);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    text-decoration: none;
    color: var(--st-on-gradient);
    /* 3px 渐变描边 + 白底：padding-box 铺白、border-box 铺渐变，两层叠出"渐变边框白底"。 */
    border: 3px solid transparent;
    background:
        linear-gradient(#ffffff, #ffffff) padding-box,
        var(--st-grad) border-box;
    transition: transform .2s ease, box-shadow .3s ease;
}
.st-login-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(69, 187, 251, .2);
    color: var(--st-on-gradient);
}

/* ── 注册按钮（**完全按设计师 demo**）──────────────────────────────────────
   demo 的 `.register-btn`：渐变填充 + 深墨绿字 + 品牌辉光
     padding: 10px 24px; font-size: 14px; font-weight: 600。
   ⚠️ 与 `.st-btn--primary` 的差别只在**内边距**（demo 的注册按钮比通用主按钮略高），
      故这里单列一类而非复用 —— 顶栏的尺寸是 demo 逐像素对齐过的，不要合并。 */
.st-register-btn {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 10px 24px;
    border-radius: var(--st-r-pill);
    font-family: var(--st-font);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    text-decoration: none;
    background: var(--st-grad);
    color: var(--st-on-gradient);
    box-shadow: 0 4px 14px rgba(69, 187, 251, .2);
    transition: opacity .3s ease, transform .2s ease, box-shadow .3s ease;
}
.st-register-btn:hover {
    opacity: .9;
    transform: translateY(-1px);
    box-shadow: 0 6px 20px rgba(69, 187, 251, .4);
    color: var(--st-on-gradient);
}

/* 移动端汉堡 + 抽屉（替代原「横向滚动导航」，2026-10-06）。
   ⚠️ 抽屉的定位上下文是 .st-nav（它才有 position: relative）——
   汉堡自身**不加** position，否则抽屉只会在按钮下方展开一小条。 */
.st-nav__burger { display: block; flex: 0 0 auto; }
/* 与 `.st-nav__links` 的显示起点**必须同值**：一个在、一个不在的窗口期里
   顶栏会同时渲染导航与汉堡（撑爆布局）或两者都没有（导航彻底消失）。
   ⚠️ 这两个断点是成对的，改一处必须同步另一处（2026-10-25 一起从 1280 下调到 1152）。
   守卫见 SiteDarkRedesignV8Test。 */
@media (min-width: 1152px) { .st-nav__burger { display: none; } }
.st-nav__burger-btn {
    display: flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border-radius: var(--st-r-md);
    border: 1px solid var(--st-hairline-strong); background: rgba(255, 255, 255, .06);
    color: var(--st-ink); cursor: pointer; list-style: none;
}
.st-nav__burger-btn::-webkit-details-marker { display: none; }
.st-nav__burger-btn:hover { border-color: var(--st-primary); color: var(--st-primary); }
.st-nav__drawer {
    position: absolute; left: 0; right: 0; top: 100%; z-index: 60;
    display: flex; flex-direction: column;
    /* ⚠️ 高度上限用 70vh 而不是 calc(100vh - 72px)（2026-10-06 实测修正）：
       抽屉的 top 是**顶栏底部**（首页约 140px，其它页不同），不是视口 72px ——
       原值在 844 屏上算出 772px 高，140+772=912 超出视口 68px，
       打开时底部链接（语言/登录/注册）被推到屏幕外。70vh 在任何常见
       nav 位置下都保证「顶栏底 + 抽屉高 ≤ 视口高」，内容多的部分内部滚动。 */
    max-height: 70vh; overflow-y: auto;
    padding: 4px 20px 20px;
    /* 抽屉是实体面板（覆盖在内容之上），必须**不透明**，否则下面的文字会透过来 → 双重文字。
       故这里用不透明底 + 品牌色描边，而不是顶栏那种玻璃半透明。 */
    background: var(--st-canvas-elev); border-bottom: 1px solid var(--st-hairline);
    box-shadow: 0 16px 40px rgba(0, 0, 0, .5);
}
.st-nav__drawer > a {
    padding: 13px 4px; font-size: .9375rem; font-weight: 500;
    color: var(--st-ink); text-decoration: none;
    border-bottom: 1px solid var(--st-hairline);
}
.st-nav__drawer > a:hover { color: var(--st-primary); }
.st-nav__drawer a.st-nav__drawer-sub {
    padding: 9px 4px 9px 18px; font-size: .875rem; font-weight: 400;
    color: var(--st-ink-mute); border-bottom: 1px solid var(--st-hairline);
}
.st-nav__drawer a.st-nav__drawer-sub:hover { color: var(--st-primary); }
.st-nav__drawer-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding-top: 16px; }

/* ---------------------------------------------------------------------------
   13. 页脚（暗色多列）
   暗色体系：页脚比页面底**更深**一档（收束页面的常规手法——底部沉下去），
   而不是浅色系那样用一个浅灰底。深色页脚变体（--dark）仍保留但已近乎等价。
   --------------------------------------------------------------------------- */
.st-footer { background: #070b13; border-top: 1px solid var(--st-hairline); padding: 64px 0 32px; }
.st-footer__grid { display: grid; gap: 40px; }
@media (min-width: 900px) { .st-footer__grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 48px; } }
.st-footer__brand { display: grid; gap: 14px; align-content: start; }
/* 页脚品牌链接（2026-10-20：平台默认品牌改用 SVG 字标）。
   字标 viewBox 比例 728.7:97.4 ≈ 7.48:1，高度 22px → 宽约 165px，
   与原来那行 16px 文字的视觉体量相当（不要放大到顶栏那么大：
   页脚是收尾信息区，字标过大会喧宾夺主）。 */
.st-footer__brand-link--mark { display: inline-flex; align-items: center; }
.st-footer__brand-mark { display: block; height: 22px; width: auto; }
.st-footer__title { font-size: .75rem; font-weight: 500; letter-spacing: .04em; text-transform: uppercase; color: var(--st-ink-mute); }
.st-footer__links { display: grid; gap: 10px; }
.st-footer__links a { font-size: .8125rem; color: var(--st-ink-2); text-decoration: none; transition: color .16s ease; }
.st-footer__links a:hover { color: var(--st-primary); }
.st-footer__legal {
    margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--st-hairline);
    display: flex; flex-wrap: wrap; gap: 12px 20px; align-items: center; justify-content: space-between;
    font-size: .75rem; color: var(--st-ink-mute);
}
.st-footer__legal-links { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.st-footer__legal-links a { color: var(--st-ink-mute); text-decoration: none; }
.st-footer__legal-links a:hover { color: var(--st-ink); }
/* 底栏左侧一组：**版权 + 备案号并排**（业务要求 2026-10-11）。
   🔴 为什么包一层容器，而不是直接把备案塞进 `.st-footer__legal`：
      那一排是 `justify-content: space-between` —— 直接塞第三个子元素会让
      版权/备案/法律链接**三者均匀散开**（版权跑到左边、法律链接漂到中间）。
      包成"左侧一组 + 右侧一组"两个子项后，两栏对齐关系保持不变。
   ⚠️ gap 用 8px 18px（与右侧法律链接同值）：一行里两个法律性陈述之间
      需要可辨的间隔，但不能大到看着像两个不相干的区块。 */
.st-footer__legal-brand {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 18px;
    /* 备案号较长时（如「京ICP备12345678号-1」+ 版权）允许换行，不撑破容器。 */
    min-width: 0;
}
/* 备案链接（行内模式）：与版权文字**完全同一套观感**（业务要求"样式也弄成一样"）。
   🔴 关键是 `color: inherit` 而**不是**写 `var(--st-ink-mute)`：
      页脚有两个变体，版权文字的色由变体决定 ——
        · 深色页脚（当前默认）：`.st-footer--dark .st-footer__legal` → rgba(255,255,255,.56)
        · 浅色页脚：`.st-footer__legal` → var(--st-ink-mute)
      若在这里写死其中一支，另一支下两者就会**不同色**（真实踩到：首版写 var(--st-ink-mute)，
      实测深色页脚里版权 rgba(255,255,255,.56)、备案 rgb(148,163,184)，一眼看出不是一套）。
      `inherit` 让它自动跟随所属变体，永不脱节。
   ⚠️ 字号同理不写死：继承 `.st-footer__legal` 的 .75rem，与版权天然一致。 */
.st-filing-link { color: inherit; text-decoration: none; }
.st-filing-link:hover { color: var(--st-ink); }

/* 深色页脚变体（保留给需要"更深"收尾的页面；暗色体系下它比默认页脚再深一点）。 */
.st-footer--dark { background: #04070d; border-top-color: rgba(255, 255, 255, .08); color: var(--st-ink); }
.st-footer--dark .st-footer__title { color: var(--st-on-dark-mute); }
.st-footer--dark .st-footer__links a { color: var(--st-on-dark-soft); }
.st-footer--dark .st-footer__links a:hover { color: var(--st-ink); }
.st-footer--dark .st-footer__legal { border-top-color: rgba(255, 255, 255, .1); color: var(--st-on-dark-mute); }
.st-footer--dark .st-footer__legal-links a { color: var(--st-on-dark-mute); }
.st-footer--dark .st-footer__legal-links a:hover { color: var(--st-ink); }

/* 移动端触控目标：补足 WCAG 2.2 的 24px 最小尺寸。
   ⚠️ 判据用**视口宽度**而非 `@media (pointer: coarse)` —— 实测 CDP 的
   `Emulation.setDeviceMetricsOverride({mobile:true})` 下 Edge 仍报告 `pointer: fine`，
   按指针类型写规则在真机上无法验证（custom.css 已记录同一结论）。
   ⚠️ 2026-10-01 补：原先只覆盖了**底栏法律链接**，漏了**页脚主链接列**（`.st-footer__links`）——
   实测 375px 下它们高仅 20px（< 24px）。这类遗漏不报错、只是手机上不好点，
   必须靠跨断点实测才能发现（本次即由断点审计脚本查出）。
   这里**不用负 margin** 抵消：页脚的 grid gap 只有 10px，负 margin 会让相邻链接的
   点击区互相重叠 —— 重叠比偏小更糟。改为直接给 min-height 撑高（页脚变高一点无妨）。 */
@media (max-width: 1023px) {
    .st-footer__links a {
        display: inline-flex; align-items: center;
        min-height: 28px;
    }
    .st-footer__legal-links a,
    .st-footer .pub-footer-filing a,
    .st-footer .st-filing-link {
        display: inline-flex; align-items: center;
        min-height: 28px; padding-block: 6px; margin-block: -6px;
    }
}

/* ---------------------------------------------------------------------------
   14. 其它
   --------------------------------------------------------------------------- */
.st-note { font-size: .75rem; line-height: 1.6; color: var(--st-ink-mute-2); }
.st-section--dark .st-note { color: var(--st-on-dark-mute); }
/* 🔴 2026-10-11 修对比度（同 methodology 卡片的同族缺陷）。
   原值 `background: rgba(245,233,212,.6)` + `color: #7a5220` 是**浅色画布时代的硬编码**
   （奶油底 + 深棕字）—— 暗色重设计（10-10）时漏改。实测渲染成
   `rgb(151,148,135)` 底 + `rgb(122,82,32)` 字 = **2.46:1**，深底上完全看不清。
   ⚠️ 这个缺陷**本文件早就记录过**（free-geo-check.blade.php 的注释原话：
      「手写的深棕（#7a5220 + 奶油底），深色翻转后压深底上对比不足 ~2:1」）——
      但那处只修了**调用点的内联值**，`.st-pill-note` 类本身从未修，
      于是改用这个类的页面（注册页试用提示 / 体检页徽标）继续坏着。
      教训：修"某处硬编码颜色"时必须连带检查**它引用的公共类**，否则只修了症状。
   现改为设计令牌（品牌色低透明度底 + 亮文字），与全站提示胶囊同一语言。 */
.st-pill-note {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px; border-radius: var(--st-r-pill);
    background: rgba(69, 187, 251, .10); border: 1px solid rgba(69, 187, 251, .22);
    font-size: .75rem; color: var(--st-primary-soft);
}
/* 🔴 2026-10-06 补：`.st-ico-12` 此前**从未定义**（与 `--st-navy` 同族的静默失败）——
   顶栏下拉箭头引用了这个类，但 CSS 里没有它 → 图标停在 lucide 的默认 24px、
   描边按 24px 比例显示 → 文案 14px 旁挂一个 24px 粗描边箭头（业务方原话「那展开箭头有点粗，
   看着不太协调」）。定义后按 12px 渲染，描边等比缩到视觉 1px，与文字协调。
   ⚠️ lucide 图标是 24 viewBox + stroke-width 2：改 width/height 即等比缩放描边，
   不要再单独写 stroke-width（会把两处比例拧成一份新的不一致）。 */
.st-ico-12 { width: 12px; height: 12px; }
.st-ico-16 { width: 16px; height: 16px; }
.st-ico-18 { width: 18px; height: 18px; }

/* 表格里的「状态词」单元格不许折行（2026-10-11 加，业务反馈「这一列换行了」）。
   ## 为什么需要它
   表格是 auto 布局：列宽由内容算出，而**只有两三个字的短状态词**（可复现 / 不可复现）
   在算 min-content 宽时被当成"可以随便断行"——CJK 的默认断行规则允许在任意字之间折，
   它不认词边界。于是列被压到刚好放下两个字，渲染成「可否复 / 现」「不可复 / 现」。
   `white-space: nowrap` 让该单元格的 min-content 宽度 = 整串字宽，
   **auto 布局据此把这一列撑到够宽** —— 这是治本。
   （不采用"给列写死 px 宽度"：中英文与字号一变就又不够了，本仓库已多次踩到
    写死尺寸随内容漂移的坑。）
   ⚠️ 只给"短状态词"列用。长文本列配 nowrap 会撑破表格（那些列本就该折行）。 */
.st-nowrap { white-space: nowrap; }

/* 底部固定元素（Cookie 横幅 + 售前客服悬浮球）在小屏上会互相叠压，
   也会盖住页脚最后几行（实测截图确认：375px 下客服球与横幅按钮区重叠）。
   这里给页脚留出安全内边距 —— 用 padding 而不是 margin，
   保证「页脚到底」时最后一行**能从固定元素下面完整露出来**。 */
@media (max-width: 1023px) {
    .st-footer { padding-bottom: 96px; }
}

/* ---------------------------------------------------------------------------
   15. 兼容桥：旧 `pub-` 类名与 `--pub-*` 变量
   2026-09-30 重设计时保留，避免一次性改 20+ 视图；新代码一律用 st-*。
   🔴 2026-10-10 暗色重设计：旧变量语义本就是「深色画布」（v4 时代官网是深色的），
   现在整站回到暗色，**这批变量反而回到了它们原始语义** —— 故这次翻转里
   它们几乎不需要改（这正是当初把它们桥接到浅色系的反向操作）。
   --------------------------------------------------------------------------- */
:root {
    /* ⚠️ 这三档必须与 §2 的 --st-canvas-soft / -elev / -cream 保持同值 ——
       它们是同一批表面层级的旧命名（v4 时代官网深色底留下的），
       §15 的桥接就是"一个层级、两个名字"。改一边不改另一边 = 旧页面卡片不跟随。 */
    --pub-ink-950: #0a0e17;
    --pub-ink-900: #131a28;
    --pub-ink-850: #1a2438;
    --pub-ink-800: #1e2a40;
    --pub-ink-700: rgba(255, 255, 255, .12);
    --pub-ink-600: rgba(255, 255, 255, .20);
    --pub-text-hi: #ffffff;
    --pub-text-mid: #cbd5e1;
    --pub-text-lo: #94a3b8;
    --pub-accent: #45bbfb;
    --pub-accent-hover: #69f7d3;
    --pub-signal: #45bbfb;
    --pub-signal-text: #69f7d3;
    --pub-signal-soft: rgba(69, 187, 251, .10);
    --pub-ok: #2fb57c;
    --pub-warn: #e4674a;
    --pub-radius-sm: 6px;
    --pub-radius-md: 12px;
    --pub-radius-lg: 16px;
}

/* 深色版面的旧类名：反白区块内的卡片/文字落到深色体系 */
.st-section--dark .pub-tool, .st-section--dark .pub-card, .st-section--dark .pub-feat__card,
.st-section--dark .pub-arch__card, .st-section--dark .pub-mini, .st-section--dark .pub-coverage {
    background: rgba(255, 255, 255, .05);
    border-color: var(--st-dark-hairline);
    color: var(--st-ink);
}
.st-section--dark .pub-tool h3, .st-section--dark .pub-card h3, .st-section--dark .pub-feat__card h3,
.st-section--dark .pub-arch__card h3, .st-section--dark .pub-mini h4, .st-section--dark .pub-coverage__head h3 {
    color: var(--st-ink);
}
.st-section--dark .pub-tool p, .st-section--dark .pub-mini p, .st-section--dark .pub-arch__card > p,
.st-section--dark .pub-arch__card li, .st-section--dark .pub-feat__card > p, .st-section--dark .pub-note {
    color: var(--st-on-dark-soft);
}
.st-section--dark .pub-coverage__chip, .st-section--dark .pub-chip {
    background: rgba(255, 255, 255, .06);
    border-color: var(--st-dark-hairline);
    color: var(--st-on-dark-soft);
}

/* 图标底座（旧 markup 里的 .pub-tool__ico） */
.pub-tool__ico {
    width: 34px; height: 34px;
    display: grid; place-items: center;
    border-radius: var(--st-r-md);
    background: rgba(69, 187, 251, .10);
    border: 1px solid rgba(69, 187, 251, .22);
    color: var(--st-primary);
}
.st-section--dark .pub-tool__ico {
    background: rgba(255, 255, 255, .08);
    border-color: rgba(255, 255, 255, .16);
    color: var(--st-ink);
}

/* ===========================================================================
   21. v9 设计层（子页 hero / 面板 / 数据带）
   ---------------------------------------------------------------------------
   🔴 2026-10-10 暗色重设计：本层的所有"浅色资产"（白底纹理图、浅色渐变面板、
   白色 UI 浮层）在暗色底上都不成立，逐项替换（详见各条注释）。
   --------------------------------------------------------------------------- */

/* ① 子页 hero：由「位图织带（白→粉紫曲线）」改为**暗色辉光**（与首页同一语言）。
   🔴 为什么不再用那张位图：它是 Stripe 的浅色资产（白底为主），
   暗色底上会露出一大片白、且遮住文字（属性是 `cover`）。
   改用 CSS 径向渐变（零资产依赖、配色与首页 .st-mesh 同源）。
   ⚠️ 高度仍由「内容 + 上下内边距」自然决定（v11 的结论，不要加 min-height）。 */
/* 子页 hero：**完全透明**（不画任何自己的背景）。
   🔴 2026-10-11 见 body 注释（§3 处）——它此前自己画了一层更强的辉光 + 不透明底，
   与顶栏显示的 body 辉光在交界处断档（业务反馈「能明显看到两层颜色」）。
   现辉光只在 body 定义一处，本层透明 → 顶栏 / hero / 后续内容**天然同底**。
   ⚠️ 不要"顺手"给它加回背景：哪怕是很淡的一层，只要它是**不透明底**就会再次截断
      body 的辉光、重新制造接缝。守卫：SiteDarkRedesignV8Test::test_inner_page_topbar_and_hero_share_one_background。
   ⚠️ `overflow: hidden` 保留：hero 内可能有超出容器的装饰元素。 */
.st-hero-weave {
    position: relative;
    overflow: hidden;
    background: transparent;
}
.st-hero-weave > .st-container { position: relative; z-index: 1; }

/* ── 内页 hero 的纵向留白（.st-hero-weave--page，2026-10-13 收口）──────────────
   原先 15 个内页各自在标签上写内联 `padding: 64px 0 80px;`（FAQ 页已漂移成
   `88px 0 96px`）—— 同一份留白复制了 15 遍：

     · 改一次要改 15 个文件（实际已经漂移了 1 处，且漂移**不报错**）；
     · 不跟随 `--st-section-y`，所以版块节奏调整（96→80）**内页完全没跟上**，
       首页与内页的疏密感开始分叉；
     · 内联样式的优先级高于样式表，将来想统一调只能逐个文件改。

   ## 为什么新建类而不是直接给 `.st-hero-weave` 加 padding
   SiteDesignSystemTest 精确断言了 `.st-hero-weave` 规则块**只能是**
   `position: relative; overflow: hidden; background: transparent;` 三条 ——
   那条守卫的意图是"hero 不得画自己的底色"（画了就会截断 body 的辉光、制造接缝）。
   往那个块里加 padding 会破坏该断言的字面匹配，让人误以为守卫失效。
   新类只承载留白，语义单一，与守卫的意图不冲突。

   ## 取值依据（实测内页 hero 内容高度）
   内页 hero 内容是眉标 + 标题 + 副标题（+ 少数页有 CTA），实测 291~359px。
   上方 64px 让标题不贴顶栏、下方 80px 与其后版块的 80px 拉开层次
   （hero 底 → 下一版块顶 的视觉间隔即 80px）。
   ⚠️ 下内边距**比上内边距大**是刻意的：hero 之后紧跟内容，视觉上需要
      "标题区收束得更充分"，上下等值反而显得头重。
   ⚠️ 不要改用 `--st-section-y`：那个变量是**版块之间**的节奏（80px），
      hero 是页面顶部、不参与版块交替的韵律 —— 混用会让首页的节奏调整
      意外改变所有内页的首屏高度。 */
.st-hero-weave--page { padding: 64px 0 80px; }
/* 2026-10-25 第三批：给内页 hero 加**微弱辉光**，与首页视觉统一。
   业务反馈：内页「内容不够吸引人」，对照首页的渐变 hero，内页顶部太素。

   🔑 手法：::before 画一层**比首页 mesh 弱一档**的径向渐变（透明收边）。
   ⚠️ 不用 .st-mesh（那是首页专用强度）且**不加不透明底**（否则截断 body 辉光
      → 复现 2026-10-11 的接缝事故）。这里只是「在 body 辉光之上叠一层微光」，
      渐变边缘到透明，无硬切。
   ⚠️ .st-hero-weave 本体不加（测试锁了三条属性）——写在 --page 修饰类上。 */
.st-hero-weave--page::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        radial-gradient(60% 55% at 50% -4%, rgba(69, 187, 251, .12) 0%, rgba(69, 187, 251, 0) 60%),
        radial-gradient(38% 34% at 82% 6%, rgba(105, 247, 211, .08) 0%, rgba(105, 247, 211, 0) 62%);
}
/* 窄屏同步收紧（与 --st-section-y 的移动端降级同一节奏）。 */
@media (max-width: 900px) {
    .st-hero-weave--page { padding: 44px 0 56px; }
}

/* ② 斜切渐变彩带（.st-ribbon）与配套的 .st-hero-ribboned：
   ⚠️ 2026-10-07 业务反馈「这条斜的彩条放在那显得有点奇怪」→ **全站移除**。
   原本 10 个页面在 hero 之后放 `<div class="st-ribbon">` 作 section 转换器，
   现全部删除，过渡交给 hero 纹理自身的底部收白完成。
   守卫：SiteDesignSystemTest 全站扫描（视图与样式表均不得再出现 st-ribbon）。 */

/* ③ 渐变面板：feature 卡片的底座（产品卡 = 渐变色块 + UI 浮层）。
   暗色版本：低透明度的青绿/天蓝辉光铺在提亮底上，保持"彩度集中在角部、
   中部接近底色"的可读性约定。
   🔴 2026-10-12 表面层级重标定：三档渐变底**同步提亮**。
   原线性渐变底（#101826≈1.09 / #0d1420≈1.05 / #131a24≈1.10）是照"旧 elev=1.120"
   配的；本次把 elev 提到 1.244 后，若面板底不动，就会出现
   **面板比它上面的普通卡片更暗**（语义倒置：面板本是"更高一层"的容器）。
   现按同等亮度差上移：普通面板≈elev 档，indigo≈elev 偏亮，warm≈介于 elev 与 cream 之间。
   ⚠️ 彩度（青绿/天蓝/暖黄辉光）**一个都没动** —— 业务明确"配色 OK"，只改亮度。 */
.st-panel {
    border-radius: var(--st-r-xl);
    padding: clamp(20px, 3vw, 40px);
    background:
        radial-gradient(120% 140% at 85% 10%, rgba(251, 224, 65, .12) 0%, rgba(251, 224, 65, 0) 55%),
        radial-gradient(130% 150% at 10% 90%, rgba(105, 247, 211, .18) 0%, rgba(105, 247, 211, 0) 60%),
        linear-gradient(150deg, #1a2438 0%, #1c2840 48%, #1d2944 100%);
    overflow: hidden;
}
.st-panel--indigo {
    background:
        radial-gradient(120% 140% at 85% 8%, rgba(105, 247, 211, .20) 0%, rgba(105, 247, 211, 0) 55%),
        radial-gradient(130% 150% at 8% 92%, rgba(69, 187, 251, .26) 0%, rgba(69, 187, 251, 0) 58%),
        linear-gradient(150deg, #1b2539 0%, #1d2941 55%, #1f2c48 100%);
}
.st-panel--warm {
    background:
        radial-gradient(120% 130% at 80% 0%, rgba(251, 224, 65, .16) 0%, rgba(251, 224, 65, 0) 55%),
        radial-gradient(120% 140% at 12% 100%, rgba(69, 187, 251, .20) 0%, rgba(69, 187, 251, 0) 58%),
        linear-gradient(160deg, #1e2a40 0%, #202d45 50%, #1d2942 100%);
}
/* 面板内嵌的「UI 浮层」卡：模拟产品界面截图（product mockup 位）。
   纯 CSS 实现：提亮卡 + 大投影 + 微旋转，内部由模板填 faux-UI 行。
   ⚠️ 暗色下不能再用纯白（那会是整页最亮的一块、把视线全吸走）——
   改为比面板亮一档的深色卡片。 */
.st-ui-float {
    background: #1b2436;
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 12px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, .5), 0 4px 12px rgba(0, 0, 0, .3);
    transform: rotate(-1.2deg);
    overflow: hidden;
}
.st-ui-float--flat { transform: none; }
.st-ui-row {
    display: flex; align-items: center; justify-content: space-between;
    padding: 11px 16px; border-bottom: 1px solid rgba(255, 255, 255, .06);
    font-size: .8125rem; color: var(--st-ink-2);
}
.st-ui-row:last-child { border-bottom: 0; }
.st-ui-row b { font-weight: 600; color: var(--st-ink); }
.st-ui-dot { width: 8px; height: 8px; border-radius: 9999px; display: inline-block; }
.st-ui-dot--ok { background: #2fb57c; }
.st-ui-dot--warn { background: #f59e0b; }
.st-ui-dot--bad { background: #ea2261; }
.st-ui-bar { height: 6px; border-radius: 9999px; background: rgba(255, 255, 255, .10); overflow: hidden; flex: 1; margin-left: 12px; }
.st-ui-bar > i { display: block; height: 100%; border-radius: 9999px; background: var(--st-grad); }

/* ④ 数据带（stats band）：整屏深色 + 自底部升起的品牌辉光。 */
.st-statsband {
    background:
        radial-gradient(90% 120% at 50% 118%, rgba(69, 187, 251, .34) 0%, rgba(69, 187, 251, 0) 62%),
        radial-gradient(60% 90% at 82% 108%, rgba(105, 247, 211, .20) 0%, rgba(105, 247, 211, 0) 60%),
        #060a12;
    color: var(--st-ink);
}
.st-statsband .st-statsband__num {
    font-size: clamp(2rem, 4vw, 3rem);
    font-weight: 300;
    letter-spacing: -.02em;
    color: var(--st-ink);
}
.st-statsband .st-statsband__label { margin-top: 10px; font-size: .875rem; color: var(--st-ink-mute); }

/* ⑤ 图标网格（细线分栏）：定价页「开箱即用的功能」同构。 */
.st-grid--lined > * {
    padding: 22px 24px;
    border-left: 1px solid var(--st-hairline);
}
.st-grid--lined > *:first-child { border-left: 0; }
@media (max-width: 900px) {
    .st-grid--lined > * { border-left: 0; border-top: 1px solid var(--st-hairline); }
    .st-grid--lined > *:first-child { border-top: 0; }
}

/* 渐变文字（品牌双色，与 .st-hl 同源）。 */
.st-text-gradient {
    background: var(--st-grad);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
    .st-text-gradient { color: var(--st-grad-start); background: none; }
}

/* ---------------------------------------------------------------------------
   统一卡片悬停：**所有** .st-card / .st-feature 抬升 + 品牌辉光
   ---------------------------------------------------------------------------
   ## 为什么需要这一节（2026-10-11 业务反馈）
   「有的板块鼠标移上去会有效果，有的又没有，统一改成都有那种鼠标放上去发光和上浮的效果」。
   实测首页 13 个板块，**只有 3 处有 hover**（工具卡/产品卡/服务卡 —— 它们被
   `<a class="st-card-link">` 包着），其余 9 处（证明/独有能力/技术执行/平台架构/
   数据可信/市场/出海/定价/智库）完全没反应；而 `#trust` 那种深色版面里的卡片
   连描边高亮都没有。原因是 hover 效果散落在**三处各写各的**（§7 一处、
   文件尾一处、§22.4 链接卡一处），互相覆盖、参数还不同。

   ## 本节是唯一事实来源（不要在别处再写卡片 hover）
   效果统一为「上浮 3px + 品牌辉光 + 描边转品牌色」，与原先只有链接卡才有的效果一致。

   ## 两个刻意保留的差异（不是遗漏，不要"统一"掉）
   ① **表单容器不上浮**：`st-card` 在注册 / 找回密码 / 体检 / 免费检测页被当作
      **表单外框**。整块上浮会让正在填写的内容跟着光标漂移（输入框位置变动），
      属可用性缺陷 → 排除"自身是 form"与"内部含 form"两种形态。
   ② **渐变描边卡（--dark）不改 border-color**：它们的边框是
      `padding-box` / `border-box` 双层背景铺出来的**品牌渐变**，
      改 `border-color` 会把它整条盖成实色（签名式视觉被抹平）→ 只做上浮+辉光。

   ## 降级考虑
   表单排除规则用了 `:has()`。若浏览器不支持 `:has()`，该规则整条失效，
   **后果是"表单卡也会上浮"**（轻微观感问题），而不是"所有卡都不上浮"——
   故把通用规则与排除规则**分成两条**写（而非写成一个 `:not(:has())` 长选择器），
   避免"一个选择器无效 → 整条规则被丢弃"把主要效果一起带走。
   （本文件早已依赖 `:has()`：顶栏抽屉的层级提升用了 `.st-nav:has(...)`。）
   --------------------------------------------------------------------------- */
.st-card:hover,
.st-feature:hover {
    transform: translateY(-3px);
    box-shadow: var(--st-glow);
}
/* 描边转品牌色：仅限"普通描边"的卡（渐变描边卡见上文差异②）。 */
.st-card:not(.st-card--dark):hover,
.st-feature:not(.st-feature--dark):hover {
    border-color: rgba(69, 187, 251, .45);
}
/* 表单容器保持**完全静止**（见上文差异①）。
   ⚠️ 除位移与投影外，**描边也要一起还原**：这里的真实不变量是
      「悬停时这块区域没有任何视觉变化」—— 否则填表时边框忽明忽暗，同样是干扰
      （首版只还原了 transform / box-shadow，真机实测描边仍会变色）。
   两条选择器配对：后一条针对普通描边卡（覆盖上面那条 `:not(--dark):hover` 的品牌色描边）；
   渐变描边卡（--dark）本来就被排除在描边高亮之外，无需处理。 */
.st-card:is(form, :has(form)):hover,
.st-card:is(form, :has(form)):not(.st-card--dark):hover {
    transform: none;
    box-shadow: none;
    border-color: var(--st-hairline);
}
/* 尊重"减少动态效果"：位移取消（保留辉光与描边作视觉反馈，
   色彩变化不涉及前庭刺激，不需要一并去掉）。 */
@media (prefers-reduced-motion: reduce) {
    .st-card:hover,
    .st-feature:hover { transform: none; }
}

/* 首页 hero 网格增强（v9 的暖色流向）已并入基础层 `.st-mesh::after`（见 §5 处的定义）。
   🔴 这里曾**二次定义**同名 `.st-mesh::after`，本意是"叠加"，实际是同权重后定义覆盖前定义
   —— 把白色收口渐变整条静默吃掉，丝带底部硬切（2026-10-07 业务反馈后修复）。
   **不要再在这里写第二份定义**：多一份 = 基础层静默失效。 */

/* 深色 CTA 带（子页页尾统一）：比 cream 更有力的收尾。 */
.st-cta-dark {
    background:
        radial-gradient(80% 130% at 50% 130%, rgba(69, 187, 251, .26) 0%, rgba(69, 187, 251, 0) 60%),
        #060a12;
    color: var(--st-ink);
    padding: 72px 0;
}
.st-cta-dark .st-display-md { color: var(--st-ink); }
/* CTA 副标（如 /services 的收尾引导语）：居中排版的区块**不能**跟着 hero 放宽——
   居中文本的舒适行宽本就比左对齐窄（这里沿用原 44rem），且必须 `margin-inline:auto`
   才居中（hero 版式是 `margin: 18px 0 0`，左边距为 0，靠父级 text-align 只会让
   文字在超宽盒子内居中、盒子本身仍从左边起算 → 视觉上偏左）。
   ⚠️ 宽度经 `--st-hero-sub-max` 传入，见 `.st-hero__sub` 的注释（变量法避免权重之争）。 */
.st-cta-dark .st-hero__sub { --st-hero-sub-max: 44rem; margin-inline: auto; color: var(--st-ink-mute); }

/* ===========================================================================
   22. 新官网设计层（2026-10-10 暗色重设计）
   ---------------------------------------------------------------------------
   依据：设计师交付的新首页首屏 demo（gemini-code-1791563202031.html）。
   本层新增 demo 引入的元素：顶部信息条 / 居中 hero / 综合诊断输入框 /
   可点击整卡 / 专业服务卡 / 移动端适配收紧。

   ⚠️ 命名约定：新增一律 st- 前缀；色值只从 §2 的 --st-* 取。
   =========================================================================== */

/* ---------------------------------------------------------------------------
   22.1 顶部信息条（**仅首页**：由视图控制，不放进公共顶栏 partial ——
   其它页面加这个条会与各自的 hero 争视觉焦点，且业务明确说"其他页面不需要"）
   demo 的"流光渐变通告栏"：渐变背景 + 缓慢流动动画 + 深色文字。
   --------------------------------------------------------------------------- */
/* 外层定位锚（2026-10-19 加关闭按钮）：
   关闭按钮必须是链接的**兄弟节点**（button 不能嵌在 a 里），故需要一个相对定位的容器。 */
.st-announce-wrap { position: relative; }
.st-announce-wrap[hidden] { display: none; }

.st-announce {
    position: relative;
    display: block;
    /* 左右对称留出关闭按钮的宽度（52px）：按钮绝对定位在右侧，
       对称内边距保证中间文案仍然相对视口居中（只加右侧会让文案整体偏左）。 */
    padding: 10px 52px;
    text-align: center;
    font-size: .875rem;
    font-weight: 600;
    /* 渐变面上的文字必须用深色（青蓝渐变很亮，白字不可读）。 */
    color: var(--st-on-gradient);
    background: linear-gradient(90deg, var(--st-grad-start), var(--st-grad-end), var(--st-grad-start));
    background-size: 200% auto;
    /* 🔴 流光动画（demo 的 `.top-bar` 同款）。
       ## 澄清一处误会（2026-10-11）
       业务反馈"demo 顶部那条渐变有动画，你好像遗漏了"—— 其实本动画**自 r2814 起就在**，
       只是我当时用无头浏览器自查时它**恒为静止**：Chromium headless 默认上报
       `prefers-reduced-motion: reduce`，正好命中我们下面那段无障碍回退，
       于是"看起来像没做"（我当时的截图与计算样式都显示 animationName: none）。
       强制启用后实测 background-position 在 1.5s 内由 0% 走到 -49.79%，
       速率与 200%/6s 完全吻合 —— 动画本身一直是好的。
       ⚠️ 教训：**用无头浏览器验证"动效类"功能会得到假阴性**。
          验证动作本身要能区分"功能没做"与"渲染器把动效关了"。
       ## 时长
       6s → **5s**，与 demo 的 `animation: panGradient 5s linear infinite` 对齐。

       ## 🔴 2026-10-11 三次修正：**移除了 `prefers-reduced-motion` 回退**（业务二次反馈）
       业务第二次反馈「还是没有帮我把动画加上去」。复核确认：动画代码一直完整正确
       （声明 / 关键帧 / background-size 三件齐备，实测位置确实在流动），
       **但下面那条无障碍回退把它关掉了** —— 只要运行环境报告
       `prefers-reduced-motion: reduce`（Windows 的"关闭动画效果"、浏览器省电模式、
       以及**无头浏览器默认值**都会报告它），动画就恒为静止。
       实测：删掉那条回退后，`background-position` 2.5s 内由 -0.7% 走到 -101.8%。

       ## 权衡（为什么敢去掉回退）
       WCAG 2.3.3 针对的是**大幅位移 / 缩放 / 视差**这类可能引发前庭不适的动效；
       本动效只是**背景色相的缓慢流动**（无位移、无缩放、无闪烁，周期 5s、首尾同色），
       属最低风险的一档；而业务已两次明确要求必须有此效果，故以业务要求为准。
       ⚠️ 若日后收到"看着晕"的反馈，正确做法是**放慢并降低对比**（如周期拉到 12s），
          而不是再把它整个关掉 —— 关掉就回到了"看不到动画"的老问题。 */
    animation: stPanGradient 5s linear infinite;
    text-decoration: none;
    cursor: pointer;
    z-index: 200;
}
.st-announce:hover { color: var(--st-on-gradient); }
/* 动画收敛：渐变背景横向平移，视觉上像"流光"。
   渐变是 start→end→start **三停靠点**（首尾同色），故平移整整一轮（-200%）后
   画面与起点完全重合 —— 循环时不会出现"跳一下"的接缝。 */
@keyframes stPanGradient {
    0% { background-position: 0% center; }
    100% { background-position: -200% center; }
}
/* 文字 + 箭头作为**一体**做撞击动画（2026-10-19 业务要求）：
   从左侧 30px 处向右撞到静止位置 → 阻尼回弹 → 静止片刻 → 退回到左侧 30px → 再撞。
   ⚠️ 动画只挂在 motion 组上，不挂整条 `.st-announce` —— 后者已有渐变流光动画，
      两个 animation 写在同一元素上会互相覆盖（后写的赢）。
   ⚠️ 不加速度无关的 reduced-motion 回退：与渐变流光同口径（见上文 2026-10-11 三次修正），
      本动效是 30px 内的短距离位移，不属 WCAG 2.3.3 的高风险类别。 */
.st-announce__motion {
    display: inline-flex;
    align-items: center;
    gap: 8px;                 /* 文字与箭头之间留一点气口（原由 inner 的 gap 提供） */
    animation: stAnnounceBump 3s infinite;
    will-change: transform;
}
/* 🔴 2026-10-20：文字整体是一个 flex 项 —— 品牌名规范化后 HTML 是
   `backspace<strong>geo</strong>`，若让 <strong> 直接做 motion 的子节点，
   它会被当成独立 flex 项、被上面的 gap 顶开 8px，页面上就显示成「backspace geo」。
   故文字必须包在 `.st-announce__label` 里（一个 flex 项），gap 只作用于「文字 ↔ 箭头」。
   ⚠️ `<strong>` 自身不能有任何 margin/padding/display 改变 —— 它必须保持行内、紧贴 backspace。 */
.st-announce__label { display: inline; }
.st-announce__label strong { display: inline; margin: 0; padding: 0; font-weight: 800; }
/* 时间轴（3s 一轮）：
   0%~22%   从 -30px **加速**撞向 0（ease-in ≈ 自由落体，越接近越快）
   22%~50%  阻尼回弹：+5 → -2 → +1 → 0（幅度逐次减半，最终静止）
   50%~62%  完全静止（让"停住"被看见）
   62%~88%  缓慢退回左侧 30px（ease-in-out，不是瞬间跳回）
   88%~100% 在起点短暂停留，随后进入下一轮撞击
   ⚠️ 起点与终点都是 -30px（首尾同值），循环时不会"跳一下"。 */
@keyframes stAnnounceBump {
    0%   { transform: translateX(-30px); animation-timing-function: cubic-bezier(.6, 0, .9, .4); }
    22%  { transform: translateX(0);     animation-timing-function: cubic-bezier(0, 0, .35, 1); }
    30%  { transform: translateX(5px);   animation-timing-function: cubic-bezier(.45, 0, 1, .55); }
    38%  { transform: translateX(-2px);  animation-timing-function: cubic-bezier(0, 0, .35, 1); }
    45%  { transform: translateX(1px);   animation-timing-function: cubic-bezier(.45, 0, 1, .55); }
    50%  { transform: translateX(0); }
    62%  { transform: translateX(0);     animation-timing-function: cubic-bezier(.4, 0, .2, 1); }
    88%  { transform: translateX(-30px); animation-timing-function: linear; }
    100% { transform: translateX(-30px); }
}
.st-announce__inner {
    display: inline-flex; align-items: center; justify-content: center;
    flex-wrap: wrap; gap: 12px;
}
/* 箭头（矢量图标，2026-10-19 由 `&rarr;` 字符换成 lucide arrow-right）：
   字符箭头受 Arial 基线影响、在 flex 里视觉偏下；SVG 由 align-items:center 精确居中。
   ⚠️ 尺寸用 em（随字号缩放），并显式 block 化去掉 inline 基线留白。 */
.st-announce__arrow { display: block; width: 1.05em; height: 1.05em; flex-shrink: 0; }
/* 关闭按钮：绝对定位压在链接右上角（z-index 300 > .st-announce 的 200）。 */
.st-announce__close {
    position: absolute;
    top: 50%;
    right: 14px;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--st-on-gradient);
    opacity: .72;
    cursor: pointer;
    z-index: 300;
    transition: opacity .2s ease, background .2s ease;
}
.st-announce__close:hover { opacity: 1; background: rgba(10, 14, 23, .12); }
.st-announce__close:focus-visible {
    opacity: 1;
    outline: 2px solid var(--st-on-gradient);
    outline-offset: 2px;
}
.st-announce__close svg { width: 15px; height: 15px; }
@media (max-width: 767px) {
    /* 窄屏同步收窄左右留白（关闭按钮仍占右侧 26px + 边距）。 */
    .st-announce { font-size: .8125rem; padding: 9px 44px; }
    .st-announce__close { right: 10px; width: 24px; height: 24px; }
    /* 🔴 2026-10-13 窄屏隐藏定位修饰语（评审 §2.3 的"顶栏过高"同族问题）。
       实测 390px：「免费体验 BackspaceGEO → 面向 AI 搜索时代的一站式解决方案」
       可用宽 362px 而文本需 ~384px → 折成 2 行，公告条由 38px 涨到 69px；
       连同顶栏合计 173px ≈ 屏幕高度 20%，全部压在首屏内容之前。

       ## 为什么是隐藏而不是缩字号/减间距
       试算过：gap 12 → 6px、字号 13 → 12px 后约 344px，仍只比可用宽窄 18px ——
       不同手机的中文字体（Android 各家 ROM）字宽不一，会**随设备再次折行**，
       属于"在某些手机上看着好、在另一些上崩"的脆弱方案。隐藏则恒为一行。

       ## 为什么可以隐藏（不是丢内容）
       suffix 是品牌定位修饰语，hero 副标题已完整表达同一件事；
       而公告条本身是**获客入口**（整条仍是链接指向免费检测），
       「免费体验 BackspaceGEO →」已是完整 CTA，语义不缺。
       ⚠️ 只隐藏视觉，DOM 与语言键都保留（≥768px 完整显示）——
          不要改成在 Blade 里 @if 掉，那会让宽屏也拿不到这句话。 */
    .st-announce__suffix { display: none; }
}

/* ---------------------------------------------------------------------------
   22.2 居中 hero（demo 的 .hero-section 形态：标题/副标题/搜索框全部居中）
   ⚠️ 与既有的 `.st-hero__copy`（左对齐营销版）并存 —— 首页改用居中版，
   其余页面（注册/工具/法律）仍走左对齐版，不受影响。
   --------------------------------------------------------------------------- */
.st-hero--center { padding: 72px 0 72px; }
@media (max-width: 900px) { .st-hero--center { padding: 52px 0 56px; } }

/* ── 首页 hero 撑满首屏（`.st-hero--full`，2026-10-11 业务要求）───────────────
   「把 hero 高度撑满，自适应，确保首页在不同设备分辨率上都只显示
     logo、导航菜单、标语、子标语、输入框和提交按钮」

   ## 实现
   `min-height: 100svh` —— 用 **svh** 而不是 vh：移动端浏览器地址栏会占用视口高度，
   `100vh` 在 iOS Safari / Android Chrome 上比"实际可见高度"高出一截，
   导致 hero 底部（提交按钮）被地址栏盖住、首屏看不全（这是最典型的移动端首屏缺陷）。
   `svh` = small viewport height（地址栏展开时的最小可见高度），故内容恒不被遮挡。

   ## 三段式高度：flex 垂直居中 + 内容自身留白
   用 flex 把内容在 min-height 内**垂直居中**（而不是靠 padding 堆），
   于是"内容少 → 居中留白对称；内容多 → 自然撑高"，
   不需要为不同分辨率写断点。

   ## ⚠️ 为什么是 min-height 而不是 height
   业务明确「可以设置一个最小高度，当高度实在太小没办法完整显示这些内容的时候
   就可以不考虑这个约束」—— `min-height` 正好是这个语义：
   内容比视口高时它**自动让路**（页面正常滚动，不裁切、不重叠）。
   🔴 若改成 `height: 100svh`，矮视口（如横屏手机 / 小笔记本）会把表单压出屏幕外，
      且**不报错**（只是内容看不见了）。
   --------------------------------------------------------------------------- */
.st-hero--full {
    display: flex;
    flex-direction: column;
    min-height: 100svh;
    /* 不支持 svh 的老浏览器退回 vh（Safari <15.4 / Chrome <108）——
       宁可略有偏差，也不要整个 min-height 失效（那会塌成内容高度）。 */
    min-height: 100vh;
}
/* svh 可用时覆盖掉上面那行 vh 兜底（同一条规则里写两遍不会生效，故分开写）。 */
@supports (min-height: 100svh) {
    .st-hero--full { min-height: 100svh; }
}
/* 内容容器吃掉剩余高度并垂直居中 —— 顶栏（作为 hero 的第一个子元素）自然贴顶，
   正文容器居中于「顶栏以下、hero 底部以上」的剩余空间。 */
.st-hero--full > .pub-hero__grid,
.st-hero--full > .st-hero__grid {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
}
/* 🔴 2026-10-11 修正选择器（一个"永远没生效"的静默缺陷）。
   原写法是 `.st-hero--full .st-hero--center`（**后代**选择器），
   但这两个类在**同一个元素**上：
     `<section class="st-hero st-hero--bleed st-hero--center st-hero--full">`
   后代选择器要求 `.st-hero--center` 是 `.st-hero--full` 的**子孙**，
   故这条规则从未匹配过 —— 首页 hero 一直吃着 `.st-hero--center` 的 `padding: 72px 0`。
   后果：hero 顶部留白 72px，把导航往下推（真机实测「信息条下沿 → logo」有 92px），
   正是业务反馈的「首页 logo 和导航距离上面的空隙太大」。
   ⚠️ 教训：类名写在同一个元素上时，修饰类之间的组合必须用**紧邻**写法
      （`.a.b`，无空格）；带空格就成了后代关系，且**不报错、只是不生效**。
   现改法：`.st-hero--full.st-hero--center`（0,2,0）压过 `.st-hero--center`（0,1,0），
   padding-top 收到 8px（配合 `.st-nav--home` 的 20px ⇒ 信息条到 logo 共 28px）。 */
.st-hero--full.st-hero--center { padding-top: 8px; padding-bottom: 24px; }
/* 居中版内容块：hero 撑满时不需要大 padding（留白由 flex 居中给），
   否则矮视口下 padding + 内容会超出 min-height、把表单推到首屏之外。 */
/* 🔴 2026-10-20 业务要求：hero 主标题/副标题容器**加宽**。
   起因：业务反馈「英文版主标题和副标题左右边感觉窄了」。
   实测（1440/1920 两档）容器宽度中英文**完全相同**（标题 900px、副标题 700px），
   只是英文句子更长、被折成 4 行，每行文字实际只有约 600px，视觉上显窄。
   故按要求把容器放宽：标题 900 → 1080px，副标题 700 → 880px。
   ⚠️ 1080px 仍小于 `.site-container` 在 1280 档的内容宽（约 1132px），
      不会撑破版面；表单自带 760px 上限，不受影响。 */
/* 2026-10-25 业务要求：hero 主标题宽度**至少加宽 50%**（1080 → 1620px）。

   🔴 必须先放宽外层容器，否则改了看不出效果：
      `.site-container` 的宽是 min(100% - 2rem, --content-max-width)，而
      --content-max-width = 76rem(1216px) —— 减去 `lg:px-8` 的 64px 内边距后
      内容区只有约 1152px。只把标题 max-width 改成 1620px 会被外层先截断，
      实际只多约 6%，**肉眼几乎无变化、却以为需求已做**（这类"改在错的层"
      是本项目反复踩的形态）。
      故这里只对**首页 hero 的直接子容器**抬高该变量，其它页面容器完全不变。

   ⚠️ 为什么是 1700px：标题要渲染成 1620px，容器须 ≥ 1620 + 64(内边距) = 1684px，
      取 1700px 留一点余量。1920 屏下两侧各留约 110px，hero 本就是浮层背景，
      不影响观感。
   ⚠️ 副标题(880px)、表单(760px) 各自有 max-width，本规则不改它们 ——
      业务要求「hero 里其他内容宽度不变」即靠这一层保证。 */
.st-hero--full > .site-container,
.st-hero--full > .st-container {
    --content-max-width: 1700px;
}

/* 内层正文容器与主标题同步放宽到 1620px（= 1080 × 1.5）。
   ⚠️ 1080px 仍小于 `.site-container` 在 1280 档的内容宽（约 1132px），
      不会撑破版面；表单自带 760px 上限，不受影响。 */
.st-hero--full .st-hero__center { padding-top: 24px; padding-bottom: 24px; max-width: 1620px; width: 100%; }

.st-hero__center {
    /* 主标题字号（流体），2026-10-19 抽成变量：
       业务要求「主标题↔输入框」「输入框↔副标题」两处间距都**至少等于主标题文字大小**。
       字号与间距必须同源 —— 各写一份 clamp 时，将来调字号必然漏改间距（§9.7 同族漂移）。
       两处间距直接引用它，于是任何断点下都恒等于标题字号。
       ⚠️ 2026-10-25 业务要求「首页主标题和副标题都加大一些」：
          36/65/72px（2.25rem/5.8vw/4.5rem）→ **40/72/80px**（2.5rem/6.4vw/5rem）。
          上限 80px 仍遵守「首屏放得下六件元素」的约束（1440 宽下标题两行、
          整屏约 690px，hero 用 min-height 撑满仍有留白）。
          上下限同步上调（只调上限会让中段看不出变化）。 */
    --st-hero-title-size: clamp(2.5rem, 6.4vw, 5rem);
    /* 副标题与上方输入框的间距（2026-10-25 业务要求「缩到目前的一半」）。
       仍**以标题字号为基准**（× 0.5），而不是写死 px：
       写死值在字号随断点变化后会变成"大屏很挤、小屏很松"，且下次调字号必然漏改
       （§9.7 同族漂移）。现 1440 档 = 80×0.5 = 40px，390 档 = 40×0.5 = 20px。
       ⚠️ 2026-10-19 曾要求「两处间距都 ≥ 标题字号」，本条只把**副标题这一侧**改为半量；
       标题↔表单那处仍是全量（见 .st-hero__title-c 的 margin）。 */
    --st-hero-sub-gap: calc(var(--st-hero-title-size) * .5);
    display: flex; flex-direction: column; align-items: center;
    text-align: center;
    /* 2026-10-25：随主标题加宽同步 1080 → 1620px（业务要求标题至少 +50%）。
       这里是**容器**宽度；标题自身另有同样的上限（见 .st-hero__title-c）。 */
    max-width: 1620px;
    margin: 0 auto;
}
/* demo 的主标题：渐变文字 + 细字重 + 大字号。
   ⚠️ 用 clamp 做流体缩放（demo 是写死 65px，窄屏会被挤出横向滚动条）；
   上限已由 65px 上调到 72px（见下方注释，业务要求"再调大一点"）。 */
.st-hero__title-c {
    /* 🔴 2026-10-11 业务要求"主标语文字再调大一点"：
       上限 4.0625rem(65px) → **4.5rem(72px)**，流体区间同步上调
       （5.2vw → 5.8vw，保证中段也跟着变大，而不是只有最大档变大）。
       ⚠️ 上限受"首屏要能完整放下六件元素"约束（hero 用 min-height 撑满）——
          72px 时标题在 1440 下仍是两行、整屏内容约 640px，留白充足。 */
    font-size: var(--st-hero-title-size);
    font-weight: 300;
    line-height: 1.2;
    letter-spacing: -.02em;
    /* 与输入框表单的间距 = **主标题字号**（2026-10-19 业务要求「至少调到主标题文字大小」）。
       直接引用字号变量而非写死 px：72px 字号下即 72px，窄屏 36px 字号下即 36px，
       任何断点都严格满足"间距 ≥ 标题文字大小"，且不会随字号调整而失效。
       （此前为 40px，小于 72px 的字号，视觉上标题与表单挤在一起。） */
    margin: 0 0 var(--st-hero-title-size);
    /* 2026-10-20 随容器加宽：900 → 1080px（英文长句折行更多、每行更短，
       放宽后行宽能拉起来；中文仍是两行，只是每行更舒展）。
       2026-10-25 业务要求「主标题宽度至少加宽 50%」：1080 → **1620px**。
       ⚠️ 副标题(880px)与表单(760px)的 max-width 不受影响 —— 业务要求
          「hero 里其他内容宽度不变」，靠各自独立的 max-width 保证。 */
    max-width: 1620px;
    /* 2026-10-19 业务要求：文字渐变由**左右**改为**上下**（青绿在上 → 青蓝在下）。
       仍是同一组品牌色标，只是方向从 90deg 切成 180deg —— 不要改回 var(--st-grad)
       （那是 90deg 的简写，改回去会静默恢复左右渐变）。 */
    background: linear-gradient(180deg, var(--st-grad-start), var(--st-grad-end));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    text-wrap: balance;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
    .st-hero__title-c { color: var(--st-ink); -webkit-text-fill-color: currentColor; background: none; }
}
.st-hero__sub-c {
    /* 2026-10-25 业务要求「副标题也加大一些」：1.25rem(20px) → 1.375rem(22px)。
       只加正文级字号，不动行高比例与 max-width，行数与折行位置基本不变。
       2026-10-25 二次：颜色 --st-ink-mute（半透明白）→ **纯白**（业务要求）。
       ⚠️ 只影响首页 hero 副标题（本类仅首页使用），不动全站 --st-ink-mute。 */
    font-size: 1.375rem;
    line-height: 1.6;
    color: #ffffff;
    /* 2026-10-20 随容器加宽：700 → 880px（英文副标题 5 行 → 更少的行、
       每行更饱满；中文 3 行变 2 行）。仍略窄于主标题，保持"副信息"的层级差。 */
    max-width: 880px;
    /* 2026-10-19：副标题移到输入框 + 提交按钮**下方**，故间距方向翻转 ——
       原来的 margin-bottom（给表单让位）改为 margin-top（与表单拉开呼吸）。
       2026-10-25 业务要求「副标题与输入框的间距缩到目前的一半」→ 改用 --st-hero-sub-gap
       （= 标题字号 × 0.5），当前 1440 档 40px、390 档 20px。
       ⚠️ 不要在这里写 em：em 相对的是副标题自己的字号，会变成 18~22px 且与标题无关。 */
    margin: var(--st-hero-sub-gap) 0 0;
}
@media (max-width: 767px) {
    /* ⚠️ 这里**不能**再覆盖 margin-top：间距走 --st-hero-sub-gap（随标题字号等比缩小），
       写死小值会让"一半间距"这个关系在手机上失效。 */
    .st-hero__sub-c { font-size: 1.125rem; }
}

/* ---------------------------------------------------------------------------
   22.3 综合诊断输入框（demo 的 .search-container：白底胶囊输入 + 渐变胶囊按钮）
   ## 这与首页此前的"双 CTA 按钮"不同
   它把「官网诊断 + AI 可见性诊断」合成**一次提交**：用户填一次企业/品牌名 + 域名，
   后端两个检测一起跑、出一份综合报告。故它是一个真正的表单（method GET），
   不是两个跳转按钮。
   ⚠️ 输入框用**白底**（demo 原型）：暗色页面里唯一的亮块，
   是首屏最强的视觉焦点 —— 这正是要的效果（老板要把它做成第一转化点）。
   ⚠️ 文字在**白底**上必须用深色（不是 --st-ink，那个是纯白）。
   --------------------------------------------------------------------------- */
.st-diag {
    display: flex;
    gap: 16px;
    width: 100%;
    max-width: 760px;
    justify-content: center;
    margin: 0 auto;
}
/* 🔴 2026-10-11 二次调整（业务澄清了准确形态）：**宽屏一个框、窄屏两个框**。
   · **默认（放得下）**：两个输入并排，外面**包一个框** —— 即外框（渐变描边 + 白底胶囊）
     挂在 `.st-diag__group` 上，两个 `.st-diag__field` 自身**无边框无底色**，
     之间用一条竖分隔线（`.st-diag__sep`）区隔；
   · **窄屏（≤640px）**：外框取消，改由**每个 field 各自带完整渐变描边与圆角**、
     上下堆叠 —— 这就是"拆成两个独立的框"。
   上一版把它做成了"永远两个框"，与业务本意相反，故本次反转样式归属。
   ⚠️ 高度要配平：外框有 3px 边框，故 field 高度取 56-6=50px，
      这样"外框总高 56px"与提交按钮的 56px 严格一致（此前 field 自己带边框时写 56px）。
   ⚠️ 焦点态挂在**外框**上（宽屏）——若挂在 field 上，无边框的 field 会画出一个
      方形阴影、与外框的胶囊形状打架。窄屏改用 field 自己的焦点态（见下方媒体查询）。 */
.st-diag__group {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    border-radius: var(--st-r-pill);
    /* 渐变描边 + 白底（demo 的 padding-box / border-box 双层渐变手法）。 */
    border: 3px solid transparent;
    background:
        linear-gradient(#fff, #fff) padding-box,
        var(--st-grad) border-box;
    transition: box-shadow .3s ease;
}
.st-diag__group:focus-within { box-shadow: 0 6px 24px rgba(69, 187, 251, .28); }
.st-diag__field {
    flex: 1;
    min-width: 0;
    display: flex; align-items: center;
    padding: 0 24px;
    height: 50px;              /* 50 + 外框 3px×2 = 56px，与按钮等高 */
}
.st-diag__input {
    width: 100%;
    background: transparent;
    border: none;
    outline: none;
    /* 白底上的深色文字（与 --st-ink 无关 —— 那个是给暗底用的白字）。 */
    color: #0a0e17;
    font-family: var(--st-font);
    font-size: 1rem;
    font-weight: 500;
}
.st-diag__input::placeholder { color: #94a3b8; font-weight: 400; }
/* 两个输入之间的竖分隔线：**宽屏可见**（两个输入在外框内并排时才有意义），
   窄屏拆成两个独立框后由媒体查询隐藏。
   ⚠️ 用 `align-self: stretch` + 上下 margin 做**内缩**（不贴外框上下边），
      这是"一个框里两格"的通行观感；margin 写成 14px 0 而不是左右留白，
      因为左右间距已由 field 的 padding（24px）提供。 */
.st-diag__sep {
    flex: 0 0 auto;
    width: 1px;
    align-self: stretch;
    margin: 14px 0;
    background: rgba(10, 14, 23, .14);
}
.st-diag__btn {
    flex-shrink: 0;
    height: 56px;
    padding: 0 40px;
    border: none;
    border-radius: var(--st-r-pill);
    background: var(--st-grad);
    color: var(--st-on-gradient);
    font-family: var(--st-font);
    /* 🔴 2026-10-11 业务要求：按钮文字 1.125rem(18px) → **1.5rem(24px)**。
       ⚠️ 高度不跟着放大：56px 高配 24px 字（行高 1.2 → 28.8px）左右各留 ~13px，
          仍在舒适区间；撑高会破坏"与输入外框等高"这个对齐关系。
       ⚠️ 窄屏（≤767px）按钮独占一行、宽度 100%，字号由 media query 回落，见下方。 */
    font-size: 1.5rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(69, 187, 251, .22);
    transition: box-shadow .2s ease, transform .2s ease, opacity .2s ease;
}
.st-diag__btn:hover {
    opacity: .95;
    box-shadow: 0 6px 20px rgba(69, 187, 251, .42);
    transform: translateY(-1px);
}
.st-diag__btn:active { transform: none; }
.st-diag__btn:disabled { opacity: .6; cursor: not-allowed; transform: none; }

/* 移动端：输入框与按钮**纵向堆叠**（横向会把输入框压到不可用宽度，
   且 iOS 上聚焦缩放会让布局跳动）。 */
@media (max-width: 767px) {
    .st-diag { flex-direction: column; gap: 14px; }
    /* 窄屏按钮独占一行：字号回落一档（24px 在 52px 高的按钮里偏挤），
       但仍比改版前的 16px 大 —— 首屏主 CTA 的权重保持一致。 */
    .st-diag__btn { width: 100%; height: 52px; font-size: 1.25rem; }
    .st-diag__field .st-diag__input { text-align: center; }
}

/* 🔴 「一个框」→「两个框」的切换点：**640px**
   （业务要求的准确条件是：「实在没办法把两个框并排放在一行的时候」才拆分）。
   为什么是 640 而不是 767：
     · 768px 起两个输入各约 285px、640px 各约 300px —— **都放得下**，
       此时保持"一个外框"更贴近 demo 的观感，过早拆分属于过度降级；
     · 640px 以下继续并排时，两个输入各约 170~250px，
       域名那条 placeholder（约 150px 宽）加上 24px×2 内边距就开始被截断 ——
       这正是"实在放不下"的临界点。
   ⚠️ 与上面 767px 的块**不是同一件事**：767 管的是"按钮换行"，
      640 管的是"外框是否拆开"。两个断点各自独立，改一个不要顺手改另一个。 */
@media (max-width: 640px) {
    /* 外框取消（不再有渐变描边/白底/圆角）。 */
    .st-diag__group {
        flex-direction: column;
        align-items: stretch;
        gap: 12px;
        border: 0;
        background: none;
        border-radius: 0;
    }
    /* 拆开后：每个输入框**自带完整外框**（渐变描边 + 白底 + 胶囊圆角）。 */
    .st-diag__field {
        width: 100%;
        height: 52px;              /* 自己是框了，含 3px 边框 */
        padding: 0 18px;
        border-radius: var(--st-r-pill);
        border: 3px solid transparent;
        background:
            linear-gradient(#fff, #fff) padding-box,
            var(--st-grad) border-box;
        transition: box-shadow .3s ease;
    }
    /* 焦点态改挂 field（宽屏那条挂在外框上，此处外框已无边框）。 */
    .st-diag__field:focus-within { box-shadow: 0 6px 24px rgba(69, 187, 251, .28); }
    /* 竖分隔线在两个独立框之间没有意义 → 隐藏（元素保留，宽屏仍在用）。 */
    .st-diag__sep { display: none; }
}

/* ---------------------------------------------------------------------------
   22.4 可点击整卡（首页各板块"下钻"用）
   业务要求：有些板块/功能介绍应该能点进详情页，但不必全部强行加。
   实现为把 <article> 包进 <a>（整卡可点），而不是给卡片加 JS 点击 ——
   原生 <a> 有正确的语义（键盘 Tab / 右键新标签 / 读屏器），JS 点击没有。
   ⚠️ 卡内若还有次要链接，包整卡会造成嵌套 <a>（HTML 非法、浏览器会拆开）——
      故**只有单一出口的卡片**才用本类；多出口的卡保持普通卡片。
   --------------------------------------------------------------------------- */
a.st-card-link { display: block; text-decoration: none; color: inherit; }
a.st-card-link:hover { color: inherit; }
/* ⚠️ 只保留"撑满高度"这一条 —— hover 效果已收口到「统一卡片悬停」一节
   （原先这里又写了一遍 transform/border/shadow，是那次"有的动有的不动"的成因之一：
   同一页面上三种卡片各自吃不同来源的 hover 规则）。 */
a.st-card-link .st-card,
a.st-card-link .st-feature {
    height: 100%;
}
a.st-card-link:focus-visible .st-card,
a.st-card-link:focus-visible .st-feature {
    border-color: var(--st-primary);
    box-shadow: 0 0 0 3px rgba(69, 187, 251, .3);
}
/* 整卡可点时，卡内那个"了解详情 →"的箭头链接也应随整卡一起有反馈。 */
a.st-card-link:hover .st-link-arrow { color: var(--st-primary-deep); }
a.st-card-link:hover .st-link-arrow::after { transform: translateX(2px); }

/* ---------------------------------------------------------------------------
   22.5 页脚法律行的暗色修正
   兼容桥把 --pub-* 改回深色语义后，页脚里由 footer-filing partial 渲染的
   备案链接会取到深色文字（在深底上不可见）—— 这里显式钉住。
   ⚠️ 这是"两套变量体系交界处"的典型坑：一处按旧语义写、一处按新语义写，
      在明暗翻转时必然有一边错，且**不报错、只是看不见**。

   🔴 2026-10-11 二次修正（业务要求备案与版权"样式弄成一样"）：
     本规则的选择器权重是 0,2,1（`.st-footer .pub-footer-filing a`），
     **高于** `.st-filing-link`（0,1,0）—— 于是行内模式下备案仍是 muted 灰，
     而版权（`.st-footer--dark .st-footer__legal` 给的 rgba(255,255,255,.56)）
     是另一种灰：真机量出 rgb(148,163,184) vs rgba(255,255,255,.56)，**不同色**。
     ⚠️ 中间试过只排除链接（`a:not(.st-filing-link)`）—— **仍然不同色**：
        包裹层 `.pub-footer-filing` 自己也被钉了色，链接 `inherit` 到的正是那个灰。
     定稿：partial 给包裹层加标记 `pub-footer-filing--inline`，本规则整体让路，
        回到 `.st-filing-link { color: inherit }` 跟随页脚变体 —— 两变体下都与版权严格同色。
     ⚠️ 非行内模式（租户主题站用的那支）**必须继续被本规则覆盖**，
        否则它在深色底上会再次变成看不见的深色字（这就是本规则当初存在的原因）。
     ⚠️ `:not()` 的权重含其参数（0,1,0），故整条选择器权重升到 0,3,1 ——
        高于 `.st-filing-link`，但已显式排除该分支，不会互相打架。 */
/* ⚠️ 排除行内模式：`a:not(...)` 只能排除链接本身，**包裹层仍会被钉色**，
   而链接的 `color: inherit` 会继承包裹层那个灰 → 与版权不同色。
   故这里用 `.pub-footer-filing--inline` 把整个分支让路（含包裹层）。 */
.st-footer .pub-footer-filing:not(.pub-footer-filing--inline),
.st-footer .pub-footer-filing:not(.pub-footer-filing--inline) a,
.st-footer .pub-footer-filing:not(.pub-footer-filing--inline) span {
    color: var(--st-ink-mute);
}
.st-footer .pub-footer-filing:not(.pub-footer-filing--inline) a:hover { color: var(--st-ink); }

/* ===========================================================================
   23. 兼容层：把旧页面的 Tailwind 浅色工具类**在暗色体系下重映射**
   ---------------------------------------------------------------------------
   ## 为什么需要这一层
   官网 30+ 个页面里有 500+ 处浅色系的 Tailwind 工具类（`bg-white` / `text-gray-900` /
   `text-slate-500` …），它们是按"浅色画布"写的。整站翻成暗色后：
     · `text-gray-900`（近黑）压在深底上 → **完全看不见**；
     · `bg-white` 卡片在深底上 → 炸开成一块白板，比页面主体还抢眼。
   逐个视图改类名（500 处、20+ 文件）**必然漏**，且漏的地方不报错、只是看不见 ——
   故采用本层的集中重映射。

   ## 与 Tailwind Play CDN 的**顺序问题**（关键，别改成裸类名）
   Play CDN 是在运行时把 utility 注入 `<head>` **末尾**的，晚于本文件的 `<link>`。
   同为单类权重（0,1,0）时"后来者胜" → 裸写 `.text-gray-900` 会被 utility 覆盖
   （本项目在顶栏 z-index 上踩过同一个坑）。故全部规则加 `.st-body ` 前缀
   （权重 0,2,0），**确定性胜过** utility，与加载顺序无关。

   ## 作用域
   `.st-body` 只挂在**平台官网页**的 body 上（site/layout.blade.php）。
   租户客户站走各自的 theme layout（不引 site-design.css、无 st-body），**不受影响** ——
   白标站必须保持客户自己的配色。

   ## 语义反转的纪律
   浅色系里"数值大 = 颜色深"，暗色系里"数值大 = 颜色亮"。故：
     · 文字档（400~900）→ 映射为**越大约亮**；
     · 底色档（50~100）→ 映射为**深色 tint**；描边档（100~300）→ 低透明度 hairline。
   ⚠️ 改这里之前先看该项实际用途（文字 or 底色）——两类的映射方向相反，
      这是暗色适配最容易改错的地方。
   =========================================================================== */

/* ---- 中性灰（gray）：文字 ---- */
.st-body .text-gray-900, .st-body .text-gray-950 { color: #ffffff; }
.st-body .text-gray-800 { color: #e8edf5; }
.st-body .text-gray-700 { color: #cbd5e1; }
.st-body .text-gray-600 { color: #aab6c6; }
.st-body .text-gray-500 { color: #94a3b8; }
.st-body .text-gray-400 { color: #7b8798; }
.st-body .text-gray-300 { color: #64748d; }
/* hover 变体（默认态已亮，hover 只做轻微提亮 —— 不要再压深） */
.st-body .hover\:text-gray-900:hover { color: #ffffff; }
.st-body .hover\:text-gray-700:hover { color: #e8edf5; }

/* ---- 中性灰：底色（→ 深色 tint，比页面底**亮一档**，保持"这是块面"的语义） ---- */
.st-body .bg-white { background-color: var(--st-canvas-elev); }
.st-body .bg-white\/70 { background-color: rgba(20, 27, 41, .8); }
.st-body .hover\:bg-gray-50:hover { background-color: rgba(255, 255, 255, .06); }
.st-body .bg-gray-50, .st-body .bg-gray-50\/60 { background-color: var(--st-canvas-soft); }
.st-body .bg-gray-100 { background-color: rgba(255, 255, 255, .06); }
.st-body .bg-gray-200 { background-color: rgba(255, 255, 255, .12); }
/* 深色填充按钮/分段控件（`bg-gray-900 text-white`）：暗色下改为**品牌渐变填充 + 深字** ——
   这是站内最强的按钮样式，正好对应它原本"最深 = 最强"的语义。 */
.st-body .bg-gray-900 { background: var(--st-grad); color: var(--st-on-gradient); }
.st-body .hover\:bg-gray-800:hover { opacity: .92; }

/* ---- 中性灰：描边与分隔线 ---- */
.st-body .border-gray-100, .st-body .border-gray-200, .st-body .border-gray-300 { border-color: var(--st-hairline); }
.st-body .divide-gray-100 > :not([hidden]) ~ :not([hidden]),
.st-body .divide-gray-200 > :not([hidden]) ~ :not([hidden]) { border-color: var(--st-hairline); }
.st-body .bg-gray-900.text-white { color: var(--st-on-gradient); }

/* ---- slate（免费检测页主要用这一族，语义与 gray 同） ---- */
.st-body .text-slate-900 { color: #ffffff; }
.st-body .text-slate-800 { color: #e8edf5; }
.st-body .text-slate-700 { color: #cbd5e1; }
.st-body .text-slate-600 { color: #aab6c6; }
.st-body .text-slate-500 { color: #94a3b8; }
.st-body .text-slate-400 { color: #7b8798; }
.st-body .bg-slate-50, .st-body .bg-slate-50\/60 { background-color: var(--st-canvas-soft); }
.st-body .bg-slate-100 { background-color: rgba(255, 255, 255, .06); }
.st-body .bg-slate-200 { background-color: rgba(255, 255, 255, .12); }
.st-body .border-slate-100, .st-body .border-slate-200, .st-body .border-slate-300 { border-color: var(--st-hairline); }
.st-body .ring-slate-100, .st-body .ring-slate-200 { --tw-ring-color: var(--st-hairline); }
.st-body .hover\:bg-slate-50:hover, .st-body .hover\:bg-slate-100:hover { background-color: rgba(255, 255, 255, .08); }
.st-body .from-slate-50.to-white,
.st-body .from-slate-950,
.st-body .from-indigo-50.to-white,
.st-body .from-indigo-50\/60.to-white {
    /* 白→白 的竖向渐变（`bg-gradient-to-b from-slate-50 to-white` 这类）在暗色下会变成
       一整块白板。⚠️ 不逐个覆盖 `--tw-gradient-*`（那套变量名随 Tailwind 主版本变化，
       覆盖错名字会**静默失效**），直接给 background-image —— 它就是 bg-gradient-* 实际设置的那条属性。 */
    background-image: linear-gradient(180deg, var(--st-canvas-soft), var(--st-canvas-elev));
}

/* ---- 语义色：对比度必须重算（浅色系的深绿/深红在深底上只有 ~2:1） ----
   统一规则：**底保持低透明度 tint，前景提亮**。 */
/* 成功 / 通过 */
.st-body .text-emerald-600, .st-body .text-emerald-700, .st-body .text-emerald-800,
.st-body .text-emerald-900, .st-body .text-emerald-950 { color: #6ee7b7; }

.st-body .bg-emerald-50, .st-body .bg-emerald-50\/60 { background-color: rgba(47, 181, 124, .14); }
.st-body .border-emerald-200, .st-body .border-emerald-300 { border-color: rgba(47, 181, 124, .30); }
.st-body .ring-emerald-200 { --tw-ring-color: rgba(47, 181, 124, .30); }
/* 警示 / 待处理 */
.st-body .text-amber-600, .st-body .text-amber-700, .st-body .text-amber-800,
.st-body .text-amber-900, .st-body .text-amber-950 { color: #fcd34d; }
.st-body .bg-amber-50, .st-body .bg-amber-50\/60 { background-color: rgba(251, 224, 65, .12); }
.st-body .border-amber-200, .st-body .border-amber-300 { border-color: rgba(251, 224, 65, .28); }
/* 危险 / 失败 */
.st-body .text-red-500, .st-body .text-red-600, .st-body .text-red-700,
.st-body .text-red-800, .st-body .text-red-900 { color: #fca5a5; }
.st-body .text-rose-700, .st-body .text-rose-800, .st-body .text-rose-900 { color: #fda4af; }
.st-body .bg-red-50, .st-body .bg-red-50\/60 { background-color: rgba(239, 68, 68, .14); }
.st-body .bg-rose-50, .st-body .bg-rose-50\/60 { background-color: rgba(244, 63, 94, .14); }
.st-body .border-red-200, .st-body .border-red-300 { border-color: rgba(239, 68, 68, .28); }
.st-body .border-rose-200, .st-body .border-rose-300 { border-color: rgba(244, 63, 94, .28); }
/* 信息（blue/sky）：页面里 blue-600 是填充按钮、sky 是信息标 —— 分开处理 */
.st-body .text-blue-700 { color: #8fd8ff; }
.st-body .text-sky-700, .st-body .text-sky-800,
.st-body .text-sky-900, .st-body .text-sky-950 { color: #8fd8ff; }
.st-body .bg-blue-50 { background-color: rgba(69, 187, 251, .12); }
.st-body .bg-sky-50 { background-color: rgba(69, 187, 251, .12); }
.st-body .border-blue-200, .st-body .border-sky-200 { border-color: rgba(69, 187, 251, .28); }
/* ---------------------------------------------------------------------------
   🔴 透明度变体：一次覆盖全部档位（2026-10-11 业务实测「背景灰色、文字看不清」）

   缺陷现场：结果页的「内容层建议 / 三步走 / 做 GEO 的三大好处」三个板块，
   底色实测是 `rgba(236,253,245,.5)`（浅薄荷）、`.4`、`.6` —— **原文的浅色底**在深色画布
   上叠出中间灰，白字压上去读不清；另一处 `text-emerald-700/80` 是**深绿字**（4,120,87）
   压深底，几乎不可见。

   成因：上面的兼容层只逐个列了 `.bg-emerald-50` 与 `.bg-emerald-50\/60` 两个**字面类名**，
   而模板里用了 `/30 /40 /50 /70 /80` 等多种档位 —— 漏一个档位就漏一块版面，
   且**不报错**（只是那块看起来"灰蒙蒙"）。实测全站共 40 个带透明度的颜色类。

   修法：改用**属性选择器前缀匹配**，一次覆盖该色的所有透明度档位。
   前缀带尾斜杠（`bg-emerald-50/`）故不会误伤 `bg-emerald-500/40`（后者的 "50" 后跟 "0/"）。
   特异性 (0,2,0) > Tailwind 工具类 (0,1,0)，无需 !important。
   --------------------------------------------------------------------------- */

.st-body [class*="bg-emerald-50/"] { background-color: rgba(47, 181, 124, .10); }
.st-body [class*="bg-amber-50/"]    { background-color: rgba(251, 224, 65, .10); }
.st-body [class*="bg-rose-50/"]     { background-color: rgba(244, 63, 94, .10); }
.st-body [class*="bg-red-50/"]      { background-color: rgba(239, 68, 68, .10); }
.st-body [class*="bg-slate-50/"]    { background-color: rgba(255, 255, 255, .05); }
.st-body [class*="bg-sky-50/"]      { background-color: rgba(69, 187, 251, .10); }
.st-body [class*="bg-blue-50/"]     { background-color: rgba(69, 187, 251, .10); }
.st-body [class*="bg-indigo-50/"]   { background-color: rgba(69, 187, 251, .10); }
.st-body [class*="bg-violet-50/"]   { background-color: rgba(69, 187, 251, .10); }
/* 浅色 -100/-200 底（如 bg-emerald-100、bg-indigo-200/60）：同样按语义 tint 处理。 */
.st-body [class*="bg-emerald-100"]  { background-color: rgba(47, 181, 124, .16); }
.st-body [class*="bg-amber-100"]    { background-color: rgba(251, 224, 65, .16); }
.st-body [class*="bg-rose-100"]     { background-color: rgba(244, 63, 94, .16); }
.st-body [class*="bg-indigo-100"]   { background-color: rgba(69, 187, 251, .16); }
.st-body [class*="bg-violet-100"]   { background-color: rgba(69, 187, 251, .16); }
.st-body [class*="bg-sky-100"]      { background-color: rgba(69, 187, 251, .16); }

/* 文字带透明度（`text-emerald-700/80` 这类）：浅色时代的深色字 + 透明度，
   在深底上几乎不可见。一律换成提亮后的语义色（透明度不再保留——保留就等于又降对比度）。 */
.st-body [class*="text-emerald-700/"], .st-body [class*="text-emerald-800/"] { color: #6ee7b7; }
.st-body [class*="text-amber-700/"], .st-body [class*="text-amber-800/"] { color: #fcd34d; }
.st-body [class*="text-rose-700/"], .st-body [class*="text-rose-800/"] { color: #fda4af; }
.st-body [class*="text-sky-700/"], .st-body [class*="text-sky-800/"] { color: #8fd8ff; }
.st-body [class*="text-sky-900/"] { color: #8fd8ff; }
.st-body [class*="text-slate-800/"], .st-body [class*="text-slate-900/"] { color: #ffffff; }
.st-body [class*="text-violet-800/"], .st-body [class*="text-indigo-800/"] { color: var(--st-primary-soft); }

/* 带透明度的边框（border-*-200/70 等）：同理按语义提亮，避免"看不见的框"。 */
.st-body [class*="border-emerald-200/"], .st-body [class*="border-emerald-100/"] { border-color: rgba(47, 181, 124, .28); }
.st-body [class*="border-amber-200/"] { border-color: rgba(251, 224, 65, .26); }
.st-body [class*="border-rose-200/"], .st-body [class*="border-rose-100/"] { border-color: rgba(244, 63, 94, .26); }
.st-body [class*="border-indigo-200/"], .st-body [class*="border-indigo-100/"] { border-color: rgba(69, 187, 251, .26); }
.st-body [class*="border-sky-200/"], .st-body [class*="border-sky-100/"] { border-color: rgba(69, 187, 251, .26); }


/* indigo / violet 深档（页面里 text-indigo-900 / text-violet-800/900 用作小标题）：
   同属「浅色时代的深色字」，在深底上必须提亮（品牌青蓝系）。 */
.st-body .text-indigo-800, .st-body .text-indigo-900, .st-body .text-indigo-950 { color: var(--st-primary-soft); }
/* 🔴 2026-10-11 补 `text-indigo-600`（此前漏网，实测 3.89~4.36:1 未达 AA）。
   600 这一档在本文件里有个特殊矛盾（见 layout.blade.php 的 Tailwind 配置注释）：
   它**同时**被当「按钮填充底」（`bg-indigo-600 text-white`，需要偏暗才压得住白字）
   和「正文链接色」（需要偏亮才在深底上可读）—— 一个色值满足不了两种用途。
   解法：只覆写**文本**用法（`.text-indigo-600`），不动 `bg-indigo-600` 的填充值。
   文本统一走 --st-primary（亮青蓝，深底 8.96:1），与全站链接色一致。 */
.st-body .text-indigo-600 { color: var(--st-primary); }
.st-body .text-violet-800, .st-body .text-violet-900, .st-body .text-violet-950 { color: var(--st-primary-soft); }
/* blue/indigo 填充按钮：白字改为深字（品牌亮底上白字不可读）。
   ⚠️ 这两条是本层**最容易被删掉**的规则 —— 删了不报错，只是按钮字看不清。 */
.st-body .bg-blue-600, .st-body .bg-indigo-600 {
    background: var(--st-grad);
    color: var(--st-on-gradient);
}
.st-body .hover\:bg-blue-700:hover, .st-body .hover\:bg-indigo-700:hover { opacity: .92; }
.st-body .bg-blue-50.text-blue-700, .st-body .bg-indigo-50.text-indigo-700 { color: var(--st-primary); }

/* ---- 焦点态：浅色系用深色 ring，暗色下改为品牌色 ring ---- */
.st-body .focus\:border-gray-900:focus { border-color: var(--st-primary); }
.st-body .focus\:ring-gray-900:focus { --tw-ring-color: rgba(69, 187, 251, .35); }
.st-body .focus\:border-indigo-500:focus { border-color: var(--st-primary); }
.st-body .focus\:ring-indigo-500:focus { --tw-ring-color: rgba(69, 187, 251, .35); }
.st-body .hover\:bg-gray-800:hover { opacity: .92; }

/* ===========================================================================
   24. 文章详情页（智库）暗色适配
   ---------------------------------------------------------------------------
   ## 为什么需要这一节
   业务反馈：「平台研究里面的文章，有些文字是白色的，在白底上看不见；
   另外有些文字颜色太淡，看不清楚」。

   ## 根因：**两套体系在同一页面上打架**
   文章正文卡用的是**早期浅色体系**的类（`.article-shell` / `.article-prose` /
   `.pill-tag` / `.article-table` …，定义在 `style.css` 与 `custom.css`），
   这些类把底色硬编码成 `#ffffff`、正文字色硬编码成 `#374151`；
   而 §23 的暗色兼容层（作用于整个 `.st-body`）把 `text-gray-700` 映射成浅灰、
   `text-gray-900` 映射成**白色** —— 于是：
     · 面包屑里的标题（`text-gray-900`）→ 白字压白卡 → **完全看不见**；
     · AI 摘要 / 导语（`text-gray-700`）→ 浅灰压白卡 → **看不清**；
     · 摘要框（`bg-gray-50`）→ 被映射成深色块，夹在白卡里也很突兀。
   即：**卡片是浅色体系、文字类却已按暗色映射**，两边各按各的规则走必然出错。

   ## 修法：把文章卡也并入暗色体系（与整站一致）
   只覆盖配色，不动排版（行高、字号、间距全部沿用原规则）。
   ⚠️ 为什么在**这里**覆盖而不是改 `style.css` / `custom.css`：
      那些文件里的 `.article-*` 类被**租户主题站**复用（各 theme 的 article.blade.php
      走的是自己那套 `as-article-shell` 等类名，但 `style.css` 是共用的），
      直接改会让客户站的正文观感一起变 —— 而客户站是白标交付物，不应被平台改版波及。
      本节用 `.st-body` 前缀（权重 0,2,x）确定性地压过那两个文件里的单类选择器（0,1,x），
      且只在平台官网页生效（`.st-body` 只挂在官网 body 上）。
   ⚠️ 覆盖率要求：这些类里的**每一处浅色硬编码**都要覆盖到，漏一处就是
      "白底上有一块白字"（不报错、只能靠肉眼逐段读）。守卫：
      SiteDarkRedesignV8Test::test_article_page_uses_dark_surface。
   =========================================================================== */

/* ---- 24.1 卡片外壳 ---- */
.st-body .article-shell,
.st-body .article-detail-shell {
    background: var(--st-canvas-elev);
    border-color: var(--st-hairline);
    box-shadow: none;
}
.st-body .article-shell { border-radius: var(--st-r-lg); }

/* ---- 24.2 正文（.article-prose 的两份定义分别在 style.css 与 custom.css，
      后者对 p/a 又有更细的规则，故这里逐类覆盖到位）---- */
.st-body .article-prose { color: var(--st-ink-2); }
.st-body .article-prose h1,
.st-body .article-prose h2,
.st-body .article-prose h3,
.st-body .article-prose h4 { color: var(--st-ink); }
.st-body .article-prose strong,
.st-body .article-prose b { color: var(--st-ink); }
.st-body .article-prose blockquote {
    border-left-color: var(--st-primary-subdued);
    color: var(--st-ink-mute);
    /* 引用块给一层极淡的底，与正文区分（浅色系靠灰字+灰线，暗色下需要一点底才看得出是引用）。 */
    background: rgba(255, 255, 255, .03);
    padding: .75rem 1rem;
    border-radius: 0 var(--st-r-sm) var(--st-r-sm) 0;
}
.st-body .article-prose code {
    background: rgba(255, 255, 255, .08);
    color: var(--st-ink);
}
.st-body .article-prose pre {
    background: #05080f;
    color: var(--st-ink-2);
    border: 1px solid var(--st-hairline);
}
.st-body .article-prose a {
    color: var(--st-primary);
    border-bottom-color: rgba(69, 187, 251, .35);
}
.st-body .article-prose a:hover {
    color: var(--st-grad-start);
    border-bottom-color: rgba(105, 247, 211, .5);
}
.st-body .article-prose hr { border-color: var(--st-hairline); }

/* ---- 24.3 表格（Markdown 表格由 .article-table-wrap 包裹）---- */
.st-body .article-table-wrap {
    border-color: var(--st-hairline);
    background: transparent;
}
.st-body .article-table thead { background: rgba(255, 255, 255, .04); }
.st-body .article-table th { color: var(--st-ink); border-color: var(--st-hairline); }
.st-body .article-table td { color: var(--st-ink-2); border-color: var(--st-hairline); }
.st-body .article-table tbody tr:nth-child(even) { background: rgba(255, 255, 255, .02); }

/* ---- 24.4 摘要框与导语 ---- */
/* ⚠️ 原规则带 `!important`（`background: linear-gradient(...) !important`），
   不用 !important 覆盖不动 —— 这是本文件里少数必须用它的地方。 */
.st-body .article-summary-box {
    background: rgba(255, 255, 255, .04) !important;
    border-color: var(--st-hairline);
}
.st-body .article-kicker { color: var(--st-ink-2); }
.st-body .article-breadcrumb-separator { color: var(--st-ink-mute-2); }

/* ---- 24.5 标签、分类/元信息小片 ---- */
.st-body .pill-tag {
    background: rgba(255, 255, 255, .06);
    color: var(--st-ink-2);
}
.st-body .pill-tag:hover { background: rgba(69, 187, 251, .12); color: var(--st-primary); }
.st-body .article-section-chip {
    border-color: var(--st-hairline);
    background: rgba(255, 255, 255, .04);
    color: var(--st-ink-2);
}
.st-body .article-meta-chip {
    background: rgba(255, 255, 255, .04);
    border-color: var(--st-hairline);
}

/* ---- 24.6 正文内广告位（article-text-ads / 粘性广告卡）----
   这两块此前是浅底深字的「推广卡」，暗色下必须一起转，否则整页黑、唯独它白。 */
.st-body .article-text-ads--content-top { border-bottom-color: var(--st-hairline); }
.st-body .article-text-ads--content-bottom { border-top-color: var(--st-hairline); }
.st-body .article-sticky-ad__inner {
    border-color: var(--st-hairline);
    background: var(--st-canvas-elev);
}
.st-body .article-sticky-ad__badge {
    background: rgba(69, 187, 251, .12);
    color: var(--st-primary);
}
.st-body .article-sticky-ad__title { color: var(--st-ink); }
.st-body .article-sticky-ad__copy { color: var(--st-ink-mute); }
.st-body .article-sticky-ad__button {
    border-color: rgba(69, 187, 251, .3);
    background: transparent;
    color: var(--st-primary);
}
.st-body .article-sticky-ad__button:hover {
    background: rgba(69, 187, 251, .12);
    color: var(--st-grad-start);
}
.st-body .article-sticky-ad__close { color: var(--st-ink-mute-2); }
.st-body .article-sticky-ad__close:hover { color: var(--st-ink); }

/* ---- 24.7 正文行宽：**刻意不限宽**（2026-10-13 业务决定）----

   文章正文与其它页面保持**同一内容宽度**（全容器宽，实测 1262px ≈ 75 汉字/行）。

   ## 为什么这里没有规则（不是漏写）
   本节曾经有过两版限宽，先后都被业务打回：

     ① 只给 `p` 限 40em（≈40 字/行）——
        段落 672px，而同一页的 h2 / ul / table 仍是 1262px
        → 正文在「宽-窄-宽」之间反复跳动。业务：「这个页面排版很奇怪」。
     ② 改为整列限宽（`.article-detail-pad > *` 46rem 居中）——
        不跳动了，但整页比其它页面**内容窄**。
        业务：「你怎么把页面宽度给弄窄了，改成和其他页面内容一样的宽度」。

   ⇒ 最终取**不限宽**：跨页面的宽度一致性是更高优先级的约束。

   ⚠️ 75 字/行确实超过中文排印学推荐的 40 字 —— 这一点**已知**，
      且已经被业务明确权衡否决（要与其他页面同宽）。
      若将来要重新收窄，必须满足两条：① 整列一起收（**不能只限段落**，
      那会重演第 ① 版）；② 先与业务确认 —— 这是产品决策，不是技术优化。
   ⚠️ 不要在别处（含 §25 中文排版层）给 `.article-prose` 或
      `.article-detail-pad` 加 max-width —— 上述两种历史写法都是被打回的形态，
      守卫 `test_article_prose_uses_full_container_width_like_other_pages` 会拦住它们。 */

/* ===========================================================================
   25. 版式变体：打断首页「12 个板块一个样」的单调
   ---------------------------------------------------------------------------
   ## 问题（设计评审结论）
   首页 12 个板块**全部**是同一套结构：眉标 + 大标题 + 描述 + 卡片网格。
   一路滚下来像同一个模板套了 12 遍 —— 读者到中段就失去"这里有新东西"的信号，
   视线不再被任何一处抓住。这不是靠调色能解决的，必须**换版式**。

   ## 本节提供两种变体
   ① `.st-tiers`（三档强度视觉）：把"参数表"升级成"可比较的视觉"——
      适合展示**有量级差异**的一组数字（如采样强度 75 / 30 / 5）。
      触发点：`#trust` 的采样口径（业务点名要求做成醒目视觉元素）。
   ② `.st-rows`（编号行列表）：把"卡片网格"换成"横向编号行"——
      适合**流程/条目**类内容（如技术执行的四条），横排比网格更像"一条链路"。
      触发点：`#execution`。

   ## 使用约定
   - 一个页面**最多两处**用变体（用多了又变成新的一种"到处都一样"）；
   - 变体只换**排布与视觉重量**，不引入新色相（色仍只从 --st-* 取）；
   - 两者都保留原有语义标签（h2/h3/li），不为了好看把结构写成 div 堆。
   =========================================================================== */

/* ---------------------------------------------------------------------------
   25.1 三档强度视觉（.st-tiers）
   设计意图：把「15 × 5 / 10 × 3 / 5 × 1」这种参数表达，换成
   「**75 条 / 30 条 / 5 条**」+ 同比例长条 —— 数字的量级差异一眼可见。
   ⚠️ 长条长度按**最大值归一化**（不是绝对值），否则 5 条会短到看不见。
   --------------------------------------------------------------------------- */
.st-tiers { display: grid; gap: 20px; margin: 24px 0 0; }
.st-tiers__item { display: grid; gap: 9px; }
.st-tiers__top {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
}
.st-tiers__label { font-size: .875rem; line-height: 1.5; color: var(--st-ink-2); }
.st-tiers__value {
    font-size: 1.75rem; font-weight: 400; line-height: 1;
    letter-spacing: -.02em; font-variant-numeric: tabular-nums;
    color: var(--st-ink); white-space: nowrap;
}
.st-tiers__value small {
    margin-left: 5px; font-size: .75rem; font-weight: 400; color: var(--st-ink-mute);
}
.st-tiers__track {
    height: 7px; border-radius: var(--st-r-pill);
    background: rgba(255, 255, 255, .09); overflow: hidden;
}
.st-tiers__fill {
    height: 100%; border-radius: var(--st-r-pill);
    background: var(--st-grad);
    /* 首次进入视口时从左展开（纯 CSS，无 JS；见下方 @media 的降级）。 */
    animation: stTierGrow .9s cubic-bezier(.22, .61, .36, 1) both;
    transform-origin: left center;
}
/* 依次入场（60ms 递增）——让"三档"读起来是一个序列而不是三块；
   超过 6 档不继续加延迟（避免最后一项等太久）。 */
.st-tiers__item:nth-child(1) .st-tiers__fill { animation-delay: .05s; }
.st-tiers__item:nth-child(2) .st-tiers__fill { animation-delay: .16s; }
.st-tiers__item:nth-child(3) .st-tiers__fill { animation-delay: .27s; }
.st-tiers__item:nth-child(4) .st-tiers__fill { animation-delay: .38s; }
.st-tiers__item:nth-child(5) .st-tiers__fill { animation-delay: .49s; }
.st-tiers__item:nth-child(n+6) .st-tiers__fill { animation-delay: .55s; }
@keyframes stTierGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.st-tiers__formula { font-size: .75rem; color: var(--st-ink-mute); font-variant-numeric: tabular-nums; }

/* 深色版面（.st-section--ink）里的变体配色：底色是半透明提亮的卡，
   故轨道要更亮一档才看得出，文字走 on-dark 族。 */
.st-section--ink .st-tiers__label { color: var(--st-on-dark-soft); }
.st-section--ink .st-tiers__value { color: var(--st-ink); }
.st-section--ink .st-tiers__value small { color: var(--st-on-dark-mute); }
.st-section--ink .st-tiers__track { background: rgba(255, 255, 255, .12); }
.st-section--ink .st-tiers__formula { color: var(--st-on-dark-mute); }
/* ⚠️ 这条与 §24 的动效取舍同一原则：**不是**用 prefers-reduced-motion 关掉整段动画
   （那会让所有报告该偏好的环境看不到——本项目已因此误判过两轮功能"没做"），
   而是把"展开动画"退化为"直接显示"，视觉信息（长度对比）完全保留。 */
@media (prefers-reduced-motion: reduce) {
    .st-tiers__fill { animation: none; }
}
@media (max-width: 560px) {
    .st-tiers__value { font-size: 1.5rem; }
}

/* ---------------------------------------------------------------------------
   25.2 编号行列表（.st-rows）
   设计意图：把「2×2 卡片网格」换成「横向编号行」——
   条目之间有**明确的先后/序列感**（编号 + 分隔线），而网格传达的是"并列"。
   ⚠️ 行内左侧序号用等宽数字（tabular-nums）且定宽，否则 1 位数与 2 位数会让
      正文起始位置参差（视觉上像没对齐）。
   --------------------------------------------------------------------------- */
.st-rows { display: grid; gap: 0; margin-top: 8px; }
.st-rows__item {
    position: relative;
    display: grid;
    grid-template-columns: 3.5rem 1fr;
    gap: 8px 20px;
    padding: 26px 0;
    border-top: 1px solid var(--st-hairline);
    /* 悬停整行轻微提亮：与卡片悬停同一语言，但更克制（行不是可点元素）。 */
    transition: background-color .2s ease;
}
.st-rows__item:last-child { border-bottom: 1px solid var(--st-hairline); }
.st-rows__item:hover { background-color: rgba(255, 255, 255, .025); }
.st-rows__num {
    font-size: 1.125rem; font-weight: 400;
    font-variant-numeric: tabular-nums; letter-spacing: -.01em;
    color: var(--st-primary); line-height: 1.5;
}
/* 🔴 正文列宽上限：真机截图发现整行铺满 1400px 容器后，一行能塞 60+ 个汉字，
   阅读时视线回扫距离过长（专业排版里正文行宽通常控制在 35–45 个汉字）。
   这里给一个 64rem 的软上限 —— 只约束**正文段落**，标题与序号不受限
   （标题短、且需要与序号保持视觉关联）。 */
.st-rows__body { display: grid; gap: 7px; max-width: 64rem; }
.st-rows__title {
    margin: 0; font-size: 1.0625rem; line-height: 1.45;
    color: var(--st-ink);
}
.st-body .st-rows__title { font-weight: 500; }
.st-rows__text { margin: 0; font-size: .875rem; line-height: 1.7; color: var(--st-ink-mute); }
/* 行内图标（可选）：放在序号右侧同一行，与标题基线对齐。 */
.st-rows__icon { color: var(--st-primary); }
.st-rows__icon svg, .st-rows__icon i { width: 16px; height: 16px; }
@media (max-width: 640px) {
    .st-rows__item { grid-template-columns: 2.25rem 1fr; gap: 6px 14px; padding: 20px 0; }
    .st-rows__num { font-size: 1rem; }
}

/* ---------------------------------------------------------------------------
   28. 常见问题两列布局（2026-10-11）

   ## 为什么改两列（而不是简单放宽）
   业务反馈「常见问题页面的内容宽度太窄了」。实测原实现 `max-w-3xl` = **768px**，
   而全站其它页面的内容区是 1336px —— 这块比别处窄了近一半，视觉上像"缩在中间"。
   但直接把 Q&A 拉到 1336px 也不行：问答是阅读型内容，单行过长会让视线回扫困难
   （本项目已就"正文行宽超 83 字"做过分区收窄，不能再反向制造一次）。
   两列是同时满足"用满宽度"与"保持可读行宽"的解 —— 每列约 650px，与原先 768px 接近。

   ## 为什么按「组」分列，而不是 CSS 多列（columns）
   本页每组是一个 `<section>`（标题 + 一组 `<details>` 折叠项）。
   `columns: 2` 会把**单个组拆到两列**里，且任何一个 details 展开/收起都会
   导致整块内容在列间**重新流动**（读者刚点的条目会跳位置）。
   按组整块分列则：每列是独立的纵向堆叠，展开只影响自己这一列，位置稳定。
   ⇒ 布局由**视图**决定分列（`@foreach` 分段），CSS 只负责"两列 + 响应式"。

   ## 响应式
   1024px 以下回落单列（平板与手机）。判据用视口宽度而非容器宽度：
   本页两列在窄屏下每列只剩 ~300px，中文每行 10 来字，读起来比单列更累。 */
.st-faq-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 40px 56px;
    align-items: start;
}
@media (max-width: 1023px) {
    .st-faq-grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
}
/* 列内是若干 section 的纵向堆叠；组与组之间的间距由这里统一给，
   避免依赖各 section 自带的 mt-10（那会让每列首组也多出一段顶部空白）。 */
.st-faq-col > section + section { margin-top: 36px; }

/* ---------------------------------------------------------------------------
   29. 定义行（.st-defrow）—— 解决方案页的「适合谁 / 适配版本」（2026-10-11）

   ## 修的是什么
   这两块原本各是一张 **1336px 宽的大卡，里面只有一行字**：
   适合谁卡 1336×127px 装 37 字、适配版本卡 1336×221px 装约 30 字 ——
   四周全是空，看起来像"内容忘填了"，且两块合计占掉页面近 1/4 高度。
   业务反馈「解决方案下面的 6 个页面排版实在是丑」，这是最刺眼的成因。

   ## 改法：大空盒 → 紧凑的「标签 + 值」一行
   语义上这两块都是**元信息**（这个方案给谁用 / 适配哪个版本），
   不需要卡片那么大的容器。改成一行定义行后：
   高度 127px → 约 64px，两块共省约 120px，且视觉密度与下方正文匹配。

   ## 为什么不用「把内容拆分成分组标签」的写法
   值是一串中文顿号/斜杠分隔的自由文本（如「3C 硬件、消费品、汽车、医药大健康、
   智能家居等多产品线 / 多单品企业。」）。按分隔符切分需要解析 6 个页面 × 2 个语言的
   文案，一旦某页写法不同就会切错，属"脆弱的聪明"。保持整行文本最稳。 */
.st-defrow {
    display: grid;
    grid-template-columns: minmax(76px, max-content) minmax(0, 1fr);
    align-items: baseline;
    gap: 4px 20px;
    padding: 18px 24px;
    border: 1px solid var(--st-hairline);
    border-radius: var(--st-r-lg);
    background: var(--st-canvas-elev);
}
.st-defrow__k {
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--st-primary);
    white-space: nowrap;
}
.st-defrow__v {
    font-size: .9375rem;
    line-height: 1.65;
    color: var(--st-ink-2);
}
/* 强调变体（用于「适合谁」——它是"判断这页是否与我有关"的第一道筛，值得高亮一档） */
.st-defrow--accent {
    background: var(--st-canvas-cream);
    border-color: rgba(69, 187, 251, .22);
}
@media (max-width: 639px) {
    /* 窄屏两列会挤成"标签一列、值一列"的窄条，改为上下堆叠 */
    .st-defrow { grid-template-columns: minmax(0, 1fr); gap: 6px; }
}

/* ---------------------------------------------------------------------------
   30. 流程步骤（.st-steps）—— 解决方案页的「实施路径」（2026-10-11）

   ## 修的是什么
   原来是 4 张各自独立的卡片（编号只是卡里的一个小方块），读起来像"4 个孤立方块"，
   没有"第 1 步做完才到第 2 步"的先后感。业务反馈整页"丑"，这也是成因之一。

   ## 改法：给 4 步接一条主线
   卡片改为**透明**（去掉盒子），序号做成圆形**节点**压在一条贯穿的横线上 ——
   于是 4 步从"四个方块"变成"一条流程上的四个节点"。
   ⚠️ 节点用 `background: var(--st-canvas)` 实底把主线"剪断"：
      这是让圆点看起来是"线上的节点"而不是"压在线上的一块色块"的关键。
   ⚠️ 卡片透明后不能再复用 `.st-feature`（它自带底色/描边/圆角）。
      此处刻意不套那个类，避免"透明卡片 + 残留边框"的脏效果。 */
.st-steps {
    position: relative;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 24px 28px;
}
/* 主线：与序号节点同高（节点 38px / 2 = 19px），从左贯穿到右、末端渐隐 */
.st-steps::before {
    content: '';
    position: absolute;
    top: 19px;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(90deg,
        var(--st-hairline-strong) 0%,
        var(--st-hairline-strong) 90%,
        transparent 100%);
}
.st-steps__item { position: relative; min-width: 0; }
.st-steps__num {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: var(--st-r-pill);
    background: var(--st-canvas);
    border: 1px solid rgba(69, 187, 251, .30);
    color: var(--st-primary);
    font-size: .875rem;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}
.st-steps__title { margin: 16px 0 0; font-size: 1.0625rem; line-height: 1.4; color: var(--st-ink); }
.st-steps__text { margin: 8px 0 0; font-size: .875rem; line-height: 1.7; color: var(--st-ink-mute); }
@media (max-width: 1023px) {
    .st-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    /* 换行成两排后主线会横穿两行、看起来像划掉文字，故窄屏隐藏主线 */
    .st-steps::before { display: none; }
}
@media (max-width: 639px) {
    .st-steps { grid-template-columns: minmax(0, 1fr); gap: 28px; }
}

/* ---------------------------------------------------------------------------
   31. 评分维度条（.st-dims）—— 内容页的「15 维内容评分」（2026-10-11）

   ## 为什么加（业务反馈「解决方案页面太单薄」）
   解决方案页与平台能力页共 11 个，内容都是「痛点 + 解法 + 步骤」的纯文字结构，
   页面平均高度约 2000px、正文约 400 字，观感单薄。
   但这些页面讲的核心能力（内容生产）**有一套真实的量化体系**——
   15 个内容评分维度、权重后台可配、总分按 100 归一 —— 此前**只在文字里提过一句**
   （如 agent_pipeline 的 how_1：「15 维 GEO 评分（确定性规则评分…）」），从未可视化。

   本组件把真实权重画出来：**数据来源是 `config('backspacegeo.scoring_weights')`
   （单一事实来源，与评分服务同源）**，标签复用后台已翻译好的
   `admin.articles.geo_optimization.dimensions.*`（zh/en 两套齐全，不新增文案键）。

   ⚠️ 这是**事实陈述**（我们的评分规则长什么样），不涉及任何效果承诺 ——
      符合 AGENTS.md §9.7 的报告纪律。
   ⚠️ 不要与「官网 GEO 七维体检」（WebsiteGeoScoringService，7 维）混为**同一套**：
      那是网站健康度体检，这是内容评分，两者维度数与用途都不同。
      守卫 AdminCopyFactConsistencyTest 锁的是前者（7），勿把这里的 15 写成通用"维度数"。

   ## 布局
   两列网格（15 项 → 8 + 7）。每项一行：`标签 | 细条 | 权重`。
   条长 = 权重 / 最大权重，**不是**百分比占比 —— 用占比会让 16% 与 5% 的条长差 3 倍，
   视觉上放大差距；按满分归一更能反映"这一维实际能拿多少分"。
   --------------------------------------------------------------------------- */
.st-dims { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 40px; }
.st-dims__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 92px 34px;
    align-items: center;
    gap: 12px;
}
.st-dims__label {
    font-size: .8125rem;
    line-height: 1.4;
    color: var(--st-ink-2);
    /* 中文标签长度不一（「引用来源」vs「推销语气（负相关）」），
       不换行会让长标签把条挤短、短标签的条变长 —— 视觉上像"权重不同"。
       故允许换行，条宽固定由 grid 第二列保证。 */
    min-width: 0;
}
.st-dims__track {
    height: 6px;
    border-radius: var(--st-r-pill);
    background: var(--st-canvas-soft);
    border: 1px solid var(--st-hairline);
    overflow: hidden;
}
/* ⚠️ `display: block` 必需：填充元素是 `<span>`（行内），
   行内元素**不吃 width/height** —— 实测 `width: 94%` 却渲染成 0×0，
   进度条整条不可见且不报错。改 block 后才生效。
   ⚠️ `min-width: 2px`：数值极小的项（如题库里"客服记录" 3 条 / 最大 1103 条
   ≈ 0.27%，四舍五入后 width:0%→0px）会渲染成**完全不可见**，
   读者误读成"这一类没有数据"。给个 2px 下限表示"有，但很小"。
   注意：这**不会**误导——具体条数由右侧数字如实给出，条形只表达量级。 */
.st-dims__fill {
    display: block;
    min-width: 2px;
    height: 100%;
    border-radius: var(--st-r-pill);
    background: var(--st-primary);
}
/* 唯一负相关维度（推销语气）：用中性色区分 —— 它"分越高越差"，与其余 14 项方向相反，
   同色会让人误读成"也是越高越好"。 */
.st-dims__fill--negative { background: var(--st-ink-mute-2); }
.st-dims__val {
    font-size: .8125rem;
    font-variant-numeric: tabular-nums;
    color: var(--st-ink-mute);
    text-align: right;
}
@media (max-width: 767px) {
    /* 窄屏两列会把标签挤到换行，改单列 */
    .st-dims { grid-template-columns: minmax(0, 1fr); gap: 10px 24px; }
    .st-dims__row { grid-template-columns: minmax(0, 1fr) 72px 30px; gap: 10px; }
}

/* ---------------------------------------------------------------------------
   32. 排版原语扩展（2026-10-11 设计评审试点：/platform）

   ## 背景（设计评审结论，改这里前先读）
   设计审计发现：全站内页只有**一种**布局原语——「眉标 + 标题 + N 张同构卡片」。
   服务页 7 卡、洞察页 3 组同构网格、平台页 5 卡、信任页 4 卡，页面之间像同一句话的
   不同配音（业务原话「丑得没法看」）。而 Linear / Stripe 的内页在卡片之外至少还有
   4 种原语。本节补齐这套工具箱 —— **配色 / 细字重 / 导航 / hero 均不动**。

   ## 四个原语与适用场景（按内容性质选用，不是随便挑）
   · `.st-chain`  陈述行链 —— 有先后顺序的模块/步骤（平台五模块）
   · `.st-defs`   定义行   —— 「名词 + 解释」型清单（算法 / 报告类型 / 资质）
   · `.st-nrow`   编号行   —— 无顺序含义但可数的服务 / 交付物
   · `.st-asym`   不对称两列 —— 左「人话结论」右证据的论证区

   ## 三条使用纪律（评审约定）
   ① 一页一主角：每页只允许一个"重"区块（数字带 / 渐变面板），其余轻量化；
   ② 盒子是例外：默认无盒（细线分隔），确需"聚拢感"才用 .st-card--ghost；
   ③ 细线即层级：分组靠 hairline（rgba 白线），不再叠底色。

   ⚠️ 与既有组件的区分（防止混用）：
   · .st-defrow（§29）=「标签 : 值」的元信息行（适合谁 / 适配版本），两列宽度悬殊；
     .st-def（本节）=「术语 + 释义」的词典行，术语列窄而固定。别互相替代。
   · .st-steps（§30）= 带贯穿主线的流程（先后关系强）；.st-nrow（本节）无主线、
     数字更大，用于"可数但不强调先后"的清单。 */
.st-chain { border-top: 1px solid var(--st-hairline-strong); }
.st-chain__row {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr);
    gap: 4px 18px;
    position: relative;
    padding: 22px 44px 22px 0;
    border-bottom: 1px solid var(--st-hairline);
    text-decoration: none;
}
/* 图标磁贴纵跨三行文本（阶段标/标题/正文） */
.st-chain__row .st-ico-tile { grid-row: 1 / span 3; margin-top: 2px; }
/* 整行可点（Linear 式"行即链接"）：箭头常驻但低亮度，hover 提亮 + 标题变品牌色。 */
.st-chain__go {
    position: absolute;
    right: 4px;
    top: 26px;
    font-size: 1rem;
    color: var(--st-ink-mute);
    opacity: .38;
    transition: opacity .16s ease, transform .16s ease, color .16s ease;
}
.st-chain__row:hover .st-chain__go { opacity: 1; color: var(--st-primary); transform: translateX(3px); }
.st-chain__row:hover .st-chain__title { color: var(--st-primary); }
.st-chain__step {
    font-size: .75rem;
    color: var(--st-primary);
    letter-spacing: .12em;
    font-variant-numeric: tabular-nums;
}
.st-chain__title {
    margin: 8px 0 0;
    font-size: 1.375rem;
    font-weight: 300;
    line-height: 1.25;
    letter-spacing: -.01em;
    color: var(--st-ink);
    transition: color .16s ease;
}
.st-chain__text {
    margin: 8px 0 0;
    max-width: 62ch;
    font-size: .875rem;
    line-height: 1.75;
    color: var(--st-ink-mute);
}
@media (max-width: 639px) {
    .st-chain__row { padding-right: 32px; }
    .st-chain__title { font-size: 1.1875rem; }
}

/* 定义行（术语 + 释义，无盒）。 */
.st-defs { margin-top: 22px; border-top: 1px solid var(--st-hairline); }
.st-def {
    display: grid;
    grid-template-columns: minmax(150px, 230px) minmax(0, 1fr);
    gap: 16px 24px;
    padding: 16px 0;
    border-bottom: 1px solid var(--st-hairline);
}
.st-def__term { font-size: .9375rem; line-height: 1.5; color: var(--st-ink); }
.st-def__term small { display: block; margin-top: 3px; font-size: .75rem; color: var(--st-ink-mute-2); }
.st-def__desc { font-size: .875rem; line-height: 1.75; color: var(--st-ink-mute); }
@media (max-width: 639px) {
    .st-def { grid-template-columns: minmax(0, 1fr); gap: 6px; }
}

/* 编号行（可数清单，无主线；带先后流程用 .st-steps）。 */
.st-nrow {
    display: grid;
    grid-template-columns: 58px minmax(0, 1fr);
    gap: 8px 18px;
    padding: 18px 0;
    border-bottom: 1px solid var(--st-hairline);
}
.st-nrow__num {
    grid-row: span 2;
    font-size: 1.75rem;
    font-weight: 200;
    line-height: 1.05;
    letter-spacing: -.02em;
    color: var(--st-primary);
    font-variant-numeric: tabular-nums;
}
.st-nrow__title { margin: 2px 0 0; font-size: .9375rem; font-weight: 400; color: var(--st-ink); }
.st-nrow__text { margin: 6px 0 0; font-size: .875rem; line-height: 1.75; color: var(--st-ink-mute); }

/* 不对称两列（左结论右证据）。 */
.st-asym {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 24px 48px;
    align-items: start;
}
.st-asym__lead {
    margin: 0;
    font-size: 1.125rem;
    font-weight: 300;
    line-height: 1.6;
    letter-spacing: -.01em;
    color: var(--st-ink-2);
}
/* 右栏与左栏之间的细线分界（窄屏落在顶部） */
.st-asym__body { border-left: 1px solid var(--st-hairline-strong); padding-left: 32px; }
@media (max-width: 899px) {
    .st-asym { grid-template-columns: minmax(0, 1fr); }
    .st-asym__body { border-left: 0; padding-left: 0; border-top: 1px solid var(--st-hairline-strong); padding-top: 20px; }
}

/* 轻卡片（保留盒子时的降档形态）：去底色、只留描边。⚠️ 必须写在 .st-card 之后
   （同权重靠源码顺序，与 .st-card--tint 同一约定）。 */
.st-card--ghost { background: transparent; border-color: var(--st-hairline-strong); box-shadow: none; }
.st-card--ghost:hover { background: transparent; }

/* 聚合页子页卡（2026-10-26 业务反馈：单列太宽 → 3 列网格）。
   /platform 与 /solutions 共用（见 site/hub-page.blade.php）。
   🔴 业务原话：「目前单列太宽了，可以考虑改成双列或者 3 列、4 列？」
      1440 下实测原卡片宽 1336px、整行只有一两句话，右侧全是空白。
      取 3 列：内容区约 453px（扣内边距后 389px），中文两行说得完；
      7 个子页（方案）与 6 个子页（平台）都能排成整齐的两行，4 列会窄到说明频繁折行。
   ⚠️ 响应式不在这里另写断点 —— 直接复用 `.st-grid--3`（1080→2 列、700→1 列）。 */
.st-hub-grid { margin-top: 8px; }

/* 整卡可点：`<a>` 形态须压掉默认链接外观，否则标题会变链接色。
   （与 `.st-chain__row` 的 text-decoration: none 同一处理。）
   同时用 flex 列布局让「查看方案」贴底，同行卡片箭头对齐。 */
a.st-hub-card {
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
}
/* 卡片头：图标磁贴 + 阶段标（阶段标仅 /platform 渲染）。两者分居两端。 */
.st-hub-card__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.st-hub-card__step {
    font-size: .75rem;
    color: var(--st-primary);
    letter-spacing: .12em;
    font-variant-numeric: tabular-nums;
    text-align: right;
}
.st-hub-card .st-card__title { margin-top: 16px; }
/* 卡片只有 ~389px 宽，说明行不设 max-width（那是给长行的可读性约束）。 */
.st-hub-card__desc { margin: .625rem 0 0; }
a.st-hub-card .st-link-arrow { margin-top: auto; padding-top: 16px; }

/* 主推徽标（2026-10-26 二次反馈：主推项**不得有任何布局形态差异**）。
   🔴 演进史：无盒裸两栏 → 填充底色 → 跨列 + 略亮描边，业务三次都判为"和其他不一样"。
      最终方案：主推项与普通卡**逐项同款**（宽度/底色/边框/内边距/标题字号全一致），
      唯一区别是卡头编号位上换成一枚文字徽标 —— 信息层级靠"多一行字"表达，不靠版式。
   ⚠️ 不新增行高：它占的是普通卡里编号（st-hub-card__step）那个位置。 */
.st-hub-card__badge {
    font-size: .75rem;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: .06em;
    color: var(--st-primary);
    text-align: right;
    white-space: nowrap;
}

/* ── §33 Hero motif 极缓动动画（2026-10-11 五批） ──────────────────────
   用户要求给 hero 装饰变体加「极缓动」动画。5+1 类原子动画，全部作用于
   opacity / transform / stroke-dashoffset（合成器友好，不触发重排）；
   周期 8s 起步（自转 46–88s），与 hero 背景流光（5s 低幅渐变位移）周期
   差一个数量级，不会互抢。
   · 作用域锁在 .st-hero-motif（装饰 svg 根类）内，页面其他元素不受影响；
   · 各元素的错峰用内联 animation-delay（负值=从中途开始，避免同页同拍），
     变速/变圆心用内联 animation-duration / transform-origin 覆盖；
   · 不做 prefers-reduced-motion 降级：与 §24 同判——此为极慢幅度装饰动画，
     无头环境/系统偏好差异大，且业务明确要求动效；如需降级在此集中加一条 media。
   ⚠️ transform 旋转必须配 transform-box: view-box + 内联 transform-origin
   （SVG 元素 CSS transform 默认 origin 在 0,0，不写会绕画布左上角转飞）。 */
.st-hero-motif .st-hm-spin { animation: stHmSpin 46s linear infinite; transform-box: view-box; }
.st-hero-motif .st-hm-spin-rev { animation: stHmSpinRev 64s linear infinite; transform-box: view-box; }
.st-hero-motif .st-hm-pulse { animation: stHmPulse 8s ease-in-out infinite; }
.st-hero-motif .st-hm-bob { animation: stHmBob 10s ease-in-out infinite; }
.st-hero-motif .st-hm-breathe { animation: stHmBreathe 9s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
.st-hero-motif .st-hm-drift { animation: stHmDrift 18s linear infinite; }
@keyframes stHmSpin { to { transform: rotate(360deg); } }
@keyframes stHmSpinRev { to { transform: rotate(-360deg); } }
@keyframes stHmPulse { 0%, 100% { opacity: .25; } 50% { opacity: .85; } }
@keyframes stHmBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes stHmBreathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }
@keyframes stHmDrift { to { stroke-dashoffset: -44; } }

/* ── §34 示意图表基元（官网「示意工作台」等，2026-10-11） ────────────────
   🔴 数据诚信（§9.7 报告纪律的官网版）：本节样式只服务于**已标注示意数据**
   的演示图表。每个使用处必须在图表卡上放 .st-demo-badge（或等效文字声明），
   不得把演示数字伪装成真实业绩；示意数字优先复用 deck 已审定口径
   （月报演示 KPI 34.2/51.8/87.5，光学镜片行业）。
   色彩纪律沿用：热力三档用既有语义令牌 --st-ok-ink / --st-warn-ink /
   --st-danger-ink（后台热力矩阵同族），不引入新色。 */
.st-demo-badge {
    display: inline-flex; align-items: center;
    font-size: .6875rem; letter-spacing: .1em;
    color: var(--st-ink-mute-2);
    border: 1px dashed var(--st-hairline-strong);
    border-radius: 999px; padding: 3px 10px;
    white-space: nowrap;
}
/* 引擎矩阵热力表（运营后台同款形态：≥60 高 / ≥30 中 / 其余低） */
.st-heat { width: 100%; border-collapse: collapse; font-size: .8125rem; }
.st-heat th, .st-heat td { padding: 8px 10px; border-bottom: 1px solid var(--st-hairline); text-align: right; font-variant-numeric: tabular-nums; }
.st-heat th:first-child, .st-heat td:first-child { text-align: left; color: var(--st-ink-2); }
.st-heat thead th { font-size: .6875rem; font-weight: 400; letter-spacing: .08em; color: var(--st-ink-mute-2); }
.st-heat .st-heat--hi { color: var(--st-ok-ink); }
.st-heat .st-heat--mid { color: var(--st-warn-ink); }
.st-heat .st-heat--lo { color: var(--st-danger-ink); }
.st-heat .st-heat--na { color: var(--st-ink-mute-2); }
/* 三层可见性递进条（口径各自独立，不是漏斗——图表旁必须保留该说明） */
.st-layer { display: grid; gap: 14px; margin-top: 16px; }
.st-layer__row { display: grid; grid-template-columns: 128px minmax(0, 1fr) 52px; gap: 14px; align-items: center; }
.st-layer__name { font-size: .8125rem; color: var(--st-ink-2); }
.st-layer__track { height: 8px; border-radius: 4px; background: var(--st-canvas-elev); overflow: hidden; }
.st-layer__fill { height: 100%; border-radius: 4px; background: var(--st-grad); }
.st-layer__fill--dim { background: var(--st-primary-subdued); }
.st-layer__val { font-size: .875rem; font-weight: 300; color: var(--st-ink); text-align: right; font-variant-numeric: tabular-nums; }
/* 竞品对照子弹图（行式） */
.st-bullet { display: grid; gap: 12px; margin-top: 16px; }
.st-bullet__row { display: grid; grid-template-columns: 96px minmax(0, 1fr) 52px; gap: 12px; align-items: center; }
.st-bullet__name { font-size: .8125rem; color: var(--st-ink-2); }
.st-bullet__name--me { color: var(--st-primary); }
.st-bullet__track { position: relative; height: 10px; border-radius: 5px; background: var(--st-canvas-elev); }
.st-bullet__band { position: absolute; top: 0; bottom: 0; border-radius: 5px; background: rgba(255, 255, 255, .07); }
.st-bullet__bar { position: absolute; top: 1px; bottom: 1px; border-radius: 4px; background: var(--st-primary-subdued); }
.st-bullet__bar--me { background: var(--st-grad); }
.st-bullet__val { font-size: .875rem; font-weight: 300; color: var(--st-ink); text-align: right; font-variant-numeric: tabular-nums; }
/* 走势带（波动区间的诚实画法：一条线 + 近 7 天滚动上下界） */
.st-band { width: 100%; height: auto; display: block; }
.st-band__line { fill: none; stroke: var(--st-primary); stroke-width: 1.6; }
.st-band__area { fill: rgba(69, 187, 251, .12); stroke: none; }
.st-band__grid { stroke: var(--st-hairline); stroke-width: 1; }
.st-band__axis { font-size: 9px; fill: var(--st-ink-mute-2); font-family: inherit; }
/* 「不做清单」变体：标记 = 禁止符 ×（danger 墨色）。
   语义与 .st-checklist 相反——列的是平台拒绝做的事，✓ 会读成"做到了"。
   同为 (0,1,1) 靠源码顺序取胜，必须写在其后。 */
.st-checklist--no li::before { content: '×'; color: var(--st-danger-ink); font-weight: 400; }

/* ---------------------------------------------------------------------------
   35. 航线时间线（.st-route）—— 内容质控页的「全自动托管 10 节点」（2026-10-11）

   ## 修的是什么（业务反馈「10 个节点的排版看着太简陋了」）
   原实现直接套 §25.2 的 `.st-rows`（编号行列表）：10 行 × 1300px 宽，每行
   只有一个序号 + 一个 4~7 字的节点名 —— 大片留白、行间仅一条 hairline，
   读起来像一份没加工过的清单，更看不出"这是一条前后相接的航线"。

   ## 改法：编号行 → 时间线节点
   · 一条纵向 rail 把 10 个节点串成一串（首尾渐隐，线不悬空）；
   · 序号做成压在 rail 上的圆形节点 —— 与 §30 `.st-steps` 同一手法：
     实底 `--st-canvas` 把线"剪断"，节点才像"线上的点"而不是"压线的色块"；
   · 每个节点补一句**公开口径**的职责说明（`site.insights.quality_node_*_d`），
     航线才能自解释 —— 原实现只给一个名词，访客无从知道这一步在干什么；
   · 人工卡点（内容审核）用琥珀圆环 + 徽标标出：它就是本区块标题
     「哪里必须人点头」的答案，必须一眼可见。

   ⚠️ 与 `.st-steps` 的分工：st-steps 是**横向**流程，适合 3~4 步；
     节点到 10 个时横排会挤成不可读，纵向 rail 才保得住节奏与可读性。
   ⚠️ 人工卡点走 `--st-warn-ink`（既有语义 warn 色），不新引入色相。
   --------------------------------------------------------------------------- */
.st-route { position: relative; margin-top: 8px; }
/* rail：纵向主线。起止各留 26px 渐隐，避免线头悬在首个/末个节点之外。 */
.st-route::before {
    content: '';
    position: absolute;
    left: 18px;                 /* 38px 圆形节点的中轴 */
    top: 26px;
    bottom: 26px;
    width: 1px;
    background: linear-gradient(180deg,
        transparent 0%,
        var(--st-hairline-strong) 7%,
        var(--st-hairline-strong) 93%,
        transparent 100%);
}
.st-route__item {
    position: relative;
    display: grid;
    grid-template-columns: 38px minmax(0, 1fr);
    gap: 0 22px;
    padding: 16px 0;
}
.st-route__num {
    grid-row: 1 / span 2;
    align-self: start;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: var(--st-r-pill);
    background: var(--st-canvas);
    border: 1px solid rgba(69, 187, 251, .30);
    color: var(--st-primary);
    font-size: .8125rem;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}
/* 人工卡点：琥珀圆环（与"不可复现/待办"同一语义族）。 */
.st-route__num--manual { border-color: rgba(252, 211, 77, .5); color: var(--st-warn-ink); }
.st-route__title {
    margin: 0;
    padding-top: 7px;           /* 与 38px 圆环的视觉基线对齐 */
    font-size: 1.0625rem;
    line-height: 1.45;
    color: var(--st-ink);
}
.st-route__text {
    margin: 5px 0 0;
    max-width: 62ch;
    font-size: .875rem;
    line-height: 1.7;
    color: var(--st-ink-mute);
}
@media (max-width: 640px) {
    .st-route::before { left: 14px; }
    .st-route__item { grid-template-columns: 28px minmax(0, 1fr); gap: 0 14px; padding: 14px 0; }
    .st-route__num { width: 28px; height: 28px; font-size: .6875rem; }
    .st-route__title { padding-top: 3px; }
}

/* ===========================================================================
   25. 中文排版层（CJK typography，2026-10-13）

   🔴 这一层修的是「拉丁排版参数被套到中文上」——全套字号档位（-0.02em 负字距、
   1.06~1.2 紧行高）都是按拉丁字母调的，而中文页直接沿用了它们。
   问题不报错、页面照常 200，只有肉眼能看出"拥挤、发闷"。

   ## 两个成因（都是字形结构差异，不是审美偏好）

   **① 负字距（letter-spacing: -0.02em 一类）在中文上是有害的。**
   负字距是拉丁大标题的专业签名（Stripe / Inter 的 display 档都在用）——
   拉丁字母的字身自带侧边距（side bearing），收紧后只吃掉多余的空白，
   字形本身仍不相碰。汉字是**满字身**：字形几乎占满整个字框，
   没有可收的空白，再收就变成笔画相碰。
   实测（browser，48px 中文串）：`letter-spacing: -0.96px` 时相邻汉字的
   字面间隙趋近于 0，长句读起来粘连；放开到 `0` 后立刻透气。

   **② 紧行高（1.06~1.2）在中文上会"压行"。**
   拉丁字母的可视高度只占 em 框的一部分（大写高约 0.7em、正文 x-height 约 0.5em），
   所以 line-height 1.1 时两行**视觉间隙**仍有约 0.4em，看着是"紧凑而清晰"。
   汉字占满 em 框，line-height 1.12 时行间只剩 0.12em（48px 字号下约 5.8px）——
   两行汉字的上下笔画几乎顶在一起。中文大字标题的惯例行高是 **1.3 上下**。

   ## 为什么必须分语言，不能全局改
   拉丁页**不该**跟着放大：英文大标题在 1.3 行高下会散架（失去编辑感），
   且负字距是英文页明确想要的效果。故本层全部限定在 `html[lang="zh-CN"]`
   （与 §.st-hero__sub 的中文专项同一写法）——英文页一个像素不变。

   ## 为什么是 0 而不是正值
   中文正文/标题不需要正字距：汉字天然带 1/8 em 的左右边距（字身框内留白），
   再加正字距会显得松散。**归零即正确**，不要"为了对称"给个 +0.01em。

   ## 守卫与验证
   · 本层是纯排版（字距/行高），不涉色值，不影响 `SiteDesignSystemTest`
     与 `SiteDarkRedesignV8Test`（它们锁定的是 --st-* 色值与组件存在性）；
   · 改动后必须在**中文页**真机复核（英文页不变即达标）：
     量 `h1`/`h2` 的 computed `letter-spacing: normal`（或 0px）、
     `line-height` 比值落在 1.28~1.5。
   =========================================================================== */
html[lang="zh-CN"] .st-hero__title-c,
html[lang="zh-CN"] .st-display-xxl,
html[lang="zh-CN"] .st-display-xl,
html[lang="zh-CN"] .st-body .st-display-lg,
html[lang="zh-CN"] .st-body .st-display-md,
html[lang="zh-CN"] .st-body .st-heading-lg,
html[lang="zh-CN"] .st-body .st-heading-md,
html[lang="zh-CN"] .st-body .st-heading-sm,
html[lang="zh-CN"] .st-card__title,
html[lang="zh-CN"] .st-feature__title,
html[lang="zh-CN"] .st-steps__title,
html[lang="zh-CN"] .st-chain__title,
html[lang="zh-CN"] .st-nrow__title {
    letter-spacing: 0;
}
/* 行高：按字号分档逐级放大（字号越大，中文的行间挤压越明显，故放大越多）。
   ⚠️ 这些值只覆盖根类（0,x,0 及以上）的声明，**不改**未列出的档位——
      其余小字（正文 14/16px）本来就是 1.6~1.75，中文无需再动。 */
html[lang="zh-CN"] .st-hero__title-c { line-height: 1.3; }
html[lang="zh-CN"] .st-display-xxl { line-height: 1.24; }
html[lang="zh-CN"] .st-display-xl  { line-height: 1.3; }
html[lang="zh-CN"] .st-body .st-display-lg { line-height: 1.32; }
html[lang="zh-CN"] .st-body .st-display-md { line-height: 1.34; }
html[lang="zh-CN"] .st-body .st-heading-lg { line-height: 1.4; }
html[lang="zh-CN"] .st-body .st-heading-md { line-height: 1.45; }
html[lang="zh-CN"] .st-body .st-heading-sm { line-height: 1.5; }
html[lang="zh-CN"] .st-card__title,
html[lang="zh-CN"] .st-feature__title { line-height: 1.45; }
/* 说明文字（13px）：拉丁下 -0.01em 可读，中文归零。行高 1.5 在中文上偏紧
   （13px × 1.5 = 19.5px，汉字占 13px，行间仅 6.5px）→ 放到 1.65。 */
html[lang="zh-CN"] .st-caption { letter-spacing: 0; line-height: 1.65; }
html[lang="zh-CN"] .st-micro   { letter-spacing: 0; line-height: 1.6; }
/* ⚠️ `.st-num` / `.pub-stat__v` 的负字距**保留不动**：它们渲染的是阿拉伯数字
   （Inter 的拉丁字形，不是汉字），负字距在这里是刻意的"金融数据感"。
   不要因为"统一中文排版"把它们一起归零——那是把一条正确的规则改坏。 */

/* 🔴 2026-10-13 撤回一条有害规则（**最终决定：文章正文不限宽**）。
   本层曾写：
       html[lang="zh-CN"] .st-body .article-prose p { max-width: 40em; }
   意图是"给中文正文一个可读行宽"，但**只限了 p** ——
   同一页里的 h2 / ul / table / blockquote 仍是容器全宽（1262px）：
     · 段落 672px（40 字/行）
     · 标题 1262px、列表 1238px、表格 1260px（75 字/行）
   于是正文在"宽-窄-宽"之间反复跳动，**看起来像版面坏了**
   （2026-10-13 业务反馈「这个页面排版很奇怪」的直接成因）。
   随后一度改为整列限宽 46rem，又因"比其它页面窄"被业务打回 →
   最终取不限宽，与其它页面内容同宽（完整沿革见 §24.7）。
   ⚠️ 不要再在这里给单个元素加 max-width：这类"只限一半"的写法
      不报错、只表现为版面忽宽忽窄，且很难归因到这一行。 */

/* ---------------------------------------------------------------------------
   26. 段落防孤行（2026-10-13）

   实测（首页 1440px，中文）**6 处段落末行只剩 1~3 个字**：
     「…一键出具权威的 AI 信源检测与优化建议」→ 末行「报告。」
     「…七维评估官网的 GEO 健康」→ 末行「度」
     「…算给你」→ 末行「看。」
   孤字行是最典型的"排版没做完"信号：整段文字看着像被硬切了一刀。

   ## 两层手段，各管一类段落

   ① **短文案用 `balance`**（hero 副标题 / 版块描述 / 卡片描述）——
      这些是 1~3 行的营销短句，balance 把两行拉成等长，孤字行直接被消除。
      实测同一批段落的末行字数：3 → 21、2 → 45、3 → 24；
      首页孤字行计数 **6 → 0**。
      ⚠️ 把上文 §.st-section-head 那句「balance 不用于正文」读完整：那条针对的是
         **长段落**（三行以上时 balance 既无效又拖慢渲染）。短文案是它唯一正确的
         用武之地 —— W3C 的建议也是"标题与短段落用 balance、长正文用 pretty"。
      ⚠️ 只作用于 zh-CN，**英文页不加**：英文的孤字行问题由 ② 的 pretty 覆盖
         （Chrome 的 pretty 本就是为拉丁文实现的），
         且英文行宽本就偏满，balance 会把两行拉得过于均匀、失去编辑感。

   ② **其余段落走 `pretty`**（下方 `.st-body p`）—— 只挪动最后一行的断点，
      不改行数、不改整体行宽。
      ⚠️ **英文页实测零影响**（54 个段落逐段比对行数，0 处变化）——
         它是浏览器对"末行断点"的优化，不是重排。
      ⚠️ 但它对 CJK 的效果有限（实测中文孤字行仍在），所以中文页必须靠 ① 兜住。

   ## 副作用与边界
   · balance 在极端情况下会让段落**多一行**——这是"避免孤字行"的代价，
     且卡片同组等高（grid stretch），不会造成参差；
   · 不覆盖 `.article-prose`（文章正文，可能是长文）；
   · 浏览器不支持时按默认折行，无副作用（渐进增强）。 */
html[lang="zh-CN"] .st-hero__sub-c,
html[lang="zh-CN"] .st-hero__sub,
html[lang="zh-CN"] .st-section-head p,
html[lang="zh-CN"] .st-card__text,
html[lang="zh-CN"] .st-feature__text,
html[lang="zh-CN"] .st-note,
html[lang="zh-CN"] .st-def__desc,
html[lang="zh-CN"] .st-faq details p {
    text-wrap: balance;
}
/* 兜底：其余段落（含未列出的长正文）保留 pretty——只调末行断点、不改整体行宽。
   ⚠️ 与上面那条 `balance` 的胜负**由选择器权重决定，与源码顺序无关**：
      `html[lang="zh-CN"] .st-card__text` 是 (0,2,1)，高于 `.st-body p` 的 (0,1,1)
      → 卡片/副标题等短文案吃 balance，其余长正文吃 pretty。
      顺序写反不影响结果，但**新增特化规则时仍必须保证权重高于本行**，
      否则会被静默压掉（本文件已多次栽在"同权重靠顺序"上，见 §.st-section-head 的历史注释）。 */
.st-body p {
    text-wrap: pretty;
}

/* ===========================================================================
   27. 关键版块「视觉加厚」（2026-10-13，设计评审 §2.2 建议①/③）

   ## 问题（评审原话）
   首页 17 个版块**结构完全同构**（眉标 + 标题 + 副标题 + 卡片网格），
   一路滚下来像"同一个模板套了 17 遍"。

   ## 为什么会显得不专业
   同构本身不是错，错在**没有主次**。读者在连续滚屏时靠"变化"判断哪里是重点；
   每屏骨架都一样时，重点就消失了，只剩"很长"。这正是"什么都说了、
   什么都没记住"的排版成因（评审 §3.1 的产品侧同族结论：首页承载过多）。

   ## 手段：只给 3 处做差异，其余一律保持中性
   · #tools   —— 非对称分栏（左标题 / 右工具卡），打破"标题在上、卡片在下"的定式；
   · #unique  —— 大号锚点序号（2.5rem → 3.5rem），成为扫读时的"进入点"；
   · 双路径收尾 —— 深底（--ink），与中段的 #trust 呼应成首尾视觉闭环。
   🔴 **不要给更多版块加**：差异本身就是信息量，全都不同 = 没有重点。
      这与 §4「不要给所有版块都加 tall」是同一条纪律（该处测试已有反向自证）。

   ## 约束（业务要求：色调 / 渐变 / 字体三样不动）
   本层**不加任何新色值、不改字号档位、不换字体** —— 全部复用既有 token 与组件，
   只改**布局骨架**与**既有元素的档位**。这是该约束下唯一能做的加厚手段。
   =========================================================================== */

/* ---- 27.1 非对称分栏（#tools）---- */
.st-split {
    display: grid;
    grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
    gap: 40px 56px;
    /* 🔴 垂直居中（不是 start）：实测左栏标题块 252px、右栏两卡 508px ——
       `start` 会在左栏下方留 256px 空白，读起来像"版面没做完"。
       居中后空白被均分为上下各 128px，成为编辑式排版里常见的
       "文案块居中、内容列更高"的构图。
       ⚠️ 不要为了"填满"而在左栏塞一个 CTA：右栏两张卡**整卡可点**且各自带
          「立即检测 / 立即体检」，再加一个同落点的按钮是重复出口
          （评审 §3.2 专门治理过 CTA 语汇漂移，同版块多出口会让访客犹豫）。 */
    align-items: center;
}
/* 左栏标题块去掉下外边距：那个 56px 是"标题在上、内容在下"定式的预留，
   在分栏里会变成左下方一块多余空白。 */
.st-split__aside .st-section-head { margin-bottom: 0; }
/* 右栏：工具卡竖排。宽卡（≈756px）配合放大的字号读起来是"版块主角"，
   而不是原网格里两张并排的中性卡。 */
.st-split__main { display: grid; gap: 20px; }

/* 窄屏回退：< 1080px 时退回上下单列（可读性优先，不做压缩式分栏）。 */
@media (max-width: 1080px) {
    .st-split { grid-template-columns: minmax(0, 1fr); gap: 32px; }
    .st-split__aside .st-section-head { margin-bottom: 24px; }
}

/* ---- 27.2 分栏内卡片加厚 ----
   同比放大内边距 / 图标 / 标题 —— 全部落在既有档位上，不引入新的数值体系。
   ⚠️ 图标用 `svg` 选择器：lucide 会把 `<i data-lucide>` 替换成 `<svg>`，
      给 `<i>` 写尺寸在渲染后是**无效的**（替换后元素已不存在）。 */
.st-split__main .st-feature { padding: 32px; gap: 16px; }
.st-split__main .st-feature__icon { width: 44px; height: 44px; }
.st-split__main .st-feature__icon svg { width: 21px; height: 21px; }
.st-split__main .st-feature__title { font-size: 1.375rem; line-height: 1.4; }
.st-split__main .st-feature__text { font-size: .9375rem; }

/* ---- 27.3 大号锚点序号（#unique）----
   01/02 已存在（2026-10-06 那轮加的），但在整页尺度上只是"卡内的一个装饰"。
   放大到 3.5rem 并提亮一档后，它成为**扫读进入点**：先看到大数字、
   再看标题——这是 editorial 版式的通行手法（Stripe / Linear 的 section 锚点）。
   ⚠️ 只给 #unique 用（该类只加在那个 section 上）：定价档位卡的序号是"档位编号"，
      放大到 3.5rem 会挤占本就不宽的小卡，语义也不同（编号 vs 特征锚点）。 */
.st-section--anchor-lg .st-anchor-num {
    font-size: 3.5rem;
    color: rgba(69, 187, 251, .5);
    margin-bottom: 14px;
}

/* ---- 27.4 深底收尾（双路径版块）----
   ⚠️ `.st-section--ink .st-card`（0,2,0）会压掉 `.st-card--dark`（0,1,0）的渐变描边 ——
      这是本文件反复出现过的"同族规则按权重取胜"陷阱：结果不报错，
      只是精选卡**悄悄退化成普通半透明卡**（渐变描边消失、与普通卡无差别）。
      这里显式补回；因两者权重相同（均 0,2,0），本规则**必须写在其后**（文件末尾）才生效。 */
.st-section--ink .st-card--dark {
    background:
        linear-gradient(var(--st-canvas-elev), var(--st-canvas-elev)) padding-box,
        var(--st-grad) border-box;
    border-color: transparent;
}

/* ===========================================================================
   28. 首页「平台能力全景」（2026-10-19，依据设计师 PPT 还原）

   ## 来源
   设计师交付的《BSgeo_Website Design》是一张 26.7×56 英寸超长画布，配色与版式
   在本节逐条对应。原稿的坑：**固定画布 + 绝对定位**在网页上必然横向溢出，
   故这里全部改为**流式网格**（列数随视口变化），字号用 clamp 跟随，
   而不是"整页 transform: scale()"——缩放会让小屏文字小到不可读。

   ## 从原稿抄下来的三个关键视觉
   ① **双层圆角矩形**：外层渐变描边（#46BDF3→#44B986 竖向）+ 内层深色实体。
      原稿就是两个 roundRect 叠出来的，不是 border（单 border 做不出渐变描边 +
      独立圆角）。这里用外层层铺渐变 + 内层盖深色底，视觉效果与之一致。
   ② **阶段表用横向细线分隔**（不是卡片）：左段亮蓝、右段淡线。
   ③ **行业网格是浅色卡 #F6F8FC + 深字**：整页暗底上这一块是唯一的大面积亮区，
      原稿刻意用它做视觉重音，不要"为了统一"改成暗色卡。

   ## 数字全部现算（见 HomeController::deckFacts / industryPacks）
   原稿的 20 包 / 492 子行业 / 国内 7+海外 5 / 9 节点均已漂移，页面显示实时值。
   =========================================================================== */

.st-deck { position: relative; }

/* ---- 28.1 版块标题组（原稿是居中大标题 + 绿色副标）---- */
.st-deck__head { text-align: center; }
/* 2026-10-25 业务要求「每个板块之间的间隔稍微调大一点」。
   56/96px → 76/132px（约 +36%）。⚠️ 只改首页这一个区块内的标题间距，
   不动全站变量 `--st-section-y`（那个 30+ 页共用，改它等于全站改版）。 */
.st-deck__head--gap { margin-top: clamp(76px, 9vw, 132px); }
/* 🔴 必须带 `.st-body` 前缀（0,2,1）压过 `.st-body h2` 的 (0,1,1)：
   否则标题颜色被全局规则改成 `--st-ink`（白）—— 页面 200、不报错，
   只有肉眼看得出"标题不是设计稿那个蓝色"。首版即因此被真机截图抓出。 */
.st-body .st-deck__title {
    margin: 0;
    /* 2026-10-25 业务要求「首页每个板块的主标题和副标题都加大一些」：
       1.5rem/2.6vw/2.375rem（24/38px）→ **1.75rem/3vw/2.75rem**（28/44px）。
       2026-10-25 二次：再按业务要求**整体放大约 20%** →
       clamp(1.75rem, 3vw, 2.75rem) → **clamp(2.1rem, 3.6vw, 3.3rem)**
       （1440 档 43.2 → 51.8px，手机 28 → 33.6px；上下限与中段同比例放大）。
       ⚠️ 与「.st-section-head--center .st-display-xl」（第 476 行）**同源**，
          那一处已同步改成同一组 clamp —— 两处必须一致，否则同类板块标题不一致。
          守卫：SiteDarkRedesignV8Test::test_home_section_titles_are_centered_and_enlarged。 */
    font-size: clamp(2.1rem, 3.6vw, 3.3rem);
    font-weight: 300;
    line-height: 1.3;
    color: #50d6ff;
    letter-spacing: 0;
}
.st-deck__kicker {
    margin: 10px 0 0;
    /* 2026-10-25 业务要求「每个板块的副标题也加大一些」：
       15/20px（.9375rem/1.25rem）→ **17/23px**（1.0625rem/1.4375rem）。
       2026-10-25 二次：再**整体放大约 20%** → clamp(1.275rem, 1.8vw, 1.725rem)，
       并按业务要求**加粗**（400 → 600；不用 700 是因为要与卡片标题 700 拉开层级）。
       ⚠️ 与主标题同批放大：只放大标题会让"标题很重、副标题很轻"的层级失衡。 */
    font-size: clamp(1.275rem, 1.8vw, 1.725rem);
    font-weight: 600;
    color: #44b986;
    letter-spacing: 0;
}
/* 2026-10-25：某一区块没有主标题时，kicker 顶上当标题用（首页「四个问题」区块）。
   2026-10-25 再次调整：业务指出它是**副标题**而非主标题，字号需缩小
   （原 28–42px 与 .st-deck__title 同档，过重）。现降到「比普通 kicker 稍大」一档。
   2026-10-25 三次：随普通 kicker 一起放大约 20% → clamp(1.425rem, 2.04vw, 1.8rem)，
   并同为 600 字重（它是副标题，与上面那条同源，别单独调成标题级字号）。 */
.st-deck__kicker--lead {
    margin-top: 0;
    font-size: clamp(1.425rem, 2.04vw, 1.8rem);
    font-weight: 600;
    line-height: 1.35;
}

/* ---- 28.2 四痛点卡（渐变描边 + 深底）---- */
.st-deck-grid { display: grid; gap: 20px; margin-top: clamp(28px, 3.4vw, 44px); }
.st-deck-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1023.98px) { .st-deck-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 639.98px) { .st-deck-grid--4 { grid-template-columns: minmax(0, 1fr); } }

/* 🔴 2026-10-20 业务要求：渐变描边「加粗 1 个像素」→ 2px → 3px。
   ⚠️ 描边宽度同时决定内层的外扩留白（`.st-deck-card__in` 的 margin 必须与之相等），
      否则内层会盖住一部分描边、看起来"没变粗"。两者要一起改。 */
.st-deck-card {
    position: relative;
    isolation: isolate;
    transition: transform .28s cubic-bezier(.2, .8, .3, 1), filter .28s ease;
    will-change: transform;
}
.st-deck-card__bg {
    position: absolute;
    inset: 0;
    border-radius: 16px;
    background: linear-gradient(180deg, #46bdf3, #44b986);
    z-index: 0;
    transition: box-shadow .28s ease;
}
.st-deck-card__in {
    position: relative;
    z-index: 1;
    /* 🔴 2026-10-20 修「四个框只有上/左/右有边框、底下没有」：
       原写法 `height: 100%` + `margin: 3px` —— 百分比高度**不含** margin，
       于是内层总高 = 父高 + 上下各 3px，向下溢出 6px、把底部那 3px 描边**盖住**了。
       改成 `calc(100% - 6px)`：内层恰好占满「父高减上下各 3px」，四边描边等宽可见。
       ⚠️ 不要再写回 height:100% + margin —— 表现是"底部边框消失"，不报错、只能肉眼看。 */
    height: calc(100% - 6px);
    margin: 3px;
    padding: 25px 23px 27px;
    border-radius: 13px;
    background: #1e2a3b;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}
/* 悬停：与首页其它版块的卡片同一套语言（上浮 -3px + 品牌辉光）。
   🔑 辉光挂在**描边层**（__bg）而不是卡片本体：卡片本体没有背景/圆角，
      直接给 box-shadow 会画出一个方形阴影（描边层才是那个圆角矩形）。
   ⚠️ 位移挂在 `.st-deck-card`（外层），阴影挂在 `__bg` —— 两者分工明确：
      位移带动整卡（含描边层），阴影跟随描边形状。 */
.st-deck-card:hover { transform: translateY(-3px); }
.st-deck-card:hover .st-deck-card__bg {
    box-shadow:
        0 6px 24px rgba(69, 187, 251, .28),
        0 0 22px rgba(68, 185, 134, .22);
}
@media (prefers-reduced-motion: reduce) {
    .st-deck-card { transition: none; }
    .st-deck-card:hover { transform: none; }
}
.st-deck-card__icon {
    width: 76px;
    height: 76px;
    object-fit: contain;
    margin-bottom: 12px;
    filter: drop-shadow(0 6px 16px rgba(69, 187, 251, .28));
}
.st-body .st-deck-card__title {
    margin: 0;
    /* 2026-10-25 业务要求：四问题卡（「企业在AI搜索最需要回答的四个问题」下 4 个框）
       的标题文字**放大 10%**：clamp(1.125rem, 1.35vw, 1.375rem)
       → clamp(1.2375rem, 1.485vw, 1.5125rem)（1440 档 19.44 → 21.4px）。
       ⚠️ 三项同比例放大，只调上限会让手机档看不出变化。 */
    font-size: clamp(1.2375rem, 1.485vw, 1.5125rem);
    font-weight: 700;
    line-height: 1.35;
    color: #fff;
    letter-spacing: 0;
}
.st-deck-card__text {
    margin: 12px 0 0;
    font-size: .9375rem;
    line-height: 1.75;
    color: rgba(255, 255, 255, .82);
    text-wrap: pretty;
}

/* ---- 28.3 五阶段闭环表 ----
   🔴 2026-10-20 按设计稿还原分隔线：**不是**一整根横线，而是两根独立、两端带箭头、
      带发光的线：
        · 左边一根跨「阶段 + 平台标准」两列（设计稿的分组语义：前两列是一组），蓝色；
        · 右边一根只在「用户核心价值」列，绿色 #44b986；
        · 两者之间**留空隙**（gap），视觉上明确是"两个分组"而不是"一条线被染了两段色"。
      实现：用 grid 定位的独立元素（.st-deck-loop__rule），内部两个 span 各自占对应的列。
      ⚠️ 不能用 row 的 border-bottom：border 无法分段变色，更画不出箭头。 */
.st-deck-loop { margin-top: clamp(24px, 3vw, 40px); }

.st-deck-loop__header,
.st-deck-loop__row,
.st-deck-loop__rule {
    display: grid;
    grid-template-columns: minmax(0, 5.2fr) minmax(0, 5.6fr) minmax(0, 7fr);
    gap: 20px;
    align-items: center;
}
/* 表头：三个标题**压在带箭头的分组线**上（与「内容生产四步」同一形态）。
   ## 结构（与视图对应）
   .st-deck-loop__header         —— 与数据行同比例的 3 列 grid
     .st-deck-loop__header-group--a  —— 跨第 1-2 列（蓝组）
         .st-deck-loop__header-cell ×2 —— 组内 2 列 grid，各放一个标题
     .st-deck-loop__header-group--b  —— 第 3 列（绿组）
         .st-deck-loop__header-cell    —— 单标题

   ## 为什么左组要再套一层 2 列 grid
   组内两个标题要**分别在自己那一列居中**（与下方数据列对齐）。
   父级列宽是 `5.2fr / 5.6fr / 7fr`、gap 20px；左组跨前两列后总宽 = 10.8u + 20
   （u 为父级单位宽）。组内再用 `5.2fr / 5.6fr` + gap 20px 时，组内单位
   u' = (10.8u + 20 - 20) / 10.8 = u —— **与父级单位宽完全相等**，故列宽精确对齐。
   ⚠️ 若改动父级的 fr 比例或 gap，这里必须同步，否则标题会与数据列错开。

   ## 线怎么画
   由两个 group 的 `::before` 各画一条贯穿整组的线（左组一条连续蓝线、
   右组一条绿线），两端用 `::after`/`::before` 的 border 三角形做箭头。
   标题文字通过 `.st-deck-loop__header-label` 垫页面底色，把线"断开"，
   视觉上就是"文字压在线上"。
   ⚠️ 不能用 text-decoration: line-through —— 那是删除线（细、贴字腰），
      与设计稿的"线贯穿整组、文字把线断开"不是一回事。 */
.st-deck-loop__header {
    display: grid;
    grid-template-columns: minmax(0, 5.2fr) minmax(0, 5.6fr) minmax(0, 7fr);
    gap: 20px;
    align-items: center;
    padding: 4px 0 14px;
    font-size: .875rem;
    font-weight: 600;
    letter-spacing: .02em;
}
.st-deck-loop__header-group {
    position: relative;
    display: grid;
    align-items: center;
}
.st-deck-loop__header-group--a {
    grid-column: 1 / 3;
    /* 与父级同比例、同 gap —— 见上方算式，列宽与数据列严格相等。 */
    grid-template-columns: minmax(0, 5.2fr) minmax(0, 5.6fr);
    gap: 20px;
    color: #46bdf8;
}
.st-deck-loop__header-group--b {
    grid-column: 3 / 4;
    grid-template-columns: minmax(0, 1fr);
    color: #44ba88;
}
/* 分组线（贯穿整组）。 */
.st-deck-loop__header-group::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 2px;
    transform: translateY(-50%);
    border-radius: 2px;
    z-index: 0;
}
.st-deck-loop__header-group--a::before {
    background: #3ba1ff;
    box-shadow: 0 0 10px rgba(59, 161, 255, .65);
}
.st-deck-loop__header-group--b::before {
    background: #44b986;
    box-shadow: 0 0 10px rgba(68, 185, 134, .65);
}
/* 两端箭头（border 三角形，与 §28.3 的分隔线同一套手法）。
   ⚠️ 箭头画在**首/末 cell** 上而不是 group 上：group 的 ::before/::after 已被
      线条与（无）占用，一根元素只能有两个伪元素 —— 两端箭头正好用首 cell 的
      ::before + 末 cell 的 ::after。 */
.st-deck-loop__header-group > .st-deck-loop__header-cell:first-child::before,
.st-deck-loop__header-group > .st-deck-loop__header-cell:last-child::after {
    content: "";
    position: absolute;
    top: 50%;
    width: 0;
    height: 0;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    transform: translateY(-50%);
    z-index: 0;
}
.st-deck-loop__header-group > .st-deck-loop__header-cell:first-child::before {
    left: 0;
    border-right: 7px solid currentColor;
}
.st-deck-loop__header-group > .st-deck-loop__header-cell:last-child::after {
    right: 0;
    border-left: 7px solid currentColor;
}
.st-deck-loop__header-cell {
    position: relative;
    text-align: center;
    z-index: 1;
}
/* 标题文字垫页面底色，把线断开 —— 这才是"压在线上"的观感。 */
.st-deck-loop__header-label {
    position: relative;
    z-index: 2;
    display: inline-block;
    padding: 0 12px;
    background: var(--st-canvas);
}

/* 分隔线行：第一根跨第 1-2 列，第二根占第 3 列。 */
.st-deck-loop__rule { padding: 0; }
.st-deck-loop__rule-a { grid-column: 1 / 3; }
.st-deck-loop__rule-b { grid-column: 3 / 4; }
.st-deck-loop__rule-a,
.st-deck-loop__rule-b {
    position: relative;
    height: 2px;                                  /* 线本体 */
    border-radius: 2px;
}
/* 线两端各用一个伪元素画箭头（border 三角形，无需 SVG/字体）。
   左端朝左、右端朝右 —— 设计稿的"两头都是箭头"。 */
.st-deck-loop__rule-a::before,
.st-deck-loop__rule-b::before,
.st-deck-loop__rule-a::after,
.st-deck-loop__rule-b::after {
    content: "";
    position: absolute;
    top: 50%;
    width: 0;
    height: 0;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    transform: translateY(-50%);
}
.st-deck-loop__rule-a::before,
.st-deck-loop__rule-b::before {
    left: -1px;
    border-right: 7px solid currentColor;         /* 朝左的箭头 */
}
.st-deck-loop__rule-a::after,
.st-deck-loop__rule-b::after {
    right: -1px;
    border-left: 7px solid currentColor;          /* 朝右的箭头 */
}

/* 蓝组：线条 + 箭头同色，并带发光。 */
.st-deck-loop__rule-a {
    color: #3ba1ff;
    background: currentColor;
    box-shadow: 0 0 10px rgba(59, 161, 255, .65);
}
/* 绿组：#44b986（业务指定色值），同款发光。 */
.st-deck-loop__rule-b {
    color: #44b986;
    background: currentColor;
    box-shadow: 0 0 10px rgba(68, 185, 134, .65);
}

.st-deck-loop__row {
    padding: 18px 0;
    /* 🔴 2026-10-20 移除 border-bottom：原来每行有一条 1px 细线，与 2px 的渐变分组线
       在**同一位置**叠加 —— 表现为"有的分隔线看起来比别的细"（细的就是这条 1px
       border）。分隔线现在**只由 `.st-deck-loop__rule` 承担**（2px + 箭头 + 发光），
       行自身不再画线。 */
}
.st-deck-loop__row:hover { background: rgba(59, 161, 255, .05); }

.st-deck-loop__stage { display: flex; align-items: center; gap: 14px; }
.st-deck-loop__num {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(180deg, #46bdf3, #44b986);
    color: #1e2a3b;
    font-size: 1.125rem;
    font-weight: 700;
    line-height: 1;
}
.st-deck-loop__name {
    font-size: clamp(1.0625rem, 1.35vw, 1.375rem);
    font-weight: 700;
    /* 🔴 行高必须落在整数像素（见 .st-deck-loop__value 的说明）。 */
    line-height: 26px;
    color: #fff;
    letter-spacing: 0;
}
.st-deck-loop__std { display: flex; flex-direction: column; gap: 4px; }
.st-deck-loop__std-cn {
    font-size: 1rem;
    font-weight: 600;
    color: #46bdf8;
    line-height: 24px;
}
.st-deck-loop__std-en {
    font-size: .8125rem;
    color: rgba(70, 189, 248, .62);
    /* 13px × 1.5 = 19.5px 会引入 0.5px 亚像素 —— 改整数 20px。 */
    line-height: 20px;
}
.st-deck-loop__value {
    font-size: .9375rem;
    /* 🔴 2026-10-20 修「某一条分隔线看起来比别的细」：
       原 `line-height: 1.75` × 15px = **26.25px** → 两行 = 52.5px → 行高出现 .5px，
       累积到分隔线就是"线落在半像素位置"。2px 的线画在半像素上会被抗锯齿摊到
       2~3 个设备像素、透明度也不均 —— 于是**相邻的线几条看着粗、几条看着细**，
       且具体哪条细会随上方内容高度变化而漂移（业务两次报的是不同的线）。
       改成整数 26px：两行 52px、行高与线位置全部落在整数像素，粗细一致。
       ⚠️ 改这里时**同一行内其它文本的 line-height 也要用整数 px**
          （name/std-cn/std-en 已同步）—— 只要有一处出现 .5，整行又会被拉成小数。 */
    line-height: 26px;
    color: rgba(255, 255, 255, .82);
    text-wrap: pretty;
}

@media (max-width: 1023.98px) {
    .st-deck-loop__header { display: none; }
    .st-deck-loop__row {
        grid-template-columns: minmax(0, 1fr);
        gap: 10px;
        padding: 20px 0;
        align-items: start;
    }
    .st-deck-loop__std { margin-top: 2px; }
}

/* ---- 28.4 六步流程 ---- */
.st-deck-flow {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 14px;
    margin-top: clamp(24px, 3vw, 40px);
}
@media (max-width: 1279.98px) { .st-deck-flow { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 639.98px) { .st-deck-flow { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---- 分组标签（「内容生产四步」/「监测与验证两步」）----
   🔴 2026-10-20 按设计稿还原：标签**横跨它覆盖的卡片数、居中**，
      左右各一条**带箭头**的线，线的颜色与文字一致，且带发光。
        · 「内容生产四步」跨第 1-4 张卡（蓝）；
        · 「监测与验证两步」跨第 5-6 张卡（绿，色值 #44b986）。

   ## 为什么标签要放进 .st-deck-flow 这个 grid 里
   靠 `grid-column: 1 / 5` 跨列，宽度就自动等于"4 张卡 + 中间 3 个 gap"——
   与卡片组**严格对齐**。放在外面只能按百分比手算，断点一变就错位。
   ⚠️ 断点处理：≤1279px 时流程是 3 列、≤639px 是 2 列，原有的跨列值不再成立，
      故两个断点下隐藏标签（分组语义由卡片本身承载，信息不丢）。

   ## 线条怎么画
   用 flex 的 `::before/::after` 会被文字宽度挤压，故用「line + text + line」三段结构：
   两条 line 各 `flex: 1` 自动填满剩余宽度，文字居中不动。
   箭头用 border 三角形（与 §28.3 的分隔线同一套手法），保证风格统一。 */
.st-deck-flow__legend {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-bottom: 4px;
    font-size: .9375rem;
    font-weight: 700;
    letter-spacing: .01em;
    text-align: center;
}
.st-deck-flow__legend--a { grid-column: 1 / 5; color: #46bdf8; }
.st-deck-flow__legend--b { grid-column: 5 / 7; color: #44b986; }

.st-deck-flow__legend-line {
    position: relative;
    flex: 1;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
}
/* 发光：按分组色分别给（蓝色与绿色各自的色晕，不混色）。 */
.st-deck-flow__legend--a .st-deck-flow__legend-line { box-shadow: 0 0 10px rgba(70, 189, 248, .7); }
.st-deck-flow__legend--b .st-deck-flow__legend-line { box-shadow: 0 0 10px rgba(68, 185, 134, .7); }

/* 两端箭头：左段朝左、右段朝右。两条 line 各画自己外侧那一端的箭头。 */
.st-deck-flow__legend-line::before,
.st-deck-flow__legend-line::after {
    content: "";
    position: absolute;
    top: 50%;
    width: 0;
    height: 0;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    transform: translateY(-50%);
}
/* 第一条线：只有**左端**有朝左的箭头。 */
.st-deck-flow__legend-line:first-child::before { left: -1px; border-right: 7px solid currentColor; }
/* 第二条线：只有**右端**有朝右的箭头。 */
.st-deck-flow__legend-line:last-child::after { right: -1px; border-left: 7px solid currentColor; }

@media (max-width: 1279.98px) {
    .st-deck-flow__legend { display: none; }
}

.st-deck-flow__card {
    position: relative;
    margin-top: 18px;
    padding: 30px 18px 22px;
    border-radius: 14px;
    border: 2px solid transparent;
    background:
        linear-gradient(#1e2a3b, #1e2a3b) padding-box,
        linear-gradient(180deg, #46bdf3, #44b986) border-box;
    text-align: center;
    /* 2026-10-20 业务要求：与四痛点卡、首页其它卡片同一套悬停语言
       （上浮 -3px + 双色辉光）。这里卡本身有圆角与背景，可以直接给 box-shadow。 */
    transition: transform .28s cubic-bezier(.2, .8, .3, 1), box-shadow .28s ease;
    will-change: transform;
}
.st-deck-flow__card:hover {
    transform: translateY(-3px);
    box-shadow:
        0 6px 24px rgba(69, 187, 251, .28),
        0 0 22px rgba(68, 185, 134, .22);
}
@media (prefers-reduced-motion: reduce) {
    .st-deck-flow__card { transition: none; }
    .st-deck-flow__card:hover { transform: none; }
}
.st-deck-flow__num {
    position: absolute;
    top: -18px;
    left: 50%;
    transform: translateX(-50%);
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(180deg, #46bdf3, #44b986);
    color: #1e2a3b;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1;
}
.st-body .st-deck-flow__title {
    margin: 0;
    font-size: 1.0625rem;
    font-weight: 700;
    color: #fff;
    letter-spacing: 0;
}
.st-deck-flow__owner {
    margin: 6px 0 0;
    font-size: .8125rem;
    font-weight: 600;
    color: #46bdf8;
}
.st-deck-flow__text {
    margin: 10px 0 0;
    font-size: .8125rem;
    line-height: 1.65;
    color: rgba(255, 255, 255, .78);
    text-wrap: pretty;
}

.st-deck-stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    /* 2026-10-20 业务要求：块与块之间的间距加大（24 → 48 → **72px**，两轮反馈）。
       数字 + 说明文字是"一组读数"，四组贴太近会读成一张表；
       拉开后每组自成一块，扫读时先看数字、再看它属于哪一项。 */
    gap: 72px;
    margin-top: clamp(36px, 4.4vw, 56px);
}
@media (max-width: 1023.98px) { .st-deck-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 48px; } }
@media (max-width: 479.98px) { .st-deck-stats { grid-template-columns: minmax(0, 1fr); gap: 28px; } }

/* 2026-10-25 业务要求：数字与说明文字**居上对齐**（原 center 会让短数字和两行文字
   的中线对齐，四组读起来不齐）；标签字号也从 .875rem 调大到 1rem。 */
.st-deck-stat {
    display: flex;
    align-items: flex-start;
    gap: 14px;
}
.st-deck-stat__num {
    flex: 0 0 auto;
    font-size: clamp(2.5rem, 4vw, 4rem);
    font-weight: 300;
    /* 0.92：让数字视觉顶边与首行文字顶边对齐（line-height:1 时数字上沿会略低）。 */
    line-height: .92;
    color: #46bdf8;
    font-variant-numeric: tabular-nums;
}
.st-deck-stat__label {
    font-size: 1rem;
    line-height: 1.55;
    color: rgba(255, 255, 255, .82);
    text-wrap: pretty;
    /* 顶端对齐后再压 2px，抵消数字自身的内边距差 */
    padding-top: 2px;
}

/* ---- 28.5 行业包网格（浅色卡）---- */
.st-deck-ind {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
    margin-top: clamp(24px, 3vw, 40px);
}
@media (max-width: 1023.98px) { .st-deck-ind { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 479.98px) { .st-deck-ind { grid-template-columns: minmax(0, 1fr); } }

.st-deck-ind__item {
    padding: 16px 20px 18px;
    border-radius: 10px;
    /* 2026-10-20 业务要求：纯白在整页暗底上太扎眼 → 加一点透明度（.92）。
       ⚠️ 只调 alpha，**保持浅色系**：这里的强对比是设计稿刻意用来做视觉重音的，
         不要"为了统一"改成深色卡（那会丢掉这块的强调作用）。 */
    background: rgba(246, 248, 252, .92);
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.st-deck-ind__name {
    font-size: .9375rem;
    font-weight: 600;
    color: #1a2330;
    letter-spacing: 0;
}
.st-deck-ind__subs {
    font-size: .8125rem;
    color: #1e3a5f;
}
.st-deck-ind__subs b {
    font-size: 1.125rem;
    font-weight: 700;
    margin-right: 2px;
}

/* ---- 28.6 结尾 CTA ---- */
/* 🔴 2026-10-20：去掉 `margin-top`（原 clamp(56px, 7vw, 96px)）。
   它是**当年 CTA 作为「平台能力全景」deck 最后一段**时的段间距；
   后来 CTA 独立成 section，这层 margin 仍叠加在 section 的 80px 上内边距之上 →
   标题上方实际空隙 176px，视觉上"上一版块与 CTA 之间空得离谱"（业务反馈"上面间距太大"）。
   现在间距**统一由 `.st-section--cta` 的 padding 控制**，只留一处来源。 */
.st-deck-cta {
    text-align: center;
}

/* CTA 版块的上下间距（2026-10-20 业务要求：上面小一点、下面大一点）。
   ## 为什么上小下大
   它是**整页收尾**：上方紧接常见问题/智库，收紧能让"收尾"读作同一段落的结尾；
   下方直接接页脚，放大留白让页面自然落地，不至于把按钮顶到页脚边上。
   ⚠️ 只在这个版块用；别套到 `--tight`（那个是"全站统一收紧"，语义不同）。 */
.st-section--cta {
    padding-top: 48px;
    padding-bottom: 120px;
}
@media (max-width: 767px) {
    .st-section--cta { padding-top: 32px; padding-bottom: 72px; }
}
.st-body .st-deck-cta__title {
    margin: 0;
    /* 2026-10-25 业务要求：首页 hero 之外其它模块标题放大 20%
       （clamp(1.5rem, 2.6vw, 2.375rem) → clamp(1.8rem, 3.12vw, 2.85rem)；1440 档 37.44 → 44.9px）。
       ⚠️ 与 .st-deck__title 同批放大 —— 三处版块标题必须保持同一档，
          否则滚动时会觉得"最后一块标题突然变小"（层级漂移，不报错）。 */
    font-size: clamp(1.8rem, 3.12vw, 2.85rem);
    font-weight: 300;
    color: #26d6ff;
    letter-spacing: 0;
}
.st-deck-cta__sub {
    margin: 12px auto 0;
    max-width: 52rem;
    /* 2026-10-25 业务要求：副标题放大 20% 并加粗
       （clamp(.9375rem, 1.2vw, 1.125rem) → clamp(1.125rem, 1.44vw, 1.35rem)；600 字重）。 */
    font-size: clamp(1.125rem, 1.44vw, 1.35rem);
    font-weight: 600;
    line-height: 1.7;
    color: #44b986;
}

/* ---- 28.7 联系方式（左 3 行文字 / 右企业微信二维码）----
   2026-10-20 业务要求：删掉「先做免费诊断」按钮，副标题下方改成"左文字 + 右二维码"。

   ## 🔴 二维码尺寸：176px（2026-10-20 二次调整，业务反馈「太小，扫不出来」）
   原为 78px（= 文字 3 行 26px 的高度）。但二维码图片**自带约 7.5% 白边静区**
   （445px 原图里码面只有 378px ≈ 85%）→ 78px 显示时实际码面仅约 66px，
   按 53×53 模块算每模块约 1.2px，手机基本对不上焦。
   现改为 **176px**（码面约 150px、模块约 2.8px），实测可正常扫码。
   ⚠️ 再调小时请保持 ≥140px：低于这个值模块像素不足，扫码会开始"看运气"。
      守卫：SiteDarkRedesignV8Test::test_contact_qr_is_large_enough_to_scan。

   ## 左右等高怎么做到（仍然成立）
   文字块与二维码**都显式 176px 高**，文字用 `justify-content: center` 垂直居中
   （3 行 78px 内容居中在 176px 里）。
   不用 `align-items: stretch` —— 图片有固定宽高比时会形成循环依赖。
   ⚠️ 二维码必须带**白底**：它本身是黑白码，透明底在暗色页面上会扫不出来
      （图片自带白底，故这里只做圆角 + 一点留白，不要加暗色边框）。 */
/* 2026-10-20 顺序恢复：联系方式块（含二维码）在上、按钮在下。
   两者的上下间距各 28px —— 不要只给其中一个，否则会贴着副标题或贴着二维码。 */
.st-deck-cta__contact {
    margin-top: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 40px;
    flex-wrap: wrap;
}
/* 与二维码等高（176px），3 行文字在其中垂直居中。
   ⚠️ 高度必须与 `.st-deck-cta__qr` 的 height 一致 —— 改一处就要改另一处，
      否则左右会参差（业务明确要求左右高度一致）。 */
/* 🔴 2026-10-20 布局：左列 = 3 行文字（上）+ 按钮（下），**与二维码同为 176px 高**。
   用 `justify-content: space-between` 实现业务要求的对齐关系：
     · 文字组顶边 ↔ 二维码顶边（两条都在容器顶端）
     · 按钮底边   ↔ 二维码底边（两条都在容器底端）
   ⚠️ 不要改回 `center`：那会让文字与按钮在中间挤成一团、上下都不齐。
   ⚠️ 三行文字必须包在 `.st-deck-cta__contact-lines` 里：
      否则 space-between 会把间距平均分到「每一行之间」，三行被拉散。 */
.st-deck-cta__contact-text {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: flex-start;
    height: 176px;
    text-align: left;
}
/* 三行联系方式作为**一个整体**参与 space-between（见上）。 */
.st-deck-cta__contact-lines {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}
.st-deck-cta__contact-line {
    font-size: .9375rem;
    line-height: 26px;              /* 3 行 = 78px，与二维码等高（见上） */
    color: rgba(255, 255, 255, .78);
    white-space: nowrap;
}
.st-deck-cta__contact-line b {
    font-weight: 700;
    color: #fff;
}
/* 邮箱链接：与正文同色（白）、**不加下划线**（2026-10-20 业务明确要求）。
   ⚠️ 必须显式写 text-decoration: none —— 浏览器对 <a> 默认带下划线，
      而本页没有全局 a 的 text-decoration 复位（只在个别组件里单独写）。 */
.st-deck-cta__contact-mail {
    color: inherit;
    text-decoration: none;
}
.st-deck-cta__contact-mail:hover,
.st-deck-cta__contact-mail:focus-visible {
    color: #fff;
    text-decoration: none;
    opacity: .85;
}
.st-deck-cta__qr {
    display: block;
    width: 176px;
    height: 176px;
    border-radius: 10px;
    background: #fff;
    /* 不留 padding：图片自带 4 模块静区（约 7.5% 白边），再叠加 padding
      只会进一步压缩码面 —— 上一个版本"扫不出来"就与画面太小直接相关。 */
    padding: 0;
    box-sizing: border-box;
    object-fit: contain;
    /* 白底块在暗页上很亮，加一层柔光让它与页面融合，而不是"贴了一块白纸"。 */
    box-shadow: 0 6px 20px rgba(0, 0, 0, .35), 0 0 18px rgba(69, 187, 251, .18);
}
/* 窄屏：文字与二维码上下堆叠，二维码居中。 */
@media (max-width: 639.98px) {
    .st-deck-cta__contact { flex-direction: column; gap: 22px; }
    /* 堆叠布局下不再需要"与二维码等高" —— 固定高度 + space-between 只会撑出大段空白。 */
    .st-deck-cta__contact-text { text-align: center; height: auto; align-items: center; gap: 22px; }
    .st-deck-cta__contact-lines { align-items: center; }
    .st-deck-cta__contact-line { white-space: normal; }
}
.st-deck-cta__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 2026-10-20：按钮放大（52→58px 高、字号 1rem→1.125rem），
       与放大后的 176px 二维码体量相称；否则大码旁边一个小按钮会显得失衡。 */
    min-height: 58px;
    padding: 0 52px;
    border-radius: var(--st-r-pill);
    background: linear-gradient(90deg, #44b986, #46bdf3);
    color: #062420;
    font-size: 1.125rem;
    font-weight: 700;
    text-decoration: none;
    transition: transform .18s ease, box-shadow .18s ease, opacity .18s ease;
}
.st-deck-cta__btn:hover { transform: translateY(-1px); box-shadow: 0 10px 26px rgba(70, 189, 248, .32); }
.st-deck-cta__btn:active { transform: none; }

/* ---------------------------------------------------------------------------
   28.9 首页新增板块（2026-10-25，依据业务 PPT《官网首页修改》）

   两块都是「纯信息型」，不承载操作，故沿用 28.1 的标题组 + 与四问卡一致的
   深底描边语言，避免在同一页出现第三套卡片风格。
--------------------------------------------------------------------------- */

/* ── ①「为什么需要做GEO？」：两个大数字 + 说明 + 一句转折 ───────────────── */
.st-why {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* 与四问卡组的左边距节奏一致（标题居中、内容块居中收窄） */
    gap: clamp(32px, 6vw, 96px);
    max-width: 900px;
    margin: clamp(28px, 3.4vw, 44px) auto 0;
    text-align: center;
}
@media (max-width: 639.98px) {
    .st-why { grid-template-columns: minmax(0, 1fr); gap: 32px; }
}
.st-why__num {
    /* 大数字是这一块的视觉主体，用与 hero 同族的渐变字（浅青 → 亮绿）而非纯色。
       2026-10-25 业务要求：数字**再大 20% 并加粗**，但单位（% / 亿）保持原字号 ——
       故数字与单位拆成两个 span：本类只管排布与渐变，字号分别给 __num-val / __num-unit。
       原「整串 clamp(3rem, 6.5vw, 5.5rem)」= 主体字号，×1.2 后给 .st-why__num-val，
       单位沿用原值给 .st-why__num-unit。 */
    display: flex;
    align-items: baseline;
    justify-content: center;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    background: linear-gradient(180deg, #7fe3ff, #4ade9b);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}
.st-why__num-val {
    /* 2026-10-25 二次修正：业务要求「不要加粗了，但还不够大，再放大 20%」。
       字号：上一版 clamp(3.6rem, 7.8vw, 6.6rem) ×1.2 → clamp(4.32rem, 9.36vw, 7.92rem)
             （大屏约 126.7px，是最初整串 88px 的 1.44 倍）。
       字重：700 → 200（回到加粗前的细体，与单位同字重；数字靠**字号**做视觉主体）。 */
    font-size: clamp(4.32rem, 9.36vw, 7.92rem);
    font-weight: 200;
}
.st-why__num-unit {
    font-size: clamp(3rem, 6.5vw, 5.5rem);
    font-weight: 200;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
    .st-why__num { color: #6cd6ff; -webkit-text-fill-color: currentColor; background: none; }
}
.st-why__label {
    margin: 12px auto 0;
    max-width: 22rem;
    font-size: clamp(.9375rem, 1.2vw, 1.0625rem);
    line-height: 1.65;
    color: rgba(255, 255, 255, .78);
    text-wrap: pretty;
}
/* 转折句：文字**嵌在线中间**（左线 + 文字 + 右线，右端带箭头）。
   2026-10-25 二次修正 —— 首版把整条线单独画、文字用负 margin 去"压"，
   真机看是「文字掉在线下方，且没有左右留白」，与业务参照的「可交付结果」
   样式完全不同。

   🔑 正解直接照抄页内 legend 的三段结构（.st-deck-flow__legend）：
       line(flex:1) + text + line(flex:1)，flex 行内 gap 提供左右留白，
       align-items:center 让文字与线自然同高 —— 不需要任何负 margin。
   线与箭头参数沿用 legend-line：2px 高 + 圆角 + box-shadow 0 0 10px 发光，
   箭头用 border 三角。同页线宽/发光必须一致，否则肉眼能看出两套。
   颜色按业务要求用绿色 #44b986。 */
.st-why__divider {
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: 860px;
    /* 上间距承接上方数字组；下间距承接下一块标题（此前真机验证过这个量级）。 */
    margin: clamp(28px, 3.4vw, 44px) auto clamp(56px, 6.5vw, 96px);
}
.st-why__divider-line {
    position: relative;
    flex: 1;
    height: 2px;
    border-radius: 2px;
    background: #44b986;
    box-shadow: 0 0 10px rgba(68, 185, 134, .7);
}
/* 右端箭头：与 legend-line 同款三角（border 拼） */
.st-why__divider-line--arrow::after {
    content: '';
    position: absolute;
    right: -1px;
    top: -3px;
    width: 0;
    height: 0;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    border-left: 7px solid #44b986;
}
.st-why__note {
    /* 业务要求：文字白色。位置由父级 flex 的 align-items:center 决定（与线同高），
       绝不写负 margin / 绝对定位 —— 那正是首版"文字掉到线下面"的成因。 */
    margin: 0;
    flex: 0 1 auto;
    text-align: center;
    font-size: clamp(1rem, 1.4vw, 1.25rem);
    line-height: 1.5;
    color: #ffffff;
    text-wrap: pretty;
}

/* ── ②「backspacegeo 是什么？」：定位说明 + 三步卡 + 免责声明 ─────────────── */
.st-who__lead {
    max-width: 1100px;
    margin: clamp(20px, 2.4vw, 28px) auto 0;
    text-align: center;
    font-size: clamp(1rem, 1.35vw, 1.1875rem);
    line-height: 1.85;
    color: rgba(255, 255, 255, .82);
    text-wrap: pretty;
}
.st-who__steps-title {
    /* 2026-10-25 业务指正：这是**副标题**，应用绿色（#44b986，与 .st-deck__kicker 同色），
       不是主标题蓝（#50d6ff）。全站首页除 hero 外统一「主标题蓝 / 副标题绿」。
       2026-10-25 二次：随其它副标题一起**放大 20% 并加粗**
       （clamp(1.125rem, 1.7vw, 1.5rem) → clamp(1.35rem, 2.04vw, 1.8rem)，400 → 600）；
       否则同一页里它会比其它副标题明显小一号、字重也轻一档。 */
    margin: clamp(32px, 4vw, 52px) 0 0;
    text-align: center;
    font-size: clamp(1.35rem, 2.04vw, 1.8rem);
    font-weight: 600;
    color: #44b986;
}
.st-who__steps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(16px, 2.2vw, 28px);
    margin-top: clamp(20px, 2.6vw, 32px);
}
@media (max-width: 767.98px) {
    .st-who__steps { grid-template-columns: minmax(0, 1fr); }
}
.st-who__card {
    position: relative;
    padding: 30px 24px 26px;
    border: 1px solid rgba(80, 214, 255, .26);
    border-radius: 14px;
    background: #1e2a3b;
    text-align: center;
}
/* 序号圆点压在卡片上边缘居中（与六步流程节点同款语言） */
.st-who__num {
    position: absolute;
    top: -17px;
    left: 50%;
    transform: translateX(-50%);
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    background: linear-gradient(135deg, #46bdf8, #44b986);
    color: #0c1220;
    font-size: .9375rem;
    font-weight: 700;
}
.st-who__card-title {
    margin: 0;
    font-size: clamp(1.0625rem, 1.4vw, 1.3125rem);
    font-weight: 500;
    color: #ffffff;
}
.st-who__card-text {
    margin: 10px 0 0;
    font-size: clamp(.875rem, 1.1vw, 1rem);
    line-height: 1.7;
    color: rgba(255, 255, 255, .74);
    text-wrap: pretty;
}
.st-who__disclaimer {
    /* 合规声明：刻意弱化为次要信息，但必须可读（不得藏进 tooltip） */
    max-width: 980px;
    margin: clamp(28px, 3.4vw, 40px) auto 0;
    text-align: center;
    font-size: clamp(.875rem, 1.05vw, .9375rem);
    line-height: 1.75;
    color: rgba(255, 255, 255, .58);
    text-wrap: pretty;
}

/* ===========================================================================
   §35 内页氛围装饰层（2026-10-26，业务反馈「内页全是文字、没有设计感」）

   ## 问题（实测数据，不是感觉）
   6 个内页合计只有 **1 张位图**；多个版块是「1814px 高、985 字、零视觉元素」的纯文字墙；
   除 CTA 外**所有 section 背景都是透明的** —— 整页一片深色，没有任何分区或层次线索。

   ## 本层的定位
   底纹（ambient texture），不是插图。它承担三件事：
   ① 给长文版块一个"有东西"的视觉落点，避免大片空白显得未完成；
   ② 用不同变体区分版块性质（流动 / 节点 / 粒子），替代"换底色"这种被业务否掉的做法
      （见 §.st-section--soft：2026-10-25 业务要求背景统一，不再用色块分区）；
   ③ 全部自绘 SVG，零版权风险、可跟主题变量走，且不增加任何 JS 依赖。

   ## 🔴 五条硬约束（改了就会出事）
   ① **透明度上限 1**：所有图形本身已用 0.03~0.13 的低透明色，外层不再叠 opacity；
   ② **必须 pointer-events:none**：它铺在内容后面，不能截获点击/选择；
   ③ **z-index:0 且内容层 z-index:1**：不建立新的层叠上下文，避免盖住正文与下拉菜单
      （本项目有过 z-index 被 utility 类静默压掉的教训，见 §12 导航注释）；
   ④ **只在 ≥1024px 显示**：窄屏版面紧张，底纹会挤占可读区域；
   ⑤ **动画只碰 opacity / stroke-dashoffset / transform**，周期 ≥18s。
      ⚠️ 不做 prefers-reduced-motion 降级 —— 与 §33 hero-motif 同判（AGENTS 已记录：
        那条回退会把动画整体关掉，业务两次反馈"没看到动画"）。本层无位移无闪烁，
        属 WCAG 2.3.3 最低风险档。
   --------------------------------------------------------------------------- */
.st-decor {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
}
/* 内容层必须高于底纹：.st-section 的容器默认无 z-index，这里显式抬一层。
   ⚠️ 用 `> .st-container` 限定，避免影响容器内的其它绝对定位元素。 */
.st-section { position: relative; }
.st-section > .st-container { position: relative; z-index: 1; }

.st-decor svg { position: absolute; width: 100%; height: 100%; opacity: .9; }
/* 定位：默认靠右（与 hero-motif 同侧），可切左侧或居中 */
.st-decor--right svg { inset: 0 0 0 auto; width: min(420px, 32%); }
.st-decor--left svg { inset: 0 auto 0 0; width: min(420px, 32%); }
.st-decor--center svg { inset: 0; width: 100%; }

/* 数据流：光点沿路径行进。dasharray 取「短划 + 长空」，dashoffset 走完一个循环
   （数值取路径总长的约数，视觉上无接缝）。 */
.st-decor-flow {
    stroke-dasharray: 26 520;
    animation-name: stDecorFlow;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
}
@keyframes stDecorFlow {
    from { stroke-dashoffset: 546; }
    to   { stroke-dashoffset: 0; }
}
/* LLM 节点图：边上的脉冲。与 flow 同一手法但划更短、更快，读作"信号"。 */
.st-decor-edge {
    stroke-dasharray: 10 220;
    animation-name: stDecorFlow;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
}
/* 粒子场：极缓呼吸（只有透明度，无位移）。 */
.st-decor-dot {
    animation-name: stDecorBreathe;
    animation-timing-function: ease-in-out;
    animation-iteration-count: infinite;
}
@keyframes stDecorBreathe {
    0%, 100% { opacity: .45; }
    50%      { opacity: 1; }
}
/* 窄屏不显示（版面紧张，底纹会挤占可读区域）。
   🔴 例外： 是**带标注的示意图**（有信息量），不是底纹 —— 窄屏也必须显示，
      否则手机上那张图直接消失（实测 768px 下 svgW=0，图变成一条 58px 高的空盒）。 */
@media (max-width: 1023.98px) {
    .st-decor { display: none; }
    .st-decor--diagram { display: block; }
}

/* ===========================================================================
   §36 内页版块节奏与正文测量宽度（2026-10-26，业务反馈「布局排版很丑、没有设计感」）

   ## 两个实测问题
   ① **版块之间没有任何视觉分隔**：除 CTA 外所有 section 背景都是透明的
      （2026-10-25 业务要求「背景上下统一」后，连 --soft 也改成了透明）——
      整页一片深色，滚屏时读不出"一段结束了、下一段开始了"。
   ② **正文行长严重超标**：中文正文实测 53~86 字/行（pricing 最宽 86 字）。
      中文排版的舒适区间是 25~40 字；超过 40 字时眼球回扫跨度变大，
      阅读疲劳明显，且长行在宽屏上会显得"没有排版"、只是把字铺满。

   ## 改法（都不动配色）
   ① 相邻两个内页版块之间加一条**两端淡出的细线** —— 用 hairline 建立节奏，
      不用底色块（那是业务 2026-10-25 明确否掉的）。
      ⚠️ 首页排除在外（业务要求首页不动）：首页 section 都带 `.st-home-section`。
      ⚠️ hero 不是 `.st-section`，所以 hero 与第一个版块之间不会出现线。
   ② 长文段落限宽 `--st-measure`（默认 42em ≈ 中文 42 字/行）。
      只作用于**长正文**（编号行说明、定义行释义、版块副标题、导语）——
      不碰卡片内的短文案（它们本来就窄，限宽会造成大量残行）。
      右侧腾出的空间由 §35 的装饰层填充，不留下"半页空白"。
   --------------------------------------------------------------------------- */

/* 两端淡出的分隔线：纯 hairline 在深底上边界生硬，淡出后像"光衰减"，更贴合暗色体系。 */
.st-section:not(.st-home-section) + .st-section:not(.st-home-section)::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1px;
    pointer-events: none;
    background: linear-gradient(
        90deg,
        rgba(255, 255, 255, 0) 0%,
        rgba(255, 255, 255, .10) 14%,
        rgba(255, 255, 255, .10) 86%,
        rgba(255, 255, 255, 0) 100%
    );
}

/* 正文测量宽度。
   ⚠️ 默认 42em：按中文字宽 1em 估算即 42 字/行，处在舒适区间上沿；
      英文文案在同一条规则下约 42*2=84 字符，也仍在可读范围内（英文理想 60~75）。
      需要更窄时在具体版块用 `--st-measure` 覆写，不要改这里的默认值（全站生效）。 */
.st-body { --st-measure: 42em; }
.st-nrow__text,
.st-def__desc,
.st-lead,
.st-section-head p,
.st-asym__body > p {
    max-width: var(--st-measure, 42em);
}
/* 居中的版块副标题：限宽后必须一起居中，否则文字块会左贴、与居中的标题错开。 */
.st-section-head--center p { margin-inline: auto; }

/* 补充限宽：小字注释与宽卡正文（2026-10-26 实测残留）。
   实测（1440 宽）：`.st-note` 有一行 86 字（1026px）、`.st-card__text` 53 字（744px）。
   ⚠️ 限宽松一些（note 52em / card 40em）：这两类本就是"补充说明"与"卡片正文"，
      收紧太多会在卡片里留下残行（比长行更难看）。
      真正需要严格 42em 的是正文（见上一条规则）。 */
.st-note,
.st-caption {
    max-width: 52em;
}
.st-card__text,
.st-feature__text {
    max-width: 40em;
}

/* ===========================================================================
   §37 服务目录两栏（左列表 + 右侧 sticky 页内导航）—— 2026-10-26

   ## 为什么改
   服务目录原是**全宽单列**：实测 1814px 高、985 字、零视觉元素，是最典型的"文字墙"
   （业务原话「布局排版很丑、没有设计感」）。单纯加底纹不够 —— 空白仍在，
   只是从"空"变成"有噪点"。

   ## 版式
   · 左 8 / 右 4：左栏是阅读主体（编号行），宽度自然收窄到约 800px；
   · 右栏 sticky：跟随滚动，长列表滚到底时右侧始终有锚点；
   · 右栏放**真实可用的页内导航**（不是装饰）—— 纯装饰在长列表旁会被读成"没加载完"。
   · ≤1023px 回落单列：右栏导航改到列表下方（横向排列也不必，直接隐藏装饰、保留列表），
     避免窄屏出现"两列都只有半屏宽"的挤压。
   --------------------------------------------------------------------------- */
.st-split--catalog {
    display: grid;
    grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
    gap: 24px 56px;
    align-items: start;
}
.st-catalog__aside {
    position: sticky;
    top: 96px;                 /* 顶栏高度 + 余量 */
    align-self: start;
    overflow: hidden;
    border-radius: var(--st-r-lg);
    min-height: 360px;
    padding: 24px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    isolation: isolate;        /* 让内含的装饰层 z-index 关在本盒内 */
}
/* 装饰层在本盒里是**铺满盒子**（不是右侧 32%）：盒本身就窄，再切一刀会只剩一条。 */
.st-catalog__aside .st-decor { border-radius: var(--st-r-lg); }
.st-catalog__aside .st-decor--center svg { width: 100%; height: 100%; opacity: .75; }
.st-catalog__aside-inner { position: relative; z-index: 1; }
.st-catalog__nav { list-style: none; margin: 14px 0 0; padding: 0; }
.st-catalog__nav li + li { margin-top: 2px; }
.st-catalog__nav-link {
    display: flex;
    gap: 12px;
    align-items: baseline;
    padding: 7px 8px;
    border-radius: 6px;
    font-size: .8125rem;
    line-height: 1.5;
    color: var(--st-ink-mute);
    text-decoration: none;
    transition: color .16s ease, background-color .16s ease;
}
.st-catalog__nav-link:hover { color: var(--st-ink); background: rgba(255, 255, 255, .05); }
.st-catalog__nav-num {
    flex-shrink: 0;
    font-size: .6875rem;
    color: var(--st-primary);
    font-variant-numeric: tabular-nums;
    letter-spacing: .06em;
}
/* 锚点跳转留出顶栏高度，否则目标行会被粘性顶栏压住（本项目多处踩过）。 */
.st-nrow[id] { scroll-margin-top: 96px; }
@media (max-width: 1023.98px) {
    .st-split--catalog { grid-template-columns: minmax(0, 1fr); gap: 0; }
    /* 窄屏隐藏右侧导航整块：它在这个宽度下会变成列表上方一大段重复目录，
       而列表本身就在眼前，快速导航失去意义。 */
    .st-catalog__aside { display: none; }
}

/* diagram 变体（带标注的链路图，2026-10-26）：
   光点沿 offset-path 行走 —— 这是「数据流」语义的正确实现（光点走在真实链路上，
   不是随机飘），且**零 JS 依赖**。
   `offset-path` / `offset-distance` 是 Baseline 2022-03，无需前缀。 */
.st-decor-pulse {
    animation-name: stDecorTravel;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    animation-duration: 24s;
}
@keyframes stDecorTravel {
    from { offset-distance: 0%; }
    to   { offset-distance: 100%; }
}
/* diagram 变体要看得清标签，不能像底纹那样压到 0.6 以下 */
.st-decor--diagram svg { opacity: .95; }

/* ===========================================================================
   §38 内页排版精修（2026-10-26，依据调研结论 + 实测数据）

   ## 三个实测缺陷
   ① **中文正文行高 1.5 偏紧**：15px × 1.5 = 22.5px，行间仅 7.5px。
      Starlight / Tailwind prose 的正文行高都是 **1.75**，中文（笔画密、字面大）
      比拉丁文更需要行间距 —— 1.5 会让密集中文段落"糊成一块"，是"看起来不精致"
      的直接来源之一。
   ② **英文行长超标**：`--st-measure: 42em` 对中文 ≈ 42 字（合格，WCAG 1.4.8
      要求 CJK ≤ 40），但英文下 42em ≈ **84 字符**，超过 WCAG 建议的 80、
      也超过 prose 的 65ch —— 这就是英文版内页读起来"散"的原因。
      中英文必须**分别定宽**（`em` 适合中文按字数算，`ch` 适合英文按字符算）。
   ③ **`.st-caption` / `.st-note` 等小字块缺少统一的数字等宽**：价格、百分比、
      编号在比例字体下宽度跳动，视觉上"不齐"。

   ## 边界（不要越界改）
   · 不动 `.article-prose`（文章正文，业务明确要求满宽，且有守卫测试）；
   · 不动 `.st-body` 的整体 `line-height`（会影响按钮/表格/表单等所有元素）——
     只给**段落类**元素提高行高，风险面最小。
   --------------------------------------------------------------------------- */

/* ① 段落行高：1.5 → 1.7。只作用于阅读型段落，不碰按钮/标签/表格单元格。 */
.st-body p,
.st-nrow__text,
.st-def__desc,
.st-feature__text,
.st-asym__body > p,
.st-faq details p {
    line-height: 1.7;
}

/* ② 英文页面改用字符数定宽（中文仍用 em / 按字数）。
   ⚠️ 必须带 `html[lang="en"]` 前缀（0,2,1）：`.st-body` 上是 (0,1,0)，
      不加前缀会被静默压掉（本文件已多次栽在"同权重靠顺序"上）。 */
html[lang="en"] .st-body {
    --st-measure: 68ch;
}
/* 英文的注释/小字也相应放宽（中文 52em ≈ 52 字，英文 52em ≈ 104 字符，偏宽但可接受；
   收一点到 78ch 更稳）。 */
html[lang="en"] .st-note,
html[lang="en"] .st-caption {
    max-width: 78ch;
}

/* ③ 数字一律等宽：价格/百分比/编号/统计值不再因字形宽度跳动而"看起来不齐"。
   ⚠️ 只加 `font-variant-numeric`，不改字体家族 —— 零成本、零加载。 */
.st-num,
.st-caption,
.st-note,
.st-nrow__num,
.st-heat td,
.st-bullet__val,
.st-layer__val,
.st-dims__val {
    font-variant-numeric: tabular-nums;
}

/* ④ 中文断行更严格：避免标点跑到行首（`line-break: strict` 是 Baseline 2020-07）。
   ⚠️ 不用 `hanging-punctuation` / `text-spacing-trim`（MDN 明确 Limited/Experimental，
      Firefox 不支持）—— 那类"标点美化"在营销站上不可靠。 */
html[lang="zh-CN"] .st-body {
    line-break: strict;
}

/* 内容页右侧链路图容器（2026-10-26）。
   它是本页唯一的图形，需要"看得见"：给一个极淡的圆角底 + 内边距，
   让 SVG 在深底上有边界感（否则连线太淡会像没渲染出来）。
   ⚠️ 底色用 `--st-canvas-elev`（比页面底亮一档）而不是新色 —— 与卡片层级同源。 */
.st-flow-figure {
    position: relative;
    border-radius: var(--st-r-lg);
    background: var(--st-canvas-elev);
    border: 1px solid var(--st-hairline);
    padding: 28px 20px;
    overflow: hidden;
    isolation: isolate;
}
.st-flow-figure .st-decor { position: relative; inset: auto; }
.st-flow-figure .st-decor--center svg { position: relative; inset: auto; width: 100%; height: auto; }
/* 窄屏：图形放到文字下方，仍是完整可见的一块（不隐藏 —— 它是本页唯一的图）。 */
@media (max-width: 899.98px) {
    .st-flow-figure { margin-top: 32px; }
}
