/* ============================================================
   ⚠⚠ 先读这一段：本文件踩过四次同一类坑，四次都是不同的人
   在不同页面上独立撞到的，所以不是谁粗心，是这类写法本身会咬人。
   共同点：**简写属性或默认值，会把你没写的那一维静默改掉，而且不报错。**

   1. 简写的特异度会压过容器类
      .lang-work main{padding:30px 0 90px} 是 (0,1,1)，压过 .wrap-w 的 (0,1,0)，
      于是 <main class="wrap-w"> 的左右留白被清成 0。改用 padding-block。
   2. margin 简写会抹掉 margin-inline
      .rail 的出血依赖 margin-inline 负值，谁写 margin:14px 0 0 想加个上边距，
      出血就没了。只能用 margin-block-start。
   3. grid 轨道的 1fr，最小值是 auto 不是 0
      .split 窄屏写 1fr，里面的 table.t{min-width:640px} 会把整列顶到 640。
      要写 minmax(0,1fr)。
   4. flex/grid 子项的最小尺寸默认是 min-content
      .tw 里的 min-width 会顺着 .tw→.panel-bd→.panel→.grid→.col 一路顶穿，
      overflow-x:auto 只在容器真被限宽时才生效。要显式 min-width:0。
   3 和 4 是同一个机制的两面：一个是轨道的最小值，一个是子项的最小值。

   另：共享件 .rail / .dock 读 --gut 计算出血，页面覆盖容器 padding 时
   必须同步覆盖 --gut，否则轨道会比容器宽（实测 641~720px 之间宽 10px）。
   ============================================================ */

/* ============================================================
   CERYé PRO ： 分销平台设计系统
   基底取自苹果官网实际用色；字体走系统栈，不依赖网络字体
   两种界面语言共用一套令牌：
     .lang-show  展示型（大留白、大字、单栏堆叠）
     .lang-work  工具型（信息密度高、细线分区、表格与状态）
   ============================================================ */

:root{
  color-scheme:light;

  /* 底色 */
  --w:#FFFFFF;
  --g:#F5F5F7;          /* 苹果实际使用的浅灰 */
  --g2:#FBFBFD;
  --g3:#EDEDF0;
  --dark:#1A1A1C;

  /* 文字灰阶 ： 整条梯度下移了一档，因为原来的后两档在浅底上根本读不出来。
     实测对比度（白底 / #F5F5F7 灰底），正文门槛 4.5:1：
       旧 --ink3 #8E8E93 → 3.26 / 2.99   不及格
       旧 --ink4 #AEAEB2 → 2.21 / 2.03   远不及格
     而这两档正是全站说明文字、提示语、占位符、次要标签的唯一颜色，
     字号又都在 12~15px。B2B 采购人群普遍四十往上，手机在户外看，这是硬伤。
     ⚠ 无障碍审计建议 --ink3 用 #6B6B70（5.30），但那比当时的 --ink2（5.07）
     还深，会把灰阶倒过来。所以不是单点替换，是整条重排：
       --ink2 7.41/6.81  --ink3 5.07/4.66（最浅的可读档）  --ink4 3.62/3.33
     --ink4 从此只给非文本用：分隔线、图标描边、禁用态箭头。
     要读的字一律不许用 --ink4。 */
  --ink:#1D1D1F;
  --ink2:#55555A;
  --ink3:#6E6E73;
  --ink4:#86868B;

  /* 线 */
  --line:rgba(0,0,0,.09);
  --line2:rgba(0,0,0,.055);
  --line3:rgba(0,0,0,.14);

  /* 品牌：沿用官网绿，加深至白底可承载白字 */
  --brand:#2F7350;
  --brand-h:#255C40;
  --brand-l:#63B07A;
  --brand-w:rgba(47,115,80,.07);
  --brand-b:rgba(47,115,80,.24);

  /* 语义色（与品牌色分开，不作强调色使用）。
     判据不是「在白底上够不够」，而是「在自己那层 8~10% 的浅底上够不够」：
     页面一定会把同色文字放在同色浅底上（.chip-warn、pro-desk 的预览条都是）。
     实测旧值：ok 4.25、warn 4.11，都卡在 4.5 以下；bad 5.27、info 5.55 本来就够。
     所以只压深 ok 与 warn 两档，另两档不动，避免无谓的视觉漂移。
     压深后放白字也更稳（--ok 7.41、--warn 6.52）。 */
  --ok:#146238;    --ok-w:rgba(28,124,74,.09);
  --warn:#845304;  --warn-w:rgba(154,98,6,.10);
  --bad:#B3261E;   --bad-w:rgba(179,38,30,.08);
  --info:#2B5C9B;  --info-w:rgba(43,92,155,.08);

  /* 形状：全站两档圆角，不混用。
     --r-lg 在手机上收到 22px（见文末窄屏段）：26px 的圆角在 390px 宽的卡片上
     占比太大，看起来发圆发软；苹果手机端的卡片正是 16~22 这一档。 */
  --r:14px;
  --r-lg:26px;
  --r-pill:980px;

  /* ── 字号刻度（全部走变量，不在各处写死 px）────────────────
     字体工程师的 assets/pro-type.css 会排在本文件之后覆盖这几个值，
     所以这里是唯一的定义点。新增字号请加变量，不要在规则里直接写 px。
       --fs-note 注释：表头、hint、chip、分组标题
       --fs-ui   密控件：小按钮、筛选、导航、表单标签
       --fs-base 标准：输入框、按钮、表格、次级正文
       --fs-body 正文：正文、卡片标题、h4
       --fs-lead 引导：.lead、h3
     再往上是展示型大标题，中间故意留空。 */
  --fs-note:12px;
  --fs-ui:13px;
  --fs-base:15px;
  --fs-body:17px;
  --fs-lead:21px;
  --fs-h3:21px;
  --fs-h2:clamp(25px,3.2vw,32px);
  --fs-h1:clamp(30px,4.2vw,40px);
  /* 展示型（招募页、玩法页）：标题才是主角 */
  --fs-show-h1:clamp(40px,6.2vw,80px);
  --fs-show-h2:clamp(31px,4.4vw,54px);
  --fs-show-h3:24px;
  /* 上限从 25 收到 24：原来 --fs-show-h3 是 24、这条是 25，差 1px 等于没有区别，
     却在刻度上多占一档。24 也正好落在实测的字号阶梯上（…19·21·24·28…）。 */
  --fs-show-lead:clamp(19px,2.1vw,24px);
  /* 工具型（工作台、商城、询价）：标题压回控件尺度。
     下限从 25 抬到 28：clamp 的下限就是手机上的实际值，390px 时 3.2vw 只有
     12.5px，一直取到下限。25px 的标题在手机上第一眼太弱：苹果手机端
     进页面第一眼永远是一个 28~34px 的大标题，而不是小字加一堆卡片。
     这样不必再为手机单写一条媒体查询，下限本身就是手机刻度。 */
  --fs-work-h1:clamp(28px,3.2vw,33px);
  --fs-work-h2:clamp(22px,2.6vw,26px);
  --fs-work-h3:17px;

  /* 影：极软弥散，带底色倾向，不用纯黑。
     每档第一层是半像素「接触影」：它才是层次感的来源：
     不加深整体阴影，只让元素贴住底面，白底上的白卡才不会飘。 */
  --sh-1:0 .5px 1px rgba(20,28,22,.05),0 1px 2px rgba(20,28,22,.03),0 6px 16px -8px rgba(20,28,22,.07);
  --sh-2:0 .5px 1px rgba(20,28,22,.055),0 2px 6px rgba(20,28,22,.035),0 14px 36px -14px rgba(20,28,22,.10);
  --sh-3:0 .5px 1px rgba(20,28,22,.06),0 4px 12px rgba(20,28,22,.045),0 34px 76px -32px rgba(20,28,22,.16);

  /* 焦点/校验环：单独一档，不复用 --brand-w（那是底色，7% 做环几乎看不见） */
  --ring:0 0 0 3.5px rgba(47,115,80,.17);
  --ring-bad:0 0 0 3.5px rgba(179,38,30,.14);

  --ease:cubic-bezier(.32,.72,0,1);
  --ease-o:cubic-bezier(.22,1,.36,1);
  /* 时长分档：手指按下去要立刻有反应，滚动入场才慢。
     以前整站一律 .3~.42s，换色也要等三分之一秒，摸上去像卡了一下。 */
  --t-1:.15s;   /* 换色、换边框：微交互 */
  --t-2:.24s;   /* 位移、阴影、小尺寸变化 */
  --t-3:.4s;    /* 抽屉、面板一类的大形变 */
  --t-in:.72s;  /* 滚动入场 */

  /* 页面宽度：导航与正文共用同一组值，保证 logo 与内容左边缘严格对齐 */
  --page-w:1040px;
  --page-p:24px;
  --nav-h:50px;
  --font:-apple-system,BlinkMacSystemFont,"SF Pro SC","SF Pro Display","SF Pro Text",
         "PingFang SC","HarmonyOS Sans SC","Microsoft YaHei","Noto Sans CJK SC",sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono","JetBrains Mono",Menlo,Consolas,monospace;
}

*{box-sizing:border-box}
html{
  -webkit-text-size-adjust:100%;scroll-behavior:smooth;
  /* 吸顶导航会盖住锚点目标和「Tab 到屏幕外元素时的自动滚动」，
     焦点环被固定元素遮住是清单里的 MUST。scroll-padding-top 让所有
     滚动定位都自动让开导航条，手机上 --nav-h 变 56 也会跟上。 */
  scroll-padding-top:calc(var(--nav-h) + 12px);
}
/* 可点元素统一两件事：
   touch-action:manipulation 去掉移动端双击缩放，顺带消除 300ms 点击延迟；
   点按高亮换成品牌色的极淡一层，不设成 transparent：
   把系统反馈整个删掉等于在触摸设备上丢掉「我按到了」这条线索。 */
a,button,summary,label,input,select,textarea,[role="button"],[tabindex]{
  touch-action:manipulation;
  -webkit-tap-highlight-color:rgba(47,115,80,.1);
}
/* 标题作为锚点目标时同样要让开导航 */
h1,h2,h3,h4{scroll-margin-top:calc(var(--nav-h) + 16px)}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0;background:var(--w);color:var(--ink);font-family:var(--font);
  font-size:var(--fs-body);line-height:1.6;letter-spacing:normal;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}
/* 键盘焦点：双色环。
   offset 从 3px 收到 2px：面板与卡片都是 overflow:hidden，3px 的环在贴边
   元素上会被裁掉半圈，看起来像没聚焦。
   单色绿环在浅底上够（vs 白 5.69、vs #F5F5F7 5.23），但压在深色控件上不够：
   绿 #2F7350 vs --ink #1D1D1F 只有 2.96，低于 3:1 的门槛；压在半透明深底上
   更低到 1.26。所以外面再套一圈白色 box-shadow：
   浅底上白圈看不见、绿环起作用；深底上白圈起作用（白 vs --ink 是 16.83）。
   一个环同时管两种底，不必再为每种深色控件单独覆盖。 */
:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:5px}
/* 深色控件上换成「白环贴身 + 深色细线在外」。
   ⚠ 没有把白环无差别加到全局 :focus-visible 上：那样会用 box-shadow 顶掉
   .btn-g、.side a[aria-current] 这些元件自己的接触影，一聚焦阴影就没了。
   浅底上 outline-offset:2px 本来就隔出一圈页面底色，绿环两侧都是浅色，
   实测 5.23~5.69 是够的；只有元件本身是深色时才需要反转。
   页面级新增的深色控件请自行加进这个选择器列表。 */
.dark :focus-visible,.toast :focus-visible,.sheet :focus-visible,
.dock :focus-visible,.btn-p:focus-visible,.pill[aria-pressed="true"]:focus-visible{
  outline-color:#fff;box-shadow:0 0 0 4px rgba(20,28,22,.62);
}
[hidden]{display:none!important}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
.num{font-variant-numeric:tabular-nums}

/* ── 容器 ─────────────────────────────────
   每个容器把自己的左右留白写进 --gut。横滑轨道 .rail 和底部常驻栏 .dock
   读这个值，就能自动和所在容器的边缘对齐，页面不用再手填数字。 */
.wrap{--gut:24px;max-width:1040px;margin:0 auto;padding:0 var(--gut)}
.wrap-w{--gut:28px;max-width:1280px;margin:0 auto;padding:0 var(--gut)}
.narrow{--gut:24px;max-width:760px;margin:0 auto;padding:0 var(--gut)}
@media(max-width:640px){.wrap,.narrow{--gut:20px}.wrap-w{--gut:18px}}

/* ── 排版 ─────────────────────────────────
   ⚠ 字号只有五档，中间不许再插值。
   改之前这个文件在 11.5~17 之间挤了 11 个不同字号
   （11.5/12/12.5/13/13.5/14/14.5/15/16/16.5/17），每档只差半号到一号，
   眼睛分不出主次，整页就是一片灰糊：「一看就是后台管理系统」主要来源于此，
   而不是来源于配色。五档如下，每档有明确分工：
     12px  注释层：表头、hint、chip、分组标题
     13px  密控件：小按钮、筛选胶囊、导航、表单标签
     15px  标准层：输入框、按钮、表格、次级正文
     17px  正文层：正文、卡片标题、h4
     21px  引导层：.lead、h3
   再往上直接跳到展示型大标题（40~80px），中间**故意留空**。
   苹果的层次就是这么来的：不是靠多给几档，是靠敢空掉中间。 */
/* ⚠ 字距：中文页面**不要负字距**，这是实测结论不是审美偏好。
   苹果中文页实测：12/14/17px 正文一律 normal，24/28px 标题反而是正值
   +0.007~0.009em；理想、蔚来全站 0。三个中文站零负字距。
   压缩 CSS 里那些 -.022em 在中文页一条都没生效：**它们是 SF Pro Text 的
   字体补偿，不是通用审美**。中文字形本来就方正等宽，再收紧只会糊成一团，
   在微软雅黑上尤其明显，而老板正是在 Windows 上看的。
   西文专属的元素（logo、EN 切换）保留正值字距，那本来就是给西文的。 */
h1,h2,h3,h4{margin:0;font-weight:var(--fw-semibold,600);letter-spacing:.006em;line-height:1.14;text-wrap:balance}
h1{font-size:var(--fs-h1)}
h2{font-size:var(--fs-h2)}
h3{font-size:var(--fs-h3);line-height:1.3;letter-spacing:.005em}
h4{font-size:var(--fs-body);line-height:1.35;letter-spacing:normal}
p{margin:0}
/* 展示型：标题才是主角。字重保持 600（不是 700：700 会显得廉价），
   靠字号和负字距拉开，字越大字距收得越紧。 */
.lang-show h1{font-size:var(--fs-show-h1);letter-spacing:.008em;line-height:1.06}
.lang-show h2{font-size:var(--fs-show-h2);letter-spacing:.007em;line-height:1.1}
.lang-show h3{font-size:var(--fs-show-h3);letter-spacing:.006em}
/* 工具型：标题不是主角，压回控件尺度。
   这一档原来是每个页面自己写 h1{font-size:clamp(25px,...)}，
   于是新加的 pro-order.html 漏写就继承了展示型的大标题。
   收到这里之后各页不必再各写一遍。 */
.lang-work h1{font-size:var(--fs-work-h1);letter-spacing:.005em}
.lang-work h2{font-size:var(--fs-work-h2)}
.lang-work h3{font-size:var(--fs-work-h3);letter-spacing:normal}
.lead{font-size:var(--fs-body);color:var(--ink2);line-height:1.6;letter-spacing:normal;text-wrap:pretty}
.lang-show .lead{font-size:var(--fs-show-lead);line-height:1.5}
.muted{color:var(--ink2)}
.faint{color:var(--ink3)}
.tiny{font-size:var(--fs-note);line-height:1.65}
.note{font-size:var(--fs-note);color:var(--ink3);line-height:1.7}
.sec-head{max-width:680px;margin:0 0 56px}
.sec-head h2{margin-bottom:16px}
.center{text-align:center;margin-left:auto;margin-right:auto}
@media(max-width:640px){.sec-head{margin-bottom:40px}.btns{gap:12px}}

/* 展示型区块：大留白。104 → 120，苹果的区块间距在 80~140 之间，
   我们原来偏紧，几个区块挤在一起就没有「一屏一件事」的从容。 */
.lang-show section{padding:120px 0}
.lang-show .sec-tight{padding:88px 0}
.sec-grey{background:var(--g)}
@media(max-width:700px){.lang-show section{padding:72px 0}.lang-show .sec-tight{padding:56px 0}}

/* 工具型页面：贴着工作区，不留大白。
   底色从 --g2 换成 --g：#FBFBFD 与白面板只差 4 级灰，面板等于没有边界，
   整页就是「白底加一条细线」的那种平。#F5F5F7 正是苹果放白卡片的底色，
   不动阴影，层次立刻出来。 */
.lang-work{background:var(--g);--page-w:1280px;--page-p:28px}
/* ⚠ 这里必须是 padding-block，不许改回 padding 简写。
   简写 padding:30px 0 90px 的特异度是 (0,1,1)，会压过 .wrap-w 的 (0,1,0)，
   于是只要页面写成 <main class="wrap-w">，main 实际拿到的左右留白就是 0。
   连锁反应更糟：.rail 靠 margin-inline 负值出血到容器边缘，父容器没有留白时
   它就凭空比视口宽 2×gut（香型库实测文档 426 对视口 390，差的正好是 2×18）。
   已经有四个页面各自踩进来过。改用 padding-block 之后 main 完全不碰左右方向，
   .wrap / .wrap-w 写在 main 上就正常生效，陷阱从根上没了；
   已经套了内层 div 的页面也不受影响（内层自己有留白，外层 0，总和不变）。 */
.lang-work main{padding-block:30px 90px}

/* ── 导航（苹果式贴顶毛玻璃窄条） ─────────── */
.nav{
  position:sticky;top:0;z-index:100;
  background:rgba(255,255,255,.72);
  -webkit-backdrop-filter:saturate(180%) blur(20px);
  backdrop-filter:saturate(180%) blur(20px);
  border-bottom:1px solid var(--line2);
}
.nav-in{
  /* 导航是常驻元素，宽度必须在所有页面一致。
     早先让它读 --page-w，结果展示页 1040、工具页 1280，
     一点菜单导航就变宽，间距跟着跳。 */
  max-width:1280px;margin:0 auto;padding:0 28px;height:var(--nav-h);
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  /* 菜单要绝对居中，这里必须是定位参照。
     注意 .nav-panel 是 .nav 的直接子元素、不在 .nav-in 里，不受影响。 */
  position:relative;
}
.nav-logo{font-size:var(--fs-body);font-weight:600;letter-spacing:.04em;white-space:nowrap}
.nav-logo em{font-style:normal;color:var(--ink3);font-weight:400;margin-left:8px;font-size:var(--fs-ui);letter-spacing:.06em}
/* ⚠ 这里改过三次，别再改回 flex:1 + space-evenly。
   那种写法下菜单宽度 =「总宽 − logo − 右侧」，而右侧一直在变：
   未登录没有等级徽章、登录后才出现；徽章有 分销商/核心分销商/战略分销商
   三种宽度；按钮文字从「登录」变「工作台」；pro-login 根本没有徽章元素。
   实测同为 1440 宽：pro.html 间距 110px、pro-shop 93px、pro-desk 85px ：
   每切一次页面菜单就位移，老板看到的就是这个。
   绝对居中 + 固定 gap 是唯一能让菜单位置与左右内容彻底无关的做法。
   铺满整条再 justify-content:center，而不是 left:50%+translateX(-50%)：
   后者遇到奇数宽度会落在半个像素上，文字发虚。 */
.nav-links{
  position:absolute;left:0;right:0;top:0;bottom:0;
  /* 间距放在 padding 里而不是 gap 里：gap 撑开的是空白、点不着，
     padding 撑开的是链接自己、手指和鼠标都点得到。
     实测桌面导航链接原来只有 44×29（gap:34 + padding:4px 2px），
     换成 gap:20 + padding:10px 7px 之后视觉间距不变（20+7+7=34），
     点击区变成约 58×44。这个套路对所有横向标签条都适用。 */
  display:flex;align-items:center;justify-content:center;gap:20px;
  font-size:var(--fs-ui);color:var(--ink2);
  /* 这一层铺满了整条导航，会盖住 logo 和右侧按钮，必须把点击放行 */
  pointer-events:none;
}
.nav-links a{transition:color var(--t-1) var(--ease-o);position:relative;padding:12px 7px;white-space:nowrap;pointer-events:auto}
.nav-links a:hover{color:var(--ink)}
.nav-links a:active{color:var(--ink2)}
/* 当前页只加深颜色，绝不加粗：加粗就会变宽，变宽就会推移其他项。
   苹果自己也是只加深不加粗。 */
.nav-links a[aria-current="page"]{color:var(--ink)}
.nav-right{display:flex;align-items:center;gap:14px}
/* 等级不再做成胶囊徽章。
   这是全站曝光最高的一个元素，原来是「灰底胶囊 + 绿色粗体」：
   一个彩色药丸钉在导航里，苹果的导航上不会有这种东西。
   改成一行安静的小字：等级信息照常在，但它不再和登录按钮抢。 */
.nav-tier{
  font-size:var(--fs-note);color:var(--ink3);background:none;border:0;
  padding:0;white-space:nowrap;letter-spacing:.01em;
}
.nav-tier b{color:var(--ink2);font-weight:var(--fw-semibold,600)}

