/* =========================================================
   1. TOKENS —— 全站唯一令牌源（dark 基准）
   ---------------------------------------------------------
   ★ 2026-09-19 结构整理：原先有 13 个顶层令牌块（7 个 :root +
   6 个 [data-theme="light"]）。历轮改动都是「在文件后面再追加一个块去覆盖前面的值」，
   于是**想知道一个变量的真值必须扫完整个文件**：
     · --r-lg    §1 写 22px，§12 又被改成 26px
     · --text-4  §1 写 .28，§21.3 又被改成 .48
     · --text-3  §1(light) 写 .50，§21.3 又被改成 .64
     · --green-hi 直到 §21.1 才补上浅色值
   这种「覆盖层」是维护性 bug 的直接来源（改错地方 = 改了不生效）。
   现在合并为**每主题一个块**：本块（dark 基准）+ 紧随其后的 light 覆盖块。
   子系统仍在块内按「基础 → 玻璃 → 装裱 → 外壳 → 对比度」分组，但每个变量只声明一次。

   ⚠️ 条件层令牌块（@media prefers-reduced-transparency / prefers-contrast）
      仍留在文件后半段的原位 —— 它们**按设计就是有条件的**，不参与本块合并。
   ========================================================= */
:root{
  /* —— 1.1 基础色板 / 玻璃基元 / 品牌色 / 阴影 / 纹理 —— */
  --bg-base:#000000;                 /* Apple 风：纯黑底，拒绝蓝紫 bias */
  /* —— Apple 风环境光：由 violet/pink 霓虹光斑改为极低饱和的白灰光晕 ——
     保留 orb 体积感但彻底降低“华丽/霓虹”感；粉紫仅作为 macOS 式微点缀使用。 */
  --bg-grad-a:rgba(255,255,255,.05);
  --bg-grad-b:rgba(255,255,255,.03);
  --bg-grad-c:rgba(255,255,255,.04);
  --bg-grad-d:rgba(255,255,255,.02);
  /* 文字梯度（四级）。--text-4 见下方，它不是纯装饰 */
  --text:#f5f5f7;
  --text-2:rgba(245,245,247,.72);
  --text-3:rgba(245,245,247,.50);
  /* --text-4 并非纯装饰（.side-cap 侧栏分组标题 / .brand-sub / .step 流程步骤 /
     .oauth-note 登录说明 / .inno-num / .side-user .r 都在里面）。
     §21.3 实测：.28 = 2.32:1 → .42 = 3.94:1（AA 要 4.5）→ **.48 = 4.82:1**。 */
  --text-4:rgba(245,245,247,.48);
  --glass-top:rgba(255,255,255,.05);
  --glass-bot:rgba(255,255,255,.02);
  --hair:rgba(255,255,255,.10);
  --hair-soft:rgba(255,255,255,.05);
  --pink:#FF2D55;                  /* macOS systemPink：仅作微点缀 */
  --cyan:#0071e3;
  --green:#22C55E;
  --green-hi:#86EFAC;
  --pink-hi:#fb7185;
  --tx:#f5f5f7;--tx-soft:rgba(245,245,247,.58);
  --accent:#22C55E;
  --warn:#FBBF24;
  --grad:linear-gradient(135deg,#7A7A82 0%,#7A7A82 100%);
  --grad-cyan:linear-gradient(135deg,#7A7A82 0%,#7A7A82 100%);
  --grad-green:linear-gradient(135deg,#22C55E 0%,#86EFAC 100%);
  --apple-blue:#0071e3;            /* Apple 风主操作蓝（CTA、聚焦环） */
  /* §47 3D 实体投影：三层「接触影→体影→环境扩散影」叠加，读作悬浮实体而非贴纸。
     近层小而深（贴地接触）、中层过渡、远层大而浅（环境光散射），配顶部高光内边
     营造「上亮下暗」的厚度。spread 全部用负值，保证只在边缘下方露影不糊满面板。 */
  --shadow-1:0 1px 0 rgba(255,255,255,.16) inset, 0 -1px 0 rgba(255,255,255,.05) inset,
             0 2px 4px -1px rgba(0,0,0,.55),
             0 12px 28px -12px rgba(0,0,0,.60),
             0 40px 90px -34px rgba(0,0,0,.78);
  --shadow-glow:0 40px 100px -14px rgba(0,0,0,.55), 0 24px 60px -18px rgba(0,0,0,.35);
  /* —— 1.1b 发光材质阶梯（品牌绿）——
     与 --shadow-*（中性投影）分工明确：这里的每一档都是「品牌绿自身发光」，
     只用于状态 / 选中 / 强调。收敛前全站散着 15 处字面量、12 个不同值：
     同一个「指示灯」概念在三处写了两个不同半径（.eyebrow .pulse / .status-pill .led
     是 10px，.toast .dotled 是 11px），同一个「选中胶囊」概念在四处写了同一个几何
     却分成 .9 / .7 两种强度。这类东西读得出毛糙，却说不清哪里糙 —— 根因在此。
     现按「同类同档」收敛为 8 档：

       --glow-led       0 0 10px              6–7px 指示灯（.pulse / .status-pill .led）
       --glow-ring      0 0 16px              图标按钮选中（半径更大、强度更低）
       --glow-chip      0 6px 16px -8px       分段控件选中
       --glow-chip-hi   同上、强度 .7         同类悬停态
       --glow-raise     0 8px 22px -14px      侧栏激活项
       --glow-raise-lg  0 12px 30px -14px     头像（同族、抬升更高）
       --glow-lift      0 12px 34px -10px     主按钮静态
       --glow-lift-hi   0 22px 50px -10px     主按钮悬停

     ⚠️ 两类**不纳入阶梯**、继续写字面量的例外（同 --r-* 的「几何绑定值」豁免）：
        ① .toast .dotled 的 0 0 11px —— 点径 8px（其余指示灯 6/7px），发光半径跟随点径；
           toast 三态 cyan/warn/ok 本来就统一在 11px，内部自洽，不该被拉平。
        ② .view3d / .side-handle 的多层复合阴影 —— 那是面板材质的一部分，不是单纯发光。
     ★ --glow-green（0 0 26px rgba(34,197,94,.55)）全站零引用（静态 grep + 运行时
       computed 双查），2026-09-20 随本阶梯一并移除。 */
  --glow-led:0 0 10px rgba(34,197,94,.9);
  --glow-ring:0 0 16px rgba(34,197,94,.32);
  --glow-chip:0 6px 16px -8px rgba(34,197,94,.9);
  --glow-chip-hi:0 6px 16px -8px rgba(34,197,94,.7);
  --glow-raise:0 8px 22px -14px rgba(34,197,94,.9);
  --glow-raise-lg:0 12px 30px -14px rgba(34,197,94,.9);
  --glow-lift:0 12px 34px -10px rgba(34,197,94,.55);
  --glow-lift-hi:0 22px 50px -10px rgba(34,197,94,.6);
  --noise:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0.055,0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
  /* —— 1.2 圆角：一条**等比 ≈1.33 的阶梯**，全站容器圆角只允许取这 8 档 ——
        --r-2xs   6px   微型方块：刻度 / 内联 code / 22px 细条
        --r-xs    8px   小方块 26–30px（.si-ico / .side-avatar）
        --r-sm   11px   小控件（输入框 / 标签 / 搜索项 / 侧栏链接）
        --r-md   15px   小容器：气泡 / 内联提示 / 图标方块 36–44px
        --r-ml   20px   中容器：浮层面板 / 条带 / 图标方块 56–64px / 统计瓦片
        --r-lg   26px   卡片（.card / .card-md / .mega-panel / .side / .cmp-slot）
        --r-xl   34px   大幅面：画面面板（.view3d / .scope / .stage-shell）/ 模态（.modal-card）
                        / 助手面板（.ai-chat）/ 登录外壳（.auth-shell）
        --r-pill 999px  胶囊

     比值逐档成立：6×1.33=8 · 8×1.33=11 · 11×1.33=15 · 15×1.33=20 · 20×1.33=27≈26 · 26×1.33=35≈34。
     ★ 2026-09-19：--r-2xs 与 --r-ml 是**补上的两个缺档**。此前 6/16/17/18/19/20px 全是散落字面量，
     且**同一类元素圆角各不相同** —— 最明显的是图标方块：36/40/44px 一律 --r-md(15)，
     56/58/64px 却分别写了 17/19/20 三个值，比例反而更小（越大越方）。
     读得出「毛糙」却说不清哪里糙，根因就是这里。
     已按「就近就档 + **同类同档**」统一为令牌。判据：同一类元素必须落同一档。
     ⚠️ 两类**不属于本阶梯**、可以继续写字面量的圆角：
        ① 发丝级（1~5px）：圆点 / 细条 / 气泡缺口；
        ② **几何绑定值**：跟随元素自身尺寸推导出来的圆角（如 18px 宽的侧栏把手右帽）。
           这类值一律要在原地注明「为什么是这个数」。**别硬套 --r-pill** ——
           在 18×148 的元素上 `0 999px 999px 0` 会被收缩成 18px（而非直觉的 9px 半圆），
           比 `0 13px 13px 0` 反而更圆 5px。见 #app .side-handle 的注释。
     --r-lg / --r-xl 原来在 §12 用覆盖块改过（§1 写的是 22 / 30），现已合并为唯一声明。
     注意：.card 的圆角曾写成字面量 26px（而不是 var(--r-lg)），已一并改回令牌。 —— */
  --r-2xs:6px;
  --r-xs:8px;
  --r-sm:11px;
  --r-md:15px;
  --r-ml:20px;
  --r-lg:26px;
  --r-xl:34px;
  --r-pill:999px;
  /* —— 1.3 字阶（9 级模块化 scale）：全站唯一字号来源 ——
     改字号只改这里；任何地方写死 px 字号都会破坏阶梯。
       1  11px    微型标签 / 大写 mono 角标
       2  12.5px  元信息 / 次级标签
       3  14px    默认 UI 正文（按钮、输入框、气泡）
       4  16px    正文基准 / h4
       5  18px    小标题 h3
       6  24px    标题
       7  28px    大标题
       8  40px    章节标题
       9  48px    展示数字
     流体层（唯一例外）：Hero / 章节大标题用 clamp()，端点已对齐 4px 栅格，
     随视口在 32~112px 之间滑动，不参与上面的固定阶梯。 */
  --fs-1:11px;
  --fs-2:12.5px;
  --fs-3:14px;
  --fs-4:16px;
  --fs-5:18px;
  --fs-6:24px;
  --fs-7:28px;
  --fs-8:40px;
  --fs-9:48px;
  /* —— 1.4 交互时长（4 级）：只用于 transition；animation 的长时长是另一回事 —— */
  --dur-1:.12s;
  --dur-2:.2s;
  --dur-3:.3s;
  --dur-4:.45s;
  /* —— 1.5 缓动曲线 —— */
  --ease-out-quart:cubic-bezier(.25,1,.5,1);
  --ease-out-expo:cubic-bezier(.16,1,.3,1);
  --ease-spring:cubic-bezier(.34,1.56,.64,1);
  /* —— 1.6 版心 / 间距 —— */
  --max:1280px;
  --gutter:clamp(18px,4vw,40px);
  --section-y:clamp(84px,10vw,150px);   /* Apple 风：更舒展的板块留白 */
  /* —— 1.7 页面级层叠阶梯（z-index）：全站浮层只允许取下面这几档 ——
       数值只在**同一层叠上下文**内比较。.nav 自身 position:fixed + z-index 会创建新的
       层叠上下文，挂在它内部的 .mega-panel / .search-results 用的是**局部**层叠，
       不参与本阶梯（那里的数只是局部相对高低，与页面无关）。
       同一档位内禁止并列 —— 并列时由 DOM 顺序决定胜负，属于隐形依赖。
         --z-mega-scrim     69  顶部 mega 菜单遮罩，须在 .nav 之下
         --z-nav            70  顶部导航条 .nav
         --z-side-scrim     89  侧栏遮罩 .side-scrim
         --z-side           90  左侧主导航 .side
         --z-modal          91  模态对话框 .modal —— 必须高于 .side，且低于侧栏把手
         --z-side-zone      95  侧栏唤出热区 .side-zone（桌面·不可见）
         --z-side-handle    96  侧栏折叠把 .side-handle（桌面）
         --z-float         100  同层浮层：轻提示 .toast / 全屏舞台 / 全屏对话（三者互斥出现）
         --z-drawer        120  右侧抽屉 .drawer
         --z-chat          180  AI 悬浮窗 .ai-chat
         --z-tour          190  新手指引 #tour
         --z-gate          200  登录门 / 登录页（#authGate / #authPage）
         --z-top           210  登录页顶栏 .auth-topbar
       ★ 2026-09-19：此前这 13 处全是散落字面量，且 .modal 与 .side **同为 95** ——
       谁在上面完全取决于 DOM 顺序（modal 在 .side 之后，所以当前是 modal 胜出）。
       现把 modal 提到 91、侧栏三档整体下移，让「modal 高于 .side、低于侧栏把手」
       变成显式约定。**逐对相对次序与改前完全相同**，因此零视觉变化。
       ⚠️ .search-results 写的 80 是**假页面级**：它在 .nav 内，被 nav 的层叠上下文关住，
       实际只与 .mega-panel 比高低。别把它当页面阶梯用。 —— */
  --z-mega-scrim:69;
  --z-nav:70;
  --z-side-scrim:89;
  --z-side:90;
  --z-modal:91;
  --z-side-zone:95;
  --z-side-handle:96;
  --z-float:100;
  --z-drawer:120;
  --z-chat:180;
  --z-tour:190;
  --z-gate:200;
  --z-top:210;

  /* =========================================================
     §19 液态玻璃（iOS 26/27）的令牌
     高透明填充 + 强折射模糊 + 顶部高光描边 + 底部虹彩晕边
     ========================================================= */
  /* 透明度无级调节（iOS 27 玻璃浓度滑块）：JS 按主题基值换算后写入下面两个 alpha */
  /* 2026-09-17（第三轮，用户明确「两个主题都再通透一些」）：填充只留极薄一层雾，
     「像玻璃」的观感全部交给模糊 + 边缘高光；可读性由更大半径的模糊兜底。 */
  --lg-fill-a-alpha:.062;
  --lg-fill-b-alpha:.016;
  --lg-blurpx:52px;
  /* 下面两条用 var() 引用上面的 alpha，便于 JS 无级调节 */
  --lg-fill-a:rgba(255,255,255,var(--lg-fill-a-alpha));
  --lg-fill-b:rgba(255,255,255,var(--lg-fill-b-alpha));
  /* iOS 27：更强背景扩散（可读性）+ 深色描边（层次/分区）+ 更亮高光 */
  --lg-blur:blur(var(--lg-blurpx)) saturate(210%) brightness(1.12);
  /* 「廉价折射」变体：只有模糊+饱和，不含 SVG 位移。
     任何「内部有动画画布」的面板都改用它 —— 位移折射会让浏览器每一帧都重算一遍
     backdrop 全屏位移，是掉帧的头号元凶（实测取景器渲染由 9 分钟级掉到秒级）。
     视觉上模糊+饱和+rim 已经占了玻璃质感的大头，去掉位移几乎看不出差别。 */
  --lg-blur-flat:blur(var(--lg-blurpx)) saturate(210%) brightness(1.12);
  /* 四段 rim：顶部镜面亮线（最亮）→ 上缘内侧柔光 → 左右侧壁 → 底部厚度暗边；
     填充降到 5% 之后，**玻璃的「存在感」几乎全靠这几条边**（否则会退化成看不见的灰雾）。 */
  --lg-rim:inset 0 2px 0 rgba(255,255,255,1), inset 0 34px 46px -30px rgba(255,255,255,.44),
           inset 0 -1.6px 0 rgba(255,255,255,.28), inset 1.6px 0 0 rgba(255,255,255,.30),
           inset -1.6px 0 0 rgba(255,255,255,.20), inset 0 0 52px -24px rgba(4,8,20,.66);
  /* 棱边色散：真玻璃边缘会分光，四边各错位 1.5px 的青/品红/蓝紫 */
  --lg-prism:inset 1.5px 0 0 rgba(112,214,255,.24), inset -1.5px 0 0 rgba(200,200,210,.20),
             inset 0 12px 16px -14px rgba(150,240,255,.30), inset 0 -12px 16px -14px rgba(190,160,255,.26);
  --lg-edge:0 0 0 1px rgba(0,0,0,.56);
  --lg-drop:0 2px 6px -1px rgba(0,0,0,.55), 0 16px 40px -18px rgba(0,0,0,.68), 0 40px 90px -36px rgba(0,0,0,.84), 0 10px 34px -24px rgba(56,140,255,.42);
  --lg-sheen:radial-gradient(126% 74% at 16% -8%,rgba(255,255,255,.92),transparent 56%);
  --lg-irid:radial-gradient(96% 62% at 88% 104%,rgba(90,255,220,.28),transparent 62%),
            radial-gradient(78% 56% at 104% 4%,rgba(150,132,255,.28),transparent 62%),
            radial-gradient(72% 50% at -6% 96%,rgba(96,196,255,.24),transparent 62%);
  /* 玻璃按钮的填充/模糊（比主面板更亮一档，读作「可点」） */
  --lg-btn-a:rgba(255,255,255,.12);
  --lg-btn-b:rgba(255,255,255,.030);
  --lg-btn-blur:blur(22px) saturate(200%);

  /* —— §20 应用外壳：左侧导航宽度 —— */
  --side-w:250px;

  /* =========================================================
     §20 图像面板的「玻璃装裱」（LENS FRAME）的令牌
     画面（canvas）面板没法用 backdrop-filter 做折射：画布每帧都在变，
     backdrop 位移折射会每帧全屏重算（见 --lg-blur-flat 的注释）。
     所以这里的「玻璃质量」全部落在**静态光学层**上，不参与每帧合成：
       ① 边缘四段：外暗环 → 外亮环（厚度）→ 落地影 + 冷环境反光 → 内侧薄亮环
       ② 内阴影：让画面读起来是「在玻璃后面」。没有它，画面就是一张贴纸。
       ③ 棱边色散：青/品红/紫在四边各错位 1.5px（真玻璃边缘会分光）
       ④ 斜向镜面掠光 + 四边折射环 + 磨砂微纹理（--grain）
     ========================================================= */
  --lens-out:0 0 0 1px rgba(0,0,0,.60), 0 0 0 3px rgba(255,255,255,.035);
  --lens-shadow:0 38px 88px -44px rgba(0,0,0,.90), 0 8px 24px -12px rgba(0,0,0,.62), 0 14px 40px -26px rgba(56,140,255,.34);
  --lens-in:inset 0 0 38px -6px rgba(4,8,20,.62);
  --lens-top:inset 0 2px 0 rgba(255,255,255,.36), inset 0 30px 44px -30px rgba(255,255,255,.22);
  --lens-prism:inset 1.5px 0 0 rgba(112,214,255,.17), inset -1.5px 0 0 rgba(200,200,210,.14),
               inset 0 12px 16px -14px rgba(150,240,255,.22), inset 0 -12px 16px -14px rgba(190,160,255,.18);
  --lens-glare:radial-gradient(52% 42% at 13% -8%,rgba(255,255,255,.15),rgba(255,255,255,.038) 40%,rgba(255,255,255,0) 74%),
               linear-gradient(0deg,rgba(150,230,255,.070) 0,rgba(0,0,0,0) 6px),
               linear-gradient(90deg,rgba(255,150,235,.055) 0,rgba(0,0,0,0) 6px),
               radial-gradient(120% 80% at 50% -10%,rgba(134,239,172,.09),transparent 62%);

  /* —— §21.11 滑块轨道（两端色 + 已填充色）——
     .scope / .video-preview / .cmp-canvas-wrap 内部另有同名「钉深色」的局部覆盖，
     因为那些面板**两个主题都不翻转**（见 §21.2）。 —— */
  --sld-a:rgba(255,255,255,.10);
  --sld-b:rgba(255,255,255,.30);
}


/* =========================================================
   1.1 TOKENS —— 浅色主题覆盖（与上面的 :root 逐条对应）
   只写「与 dark 不同」的值；未列出的变量由 :root 继承。
   ========================================================= */
[data-theme="light"]{
  /* —— Apple 风浅色底：#f5f5f7 近白 + 极淡灰光斑，避免紫灰 bias —— */
  --bg-base:#f5f5f7;
  --bg-grad-a:rgba(0,0,0,.04);
  --bg-grad-b:rgba(0,0,0,.02);
  --bg-grad-c:rgba(0,0,0,.03);
  --bg-grad-d:rgba(0,0,0,.01);
  /* 文字梯度：浅色基准（Apple 近黑 #1d1d1f） */
  --text:#1d1d1f;
  --text-2:rgba(29,29,31,.72);
  --text-3:rgba(29,29,31,.64);
  --text-4:rgba(29,29,31,.58);
  --tx:#1d1d1f;--tx-soft:rgba(29,29,31,.58);
  /* 玻璃与发丝：浅底上用黑灰描边，降低视觉噪点 */
  --glass-top:rgba(255,255,255,.70);
  --glass-bot:rgba(255,255,255,.32);
  --hair:rgba(0,0,0,.08);
  --hair-soft:rgba(0,0,0,.04);
  --accent:#15803D;
  --shadow-1:0 1px 0 rgba(255,255,255,.85) inset, 0 -1px 0 rgba(255,255,255,.3) inset,
             0 1px 2px rgba(10,11,26,.10),
             0 8px 20px -10px rgba(10,11,26,.16),
             0 34px 70px -30px rgba(10,11,26,.24);
  --shadow-glow:0 40px 100px -16px rgba(122,122,130,.20), 0 24px 60px -20px rgba(122,122,130,.10);

  /* =========================================================
     §19 液态玻璃的令牌（浅色）
     ========================================================= */
  /* 浅色底同样只留一层雾；可读性靠模糊与文字自身对比度，不靠白填充「糊住」背景 */
  --lg-fill-a-alpha:.20;
  --lg-fill-b-alpha:.07;
  --lg-blurpx:52px;
  --lg-fill-a:rgba(255,255,255,var(--lg-fill-a-alpha));
  --lg-fill-b:rgba(255,255,255,var(--lg-fill-b-alpha));
  --lg-blur:blur(var(--lg-blurpx)) saturate(190%) brightness(1.07);
  --lg-blur-flat:blur(var(--lg-blurpx)) saturate(190%) brightness(1.07);
  --lg-rim:inset 0 2px 0 rgba(255,255,255,1), inset 0 -1.6px 0 rgba(255,255,255,.72),
           inset 1.6px 0 0 rgba(255,255,255,.92), inset -1.6px 0 0 rgba(255,255,255,.72),
           inset 0 0 46px -22px rgba(28,22,70,.28);
  --lg-prism:inset 1.5px 0 0 rgba(150,150,160,.28), inset -1.5px 0 0 rgba(200,200,210,.24),
             inset 0 12px 16px -14px rgba(70,190,235,.30), inset 0 -12px 16px -14px rgba(140,110,215,.22);
  --lg-edge:0 0 0 1px rgba(28,22,70,.16);
  --lg-drop:0 1px 3px rgba(28,22,70,.08), 0 10px 24px -12px rgba(28,22,70,.16), 0 30px 62px -30px rgba(28,22,70,.30), 0 8px 26px -18px rgba(56,140,255,.20);
  --lg-sheen:radial-gradient(126% 74% at 16% -8%,rgba(255,255,255,1),transparent 58%);
  --lg-irid:radial-gradient(96% 62% at 88% 104%,rgba(64,220,190,.22),transparent 62%),
            radial-gradient(78% 56% at 104% 4%,rgba(140,120,255,.20),transparent 62%),
            radial-gradient(72% 50% at -6% 96%,rgba(90,180,255,.20),transparent 62%);
  --lg-btn-a:rgba(255,255,255,.58);
  --lg-btn-b:rgba(255,255,255,.26);
  --lg-btn-blur:blur(20px) saturate(180%);

  /* =========================================================
     §20 图像面板「玻璃装裱」的令牌（浅色）
     ========================================================= */
  --lens-out:0 0 0 1px rgba(28,22,70,.16), 0 0 0 3px rgba(255,255,255,.78);
  --lens-shadow:0 30px 68px -42px rgba(28,22,70,.36), 0 6px 18px -10px rgba(28,22,70,.20), 0 12px 32px -24px rgba(56,140,255,.22);
  --lens-in:inset 0 0 34px -8px rgba(28,22,70,.22);
  --lens-top:inset 0 2px 0 rgba(255,255,255,.95), inset 0 30px 44px -30px rgba(255,255,255,.75);
  --lens-prism:inset 1.5px 0 0 rgba(150,150,160,.22), inset -1.5px 0 0 rgba(200,200,210,.18),
               inset 0 12px 16px -14px rgba(70,190,235,.24), inset 0 -12px 16px -14px rgba(140,110,215,.17);
  --lens-glare:radial-gradient(52% 42% at 13% -8%,rgba(255,255,255,.70),rgba(255,255,255,.20) 40%,rgba(255,255,255,0) 74%),
               linear-gradient(0deg,rgba(120,200,255,.095) 0,rgba(0,0,0,0) 6px),
               linear-gradient(90deg,rgba(230,140,220,.085) 0,rgba(0,0,0,0) 6px),
               radial-gradient(120% 80% at 50% -10%,rgba(34,197,94,.07),transparent 62%);
  /* §21.1 浅底上的绿：--green-hi(#86EFAC) 是给深色底用的浅薄荷，
     浅色主题原先从未覆盖它，而它被当作**文字色**用了 21 处（.ai-bubble b /
     .goal-chip / .tag[data-s="ok"] / .view3d-stat b / .about-steps li b /
     .id-name .id-fr …）—— 在浅底上实测只有 1.1~1.9:1，等于隐形。
     #15803D 在玻璃面板上实测 4.49:1（贴着 4.5 的线）→ 再压暗一档
     **#14713A = 5.4:1**，留出余量。原来写在 §21.1 的覆盖块里，现并入此处。 */
  --green-hi:#14713A;
  --pink-hi:#BE123C;
  --tx:#0A0B1A;--tx-soft:rgba(10,11,26,.64);

  /* —— §21.11 滑块轨道（浅色）—— */
  --sld-a:rgba(10,11,26,.10);
  --sld-b:rgba(10,11,26,.26);
}


/* =========================================================
   2. RESET
   ========================================================= */
*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;padding:0}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%;scroll-behavior:smooth}
body{
  /* 字体栈（2026-09-18 修）：原来 'Inter' 排第一位，但本项目**零外部依赖、
     从不加载任何 Web 字体** → 这一位是死配置，只会让后面的回退判断绕一圈。
     改为系统字体优先，并补上原先缺失的 system-ui / Win11 的
     Segoe UI Variable；CJK 依次回退 PingFang(Apple) → HarmonyOS(华为)
     → 冬青/雅黑，避免中英混排时落到字形质量最差的那一档。 */
  font-family:-apple-system,BlinkMacSystemFont,system-ui,'SF Pro Display',
              'Segoe UI Variable Display','Segoe UI',Roboto,'Helvetica Neue',Arial,
              'PingFang SC','HarmonyOS Sans SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;
  font-feature-settings:'cv11','ss01';
  font-size:var(--fs-4);line-height:1.62;
  color:var(--text);background:var(--bg-base);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  min-height:100vh;min-height:100dvh;overflow-x:hidden;
  transition:background-color var(--dur-4) var(--ease-out-quart), color var(--dur-4) var(--ease-out-quart);
}
img,svg{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;padding:0}
input,textarea{font:inherit;color:inherit}
[hidden]{display:none !important}
::selection{background:rgba(122,122,130,.4);color:#fff}
/* 浅色主题：40% 粉叠在近白底上是浅粉高亮，白字对比度仅 ≈1.6:1（选中文字几乎隐形）。
   改深字浅粉底：#0A0B1A 落在合成后 ≈ rgb(237,184,211) 上实测 ≈9.5:1，达 AA。 */
[data-theme="light"] ::selection{background:rgba(219,39,119,.28);color:#0A0B1A}
.mono{font-family:'JetBrains Mono','SF Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
:focus-visible{outline:2px solid var(--apple-blue);outline-offset:3px;border-radius:var(--r-xs)}
/* 打印分页孤字控制：屏幕渲染零影响，仅导出 PDF / 打印报告时段落首末行不悬单字 */
p,li{orphans:2;widows:2}
.ic{width:20px;height:20px;flex:none}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.13);border-radius:var(--r-pill);border:2px solid transparent;-webkit-background-clip:padding-box;background-clip:padding-box}
[data-theme="light"] ::-webkit-scrollbar-thumb{background:rgba(10,11,26,.16)}
/* Firefox：::-webkit-* 不适用 Firefox。scrollbar-color/width 是可继承属性，
   :root 设一次即覆盖视口与全部滚动容器。取值与 webkit 侧同源
   （thumb 白/黑两档、track 透明），α 从 .13/.16 提到 .20/.24：
   Firefox thin 档拇指比 webkit 10px 细且无 2px 透明描边柔化，
   同 α 会偏暗，按感知重量补偿。 */
:root{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.20) transparent}
[data-theme="light"]{scrollbar-color:rgba(10,11,26,.24) transparent}
.side-scroll{scrollbar-width:none}                       /* 对齐 webkit 侧 width:0 */
.ai-chat-body{scrollbar-color:rgba(128,128,170,.3) transparent}   /* 对齐其 webkit 专属拇指色 */

/* =========================================================
   3. BACKGROUND
   ========================================================= */
.bg{position:fixed;inset:0;z-index:-1;pointer-events:none;overflow:hidden;background:var(--bg-base)}
/* ⚡ 性能记事：这里本来是「blur 与每帧变化的 transform 同处一个元素」的典型热点
   （scale 一变就要重算整块「视口 150% 大小」的模糊面，22s 不停）。已实测过把它
   改写成「filter 下沉到静态 ::before、动画只做合成层纹理变换」的方案：
   帧率无可分辨改善（见 .workbuddy/probe-perf.js 的 A/B 多次重复实验），
   但整片极光的渲染会出现约 2.6% 的亮度偏移 —— 收益为零却有视觉代价，
   因此保留原写法。想再试的话请先跑 probe-perf.js 拿到可分辨的收益再动。 */
/* ⚡ 背景主视觉照片层（2026-10-01 流畅性重构）：
   AI 生成的球馆光影照片（无水印）作为最底层的「有机纹理」。
   照片是静态位图 → GPU 纹理合成，零滤镜、零重绘、零动画成本 —— 这是 apple.com
   背景的做法：真实材质照片 + 上层薄渐变，而不是 CSS 大半径 blur 模拟氛围。
   照片自带暗部，::after 压一层纵向暗化渐变保住玻璃面板与文字的对比度。
   浅色主题不显示照片（保持原有近白底，避免暗照片+深字的对比度问题）。 */
.bg-photo{position:absolute;inset:0;
  background:url("../assets/bg-court.jpg") center 40% / cover no-repeat;
}
.bg-photo::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(5,8,20,.36) 0%,rgba(5,8,20,.62) 55%,rgba(5,8,20,.88) 100%);
}
[data-theme="light"] .bg-photo{display:none}
/* ⚡ 性能重构：blur(30px) 已移除。原来「blur 与每帧变化的 transform 同处一个元素」
   是典型热点（scale 一变就要重算整块 150% 视口的模糊面，22s 不停）。现在照片层
   已经提供有机氛围，极光只负责品牌色 tint —— radial-gradient 本身就是软边，
   无需 blur；inset 收回 0（不再需要 blur 外溢边距），动画只剩 transform = 合成层。
   opacity .72：让照片透出来，极光退为氛围而非主体。 */