/* 语言切换：两段式小开关，不用地球图标，中英各自可读 */
.langsw{display:flex;background:var(--g);border:1px solid var(--line2);border-radius:var(--r-pill);padding:2px}
.langbtn{
  border:none;background:none;cursor:pointer;color:var(--ink3);
  font-size:var(--fs-note);letter-spacing:.04em;line-height:1;padding:5px 9px;
  border-radius:var(--r-pill);
  transition:background var(--t-1) var(--ease-o),color var(--t-1) var(--ease-o),
             box-shadow var(--t-2) var(--ease-o);
}
.langbtn:hover{color:var(--ink2)}
.langbtn:active{color:var(--ink)}
.langbtn[aria-pressed="true"]{background:var(--w);color:var(--ink);font-weight:var(--fw-semibold,600);box-shadow:var(--sh-1)}
.langbtn:focus-visible{outline-offset:1px}

/* 窄屏折叠按钮与展开面板 */
.nav-burger{
  display:none;border:none;background:none;cursor:pointer;padding:8px 6px;
  width:34px;height:34px;align-items:center;justify-content:center;flex:none;
}
.nav-burger i{display:block;width:17px;height:1.5px;background:var(--ink);border-radius:2px;position:relative;transition:transform var(--t-3) var(--ease)}
.nav-burger i::before,.nav-burger i::after{
  content:"";position:absolute;left:0;width:17px;height:1.5px;background:var(--ink);border-radius:2px;
  transition:transform var(--t-3) var(--ease),opacity var(--t-1) var(--ease-o);
}
.nav-burger i::before{top:-5.5px}
.nav-burger i::after{top:5.5px}
.nav-burger[aria-expanded="true"] i{background:transparent}
.nav-burger[aria-expanded="true"] i::before{transform:translateY(5.5px) rotate(45deg)}
.nav-burger[aria-expanded="true"] i::after{transform:translateY(-5.5px) rotate(-45deg)}
.nav-panel{
  display:none;position:absolute;left:0;right:0;top:100%;
  background:rgba(255,255,255,.96);
  -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  border-bottom:1px solid var(--line2);box-shadow:var(--sh-2);
  padding:10px 18px 18px;
  /* 菜单原来是硬切的。加 allow-discrete 让它能从 display:none 淡进来；
     不支持这两个特性的浏览器会整条丢掉 transition，回到硬切：就是现在的样子，不会坏。 */
  opacity:0;transform:translateY(-8px);
  transition:opacity var(--t-2) var(--ease-o),transform var(--t-2) var(--ease-o),
             display var(--t-2) allow-discrete;
}
.nav-panel.on{display:block;opacity:1;transform:none}
@starting-style{.nav-panel.on{opacity:0;transform:translateY(-8px)}}
.nav-panel a{
  /* 抽屉是手机上的主导航，行高按 44px 触摸目标给足 */
  display:flex;align-items:center;min-height:44px;padding:10px 2px;font-size:var(--fs-base);
  color:var(--ink2);border-bottom:1px solid var(--line2);
  transition:color var(--t-1) var(--ease-o);
}
.nav-panel a:hover,.nav-panel a:active{color:var(--ink)}
/* 与桌面一致：当前页只加深颜色，不加粗。竖排虽然不会推移，
   但「当前 = 更深而不是更粗」是一条要贯穿全站的规则，两处必须一样。 */
.nav-panel a[aria-current="page"]{color:var(--ink)}
.nav-panel a:last-child{border-bottom:none}

/* 次要项在中等宽度先收起，保证主项不被挤断 */
@media(max-width:1180px){
  .nav-opt{display:none}
  /* 菜单固定居中之后，中等宽度只能靠收窄字距让它继续待得下 */
  .nav-links{gap:26px}
}
/* 汉堡的临界点从 900 提到 1120。
   菜单绝对居中之后，它两侧的余量 =(导航内宽 − 菜单宽)/2 − 右侧宽。
   右侧最宽的一档实测 293px（等级徽章 +「工作台」按钮），
   在 960 宽时余量是负的，菜单会直接压到按钮上。
   实测临界：英文菜单比中文宽，1081px 时只剩 14px 余量，太贴；
   提到 1120 后最紧的一档（英文 + 工作台页）仍有 30px 以上。
   与其把间距压到看不出呼吸，不如早一步收进汉堡：苹果自己也在 1024 收。 */
@media(max-width:1120px){
  .nav-links{display:none}
  .nav-burger{display:flex}
}
@media(max-width:900px){
  .nav-links{display:none}
  .nav-in{padding:0 18px;gap:12px}
  .nav-burger{display:flex}
  .nav{position:sticky}
  /* 导航条从 50 抬到 56：里面要塞下 44px 的按钮和汉堡，
     50px 只剩 3px 上下留白，挤得发闷。--nav-h 是令牌，
     吸顶筛选条 / .side / scroll-margin 都读它，会一起跟上。 */
  :root{--nav-h:56px}
  .nav-logo{display:flex;align-items:center;min-height:44px}
}
/* 汉堡与中英切换的触摸尺寸跟着**设备**走，不跟宽度走。
   汉堡是手机上唯一的导航入口，原来 34×34，比 44×44 少四成面积；
   中英切换更小，只有约 21×21（padding 5 + line-height 1 的 11.5px 字），
   而且两个按钮紧挨着没有间隙，点「中」很容易点到「EN」。
   之前只有 pro-quote.html 自己补过一条，其余七页都没有：收进共享层，
   页面里那条重复的可以删了。 */
@media(hover:none),(pointer:coarse){
  .nav-burger{width:44px;height:44px}
  .langbtn{min-height:44px;padding-top:0;padding-bottom:0;display:flex;align-items:center;min-width:44px;justify-content:center}
  .langsw{gap:2px}
}
@media(max-width:900px){.nav-burger{margin-right:-5px}}
/* ⚠ 手机导航塞不下五件套，这里是实测数据不是估计。
   未登录时不溢出，所以一直没被发现：#navTier 那时是 hidden 的。
   登录态最坏情况实测（藏掉导航即回落，对照实验确认是导航撑的）：
     中文·战略分销商·工作台   360px → 文档 401（溢出 41）
     英文·Strategic Partner   360px → 文档 435（溢出 75）
   右侧那 349px 拆开是：langsw 96 + nav-tier 96 + 按钮 94 + 汉堡 44 + 间隙 24。
   其中 96px 的语言切换正是 44px 触摸规则撑出来的：修一个指标撑破另一个。

   取舍：**等级徽章在 480px 以下让位**，不是压缩它。
   理由是这四件里只有它是「信息」，其余三件都是「操作」：
   语言切换、登录/工作台、汉堡，少一个都断功能。
   等级在工作台页正文里本来就有一处，手机顶栏不是它必须出现的地方。
   让位之后 360px 英文最坏情况还剩 11px 余量（实测）。 */
/* 断点是实测定的不是估的：商城在「登录 + 英文 + 购物车 12 件」下，
   等级徽章一出现就要 619px 才放得下（工作台要 550）。原来定 479 太低，
   480~619 这一段仍然溢出。取 680 留出余量。 */
@media(max-width:679px){
  .nav-tier{display:none}
  /* 兜底：页面随时会往右侧塞东西（商城的购物车入口就在这儿），
     导航必须**结构上不可能**把页面顶破。
     ⚠ 第一版我写成 .nav-right{flex-shrink:0}，结果反而锁死了溢出：
     实测 320px 商城，logo 被压到宽度 0（品牌整个消失）而右侧那组 310px
     拒绝收缩，仍然溢出 17px。收缩要分优先级，不是一刀切禁止：
       汉堡、主按钮、语言切换 = 功能底线，不许缩；
       logo 留 48px 下限，至少认得出是谁；
       其余（页面自己加的）先让位。 */
  .nav-in{min-width:0}
  .nav-logo{min-width:48px;overflow:hidden;text-overflow:ellipsis}
  .nav-right{min-width:0;flex-shrink:1}
  /* 只给 min-width:0 还不够：项目本身会缩，里面的字却照样溢出去，
     scrollWidth 一样破。可让位的那些必须连内容一起裁掉。
     用 :not() 把三件功能底线排除在外，这样页面以后新增什么元素，
     自动成为「先让位」的那一个，不用我回来改名单。 */
  .nav-right>*:not(.btn):not(.langsw):not(.nav-burger){min-width:0;overflow:hidden}
  .nav-burger,.nav-right .btn,.langsw{flex:none}
}
/* ≤400px（含 320 的小屏安卓）：语言切换的 44×44 是这一档最大的一块。
   ⚠ 这里把它的**宽度**放到 38，高度仍然是 44。
   取舍写明：横向溢出是一票否决项，而 38×44 仍远高于 WCAG 2.5.8 的
   24×24（AA），只是没到 2.5.5 的 44×44（AAA）。在 320px 上两害相权，
   宁可让语言切换窄 6px，也不能让整页横向滚动。 */
/* ⚠ 这里的 38 是**有意的取舍，不是手滑**，改之前请先读完。
   为什么是 38：320px 上导航要放下 logo 48 + 语言 + 主按钮 94(Dashboard)
     + 汉堡 44 + 间隙 18 + 内边距 28。语言切换每边 44 时总和超过视口，
     整页出现横向滚动。38 是让这一档不溢出的最大值。
   放弃了哪条：WCAG 2.5.5（AAA）的 44×44。
     仍然满足 2.5.8（AA）的 24×24，而且高度保持 44，只窄 6px。
     取舍依据：横向滚动是一票否决项，AAA 不是。
   什么条件下改回 44：只要语言切换不再占据顶栏：比如它被移进汉堡面板、
     或者改成单个图标按钮：这一条就该整段删掉。
   范围：只给 ≤360 的小屏安卓。390（iPhone 主流）等级徽章已在 ≤679
     让位、空间够了，不该连坐，实测 361~400 在登录+英文最坏情况下不溢出。 */
@media(max-width:360px){
  .langbtn{min-width:38px}
  .nav-in{padding:0 14px;gap:6px}
  .nav-right{gap:6px}
}
@media(max-width:430px){
  .nav-in{gap:8px}
  .nav-right{gap:8px}
  .nav-logo em{display:none}
  .nav-right .btn-sm{padding-left:13px;padding-right:13px}
  /* ⚠ 这里原来写 min-width:40px，把上面那条触摸规则的 44 又打回去了：
     自己修好的东西被自己下一条覆盖掉。量尺在 360/390 报 .langbtn 是 40x44，
     740 那档反而 0 失败，正好指认是这条宽度覆盖（≤430 才生效）。
     触摸目标是**宽高都要够**，不是只看高度。这里只收内边距，不动 min-width。 */
  .langbtn{padding-left:4px;padding-right:4px}
}

/* ── 按钮 ───────────────────────────────── */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-size:var(--fs-base);font-weight:var(--fw-text,400);padding:12px 24px;border-radius:var(--r-pill);
  border:1px solid transparent;background:none;cursor:pointer;white-space:nowrap;
  /* 换色走 --t-1（.15s），位移与阴影走 --t-2（.24s）。
     原来全部 .34s，点下去要等三分之一秒才变色，摸着发黏。 */
  transition:background var(--t-1) var(--ease-o),color var(--t-1) var(--ease-o),
             border-color var(--t-1) var(--ease-o),
             transform var(--t-2) var(--ease-o),box-shadow var(--t-2) var(--ease-o);
}
.btn:active{transform:scale(var(--pm-press,.97));transition-duration:var(--t-1)}
/* 忙碌态：页面只需给按钮加 aria-busy="true"，不要改文案。
   ⚠ 清单里这条值得单独说：把「提交」换成「提交中…」有两个代价，
   一是按钮宽度会跳，二是丢掉「我刚按的是哪个」这条线索。
   所以这里保留原文案，只在左侧插一个转圈，并用 padding-left 给它让位，
   宽度变化只有 22px 且是可预期的。
   用属性选择器而不是新 class：aria-busy 本来就是这个语义，读屏也认。 */