.bg-grad{position:absolute;inset:0;opacity:.72;
  background:
    radial-gradient(42% 38% at 12% 6%, var(--bg-grad-a) 0%, transparent 64%),
    radial-gradient(38% 34% at 90% 10%, var(--bg-grad-b) 0%, transparent 64%),
    radial-gradient(50% 44% at 58% 100%, var(--bg-grad-c) 0%, transparent 64%),
    radial-gradient(36% 32% at 74% 52%, var(--bg-grad-d) 0%, transparent 66%);
  animation:auroraShift 22s ease-in-out infinite alternate;
}
@keyframes auroraShift{0%{transform:translate3d(0,0,0) scale(1)}100%{transform:translate3d(-3%,2%,0) scale(1.12)}}
.bg-grid{position:absolute;inset:0;opacity:.5;
  background-image:
    linear-gradient(rgba(255,255,255,.028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.028) 1px, transparent 1px);
  background-size:64px 64px;
  mask-image:radial-gradient(ellipse at 50% 24%, #000 26%, transparent 78%);
  -webkit-mask-image:radial-gradient(ellipse at 50% 24%, #000 26%, transparent 78%);
}
[data-theme="light"] .bg-grid{
  background-image:
    linear-gradient(rgba(10,11,26,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(10,11,26,.045) 1px, transparent 1px);
}
/* 3 个光球：无 filter + mix-blend-mode:screen + 无限 scale。
   ⚡ blur(80px) 已移除（2026-10-01）：3 个 560px 级光球每帧重算 80px 半径模糊是
   背景系统里最贵的一项；照片层接管氛围后，radial-gradient 的软边 + screen 混合
   已足够呈现「光晕叠在照片上」的效果。动画只剩 transform = 合成器推进。
   o3 原为 cyan，同 .bg-grad 的理由改走 violet：环境层只保留品牌主副色。
   ⚠️ 不透明度保持原值 .78 —— 见「背景极光 orb 勿削弱」的长期约定。 */
.bg-orb{position:absolute;border-radius:50%;opacity:.78;mix-blend-mode:screen}
.bg-orb.o1{width:560px;height:560px;left:-10%;top:2%;background:radial-gradient(circle,rgba(122,122,130,.62),transparent 66%);animation:orbFloat 19s var(--ease-out-quart) infinite alternate}
.bg-orb.o2{width:480px;height:480px;right:-8%;top:26%;background:radial-gradient(circle,rgba(122,122,130,.50),transparent 66%);animation:orbFloat 24s var(--ease-out-quart) 1.6s infinite alternate-reverse}
.bg-orb.o3{width:440px;height:440px;left:40%;bottom:-12%;background:radial-gradient(circle,rgba(122,122,130,.56),transparent 66%);animation:orbFloat 27s var(--ease-out-quart) .8s infinite alternate}
@keyframes orbFloat{0%{transform:translate3d(0,0,0) scale(1)}100%{transform:translate3d(6%,-8%,0) scale(1.18)}}

/* =========================================================
   4. GLASS SYSTEM
   ========================================================= */
.glass{
  position:relative;isolation:isolate;
  background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));
  border:1px solid var(--hair);
  box-shadow:var(--shadow-1);
}
.glass::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:.35;
  background-image:var(--noise);background-size:180px 180px;mix-blend-mode:overlay}
.glass::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,rgba(255,255,255,.20) 0%,rgba(255,255,255,0) 46%);
  opacity:.85;
}
/* .sheen-fx 已被 display:none 停用（见下方 .sheen-fx 规则），原来为「扫光」做的
   overflow:hidden 就成了纯粹的副作用：它会把**子面板的外阴影**整圈裁掉。
   实测（probe-clip.js）：.view3d / .canvas-wrap 都嵌在 .card.glass.sheen 里，
   外圈暗环+亮环+落地影 7px 采样 0 命中 —— 玻璃装裱只剩内侧那半套。
   改用 overflow:clip + overflow-clip-margin：仍裁掉越界 >16px 的内容（保住圆角），
   但允许子面板的外阴影正常溢出。不支持 overflow-clip-margin 的旧浏览器退回
   overflow:clip（等价于原来的 hidden），零回退风险。 */
.glass.sheen{overflow:clip;overflow-clip-margin:16px}
.glass.sheen > .sheen-fx{
  position:absolute;top:-60%;bottom:-60%;left:-60%;width:34%;z-index:0;pointer-events:none;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.30),transparent);
  transform:translateX(-160%) rotate(9deg);opacity:0;
  transition:transform 1.15s var(--ease-out-expo),opacity var(--dur-4) var(--ease-out-quart);
}
.glass.sheen:hover > .sheen-fx{transform:translateX(420%) rotate(9deg);opacity:1}
.glass.sheen > *{position:relative;z-index:1}

.card{border-radius:var(--r-lg);padding:clamp(20px,2.4vw,30px);transition:transform var(--dur-3) var(--ease-out-quart),box-shadow var(--dur-3),border-color var(--dur-3)}
.card:hover{transform:translateY(-6px);box-shadow:0 3px 8px -2px rgba(0,0,0,.5),0 20px 40px -16px rgba(0,0,0,.62),0 46px 90px -30px rgba(122,122,130,.32),0 0 0 1px rgba(170,170,180,.25) inset;border-color:rgba(170,170,180,.3)}
.card-md{border-radius:var(--r-lg);padding:clamp(18px,2vw,24px);transition:transform var(--dur-3) var(--ease-out-quart),box-shadow var(--dur-3),border-color var(--dur-3)}
.card-md:hover{transform:translateY(-4px);box-shadow:0 2px 6px -1px rgba(0,0,0,.45),0 14px 30px -12px rgba(0,0,0,.55),0 30px 60px -22px rgba(122,122,130,.24);border-color:rgba(170,170,180,.25)}
/* §47 浅色主题 hover：接触/体影改用蓝紫灰（#1C1646 系）而非纯黑 —— 浅底上纯黑
   近距接触影会发「脏」，低饱和深蓝灰保持同一 3D 抬升语义但更干净。 */
[data-theme="light"] .card:hover{box-shadow:0 2px 6px -1px rgba(28,22,70,.14),0 16px 36px -16px rgba(28,22,70,.22),0 46px 90px -30px rgba(122,122,130,.20),0 0 0 1px rgba(122,122,130,.22) inset}
[data-theme="light"] .card-md:hover{box-shadow:0 1px 4px -1px rgba(28,22,70,.12),0 12px 26px -12px rgba(28,22,70,.18),0 30px 60px -22px rgba(122,122,130,.16)}

/* =========================================================
   5. LAYOUT / TYPE
   ========================================================= */
.wrap{max-width:var(--max);margin:0 auto;padding:0 var(--gutter);position:relative}
section{position:relative;padding:var(--section-y) 0}
/* line-height 1.02 是「拉丁单行标题」的取值；本标题靠 <br> 强制断成两行，
   1.02 会让两行几乎相碰 —— 中文方块字在这种行距下尤其憋（下方另有
   [lang^="zh"] 的覆盖再放宽一档）。改 1.07 换取呼吸感，视觉上仍属展示级紧字距。 */
.h-display{font-weight:800;font-size:clamp(40px,6.8vw,84px);line-height:1.05;letter-spacing:-.038em;margin:0;text-wrap:balance}
.h-section{font-weight:700;font-size:clamp(28px,4.2vw,48px);line-height:1.08;letter-spacing:-.03em;margin:0;text-wrap:balance}
.gradient-text{background:var(--grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent}
.gradient-green{background:var(--grad-green);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent}
.lead{font-size:clamp(16px,1.4vw,18px);color:var(--text-2);line-height:1.72;text-wrap:balance}
/* 防孤字：CJK 长段落换行时容易在行尾落单一个字（如「…控制变量/法。」）。
   .lead（栏首短介，1-3 行）用 balance 均衡每行长度；普通段落用 pretty
   避免末行孤字（Chrome 117+，其余引擎忽略、自动回退默认断行，零风险） */
p{text-wrap:pretty}
.muted{color:var(--text-3);font-size:var(--fs-3)}
.eyebrow{
  display:inline-flex;align-items:center;gap:9px;
  font-family:'JetBrains Mono','SF Mono',ui-monospace,monospace;
  font-size:var(--fs-1);letter-spacing:.1em;text-transform:uppercase;color:var(--text-2);
  padding:7px 15px;border-radius:var(--r-pill);
  background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));
  border:1px solid var(--hair);
  backdrop-filter:blur(16px) saturate(170%);-webkit-backdrop-filter:blur(16px) saturate(170%);
}
/* box-shadow 的 spread 是非合成属性：2.4s 无限循环 ⇒ 每一帧都触发重绘，永不停歇。
   改用 ::after 光环做 transform:scale + opacity —— 两者只走合成层，完全不进重绘。
   几何换算：原 6px 圆点（半径 3）+ spread 11px ⇒ 半径 14 ⇒ scale = 14/3 ≈ 4.67。
   起点用 scale(0)（而非 1）是为了不遮住底下那颗实心绿点，与原效果一致。 */
/* ★ 2026-09-20 功能修复：原来只写了 .eyebrow .pulse，但页面里 .pulse 有 12 个使用者
   ——11 个在 .eyebrow 内（正常），第 12 个在 .stage-badge 内（「实时三维线框预览」徽标）。
   后者没有匹配到任何规则，无头实测渲染尺寸 0×0、border-radius 0px：
   内联 style 明明白白写了 background:var(--green) 与 box-shadow 光晕，
   却因为元素没有宽高而完全看不见 —— 那个徽标本该有的「实时绿点」一直是隐形的。
   现提升为独立组件：两种上下文共用同一条规则。
   flex:none 是必需的：两处父级（.eyebrow / .stage-badge）都是 flex 容器，
   不锁 flex-shrink 的话 6px 的点在窄容器里会被压扁。 */
.pulse{position:relative;width:6px;height:6px;flex:none;border-radius:50%;background:var(--green);box-shadow:var(--glow-led)}
.pulse::after{content:"";position:absolute;inset:0;border-radius:inherit;background:rgba(34,197,94,.55);animation:pulse 2.4s var(--ease-out-quart) infinite;will-change:transform,opacity}
@keyframes pulse{0%{transform:scale(0);opacity:.55}70%{transform:scale(4.67);opacity:0}100%{transform:scale(0);opacity:0}}
.section-head{max-width:780px;margin:0 auto clamp(40px,5vw,64px);text-align:center}
/* Apple 风：章节大标题收紧字距、加重，营造「大字号紧字距」的观感 */
.section-head :is(h2,h3){font-weight:700;letter-spacing:-.025em;line-height:1.12;text-wrap:balance}
.section-head .lead{margin:14px 0 0}

/* =========================================================
   6. BUTTONS
   ========================================================= */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  padding:14px 24px;border-radius:var(--r-pill);
  font-weight:640;font-size:var(--fs-3);letter-spacing:-.006em;white-space:nowrap;position:relative;overflow:hidden;
  transition:transform var(--dur-4) var(--ease-out-quart),box-shadow var(--dur-4) var(--ease-out-quart),opacity var(--dur-3),filter var(--dur-4);
}
.btn::before{
  content:"";position:absolute;inset:0;opacity:0;transition:opacity var(--dur-4) var(--ease-out-quart);
  background:radial-gradient(120% 160% at 50% 120%,rgba(255,255,255,.42),transparent 60%);
}
.btn:hover::before{opacity:1}
.btn > *{position:relative;z-index:1}
.btn-primary{color:#fff;background:var(--apple-blue);box-shadow:0 1px 2px rgba(0,0,0,.28),0 10px 24px -10px rgba(0,113,227,.55),0 0 0 1px rgba(255,255,255,.10) inset}
.btn-primary:hover{transform:translateY(-2px);background:#0077ED;box-shadow:0 2px 6px rgba(0,0,0,.32),0 16px 34px -12px rgba(0,113,227,.6),0 0 0 1px rgba(255,255,255,.14) inset}
.btn-primary:active{transform:translateY(0)}
/* Apple 风次按钮：透明底 + 当前色描边（Dark 白边 / Light 黑边），hover 微填充 */
.btn-ghost{color:var(--text);background:transparent;border:1px solid currentColor}
.btn-ghost:hover{transform:translateY(-2px);background:rgba(255,255,255,.06)}
[data-theme="light"] .btn-ghost:hover{background:rgba(0,0,0,.04)}
.btn-green{color:#04160A;background:var(--grad-green);box-shadow:0 2px 5px -1px rgba(0,0,0,.4),var(--glow-lift),0 0 0 1px rgba(255,255,255,.2) inset,0 1px 0 rgba(255,255,255,.5) inset}
.btn-green:hover{transform:translateY(-3px);box-shadow:var(--glow-lift-hi)}
.btn-icon{width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--r-pill);background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));border:1px solid var(--hair);color:var(--text-2);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);transition:color var(--dur-3),transform var(--dur-3),border-color var(--dur-3)}
.btn-icon:hover{color:var(--text);transform:translateY(-2px);border-color:rgba(122,122,130,.4)}
.btn[disabled]{opacity:.34;pointer-events:none;filter:grayscale(.5)}
.btn-sm{padding:11px 17px;font-size:var(--fs-3)}

/* =========================================================
   7. NAV
   ========================================================= */
.nav{position:fixed;top:0;left:0;right:0;z-index:var(--z-nav);pointer-events:none}
.nav-inner{
  pointer-events:auto;width:100%;
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:9px var(--gutter);
  border-radius:0;border:0;border-bottom:1px solid var(--hair-soft);
  background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));
  backdrop-filter:blur(24px) saturate(190%);-webkit-backdrop-filter:blur(24px) saturate(190%);
  box-shadow:0 1px 0 rgba(255,255,255,.10) inset;
  transition:background-color var(--dur-3) var(--ease-out-quart),box-shadow var(--dur-3) var(--ease-out-quart)
}
/* Apple 风：内容滚到栏下方时，顶栏收紧为更实的半透明 + 细发丝下边线（边缘到边缘） */
.nav-inner.is-scrolled{
  background-color:rgba(8,10,22,.62);background-image:none;
  box-shadow:0 1px 0 rgba(255,255,255,.10) inset,0 10px 30px -18px rgba(0,0,0,.7);
}
[data-theme="light"] .nav-inner.is-scrolled{
  background-color:rgba(255,255,255,.82);background-image:none;
  box-shadow:0 1px 0 rgba(0,0,0,.06) inset,0 10px 30px -18px rgba(0,0,0,.25);
}
.brand{display:flex;align-items:center;gap:11px;min-width:0}
.brand-mark{
  width:36px;height:36px;flex:none;display:grid;place-items:center;
  border-radius:var(--r-md);color:#F2711C;position:relative;
  background:linear-gradient(158deg,rgba(255,255,255,.11),rgba(255,255,255,.028));
  border:1px solid rgba(255,255,255,.15);
  box-shadow:0 10px 26px -10px rgba(242,113,28,.75),0 1px 0 rgba(255,255,255,.16) inset;
  animation:ballSpin 14s linear infinite;
}
[data-theme="light"] .brand-mark{
  background:linear-gradient(158deg,rgba(255,255,255,.96),rgba(240,236,252,.9));
  border-color:rgba(10,11,26,.12);
  box-shadow:0 10px 24px -12px rgba(242,113,28,.6),0 1px 0 rgba(255,255,255,.8) inset;
}
@keyframes ballSpin{0%{transform:translateY(0) rotate(0)}50%{transform:translateY(-3px) rotate(180deg)}100%{transform:translateY(0) rotate(360deg)}}
.brand-mark svg{width:26px;height:26px;display:block}
.brand-text{font-weight:700;font-size:var(--fs-3);letter-spacing:-.014em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex-shrink:0}
.brand-sub{display:block;font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.16em;color:var(--text-4);text-transform:uppercase;font-weight:500;margin-top:-2px}
.nav-right{display:flex;align-items:center;gap:8px;flex:none}
.lang-switch{display:flex;align-items:center;gap:2px;padding:3px;border-radius:var(--r-pill);background:rgba(255,255,255,.05);border:1px solid var(--hair-soft)}
.lang-btn{padding:7px 15px;border-radius:var(--r-pill);font-size:var(--fs-3);font-weight:640;color:var(--text-3);transition:color var(--dur-3),background-color var(--dur-3),box-shadow var(--dur-3)}
.lang-btn:hover{color:var(--text-2)}
.lang-btn[aria-pressed="true"]{color:#fff;background:var(--grad);box-shadow:0 8px 22px -8px rgba(122,122,130,.75)}
/* ---- Apple 式顶栏下拉（mega menu）：顶栏分组 → 全宽飞出面板 ---- */
.mega-nav{display:flex;align-items:center;gap:1px;flex:none}
.mega-top{
  position:relative;display:inline-flex;align-items:center;gap:5px;
  padding:9px 12px;border-radius:var(--r-pill);border:1px solid transparent;background:transparent;
  font-size:var(--fs-2);font-weight:620;color:var(--text-3);white-space:nowrap;
  transition:color var(--dur-3) var(--ease-out-quart),background-color var(--dur-3) var(--ease-out-quart)
}
.mega-top:hover{color:var(--text)}
.mega-top[aria-expanded="true"]{color:var(--text);background:rgba(255,255,255,.07)}
[data-theme="light"] .mega-top[aria-expanded="true"]{background:rgba(10,11,26,.055)}
.mega-top .chev{width:13px;height:13px;opacity:.55;transition:transform var(--dur-3) var(--ease-spring)}
.mega-top[aria-expanded="true"] .chev{transform:rotate(180deg);opacity:.9}
.mega-top::after{
  content:"";position:absolute;left:50%;bottom:2px;width:0;height:2px;border-radius:2px;
  background:var(--accent);transform:translateX(-50%);
  transition:width var(--dur-3) var(--ease-out-quart)
}
.mega-top[aria-expanded="true"]::after{width:15px}
/* 面板：挂在 .nav-inner 下全宽飞出 */
.nav-inner{position:relative}
.mega-panel{
  position:absolute;top:calc(100% + 10px);left:0;right:0;z-index:2;
  padding:clamp(16px,2vw,24px);border-radius:var(--r-lg);
  background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));
  background-color:rgba(9,11,22,.66);
  border:1px solid var(--hair);
  backdrop-filter:blur(34px) saturate(200%);-webkit-backdrop-filter:blur(34px) saturate(200%);
  box-shadow:var(--lg-rim),var(--lg-prism),var(--lg-edge),0 3px 8px -1px rgba(0,0,0,.5),0 20px 48px -20px rgba(0,0,0,.66),0 40px 90px -30px rgba(0,0,0,.72);
  transform-origin:top center;animation:megaIn .36s var(--ease-out-quart) both
}
.mega-panel[hidden]{display:none}
@keyframes megaIn{from{opacity:0;transform:translateY(-10px) scaleY(.965)}to{opacity:1;transform:none}}
.mega-pane[hidden]{display:none}
.mega-cap{
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.16em;text-transform:uppercase;
  color:var(--text-4);font-weight:500;margin:0 2px 12px
}
.mega-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px}
@media (max-width:1200px){.mega-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.mega-card{
  display:flex;align-items:center;gap:12px;width:100%;text-align:left;cursor:pointer;
  padding:12px 13px;border-radius:var(--r-md);border:1px solid transparent;
  transition:background-color var(--dur-3) var(--ease-out-quart),border-color var(--dur-3),transform var(--dur-3) var(--ease-out-quart)
}
.mega-card:hover{background:rgba(255,255,255,.07);border-color:var(--hair-soft);transform:translateY(-1px)}
[data-theme="light"] .mega-card:hover{background:rgba(10,11,26,.05)}
.mega-ico{
  flex:none;width:40px;height:40px;display:grid;place-items:center;border-radius:var(--r-md);
  color:var(--accent);background:rgba(34,197,94,.14);border:1px solid rgba(34,197,94,.26)
}
.mega-ico .ic{width:19px;height:19px}
.mega-txt{min-width:0;display:flex;flex-direction:column;gap:2px}
.mega-txt b{font-size:var(--fs-3);font-weight:660;color:var(--text);letter-spacing:-.01em}
.mega-txt i{font-style:normal;font-size:var(--fs-2);line-height:1.45;color:var(--text-3)}
.mega-arrow{
  flex:none;width:15px;height:15px;color:var(--text-4);opacity:0;transform:translateX(-4px);
  transition:opacity var(--dur-3),transform var(--dur-3) var(--ease-out-quart)
}
.mega-card:hover .mega-arrow{opacity:1;transform:none;color:var(--accent)}
/* 遮罩：聚焦下拉内容（点击外部即收起） */
.mega-scrim{
  position:fixed;inset:0;z-index:var(--z-mega-scrim);opacity:0;pointer-events:none;
  background:rgba(3,6,16,.44);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);
  transition:opacity var(--dur-3) var(--ease-out-quart)
}
.mega-scrim.on{opacity:1;pointer-events:auto}
[data-theme="light"] .mega-scrim{background:rgba(12,14,28,.24)}
[data-theme="light"] .mega-panel{background-color:rgba(252,252,255,.82)}
@media (prefers-reduced-motion: reduce){.mega-panel{animation:none}}
@media (max-width:1200px){
  .mega-top{padding:8px 9px;font-size:var(--fs-2)}
  #topCrumb{display:none}
  .search-input{width:150px}
  .search-input:focus{width:200px}
}
@media (max-width:1024px){.mega-nav,.mega-panel,.mega-scrim{display:none !important}}


/* =========================================================
   8. HERO
   ========================================================= */
.hero{padding-top:clamp(126px,15vw,180px);padding-bottom:clamp(46px,6vw,80px);text-align:center}
.hero-inner{max-width:960px;margin:0 auto}
.hero-title{margin:24px 0 0}
/* Apple 风 Hero：标题 plain 白/黑，不使用紫粉渐变字；eyebrow 改为简洁小字而非玻璃胶囊 */
.hero-title .gradient-text{background:none;-webkit-text-fill-color:var(--text);color:var(--text)}
.hero-inner .eyebrow{background:none;border:0;backdrop-filter:none;-webkit-backdrop-filter:none;padding:0;font-family:inherit;font-size:var(--fs-3);letter-spacing:.02em;text-transform:none;color:var(--text-3)}
.hero-sub{max-width:700px;margin:24px auto 0;font-size:clamp(16px,1.5vw,18px);color:var(--text-2);line-height:1.78}
.hero-cta{display:flex;gap:13px;justify-content:center;flex-wrap:wrap;margin-top:36px}
.hero-stats{display:flex;gap:clamp(18px,3vw,44px);justify-content:center;flex-wrap:wrap;margin-top:48px}
.stat{text-align:center}
/* 等宽字族本身字宽固定，-.04em 会让 "17 / 21 / 48f" 挤在一起；
   改 -.01em + tabular-nums（等宽数字，四格对齐）。
   光晕原来在 3.5s 里把 45% 不透明的紫光打到一组展示数字上，是「廉价霓虹感」的
   主要来源之一 —— 收到 22%，周期放慢到 4.6s，保留呼吸但不抢主体。 */
.stat b{display:block;font-family:'JetBrains Mono',monospace;font-size:clamp(24px,3vw,32px);font-weight:700;letter-spacing:-.01em;line-height:1.15;font-variant-numeric:tabular-nums}
.stat span{display:block;font-size:var(--fs-1);color:var(--text-3);letter-spacing:.06em;margin-top:5px;text-transform:uppercase}
/* ★ 2026-09-20 曾评估把 text-shadow 换成 filter:drop-shadow() —— 否决（见下方原记录）。
   ★ 2026-10-01 流畅性优化（对标 apple.com）：这里最终**直接移除**了 statPulse 动画。
   依据（实测，非推断）：
   1) text-shadow 压在 background-clip:text 的字形之下，逐像素测量振幅仅 0.0932 —— 肉眼几乎不可辨；
   2) 它却是全站唯一的「paint 属性 + 无限循环」动画，4 个 .stat b 常驻 iters=Infinity，
      每帧都要重绘这几个渐变文字，是滚动/空闲时 paint 型 jank 的来源之一；
   3) 「去霓虹感」是既定设计意图（§9 已把光晕从 45% 收到 22%），此动画本就该弱到近乎消失，
      直接移除与设计意图完全一致，零视觉回退。
   若日后要恢复「呼吸感」，正确载体是给 .stat b 加 position:relative + 伪元素 opacity 呼吸，
   而非回到 text-shadow（paint 属性）。 */
@keyframes statPulse{
  0%,100%{text-shadow:0 0 0 transparent}
  50%{text-shadow:0 0 16px rgba(170,170,180,.22),0 0 34px rgba(122,122,130,.09)}
}

/* Hero 3D 舞台 */
.hero-stage{margin-top:clamp(44px,6vw,72px);position:relative}
.hero-stage canvas{
  width:100%;height:clamp(340px,44vw,580px);display:block;border-radius:var(--r-xl);
}
.stage-shell{border-radius:var(--r-xl);overflow:hidden;position:relative}
.stage-shell::after{
  content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;
  box-shadow:0 0 0 1px var(--hair) inset,0 -60px 90px -60px rgba(255,255,255,.18) inset;
}
.stage-badge{
  position:absolute;left:18px;top:18px;z-index:3;display:flex;align-items:center;gap:8px;
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.1em;color:var(--green-hi);
  padding:7px 13px;border-radius:var(--r-pill);background:rgba(4,12,8,.5);border:1px solid rgba(34,197,94,.34);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
}
.stage-hud{
  position:absolute;right:18px;top:18px;z-index:3;text-align:right;
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);line-height:1.85;color:rgba(134,239,172,.72);
}
.stage-hud b{color:var(--green-hi);font-weight:600}

/* =========================================================
   9. UPLOAD
   ========================================================= */
.dropzone{
  position:relative;border-radius:var(--r-lg);
  border:1.5px dashed rgba(255,255,255,.18);
  background:linear-gradient(158deg,rgba(255,255,255,.055),rgba(255,255,255,.018));
  padding:clamp(32px,4.4vw,54px) 24px;text-align:center;cursor:pointer;
  transition:border-color var(--dur-4) var(--ease-out-quart),background-color var(--dur-4) var(--ease-out-quart),transform var(--dur-4) var(--ease-out-quart),box-shadow var(--dur-4) var(--ease-out-quart);
  overflow:hidden;
}
[data-theme="light"] .dropzone{border-color:rgba(10,11,26,.18)}
.dropzone::before{
  content:"";position:absolute;inset:-40%;pointer-events:none;opacity:0;
  background:radial-gradient(40% 50% at 50% 50%,rgba(122,122,130,.16),transparent 70%);
  transition:opacity var(--dur-4) var(--ease-out-quart);
}
.dropzone:hover{border-color:rgba(122,122,130,.6);transform:translateY(-3px);box-shadow:var(--shadow-glow)}
.dropzone:hover::before{opacity:1}
.dropzone.over{border-color:var(--apple-blue);transform:scale(1.008)}
.dropzone > *{position:relative}
.drop-icon{
  width:64px;height:64px;margin:0 auto 18px;border-radius:var(--r-ml);display:grid;place-items:center;color:#FF8A3D;
  background:radial-gradient(circle at 32% 28%,rgba(255,184,107,.34),rgba(242,113,28,.14));
  border:1px solid var(--hair);
  animation:floatY 4.4s var(--ease-out-quart) infinite alternate;
}
@keyframes floatY{0%{transform:translateY(0)}100%{transform:translateY(-7px)}}
.drop-title{font-weight:680;font-size:var(--fs-5);letter-spacing:-.012em}
.drop-hint{margin-top:11px;font-size:var(--fs-3);color:var(--text-3);line-height:1.7;max-width:580px;margin-left:auto;margin-right:auto}
/* 新手拍摄提示：三要点横排（窄屏纵排），弱化视觉、不抢主流程 */
.drop-tips{display:flex;flex-wrap:wrap;justify-content:center;gap:8px 20px;margin-top:18px;padding-top:16px;border-top:1px solid var(--hair-soft);max-width:620px;margin-left:auto;margin-right:auto}
.drop-tips .tip-item{display:inline-flex;align-items:center;gap:8px;font-size:var(--fs-2);color:var(--text-3);line-height:1.5}
.drop-tips .tip-num{display:inline-grid;place-items:center;width:20px;height:20px;flex:none;border-radius:var(--r-pill);
  font-size:11px;font-weight:700;color:var(--green-hi);
  background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));border:1px solid var(--hair-soft)}
.upload-actions{display:flex;gap:13px;justify-content:center;flex-wrap:wrap;margin-top:26px}