.btn[aria-busy="true"]{position:relative;padding-left:calc(24px + 22px);pointer-events:none}
.btn-sm[aria-busy="true"]{padding-left:calc(16px + 20px)}
.btn[aria-busy="true"]::before{
  content:"";position:absolute;left:22px;top:50%;margin-top:-7px;
  width:14px;height:14px;border-radius:50%;
  border:1.5px solid currentColor;border-top-color:transparent;
  opacity:.85;animation:btn-spin .7s linear infinite;
}
.btn-sm[aria-busy="true"]::before{left:15px}
@keyframes btn-spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){
  /* 不能只是停掉转圈，那样就没有「正在忙」的提示了：改成呼吸 */
  .btn[aria-busy="true"]::before{animation:btn-pulse 1.4s ease-in-out infinite}
  @keyframes btn-pulse{0%,100%{opacity:.85}50%{opacity:.3}}
}
/* 保留 pointer-events:none：去掉它 hover 样式会盖到禁用态上 */
.btn:disabled,.btn[aria-disabled="true"]{opacity:.4;pointer-events:none;box-shadow:none;cursor:not-allowed}
.btn-p{background:var(--brand);color:#fff}
.btn-p:hover{background:var(--brand-h);box-shadow:0 2px 10px -5px rgba(47,115,80,.55)}
.btn-p:active{background:#1F4C35;box-shadow:none}
.btn-s{color:var(--brand);border-color:var(--brand-b)}
.btn-s:hover{background:var(--brand-w);border-color:var(--brand)}
.btn-s:active{background:rgba(47,115,80,.13)}
/* --g 填充在工具页会消失（工作台底色本身就是 --g）。
   改成「白底 + 一条实线」，在白面板与灰底上都立得住，也不跟 .btn-s 撞。 */
/* 接触影不是装饰：白底白按钮挨着白色输入框时，光靠一条同色描边分不出
   「能按的」和「能填的」，一层 1px 的落影就把它抬成了一个控件。 */
.btn-g{background:var(--w);color:var(--ink);border-color:var(--line3);
  box-shadow:0 1px 1.5px -1px rgba(20,28,22,.14)}
.btn-g:hover{background:var(--g);border-color:var(--ink4)}
.btn-g:active{background:var(--g3);box-shadow:none}
.btn-t{color:var(--ink2);padding-left:12px;padding-right:12px}
/* 同理，文字按钮的 hover 底不能用 --g：换成半透明灰，压在任何底色上都看得见 */
.btn-t:hover{color:var(--ink);background:rgba(20,28,22,.055)}
.btn-t:active{background:rgba(20,28,22,.09)}
.btn-sm{font-size:var(--fs-ui);padding:8px 16px}
.btn-lg{font-size:var(--fs-body);padding:15px 32px}
.btn-block{width:100%}
/* 手机上一切可点的东西不低于 44px。
   实测 390px：.btn-sm 只有 39px、语言切换 22px、汉堡 34px，全部不达标，
   指头点下去经常落空。用 max-width 而不是只用 hover:none ： 后者在部分
   安卓浏览器与开了触摸屏的笔记本上并不成立，靠它保证不了。 */
@media(max-width:900px),(hover:none){
  .btn{min-height:44px}
  .btn-sm{min-height:44px;padding-top:10px;padding-bottom:10px}
}
/* 按钮内嵌圆形图标：图标不裸露在文字旁 */
.btn .dot{
  width:25px;height:25px;border-radius:50%;flex:none;
  display:flex;align-items:center;justify-content:center;font-size:var(--fs-note);line-height:1;
  background:rgba(255,255,255,.18);
  transition:transform var(--t-2) var(--ease-o),background var(--t-1) var(--ease-o);
}
/* 中性按钮里的圆点原来也是绿的：品牌色不该出现在一个中性控件上。
   只有本身就是品牌色的 .btn-s 留绿，其余走中性灰。 */
.btn-s .dot{background:var(--brand-w)}
.btn-g .dot,.btn-t .dot{background:rgba(20,28,22,.06)}
.btn:hover .dot{transform:translate(3px,-1px) scale(1.05)}
.btn:active .dot{transform:translate(1px,0) scale(1)}
.btns{display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.center .btns{justify-content:center}

/* ── 卡片：双层壳（外托 + 内芯），同心圆角 ──
   ⚠ 卡片一律不描边。
   「1px 边框 + 一层阴影」是一眼能认出来的模板做法：真实的纸片没有描边，
   它的边界来自和底面的明度差。所以规矩定死：白卡只放在 #F5F5F7 灰底上，
   边界由 10 级灰的明度差产生；阴影只留一层极软的接触影，而且带底色色相
   （rgba(20,28,22,…) 是偏冷的墨绿灰，不是纯黑），不承担划分边界的职责。 */
.card{
  background:var(--w);border-radius:var(--r-lg);
  box-shadow:0 1px 2px -1px rgba(20,28,22,.07),0 10px 30px -18px rgba(20,28,22,.12);
  overflow:hidden;
}
.shell{
  background:var(--g);border-radius:var(--r-lg);padding:6px;
}
.shell>.core{
  background:var(--w);border-radius:calc(var(--r-lg) - 6px);
  box-shadow:0 1px 2px -1px rgba(20,28,22,.07);
  overflow:hidden;
}
.pad{padding:28px 32px}
.pad-lg{padding:40px}
@media(max-width:640px){.pad,.pad-lg{padding:24px 20px}}

/* ── 面板（工具型：白卡浮在灰底上，不描边） ── */
/* 核实过：.panel 只出现在 .lang-work（底色 #F5F5F7）的页面上，
   展示型页面一处都没用。所以去掉边框不会让它在白底上消失。 */
.panel{
  background:var(--w);border:0;border-radius:var(--r-lg);
  box-shadow:0 1px 2px -1px rgba(20,28,22,.07);
  /* 表头吸顶坏在两层，这是第二层。
     overflow:hidden 本身就是一个滚动容器，sticky 找到它就停住了，
     所以光把 .tw 还原成 visible 会以为修好了、其实没有。
     overflow:clip 照样裁切（圆角裁得住），但**不产生滚动容器**，
     sticky 于是能一路找到视口。
     两行并排写是刻意的降级路径：不认识 clip 的浏览器丢掉第二行、
     退回 hidden，就是今天的样子，不会变坏。 */
  overflow:hidden;
  overflow:clip;
}
.panel-hd{
  padding:20px 24px;border-bottom:1px solid var(--line2);
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
}
/* 标题区与正文的层次靠字号和字色拉开，不靠底色也不靠加重的线 */
.panel-hd h3{font-size:var(--fs-body);letter-spacing:normal;color:var(--ink)}
.panel-hd .right{margin-left:auto;display:flex;gap:10px;align-items:center}
.panel-bd{padding:24px}
.panel-bd.flush{padding:0}
@media(max-width:640px){
  .panel-hd,.panel-bd{padding-left:18px;padding-right:18px}
  .panel-hd{padding-top:15px;padding-bottom:15px;gap:10px}
  /* 右侧一组按钮整体换行，不要拆开断在两行；
     margin-left:auto 保留：动作留在右边缘才读得出是动作，不然像副标题 */
  .panel-hd .right{flex-wrap:wrap}
}

/* ── 标签 / 状态 ─────────────────────────
   ⚠ 状态不再做成彩色胶囊。
   订单表的状态列原来是「已报价 / 已成交 / 已沟通 / 已打样」四颗不同颜色的
   实心胶囊并排，那是最典型的模板仪表盘长相：一屏里五六种彩色药丸，
   眼睛先看到颜色、再看到内容。苹果的做法是一颗小圆点带色、文字保持墨色。
   所以：中性 .chip 仍是安静的灰底标签（它是标签不是状态）；
   语义态去掉底色与描边，只让前面那颗点带颜色，文字回到正常墨色。
   颜色少了，信息反而更快读到。 */
.chip{
  display:inline-flex;align-items:center;gap:6px;
  font-size:var(--fs-note);line-height:1;padding:5px 10px;border-radius:var(--r-pill);
  background:var(--g);color:var(--ink2);border:0;white-space:nowrap;
}
.chip-ok,.chip-warn,.chip-bad,.chip-info{
  background:none;padding-left:0;padding-right:0;gap:7px;
  color:var(--ink);font-weight:400;
}
/* 没有 .led 子元素时，用 ::before 补出那颗点：状态必须有颜色以外的形状线索 */
.chip-ok::before,.chip-warn::before,.chip-bad::before,.chip-info::before{
  content:"";width:6px;height:6px;border-radius:50%;flex:none;
}
.chip-ok::before{background:var(--ok)}
.chip-warn::before{background:var(--warn)}
.chip-bad::before{background:var(--bad)}
.chip-info::before{background:var(--info)}
/* ⚠ .chip-brand 不是状态。查过用法：它被当成内容标签用：香型家族
   （「木质」「东方」）和产品名。给内容标签加状态圆点会读错意思，
   所以它保持填充标签的样子，只是把品牌绿换成中性灰：
   一个香调名不需要用品牌色喊出来。 */
.chip-brand{background:var(--g);color:var(--ink);font-weight:400}
/* 状态前的小圆点只在真的表示状态时使用。
   页面若已经自带 .led，就把 ::before 让出来，避免出现两颗点。 */
.chip .led{width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.chip-ok:has(.led)::before,.chip-warn:has(.led)::before,
.chip-bad:has(.led)::before,.chip-info:has(.led)::before{display:none}

/* 可点选的筛选按钮 */
.pill{
  font-size:var(--fs-ui);padding:8px 15px;border-radius:var(--r-pill);cursor:pointer;
  background:var(--w);color:var(--ink2);border:1px solid var(--line2);
  /* transition:all 会把 aria-pressed 切换时的一切都带上，容易抖；写清楚要动哪几个 */
  transition:background var(--t-1) var(--ease-o),color var(--t-1) var(--ease-o),
             border-color var(--t-1) var(--ease-o),transform var(--t-1) var(--ease-o);
  white-space:nowrap;
}
.pill:hover{color:var(--ink);border-color:var(--line3)}
.pill:active{transform:scale(var(--pm-press,.97))}
.pill[aria-pressed="true"]{background:var(--ink);color:#fff;border-color:var(--ink)}
.pill[aria-pressed="true"]:hover{background:#000;border-color:#000}
.pill:disabled,.pill[aria-disabled="true"]{opacity:.4;pointer-events:none;cursor:not-allowed}
@media(max-width:900px),(hover:none){.pill{min-height:44px;padding-top:11px;padding-bottom:11px}}
.pills{display:flex;flex-wrap:wrap;gap:8px}
/* 手机上筛选条横着滑出屏幕，不换行、不折叠；换行会把一屏吃掉一半。
   两端渐隐提示还能滑；滚动条在触摸设备上本来就不常驻，这里靠渐隐。
   ⚠ 语义边界：.pills 只给「筛掉一些」的筛选条用。
   「必须从中选一个才能往下走」的选项组不要用它：横滑会把后面的选项
   推到屏幕外，用户看不见就选不到。配置器里少看见一个选项，
   和筛选条里少看见一个标签，后果完全不同。那种场景请让它换行。 */
@media(max-width:640px){
  /* 同 .side：不出血，只渐隐。筛选条被塞在各种容器里，拿不准父级留白。 */
  .pills{
    --rail-fade:16px;
    flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;
    -webkit-overflow-scrolling:touch;
    scroll-snap-type:x proximity;scroll-padding-inline:2px;
    scrollbar-width:none;
    /* ⚠ 渐隐**只做右端**，左端不做。
       轨道不出血（父级留白拿不准），第一颗胶囊从 x≈0 开始，左端若也画渐隐，
       它整颗就坐在 0→16px 的透明斜坡上：未选中是白底看不出来，
       一旦选中变深色，左边圆角被削平成一块黑疙瘩。
       而且左端渐隐本来就不传递信息：滚动位置在 0 时左边没有被藏起来的内容，
       画渐隐是在暗示一件不存在的事。右端才是真的在说「后面还有」。 */
    -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - var(--rail-fade)),transparent 100%);
    mask-image:linear-gradient(90deg,#000 calc(100% - var(--rail-fade)),transparent 100%);
  }
  .pills::-webkit-scrollbar{height:0}
  .pills>*{flex:none;scroll-snap-align:start}
}

/* ── 表单 ───────────────────────────────── */
.field{display:flex;flex-direction:column;gap:7px;margin-bottom:18px}
.field>label{font-size:var(--fs-ui);font-weight:var(--fw-semibold,600);color:var(--ink);transition:color var(--t-1) var(--ease-o)}
.field .hint{font-size:var(--fs-note);color:var(--ink3);line-height:1.55}
/* .field 是 flex 列，所以能用 order 把错误行强行提到提示语前面：
   报错必须紧贴控件，隔着一行说明再报错，眼睛会先读到说明、再回头找错。
   页面里 .hint 和 .err 的书写顺序不一致也没关系，这里统一。 */
.field .err{order:1}
.field .hint{order:2}
/* 错误文案紧跟在控件下方，和 .hint 同一位置同一字号：
   报错时替换提示语，不要两条同时挤在一起。前面加一颗实心点，
   不靠颜色也能一眼看出这行是错误（色弱用户）。 */
.field .err{
  font-size:var(--fs-note);color:var(--bad);line-height:1.55;font-weight:var(--fw-semibold,600);
  display:flex;align-items:baseline;gap:6px;
}
.field .err::before{
  content:"";width:5px;height:5px;border-radius:50%;background:currentColor;
  flex:none;transform:translateY(-1px);
}
/* 控件出错时标签一起变色，整块 field 作为一个整体报错 */
.field:has([aria-invalid="true"])>label{color:var(--bad)}
.input,.select,.textarea{
  width:100%;background-color:var(--w);border:1px solid var(--line3);border-radius:var(--r);
  padding:12px 14px;font-size:var(--fs-base);line-height:1.5;
  transition:border-color var(--t-1) var(--ease-o),box-shadow var(--t-1) var(--ease-o),
             background-color var(--t-1) var(--ease-o);
}
/* 占位符是 --ink4 在本文件里唯一的「文字」用途，是有意的：占位符不是内容，
   需要和真正填进去的字区分开，3.62:1 也是苹果自己占位符的量级。
   除此之外任何要读的字都不许用 --ink4：pro-desk 的 .todo-hd 就踩了这条，
   axe 已经报出来了，已写进报告。 */
.input::placeholder,.textarea::placeholder{color:var(--ink4)}
.input:hover,.select:hover,.textarea:hover{border-color:var(--ink4)}
/* 焦点环原来用 --brand-w（7% 不透明度），在白底上几乎看不出来，
   键盘用户根本不知道光标在哪。换成单独的 --ring。 */
.input:focus,.select:focus,.textarea:focus{
  outline:none;border-color:var(--brand);box-shadow:var(--ring);
}
/* 控件自带焦点环，不再叠一圈 outline */
.input:focus-visible,.select:focus-visible,.textarea:focus-visible{outline:none}
.input[aria-invalid="true"],.select[aria-invalid="true"],.textarea[aria-invalid="true"]{
  border-color:var(--bad);box-shadow:var(--ring-bad);
}
.textarea{min-height:110px;resize:vertical}
.select{appearance:none;padding-right:40px;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink3) 50%),linear-gradient(135deg,var(--ink3) 50%,transparent 50%);
  background-position:calc(100% - 19px) 51%,calc(100% - 14px) 51%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;
}
/* Windows 上原生下拉的选项列表会跟随系统色，和页面对不上，必须显式给底色和字色 */
.select option{background-color:var(--w);color:var(--ink)}
.select:hover{background-image:linear-gradient(45deg,transparent 50%,var(--ink2) 50%),linear-gradient(135deg,var(--ink2) 50%,transparent 50%)}
.select:focus{background-image:linear-gradient(45deg,transparent 50%,var(--brand) 50%),linear-gradient(135deg,var(--brand) 50%,transparent 50%)}
/* 数字与日期用等宽数字，改数量时字宽不跳 */
.input[type=number],.input[type=date],.input[type=tel]{font-variant-numeric:tabular-nums}
/* 禁用态：原来完全没写，禁用的输入框和能填的长得一模一样。
   放在 hover/focus 之后，靠源码顺序压过它们。 */
.input:disabled,.select:disabled,.textarea:disabled,
.input[readonly],.textarea[readonly]{
  background-color:var(--g);border-color:var(--line2);color:var(--ink3);
  -webkit-text-fill-color:var(--ink3);box-shadow:none;cursor:not-allowed;
}
.select:disabled{background-image:linear-gradient(45deg,transparent 50%,var(--ink4) 50%),linear-gradient(135deg,var(--ink4) 50%,transparent 50%)}
.input[readonly],.textarea[readonly]{cursor:text}
.check{
  display:flex;gap:11px;align-items:flex-start;font-size:var(--fs-base);line-height:1.6;cursor:pointer;
  transition:color var(--t-1) var(--ease-o);
}
.check:hover{color:var(--ink)}
.check input{margin:3px 0 0;width:17px;height:17px;accent-color:var(--brand);flex:none;cursor:pointer}
.check input:focus-visible{outline-offset:2px}
.check:has(input:disabled){color:var(--ink3);cursor:not-allowed}
.check input:disabled{cursor:not-allowed}
.row{display:grid;grid-template-columns:1fr 1fr;gap:0 16px}
@media(max-width:600px){.row{grid-template-columns:1fr}}
/* ⚠ iOS 在 font-size<16px 的输入框上聚焦会自动放大整页，而且**放大后回不去**。
   这条原来挂在 @media(max-width:640px) 上，是错的：iPhone 横过来是 740×360，
   宽度 740px 不匹配 640 这条规则，输入框退回 15px，照样被放大；
   768px 平板竖屏同理。
   所以必须跟着**设备**走而不是跟着宽度走：hover:none / pointer:coarse
   命中的是「没有精确指针的触摸设备」，跟横竖屏和窗口宽度都无关。
   16px 是功能底线不是风格选择，故意不走 --fs-* 变量：
   字体工程师覆盖刻度时不应该把这里一起改小。 */
@media(hover:none),(pointer:coarse){
  .input,.select,.textarea{font-size:16px;padding:12px 14px}
}
@media(max-width:640px){
  .field{margin-bottom:16px}
}

/* ── 表格（工具型核心） ───────────────────
   ⚠ 已知的自相矛盾（本轮只修了一半，另一半要页面配合，见下）：
   table.t 写了 min-width:640px，th 又写了 position:sticky;top:0，
   但 .tw 只写了 overflow-x:auto ：按规范一轴非 visible、另一轴就计算成
   auto，于是 .tw 自己成了滚动容器；它没有高度上限，所以 th 永远贴在 .tw
   顶部，**sticky 等于从来没生效过**。外面 .panel 的 overflow:hidden 又加了
   一层，纯 CSS 修不动。
   真正的解法是窄屏不要表格：下面那段把表格塌成一行一卡，
   靠 td[data-label] 把列头搬到每个单元格前面。
   它用 :has(td[data-label]) 把关：**页面没加 data-label 就不会触发**，
   保持现在的横向滚动，不会出现一堆没有列头的裸数字。 */
/* 第一层：.tw 只写 overflow-x:auto 时，按规范另一轴算成 auto，
   .tw 自己就成了滚动容器，sticky 被锁在里面、又没有高度上限，等于不生效。
   但直接改成 visible 会让放不下的宽表格没法横滚、被 .panel 裁掉，
   所以按**实测**分档，不是拍脑袋：
   9 列宽表（管理后台那张的列数）加真实内容压测：
     1440/1280/1024/940px：容器 1224/1224/968/884，表格同宽，放得下
     820px 起：表格 868 > 容器 764，必须横滚
   940 正好也是 .split 塌成单栏的点，两者对齐。 */
/* min-width:0 不是可有可无：flex/grid 子项的最小尺寸默认是 min-content，
   table.t 的 min-width:640px 会顺着 .tw→.panel-bd→.panel→.grid→.col 一路顶上去，
   把整列撑成 640+，而 overflow-x:auto 只有在容器真的被限宽时才起作用。
   实测工作台手机端因此文档宽 707 对视口 390：整页横滚，表格自己反倒不滚。
   写死 0 之后这条链就断了。 */
.tw{overflow-x:visible;min-width:0}
@media(max-width:940px){.tw{overflow-x:auto;-webkit-overflow-scrolling:touch}}
/* 横向滚动条本身就是「右边还有内容」的提示，默认那条太粗太丑，
   细化成一根半透明胶囊；桌面端不滚动时它不出现。 */
.tw{scrollbar-width:thin;scrollbar-color:rgba(20,28,22,.22) transparent}
.tw::-webkit-scrollbar{height:9px}
.tw::-webkit-scrollbar-track{background:transparent}
.tw::-webkit-scrollbar-thumb{
  background:rgba(20,28,22,.18);border-radius:var(--r-pill);
  border:3px solid transparent;background-clip:content-box;
}
.tw:hover::-webkit-scrollbar-thumb{background:rgba(20,28,22,.3);background-clip:content-box}
table.t{border-collapse:collapse;width:100%;min-width:640px;font-size:var(--fs-base)}
table.t th{
  text-align:left;font-weight:var(--fw-text,400);font-size:var(--fs-note);color:var(--ink2);white-space:nowrap;
  letter-spacing:.015em;
  padding:13px 16px;background:var(--g2);border-bottom:1px solid var(--line);
  /* 吸顶要停在导航下沿而不是视口顶端，否则贴上去就被 50px 高的导航盖住。
     --nav-h 在手机上会变成 56，这里读令牌，自动跟上。
     ⚠ 只有 .tw 与 .panel 两层都不是滚动容器时这条才生效，见上面两段注释。 */
  position:sticky;top:var(--nav-h);z-index:1;
}
table.t td{padding:15px 16px;border-bottom:1px solid var(--line2);vertical-align:middle;line-height:1.5}
table.t tbody tr{transition:background var(--t-1) var(--ease-o)}
/* 原来 hover 用 --g2（#FBFBFD），压在白行上只差 4 级灰，等于没反馈。
   不加斑马线：密度已经够，斑马线会和 hover 打架；靠细线分行 + 清楚的 hover。 */
table.t tbody tr:hover{background:var(--g)}
table.t tbody tr:last-child td{border-bottom:none}
table.t td.strong{color:var(--ink);font-weight:var(--fw-semibold,600)}
table.t td.r,table.t th.r{text-align:right}
table.t .sub{display:block;font-size:var(--fs-note);color:var(--ink3);margin-top:3px}
/* 表格直接铺在 .panel-bd.flush 里时，首列从 16px 起排，
   面板标题却从 26px 起排，左边缘对不齐。把首末列补到与 .panel-hd 同值。
   ⚠ 改 .panel-hd / .panel-bd 的横向内边距时，这两行要跟着一起改。 */
.panel-bd.flush table.t th:first-child,.panel-bd.flush table.t td:first-child{padding-left:24px}
.panel-bd.flush table.t th:last-child,.panel-bd.flush table.t td:last-child{padding-right:24px}
@media(max-width:640px){
  .panel-bd.flush table.t th:first-child,.panel-bd.flush table.t td:first-child{padding-left:18px}
  .panel-bd.flush table.t th:last-child,.panel-bd.flush table.t td:last-child{padding-right:18px}
  table.t td{padding-top:13px;padding-bottom:13px}
}

/* 窄屏：表格塌成一行一卡。
   360px 下原来要横拖将近两屏，往下滚两行列头就不在屏上了，
   用户根本分不清在看哪一列：这是移动端最严重的一处。
   每个单元格左边用 ::before 吐出自己的列头（取 td 的 data-label），
   右边是值，读起来是「日期 2026-09-12」这样的一行，不必再横拖。
   ⚠ 只有 td 带 data-label 时才触发（:has 把关）。页面接线方式见报告。
   不支持 :has 的老浏览器退回横向滚动，不会坏。 */
@media(max-width:640px){
  .tw:has(td[data-label]){overflow-x:visible;overflow-y:visible}
  table.t:has(td[data-label]){min-width:0;display:block;font-size:var(--fs-base)}
  table.t:has(td[data-label]) thead{
    position:absolute;width:1px;height:1px;overflow:hidden;
    clip-path:inset(50%);white-space:nowrap;   /* 留给读屏，视觉上收起 */
  }
  table.t:has(td[data-label]) tbody,
  table.t:has(td[data-label]) tr{display:block}
  table.t:has(td[data-label]) tr{
    padding:14px 0;border-bottom:1px solid var(--line2);
  }
  table.t:has(td[data-label]) tr:last-child{border-bottom:none}
  table.t:has(td[data-label]) tbody tr:hover{background:none}
  table.t:has(td[data-label]) td{
    display:flex;gap:16px;align-items:baseline;justify-content:space-between;
    padding:5px 18px;border:0;text-align:right;line-height:1.55;
  }
  table.t:has(td[data-label]) td::before{
    content:attr(data-label);flex:none;text-align:left;
    color:var(--ink3);font-size:var(--fs-note);font-weight:400;letter-spacing:.015em;
  }
  /* 首个单元格当成这张卡的标题：左对齐、单独一行、字号抬一档 */
  table.t:has(td[data-label]) td:first-child{
    display:block;text-align:left;font-size:var(--fs-body);font-weight:var(--fw-semibold,600);
    color:var(--ink);padding-bottom:8px;
  }
  table.t:has(td[data-label]) td:first-child::before{display:block;margin-bottom:2px}
  table.t:has(td[data-label]) td.r{text-align:right}
  table.t:has(td[data-label]) .sub{display:inline;margin:0}
  /* 塌成卡片后 flush 表格不再需要首末列补边 */
  .panel-bd.flush table.t:has(td[data-label]) td{padding-left:18px;padding-right:18px}
}

/* ── 状态块：空 / 载入 / 错误 ───────────── */
/* 空状态原来就是居中两行字，落在一片白里像页面没加载完。
   在文字后面垫一团很淡的椭圆光晕，让这块地方看起来是「本来就空着」，
   而不是「还没加载出来」。光晕居中而不是压在顶边：贴着面板标题那条线会
   被误读成标题的投影，多一层假的层次。四周完全渐隐，所以白面板、灰底、
   flush 表格位、甚至被 grid-column:1/-1 拉通的格子里都不会露边。 */
.state{
  padding:64px 24px 56px;text-align:center;color:var(--ink2);
  background:radial-gradient(74% 58% at 50% 47%,rgba(0,0,0,.021) 0%,transparent 72%);
}
.state h4{margin-bottom:9px;color:var(--ink);font-size:var(--fs-body);letter-spacing:normal}
.state p{font-size:var(--fs-base);line-height:1.72;max-width:400px;margin:0 auto;text-wrap:pretty}
.state .btns{justify-content:center;margin-top:22px}
@media(max-width:640px){.state{padding:46px 18px 42px}}

/* 骨架屏：原来是一条「深灰带」扫过浅灰底，看着像有脏东西在爬；
   改成一道白光扫过 --g 底，和苹果的加载态一致。
   另外原来用的是 --ease（尾巴很长的缓动），循环动画用它会一顿一顿，换 linear。 */
.sk{
  background:var(--g);
  background-image:linear-gradient(100deg,transparent 26%,rgba(255,255,255,.92) 48%,transparent 70%);
  background-size:220% 100%;background-repeat:no-repeat;
  /* 原来是 8px：全站唯一的第三档圆角。块状骨架归到 --r，条状的下面走胶囊 */
  border-radius:var(--r);animation:sk 1.5s linear infinite;
}
@keyframes sk{0%{background-position:150% 0}100%{background-position:-50% 0}}
.sk-line{height:13px;margin-bottom:9px;border-radius:var(--r-pill)}
/* 长短不一才像真的段落：中间一行略短，最后一行最短 */
.sk-line:nth-child(3n+2){width:93%}
.sk-line:last-child{width:62%;margin-bottom:0}
@media(prefers-reduced-motion:reduce){.sk{animation:none;background-image:none}}

/* ── 提示条 ─────────────────────────────── */
.toast-wrap{position:fixed;left:50%;bottom:28px;transform:translateX(-50%);z-index:300;
  display:flex;flex-direction:column;gap:9px;align-items:center;pointer-events:none}
/* 窄屏上悬浮清单入口就在右下角，28px 的提示条会压在它身上；
   同时避开 iPhone 的底部横条。 */
@media(max-width:900px){
  .toast-wrap{bottom:calc(20px + env(safe-area-inset-bottom,0px));width:100%;padding:0 16px}
}
/* 页面挂了底部常驻栏时，提示条要落在它上面，不能被压住 */
@media(max-width:900px){
  body:has(.dock:not([hidden])) .toast-wrap{bottom:calc(84px + env(safe-area-inset-bottom,0px))}
}
.toast{
  background:rgba(26,26,28,.94);color:#fff;font-size:var(--fs-base);
  padding:12px 20px;border-radius:var(--r-pill);box-shadow:var(--sh-3);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  opacity:0;transform:translateY(12px);
  transition:opacity var(--t-3) var(--ease),transform var(--t-3) var(--ease);
  max-width:min(88vw,460px);text-align:center;
}
.toast.in{opacity:1;transform:none}
.toast.bad{background:rgba(179,38,30,.95)}

/* ── 提示框（页面内说明，一种样式，不滥用） ── */
/* 竖线从 2px 收到 1.5px、颜色压浅：正文旁边的一根重线会抢走注意力，
   提示语的层级本来就应该低于正文。 */
.tip{border-left:1.5px solid var(--line3);padding:2px 0 2px 17px;margin:20px 0;font-size:var(--fs-base);color:var(--ink2);line-height:1.7}
.tip.stop{border-left-color:var(--bad);border-left-width:2px;color:var(--ink2)}
.tip.stop b{color:var(--bad)}
.tip b{color:var(--ink);font-weight:var(--fw-semibold,600)}
@media(max-width:640px){.tip{padding-left:14px;margin:16px 0}}

/* ── 图片占位（图未到位时使用） ─────────── */
.ph{
  position:relative;width:100%;border-radius:var(--r-lg);
  background:repeating-linear-gradient(135deg,rgba(0,0,0,.016) 0 12px,transparent 12px 24px),var(--g);
  /* 虚线是「图还没到」的信号，要保留；但 14% 的黑边在小卡片上太抢，压到 10% */
  border:1px dashed rgba(0,0,0,.10);display:flex;align-items:center;justify-content:center;
}
.ph::after{content:attr(data-label);font-size:var(--fs-note);letter-spacing:.05em;color:var(--ink3);
  text-align:center;padding:14px 20px;line-height:1.7;max-width:84%;text-wrap:pretty}
.ph-wide{aspect-ratio:16/9}
.ph-sq{aspect-ratio:1/1}
.ph-tall{aspect-ratio:4/5}

/* ── 网格 ─────────────────────────────────
   老板看商城时说「卡片高度不齐、行与行错位」。
   grid 本身默认就是 align-items:stretch，同一行的格子等高；错位来自
   **卡片内部**没有把底部那行推到底。所以这里做两件事：
   1) 把 stretch 写明，防止页面误加 align-items:start 之后同行不等高；
   2) 给 .grid 的直接子元素一个「竖向弹性」的默认：内部最后一个块自动贴底。
      卡片自己若已经是 flex 列（商城的 .p-card 就是），这条不会打架。
   剩下那半：文字基线对齐：要求卡内元素数量一致，属于卡片组件本身，
   不是网格能解决的，已写进报告。 */
.grid{display:grid;gap:20px;align-items:stretch}
.grid>*{min-width:0}
.g-2{grid-template-columns:repeat(2,1fr)}
.g-3{grid-template-columns:repeat(3,1fr)}
.g-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:1000px){.g-4{grid-template-columns:repeat(2,1fr)}}
@media(max-width:860px){.g-3{grid-template-columns:repeat(2,1fr)}}
@media(max-width:620px){.g-2,.g-3,.g-4{grid-template-columns:1fr}.grid{gap:16px}}

/* ════════════════════════════════════════════════════════════
   手机端共享件（苹果 Apple Store 手机版那一套的三个基本件）
   六个页面此前各自手搓过横滑条：.tabs / .cmp-thumbs / .sl-lane-row /
   .strip / .shots / .cats-in，写法各不相同，而且**无一例外把滚动条藏了、
   也没有任何「还能滑」的提示**：老板说的「不能拖动还没有滚动条」就是这个。
   下面三件收口到共享层，页面直接用。
   ════════════════════════════════════════════════════════════ */

/* ── 一、横滑轨道 .rail ──────────────────────
   用法：<div class="rail"><article>…</article><article>…</article></div>
   直接子元素就是卡片，不需要再套一层 class。
   卡片宽度由页面决定（手机上建议 78~86%，让下一张露边）。
   轨道会自动出血到所在容器的边缘（读 --gut），首张卡片仍与正文左对齐，
   卡片能一直滑到屏幕边：这是苹果手机端的标志排法。 */
/* ⚠⚠ 给 .rail 加外边距时**只能用 margin-block-start / margin-top**，
   绝对不要用 margin 简写。
   .rail 的出血完全依赖下面那行 margin-inline 负值；任何人写
   `margin:14px 0 0` 想加个上边距，都会静默把 margin-inline 清零，
   结果是轨道缩回正文宽度、滑到边上突兀地断开，而且**不报错**，
   只能靠眼睛发现。已经有人踩过。
   同理，改 padding 也要用 padding-block-start，别用 padding 简写，
   那会抹掉 padding-inline，出血和内容就对不齐了。 */
.rail{
  /* ⚠ 出血量回退值必须是 0，不能是 24px。
     .rail 可能被放在没有左右留白的容器里（工作台的 .split 就是直接挂在
     main 下面的），回退成 24px 会让它凭空比父容器宽 48px，把页面顶破。
     实测就踩过：.side 用了 20px 回退，390px 视口文档宽被撑到 408。
     --gut 由 .wrap / .wrap-w / .narrow 提供；容器没定义就不出血。 */
  --rail-p:var(--gut,0px);
  --rail-fade:16px;
  /* 间距 20px 是苹果手机端横滑的实测值。配套的卡片尺寸由页面定：
     卡宽 = 视口 79.2%（实测 309/390），下一张露出 39px ≈ 10%。
     页面写 `flex:0 0 79.2%` 即可，不要写死 px。 */
  display:flex;gap:20px;
  overflow-x:auto;overflow-y:hidden;
  overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;
  scroll-snap-type:x mandatory;
  scroll-padding-inline:var(--rail-p);
  padding-inline:var(--rail-p);
  padding-block:2px 4px;
  margin-inline:calc(var(--rail-p) * -1);
  /* 两端渐隐：即使卡片没露边，也在告诉人「这里还有内容」。
     渐隐宽度是常量，出血时它落在留白里不咬内容，不出血时轻轻压住首末项边缘。 */
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 var(--rail-fade),#000 calc(100% - var(--rail-fade)),transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 var(--rail-fade),#000 calc(100% - var(--rail-fade)),transparent 100%);
}
.rail>*{scroll-snap-align:start;flex:0 0 auto}
/* 桌面留一根细滚动条：鼠标用户靠它判断还有没有内容，藏掉等于不告诉人。
   触摸设备上系统本来就不常驻滚动条，藏掉反而干净：靠渐隐和露边提示。 */
.rail{scrollbar-width:thin;scrollbar-color:rgba(20,28,22,.22) transparent}
.rail::-webkit-scrollbar{height:8px}
.rail::-webkit-scrollbar-track{background:transparent}
.rail::-webkit-scrollbar-thumb{
  background:rgba(20,28,22,.18);border-radius:var(--r-pill);
  border:2px solid transparent;background-clip:content-box;
}
.rail:hover::-webkit-scrollbar-thumb{background:rgba(20,28,22,.32);background-clip:content-box}
@media(hover:none),(pointer:coarse){
  .rail{scrollbar-width:none;padding-block-end:2px}
  .rail::-webkit-scrollbar{height:0}
}
@media(prefers-reduced-motion:no-preference){.rail{scroll-behavior:smooth}}

/* ── 二、底部弹出面板 .sheet ──────────────────
   用法：
     <div class="scrim" data-close></div>
     <div class="sheet" role="dialog" aria-modal="true" aria-labelledby="t">
       <div class="sheet-hd"><h3 id="t">标题</h3><button class="sheet-x">✕</button></div>
       <div class="sheet-bd">…</div>
       <div class="sheet-ft">…</div>
     </div>
   打开：给 .scrim 和 .sheet 同时加 .on。
   顶部的下拉把手是 ::before 画的，页面不用加元素、也就不会漏。
   ⚠ 锁 body 滚动需要 JS（overscroll-behavior 只能挡住滚动穿透，
     挡不住 iOS Safari 的橡皮筋），已写进报告交给动效工程师。 */
.scrim{
  position:fixed;inset:0;z-index:190;background:rgba(18,20,19,.38);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  opacity:0;pointer-events:none;transition:opacity var(--t-3) var(--ease);
}
.scrim.on{opacity:1;pointer-events:auto}
.sheet{
  position:fixed;left:0;right:0;bottom:0;z-index:200;
  display:flex;flex-direction:column;
  max-height:min(86dvh,760px);
  background:var(--w);
  border-radius:var(--r-lg) var(--r-lg) 0 0;
  box-shadow:0 -1px 2px rgba(20,28,22,.06),0 -24px 60px -30px rgba(20,28,22,.3);
  transform:translateY(100%);visibility:hidden;
  transition:transform var(--t-3) var(--ease),visibility var(--t-3) var(--ease);
  padding-bottom:env(safe-area-inset-bottom,0px);
}
.sheet.on{transform:none;visibility:visible}
/* 默认把手：伪元素画的，页面不用加元素、也就不会漏。 */
.sheet::before{
  content:"";position:absolute;top:8px;left:50%;transform:translateX(-50%);
  width:38px;height:4px;border-radius:var(--r-pill);background:var(--line3);
}
/* ⚠ 但伪元素 JS 抓不到，动效层要给把手绑下拉关闭就必须有真实元素。
   所以两种都支持：页面放了 .sheet-handle 或 [data-pm-handle] 就用真的，
   ::before 自动让位；没放也不会缺把手。
   真把手做成 64×24 的抓取区、里面只画 38×4 的条：4px 高的东西手指抓不住。 */
.sheet-handle,[data-pm-handle]{
  display:block;flex:none;width:64px;height:24px;margin:6px auto 0;
  border:0;background:none;padding:0;position:relative;cursor:grab;
  touch-action:none;
}
.sheet-handle::after,[data-pm-handle]::after{
  content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:38px;height:4px;border-radius:var(--r-pill);background:var(--line3);
}
.sheet-handle:active,[data-pm-handle]:active{cursor:grabbing}
.sheet:has(.sheet-handle)::before,.sheet:has([data-pm-handle])::before{display:none}
.sheet:has(.sheet-handle) .sheet-hd,.sheet:has([data-pm-handle]) .sheet-hd{padding-top:12px}
@media(min-width:901px){.sheet-handle,[data-pm-handle]{display:none}}
.sheet-hd{
  flex:none;display:flex;align-items:center;gap:12px;
  padding:22px var(--gut,20px) 14px;border-bottom:1px solid var(--line2);
}
.sheet-hd h3{font-size:var(--fs-body);letter-spacing:normal}
.sheet-x{
  margin-left:auto;flex:none;width:44px;height:44px;border:0;border-radius:50%;
  background:var(--g);color:var(--ink2);cursor:pointer;font-size:var(--fs-base);line-height:1;
  transition:background var(--t-1) var(--ease-o),color var(--t-1) var(--ease-o);
}
.sheet-x:hover{background:var(--g3);color:var(--ink)}
.sheet-bd{
  flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;padding:18px var(--gut,20px);
}
.sheet-ft{
  flex:none;padding:14px var(--gut,20px) 18px;border-top:1px solid var(--line2);
  display:flex;gap:10px;align-items:center;background:var(--w);
}
.sheet-ft .btn{flex:1;min-height:48px}
/* 桌面上从底部升起会显得奇怪，改成居中的对话框，同一套 class 两种形态 */
@media(min-width:901px){
  .sheet{
    left:50%;bottom:auto;top:50%;right:auto;
    width:min(560px,92vw);max-height:min(80vh,720px);
    border-radius:var(--r-lg);
    transform:translate(-50%,-46%) scale(.98);
  }
  .sheet.on{transform:translate(-50%,-50%) scale(1)}
  .sheet::before{display:none}
  .sheet-hd{padding-top:18px}
}

/* ── 三、底部常驻主操作 .dock ─────────────────
   用法：<div class="dock"><button class="btn btn-p btn-block">立即下单</button></div>
   手机专用；桌面上同一个动作应该放在面板里，苹果自己也是这样分的。
   高度不低于 48px，并且留出 iPhone 底部横条的安全区。 */
/* ⚠ 本件靠 --gut 算左右留白，页面若覆盖了容器的 padding，必须同步覆盖 --gut，
   否则底栏内容会和正文对不齐（.rail 同理，实测 641~720px 之间会差 10px）。 */
.dock{
  display:none;
  position:fixed;left:0;right:0;bottom:0;z-index:180;
  gap:10px;align-items:center;
  padding:10px var(--gut,20px) calc(10px + env(safe-area-inset-bottom,0px));
  background:rgba(255,255,255,.9);
  -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  border-top:1px solid var(--line2);
}
.dock .btn{min-height:48px}
.dock .btn-block,.dock>.btn:only-child{flex:1}
@media(max-width:900px){.dock{display:flex}}
/* 固定底栏必须把正文垫高，否则最后一屏内容被压在下面点不到。
   用 :has 自动判断，页面不必再记得加 padding。 */
@media(max-width:900px){
  body:has(.dock:not([hidden])) main{padding-bottom:calc(86px + env(safe-area-inset-bottom,0px))}
  body:has(.dock:not([hidden])) .foot{padding-bottom:calc(76px + env(safe-area-inset-bottom,0px))}
}

/* ── 区块标题右侧「查看全部」 ─────────────────
   用法：<div class="sec-row"><h2>常备现货</h2><a class="seeall" href="…">查看全部</a></div> */
.sec-row{display:flex;align-items:baseline;gap:16px;margin-bottom:18px}
.sec-row h2,.sec-row h3{min-width:0}
.seeall{
  margin-left:auto;flex:none;font-size:var(--fs-ui);color:var(--brand);
  display:inline-flex;align-items:center;gap:5px;white-space:nowrap;
  transition:color var(--t-1) var(--ease-o);
}
.seeall::after{content:"\203A";font-size:var(--fs-body);line-height:1;transform:translateY(-1px)}
.seeall:hover{color:var(--brand-h)}
@media(hover:none),(pointer:coarse){.seeall{min-height:44px;align-items:center}}

/* ── 跳到正文（键盘用户） ─────────────────────
   商城每页正文前有 9~11 个可聚焦元素，卡片区每张卡 7 个，
   键盘用户要走到页脚得按几百次 Tab。
   ⚠ 需要各页配合：body 第一个子元素放 <a class="skip" href="#main">跳到正文</a>，
     并给 <main> 加 id="main" 和 tabindex="-1"。已写进报告。 */
.skip{
  position:fixed;left:12px;top:-100px;z-index:400;
  background:var(--w);color:var(--ink);font-size:var(--fs-base);font-weight:var(--fw-semibold,600);
  padding:12px 18px;border-radius:var(--r);box-shadow:var(--sh-2);
  transition:top var(--t-2) var(--ease-o);
}
.skip:focus{top:calc(8px + env(safe-area-inset-top,0px))}

/* 工作台左右分栏 */
.split{display:grid;grid-template-columns:232px minmax(0,1fr);gap:24px;align-items:start}
/* ⚠ 这里必须是 minmax(0,1fr) 而不是 1fr，两者在 grid 里不等价：
   grid 子项默认 min-width:auto，不肯缩到内容的最小宽度以下。写成 1fr 时，
   里面 table.t 的 min-width:640px 会把整个格子顶到 640，再把页面撑破。
   桌面那档本来就写对了，窄屏这档写成了 1fr ： 手机上表格顶破页面
   （实测 390px 视口文档宽 408，table.t 超出 250px）就是这一个字的差别。
   .split>*{min-width:0} 是第二道保险，页面往里塞别的宽内容也不会再破。 */
@media(max-width:940px){.split{grid-template-columns:minmax(0,1fr);gap:16px}}
.split>*{min-width:0}

/* 侧栏 */
.side{position:sticky;top:calc(var(--nav-h) + 24px)}
.side a{
  display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:var(--r);
  font-size:var(--fs-base);color:var(--ink2);
  transition:background var(--t-1) var(--ease-o),color var(--t-1) var(--ease-o),
             box-shadow var(--t-2) var(--ease-o);
}
.side a:hover{background:var(--w);color:var(--ink)}
.side a:active{background:var(--w);color:var(--ink);box-shadow:var(--sh-1)}
/* 当前项：白底 + 接触影，在 --g 的工作台底色上是一张「浮起来的贴纸」 */
/* 选中态不许改字重：改字重就改宽度，改宽度就推移同行其他项。
   .side 在手机上是横向滚动条，位移尤其明显。苹果的选中态做到「一个像素都不位移」
   （1px→2px 描边的同时 padding 15→14 抵消）。这里靠白底 + 接触影 + 加深文字。 */
.side a[aria-current="page"]{background:var(--w);color:var(--ink);box-shadow:var(--sh-1)}
.side .grp{font-size:var(--fs-note);letter-spacing:.08em;color:var(--ink3);padding:18px 14px 7px}
@media(max-width:940px){
  /* 横向条。原来只是藏掉滚动条就完了，等于没告诉人右边还有东西：
     补上两端渐隐，并且出血到容器边缘，让末项被切一半，一眼就知道能滑。 */
  /* ⚠ 不出血。.side 的外层是 .split，而 .split 在工作台里直接挂在 main 下、
     并没有包在 .wrap-w 里，拿不到 --gut；按回退值出血会把页面顶破（已踩过）。
     只留两端渐隐提示「还能滑」，位置保持在容器内。 */
  .side{
    --rail-fade:16px;
    position:static;display:flex;gap:6px;overflow-x:auto;
    overscroll-behavior-x:contain;padding-bottom:4px;
    scrollbar-width:none;scroll-snap-type:x proximity;scroll-padding-inline:2px;
    /* 同 .pills：只做右端。当前项是白底胶囊，左端渐隐会啃掉它的圆角。 */
    -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - var(--rail-fade)),transparent 100%);
    mask-image:linear-gradient(90deg,#000 calc(100% - var(--rail-fade)),transparent 100%);
  }
  .side::-webkit-scrollbar{height:0}
  .side .grp{display:none}
  .side a{white-space:nowrap;flex:none;scroll-snap-align:start}
}

/* ── 数字卡（仅在数字本身是重点时使用） ─── */
.stats{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line)}
.stat{padding:30px 20px 30px 0;border-right:1px solid var(--line2)}
.stat:last-child{border-right:none}
.stat b{display:block;font-size:clamp(26px,3.4vw,38px);font-weight:var(--fw-semibold,600);letter-spacing:normal;line-height:1.1;font-variant-numeric:tabular-nums}
.stat span{display:block;font-size:var(--fs-ui);color:var(--ink2);margin-top:7px}
@media(max-width:700px){
  .stats{grid-template-columns:repeat(2,1fr)}
  .stat{padding:22px 14px 22px 0}
  .stat:nth-child(2n){border-right:none}
  .stat:nth-child(-n+2){border-bottom:1px solid var(--line2)}
}
/* 四个数字在 380px 上排两列时数字会断行，再收一次字号 */
@media(max-width:400px){.stat b{font-size:25px}.stat span{font-size:var(--fs-note)}}

/* ── 深色反差区（整页只用一次） ─────────── */
.dark{background:var(--dark);color:#F5F5F7}
.dark h1,.dark h2,.dark h3,.dark h4{color:#fff}
.dark .lead,.dark .muted{color:rgba(245,245,247,.62)}
.dark .note{color:rgba(245,245,247,.45)}

/* ── 入场动画 ───────────────────────────── */
/* 入场是唯一该慢的动作：位移走 --ease 的长尾（滑到位再停），
   透明度比位移早一点收尾，元素落位时已经完全实了，不会出现「半透明还在飘」。 */
.js .rv{opacity:0;transform:translateY(22px);
  transition:opacity .52s var(--ease-o),transform var(--t-in) var(--ease)}
.js .rv.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
  .js .rv{opacity:1!important;transform:none!important;transition:none}
  *{animation-duration:.001ms!important;transition-duration:.001ms!important}
}

/* ── 手机刻度收尾 ─────────────────────────
   26px 的圆角在 390px 宽的卡片上占比过大，看起来发圆发软；
   苹果手机端的卡片正是 16~22 这一档。只改令牌，所有读它的元件一起跟上
   （.panel / .card / .shell / .ph / .sheet，以及同心内芯的 calc）。 */
@media(max-width:640px){:root{--r-lg:22px}}

/* 点击反馈：全站可点元素统一 scale(.97)。
   只给真正的控件，不给正文里的行内链接：一个句子中间的链接被按住时
   整段文字跟着缩一下，很廉价。 */
/* 按压比例的唯一定义处在 pro-motion.css（--pm-press .97 控件 / --pm-press-lg .985 大面）。
   分两档的理由成立：缩放观感取决于绝对位移而非比例，40px 按钮缩 3% 是 1.2px，
   340px 卡片缩 3% 是 10px，后者像被踹了一脚。所以卡片走 lg 档。
   写成 var(…,回退值)：动效层没加载时本文件仍然自洽。 */
.seeall:active,.sheet-x:active{transform:scale(var(--pm-press,.97))}
.rail>*:active{transform:scale(var(--pm-press-lg,.985))}
.rail>*,.seeall,.sheet-x{transition:transform var(--t-1) var(--ease-o)}
@media(prefers-reduced-motion:reduce){
  .btn:active,.pill:active,.rail>*:active,.seeall:active,.sheet-x:active{transform:none}
}

/* ── 页脚 ───────────────────────────────── */
.foot{border-top:1px solid var(--line2);padding:40px 0 56px;font-size:var(--fs-ui);color:var(--ink3)}
.foot-in{display:flex;flex-wrap:wrap;gap:10px 26px;justify-content:space-between;align-items:center}
/* 页脚链接原来只有 78×15，十一个页面都中。
   用「内边距撑开 + 等量负外边距抵消」把可点区做到 44px 高，
   版式一像素不动：padding 撑开的是链接自己、手指点得到，
   负 margin 把它对周围的影响抵消掉。 */
.foot a{transition:color var(--t-1) var(--ease-o)}
.foot a:hover,.foot a:active{color:var(--ink2)}
@media(hover:none),(pointer:coarse){
  .foot a{display:inline-flex;align-items:center;min-height:44px;
          padding-block:12px;margin-block:-12px}
}
/* 窄屏页脚一行挤不下就整体左对齐成一叠，不要两端对齐出大空档 */
@media(max-width:640px){
  .foot{padding:28px 0 calc(40px + env(safe-area-inset-bottom,0px))}
  .foot-in{justify-content:flex-start;gap:8px 18px}
}

/* ── 小助手「香香嘟」 ─────────────────────── */
.pet{display:flex;gap:16px;align-items:center}
/* 原来是一圈 白→灰→深灰 的径向渐变，做成假的球体高光。
   这种「拟物小球」是模板感最强的装饰之一，拍平成一个干净的灰圆。 */
.pet-art{
  width:78px;height:78px;flex:none;border-radius:50%;
  background:var(--g);
  display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;
}
.pet-art svg{width:56px;height:56px;overflow:visible}
.pet-art .breathe{animation:breathe 4.4s var(--ease) infinite}
@keyframes breathe{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-2.5px) scale(1.012)}}
.pet-bar{height:5px;border-radius:var(--r-pill);background:var(--g3);overflow:hidden;margin-top:9px}
.pet-bar i{display:block;height:100%;border-radius:inherit;background:var(--brand);
  transition:width 1.1s var(--ease)}
/* 等级不用品牌色，品牌色留给真正的动作与选中态 */
.pet-lv{font-size:var(--fs-note);letter-spacing:.05em;color:var(--ink2);font-weight:var(--fw-text,400)}
.pet-say{font-size:var(--fs-base);color:var(--ink2);line-height:1.62;margin-top:4px}
@media(prefers-reduced-motion:reduce){.pet-art .breathe{animation:none}}

/* 打印：工作台与订单需要能打出来 */
@media print{
  /* ⚠ .rv 在滚动到之前是 opacity:0。直接 Ctrl+P 打印长页面时，
     没滚过的部分全是白纸（作战手册那页实测：空白版 30KB / 完整版 414KB）。
     打印时必须把入场态强制还原，这是 bug 不是样式偏好。 */
  .js .rv{opacity:1!important;transform:none!important;transition:none!important;animation:none!important}
  .nav,.side,.toast-wrap,.btn,.pet,.dock,.sheet,.scrim,.skip{display:none!important}
  body{background:#fff;font-size:11pt}
  .panel,.card{box-shadow:none;border:1px solid #ccc}
  .lang-work main{padding-block:0}   /* 同上：只清上下，别碰左右 */
}