.video-preview{margin-top:22px;border-radius:var(--r-md);overflow:hidden;border:1px solid var(--hair);background:#05060f;display:flex;flex-wrap:wrap}
/* vp-stage：把 video 与叠加 canvas 锁在同一个定位上下文里。
   object-fit 必须用 contain（不能用 cover）—— cover 会裁切画面，
   而骨架是按视频**原始像素坐标**绘制的，裁切会导致骨架与真人错位。
   PoseOverlay.resize() 会把 canvas 的 CSS 宽高同步为 .vp-stage 的可见盒尺寸。 */
.vp-stage{position:relative;width:min(420px,100%);aspect-ratio:16/9;background:#05060f;flex:none}
.vp-stage video{width:100%;height:100%;object-fit:contain;background:#05060f;display:block}
.vp-overlay{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:2}
.vp-meta{padding:17px 20px;display:flex;flex-direction:column;gap:7px;justify-content:center;flex:1;min-width:0}
.vp-meta .mono{font-size:var(--fs-2);color:var(--text-3);word-break:break-all}
.vp-name{font-weight:640;font-size:var(--fs-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vp-tools{display:flex;gap:14px;flex-wrap:wrap;margin-top:6px;padding-top:10px;border-top:1px solid var(--hair-soft)}
.vp-toggle{display:flex;align-items:center;gap:7px;font-size:var(--fs-2);color:var(--text-2);cursor:pointer;user-select:none}
.vp-toggle input{width:15px;height:15px;accent-color:var(--apple-blue);cursor:pointer}

.acc{margin-top:20px;border-radius:var(--r-md);border:1px solid var(--hair);overflow:hidden}
.acc-head{width:100%;display:flex;align-items:center;gap:12px;padding:15px 18px;text-align:left;transition:background-color var(--dur-3)}
.acc-head:hover{background:rgba(255,255,255,.05)}
.acc-head .t{font-weight:640;font-size:var(--fs-3);flex:1;letter-spacing:-.008em}
.acc-head .chev{transition:transform var(--dur-4) var(--ease-out-quart);color:var(--text-3)}
.acc[data-open="true"] .acc-head .chev{transform:rotate(180deg)}
.acc-body{max-height:0;overflow:hidden;transition:max-height var(--dur-4) var(--ease-out-quart)}
.acc[data-open="true"] .acc-body{max-height:900px}
.acc-body > div{overflow:hidden}
.acc-inner{padding:0 18px 20px;display:flex;flex-direction:column;gap:14px}
.acc-desc{font-size:var(--fs-3);color:var(--text-3);line-height:1.72}
.field{display:flex;flex-direction:column;gap:7px}
.field label{font-size:var(--fs-2);color:var(--text-3)}
.field input{
  width:100%;padding:11px 14px;border-radius:var(--r-sm);
  background:rgba(255,255,255,.05);border:1px solid var(--hair);color:var(--text);
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-2);transition:border-color var(--dur-3),background-color var(--dur-3);
}
.field input:focus{outline:none;border-color:rgba(122,122,130,.6);background:rgba(255,255,255,.08)}
.status-pill{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border-radius:var(--r-pill);font-size:var(--fs-2);font-weight:640;border:1px solid var(--hair);background:rgba(255,255,255,.05)}
.status-pill .led{width:7px;height:7px;border-radius:50%;background:var(--text-4)}
.status-pill[data-state="api"] .led{background:var(--green);box-shadow:var(--glow-led)}
.status-pill[data-state="demo"] .led{background:var(--warn);box-shadow:0 0 10px rgba(251,191,36,.85)}

/* =========================================================
   10. PROGRESS
   ========================================================= */
/* —— Apple 风分析进程 / 进度 ——
   参考 Apple 进程语言：纯黑卡面、极细分隔、克制蓝色主进度、当前步高亮但不过度发光。
   动画一律走 transform/opacity（合成层），避免重绘，保证流畅度。 */
.prog{margin-top:24px;padding:26px;border-radius:var(--r-lg);border:1px solid var(--hair);background:rgba(255,255,255,.035);box-shadow:0 1px 0 rgba(255,255,255,.05) inset}
.prog-top{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:16px}
.prog-label{font-size:var(--fs-4);font-weight:600;letter-spacing:-.01em;display:flex;align-items:center;gap:10px;min-width:0;color:var(--text)}
.prog-label .spin{animation:spin 1.05s linear infinite;color:var(--apple-blue)}
@keyframes spin{to{transform:rotate(360deg)}}
.prog-pct{font-family:'SF Mono',ui-monospace,monospace;font-size:var(--fs-4);font-weight:600;color:var(--text-2);font-variant-numeric:tabular-nums;letter-spacing:-.01em}
/* 主进度条：细、圆角、Apple 蓝 + 前沿柔光（transform 动画，合成层） */
.bar{height:6px;border-radius:var(--r-pill);background:rgba(255,255,255,.10);overflow:hidden;position:relative}
.bar > i{display:block;height:100%;width:0%;border-radius:var(--r-pill);background:var(--apple-blue);position:relative;transition:width var(--dur-4) var(--ease-out-quart);will-change:width}
.bar > i::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,transparent,rgba(255,255,255,.5),transparent);animation:barFlow 1.6s linear infinite;will-change:transform}
@keyframes barFlow{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
/* 步骤条：Apple 式分段步进器 —— 圆点 + 标签，当前步粉色克制高亮 */
.steps{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-top:20px}
.step{display:flex;align-items:center;gap:8px;font-size:var(--fs-2);color:var(--text-4);transition:color var(--dur-4) var(--ease-out-quart)}
/* 属性表由配对状态反推：.step.active .pin 改 border-color/background/box-shadow，
   .step.done .pin 改 border-color/background/color。用 transition:all 会顺带
   监视 width/height/padding 这类布局属性，一旦将来有人在这里加状态就是一次重排。 */
.step .pin{width:20px;height:20px;border-radius:50%;border:1px solid var(--hair);display:grid;place-items:center;flex:none;background:rgba(255,255,255,.05);transition:border-color var(--dur-4) var(--ease-out-quart),background-color var(--dur-4) var(--ease-out-quart),color var(--dur-4) var(--ease-out-quart),box-shadow var(--dur-4) var(--ease-out-quart),transform var(--dur-4) var(--ease-out-quart)}
.step svg{width:11px;height:11px;opacity:0;transform:scale(.5);transition:opacity var(--dur-4) var(--ease-out-quart),transform var(--dur-4) var(--ease-out-quart)}
.step.active{color:var(--text)}
.step.active .pin{border-color:var(--pink);background:rgba(255,45,85,.16);box-shadow:0 0 0 4px rgba(255,45,85,.10);transform:scale(1.05)}
.step.done{color:var(--text-2)}
.step.done .pin{border-color:transparent;background:var(--green);color:#04140a}
.step.done svg{opacity:1;transform:scale(1)}
.step .lbl{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 浅色主题：进度轨道/未激活圆点需用黑低透明，否则白底上不可见 */
[data-theme="light"] .bar{background:rgba(0,0,0,.10)}
[data-theme="light"] .bar > i{box-shadow:0 0 0 1px rgba(0,113,227,.20)}
[data-theme="light"] .step .pin{background:rgba(0,0,0,.04);border-color:rgba(0,0,0,.14)}
[data-theme="light"] .prog{background:rgba(255,255,255,.72)}

/* =========================================================
   11. FRAME SCOPE / 逐帧视口
   ========================================================= */
.scope{border-radius:var(--r-xl);overflow:hidden;border:1px solid var(--hair);background:#0B0C16;position:relative}
.scope canvas{width:100%;height:auto;display:block}
.scope-hud{
  position:absolute;left:16px;top:16px;pointer-events:none;
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);line-height:1.9;color:rgba(134,239,172,.78);
  text-shadow:0 1px 4px rgba(0,0,0,.7);
}
.scope-hud b{color:var(--green-hi);font-weight:600}
.scope-corner{
  position:absolute;right:16px;top:16px;pointer-events:none;text-align:right;
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);line-height:1.9;color:rgba(255,255,255,.42);
}
.scope-bar{
  display:flex;align-items:center;gap:12px;padding:13px 16px;
  border-top:1px solid var(--hair);background:rgba(255,255,255,.035);
}
.timeline{flex:1;position:relative;height:34px;cursor:pointer}
.timeline-track{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);height:5px;border-radius:var(--r-xs);background:rgba(255,255,255,.1);overflow:hidden}
.timeline-fill{position:absolute;left:0;top:0;bottom:0;width:0%;background:var(--grad-green);border-radius:var(--r-xs);transition:width var(--dur-1) linear}
.timeline-wave{position:absolute;inset:0;display:flex;align-items:center;gap:1px;pointer-events:none;opacity:.65}
.timeline-wave i{flex:1;background:linear-gradient(180deg,rgba(134,239,172,.85),rgba(34,197,94,.25));border-radius:1px;min-height:3px}
.timeline-head{
  position:absolute;top:50%;left:0;width:3px;height:22px;margin-top:-11px;border-radius:2px;
  background:#fff;box-shadow:0 0 12px rgba(255,255,255,.9);transition:left var(--dur-1) linear;
}

/* =========================================================
   12. VIEW3D / 3D 线框查看器
   ========================================================= */
.view3d{border-radius:var(--r-xl);overflow:hidden;border:1px solid var(--hair);position:relative;background:
  linear-gradient(180deg,#0E1018 0%,#0A0B14 60%,#0E1018 100%)}
[data-theme="light"] .view3d{background:linear-gradient(180deg,#E9E6F5 0%,#DFDCEE 100%)}
.view3d canvas{width:100%;height:auto;display:block;cursor:grab}
.view3d canvas:active{cursor:grabbing}
.view3d canvas,.hero-stage canvas,.scope canvas{touch-action:none}
.view3d-tag{
  position:absolute;left:16px;top:16px;pointer-events:none;
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.11em;
  color:var(--green-hi);padding:6px 12px;border-radius:var(--r-pill);
  background:rgba(4,12,8,.46);border:1px solid rgba(34,197,94,.32);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
}
.view3d-stat{
  position:absolute;right:16px;top:16px;pointer-events:none;text-align:right;
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);line-height:1.9;color:rgba(134,239,172,.72);
}
.view3d-stat b{color:var(--green-hi)}
.view3d-foot{display:flex;gap:10px;align-items:center;justify-content:space-between;flex-wrap:wrap;padding:13px 16px;border-top:1px solid var(--hair);background:rgba(255,255,255,.035)}
/* 全屏预览：建模视图与逐帧视口放大，画布按容器自适应分辨率 */
.view3d:fullscreen, .scope:fullscreen{
  display:flex;flex-direction:column;width:100vw;height:100vh;max-width:none;border-radius:0;overflow:hidden;
  background:linear-gradient(180deg,#0E1018 0%,#0A0B14 60%,#0E1018 100%);
}
[data-theme="light"] .view3d:fullscreen, [data-theme="light"] .scope:fullscreen{
  background:linear-gradient(180deg,#E9E6F5 0%,#DFDCEE 100%);
}
.view3d:fullscreen canvas, .scope:fullscreen canvas{
  flex:1 1 0;min-height:0;width:100%;height:100%;object-fit:contain;display:block;
}
.view3d:fullscreen .view3d-foot, .scope:fullscreen .scope-bar{ flex:0 0 auto; }
.view3d:fullscreen .view3d-tag, .view3d:fullscreen .view3d-stat,
.scope:fullscreen .scope-hud, .scope:fullscreen .scope-corner{ font-size:var(--fs-2); }
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:26px}

/* =========================================================
   12b. 控制坞（缩放 / 慢放 / 全屏）与高级质感
   ========================================================= */
.ctl-dock{
  position:absolute;right:16px;bottom:16px;z-index:6;display:flex;align-items:center;gap:7px;
  padding:6px 7px;border-radius:var(--r-pill);
  background:linear-gradient(180deg,rgba(22,26,44,.74),rgba(9,11,22,.7));
  border:1px solid rgba(255,255,255,.14);
  backdrop-filter:blur(18px) saturate(150%);-webkit-backdrop-filter:blur(18px) saturate(150%);
  box-shadow:0 18px 44px -18px rgba(0,0,0,.88),0 1px 0 rgba(255,255,255,.06) inset,0 0 0 1px rgba(34,197,94,.05);
  transition:opacity var(--dur-3) var(--ease-out-quart),transform var(--dur-3) var(--ease-out-quart);
}
[data-theme="light"] .ctl-dock{
  background:linear-gradient(180deg,rgba(255,255,255,.94),rgba(243,241,253,.9));
  border-color:rgba(10,11,26,.12);
  box-shadow:0 16px 40px -18px rgba(60,50,120,.4),0 1px 0 rgba(255,255,255,.7) inset;
}
.ctl-dock.is-hidden{opacity:0;transform:translateY(6px);pointer-events:none}
/* 全屏态：隐藏周围 UI，让画布独占视口 */
.v3d-stage.is-fullscreen{position:fixed;inset:0;z-index:var(--z-float);background:var(--bg);padding:0}
.v3d-stage.is-fullscreen canvas{width:100%;height:100%}
.v3d-stage.is-fullscreen .ctl-dock{right:max(16px,env(safe-area-inset-right));bottom:max(16px,env(safe-area-inset-bottom))}
.ai-chat.is-fullscreen{position:fixed;inset:0;z-index:var(--z-float);max-width:none;border-radius:0}
.ai-chat.is-fullscreen .ai-chat-body{max-height:none}
.ctl-btn{
  width:30px;height:30px;border-radius:var(--r-pill);display:grid;place-items:center;cursor:pointer;flex:0 0 auto;
  border:1px solid transparent;background:rgba(255,255,255,.055);color:var(--text-2);
  transition:background var(--dur-2) var(--ease-out-quart),color var(--dur-2) var(--ease-out-quart),transform var(--dur-2) var(--ease-out-quart),box-shadow var(--dur-2) var(--ease-out-quart);
}
[data-theme="light"] .ctl-btn{background:rgba(10,11,26,.05)}
.ctl-btn:hover{background:rgba(34,197,94,.2);color:var(--green-hi);transform:translateY(-1px);box-shadow:var(--glow-chip-hi)}
.ctl-btn:active{transform:translateY(0) scale(.93)}
.ctl-btn:focus-visible{outline:2px solid var(--green-hi);outline-offset:2px}
/* —— 青少年训练激励条 / 下次要改目标（围绕青少年） —— */
.youth-strip{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:16px;padding:10px 14px;border-radius:var(--r-ml);
  background:linear-gradient(158deg,var(--lg-btn-a),var(--lg-btn-b));border:1px solid var(--hair);
  backdrop-filter:var(--lg-btn-blur);-webkit-backdrop-filter:var(--lg-btn-blur)}
.youth-peer{display:flex;align-items:center;gap:8px;font-size:var(--fs-2);color:var(--text-2)}
.youth-peer .medal{width:26px;height:26px;border-radius:var(--r-pill);display:grid;place-items:center;flex:0 0 auto;
  background:linear-gradient(145deg,#fbbf24,#f59e0b);color:#3b2500;font-weight:800;font-size:var(--fs-2);box-shadow:0 6px 14px -6px rgba(245,158,11,.8)}
.youth-peer b{color:var(--green-hi);font-weight:800}
.youth-encourage{font-size:var(--fs-3);font-weight:600;color:var(--text-1);line-height:1.5}
.goal-chip{display:inline-flex;align-items:center;gap:8px;margin-left:auto;padding:8px 14px;border-radius:var(--r-pill);cursor:pointer;
  background:linear-gradient(158deg,var(--lg-btn-a),var(--lg-btn-b));border:1px solid var(--hair);color:var(--text-2);
  font-size:var(--fs-2);font-weight:600;transition:border-color var(--dur-2),color var(--dur-2),transform var(--dur-2)}
.goal-chip:hover{border-color:var(--green-hi);color:var(--green-hi);transform:translateY(-1px)}
.goal-chip.on{border-color:var(--green-hi);color:var(--green-hi);background:rgba(34,197,94,.12)}
.goal-chip .tick{color:var(--green-hi);font-weight:800}
.ctl-btn svg{width:15px;height:15px;display:block}
.ctl-zoom-val{
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.03em;min-width:40px;text-align:center;
  color:var(--green-hi);-webkit-user-select:none;user-select:none;
}
.ctl-sep{width:1px;height:18px;background:rgba(255,255,255,.13);flex:0 0 auto}
[data-theme="light"] .ctl-sep{background:rgba(10,11,26,.12)}

/* ===================== AI 篮球助手对话面板 ===================== */
.ai-chat{
  position:fixed;z-index:var(--z-chat);top:14px;right:14px;bottom:14px;width:min(420px,calc(100vw - 28px));
  display:flex;flex-direction:column;border-radius:var(--r-xl);overflow:hidden;
  border:1px solid var(--hair);background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));
  box-shadow:0 3px 8px -1px rgba(0,0,0,.5),0 24px 60px -28px rgba(0,0,0,.68),0 60px 130px -44px rgba(0,0,0,.72),0 0 0 1px rgba(170,170,180,.12) inset;
  -webkit-backdrop-filter:blur(34px) saturate(190%);backdrop-filter:blur(34px) saturate(190%);
  transform:translateX(calc(100% + 28px));opacity:0;
  transition:transform var(--dur-4) var(--ease-out-quart),opacity var(--dur-3) ease;
}
.ai-chat.open{transform:none;opacity:1}
[data-theme="light"] .ai-chat{box-shadow:0 1px 3px rgba(28,22,70,.08),0 14px 34px -20px rgba(28,22,70,.24),0 40px 100px -40px rgba(60,40,120,.34),0 0 0 1px rgba(122,122,130,.12) inset}
.ai-chat-head{display:flex;align-items:center;gap:11px;padding:15px 16px;border-bottom:1px solid var(--hair);
  background:linear-gradient(150deg,rgba(122,122,130,.16),rgba(122,122,130,.08) 60%,rgba(122,122,130,.07));}
.ai-ava{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;flex:none;color:#fff;
  background:linear-gradient(140deg,#7A7A82,#7A7A82);box-shadow:0 0 18px rgba(122,122,130,.5)}
.ai-ava svg{width:20px;height:20px}
.ai-head-txt{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.25}
.ai-head-txt b{font-size:var(--fs-3);font-weight:700;letter-spacing:-.01em}
.ai-head-txt .sub{font-size:var(--fs-1);color:var(--text-3);letter-spacing:.04em}
.ai-chat-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;scroll-behavior:smooth}
.ai-chat-body::-webkit-scrollbar{width:8px}
.ai-chat-body::-webkit-scrollbar-thumb{background:rgba(128,128,170,.3);border-radius:var(--r-xs)}
.ai-msg{display:flex;gap:9px;max-width:88%}
.ai-msg .av{width:26px;height:26px;border-radius:50%;flex:none;display:grid;place-items:center;font-size:var(--fs-2);font-weight:800}
.ai-msg.user{flex-direction:row-reverse;align-self:flex-end}
.ai-msg.user .av{background:rgba(34,197,94,.22);color:var(--green-hi);border:1px solid rgba(34,197,94,.4)}
.ai-msg.bot .av{background:linear-gradient(140deg,#7A7A82,#7A7A82);color:#fff}
.ai-bubble{padding:10px 13px;border-radius:var(--r-md);font-size:var(--fs-3);line-height:1.65;word-break:break-word}
.ai-msg.bot .ai-bubble{background:rgba(128,128,170,.12);border:1px solid var(--hair);border-top-left-radius:5px;color:var(--text)}
.ai-msg.user .ai-bubble{background:linear-gradient(140deg,rgba(255,45,85,.30),rgba(255,45,85,.20));border:1px solid rgba(255,45,85,.40);border-top-right-radius:5px;color:#fff}
.ai-bubble p{margin:0 0 7px}
.ai-bubble p:last-child{margin:0}
.ai-bubble b{color:var(--green-hi)}
.ai-bubble ul{margin:6px 0 4px;padding-left:18px}
.ai-bubble li{margin:3px 0}
.ai-typing{display:inline-flex;gap:4px;align-items:center;padding:4px 2px}
.ai-typing i{width:6px;height:6px;border-radius:50%;background:var(--text-3);animation:aiBlink 1.1s infinite}
.ai-typing i:nth-child(2){animation-delay:.18s}
.ai-typing i:nth-child(3){animation-delay:.36s}
@keyframes aiBlink{0%,60%,100%{opacity:.25;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}}
.ai-quick{display:flex;gap:7px;flex-wrap:wrap;padding:0 14px 8px}
.ai-quick .chip{font-size:var(--fs-1);padding:5px 10px;cursor:pointer;border:1px solid var(--hair);border-radius:var(--r-pill);
  background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));color:var(--text-2);transition:color var(--dur-2),border-color var(--dur-2),transform var(--dur-2)}
.ai-quick .chip:hover{color:var(--text);border-color:rgba(122,122,130,.4);transform:translateY(-1px)}
.ai-chat-actions{display:flex;gap:7px;padding:6px 14px 10px;border-top:1px solid var(--hair)}
.ai-chat-actions .chip{flex:1;font-size:var(--fs-1);padding:7px 6px;text-align:center;justify-content:center;cursor:pointer;
  border:1px solid var(--hair);border-radius:var(--r-pill);background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));color:var(--text-2);transition:color var(--dur-2),border-color var(--dur-2),transform var(--dur-2)}
.ai-chat-actions .chip:hover{color:var(--text);border-color:rgba(170,170,180,.4);transform:translateY(-1px)}
.ai-chat-input{display:flex;gap:8px;align-items:flex-end;padding:10px 14px 14px;border-top:1px solid var(--hair)}
.ai-chat-input textarea{flex:1;resize:none;max-height:120px;min-height:40px;padding:10px 13px;border-radius:var(--r-md);font-family:inherit;font-size:var(--fs-3);
  color:var(--text);background-image:linear-gradient(180deg,rgba(255,255,255,.05),rgba(255,255,255,.02));
  border:1px solid var(--hair);outline:none;line-height:1.5}
[data-theme="light"] .ai-chat-input textarea{background-image:linear-gradient(180deg,rgba(255,255,255,.9),rgba(255,255,255,.62))}
.ai-chat-input textarea:focus{border-color:rgba(122,122,130,.5)}
.ai-chat-input .btn{padding:10px 13px;align-self:stretch}
@media(max-width:560px){.ai-chat{top:0;right:0;bottom:0;width:100%;border-radius:0}}

/* AI 助手个性化设置 */
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.fld{display:flex;flex-direction:column;gap:7px;font-size:var(--fs-2);color:var(--text-2)}
.fld input{width:100%;padding:10px 12px;border-radius:var(--r-md);font-family:inherit;font-size:var(--fs-3);color:var(--text);
  background-image:linear-gradient(180deg,rgba(255,255,255,.05),rgba(255,255,255,.02));border:1px solid var(--hair);outline:none}
[data-theme="light"] .fld input{background-image:linear-gradient(180deg,rgba(255,255,255,.9),rgba(255,255,255,.62))}
.fld input:focus{border-color:rgba(122,122,130,.5)}
.pill-row{display:flex;gap:8px;flex-wrap:wrap}
.pill{padding:7px 13px;border-radius:var(--r-pill);font-size:var(--fs-2);cursor:pointer;border:1px solid var(--hair);
  background:rgba(128,128,170,.06);color:var(--text-2);transition:background-color var(--dur-2) var(--ease-out-quart),background-image var(--dur-2) var(--ease-out-quart),border-color var(--dur-2) var(--ease-out-quart),color var(--dur-2) var(--ease-out-quart)}
.pill:hover{border-color:rgba(170,170,180,.4);color:var(--text)}
.pill.on{background:linear-gradient(140deg,rgba(122,122,130,.32),rgba(122,122,130,.26));border-color:rgba(122,122,130,.5);color:#fff}
.ai-profile-note{margin:16px 0 0;font-size:var(--fs-2);color:var(--text-3);line-height:1.6}
.speed-seg,.mode-seg{display:flex;gap:2px;padding:3px;border-radius:var(--r-pill);background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.08);flex:0 0 auto}
[data-theme="light"] .speed-seg,[data-theme="light"] .mode-seg{background:rgba(10,11,26,.05);border-color:rgba(10,11,26,.1)}
.speed-seg button,.mode-seg button{
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.02em;padding:4px 8px;border-radius:var(--r-pill);
  background:transparent;color:var(--text-3);cursor:pointer;border:0;line-height:1;
  transition:background var(--dur-2) var(--ease-out-quart),color var(--dur-2) var(--ease-out-quart);
}
.speed-seg button:hover{color:var(--text-1)}
.speed-seg button.on{background:var(--grad-green);color:#04140a;font-weight:800;box-shadow:0 6px 16px -8px rgba(34,197,94,.9)}
/* 视角预设：正面 / 侧面 / 俯视，与 speed-seg 同款胶囊 */
.view-seg{display:flex;gap:2px;padding:3px;border-radius:var(--r-pill);background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.08);flex:0 0 auto}
[data-theme="light"] .view-seg{background:rgba(10,11,26,.05);border-color:rgba(10,11,26,.1)}
.view-seg button{
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.02em;padding:4px 8px;border-radius:var(--r-pill);
  background:transparent;color:var(--text-3);cursor:pointer;border:0;line-height:1;
  transition:background var(--dur-2) var(--ease-out-quart),color var(--dur-2) var(--ease-out-quart);
}
.view-seg button:hover{color:var(--text-1)}
.view-seg button.on{background:var(--grad-green);color:#04140a;font-weight:800;box-shadow:0 6px 16px -8px rgba(34,197,94,.9)}

/* 高级质感：舞台 / 建模视图的内发光与描边层次 */
.hero-stage .stage-shell{
  box-shadow:0 3px 8px -1px rgba(0,0,0,.45),0 24px 60px -26px rgba(0,0,0,.6),0 40px 120px -60px rgba(122,122,130,.75),0 0 0 1px var(--hair) inset,0 1px 0 rgba(255,255,255,.06);
}
/* 注意：这层绿色顶部辉光已被下面 section 20 的 --lens-glare 第 4 层
   （radial-gradient(120% 80% at 50% -10%, rgba(134,239,172,.09), …)）等价覆盖，
   此处不再重复叠加，避免顶边叠加两次绿光发「奶」。
   保留原规则文本会误导后续维护，故删除。 */
.view3d{
  box-shadow:0 3px 8px -1px rgba(0,0,0,.42),0 18px 44px -22px rgba(0,0,0,.5),0 30px 80px -46px rgba(34,197,94,.5),0 0 0 1px var(--hair) inset;
}
/* 同上一处：绿色顶部辉光已由 section 20 的 --lens-glare 承担，去掉重复层。 */
.view3d canvas{position:relative;z-index:1}
.view3d-tag,.view3d-stat,.ctl-dock{z-index:6}
/* 画布+控制坞的定位容器 */
.v3d-stage{position:relative;display:block}
.v3d-stage > canvas{display:block;width:100%;height:auto}
/* 真 3D 层（WebGL）铺在 2D 叠加层之下：叠加层只画轨迹/标注，背景透明 */
.v3d-stage > canvas.gl3d-under{position:absolute;inset:0;width:100%;height:100%;z-index:0;pointer-events:none}
.v3d-stage > canvas.gl3d-over{position:relative;z-index:1}
/* 3D 取景「影棚化」：GL 画布清屏为透明，露出这层渐变背景；再用 inset 阴影做暗角。
   比原来的纯色底更有纵深，也不增加任何渲染开销。 */
.v3d-stage{background:radial-gradient(125% 95% at 50% 6%,#1c2542 0%,#0e1526 44%,#080b14 100%)}
[data-theme="light"] .v3d-stage{background:radial-gradient(125% 95% at 50% 6%,#ffffff 0%,#eef1f9 46%,#e1e6f3 100%)}
/* 可操作性：舞台操作提示（低干扰、可点击查看快捷键）—— 用户不知道画布能拖/能滚/能逐帧 */
.stage-hint{
  position:absolute;left:12px;bottom:12px;z-index:4;
  display:inline-flex;align-items:center;gap:7px;flex-wrap:wrap;
  padding:5px 11px;border-radius:var(--r-pill);
  font-size:var(--fs-1);line-height:1.5;color:var(--text-3);letter-spacing:.01em;
  background:rgba(10,14,24,.44);border:1px solid var(--hair);
  backdrop-filter:blur(10px) saturate(150%);-webkit-backdrop-filter:blur(10px) saturate(150%);
  cursor:pointer;pointer-events:auto;max-width:calc(100% - 24px);
  transition:color .25s var(--ease-out-quart),background .25s var(--ease-out-quart),transform .3s var(--ease-spring);
}
.stage-hint:hover{color:var(--text-2);background:rgba(10,14,24,.62);transform:translateY(-1px)}
[data-theme="light"] .stage-hint{background:rgba(255,255,255,.74);border-color:rgba(10,11,26,.13);color:var(--text-2)}
[data-theme="light"] .stage-hint:hover{background:rgba(255,255,255,.9)}
.stage-hint kbd{
  font-family:'JetBrains Mono',monospace;font-size:.92em;padding:0 4px;border-radius:4px;line-height:1.35;
  background:rgba(255,255,255,.15);border:1px solid var(--hair);color:var(--text-2);
}
[data-theme="light"] .stage-hint kbd{background:rgba(10,11,26,.07)}
@media (max-width:640px){
  .stage-hint{left:8px;bottom:8px;font-size:10px;padding:4px 9px;gap:5px}
}
.v3d-stage > canvas.gl3d-under{box-shadow:inset 0 0 130px 48px rgba(0,0,0,.52)}
[data-theme="light"] .v3d-stage > canvas.gl3d-under{box-shadow:inset 0 0 130px 48px rgba(38,32,80,.15)}
/* Hero 舞台全屏 */
.hero-stage:fullscreen,.hero-stage:-webkit-full-screen{
  display:flex;flex-direction:column;width:100vw;height:100vh;margin:0;max-width:none;
  background:linear-gradient(180deg,#0E1018 0%,#0A0B14 60%,#0E1018 100%);
}
[data-theme="light"] .hero-stage:fullscreen,[data-theme="light"] .hero-stage:-webkit-full-screen{
  background:linear-gradient(180deg,#E9E6F5 0%,#DFDCEE 100%);
}
.hero-stage:fullscreen .stage-shell,.hero-stage:-webkit-full-screen .stage-shell{
  flex:1 1 0;min-height:0;border-radius:0;display:flex;flex-direction:column;
}
.hero-stage:fullscreen canvas,.hero-stage:-webkit-full-screen canvas{
  flex:1 1 0;min-height:0;width:100%;height:100%;object-fit:contain;border-radius:0;
}
.view3d:fullscreen .v3d-stage,.scope:fullscreen .v3d-stage{flex:1 1 0;min-height:0;position:relative}
/* 拖拽平移时的手型 */
.view3d.panning canvas,.hero-stage.panning canvas{cursor:grabbing}
@media (max-width:640px){
  .ctl-dock{gap:5px;padding:5px;right:10px;bottom:10px;transform:scale(.94);transform-origin:bottom right}
  .ctl-zoom-val{min-width:34px;font-size:var(--fs-1)}
  .speed-seg button{padding:3px 6px}
}

/* =========================================================
   13. RESULTS
   ========================================================= */
.result-block{display:grid;gap:22px}
.score-grid{display:grid;grid-template-columns:230px 1fr;gap:clamp(20px,3vw,40px);align-items:center}
.ring-wrap{position:relative;width:200px;height:200px;margin:0 auto}
.ring-wrap > svg:last-of-type{position:absolute;inset:0;transform:rotate(-90deg)}
.ring-center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px}
.ring-num{font-family:'JetBrains Mono',monospace;font-size:var(--fs-9);font-weight:700;letter-spacing:-.045em;line-height:1}
.ring-num small{font-size:var(--fs-3);color:var(--text-3);font-weight:500}
.grade{display:inline-flex;align-items:center;gap:9px;padding:7px 16px;border-radius:var(--r-pill);font-weight:660;font-size:var(--fs-3);border:1px solid var(--hair);background:rgba(255,255,255,.05)}
.grade .led{width:8px;height:8px;border-radius:50%}
.grade[data-level="good"] .led{background:var(--green)}
.grade[data-level="great"] .led{background:var(--cyan)}
.grade[data-level="work"] .led{background:var(--warn)}
.score-side{display:flex;flex-direction:column;gap:15px}
.score-side p{margin:0;color:var(--text-2);font-size:var(--fs-3);line-height:1.75}
.chip-row{display:flex;gap:9px;flex-wrap:wrap}
.chip{font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);padding:6px 12px;border-radius:var(--r-pill);border:1px solid var(--hair);background:rgba(255,255,255,.045);color:var(--text-3)}
.chip b{color:var(--text);font-weight:600}

.angles{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}
.angle{padding:19px;border-radius:var(--r-md);border:1px solid var(--hair-soft);background:rgba(255,255,255,.032);transition:transform var(--dur-4) var(--ease-out-quart),border-color var(--dur-4),box-shadow var(--dur-4);position:relative;overflow:hidden}
.angle:hover{transform:translateY(-4px);border-color:var(--hair);box-shadow:0 20px 44px -18px rgba(0,0,0,.6)}
.angle-top{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.angle-name{font-size:var(--fs-3);font-weight:640;letter-spacing:-.007em}
.angle-sub{font-size:var(--fs-1);color:var(--text-4);margin-top:4px;font-family:'JetBrains Mono',monospace;letter-spacing:.06em}
.angle-val{font-family:'JetBrains Mono',monospace;font-size:var(--fs-7);font-weight:700;letter-spacing:-.035em;line-height:1}
.angle-val small{font-size:var(--fs-3);color:var(--text-3);font-weight:500}
.angle-track{margin-top:15px;height:7px;border-radius:var(--r-pill);background:rgba(255,255,255,.07);position:relative;overflow:hidden}
.angle-track .zone{position:absolute;top:0;bottom:0;background:rgba(34,197,94,.26);border-radius:var(--r-pill)}
.angle-track .fill{position:absolute;top:0;bottom:0;border-radius:var(--r-pill);background:var(--grad-cyan);box-shadow:0 0 12px rgba(122,122,130,.5);transition:width .9s var(--ease-out-quart)}
.angle-foot{display:flex;justify-content:space-between;align-items:center;margin-top:10px;font-size:var(--fs-1);color:var(--text-3)}
.tag{display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:var(--r-pill);font-size:var(--fs-1);font-weight:660;border:1px solid var(--hair)}
.tag[data-s="ok"]{color:var(--green-hi);border-color:rgba(34,197,94,.36);background:rgba(34,197,94,.12)}
.tag[data-s="low"]{color:var(--warn);border-color:rgba(251,191,36,.34);background:rgba(251,191,36,.12)}
.tag[data-s="high"]{color:#FF6482;border-color:rgba(255,45,85,.34);background:rgba(255,45,85,.12)}

/* position:relative 必需：下面的 .canvas-wrap::before（玻璃掠光层）用 inset:0 绝对定位，
   没有定位祖先时会逃逸到最近的定位祖先，把掠光糊到整块卡片上 */
.canvas-wrap{position:relative;border-radius:var(--r-md);border:1px solid var(--hair-soft);overflow:hidden;background:linear-gradient(180deg,rgba(122,122,130,.07),rgba(122,122,130,.05))}
.canvas-wrap canvas{width:100%;height:auto;display:block}
.canvas-legend{display:flex;gap:20px;flex-wrap:wrap;padding:13px 17px;border-top:1px solid var(--hair-soft);font-size:var(--fs-2);color:var(--text-3)}
.canvas-legend span{display:inline-flex;align-items:center;gap:8px}
.legend-dot{width:9px;height:9px;border-radius:50%}

.list{display:flex;flex-direction:column;gap:13px;margin:0;padding:0;list-style:none}
.list li{display:flex;gap:13px;align-items:flex-start;font-size:var(--fs-3);color:var(--text-2);line-height:1.72}
.list .n{width:23px;height:23px;flex:none;border-radius:var(--r-xs);display:grid;place-items:center;font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);font-weight:700;color:#fff;background:var(--grad);margin-top:2px}
.list.risk .n{background:linear-gradient(135deg,#FBBF24,#7A7A82)}
.panel-head{display:flex;align-items:center;gap:13px;margin-bottom:19px}
.panel-head .ico{width:40px;height:40px;border-radius:var(--r-md);display:grid;place-items:center;flex:none;border:1px solid var(--hair);background:rgba(255,255,255,.045)}
.panel-head h3{margin:0;font-size:var(--fs-5);font-weight:670;letter-spacing:-.013em}
.panel-head .sub{font-size:var(--fs-1);color:var(--text-3);margin-top:2px;font-family:'JetBrains Mono',monospace;letter-spacing:.06em}

/* 双语建议 */
.lang-card{display:flex;flex-direction:column}
.lang-head{display:flex;align-items:center;gap:12px;padding-bottom:15px;margin-bottom:17px;border-bottom:1px solid var(--hair-soft)}
.flag{
  width:40px;height:40px;border-radius:var(--r-sm);display:grid;place-items:center;flex:none;
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-2);font-weight:700;letter-spacing:.04em;color:#fff;
  box-shadow:0 8px 20px -8px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.16) inset;
}
.flag.zh{background:linear-gradient(135deg,#DE2910,#FF7A18)}
.flag.fr{background:linear-gradient(135deg,#0055A4,#3B82F6)}
.lang-head h4{margin:0;font-size:var(--fs-4);font-weight:670;letter-spacing:-.011em}
.lang-head .sub{font-size:var(--fs-1);color:var(--text-3);font-family:'JetBrains Mono',monospace;letter-spacing:.06em;margin-top:2px}
.lang-sub{font-size:var(--fs-2);font-weight:660;color:var(--text-3);letter-spacing:.05em;text-transform:uppercase;margin:18px 0 11px;display:flex;align-items:center;gap:9px}
.lang-sub::after{content:"";flex:1;height:1px;background:var(--hair-soft)}

/* 命中率 */
.predict{text-align:center}
.predict-num{font-family:'JetBrains Mono',monospace;font-size:clamp(58px,11vw,112px);font-weight:800;letter-spacing:-.055em;line-height:1;margin:8px 0 0}
.predict-num small{font-size:.36em;color:var(--text-3);font-weight:600}
.predict-bar{max-width:540px;margin:24px auto 0;height:11px;border-radius:var(--r-pill);background:rgba(255,255,255,.08);overflow:hidden}
.predict-bar > i{display:block;height:100%;width:0;border-radius:var(--r-pill);background:var(--grad);transition:width 1.2s var(--ease-out-expo)}
.predict-note{max-width:660px;margin:22px auto 0;color:var(--text-2);font-size:var(--fs-3);line-height:1.76}
/* 已命中：数字位让给结论，字号收一档并用绿色描边胶囊，避免和「命中率」的视觉语义混淆 */
.predict-num.is-made{font-size:clamp(30px,5vw,52px);font-weight:720;letter-spacing:-.02em;color:var(--green)}
.predict-num.is-made span{display:inline-block}
.predict-made{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:10px;margin:18px auto 0;max-width:660px;
  padding:11px 16px;border-radius:var(--r-md);border:1px solid rgba(34,197,94,.34);background:rgba(34,197,94,.10)}
.predict-made[hidden]{display:none}
.predict-made b{font-size:var(--fs-3);font-weight:640;color:var(--green);letter-spacing:.02em;white-space:nowrap}
.predict-made span{font-size:var(--fs-2);color:var(--text-2);line-height:1.6}

/* 创新点 */
.inno{display:grid;grid-template-columns:repeat(4,1fr);gap:22px}
.inno-item{padding:25px;border-radius:var(--r-lg);display:flex;flex-direction:column;gap:14px;transition:transform var(--dur-4) var(--ease-out-quart),box-shadow var(--dur-4) var(--ease-out-quart)}
.inno-item:hover{transform:translateY(-7px)}
.inno-ico{width:44px;height:44px;border-radius:var(--r-md);display:grid;place-items:center;border:1px solid var(--hair)}
.inno-item[data-c="v"] .inno-ico{background:linear-gradient(135deg,rgba(122,122,130,.28),rgba(122,122,130,.06));color:#AAAAAB}
.inno-item[data-c="p"] .inno-ico{background:linear-gradient(135deg,rgba(122,122,130,.28),rgba(122,122,130,.06));color:#C8C8D2}
.inno-item[data-c="c"] .inno-ico{background:linear-gradient(135deg,rgba(122,122,130,.28),rgba(122,122,130,.06));color:#22D3EE}
.inno-item[data-c="g"] .inno-ico{background:linear-gradient(135deg,rgba(34,197,94,.28),rgba(34,197,94,.06));color:#86EFAC}
.inno-item h4{margin:0;font-size:var(--fs-4);font-weight:670;letter-spacing:-.011em;line-height:1.42}
.inno-item p{margin:0;font-size:var(--fs-3);color:var(--text-3);line-height:1.75}
.inno-num{font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);color:var(--text-4);letter-spacing:.14em}

/* 反馈 */
.feedback{max-width:760px;margin:0 auto}
.fb-field{display:flex;flex-direction:column;gap:9px;margin-top:24px}
.fb-field textarea{
  width:100%;min-height:138px;resize:vertical;padding:15px 17px;border-radius:var(--r-md);
  background:rgba(255,255,255,.045);border:1px solid var(--hair);color:var(--text);
  font-size:var(--fs-3);line-height:1.7;transition:border-color var(--dur-3),background-color var(--dur-3);
}
.fb-field textarea:focus{outline:none;border-color:rgba(122,122,130,.6);background:rgba(255,255,255,.075)}
.fb-foot{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-top:17px;flex-wrap:wrap}
.spinner{width:16px;height:16px;border-radius:50%;border:2px solid rgba(255,255,255,.28);border-top-color:#fff;animation:spin .7s linear infinite}
[data-theme="light"] .spinner{border-color:rgba(10,11,26,.2);border-top-color:#0A0B1A}

.footer{padding:46px 0 56px;border-top:1px solid var(--hair-soft);text-align:center}
.footer p{margin:0;font-size:var(--fs-3);color:var(--text-3);line-height:1.75}

/* =========================================================
   14. MODAL + TOAST
   ========================================================= */
.modal{position:fixed;inset:0;z-index:var(--z-modal);display:grid;place-items:center;padding:clamp(14px,3vw,32px);background:rgba(3,4,12,.7);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);opacity:0;pointer-events:none;transition:opacity var(--dur-4) var(--ease-out-quart)}
.modal[data-open="true"]{opacity:1;pointer-events:auto}
.modal-card{width:min(800px,100%);max-height:86vh;display:flex;flex-direction:column;border-radius:var(--r-xl);transform:translateY(20px) scale(.98);transition:transform var(--dur-4) var(--ease-out-expo)}
.modal[data-open="true"] .modal-card{transform:translateY(0) scale(1)}
.modal-head{display:flex;align-items:center;gap:13px;padding:19px 22px;border-bottom:1px solid var(--hair-soft)}
.modal-head h3{margin:0;font-size:var(--fs-4);font-weight:670;flex:1;letter-spacing:-.012em}
.modal-body{padding:22px;overflow:auto}
.modal-body pre{margin:0;white-space:pre-wrap;word-break:break-word;font-family:'JetBrains Mono','SF Mono',ui-monospace,Menlo,monospace;font-size:var(--fs-2);line-height:1.9;color:var(--text-2)}
.modal-foot{display:flex;gap:11px;justify-content:flex-end;padding:15px 22px;border-top:1px solid var(--hair-soft)}
.toast{
  position:fixed;left:50%;bottom:32px;transform:translate(-50%,24px);z-index:var(--z-float);
  display:flex;align-items:center;gap:11px;max-width:min(560px,92vw);
  padding:14px 22px;border-radius:var(--r-pill);
  background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));
  border:1px solid var(--hair);backdrop-filter:blur(28px) saturate(190%);-webkit-backdrop-filter:blur(28px) saturate(190%);
  box-shadow:0 2px 5px -1px rgba(0,0,0,.5),0 12px 32px -14px rgba(0,0,0,.62),0 24px 60px -18px rgba(0,0,0,.7);
  font-size:var(--fs-3);opacity:0;pointer-events:none;
  transition:opacity var(--dur-4) var(--ease-out-quart),transform var(--dur-4) var(--ease-out-expo);
}
.toast[data-open="true"]{opacity:1;transform:translate(-50%,0)}
.toast .dotled{width:8px;height:8px;border-radius:50%;flex:none;background:var(--cyan);box-shadow:0 0 11px rgba(0,113,227,.45)}
.toast[data-kind="warn"] .dotled{background:var(--warn);box-shadow:0 0 11px rgba(251,191,36,.9)}
.toast[data-kind="ok"] .dotled{background:var(--green);box-shadow:0 0 11px rgba(34,197,94,.9)}

/* =========================================================
   15. REVEAL
   ========================================================= */
.reveal{opacity:0;transform:translateY(28px);transition:opacity .95s var(--ease-out-quart),transform .95s var(--ease-out-quart)}
.reveal.in{opacity:1;transform:none}

/* =========================================================
   16. RESPONSIVE
   ========================================================= */
@media (max-width:1024px){
  .inno{grid-template-columns:repeat(2,1fr)}
  .score-grid{grid-template-columns:1fr}
  .grid2{grid-template-columns:1fr}
}
@media (max-width:760px){
  .brand-text{font-size:var(--fs-3);max-width:40vw}
  .brand-sub{display:none}
  .angles{grid-template-columns:1fr}
  .steps{grid-template-columns:repeat(2,1fr)}
  .inno{grid-template-columns:1fr}
  .nav-inner{padding:8px var(--gutter);gap:9px}
  .lang-btn{padding:6px 11px;font-size:var(--fs-2)}
  .ring-wrap{width:170px;height:170px}
  .ring-num{font-size:var(--fs-8)}
  .stage-hud{display:none}
}
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.001ms !important}
  html{scroll-behavior:auto}
  .reveal{opacity:1;transform:none}
}

/* =========================================================
   19. LIQUID GLASS（iOS 26/27 液态玻璃）
   高透明填充 + 强折射模糊 + 顶部高光描边 + 底部虹彩晕边
   ========================================================= */
/* 玻璃令牌已上移 §1 TOKENS（唯一真值源），此处不再重复声明 --lg-* */
/* 玻璃令牌（浅色）已上移 §1 TOKENS，此处不再重复声明 --lg-* */
/* —— 玻璃基体 —— */
.glass,.card.glass,.glass.sheen{
  background-image:linear-gradient(158deg,var(--lg-fill-a),var(--lg-fill-b)) !important;
  border:1px solid var(--hair);
  backdrop-filter:var(--lg-blur);-webkit-backdrop-filter:var(--lg-blur);
  box-shadow:var(--lg-rim),var(--lg-prism),var(--lg-edge),var(--lg-drop);
}
/* 顶部镜面高光（原噪点层废弃，改为镜面反光） */
.glass::before{
  display:block !important;content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  opacity:1;mix-blend-mode:normal;border-radius:inherit;background-size:auto,160px 160px;
  background-image:var(--lg-sheen),var(--grain);
}
/* 底部与两侧的虹彩折射晕边 */
.glass::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;
  background:var(--lg-irid);opacity:.95;
}
.sheen-fx{display:none !important;}
/* —— 胶囊控件：顶栏 / 侧边栏 / 弹窗 / 控制坞 / 分段器 —— */
.nav-inner,.modal-card,.ctl-dock,.search-results,.acc,.inno-item,.result-block .card,.score-grid{
  background-image:linear-gradient(158deg,var(--lg-fill-a),var(--lg-fill-b)),var(--grain);
  background-size:auto,160px 160px;
  backdrop-filter:var(--lg-blur);-webkit-backdrop-filter:var(--lg-blur);
  box-shadow:var(--lg-rim),var(--lg-prism),var(--lg-edge),var(--lg-drop);
}
.nav-inner{border:1px solid var(--hair)}
.side{
  top:12px;left:12px;bottom:12px;width:calc(var(--side-w) - 24px);
  border:1px solid var(--hair);border-radius:var(--r-lg);
  background-image:var(--grain);background-size:160px 160px;
  box-shadow:var(--lg-rim),var(--lg-prism),var(--lg-edge),var(--lg-drop);
  overflow:hidden auto;
}
.side-scrim{backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.ctl-dock{border:1px solid var(--hair)}
.modal-card{border:1px solid var(--hair)}
/* —— 玻璃按钮 / 圆形图标按钮 / 分段控件 ——
   ★ .side-link 已移出 backdrop-filter 家族：侧栏背景本身 96% 近不透明，
   按钮的 backdrop 模糊最多透出 4% 背景（视觉≈0），却让全站最大面积的
   常驻按钮组（≈103Kpx）每帧做 backdrop 采样 —— 纯浪费，归零处理。 */
.btn-ghost,.btn-icon,.ctl-btn,.oauth-btn,.lang-switch,.speed-seg,.eyebrow,.chip,.status-pill{
  background-image:linear-gradient(158deg,var(--lg-btn-a),var(--lg-btn-b));
  backdrop-filter:var(--lg-btn-blur);-webkit-backdrop-filter:var(--lg-btn-blur);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.38), inset 0 -1px 0 rgba(255,255,255,.08),
             0 2px 5px -1px rgba(0,0,0,.45), 0 10px 26px -18px rgba(0,0,0,.72);
}
.side-link{border:1px solid transparent;backdrop-filter:none;-webkit-backdrop-filter:none}
.btn-ghost,.btn-icon,.ctl-btn,.oauth-btn{border:1px solid var(--hair)}
.btn-icon,.ctl-btn,.oauth-btn{color:var(--text-2)}
.side-link{border:1px solid transparent}
.side-link:hover{background-image:linear-gradient(158deg,rgba(255,255,255,.20),rgba(255,255,255,.07))}
/* ★ 2026-09-20 删除死规则：这里原有一条 .side-link.active，三条声明
   （background-image / border-color / box-shadow）与 §21 末的 .side-link.active
   特异性完全相同（同为 0,2,0）而位置更靠前 —— 后声明按属性逐条覆盖，
   所以本条**一条也没生效**。无头实测该元素 computed：
     box-shadow      = rgba(34,197,94,.9) 0px 8px 22px -14px   ← 来自后面那条
     background-image= linear-gradient(158deg,.22,.05)          ← 来自后面那条
   （不是「看着像」而是逐条比对 computed 值确认的。）整块移除，不改任何渲染结果。 */
.lang-switch,.speed-seg{border:1px solid var(--hair);border-radius:var(--r-pill)}
.lang-btn[aria-pressed="true"],.speed-seg button.on,.mode-seg button.on{
  background-image:linear-gradient(158deg,rgba(255,255,255,.34),rgba(255,255,255,.12));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6),0 8px 20px -12px rgba(0,0,0,.7);
}
/* iOS 27：液态玻璃适配「降低透明度」与「增强对比度」辅助功能 */
@media (prefers-reduced-transparency: reduce){
  .glass,.card.glass,.glass.sheen,.nav-inner,.modal-card,.ctl-dock,.search-results,
  .acc,.inno-item,.result-block .card,.score-grid,.side{
    backdrop-filter:none !important;-webkit-backdrop-filter:none !important;
  }
  :root{--lg-fill-a-alpha:.94;--lg-fill-b-alpha:.90}
  [data-theme="light"]{--lg-fill-a-alpha:.97;--lg-fill-b-alpha:.94}
}
@media (prefers-contrast: more){
  :root{--lg-edge:0 0 0 1px rgba(0,0,0,.78)}
  [data-theme="light"]{--lg-edge:0 0 0 1px rgba(28,22,70,.44)}
}
/* Apple 式滚动叙事：区块/卡片进入视口时淡入上移。
   用纯 CSS scroll-driven animation（@supports 包裹 → 不支持则完全无副作用），并尊重「减少动效」。 */
@keyframes revealUp{from{opacity:0;transform:translateY(22px)}to{opacity:1;transform:none}}
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    .reveal{
      animation:revealUp linear both;
      animation-timeline:view();
      animation-range:entry 0% cover 30%;
    }
  }
}
/* =========================================================
   液态玻璃（Chromium）+ 凝胶交互
   —— 纯 blur+saturate 霜面（SVG 折射滤镜已移除，见下方 @supports 内注释）
   ========================================================= */
@supports (backdrop-filter: blur(1px)){
  /* ⚡ 流畅性重构（2026-10-01）：移除全部 SVG feDisplacementMap 折射滤镜。
     feDisplacementMap 是滚动/动画时「掉帧头号元凶」—— 背后内容一变化就要重算整块
     feTurbulence + 位移（侧栏/导航/卡片/按钮这些滚动时持续可见的元素都在用它）。
     注释已明确「模糊+饱和+rim 占了玻璃质感的大头，去掉位移几乎看不出差别」，
     此前只对 :has(canvas) 面板做了降级，现推广到全部玻璃元素：统一走纯模糊。
     保留 --lg-blur（blur + saturate + brightness），观感不变、滚动帧率显著回升。 */
  .glass,.card.glass,.glass.sheen,.nav-inner,.modal-card,.ctl-dock,.search-results,
  .acc,.inno-item,.result-block .card,.score-grid{
    backdrop-filter:var(--lg-blur);
    -webkit-backdrop-filter:var(--lg-blur);
  }
  .btn-ghost,.btn-icon,.ctl-btn,.oauth-btn,.lang-switch,.speed-seg,.mode-seg,
  .eyebrow,.chip,.status-pill{
    backdrop-filter:var(--lg-btn-blur);
    -webkit-backdrop-filter:var(--lg-btn-blur);
  }
  /* .side-link 不参与（同上：侧栏近不透明背景上的按钮模糊无视觉意义） */
  /* 画面（canvas）面板继续用纯模糊（同一结论，此处保留以覆盖可能的重声明） */
  .glass:has(canvas),.card.glass:has(canvas),.acc:has(canvas),.inno-item:has(canvas){
    backdrop-filter:var(--lg-blur-flat);
    -webkit-backdrop-filter:var(--lg-blur-flat);
  }
}
/* 凝胶按压：弹簧回弹 + 轻微缩放，让交互「有弹性」而非生硬 */
.btn-icon,.ctl-btn,.btn-ghost,.oauth-btn,.lang-btn,.mode-seg button,.speed-seg button,.chip{
  transition:transform var(--dur-3) var(--ease-spring),background-color var(--dur-3) var(--ease-out-quart),
             background-image var(--dur-3) var(--ease-out-quart),color var(--dur-3) var(--ease-out-quart),
             border-color var(--dur-3) var(--ease-out-quart),box-shadow var(--dur-3) var(--ease-out-quart),opacity var(--dur-3);
}
@media (prefers-reduced-motion: no-preference){
  .btn-icon:active,.ctl-btn:active,.btn-ghost:active,.oauth-btn:active,.lang-btn:active,
  .mode-seg button:active,.speed-seg button:active{transform:scale(.90)}
  .btn-icon:hover,.ctl-btn:hover{transform:translateY(-1px) scale(1.07)}
  .btn-ghost:hover,.oauth-btn:hover{transform:translateY(-1px)}
}
[data-theme="light"] .lang-btn[aria-pressed="true"],
[data-theme="light"] .speed-seg button.on{
  background-image:linear-gradient(158deg,rgba(255,255,255,.98),rgba(255,255,255,.72));
}
.speed-seg button.on{color:var(--text)}
/* —— 输入框：内凹玻璃 —— */
input[type="text"],input[type="password"],input[type="search"],input[type="number"],textarea,.search-input{
  background-image:linear-gradient(180deg,rgba(255,255,255,.045),rgba(255,255,255,.012));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14), inset 0 2px 10px -6px rgba(0,0,0,.85);
  border:1px solid var(--hair);
  backdrop-filter:blur(14px) saturate(160%);-webkit-backdrop-filter:blur(14px) saturate(160%);
}
[data-theme="light"] input[type="text"],[data-theme="light"] input[type="password"],
[data-theme="light"] input[type="search"],[data-theme="light"] input[type="number"],
[data-theme="light"] textarea,[data-theme="light"] .search-input{
  background-image:linear-gradient(180deg,rgba(255,255,255,.92),rgba(255,255,255,.66));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95), inset 0 2px 10px -8px rgba(28,22,70,.4);
}
/* —— 更大的圆角：贴近 iOS 连续曲率 —— */
/* --r-lg / --r-xl 已上移 §1 TOKENS（值仍为 26px / 34px），此处不再重复声明。
   原覆盖块里 .card 写的是字面量 26px 而非 var(--r-lg)，是「改令牌改不动」的典型陷阱，
   2026-09-19 一并改回令牌。
   ★ 2026-09-19 二次整理：原先这里还有一条
       .view3d,.scope,.stage-shell{border-radius:var(--r-xl)}
     它对 .stage-shell 是**冗余**（.stage-shell 在 §7 已自行声明 --r-xl），
     对 .view3d/.scope 则是**覆盖**（它们的规则里写的是 --r-lg，被这条压成 34px ——
     又一处「改令牌改不动」）。现已把 --r-xl 写回 .view3d/.scope 各自的规则，
     这条统一声明**整条删除**：画面面板的 34px 由各面板自己声明，读一条规则就知道它的圆角。
   .auth-shell 同理（曾在这条里、又在自己规则里写 26px）：已确认设计意图是
   「大幅面外壳走 --r-xl」，写回它自己的规则（§15）。 */
.card{border-radius:var(--r-lg)}
/* —— 浅色主题下 3D 视图标签的对比度 —— */
[data-theme="light"] .view3d-tag{color:var(--green-hi);background:rgba(255,255,255,.74);border-color:rgba(21,128,61,.28)}
[data-theme="light"] .view3d-stat{color:#14713A}
[data-theme="light"] .view3d-stat b{color:var(--green-hi)}
[data-theme="light"] .stage-badge{color:var(--green-hi);background:rgba(255,255,255,.80);border-color:rgba(21,128,61,.26)}
[data-theme="light"] .stage-hud{color:#14713A}
/* —— 更饱满的极光背景，为玻璃提供折射源 —— */
/* 更饱满的极光背景（blur 与动画同在元素自身，理由见上方 .bg-grad 的性能记事）。
   o1/o2/o3 的尺寸与滤镜 §2 已声明，此处原先又重抄了一遍（值相同 = 纯冗余），已删。
   ★ o4 原为 cyan：它是「更饱满的极光背景」补丁追加的第四颗球，位置在
   left:16% / top:52%（正好压在侧栏背后），所以上一轮「环境层只保留品牌主副色」
   的色相巡检取样带（右缘 + 底部）没扫到它，成了漏网之鱼。
   现按同一规则改走 violet —— 只改色相、alpha 仍为 .30，未削弱环境光。 */
.bg-orb.o4{width:340px;height:340px;left:16%;top:52%;background:radial-gradient(circle,rgba(255,255,255,.08),transparent 68%);animation:orbFloat 22s var(--ease-out-quart) 2.2s infinite alternate-reverse}
/* 浅色底上光球是 normal 混合（screen 会把浅底直接刷白），此时它的着色**直接可见**：
   原来 .5 不透明度 × 0.5 左右的径向 alpha ≈ 每颗球约 25% 净着色的实心紫/粉/青块，
   叠加 .bg-grad 后整页就是「脏粉彩」。降到 .30 让它退成一缕气息。 */
[data-theme="light"] .bg-orb{opacity:.30;mix-blend-mode:normal}
/* macOS 风格交通灯窗口 UI（建模卡片左上角展示）
   z-index 只在本行声明：曾同时在 .view3d 分组里写 6、又单独写 7，
   两条都被本行（更靠后、同特异性）覆盖成死声明，2026-09-19 已删。 */
.win-dots{position:absolute;top:15px;left:16px;display:flex;gap:7px;z-index:4}
.win-dots i{width:11px;height:11px;border-radius:50%;display:block;box-shadow:0 0 0 1px rgba(0,0,0,.18) inset,0 1px 2px rgba(0,0,0,.25)}
.win-dots i:nth-child(1){background:#FF5F57}
.win-dots i:nth-child(2){background:#FEBC2E}
.win-dots i:nth-child(3){background:#28C840}
.view3d-tag{left:72px}
/* 自动旋转开关激活态 */
.btn-icon.on{color:var(--green);border-color:rgba(34,197,94,.5);box-shadow:var(--glow-ring)}
/* 视频透明度滑块紧跟其它控件 */
.ctl-row{display:flex;align-items:center;gap:9px}
.ctl-row .mono{font-size:var(--fs-1);letter-spacing:.06em;text-transform:uppercase}
/* 抛物线图例：各项独立成 clickable chip，去拥挤 */
.canvas-legend{gap:8px !important;display:flex !important;flex-wrap:wrap !important}
.legend-chip{
  display:inline-flex;align-items:center;gap:7px;padding:6px 12px;border-radius:var(--r-pill);
  border:1px solid var(--hair);background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));
  font-size:var(--fs-2);color:var(--text-2);cursor:pointer;-webkit-user-select:none;user-select:none;
  transition:color var(--dur-3),border-color var(--dur-3),opacity var(--dur-3),transform var(--dur-3);
}
.legend-chip:hover{transform:translateY(-1px);border-color:rgba(122,122,130,.4);color:var(--text)}
.legend-chip i{width:9px;height:9px;border-radius:50%;flex:none}
.legend-chip[data-on="false"]{opacity:.35}
.legend-chip[data-on="true"]{color:var(--text);border-color:rgba(34,197,94,.45)}

/* ===================== 登录门 / 第三方扫码 ===================== */
#authGate{position:fixed;inset:0;z-index:var(--z-gate);display:grid;place-items:center;padding:clamp(14px,3vw,30px);
  background:radial-gradient(1100px 620px at 20% 12%,var(--bg-grad-a),transparent 62%),
             radial-gradient(900px 560px at 84% 84%,var(--bg-grad-b),transparent 60%),var(--bg-base);}
#authGate[hidden]{display:none}
.auth-shell{width:100%;max-width:940px;display:grid;grid-template-columns:1.02fr .98fr;border-radius:var(--r-xl);overflow:hidden;
  border:1px solid var(--hair);background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));
  box-shadow:0 50px 120px -40px rgba(0,0,0,.7);position:relative}
.auth-hero{padding:clamp(26px,3vw,42px);display:flex;flex-direction:column;gap:14px;justify-content:center;
  /* 品牌渐变叠在 AI 生成篮球特写照片上（无水印）：照片提供高级质感，渐变保证深色主题下文字对比度 */
  background:
    linear-gradient(150deg,rgba(0,0,0,.55),rgba(0,0,0,.32) 55%,rgba(0,0,0,.18)),
    url("../assets/bg-ball.jpg") center / cover no-repeat;
  position:relative}
[data-theme="light"] .auth-hero{
  background:linear-gradient(150deg,rgba(0,0,0,.18),rgba(0,0,0,.08) 55%,rgba(0,0,0,.04))}
.auth-hero h2{margin:0;font-size:clamp(24px,2.6vw,32px);font-weight:800;letter-spacing:-.03em;line-height:1.2;text-wrap:balance}
.auth-hero p{margin:0;color:var(--text-2);font-size:var(--fs-3);line-height:1.8}
.auth-hero ul{margin:6px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:10px}
.auth-hero li{display:flex;gap:10px;align-items:flex-start;font-size:var(--fs-3);color:var(--text-2);line-height:1.6}
.auth-hero li b{color:var(--text);font-weight:650}
.auth-hero .tick{width:19px;height:19px;flex:none;border-radius:var(--r-2xs);display:grid;place-items:center;margin-top:2px;
  background:rgba(34,197,94,.18);color:var(--green);font-size:var(--fs-1);font-weight:800}
.auth-panel{padding:clamp(22px,2.6vw,34px);display:flex;flex-direction:column;gap:16px;background:rgba(10,12,24,.30)}
[data-theme="light"] .auth-panel{background:rgba(255,255,255,.55)}
.auth-tabs{display:flex;gap:6px;padding:5px;border-radius:var(--r-pill);background:rgba(128,128,170,.12);border:1px solid var(--hair)}
.auth-tab{flex:1;padding:9px 12px;border:0;border-radius:var(--r-pill);background:transparent;color:var(--text-3);
  font:inherit;font-size:var(--fs-3);font-weight:600;cursor:pointer;transition:color var(--dur-3),background var(--dur-3)}
.auth-tab[aria-selected="true"]{background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));color:var(--text);
  box-shadow:0 1px 0 rgba(255,255,255,.16) inset}
.auth-view{display:none;flex-direction:column;gap:14px}
.auth-view.active{display:flex}
.qr-box{display:grid;place-items:center;gap:12px;padding:18px;border-radius:var(--r-ml);border:1px solid var(--hair);
  background:rgba(255,255,255,.045)}
.qr-code{width:172px;height:172px;border-radius:var(--r-md);background:#fff;padding:10px;display:grid;place-items:center}
.qr-code svg{width:100%;height:100%;display:block}
.qr-hint{font-size:var(--fs-2);color:var(--text-2);text-align:center;line-height:1.7}
.qr-status{font-size:var(--fs-2);color:var(--green);font-weight:600;min-height:18px;text-align:center}
.field-row{display:flex;flex-direction:column;gap:7px}
.field-row label{font-size:var(--fs-2);color:var(--text-3);letter-spacing:.02em}
.field-row input{width:100%;padding:12px 14px;border-radius:var(--r-md);border:1px solid var(--hair);
  background:rgba(255,255,255,.05);color:var(--text);font:inherit;font-size:var(--fs-3);outline:none;transition:border-color var(--dur-3)}
.field-row input:focus{border-color:rgba(122,122,130,.5)}
/* Apple 风登录卡片：输入框聚焦用品牌蓝环；提交按钮用 Apple 蓝实色胶囊 */
.auth-panel .field-row input{border-radius:var(--r-sm)}
.auth-panel .field-row input:focus{border-color:var(--apple-blue);box-shadow:0 0 0 3px rgba(0,113,227,.22)}
.auth-panel .btn-primary{background:var(--apple-blue);border:0;color:#fff;font-weight:600;letter-spacing:-.01em;
  box-shadow:0 1px 2px rgba(0,0,0,.28),0 10px 24px -10px rgba(0,113,227,.55)}
.auth-panel .btn-primary:hover{background:#0077ED;transform:translateY(-1px);box-shadow:0 2px 6px rgba(0,0,0,.32),0 16px 34px -12px rgba(0,113,227,.6)}
.auth-panel .btn-primary:active{transform:translateY(0)}
.auth-msg{font-size:var(--fs-2);min-height:18px;color:var(--warn)}
.auth-msg.err{color:#FB7185}
.auth-msg.ok{color:var(--green)}
.hcaptcha-wrap{margin:2px 0 4px;min-height:0}
.hcaptcha-wrap[hidden]{display:none}
.auth-links{display:flex;justify-content:space-between;gap:10px;font-size:var(--fs-2);color:var(--text-3)}
.auth-links button{border:0;background:none;color:var(--text-2);cursor:pointer;font:inherit;padding:0;text-decoration:underline}
.auth-links button:hover{color:var(--text)}
.oauth{display:flex;flex-direction:column;gap:10px}
.oauth-label{display:flex;align-items:center;gap:10px;font-size:var(--fs-1);color:var(--text-3);letter-spacing:.06em;text-transform:uppercase}
.oauth-label::before,.oauth-label::after{content:"";flex:1;height:1px;background:var(--hair)}
.oauth-row{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
.oauth-btn{width:46px;height:46px;border-radius:var(--r-md);border:1px solid var(--hair);display:grid;place-items:center;cursor:pointer;
  background-image:linear-gradient(158deg,var(--glass-top),var(--glass-bot));transition:transform var(--dur-3),border-color var(--dur-3)}
.oauth-btn:hover{transform:translateY(-2px);border-color:rgba(122,122,130,.4)}
.oauth-btn svg{width:22px;height:22px}
.auth-note{font-size:var(--fs-1);color:var(--text-3);line-height:1.7;text-align:center}

/* ===================== 功能搜索 ===================== */
.search-wrap{position:relative;display:flex;align-items:center}
.search-input{width:190px;padding:9px 13px 9px 34px;border-radius:var(--r-pill);border:1px solid var(--hair);
  background:rgba(255,255,255,.05);color:var(--text);font:inherit;font-size:var(--fs-2);outline:none;transition:width var(--dur-3) var(--ease-out-quart),border-color var(--dur-3)}
.search-input:focus{width:250px;border-color:rgba(122,122,130,.5)}
.search-input::placeholder{color:var(--text-3)}
.search-ico{position:absolute;left:11px;top:50%;transform:translateY(-50%);width:15px;height:15px;color:var(--text-3);pointer-events:none}
.search-results{position:absolute;top:calc(100% + 10px);right:0;width:290px;max-height:330px;overflow-y:auto;padding:7px;
  border-radius:var(--r-ml);border:1px solid var(--hair);background:var(--bg-panel,#12131F);
  box-shadow:0 30px 70px -26px rgba(0,0,0,.75);z-index:80}
[data-theme="light"] .search-results{background:#FBFAFF}
.search-results[hidden]{display:none}
.search-item{display:flex;gap:10px;align-items:center;width:100%;padding:9px 11px;border-radius:var(--r-sm);border:0;background:none;
  color:var(--text-2);font:inherit;font-size:var(--fs-2);text-align:left;cursor:pointer;transition:background var(--dur-2),color var(--dur-2)}
.search-item:hover,.search-item.sel{background:rgba(122,122,130,.12);color:var(--text)}
.search-item .si-ico{width:26px;height:26px;flex:none;border-radius:var(--r-xs);display:grid;place-items:center;background:rgba(122,122,130,.16);color:#AAAAAB}
.search-item .si-ico svg{width:14px;height:14px}
.search-empty{padding:14px;text-align:center;font-size:var(--fs-2);color:var(--text-3)}

/* ===================== 新手指引 ===================== */
#tour{position:fixed;inset:0;z-index:var(--z-tour);display:grid;pointer-events:none}
#tour[hidden]{display:none}
.tour-mask{position:absolute;inset:0;background:rgba(4,5,14,.62);pointer-events:auto}
.tour-hole{position:absolute;border-radius:var(--r-ml);box-shadow:0 0 0 9999px rgba(4,5,14,.62);border:2px solid var(--green);
  pointer-events:none;transition:left var(--dur-4) var(--ease-out-quart),top var(--dur-4) var(--ease-out-quart),width var(--dur-4) var(--ease-out-quart),height var(--dur-4) var(--ease-out-quart)}
.tour-card{position:absolute;pointer-events:auto;width:min(330px,calc(100vw - 32px));padding:20px;border-radius:var(--r-ml);
  border:1px solid var(--hair);background:var(--bg-panel,#14151F);box-shadow:0 40px 90px -30px rgba(0,0,0,.8);
  display:flex;flex-direction:column;gap:11px;transition:left var(--dur-4) var(--ease-out-quart),top var(--dur-4) var(--ease-out-quart)}
[data-theme="light"] .tour-card{background:#FCFBFF}
.tour-step{font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.12em;color:var(--green);text-transform:uppercase}
.tour-card h4{margin:0;font-size:var(--fs-4);font-weight:700;letter-spacing:-.01em}
.tour-card p{margin:0;font-size:var(--fs-3);color:var(--text-3);line-height:1.75}
.tour-dots{display:flex;gap:6px}
.tour-dots i{width:6px;height:6px;border-radius:50%;background:rgba(128,128,170,.4);transition:background var(--dur-3),transform var(--dur-3)}
.tour-dots i.on{background:var(--green);transform:scale(1.35)}
.tour-actions{display:flex;gap:9px;align-items:center;justify-content:space-between;margin-top:2px}
.tour-actions .left{display:flex;gap:8px}

/* ===================== 3D 建模 AI 建议 ===================== */
.model-advice{display:grid;grid-template-columns:1.15fr .85fr;gap:26px}
.model-advice h4{margin:0 0 10px;font-size:var(--fs-3);font-weight:680}
.model-advice ul{margin:0;padding-left:18px;display:flex;flex-direction:column;gap:9px}
.model-advice li{font-size:var(--fs-3);color:var(--text-2);line-height:1.8}
.summary-grid{display:flex;flex-direction:column;gap:10px}
.summary-line{display:flex;justify-content:space-between;gap:12px;padding:9px 13px;border-radius:var(--r-md);
  border:1px solid var(--hair-soft);background:rgba(255,255,255,.04);font-size:var(--fs-2)}
.summary-line span{color:var(--text-3)}
.summary-line b{color:var(--text);font-family:'JetBrains Mono',monospace;font-size:var(--fs-2)}
.summary-note{margin:12px 0 0;padding:13px 15px;border-radius:var(--r-md);font-size:var(--fs-3);line-height:1.85;color:var(--text-2);
  border:1px solid rgba(34,197,94,.28);background:rgba(34,197,94,.07)}
.inno-head-row{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap;margin-top:6px}
.inno-item{cursor:pointer}
.inno-more{margin-top:12px;padding-top:12px;border-top:1px dashed var(--hair);display:none;flex-direction:column;gap:8px}
.inno-item[data-open="true"] .inno-more{display:flex}
.inno-more span{font-size:var(--fs-2);color:var(--text-3);line-height:1.7;display:flex;gap:8px}
.inno-more span b{color:var(--green);flex:none}
@media (max-width:900px){
  .auth-shell{grid-template-columns:1fr}
  .auth-hero{display:none}
  .model-advice{grid-template-columns:1fr}
  .search-input{width:130px}
  .search-input:focus{width:160px}
}

/* =========================================================
   20. 应用外壳：左侧导航 + 顶栏 + 路由视图
   ========================================================= */
/* --side-w 已上移 §1 TOKENS */
.side{
  position:fixed;left:0;top:0;bottom:0;width:var(--side-w);z-index:var(--z-side);
  display:flex;flex-direction:column;gap:6px;padding:16px 13px 14px;
  background:linear-gradient(180deg,rgba(13,15,30,.94) 0%,rgba(8,9,19,.96) 100%);
  border-right:1px solid var(--hair);
  /* ⚡ 流畅性：背景已是 94%→96% 近不透明，blur(22px) 被整块遮住、视觉上近乎无差异，
     却要每帧对 189Kpx 的整条侧栏做 backdrop 采样（全站最大的模糊面，占可见模糊面积 ~44%）。
     移除 backdrop-filter 对观感零损失，直接消掉这块常驻开销（见 probe-perf 扫描：aside.side 189Kpx）。 */
  overflow:hidden;overscroll-behavior:contain;
  transition:transform var(--dur-3) var(--ease-out-quart);
}
.side-head{flex:none}
[data-theme="light"] .side{background:linear-gradient(180deg,rgba(255,255,255,.95) 0%,rgba(243,241,252,.97) 100%)}
.side-head{display:flex;align-items:center;gap:10px;padding:4px 8px 14px;border-bottom:1px solid var(--hair-soft);margin-bottom:6px}
.side-head .brand-text{font-size:var(--fs-2);line-height:1.3;white-space:normal}
.side-scroll{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding-right:2px}
.side-scroll::-webkit-scrollbar{width:0;height:0}
.side-group{margin-top:13px}
.side-group:first-child{margin-top:2px}
.side-cap{font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);letter-spacing:.16em;text-transform:uppercase;color:var(--text-4);padding:0 11px 7px}
/* iOS 27 玻璃浓度滑块（极通透 ↔ 完全着色） */
.side-glass{padding:2px 4px 4px;display:flex;flex-direction:column;gap:6px}
.side-glass .side-cap{display:flex;align-items:center;justify-content:space-between;gap:8px;padding-bottom:0}
.side-glass b{font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);color:var(--text-3);letter-spacing:.06em}
.glass-range{-webkit-appearance:none;appearance:none;width:100%;height:22px;background:transparent;cursor:pointer;margin:0}
.glass-range::-webkit-slider-runnable-track{
  height:5px;border-radius:var(--r-pill);border:1px solid var(--hair);
  background:linear-gradient(90deg,rgba(255,255,255,.10),rgba(255,255,255,.30));
}
.glass-range::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:15px;height:15px;border-radius:50%;margin-top:-6px;
  background:linear-gradient(158deg,rgba(255,255,255,.92),rgba(255,255,255,.62));
  box-shadow:0 0 0 1px rgba(0,0,0,.34),0 3px 10px -3px rgba(0,0,0,.7),inset 0 1px 0 rgba(255,255,255,.9);
}
.glass-range::-moz-range-track{height:5px;border-radius:var(--r-pill);border:1px solid var(--hair);background:linear-gradient(90deg,rgba(255,255,255,.10),rgba(255,255,255,.30))}
.glass-range::-moz-range-thumb{width:15px;height:15px;border:0;border-radius:50%;background:linear-gradient(158deg,rgba(255,255,255,.92),rgba(255,255,255,.62));box-shadow:0 0 0 1px rgba(0,0,0,.34),0 3px 10px -3px rgba(0,0,0,.7)}
.glass-range:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:var(--r-pill)}
.side-link{
  display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:var(--r-sm);
  color:var(--text-2);font-size:var(--fs-3);font-weight:550;cursor:pointer;
  border:1px solid transparent;background:none;width:100%;text-align:left;font-family:inherit;
  transition:background var(--dur-2) var(--ease-out-quart),color var(--dur-2) var(--ease-out-quart),border-color var(--dur-2) var(--ease-out-quart),transform var(--dur-2) var(--ease-out-quart);
}
.side-link:hover{background:rgba(255,255,255,.06);color:var(--text);transform:translateX(4px);border-color:rgba(170,170,180,.25)}
[data-theme="light"] .side-link:hover{background:rgba(10,11,26,.05);border-color:rgba(122,122,130,.2)}
/* iOS 27：侧边栏图标用 app 的 accent color 着色（增强个性与「当前项」辨识度） */
.side-link .ic{width:17px;height:17px;flex:none;opacity:.92;color:var(--text-3);
  transition:color var(--dur-2) var(--ease-out-quart),opacity var(--dur-2) var(--ease-out-quart)}
.side-link:hover .ic{color:var(--accent)}
.side-link.active .ic{color:var(--accent);opacity:1}
/* 唯一生效的 .side-link.active（上面 §10 那条同特异性的已被本条整条覆盖，见该处注释） */
.side-link.active{
  background:linear-gradient(158deg,rgba(34,197,94,.22),rgba(34,197,94,.05));
  color:var(--green-hi);border-color:rgba(34,197,94,.32);
  box-shadow:var(--glow-raise);
}
[data-theme="light"] .side-link.active{color:var(--green-hi)}
.side-link .n{margin-left:auto;font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);color:var(--text-4)}
.side-link.active .n{color:var(--green-hi)}
.side-foot{border-top:1px solid var(--hair-soft);padding-top:11px;margin-top:9px;flex:none;display:flex;flex-direction:column;gap:8px}
.side-user{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:var(--r-md);background:rgba(255,255,255,.045);border:1px solid var(--hair-soft)}
[data-theme="light"] .side-user{background:rgba(10,11,26,.035)}
.side-avatar{width:30px;height:30px;flex:none;border-radius:var(--r-xs);display:grid;place-items:center;font-weight:800;font-size:var(--fs-2);color:#04140A;background:var(--grad-green)}
.side-user .u{font-size:var(--fs-2);font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.side-user .r{font-size:var(--fs-1);color:var(--text-4);font-family:'JetBrains Mono',monospace}
.side-scrim{position:fixed;inset:0;z-index:var(--z-side-scrim);background:rgba(4,6,14,.62);opacity:0;pointer-events:none;transition:opacity var(--dur-3) var(--ease-out-quart)}
body.side-open .side-scrim{opacity:1;pointer-events:auto}

/* 顶栏与内容为侧边栏让位 */
#app .side-handle{display:none}
/* =========================================================
   侧边栏「下拉条」自动隐藏（桌面端 ≥1025px）
   收起后内容区吃掉整条 250px 侧栏宽度；鼠标移到左边缘即丝滑展开，移开延迟收回。
   点击把手 = 钉住/松开（钉住后不再自动隐藏），状态持久化到 syb-sidehide。
   ========================================================= */
@media (min-width:1025px){
  /* 内容区与顶栏跟着侧栏一起移动，时长/缓动与侧栏滑出保持一致 → 整块「丝滑」而不是各走各的 */
  #app .nav,#app .app-main,#app .footer{
    transition:left var(--dur-4) var(--ease-out-quart),margin-left var(--dur-4) var(--ease-out-quart);
  }
  .side{transition:transform var(--dur-4) var(--ease-out-quart),box-shadow var(--dur-4) ease}
  #app.side-collapsed .side{transform:translateX(calc(-1 * var(--side-w) - 18px))}
  #app.side-collapsed .nav{left:0}
  #app.side-collapsed .app-main{margin-left:0}
  #app.side-collapsed .footer{margin-left:0}
  .side-zone{position:fixed;left:0;top:0;bottom:0;width:26px;z-index:var(--z-side-zone);display:none}
  #app.side-collapsed .side-zone{display:block}
  /* —— 「下拉条」把手 ——
     教训：第一版做成 12px、和背景几乎同色，结果用户根本看不见它，
     于是「侧栏自动隐藏」被读成「导航消失了 / 什么都没变」。
     把手是**交互入口**，不该追求通体透明 —— 给它自己的实体底 + 亮边 + accent 辉光，
     并让箭头常驻，收起态一眼就能看出「这里可以拉出来」。 */
  #app .side-handle{
    display:grid;place-items:center;grid-template-rows:1fr auto 1fr;gap:0;
    position:fixed;left:0;top:50%;z-index:var(--z-side-handle);margin-top:-74px;
    width:18px;height:148px;padding:0;border:0;cursor:pointer;
    /* ★ 13px 是**几何绑定值**，不是阶梯档位 —— 故意保留字面量。
       本元素 18px 宽 / 148px 高，右帽取多大取决于这个尺寸关系：
         · 0 13px 13px 0  → 13+0 ≤ 18，**不发生收缩**，四角就是 13px
         · 0 999px 999px 0 → 按 18/(0+999) 收缩成 **18px**（不是直觉上的 9px 半圆！）
       也就是说写 --r-pill 会让把手反而更圆 5px。规则：**跟随元素尺寸推导出来的圆角
       不走 --r-* 阶梯**，可以写字面量，但必须像这里一样注明是几何量。 */
    border-radius:0 13px 13px 0;color:#EAF2EE;
    /* 关键：底色必须**明显亮于深色背景**。深色底上放深色把手 = 看不见，
       backdrop-filter 只会把背景的深色糊上来，救不了对比度。 */
    background-image:linear-gradient(158deg,rgba(170,170,180,.22),rgba(122,122,130,.08)),
                     linear-gradient(158deg,var(--lg-fill-a),var(--lg-fill-b));
    background-color:#25304A;
    backdrop-filter:var(--lg-blur);-webkit-backdrop-filter:var(--lg-blur);
    box-shadow:inset 0 2px 0 rgba(255,255,255,.72),
               inset 0 -2px 0 rgba(255,255,255,.26),
               inset -2px 0 0 rgba(255,255,255,.20),
               0 0 0 1px rgba(0,0,0,.55),
               0 0 1px 1px rgba(170,170,180,.28),
               0 16px 40px -18px rgba(0,0,0,.95),
               0 0 34px -8px rgba(170,170,180,.38);
    transition:width var(--dur-4) var(--ease-out-quart),background-color var(--dur-4) var(--ease-out-quart),
               color var(--dur-3) var(--ease-out-quart),left var(--dur-4) var(--ease-out-quart),opacity var(--dur-3) ease;
  }
  [data-theme="light"] #app .side-handle{
    background-color:#FFFFFF;color:var(--text-2);
    box-shadow:inset 0 2px 0 rgba(255,255,255,1),
               inset 0 -2px 0 rgba(255,255,255,.7),
               inset -2px 0 0 rgba(255,255,255,.85),
               0 0 0 1px rgba(28,22,70,.18),
               0 14px 34px -18px rgba(28,22,70,.38),
               0 0 30px -8px rgba(122,122,130,.26);
  }
  #app .side-handle-bar{width:2.5px;height:44px;border-radius:2px;background:currentColor;opacity:.7;
    transition:opacity .25s ease,transform .3s var(--ease-out-quart)}
  /* 箭头常驻：收起态指向右（可拉出），展开态翻转指向左 */
  #app .side-handle-chev{width:14px;height:14px;opacity:.9;transform:translateX(-4px);
    transition:opacity var(--dur-3) ease,transform var(--dur-3) var(--ease-out-quart)}
  #app .side-handle:hover{width:23px;color:var(--accent)}
  #app .side-handle:hover .side-handle-bar{opacity:.95}
  #app .side-handle:hover .side-handle-chev{opacity:1;transform:translateX(1px)}
  #app .side-handle:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
  /* 展开态：把手贴到侧栏右缘，箭头反向 */
  #app:not(.side-collapsed) .side-handle{left:calc(var(--side-w) - 1px)}
  #app:not(.side-collapsed) .side-handle-chev{transform:translateX(0) rotate(180deg)}
  #app.side-pinned .side-handle-bar{opacity:.98}
  /* 收起后轻推三下：「我在这里，可以拉出来」——只跑 3 次就停，不持续干扰 */
  #app.side-collapsed .side-handle{animation:handleNudge 2.4s var(--ease-out-quart) 1.2s 3}
  @keyframes handleNudge{0%,100%{transform:translateX(0)}50%{transform:translateX(5px)}}
}
@media (prefers-reduced-motion:reduce){
  #app .side-handle{transition:none;animation:none !important}
  #app .nav,#app .app-main,#app .footer,.side{transition:none !important}
}
#app .nav{left:var(--side-w)}
/* =========================================================
   全局留白节奏（2026-09-18）
   量测发现：内页「导航底 → 首个内容」的留白高达 274~302px，等于 900px 视口的三分之一
   全是空的，整页重心被压到底部 —— 这是「不够高级」最主要的结构性原因。
   根因是两段留白叠加：app-main 的 padding-top 104px（只是为躲开固定顶栏）
   又叠加了 section 的 padding-top clamp(70px,9vw,130px)（那是给区块之间做呼吸的）。
   顶栏本身已经提供了与内容的分离，所以：① app-main 只负责「刚好躲开顶栏」；
   ② 区块的顶部留白收到 44px 上限；③ 区块之间的呼吸仍由 padding-bottom 保留。
   ========================================================= */
#app .app-main{margin-left:var(--side-w);padding-top:84px;padding-bottom:64px}
#app .app-main > section{padding-top:clamp(24px,3vw,44px);padding-bottom:clamp(44px,5vw,76px)}
#app .app-main > section#top{padding-top:10px}
#app .footer{margin-left:var(--side-w)}
#app .hero{padding-top:clamp(10px,2vw,22px)}

/* 路由视图切换 */
.route-view{animation:routeIn .42s var(--ease-out-quart) both}
@keyframes routeIn{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
.gate-card{max-width:600px;margin:0 auto;text-align:center}
.gate-card .ico{width:56px;height:56px;margin:0 auto 16px;border-radius:var(--r-ml);display:grid;place-items:center;
  border:1px solid var(--hair);background:rgba(255,255,255,.05);color:var(--green-hi)}
.gate-card .ico svg{width:26px;height:26px}
.gate-card h3{margin:0 0 8px;font-size:var(--fs-5);font-weight:750;letter-spacing:-.02em}
.gate-card p{margin:0 0 18px;font-size:var(--fs-3);line-height:1.85;color:var(--text-2)}

/* 登录 / 注册整页视图 */
#authPage{position:fixed;inset:0;z-index:var(--z-gate);overflow:auto;display:grid;place-items:center;
  padding:clamp(14px,3vw,34px) clamp(14px,3vw,34px) 60px}
#authPage[hidden]{display:none}
.auth-topbar{position:fixed;top:16px;right:18px;z-index:var(--z-top);display:flex;align-items:center;gap:8px}
.auth-title-row{display:flex;align-items:center;gap:11px;margin-bottom:2px}
.field-row.pw{position:relative}
.field-row.pw input{padding-right:46px}
.pw-toggle{position:absolute;right:7px;bottom:7px;width:32px;height:32px;border-radius:var(--r-xs);border:0;background:none;
  color:var(--text-3);cursor:pointer;display:grid;place-items:center;transition:color var(--dur-2),background var(--dur-2)}
.pw-toggle:hover{color:var(--text);background:rgba(255,255,255,.08)}
.pw-toggle svg{width:17px;height:17px;display:block}
.auth-remember{display:flex;align-items:center;gap:8px;font-size:var(--fs-2);color:var(--text-3);cursor:pointer;-webkit-user-select:none;user-select:none}
.auth-remember input{width:15px;height:15px;accent-color:#22C55E;cursor:pointer}
.oauth-note{margin:2px 0 0;font-size:var(--fs-1);color:var(--text-4);text-align:center;line-height:1.6}
.auth-strength{display:flex;gap:4px;margin-top:7px}
.auth-strength i{flex:1;height:3px;border-radius:3px;background:rgba(255,255,255,.12)}
.auth-strength i.on{background:var(--green)}
.field-row.code .code-input{display:flex;gap:10px;align-items:center}
.field-row.code .code-input input{flex:1;min-width:0}
.field-row.code .code-input .btn-ghost{flex:none;white-space:nowrap;padding:10px 14px;border-radius:var(--r-md);background:rgba(122,122,130,.12);color:var(--text-1);border:1px solid var(--hair);font-size:var(--fs-2);cursor:pointer}
.field-row.code .code-input .btn-ghost:hover{background:rgba(122,122,130,.2)}
.oauth-btn:disabled{opacity:.4;cursor:not-allowed;transform:none}
.oauth-btn:disabled:hover{transform:none;border-color:var(--hair)}

/* =========================================================
   20b. 项目档案（INSA 申请材料）
   ========================================================= */
.about-actions{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:20px}
/* ⚡ apple.com 式长页流畅技术：视口外的长区块跳过渲染（layout/paint 全跳），
   滚动接近时才渲染。contain-intrinsic-size 给出占位高度避免滚动条跳动。
   打印导出（@media print）会展开全部内容 —— cv:auto 只影响屏幕渲染。 */
#about{content-visibility:auto;contain-intrinsic-size:auto 1600px}
.about-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:14px;margin-top:26px}
.about-stats > div{padding:16px 14px;border-radius:var(--r-ml);text-align:center;
  background-image:linear-gradient(158deg,var(--lg-fill-a),var(--lg-fill-b));
  border:1px solid var(--hair);backdrop-filter:var(--lg-blur);-webkit-backdrop-filter:var(--lg-blur);
  box-shadow:var(--lg-rim)}
.about-stats b{display:block;font-family:'JetBrains Mono',monospace;font-size:clamp(24px,3vw,36px);font-weight:750;letter-spacing:-.03em;line-height:1.1}
.about-stats span{display:block;font-size:var(--fs-1);color:var(--text-3);margin-top:6px;letter-spacing:.05em}
.about-h{margin:0 0 10px;font-size:var(--fs-4);font-weight:700;letter-spacing:-.015em}
.about-p{margin:0;font-size:var(--fs-3);line-height:1.9;color:var(--text-2)}
.about-note{margin:14px 0 0;font-size:var(--fs-2);line-height:1.8;color:var(--text-3);
  padding:12px 14px;border-radius:var(--r-md);border:1px solid var(--hair-soft);background:rgba(255,255,255,.035)}
.about-steps{margin:6px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:12px}
.about-steps li{display:flex;gap:13px;align-items:flex-start;font-size:var(--fs-3);line-height:1.85;color:var(--text-2)}
.about-steps li b{flex:none;font-family:'JetBrains Mono',monospace;font-size:var(--fs-1);color:var(--green-hi);
  padding:4px 9px;border-radius:var(--r-xs);border:1px solid rgba(34,197,94,.32);background:rgba(34,197,94,.10);margin-top:2px}
.about-tags{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}
.about-tags span{font-size:var(--fs-2);padding:7px 12px;border-radius:var(--r-pill);color:var(--text-2);
  border:1px solid var(--hair);background-image:linear-gradient(158deg,var(--lg-btn-a),var(--lg-btn-b));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28)}
.about-insa{margin:2px 0 0}
.about-author{display:grid;grid-template-columns:1.1fr .9fr;gap:26px;align-items:center}
.about-meta{display:flex;flex-direction:column;gap:10px}
.about-meta > div{display:flex;justify-content:space-between;gap:14px;align-items:baseline;
  padding:10px 13px;border-radius:var(--r-md);border:1px solid var(--hair-soft);background:rgba(255,255,255,.035);font-size:var(--fs-2)}
.about-meta b{font-weight:650;color:var(--text)}
/* 作者署名卡 */
.about-id{display:flex;gap:16px;align-items:center;margin:2px 0 16px;padding-bottom:16px;border-bottom:1px dashed var(--hair)}
.about-id .side-avatar{width:58px;height:58px;border-radius:var(--r-ml);font-size:var(--fs-6);flex:none;
  box-shadow:var(--glow-raise-lg)}
.id-name{font-size:var(--fs-5);font-weight:760;letter-spacing:-.02em;line-height:1.2}
.id-name .id-fr{font-size:var(--fs-2);font-weight:600;color:var(--green-hi);margin-left:7px;
  font-family:'JetBrains Mono',monospace;letter-spacing:.06em}
.id-role{font-size:var(--fs-2);color:var(--text-3);margin-top:3px}
.id-contacts{display:flex;gap:10px;flex-wrap:wrap;margin-top:9px}
.id-contacts a{display:inline-flex;align-items:center;gap:7px;font-size:var(--fs-2);color:var(--text-2);text-decoration:none;
  padding:7px 12px;border-radius:var(--r-pill);border:1px solid var(--hair);
  background-image:linear-gradient(158deg,var(--lg-btn-a),var(--lg-btn-b));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3);
  transition:color var(--dur-3) var(--ease-out-quart),border-color var(--dur-3) var(--ease-out-quart),transform var(--dur-3) var(--ease-out-quart)}
.id-contacts a:hover{color:var(--text);border-color:rgba(34,197,94,.45);transform:translateY(-2px)}
.id-contacts svg{width:13px;height:13px;flex:none;color:var(--green)}
[data-theme="light"] .id-contacts svg{color:var(--green-hi)}
[data-theme="light"] .id-name .id-fr{color:var(--green-hi)}
@media (max-width:900px){ .about-author{grid-template-columns:1fr} }

/* 打印：把项目档案导出为干净的 PDF / 纸质件 */
@media print{
  .bg,.side,.nav,.side-scrim,.ctl-dock,.win-dots,.footer,#tour,.about-actions,#authPage{display:none !important}
  #app[hidden]{display:block !important}
  #app .app-main > section:not(#about){display:none !important}
  #about{display:block !important;content-visibility:visible !important}
  .reveal{opacity:1 !important;transform:none !important}
  .route-view{animation:none !important}
  html,body{background:#fff !important;color:#111 !important}
  .app-main{margin-left:0 !important;padding-top:0 !important}
  .card.glass,.about-stats > div{border:1px solid #dcdcdc !important;box-shadow:none !important;background:#fff !important;backdrop-filter:none !important;-webkit-backdrop-filter:none !important}
  .about-p,.about-steps li,.about-note,.about-meta > div{color:#222 !important}
  .about-steps li b{color:#0a7d3c !important;border-color:#bfe6cd !important;background:#eefaf1 !important}
  .gradient-text,.gradient-green{-webkit-text-fill-color:#0a7d3c !important;color:#0a7d3c !important;background:none !important}
  .h-section,.about-h,.about-meta b,.about-stats b{color:#111 !important}
  @page{margin:16mm}
}
@media (max-width:1024px){
  .side{transform:translateX(calc(-100% - 24px));width:min(86vw,320px);box-shadow:var(--lg-drop),0 0 70px rgba(0,0,0,.6)}
  body.side-open{overflow:hidden}
  body.side-open .side{transform:none}
  #app .nav{left:0}
  #app .app-main{margin-left:0;padding-top:max(78px,calc(64px + env(safe-area-inset-top)));padding-bottom:max(64px,calc(40px + env(safe-area-inset-bottom)))}
  #app .footer{margin-left:0}
  .side-toggle{display:grid !important;width:44px;height:44px}
  .nav-inner{padding:8px 10px 8px 14px;padding-left:max(14px,calc(10px + env(safe-area-inset-left)));padding-right:max(10px,calc(10px + env(safe-area-inset-right)))}
  /* 顶栏右侧精简：把搜索收起为图标按钮一样宽，避免过窄挤变形 */
  .search-input{width:110px}
  .search-input:focus{width:140px}
  .stage-hud{display:none}
}
.side-toggle{display:none}

/* iPhone / 窄屏优化（≤640px）—— 单列堆叠 + 触控目标 ≥44px + 去 iOS 蓝框 */
@media (max-width:640px){
  html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
  body{overscroll-behavior-y:contain;-webkit-tap-highlight-color:transparent}
  .btn-icon,.ctl-btn,.oauth-btn,.lang-btn,.pw-toggle,.ctl-zoom,.speed-seg button{min-height:44px;min-width:44px}
  .btn-icon{padding:0}
  .stage-hud{display:none}
  .brand-text{max-width:46vw}
  .brand-sub{display:none}
  #userChip{display:none !important}
  /* 窄屏把语言开关收进侧栏抽屉；顶栏只留 汉堡 / 标题 / 主题，避免挤爆 */
  .nav-right{gap:6px}
  .nav-right .lang-switch{display:none}
  #guideBtn{display:none}
  .search-wrap{display:none}                  /* 窄屏隐藏搜索条，避免挤变形 */
  .nav .brand{gap:8px}
  .nav .brand-text{min-width:0}
  .lang-btn{padding:8px 12px;font-size:var(--fs-2)}
  .ring-wrap{width:158px;height:158px}
  .ring-num{font-size:var(--fs-8)}
  .ctl-dock{gap:5px;padding:5px;right:10px;bottom:max(10px,env(safe-area-inset-bottom));transform:scale(.94);transform-origin:bottom right}
  .ctl-zoom-val{min-width:34px;font-size:var(--fs-1)}
  .speed-seg button{padding:6px 9px}
  /* 卡片单列 */
  .score-grid,.angles,.steps,.inno,.grid2,.report-grid,.cmp-grid,.results-grid{grid-template-columns:1fr !important}
  /* 大表格横滑 */
  .table,.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
  /* 上传区更紧凑 */
  .upload-card{padding:18px 14px}
  /* 抽屉在 iPhone 全屏 */
  .drawer-panel{width:100vw !important;height:100dvh !important;border-radius:0 !important;max-height:100dvh !important}
  /* 聊天助手在窄屏全屏 */
  .ai-chat{top:0;right:0;bottom:0;left:0;width:100%;border-radius:0}
  /* 确保汉堡按钮在窄屏足够大，不被压缩 */
  #sideToggle{order:-1}
}
/* 防 iOS 缩放：文本输入 ≥16px 才不弹键盘放大 */
@media (max-width:640px){
  input[type="text"],input[type="password"],input[type="email"],input[type="search"],textarea,select{font-size:var(--fs-4) !important}
  /* 评价表/分数条在小屏单列 */
  .meter-row{grid-template-columns:1fr !important;gap:6px}
}

/* ---------- 数据溯源 ---------- */
.prov-card .spec-cite{font-size:var(--fs-2);color:var(--tx-soft);margin:-4px 0 14px;line-height:1.5}
.prov-list{display:flex;flex-direction:column;gap:9px}
.prov-row{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center;padding:11px 13px;border-radius:var(--r-md);border:1px solid var(--hair-soft);background:rgba(255,255,255,.03);cursor:pointer;transition:var(--dur-3) var(--ease-out-quart)}
.prov-row:hover{border-color:rgba(122,122,130,.5);background:rgba(122,122,130,.08);transform:translateY(-1px)}
.prov-row-main{display:flex;flex-direction:column;gap:2px;min-width:0}
.prov-label{font-size:var(--fs-3);font-weight:600;color:var(--tx)}
.prov-val{font-size:var(--fs-2);color:var(--tx-soft);font-variant-numeric:tabular-nums}
.prov-score{font-size:var(--fs-5);font-weight:700;color:#7A7A82;font-variant-numeric:tabular-nums;min-width:42px;text-align:right}
.prov-bar{height:5px;border-radius:var(--r-pill);background:rgba(255,255,255,.08);margin-top:7px;overflow:hidden;grid-column:1/-1}
.prov-bar > i{display:block;height:100%;border-radius:var(--r-pill);background:linear-gradient(90deg,#22C55E,#7A7A82)}
.prov-row-sub{display:flex;gap:12px;font-size:var(--fs-1);color:var(--tx-soft);grid-column:1/-1;margin-top:4px}
.prov-hint{font-size:var(--fs-1);color:var(--tx-soft);margin-top:12px;font-style:italic}

/* ---------- 抽屉 ---------- */
.drawer{position:fixed;inset:0;z-index:var(--z-drawer);display:flex;justify-content:flex-end}
.drawer[hidden]{display:none}
.drawer-mask{position:absolute;inset:0;background:rgba(4,7,16,.55);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.drawer-panel{position:relative;width:min(460px,92vw);height:100%;padding:30px 26px;overflow:auto;box-shadow:-20px 0 60px rgba(0,0,0,.5);animation:drawerIn .35s var(--ease-out-quart)}
@keyframes drawerIn{from{transform:translateX(40px);opacity:.4}to{transform:none;opacity:1}}
.drawer-x{position:absolute;top:18px;right:18px;width:34px;height:34px;border-radius:50%;border:1px solid var(--hair-soft);background:rgba(255,255,255,.05);color:var(--tx);font-size:var(--fs-5);cursor:pointer;line-height:1}
.prov-detail{margin-top:18px;display:flex;flex-direction:column;gap:14px}
.prov-detail .pd-block{background:rgba(255,255,255,.03);border:1px solid var(--hair-soft);border-radius:var(--r-md);padding:13px 15px}
.prov-detail .pd-k{font-size:var(--fs-1);text-transform:uppercase;letter-spacing:.08em;color:var(--tx-soft);margin-bottom:6px}
.prov-detail .pd-v{font-size:var(--fs-3);color:var(--tx);line-height:1.55;font-variant-numeric:tabular-nums;word-break:break-word}
.prov-detail code{background:rgba(122,122,130,.14);padding:2px 7px;border-radius:var(--r-2xs);font-size:var(--fs-2);color:#c9c9d2}
.prov-detail .pd-joints b{color:#7A7A82}

/* ---------- A/B 对比 ---------- */
.cmp-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px}
.cmp-slot{border:1px solid var(--hair-soft);border-radius:var(--r-lg);padding:18px;background:rgba(255,255,255,.028)}
.cmp-slot h4{margin:0 0 4px;font-size:var(--fs-3);display:flex;align-items:center;gap:8px}
.cmp-tag{font-size:var(--fs-1);padding:2px 9px;border-radius:var(--r-pill);font-weight:700}
.cmp-tag.a{background:rgba(122,122,130,.16);color:var(--pink-hi)}
.cmp-tag.b{background:rgba(34,197,94,.16);color:var(--green-hi)}
.cmp-drop{border:1.5px dashed var(--hair-soft);border-radius:var(--r-md);padding:18px;text-align:center;cursor:pointer;color:var(--tx-soft);transition:var(--dur-3);font-size:var(--fs-2)}
.cmp-drop:hover{border-color:rgba(122,122,130,.5);color:var(--tx)}
.cmp-prev{width:100%;border-radius:var(--r-md);margin-top:12px;max-height:150px;background:#05070f;display:none}
.cmp-slot.done .cmp-prev{display:block}
.cmp-actions{display:flex;gap:10px;margin-top:12px;flex-wrap:wrap}
.cmp-canvas-wrap{border:1px solid var(--hair-soft);border-radius:var(--r-md);background:#05070f;padding:10px;margin-top:10px}
.cmp-bars{display:flex;flex-direction:column;gap:12px;margin-top:8px}
.cmp-bar{display:grid;grid-template-columns:130px 1fr 64px;gap:12px;align-items:center;font-size:var(--fs-2)}
.cmp-bar .cb-label{color:var(--tx-soft)}
.cmp-bar .cb-track{position:relative;height:22px;border-radius:var(--r-2xs);background:rgba(255,255,255,.05);overflow:hidden}
.cmp-bar .cb-a,.cmp-bar .cb-b{position:absolute;top:0;bottom:0;border-radius:var(--r-2xs)}
.cmp-bar .cb-a{background:rgba(122,122,130,.5)}
.cmp-bar .cb-b{background:rgba(34,197,94,.5)}
.cmp-bar .cb-delta{text-align:right;font-weight:700;font-variant-numeric:tabular-nums}
.cmp-delta.up{color:var(--green-hi)}.cmp-delta.down{color:var(--pink-hi)}.cmp-delta.flat{color:var(--tx-soft)}
.cmp-empty{color:var(--tx-soft);font-size:var(--fs-2);padding:18px;text-align:center;border:1px dashed var(--hair-soft);border-radius:var(--r-md)}
.cmp-control{margin-top:14px;font-size:var(--fs-2);color:var(--tx-soft);background:rgba(122,122,130,.08);border:1px solid rgba(122,122,130,.25);border-radius:var(--r-md);padding:12px 14px;line-height:1.5}
.cmp-scores{display:flex;gap:18px;margin-top:10px}
.cmp-scores .cs{flex:1;text-align:center;border:1px solid var(--hair-soft);border-radius:var(--r-md);padding:14px}
.cmp-scores .cs b{display:block;font-size:var(--fs-7);font-weight:800;font-variant-numeric:tabular-nums}
.cmp-scores .cs.a b{color:var(--pink-hi)}.cmp-scores .cs.b b{color:var(--green-hi)}
.cmp-scores .cs span{font-size:var(--fs-1);color:var(--tx-soft)}
@media (max-width:760px){.cmp-grid{grid-template-columns:1fr}.cmp-bar{grid-template-columns:90px 1fr 60px}}
/* =========================================================
   20. 图像面板的「玻璃装裱」（LENS FRAME）
   画面（canvas）面板没法用 backdrop-filter 做折射：画布每帧都在变，
   backdrop 位移折射会每帧全屏重算（见 --lg-blur-flat 的注释）。
   所以这里的「玻璃质量」全部落在**静态光学层**上，不参与每帧合成：
     ① 边缘四段：外暗环 → 外亮环（厚度）→ 落地影 + 冷环境反光 → 内侧薄亮环
     ② 内阴影：让画面读起来是「在玻璃后面」。没有它，画面就是一张贴纸。
     ③ 棱边色散：青/品红/紫在四边各错位 1.5px（真玻璃边缘会分光）
     ④ 斜向镜面掠光 + 四边折射环 + 磨砂微纹理（--grain）
   ========================================================= */
/* 装裱令牌已上移 §1 TOKENS，此处不再重复声明 --lens-* */
/* 装裱令牌（浅色）已上移 §1 TOKENS，此处不再重复声明 --lens-* */
/* 所有「画面」容器统一走同一套玻璃装裱（.hero-stage .stage-shell 必须单列：它原本的
   box-shadow 选择器特异性更高，不重写就会被旧的绿色描边盖掉） */
.view3d,.scope,.canvas-wrap,.stage-shell,.hero-stage .stage-shell{
  box-shadow:var(--lens-out),var(--lens-shadow),var(--lens-in),var(--lens-top),var(--lens-prism);
}
/* Hero 舞台额外保留品牌紫的大范围环境光：作为整串阴影的**最后一层**（绘制在最底），
   既不影响上面的玻璃装裱，也不丢掉首页原本的紫调氛围。 */
.hero-stage .stage-shell{
  box-shadow:var(--lens-out),var(--lens-shadow),var(--lens-in),var(--lens-top),var(--lens-prism),
             0 40px 120px -60px rgba(122,122,130,.75);
}
/* 掠光 + 折射环 + 磨砂纹理：z-index 3 —— 在画布之上、浮动控件（z 6）之下 */
.view3d::before,.scope::before,.canvas-wrap::before,
.stage-shell::before,.hero-stage .stage-shell::before{
  content:"";position:absolute;inset:0;z-index:3;pointer-events:none;border-radius:inherit;
  background-image:var(--lens-glare),var(--grain);
  background-size:auto,160px 160px;
}
/* 画面上的浮动信息片：底图可能是亮画面也可能是暗画面，因此给一圈 rim + 落影把字「压住」 */
.scope-hud,.scope-corner,.stage-badge,.stage-hud{z-index:6}
.view3d-tag,.scope-corner,.stage-badge{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.30),0 0 0 1px rgba(0,0,0,.30),0 8px 20px -12px rgba(0,0,0,.82);
}
.view3d-stat,.scope-hud,.stage-hud{text-shadow:0 1px 3px rgba(0,0,0,.75)}
[data-theme="light"] .view3d-stat,
[data-theme="light"] .scope-hud,
[data-theme="light"] .stage-hud{text-shadow:0 1px 2px rgba(255,255,255,.95)}

/* ——— 无障碍回退：系统开启「降低透明度 / 提高对比度」时，玻璃退化为实体面 ———
   本文件的玻璃装裱都是纯装饰光学层（不含 backdrop-filter），不会掉帧；
   但对低视力用户，磨砂颗粒、虹彩晕边、掠光都属于噪声 —— 一并收起，
   只留描边与投影来维持层次。 */
@media (prefers-reduced-transparency: reduce){
  .glass,.card.glass,.glass.sheen,.nav-inner,.modal-card,.ctl-dock,.search-results,
  .acc,.inno-item,.result-block .card,.score-grid,.side,.side-scrim{
    backdrop-filter:none !important;
    -webkit-backdrop-filter:none !important;
    background-color:var(--bg-base);
  }
  .glass::before,.glass::after{opacity:0 !important}
  .view3d::before,.scope::before,.canvas-wrap::before,
  .stage-shell::before,.hero-stage .stage-shell::before{background-image:none !important}
}
@media (prefers-contrast: more){
  /* 高对比：去掉磨砂颗粒与掠光，描边加深，画面面板用更硬的轮廓把内容框住 */
  .view3d::before,.scope::before,.canvas-wrap::before,
  .stage-shell::before,.hero-stage .stage-shell::before{background-image:none !important}
  .view3d,.scope,.canvas-wrap,.stage-shell,.hero-stage .stage-shell{
    box-shadow:0 0 0 1px rgba(0,0,0,.62), 0 0 0 2px rgba(255,255,255,.22), var(--lens-shadow);
  }
  [data-theme="light"] .view3d,
  [data-theme="light"] .scope,
  [data-theme="light"] .canvas-wrap,
  [data-theme="light"] .stage-shell,
  [data-theme="light"] .hero-stage .stage-shell{
    box-shadow:0 0 0 1px rgba(10,11,26,.55), 0 0 0 2px rgba(255,255,255,.85), var(--lens-shadow);
  }
}/* =========================================================
   21. 视觉观感修正（2026-09-18）
   本节的每条改动都由 .workbuddy/audit-visual.js 的实测数据驱动，
   不是凭感觉调的。审计口径：文字对比度按 WCAG AA（常规 <4.5、
   大字 <3.0 记为不达标），可点击元素任一维 <24px 记为过小。
   ========================================================= */

/* —— 21.1 浅色主题缺一个「浅底上的绿」——
   --green-hi(#86EFAC) 是给深色底用的浅薄荷，但 [data-theme="light"]
   从未覆盖它，而它被当作**文字色**用了 21 处（.ai-bubble b /
   .goal-chip / .tag[data-s="ok"] / .view3d-stat b / .about-steps li b /
   .id-name .id-fr …）—— 在浅底上实测只有 1.1~1.9:1，等于隐形。
   换成深绿；#15803D 在玻璃面板上实测 4.49:1（贴着 4.5 的线），
   再压暗一档到 #14713A → 5.4:1，留出余量。 */
/* --green-hi 的浅色值已上移 §1 TOKENS（#14713A，5.4:1） */

/* —— 21.2 「永远深色」表面：把整套文字令牌重钉回去 ——
   .scope（取景器，装视频帧）/ .video-preview / .cmp-canvas-wrap 的底色
   是硬编码的深色，#0B0C16 / #05060f / #05070f，**两个主题都不翻转**。
   但它们内部的文字与控件吃的是主题令牌：浅色主题下 --text-3 变成深色
   rgba(10,11,26,.5)，压在深底上实测 1.04:1（取景器的 VIDEO / 0.25× /
   48 fps / 播放按钮全部看不见）。
   自定义属性会继承，所以只要在这三个容器上把令牌钉成深色主题的值，
   内部**所有后代**自动恢复可读，不必逐个选择器去打补丁。 */
.scope,.video-preview,.cmp-canvas-wrap{
  --text:#F8FAFC;
  --text-2:rgba(248,250,252,.74);
  --text-3:rgba(248,250,252,.58);
  --text-4:rgba(248,250,252,.48);
  --green-hi:#86EFAC;
  --pink-hi:#fb7185;
  --tx:#F8FAFC;--tx-soft:rgba(248,250,252,.58);
  --hair:rgba(255,255,255,.15);
  --hair-soft:rgba(255,255,255,.07);
}

/* —— 21.3 文字梯度按「实测底」重算 ——
   第四级 --text-4 并非纯装饰（.side-cap 侧栏分组标题 / .brand-sub /
   .step 流程步骤 / .oauth-note 登录说明 / .inno-num / .side-user .r 都在里面），
   原本两套主题都是 .28（深色 2.32:1），上一轮抬到 .42/.46 仍不够：
     深色 .42 叠在玻璃面板上实测 3.94:1（AA 要 4.5）→ 抬到 .48 = 4.82:1；
     浅色整条梯度当初是把深色的 alpha 抄过来的，没按浅底重新求值，
       实测 --text-3 .50 只有 3.58:1、--text-4 .46 只有 3.16:1，
       连正文（p / b / .sub）都落在不合格区间 → 按浅底重排：
       text-2 .72(7.6:1) / text-3 .64(5.7:1) / text-4 .58(4.7:1)。 */
/* --text-4 的深色值已上移 §1 TOKENS（.48，4.82:1） */
/* --text-3 / --text-4 的浅色值已上移 §1 TOKENS（.64 / .58） */
/* 真正承载信息的正文（分析流程步骤 / 登录页 OAuth 说明）再提一档 */
.step,.oauth-note{color:var(--text-3)}

/* —— 21.4 分段按钮只有 18px 高 ——
   审计：.speed-seg / .mode-seg / .view-seg 的按钮实测 32~47 × 18px
   （font-size:10px + padding:4px 8px + line-height:1），既低于可点击
   下限，视觉上也发扁。抬到 26px 胶囊，取景器条内保持紧凑。 */
.speed-seg button,.mode-seg button,.view-seg button{
  min-height:26px;display:inline-flex;align-items:center;justify-content:center;
  font-size:var(--fs-1);padding:5px 10px;
}
.scope-bar .speed-seg button{min-height:24px}
/* 取景器里的视频透明度滑块原本只有 16px 高。这里不再单独给值——
   21.10 已把所有 range 统一到 24px；留着这条 (0,2,1) 的规则反而会
   压住通用规则，把它钉死在 22px。 */

/* —— 21.5 修正上一轮（同日）引入的一处错误 ——
   .scope-hud 所在的面板**永远是深色**，浅色主题下也该用深色阴影；
   上一轮把 .scope-hud 加进了「浅色主题给白色 text-shadow」那一组，
   会把浅绿字糊成一团白雾。这里单独纠回，并给原本没有阴影的
   .scope-corner 补上深色阴影（10.5px 小字压在画面上需要它）。 */
[data-theme="light"] .scope-hud{text-shadow:0 1px 4px rgba(0,0,0,.72)}
.scope-corner{text-shadow:0 1px 4px rgba(0,0,0,.72)}

/* —— 21.6 A/B 对比页的轨迹画布越界 ——
   .cmp-canvas-wrap 有 padding:10px 与圆角，但**没有** canvas 尺寸规则，
   #cmpTraj 一直用 1180px 的固有宽度 → 实测右缘 1342 超出容器内容盒
   1279 达 63px，画布直接戳出圆角外。 */
.cmp-canvas-wrap{overflow:hidden}
.cmp-canvas-wrap canvas{width:100%;height:auto;display:block}

/* —— 21.7 中文不该吃拉丁负字距 ——
   -.038em 这类负 tracking 是为拉丁展示体做的；中文在这种字距下会「挤」，
   标题越大越明显。按 html[lang] 分开：中文收敛到近 0，法语保留原张力
   （applyLang 会把 lang 在 zh-CN / fr 之间切换）。 */
[lang^="zh"] .h-display{letter-spacing:-.012em;line-height:1.16}
[lang^="zh"] .h-section{letter-spacing:-.010em}
[lang^="zh"] .h-sub{letter-spacing:0}
/* §37 中文标题/正文同样不吃拉丁负字距：这批元素承载纯中文标题/姓名，漏掉了 §21.7 的收敛。
   等宽数字类（.stat b/.ring-num/.angle-val/.predict-num/.about-stats b/.exp-preview-txt b）
   与 .btn/.brand-text 有意保留负字距，不在其列。 */
[lang^="zh"] .auth-hero h2{letter-spacing:0}
[lang^="zh"] .gate-card h3{letter-spacing:0}
[lang^="zh"] .id-name{letter-spacing:0}
[lang^="zh"] .about-h{letter-spacing:0}
[lang^="zh"] .panel-head h3{letter-spacing:0}
[lang^="zh"] .modal-head h3{letter-spacing:0}
[lang^="zh"] .drop-title{letter-spacing:0}
[lang^="zh"] .lang-head h4{letter-spacing:0}
[lang^="zh"] .inno-item h4{letter-spacing:0}
[lang^="zh"] .tour-card h4{letter-spacing:0}
[lang^="zh"] .mega-txt b{letter-spacing:0}
[lang^="zh"] .ai-head-txt b{letter-spacing:0}
[lang^="zh"] .acc-head .t{letter-spacing:0}
[lang^="zh"] .angle-name{letter-spacing:0}

/* —— 21.8 抗锯齿分主题 ——
   body 上全局写了 -webkit-font-smoothing:antialiased（灰度抗锯齿），
   这在深色底上更干净；但浅色底上它会让字**变细变淡**，而浅色模式本来
   就是对比度更差的那一半（同一轮审计里，浅色不达标项始终是深色的 2~3 倍）。
   浅色主题用回默认的次像素抗锯齿，字更实。 */
[data-theme="light"] body{-webkit-font-smoothing:subpixel-antialiased}

/* —— 21.9 激活态按钮的「填充被高光盖掉」 ——
   第 1073 行给 .lang-btn[aria-pressed=true] / .speed-seg button.on /
   .mode-seg button.on 加了一层白色高光，但它用的是 **background-image**，
   于是把第 319 行的 background:var(--grad) 和第 726/736 行的
   var(--grad-green) 整条盖掉了（同特异性、位置更靠后）。后果：
     · .lang-btn 的文字是 #fff，浅色主题下白字压近白胶囊 → 实测 1.02:1，
       当前选中的语言**完全看不见**（深色主题下底够深才侥幸没事）；
     · .speed-seg button.on 丢了绿色胶囊，选中态没有颜色、只剩一块白；
     · .mode-seg button.on 压根没写过 .on 样式，只有白高光 + --text-3 文字，
       深色 3.78:1 / 浅色 3.59:1 —— 既看不清，也看不出哪个被选中。
   这里在样式表最末重新声明 background-image（同特异性、后者胜），把填充还回去。 */
.lang-btn[aria-pressed="true"],
[data-theme="light"] .lang-btn[aria-pressed="true"]{background-image:var(--grad);color:#fff}
.speed-seg button.on,.mode-seg button.on,.view-seg button.on{
  background-image:var(--grad-green);color:#04140a;font-weight:800;
  box-shadow:var(--glow-chip);
}

/* —— 21.10 滑块家族统一 ——
   全站 7 个 range 里有 6 个是「原生渲染 + accent-color」
   （#scopeVideoAlpha、#skScrub、#skYaw、#skPitch、#hdYaw、#hdPitch），
   只有侧栏的 .glass-range 是手写的玻璃滑轨 —— 同一屏里两种滑轨并存，
   而且原生那批只有 16px 高，低于 WCAG 2.5.8 的 24px 触控下限。
   统一成一套：24px 高 / 5px 玻璃轨 / 17px 圆钮；颜色仍按各滑块原本的语义
   （YAW 绿 #22C55E、PITCH 粉 #7A7A82）走 --sld-c。
   滑轨颜色要跟着主题翻转，所以定义成令牌；三个「永远深色」的容器再钉回白色。 */
input[type="range"]{
  -webkit-appearance:none;appearance:none;height:24px;margin:0;
  background:transparent;cursor:pointer;border-radius:var(--r-pill);
}
input[type="range"]::-webkit-slider-runnable-track{
  height:5px;border-radius:var(--r-pill);border:1px solid var(--hair);
  background:linear-gradient(90deg,var(--sld-a),var(--sld-b));
}
input[type="range"]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:17px;height:17px;border-radius:50%;margin-top:-7px;
  background:var(--sld-c,var(--accent));
  box-shadow:0 0 0 1px rgba(0,0,0,.30),0 3px 10px -3px rgba(0,0,0,.6),inset 0 1px 0 rgba(255,255,255,.45);
}
input[type="range"]::-moz-range-track{height:5px;border-radius:var(--r-pill);border:1px solid var(--hair);background:linear-gradient(90deg,var(--sld-a),var(--sld-b))}
input[type="range"]::-moz-range-thumb{width:17px;height:17px;border:0;border-radius:50%;background:var(--sld-c,var(--accent));box-shadow:0 0 0 1px rgba(0,0,0,.30)}
input[type="range"]:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* —— 21.12 输入类元素的键盘焦点环 ——
   上面几个输入框写了 `outline:none`（.field input:focus / .fb-field textarea:focus 的
   :focus 规则，以及 .ai-chat-input textarea / .field-row input / .search-input 的基础规则），
   本意是"鼠标点进来不要那圈系统描边"——它们确实都有 :focus 的 border-color 变化作为鼠标反馈。
   问题：`outline:none` 对**键盘焦点同样生效**，而它的特异性 ≥ 全局 `:focus-visible`
   （第 163 行），于是**键盘用户在这些输入框上看不到任何焦点环**，WCAG 2.4.11 不达标。
   修法：不改原规则（保住鼠标体验），在更靠后的位置用同等或更高特异性补回键盘焦点环。
   放在文件后段是为了让同特异性的 `.x:focus-visible` 靠"后来居上"压住 `.x:focus`。 */
.field input:focus-visible,
.fb-field textarea:focus-visible,
.ai-chat-input textarea:focus-visible,
[data-theme="light"] .ai-chat-input textarea:focus-visible,
.field-row input:focus-visible,
.search-input:focus-visible{
  outline:2px solid var(--apple-blue);outline-offset:2px;border-radius:var(--r-xs);
}

/* —— 21.13 视觉隐藏（只给读屏）——
   用于 aria-live 播报区：内容必须存在于无障碍树里，但不能占版面。
   不要用 display:none / visibility:hidden —— 那样读屏也读不到，live region 会失效。 */
.sr-only{
  position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* --sld-* 已上移 §1 TOKENS */
/* --sld-*（浅色）已上移 §1 TOKENS */
.scope,.video-preview,.cmp-canvas-wrap{ --sld-a:rgba(255,255,255,.10); --sld-b:rgba(255,255,255,.30) }

/* .glass-range（侧栏玻璃浓度）保留自己那枚白色玻璃钮，只把尺寸对齐；
   选择器要写成 input.glass-range::… 才压得住上面的通用规则。 */
input.glass-range::-webkit-slider-thumb{
  width:17px;height:17px;margin-top:-7px;
  background:linear-gradient(158deg,rgba(255,255,255,.92),rgba(255,255,255,.62));
}
input.glass-range::-moz-range-thumb{width:17px;height:17px;background:linear-gradient(158deg,rgba(255,255,255,.92),rgba(255,255,255,.62))}

/* =========================================================
   §22 视觉增强（2026-09-20 v2）—— 专治「一眼可见」的三处
   =========================================================
   上一轮做的是「看不见的工程」（令牌收敛、死码清理、焦点管理），
   用户反馈「优化不明显」。本块针对实测截图里的三个眼见病灶：
     ① 大幅面视口是一块死黑（A/B 轨迹画布 1180×440 纯 #05070f）；
     ② 卡片/槽位发平（.cmp-slot 只有 .028 白底，几乎看不出边）；
     ③ 标题发灰（渐变从深紫起笔，压在紫色背景上对比不足）。
   全部以「追加块 + 同特异性后置」生效，**不修改任何既有声明**，
   也不动 JS。因此回滚只需删掉本块。 */

/* —— 22.1 大幅面视口：统一「仪表面」装裱（本轮最大可见改动）——
   现状：.view3d / .scope / .canvas-wrap 已有 §21 的 --lens-glare + --grain 装裱层，
        但 .cmp-canvas-wrap（A/B 轨迹画布，1180×440）**完全没有** ——
        截图里那块 300px 高的纯黑就是它，看起来像没做完。
   本条给四类大幅面统一补上三层：
        ① 蓝图网格（46px 基准格，与站内其他 mono 尺寸对齐）；
        ② 内嵌描边框（inset 13px 的一圈紫色发丝线 = 取景器「边框」）；
        ③ 顶部柔光（模拟仪表面受光，使平面产生前后层次）。
   z-index 2：在画布之上、浮动 HUD（z 6）之下；pointer-events:none 不挡交互。
   ⚠️ 故意排除 .stage-shell：它在 §7 已有自己的 ::after（发丝线 + 紫色内处理），
      重叠会把那圈内光挤没。主页舞台本来就好看，不动。 */
.cmp-canvas-wrap{position:relative}
.view3d::after,.scope::after,.canvas-wrap::after,.cmp-canvas-wrap::after{
  content:"";position:absolute;inset:13px;z-index:2;pointer-events:none;
  border-radius:14px;
  box-shadow:0 0 0 1px rgba(170,170,180,.17) inset, 0 0 70px -20px rgba(122,122,130,.55) inset;
  background-image:
    linear-gradient(rgba(170,170,180,.10) 1px,transparent 1px),
    linear-gradient(90deg,rgba(170,170,180,.10) 1px,transparent 1px),
    radial-gradient(130% 100% at 50% -12%,rgba(122,122,130,.24),rgba(122,122,130,0) 62%);
  background-size:46px 46px,46px 46px,auto;
  background-position:-1px -1px,-1px -1px,0 0;
}
/* 浅色主题：.grid 改用深紫，否则在 #E9E6F5 底上全白失见 */
[data-theme="light"] .view3d::after,
[data-theme="light"] .scope::after,
[data-theme="light"] .canvas-wrap::after,
[data-theme="light"] .cmp-canvas-wrap::after{
  box-shadow:0 0 0 1px rgba(76,29,149,.14) inset;
  background-image:
    linear-gradient(rgba(76,29,149,.10) 1px,transparent 1px),
    linear-gradient(90deg,rgba(76,29,149,.10) 1px,transparent 1px),
    radial-gradient(130% 100% at 50% -12%,rgba(122,122,130,.12),rgba(122,122,130,0) 62%);
}

/* —— 22.2 槽位 / 卡片材质：从「几乎看不出边」到「有实体感」——
   .cmp-slot 原本只有
gba(255,255,255,.028)
 白底 + hair-soft 边，在深底上几乎不可见。
   现在：斜向渐变面 + 顶缘高光实线 + 落影，并补上悬停抬升（原来没有）。 */
.cmp-slot{
  background-image:linear-gradient(158deg,rgba(255,255,255,.078),rgba(255,255,255,.012) 52%,rgba(122,122,130,.080));
  border-color:rgba(255,255,255,.125);
  box-shadow:0 1px 0 rgba(255,255,255,.11) inset, 0 22px 48px -30px rgba(0,0,0,.92);
  transition:transform var(--dur-3) var(--ease-out-quart),box-shadow var(--dur-3),border-color var(--dur-3);
}
.cmp-slot:hover{
  transform:translateY(-3px);border-color:rgba(170,170,180,.32);
  box-shadow:0 1px 0 rgba(255,255,255,.17) inset, 0 26px 58px -28px rgba(122,122,130,.55);
}
/* 创新卡片（.inno-item 已是 .glass，故用 var(--shadow-1) 叠加，不覆盖玻璃底） */
.inno-item:hover{
  border-color:rgba(170,170,180,.30);
  box-shadow:var(--shadow-1),0 26px 60px -30px rgba(122,122,130,.55);
}

/* —— 22.3 展示级标题：提高对比 + 真实光晕（每一页可见）——
   原 --grad 是 linear-gradient(135deg,#7A7A82,#7A7A82)，起笔就是深紫，
   压在同为紫调的 .bg-orb 背景上→ 字形与背景明度相近，「发灰」。
   改为四档渐变，**够白起笔**。注意：只覆盖 background-image，
   不动全局 --grad 令牌（按钮、提示条仍用原渐变）。
   光晕用 filter:drop-shadow 而非 text-shadow：字形由 background-clip:text 绘制，
   text-shadow 会被压在字形之下几乎不可见（同 §9 对 statPulse 的实测结论）。 */
.gradient-text{
  background-image:linear-gradient(115deg,#FFFFFF 0%,#EDE4FF 26%,#AAAAAB 56%,#7A7A82 100%);
  filter:drop-shadow(0 6px 26px rgba(122,122,130,.50));
}
[data-theme="light"] .gradient-text{
  background-image:linear-gradient(115deg,#4C1D95 0%,#7A7A82 36%,#DB2777 100%);
  filter:drop-shadow(0 3px 12px rgba(122,122,130,.20));
}

/* —— 22.4 章节头装饰线：给每个页面的引言区收一个句号（十二页均可见）—— */
.section-head::after{
  content:"";display:block;width:78px;height:2px;margin:24px auto 0;border-radius:2px;
  background:linear-gradient(90deg,rgba(170,170,180,0),rgba(170,170,180,.92),rgba(122,122,130,.92),rgba(122,122,130,0));
}

/* —— 22.5 统计瓦片：数字放大 + 分隔线（首页可见）——
   10号字阶的 32px 在 1280 宽容器里偏小；提到 30~42px 并加 1px 竖分隔线，
   四个数字从「一排小字」变成一条仪表读数带。 */
.stat{position:relative;padding:0 clamp(10px,1.5vw,24px)}
.stat + .stat::before{
  content:"";position:absolute;left:0;top:14%;bottom:14%;width:1px;
  background:linear-gradient(180deg,transparent,rgba(255,255,255,.18),transparent);
}
.stat b{font-size:clamp(30px,3.8vw,42px)}


/* —— 22.6 打印兜底 ——
   页内已有 @media print 把 .gradient-text 改成实色绿（字形靠 background-clip
   才能出来，打印必须去掉裁切）。但本轮新加的 filter:drop-shadow
   不受那条影响 —— 会在绿色标题周围留一圈紫色阴影。
   网格/取景器装裱属屏幕装饰，纸面上只增墨不增信息，一并收起。 */
@media print{
  .gradient-text{filter:none !important}
  .view3d::after,.scope::after,.canvas-wrap::after,.cmp-canvas-wrap::after{display:none !important}
  .section-head::after{background:rgba(122,122,130,.85)}
  .stat + .stat::before{background:rgba(0,0,0,.25)}
}


/* =========================================================
   §23 统一表面材质 + 面板头品牌图标（2026-09-20 v3）
   =========================================================
   发现方法：把全站「低剑量白底」普查一遍（
   `background:rgba(255,255,255,.025~.04)`），得 10 处。
   其中 .cmp-slot 已在 §22.2 修复，剩 9 处仍是「几乎看不出边」的平面：
     卡片类  .angle（结果页指标瓦片 ×4）/ .prov-detail .pd-block / .prog
     行/提示  .prov-row / .summary-line / .about-meta > div / .about-note
     视口底栏  .view3d-foot / .scope-bar
   本块把前两类统一为同一套材质（叠加式，不覆盖底色），并给可点击行补上悬停态。
   ⚠️ 浅色主题必须单独给值：这些元素本来就嵌在白底 .glass 里，
      若沿用「半透明白」会变成**白上白**、比改前更看不见；
      故浅色下改用带紫调的不透明面 + 加深描边。 */

/* —— 23.1 卡片类：渐变面 + 顶缘高光实线 + 落影 —— */
.angle,.prov-detail .pd-block,.prog{
  background-image:linear-gradient(158deg,rgba(255,255,255,.075),rgba(255,255,255,.012) 54%,rgba(122,122,130,.068));
  border-color:rgba(255,255,255,.115);
  box-shadow:0 1px 0 rgba(255,255,255,.10) inset, 0 18px 40px -32px rgba(0,0,0,.90);
}
/* —— 23.2 行 / 提示块：只要渐变面与顶缘高光（小元素不加大投影）—— */
.prov-row,.summary-line,.about-meta > div,.about-note{
  background-image:linear-gradient(158deg,rgba(255,255,255,.070),rgba(255,255,255,.012) 58%,rgba(122,122,130,.058));
  border-color:rgba(255,255,255,.115);
  box-shadow:0 1px 0 rgba(255,255,255,.095) inset;
}
/* —— 高级感：数据行 = 标签 / 参考区间条 / 数值 ——
   与结果页的角度卡共用同一视觉语言（区间带 + 指示条），信息密度更高也更「产品化」。 */
.summary-grid{display:flex;flex-direction:column;gap:6px}
.summary-line{
  display:grid;grid-template-columns:minmax(72px,1fr) 84px auto;align-items:center;gap:14px;
  padding:10px 13px;
  transition:background-image .28s var(--ease-out-quart),border-color .28s var(--ease-out-quart),transform .3s var(--ease-spring);
}
.summary-line:hover{transform:translateX(2px);border-color:rgba(170,170,180,.30)}
.summary-line > span{color:var(--text-3);font-size:var(--fs-2);letter-spacing:.01em}
.summary-line > b{
  min-width:64px;text-align:right;color:var(--text);
  font-family:'JetBrains Mono',monospace;font-size:var(--fs-2);font-weight:600;
  font-variant-numeric:tabular-nums;letter-spacing:-.01em;
}
/* 参考区间条：zone = 理想区间，fill = 当前值（在区间内为绿，偏离转琥珀） */
.sum-track{position:relative;display:block;height:5px;border-radius:99px;overflow:hidden;
  background:rgba(255,255,255,.085)}
[data-theme="light"] .sum-track{background:rgba(10,11,26,.08)}
.sum-track > i{position:absolute;top:0;bottom:0;border-radius:99px;display:block}
.sum-track > i.zone{background:rgba(34,197,94,.30)}
.sum-track > i.fill{left:0;width:0;
  background:linear-gradient(90deg,rgba(34,197,94,.62),#86EFAC);
  box-shadow:0 0 10px rgba(34,197,94,.45);
  transition:width 1.05s var(--ease-out-expo)}
.summary-line[data-ok="0"] .sum-track > i.fill{
  background:linear-gradient(90deg,rgba(251,191,36,.62),#FDE68A);
  box-shadow:0 0 10px rgba(251,191,36,.42);
}
/* —— 23.3 交互态（.angle / .prov-row 原本只有淡淡的 hover）—— */
.angle:hover{
  border-color:rgba(170,170,180,.34);
  box-shadow:0 1px 0 rgba(255,255,255,.17) inset, 0 26px 54px -26px rgba(122,122,130,.52);
}
.prov-row:hover{
  border-color:rgba(170,170,180,.34);
  box-shadow:0 1px 0 rgba(255,255,255,.17) inset, 0 16px 34px -22px rgba(122,122,130,.45);
}
/* —— 23.4 读数条：7px 在深底上太细，且缺内阴影、看不出「槽」感 —— */
.angle-track{height:9px;box-shadow:0 1px 2px rgba(0,0,0,.45) inset}
/* —— 23.5 视口底栏：与上方画布分开的一道高光 —— */
.view3d-foot,.scope-bar{box-shadow:0 1px 0 rgba(255,255,255,.06) inset}

/* —— 23.6 面板头图标：从「一块灰方」到「品牌方」（全站 8 个 .panel-head 均可见）——
   原 `background:rgba(255,255,255,.045)` + `--hair` 边， svg 走 currentColor 而没有颜色声明
   → 继承了正文强度的淡灰，整个图标片读起来像「未加载」。 */
.panel-head .ico{
  background-image:linear-gradient(150deg,rgba(122,122,130,.44),rgba(122,122,130,.20) 62%,rgba(122,122,130,.10));
  border-color:rgba(170,170,180,.34);
  color:#EDE4FF;
  box-shadow:0 1px 0 rgba(255,255,255,.20) inset, 0 10px 22px -14px rgba(122,122,130,.85);
}

/* —— 23.7 浅色主题覆盖（必须：否则白上白）—— */
[data-theme="light"] .angle,
[data-theme="light"] .prov-detail .pd-block,
[data-theme="light"] .prog,
[data-theme="light"] .prov-row,
[data-theme="light"] .summary-line,
[data-theme="light"] .about-meta > div,
[data-theme="light"] .about-note{
  background-image:linear-gradient(158deg,#FCFCFD 0%,#F5F5F7 58%,#EFEFF2 100%);
  border-color:rgba(0,0,0,.10);
  box-shadow:0 1px 0 rgba(255,255,255,.95) inset, 0 12px 28px -24px rgba(0,0,0,.24);
}
[data-theme="light"] .panel-head .ico{
  background-image:linear-gradient(150deg,rgba(122,122,130,.17),rgba(122,122,130,.11) 62%);
  border-color:rgba(122,122,130,.28);
  color:#5B21B6;
  box-shadow:0 1px 0 rgba(255,255,255,.92) inset;
}
[data-theme="light"] .angle-track{box-shadow:0 1px 2px rgba(28,22,70,.16) inset}
[data-theme="light"] .view3d-foot,[data-theme="light"] .scope-bar{box-shadow:0 1px 0 rgba(255,255,255,.55) inset}


/* =========================================================
   §24 首屏与浮层（2026-09-20 v4）
   =========================================================
   本轮把「没看过的表面」补齐：登录/注册壳（新用户看到的**第一屏**）
   与两个浮层（.modal-card / .ai-chat）。
   实测截图：.auth-hero 虽然带品牌渐变（.22/.14/.12），但在深底上却读不出来，
   左右两栏几乎同色，整个首屏看起来就是「一块黑」。
   同样采用纯追加 + 同特异性后置；需要加额外阴影的地方用 `var(--shadow-1),<新增>` **叠加**，
   而不是直接覆盖（否则会扑掉玻璃底的内高光）。 */

/* —— 24.1 登录左栏：品牌底纹（极光 + 蓝图网格） ——
   .auth-hero 已有 position:relative，且 ::before 未被占用（全站仅 .glass / .view3d 等用了伪元素，已逐个核对）。 */
.auth-hero::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background-image:
    radial-gradient(120% 92% at 10% 4%,rgba(170,170,180,.36),rgba(170,170,180,0) 62%),
    radial-gradient(95% 75% at 102% 104%,rgba(122,122,130,.22),rgba(122,122,130,0) 60%),
    linear-gradient(rgba(170,170,180,.090) 1px,transparent 1px),
    linear-gradient(90deg,rgba(170,170,180,.090) 1px,transparent 1px);
  background-size:auto,auto,34px 34px,34px 34px;
  background-position:0 0,0 0,-1px -1px,-1px -1px;
}
.auth-hero > *{position:relative;z-index:1}

/* —— 24.2 两栏之间的品牌竖分界线 —— */
.auth-panel{position:relative}
.auth-panel::before{
  content:"";position:absolute;left:0;top:7%;bottom:7%;width:1px;pointer-events:none;
  background:linear-gradient(180deg,transparent,rgba(170,170,180,.45) 22%,rgba(122,122,130,.32) 72%,transparent);
}

/* —— 24.3 壳体：外发光 + 顶缘高光（原值必须重述，因为 box-shadow 是整体覆盖） —— */
.auth-shell{
  box-shadow:0 50px 120px -40px rgba(0,0,0,.70),
             0 0 110px -36px rgba(122,122,130,.62),
             0 0 1px 0 rgba(170,170,180,.35),
             0 1px 0 rgba(255,255,255,.14) inset;
}
[data-theme="light"] .auth-shell{
  box-shadow:0 40px 100px -40px rgba(28,22,70,.34),
             0 0 90px -40px rgba(122,122,130,.30),
             0 1px 0 rgba(255,255,255,.95) inset;
}

/* —— 24.4 第三方登录按钮：补材质（原仅 hair 边 + 透明底） —— */
.oauth-btn{
  background-image:linear-gradient(158deg,rgba(255,255,255,.078),rgba(255,255,255,.012) 58%,rgba(122,122,130,.075));
  border-color:rgba(255,255,255,.16);   /* 原值是 --hair(.15)；写 .125 会反而削弱描边 */
  box-shadow:0 1px 0 rgba(255,255,255,.10) inset, 0 10px 22px -16px rgba(0,0,0,.90);
}
.oauth-btn:hover{
  border-color:rgba(122,122,130,.45);
  box-shadow:0 1px 0 rgba(255,255,255,.18) inset, 0 16px 30px -14px rgba(122,122,130,.50);
}
[data-theme="light"] .oauth-btn{
  background-image:linear-gradient(158deg,#FFFFFF,#F6F3FF 62%);
  border-color:rgba(28,22,70,.14);
  box-shadow:0 1px 0 rgba(255,255,255,.95) inset, 0 8px 18px -14px rgba(28,22,70,.30);
}

/* —— 24.5 模态：叠加一圈品牌外发光（保留 --shadow-1 的内高光） —— */
/* ⚠️ 修正记录：初版写成 `box-shadow:var(--shadow-1),<发光>` —— 错的。
   实测：.modal-card 的阴影来自 §13 的**共享玻璃规则**
   `.nav-inner,.modal-card,.ctl-dock,.search-results,.acc,.inno-item,...{box-shadow:var(--lg-rim),var(--lg-prism),var(--lg-edge),var(--lg-drop)}`，
   而不是 --shadow-1。直接覆盖会把整套液态玻璃装裱（边框+棱镜+边缘+落影）抑掉。
   正确做法：**原栈原样重述 + 末尾追加**。用 var(--lg-*)而非字面量，浅/深两套自动跟随。 */
.modal-card{box-shadow:var(--lg-rim),var(--lg-prism),var(--lg-edge),var(--lg-drop),0 0 100px -44px rgba(122,122,130,.60)}
/* —— 24.6 AI 对话浮窗：顶缘高光（此处 specificity(0,1,0) 低于浅色覆盖(0,2,0)，
   故**只在深色生效**，不会破坏浅色原有的定制阴影 —— 这正是期望行为。 */
.ai-chat{
  box-shadow:0 50px 120px -40px rgba(0,0,0,.72),
             0 0 0 1px rgba(170,170,180,.12) inset,
             0 1px 0 rgba(255,255,255,.13) inset;
}


/* =========================================================
   §25 绿色渐变文字：补齐 §22.3 漏掉的那一半（2026-09-20 v5）
   =========================================================
   全站只有两个「渐变文字」类：.gradient-text 与 .gradient-green。
   §22.3 只改了前者，于是：
     · 深色：12 页里 10 页标题带白起笔高光 + 光晕，
             分析页 / 建模页没有 → 不一致；
     · 浅色：--grad-green 是 #22C55E → #86EFAC，尾端浅绿压在近白底上
             **几乎不可见**。实测（像素法，WCAG 相对亮度）：
               分析页标题  左半 1.94:1 / 右半 1.56:1   ← 大字 AA 需 ≥ 3:1
               对照 about 页标题（§22.3 已修） 7.00:1 / 4.63:1

   手法与 §22.3 完全一致：**只覆盖 background-image**，不动全局 --grad-green 令牌
   （.btn-green / .timeline-fill / .side-avatar / 速度胶囊还在用它 —— 那些是「面」不是「字」）。
   光晕用 filter:drop-shadow，不用 text-shadow（background-clip:text 下后者不可见）。 */
.gradient-green{
  background-image:linear-gradient(115deg,#FFFFFF 0%,#D9FBE7 26%,#6EE7A0 56%,#22C55E 100%);
  filter:drop-shadow(0 6px 26px rgba(34,197,94,.42));
}
[data-theme="light"] .gradient-green{
  /* 三个 stop 在白底上分别约 7.9:1 / 5.4:1 / 3.3:1，全部达到大字 AA */
  background-image:linear-gradient(115deg,#065F2E 0%,#0F7A38 40%,#16A34A 100%);
  filter:drop-shadow(0 3px 12px rgba(21,128,61,.18));
}
/* 打印：页内原有 @media print 已把 .gradient-text,.gradient-green 改成实色绿
   （background:none !important 会盖掉本节的渐变），但滤镜不在那条里，需单独收。 */
@media print{
  .gradient-green{filter:none !important}
}

/* =========================================================
   §26 报告导出页：「报告内容一览」面板（2026-09-20 v6）
   =========================================================
   /dashboard/report 全站唯一「像没做完」的页面（只有 hero + 两个导出按钮）。
   补一块页内一览，内容与 reportText() 的八个章节逐一对应。

   ★ 表面材质直接用 class="card glass"，复用全站共享的那条
     `.glass,.card.glass,.glass.sheen{background-image:...!important;border:...;box-shadow:var(--lg-*)}`
     所以本块**不碰** background-image / border / box-shadow ——
     一碰就会把液态玻璃栈（镜面上缘 + 棱镜 + 虹彩边 + 落影）整条抹掉。
     同理不用 ::before/::after（.glass 已占用两个伪元素）。

   七枚“分项评分”贴片复用现成的 metric.* 键（无新增指标名）。 */

.exp-preview{max-width:880px;margin:0 auto clamp(26px,3vw,38px)}
.exp-preview-head{
  display:flex;align-items:center;gap:14px;padding-bottom:18px;
  border-bottom:1px solid var(--hair-soft);
}
.exp-preview-ico{
  width:46px;height:46px;flex:none;border-radius:var(--r-sm);display:grid;place-items:center;
  color:#EDE4FF;                                  /* §4p I：svg 走 currentColor，必须显式给色 */
  background-image:linear-gradient(140deg,#7A7A82,#7A7A82);
  box-shadow:0 1px 0 rgba(255,255,255,.30) inset, 0 12px 26px -14px rgba(122,122,130,.85);
}
.exp-preview-ico .ic{width:22px;height:22px}
.exp-preview-txt{display:flex;flex-direction:column;gap:4px;min-width:0}
.exp-preview-txt b{font-size:var(--fs-6);font-weight:750;letter-spacing:-.02em;color:#F2F0FF}
.exp-preview-txt span{font-size:var(--fs-2);color:var(--text-3)}

.exp-outline{
  list-style:none;margin:20px 0 0;padding:0;
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2px 30px;
}
.exp-outline li{
  display:flex;align-items:center;gap:11px;padding:9px 0;
  border-bottom:1px dashed var(--hair-soft);
}
.exp-outline i{
  font-style:normal;flex:none;width:27px;height:22px;border-radius:var(--r-xs);
  display:grid;place-items:center;font-size:var(--fs-1);font-weight:700;color:#EDE4FF;
  background-image:linear-gradient(140deg,rgba(122,122,130,.92),rgba(122,122,130,.58));
  box-shadow:0 1px 0 rgba(255,255,255,.22) inset;
}
.exp-outline span{font-size:var(--fs-3);color:var(--text-2);min-width:0}

.exp-metrics{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  margin-top:20px;padding-top:18px;border-top:1px solid var(--hair-soft);
}
.exp-metrics-label{
  margin-right:6px;font-size:var(--fs-1);letter-spacing:.14em;
  text-transform:uppercase;color:var(--text-3);
}
.exp-chip{
  font-size:var(--fs-2);padding:6px 12px;border-radius:var(--r-pill);color:var(--text-2);
  border:1px solid var(--hair);
  background-image:linear-gradient(158deg,rgba(255,255,255,.075),rgba(255,255,255,.012) 62%,rgba(122,122,130,.10));
  box-shadow:0 1px 0 rgba(255,255,255,.10) inset;
}

/* —— 浅色主题：这块面板就在白底页面上，不改就是「白上白」（同 §23.7） —— */
[data-theme="light"] .exp-preview-txt b{color:#1B1146}
[data-theme="light"] .exp-preview-ico{
  background-image:linear-gradient(140deg,#6D28D9,#DB2777);
  box-shadow:0 1px 0 rgba(255,255,255,.55) inset, 0 10px 22px -14px rgba(109,40,217,.55);
}
[data-theme="light"] .exp-outline i{
  color:#FFFFFF;background-image:linear-gradient(140deg,#6D28D9,#DB2777);
}
[data-theme="light"] .exp-outline li{border-bottom-color:rgba(28,22,70,.10)}
[data-theme="light"] .exp-chip{
  color:#2B2158;border-color:rgba(28,22,70,.145);
  background-image:linear-gradient(158deg,#FFFFFF,#F4F1FF 62%);
  box-shadow:0 1px 0 rgba(255,255,255,.95) inset, 0 6px 14px -12px rgba(28,22,70,.30);
}

@media (max-width:760px){ .exp-outline{grid-template-columns:1fr} }

/* 打印：屏幕介绍性面板，纸面上只增墨不增信息 */
@media print{ .exp-preview{display:none !important} }

/* =========================================================
   §27 可读性补丁（2026-09-21）
   ① .scope-corner（分析页 HUD 右上角读数：肘/膝角度、球体追踪）
      原为 rgba(255,255,255,.42)，实测对比度 4.07:1 低于 WCAG AA 4.5；
      改用站内已有的 .48 档（rgba(248,250,252,.48)，实测 4.81:1）。
      纯追加块 + 同特异性 + 源序在后 即生效，不动原规则行。 */
.scope-corner{color:rgba(248,250,252,.48)}

/* =========================================================
   §43 投篮命中庆祝特效（2026-09-28）
   进球（judgeShot → made.made）时触发：全屏彩带雨 + 命中徽章弹跳。
   纯 CSS + 轻量 JS 生成粒子，零外部依赖；尊重「减少动效」。
   ========================================================= */
#confetti-root{position:fixed;inset:0;z-index:var(--z-float);pointer-events:none;overflow:hidden}
.confetti-piece{
  position:absolute;top:-24px;border-radius:2px;
  will-change:transform,opacity;
  animation:confettiFall var(--cf-dur,3.2s) cubic-bezier(.22,.7,.36,1) var(--cf-delay,0s) forwards;
}
@keyframes confettiFall{
  0%{transform:translate3d(0,-24px,0) rotate(0deg) scale(1);opacity:1}
  100%{transform:translate3d(var(--cf-drift,0px),110vh,0) rotate(var(--cf-rot,540deg)) scale(.85);opacity:0}
}
/* 命中徽章：命中结论处一个轻微弹跳 + 绿色光晕脉冲，强化「进球」反馈 */
.predict-made b{display:inline-block}
.predict-made.is-made b{animation:madeBounce .6s var(--ease-spring) both}
@keyframes madeBounce{
  0%{transform:scale(.5);opacity:0}
  60%{transform:scale(1.18)}
  100%{transform:scale(1);opacity:1}
}
@media (prefers-reduced-motion:reduce){
  .confetti-piece{animation:none;display:none}
  .predict-made.is-made b{animation:none}
}

/* —— 21.12 玻璃质感细滚动条 ——
   默认滚动条（Windows/Chrome 的粗灰条）和整体液态玻璃语言严重冲突。
   · Chrome/Edge/Safari：::-webkit-scrollbar 细条 + 半透明胶囊拇指 + hover 提亮
     （不设标准属性 scrollbar-width/color —— Chrome 121+ 里标准属性会覆盖 webkit
      规则，且可能干扰 macOS 原生 overlay 滚动条的自动隐藏行为）
   · Firefox：用 @supports(-moz-appearance) 隔离出 FF-only 块，套 scrollbar-color
   · 浅色主题换深色拇指；轨道全透明，不抢内容注意力
   · 只改颜色与宽度，不碰 scrollbar-gutter / overflow 布局，零回归风险 */
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{
  background:rgba(255,255,255,.14);
  border:2px solid transparent;border-radius:8px;background-clip:padding-box;
}
::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.28)}
::-webkit-scrollbar-corner{background:transparent}
[data-theme="light"] ::-webkit-scrollbar-thumb{background:rgba(15,23,42,.2)}
[data-theme="light"] ::-webkit-scrollbar-thumb:hover{background:rgba(15,23,42,.34)}
@supports (-moz-appearance:none){
  *{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent}
  [data-theme="light"] *{scrollbar-color:rgba(15,23,42,.22) transparent}
}

/* =============================================================================
 * 模块 6.5：视频库 + 排行榜
 * 风格对齐既有 Apple 黑白灰体系：--hair 描边、--glass-* 底、--apple-blue 主操作。
 * 动效只用 transform/opacity（合成友好），不做 width/height 动画。
 * ========================================================================== */
#library{ padding:clamp(56px,8vw,96px) 0; }
#library .lib-grid{
  display:grid; gap:var(--sp-4,16px);
  grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
  margin-top:24px;
}
.lib-card{
  background:linear-gradient(180deg,var(--glass-top),var(--glass-bot));
  border:1px solid var(--hair);
  border-radius:18px;
  padding:20px;
  backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
}
.lib-card-board{ margin-top:16px; }
.lib-card-head{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:6px; }
.lib-card-head h3{ font-size:var(--fs-4,17px); font-weight:600; letter-spacing:-.01em; }
.lib-card-desc{ font-size:var(--fs-2,13px); color:var(--text-3); line-height:1.6; margin-bottom:14px; }

.lib-gate{
  display:flex; align-items:center; gap:10px;
  margin-top:20px; padding:12px 16px;
  border:1px solid var(--hair); border-radius:12px;
  background:var(--glass-bot);
  font-size:var(--fs-2,13px); color:var(--text-2);
}
.lib-gate .ic{ width:18px; height:18px; flex:none; color:var(--apple-blue); }

/* 条目卡片 */
.lib-items{ display:flex; flex-direction:column; gap:10px; }
.lib-item{
  display:flex; align-items:center; gap:12px;
  padding:10px 12px;
  border:1px solid var(--hair-soft); border-radius:12px;
  background:rgba(255,255,255,.03);
  transition:transform .18s cubic-bezier(.4,0,.2,1), border-color .18s, background .18s;
}
.lib-item:hover{ transform:translateY(-1px); border-color:var(--hair); background:rgba(255,255,255,.05); }
.lib-item-thumb{
  width:56px; height:36px; flex:none; border-radius:7px;
  background:#000 center/cover no-repeat;
  border:1px solid var(--hair-soft);
  display:flex; align-items:center; justify-content:center;
}
.lib-item-thumb .ic{ width:16px; height:16px; color:var(--text-3); }
.lib-item-main{ flex:1; min-width:0; }
.lib-item-name{
  font-size:var(--fs-2,13px); font-weight:500; color:var(--text);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.lib-item-sub{ font-size:var(--fs-1,11px); color:var(--text-4); margin-top:2px; }
.lib-item-actions{ display:flex; gap:6px; flex:none; }
.lib-empty{
  padding:18px 12px; text-align:center;
  font-size:var(--fs-2,13px); color:var(--text-4);
  border:1px dashed var(--hair-soft); border-radius:12px;
}

/* 状态徽标 */
.chip{
  font-size:var(--fs-1,11px); font-weight:600; letter-spacing:.02em;
  padding:3px 8px; border-radius:999px; white-space:nowrap;
}
.chip-free{ background:rgba(34,197,94,.16); color:var(--green-hi); }
.chip-lock{ background:rgba(255,255,255,.08); color:var(--text-3); }
.chip-open{ background:rgba(0,113,227,.20); color:#7ab8ff; }

/* 上传 */
.lib-upload{ margin-bottom:14px; }
.btn-block{ width:100%; justify-content:center; }
.lib-up-progress{ display:flex; align-items:center; gap:10px; margin-top:10px; }
.prog-track{
  flex:1; height:4px; border-radius:999px;
  background:rgba(255,255,255,.10); overflow:hidden;
}
.prog-fill{
  height:100%; width:0%;
  background:var(--apple-blue); border-radius:999px;
  transition:width .2s linear;
}
.lib-hint{ font-size:var(--fs-1,11px); color:var(--text-4); margin-top:10px; line-height:1.55; }

/* 排行榜 */
.board{ display:flex; flex-direction:column; gap:6px; }
.board-row{
  display:grid; grid-template-columns:44px 1fr auto; align-items:center; gap:12px;
  padding:11px 14px; border-radius:11px;
  background:rgba(255,255,255,.03);
  border:1px solid transparent;
}
.board-row.is-me{ border-color:rgba(0,113,227,.45); background:rgba(0,113,227,.10); }
.board-rank{
  font-size:var(--fs-3,15px); font-weight:700; color:var(--text-4);
  font-variant-numeric:tabular-nums;
}
.board-row:nth-child(1) .board-rank{ color:#FFD60A; }
.board-row:nth-child(2) .board-rank{ color:#C7C7CC; }
.board-row:nth-child(3) .board-rank{ color:#CD7F32; }
.board-who{ font-size:var(--fs-2,13px); color:var(--text); }
.board-meta{ font-size:var(--fs-1,11px); color:var(--text-4); margin-top:2px; }
.board-score{
  font-size:var(--fs-4,17px); font-weight:700; color:var(--green-hi);
  font-variant-numeric:tabular-nums;
}

/* 播放弹层 */
.lib-modal{
  position:fixed; inset:0; z-index:9000;
  background:rgba(0,0,0,.72);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  display:flex; align-items:center; justify-content:center; padding:24px;
  animation:libFade .2s ease;
}
.lib-modal[hidden]{ display:none; }
@keyframes libFade{ from{ opacity:0 } to{ opacity:1 } }
.lib-modal-card{
  width:min(880px,100%); max-height:90vh; overflow:auto;
  background:#0b0b0d; border:1px solid var(--hair);
  border-radius:18px; box-shadow:var(--shadow-glow);
}
.lib-modal-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:16px 18px; border-bottom:1px solid var(--hair-soft);
  position:sticky; top:0; background:#0b0b0d; z-index:1;
}
.lib-modal-head h3{ font-size:var(--fs-4,17px); font-weight:600; }
.lib-modal-body{ padding:18px; }
#libPlayer{
  width:100%; max-height:62vh; border-radius:12px;
  background:#000; display:block;
}
.lib-modal-meta{ font-size:var(--fs-2,13px); color:var(--text-3); margin-top:12px; line-height:1.7; }

.btn-ghost{
  background:transparent; border:1px solid var(--hair);
  color:var(--text-2); border-radius:9px; padding:5px 12px;
  font-size:var(--fs-1,12px); cursor:pointer;
  transition:transform .16s, border-color .16s, color .16s;
}
.btn-ghost:hover{ transform:translateY(-1px); border-color:var(--hair); color:var(--text); }

@media (max-width:640px){
  .board-row{ grid-template-columns:34px 1fr auto; gap:9px; padding:10px; }
  .lib-modal{ padding:12px; }
  .lib-modal-body{ padding:12px; }
}
