/* ============================================================================
   雅之林® 前台 v14 · 设计系统（唯一源）        2026-09-29 依参考视频全面重做
   ----------------------------------------------------------------------------
   ⛔ 页面里不再写死颜色/圆角/字号，一律走本文件的令牌与组件。
   🔴 主色＝**栏目色**（下午定稿的四色轴，每页 html[data-tone] 自动取）；柠檬绿已退场，不再当主色。
   🔴 两条硬规则（实测对比度，不是感觉）：
     ① 白字压主色 6.86–10.69:1 ✅｜主色当文字压暖白 6.27–9.77:1 ✅
     ② **墨绿黑深块上要用 --brand-lt（主色浅档）**，深色主色压在深块上读不出来
     ③ 品牌金 #C9A24A 不上浅底（压暖白 2.19:1）⇒ 金只出现在深块上
   🔴 层级靠「明度差」不靠阴影：展示台(黑) → 页底(暖白) → 卡(更白) → 深块(墨绿黑)
   ========================================================================== */

/* ============================== 令牌 ============================== */
:root{
  /* 层：展示台 / 页底 / 卡 / 浅块 / 深块 */
  --stage:#E7EAE3;          /* 手机列以外（桌面展示台）· 2026-09-29 用户：不要纯黑（太像夜间模式） */
  --bg:#F5F5F0;             /* 页面底 · 暖白 */
  --card:#FDFDFD;           /* 卡片 · 更白 */
  --card2:#F3F6EE;          /* 次要卡 · 浅绿 */
  --deep:#131A17;           /* 墨绿黑深块（数据块/反白条） */
  --deep2:#1C2621;
  /* 文字 */
  --ink:#101413; --ink2:#2A3130; --sub:#616966; --mute:#6E7773;
  --on-deep:#EDEFEA; --on-deep-sub:#A9B3AE;
  /* 线 */
  --line:#E4E7E0; --line2:#EDEFE9; --line-d:rgba(255,255,255,.10);
  /* 强调：**主色＝栏目色**（2026-09-29 下午定稿的四色轴），每页按 html[data-tone] 自动取。
     🔴 实测对比度（白字压主色 6.86–10.69:1 ✅；主色当文字压暖白 6.27–9.77:1 ✅）
     --brand-lt 是主色的**浅档**，专给墨绿黑深块上的文字/图标用（深色主色压深块读不出来）。 */
  --brand:#002FA7; --brand-ink:#FFFFFF; --brand-soft:#EDF3FF; --brand-line:#D9E4FF; --brand-lt:#9DB6FF;
  /* 🔴 2026-10-02 新增「深档」--brand-dp：主色再压深一档，专给「深色底块」用
     （弹窗底、渐变深端）。以前这类地方是**硬编码**的 hex，一旦换主色就会有残留补丁 ——
     现在收进令牌，换色只需改本文件一行。
       --brand-lt = 浅档（深块上的文字/图标）
       --brand    = 本色（实心按钮、色块）
       --brand-dp = 深档（比本色更沉的块，白字压上去对比度 ≥ 11:1） */
  --brand-dp:#001A63;
  /* 语义色（不动） */
  --ok:#0E7A4A; --warn:#9A6612; --bad:#D1342C; --info:#5B5BD6;
  --gold:#C9A24A;           /* 品牌金：只上深块 */
  /* 形状 */
  --r28:28px; --r22:22px; --r16:16px; --r12:12px; --r999:999px;
  /* 动效：先快后慢 + 轻微过冲 */
  --t-fast:160ms; --t:240ms; --t-slow:380ms;
  --ease:cubic-bezier(.22,.61,.36,1);
  --spring:cubic-bezier(.34,1.42,.5,1);
  /* 排版 */
  /* ⛔ 字体栈 `--f` **不在这里定义**（2026-10-07 用户令「4 个页面中所有的页面都要改字体」）。
     唯一源 ＝ `lock.css` 的「④ 字体栈」那一节 —— 原因有两条，都别绕开：
       ① `lock.css` 是**唯一每一页都引**的样式文件（含不引本文件的 `商品详情.html`）；
          而本文件只有部分页面引 ⇒ 把令牌放这里，商品详情页的 `var(--f)` 永远是未定义
          （实测它因此整页落到浏览器默认 Times 衬线字体）。
       ② 「单一方案铁律」：同一个令牌两份定义必然漂。
     ⇒ 要改字体只改 `lock.css` 一处。 */
  --mono:"SF Mono",ui-monospace,Menlo,monospace;
}

/* ── 四栏目主色（下午定稿的色轴；顺序＝主次：心脑血管(商品中心) > 免疫力 > 血糖 > 痛风）── */
html[data-tone="home"] { --brand:#002FA7; --brand-ink:#FFFFFF; --brand-soft:#EDF3FF; --brand-line:#D9E4FF; --brand-lt:#9DB6FF; --brand-dp:#001A63; }
/* 🔴 2026-10-02 用户令：「这一页改成**高饱和度的深紫色**，现在的浅紫不好看。」
   ⇒ 给了四组候选色卡让他指认，**用户选定 B「深葡萄紫」#4C1D95**（H258/S67%/L35%）。
   演进：旧 #4A3B8F（S41% 发灰的中紫）→ 试 A #5B21B6（皇家紫，S69%）→ **定 B #4C1D95**。
   ⛔ 只动 clock 一行 —— 其余三色轴（home/admin/me）用户已定稿，别顺手改。
   ⚠️ 与 --brand 相关的硬编码（落款 --foot、弹窗底、图例、进度环渐变）必须一起换，
      否则会留下「上一版紫」的补丁 —— 本轮 A→B 就踩到了，已一并换掉。 */
html[data-tone="clock"]{ --brand:#4C1D95; --brand-ink:#FFFFFF; --brand-soft:#EFEAFD; --brand-line:#D7CCF8; --brand-lt:#B9A5F7; --brand-dp:#3B1478; }
html[data-tone="admin"]{ --brand:#8E2361; --brand-ink:#FFFFFF; --brand-soft:#F9ECF3; --brand-line:#EFD6E3; --brand-lt:#F0A9CD; --brand-dp:#5E1240; }
/* 🔴 2026-10-02 用户令：「会员中心，先给我 4 种红色选择一下」→ 出四组色卡让他指认
   → **用户选定 D「深酒红」#7A1226**（H348/S74%/L27%，白字对比度 10.8:1）。
   旧值 #A82A3C（胭脂红，H352/S60%/L41%）作为基准一同展示过，被否。
   ⚠️ **本 tone 被两页共用**：会员中心（`/`）＋「我的订单」（`/orders`，它是会员中心的子页）
      ⇒ 改这一次，两页一起变色，这是「同栏目同色」的设计，不是误伤。
   ⛔ 页内**图表系列色**（例：会员中心「董事分红」图例 #A82A3C）与 `.st-item.danger`
      属**数据/语义色**，跟主色无关，**不要顺手一起改**（与打卡站换色时「grep 旧 hex」的规矩不同）。 */
html[data-tone="me"]   { --brand:#7A1226; --brand-ink:#FFFFFF; --brand-soft:#F8E9EC; --brand-line:#EDCDD5; --brand-lt:#DC94A3; --brand-dp:#4E0A18; }
/* 深块（墨绿黑）上的强调色：不能用主色深色，改用浅档 */
.kpi .more, .card.deep .more{ color:var(--brand-lt) }
.kpi .hint b{ color:var(--brand-lt) }

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html{
  background-color:var(--stage);
  background-image:linear-gradient(rgba(16,20,19,.05) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(16,20,19,.05) 1px,transparent 1px);
  background-size:36px 36px;
}
body{
  margin:0 auto; max-width:430px; min-height:100vh; background:var(--bg); color:var(--ink);
  font:400 14px/1.7 var(--f);
  box-shadow:0 0 0 1px rgba(16,20,19,.10), 0 18px 44px -16px rgba(16,20,19,.30);
  padding-bottom:0;   /* 2026-09-29 用户：落款要「到底」，底部不要留白；改由 .ux-footer 自己吃下底栏高度 */
  text-size-adjust:100%; -webkit-text-size-adjust:100%;
  /* 🔴🔴 2026-10-24 用户令：「所有页面的底部不要有没有用的留白。」
     病根（实测「我的订单」页）：内容比一屏短时，`.ux-footer` 停在自己该在的位置，
     下面留出 **77px 页面底色空白**，再接悬浮底栏 —— 就是用户看到的那块白。
     ⇒ body 竖向 flex，让 `<main class="wrap">` 吃掉剩余高度，落款永远贴着底栏上方。
     ⚠️ 固定层（#tabbar / #loginBar / 抽屉）都是 position:fixed，不参与 flex 排布，不受影响。 */
  display:flex; flex-direction:column;
}
/* 主体吃掉剩余高度 ⇒ 落款被顶到底部（⛔ 别改成给 .ux-footer 加 min-height：那会让短页也撑出空白） */
body > main.wrap{ flex:1 0 auto; }
@media (max-width:480px){ body{box-shadow:none} }
img{max-width:100%;display:block}
button{font:inherit;color:inherit;border:0;background:none;cursor:pointer}
a{color:inherit;text-decoration:none}

/* ============================== 排版 ============================== */
.kicker{font:800 11px/1 var(--f);letter-spacing:.16em;color:var(--sub);text-transform:uppercase}
.kicker b{color:var(--brand)}   /* 🔴 2026-09-30 修正：原 --brand-ink 白字 ⇒ 首屏白卡上隐形（三页同中）；主色压暖白 6.27–9.77:1 ✅ */
.h1{font:900 27px/1.24 var(--f);letter-spacing:-.5px;margin:8px 0 4px}
.h1 u{text-decoration:none;box-shadow:inset 0 -.32em 0 var(--brand)}

/* ══ 🔴🔴🔴 2026-10-08 用户令：「会员中心 4 个页面的色块，增加**水波纹**的动画效果。
     4 个页面的 4 个颜色的色条，比如『医学营养』下面的克莱因蓝、打卡站『都算数』下面的紫色条。」
   ───────────────────────────────────────────────────────────────────────────
   色条就是 `.h1 u` 那条主色带。**只改这一处，4 页同时生效**（`yzl.css` 是 4 页共用的一份，
   颜色由各页 `data-tone` 的 `--brand` 给：商品中心克莱因蓝 / 打卡站紫罗兰 /
   工作站玫红紫 / 会员中心胭脂红）—— ⛔ 别去 4 个页面各抄一份样式（那就是 4 套，改一处漏三处）。

   做法（⛔ 原来的色带**一点没动**，只是在它上面叠了两层水波）：
     · 水波①`::after`  —— 一道**白色高光**从中心向两侧扩散、渐隐（像水面推开的涟漪）
     · 水波②`::before` —— 一圈**主色微光**从色带向外涨开（相位错开 1.6s，形成"一圈接一圈"）
   ⚠️ 两层都 `pointer-events:none`，⛔ 不吃点击（色条可能落在可点卡片里）。
   ⚠️ 只动 `transform / opacity`（走合成层，不触发重排）；`will-change` 不加（4 页会有很多个，
      加了反而占显存 —— 这个动画很轻，不需要）。
   ⚠️ `prefers-reduced-motion: reduce` 一律关掉：这是纯装饰，眩晕风险不值得换。
   --------------------------------- 以下两条必须成对出现 --------------------------------- */
.h1 u{position:relative}
.h1 u::after, .h1 u::before{content:'';position:absolute;pointer-events:none;border-radius:3px}
/* 水波①：白色高光带，从中心向两侧推开 */
.h1 u::after{
  left:0;right:0;bottom:0;height:.32em;
  background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.92),rgba(255,255,255,0));
  transform:scaleX(.06);opacity:0;
  animation:yzlBarRipple 2.8s cubic-bezier(.22,.61,.36,1) infinite;
}
@keyframes yzlBarRipple{
  0%   {transform:scaleX(.06);opacity:0}
  12%  {opacity:.95}
  62%  {transform:scaleX(1);opacity:.40}
  100% {transform:scaleX(1.02);opacity:0}
}
/* 水波②：主色微光，从色带向外涨开一圈（用 radial-gradient 保证任何 --brand 都能用，
   ⛔ 不依赖 color-mix，老机型也安全） */
.h1 u::before{
  left:-12%;right:-12%;bottom:-.16em;height:.62em;
  background:radial-gradient(50% 100% at 50% 55%,var(--brand),rgba(0,0,0,0) 72%);
  opacity:0;
  animation:yzlBarHalo 2.8s ease-out 1.6s infinite;
}
@keyframes yzlBarHalo{
  0%   {transform:scale(.72,1.6);opacity:0}
  22%  {opacity:.42}
  100% {transform:scale(1.18,.9);opacity:0}
}
@media (prefers-reduced-motion: reduce){
  .h1 u::after, .h1 u::before{animation:none;content:none}
}

/* ══ 🔴🔴🔴 2026-10-08 用户令（第二轮）：「4 个页面的**色块**，也要让他们走这四种颜色的动画，
   有**流动**的动画。比如**核心能力**、**账户档案**、**公告**、**我的钱包**。」
   —— 上一版我只做了 `.h1 u` 那条**色条**；用户要的是**整块色块**在流动。
   ───────────────────────────────────────────────────────────────────────────
   这 4 块在 4 个页面里**都是同一个组件 `.kpi.brand`**（`--brand` 每页一色：
   商品中心克莱因蓝 / 打卡站紫罗兰 / 工作站玫红紫 / 会员中心胭脂红）
   —— 实测每页**正好一个** `.kpi.brand`，就是用户点名的那四块 ⇒ 改这里一处，4 页同时生效。
   做法：一条斜向白光带从左侧扫到右侧、循环（＝"流动"），
        ⛔ 不动底色、不动文字、不动布局；`::before` 是空的（`.kpi` 从没用过伪元素，已核实）。
   ⚠️ `.kpi.brand > *` 提到 z-index:1 —— 否则**绝对定位的伪元素会盖在静态文字之上**
      （positioned box 永远画在 static 内容之上，与 DOM 顺序无关），白光扫过时会把白字压糊。
   ⚠️ 只动 `transform / opacity`（合成层，不重排）；⛔ 不加 `will-change`（一次好几块，省显存）。
   ⚠️ `prefers-reduced-motion` 关掉（下面那条）。
   ⚠️ 打卡站的「今日打卡已完成」深紫卡也共用这**同一条**光带（用户令：「也没加动效」）——
      它那里 `::before` 原本是我加的"涟漪"，观感太像呼吸、用户说没看出来 ⇒ **换成同一条流动光带**，
      让 5 处（4 色块 + 打卡完成卡）是**一套语言**。 */
@keyframes yzlFlowSheen{
  0%   {transform:translate3d(-145%,0,0) skewX(-14deg);opacity:0}
  10%  {opacity:.95}
  58%  {transform:translate3d(165%,0,0) skewX(-14deg);opacity:.38}
  100% {transform:translate3d(165%,0,0) skewX(-14deg);opacity:0}
}
.kpi.brand, .done-hero{position:relative;overflow:hidden}
.kpi.brand > *{position:relative;z-index:1}
.kpi.brand::before, .done-hero::before{
  content:'';position:absolute;top:-30%;bottom:-30%;left:0;width:34%;
  pointer-events:none;z-index:0;border-radius:inherit;
  background:linear-gradient(100deg,
    rgba(255,255,255,0) 0%, rgba(255,255,255,.46) 42%,
    rgba(255,255,255,.12) 64%, rgba(255,255,255,0) 100%);
  animation:yzlFlowSheen 5.4s cubic-bezier(.33,0,.2,1) infinite;
}
@media (prefers-reduced-motion: reduce){
  .kpi.brand::before, .done-hero::before{animation:none;content:none}
}


.h2{font:900 17px/1.3 var(--f);letter-spacing:-.2px;margin:0}
.h3{font:900 14.5px/1.4 var(--f);margin:0}
.sub{font:700 12px/1.6 var(--f);color:var(--sub)}
.en{font:800 10.5px/1 var(--f);letter-spacing:.16em;text-transform:uppercase;color:var(--sub)}
.num{font:900 34px/1.05 var(--f);letter-spacing:-1.4px;font-variant-numeric:tabular-nums}
.num small{font:800 14px/1 var(--f);letter-spacing:0;margin-left:6px;color:var(--on-deep-sub)}

/* ============================== 布局 ============================== */
.wrap{padding:0 14px}
.row{display:flex;align-items:center;gap:10px}
.between{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.stack{display:flex;flex-direction:column;gap:10px}
.g2{display:grid;grid-template-columns:1fr 1fr;gap:10px;min-width:0}
.g2>*{min-width:0}

/* 顶栏：文字商标（品牌规范：无图形 logo） */
.topbar{
  position:sticky;top:0;z-index:30;background:rgba(245,245,240,.86);
  -webkit-backdrop-filter:blur(18px) saturate(160%);backdrop-filter:blur(18px) saturate(160%);
  border-bottom:1px solid var(--line);
}
.topbar .in{height:52px;padding:0 14px;display:flex;align-items:center;gap:10px}
.logo{font:900 15px/1 var(--f);letter-spacing:.2px}
.logo em{font-style:normal;font-size:11px;font-weight:800;letter-spacing:.18em;color:var(--sub);margin-left:6px}
.iconbtn{width:34px;height:34px;border-radius:var(--r12);display:grid;place-items:center;color:var(--ink2);
  border:1px solid var(--line);background:var(--card)}
.iconbtn:active{transform:scale(.94)}
.iconbtn svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}

/* ============================== 组件 ============================== */
.card{background:var(--card);border-radius:var(--r22);padding:14px}
.card.line{border:1px solid var(--line)}
.card.deep{background:var(--deep);color:var(--on-deep)}
.card.soft{background:var(--card2)}

/* 数据块（视频里那种墨绿黑块） */
.kpi{background:var(--deep);color:var(--on-deep);border-radius:var(--r22);padding:16px 15px 15px}
.kpi .lab{font:800 9.5px/1 var(--f);letter-spacing:.16em;color:var(--on-deep-sub);text-transform:uppercase}
.kpi .hint{font:700 11.5px/1.5 var(--f);color:var(--on-deep-sub);margin-top:5px}
.kpi .hint b{color:var(--brand-lt)}

/* 列表行 */
.item{display:flex;align-items:center;gap:11px;background:var(--card);border-radius:var(--r16);padding:11px 12px}
.item .ic{width:36px;height:36px;flex:none;border-radius:var(--r12);display:grid;place-items:center;
  background:var(--brand-soft);color:var(--brand-ink);font-size:16px;font-weight:900}
.item .t{flex:1;min-width:0}
.item .t b{display:block;font:900 13.5px/1.35 var(--f)}
.item .t i{display:block;font:600 11.5px/1.5 var(--f);font-style:normal;color:var(--sub)}
.item .r{font:900 13.5px/1 var(--f);white-space:nowrap;font-variant-numeric:tabular-nums}
.item .r em{font-style:normal;font:700 10.5px/1 var(--f);color:var(--sub);margin-left:3px}
.item:active{transform:scale(.985)}

/* ══ 官方主站落款（唯一源＝`ai-advisor/deploy/shared/footer.css` + `run_deploy.py:build_footer()`）
   类名与结构**与官方完全一致**，只把字号/字距接到 v14 的排版令牌上（用户 2026-09-29：
   「底部的落款要跟官方主站的落款一样，根据现在的页面对字体做相应调整」）。
   官方原值：底 #002FA7／内边距 34 20 30／导航 13／版本 13@800／备案 13／版权 12@.6／免责 11@.45／hover 金 #C9A24A。
   🔴 用户 2026-09-29 追加（四页统一）：
     ① 「落款需要蓝色」—— 底就是克莱因蓝 #002FA7，**不要改色**；
     ② 「©是在右边，不是右上角」—— 见下面 `a sup` 那条，⚠️ 标记仍是官方源的 `<sup>©</sup>`
        （**逐字保持同构**），只把**渲染**改成基线对齐；
     ③ 「收窄一点」＋「红框这部分去掉」—— 底部原本 `26px + 92px`＝118px，
        其中 92px 是给底栏预留的，但底栏实测只占 62+12＝**74px** ⇒
        多出来的 44px 就是用户圈红的那条**空白蓝**。现值＝`12px + 74px`＝86px
        （免责底 → 底栏顶留 12px 呼吸），同时把内部节奏一起收紧。 */
/* 🔴 落款底色＝**按站令牌 --foot**（用户 2026-09-29：「底部的落款改成紫色」→ 打卡站）。
   ⛔ 不能直接用 var(--brand)：深色主题会把 --brand 换成浅档（--brand-lt），
      落款会变成一片淡色。--foot 不参与主题换档，各站独立。
   官方 footer.css 全站是 #002FA7；打卡站按用户最新要求走自己的紫罗兰。 */
:root{ --foot:#002FA7 }
html[data-tone="clock"]{ --foot:#4C1D95 }
html[data-tone="admin"]{ --foot:#8E2361 }
html[data-tone="me"]{ --foot:#7A1226 }
/* 🔴🔴 2026-10-01 用户令：「下面 4 个页面切换的横条往下移一点，现在太往上了，挡住上面的文字了；
   这 4 个页面尽量往下移，下面少留一点点空间都可以。」
   ⇒ 底栏与页脚的让位高度**必须成对改**（两个数是一套）：
      · 胶囊底距 12 → **3px**（往下挪 9px）
      · 页脚 padding-bottom `calc(12px + 74px)`（写死 86）→ **`calc(72px + env(safe-area-inset-bottom))`**
   🔴 原来那个 86 是**没算安全区**的：真机 iPhone 安全区约 34px，
      胶囊顶＝12+34+62＝**108px**，而页脚只让位 86px ⇒ **最后一行免责声明被压住 22px**
      （无头浏览器 safe-area=0，所以本地量不出来、真机上才露 —— 这就是为什么截图能看到遮挡）。
      改成 72+safe 后：胶囊顶 = 3+safe+62 = 65+safe，让位 72+safe ⇒ 恒定留 7px 余量。 */
/* 🔴🔴 2026-10-01 用户令：「4 个页面最底部落款的颜色要铺满整个页面，左右两边直接到边，不用留空白。」
   真因：落款虽然写在 `<main class="wrap">` 里，而 `.wrap{padding:0 14px}` ⇒ 实测落款
        left=14、right=376（390 屏两边各留 14px 空白）。订单页之所以本来就到边，是因为它没套在 .wrap 里。
   解：**全出血**——`margin-inline: calc(50% - 50vw)`（负外边距把元素拉到视口两侧）。
        `padding-inline` 由 18 加到 **32px**（＝原 14 容器内边距 + 18），这样内部文字位置**一格没动**。
   ⚠️ `50vw` 含滚动条宽度：桌面端有滚动条时会比视口宽约 15px ⇒ 用 `html{overflow-x:clip}` 兜住。
       用 `clip` 而不是 `hidden` —— `overflow-x:hidden` 会破坏 `position:sticky`（顶栏会失灵）；
       末尾附了 `hidden` 作为老 Safari 的回退（那里 clip 不支持）。
   ✅ 校验：footer 的 left/right 必须等于 0 / innerWidth，且 `scrollWidth <= innerWidth`（不出现横向滚动条）。 */
/* ⛔⛔ 落款样式（`.ux-footer` 及其全部子元素）**已整体搬到 `_footer.css`（唯一源）** ——
   原因：「商品详情」「支付」两页自带一套 .shell/.wrap 样式、**没有引本文件**，
   落款规则留在 yzl.css 里它们一条都吃不到（实测导航退化成一堆孤行）。
   ⛔ 别再往本文件加落款规则，改去 `_footer.css`。
   本处只保留两条**页面级**规则：落款全出血用 `calc(50% - 50vw)`，
   需要把 50vw 里含的滚动条宽度裁掉，否则桌面端出现横向滚动条。 */
html{ overflow-x:clip }
@supports not (overflow: clip){ html{ overflow-x:hidden } }
/* ⛔ 落款导航/版本行/版权/免责/统计图标 的样式**已搬到 `_footer.css`（唯一源）**。
   下面只留一条**不属于落款**的规则：快捷入口方块与弹窗标题里的 © 渲染，
   必须与落款用同一条（全站 © 只有这一种长相）。 */
.item b sup, .jump .box b sup{
  font-size:.85em; line-height:1; vertical-align:baseline; margin-left:2px }
/* ⛔ `.ux-footer-row / -version / -record / -copy / -disclaimer / -tongji`
   已整体搬到 **`_footer.css`（唯一源）**，别在本文件恢复。 */
/* ⛔ `.ux-footer-tongji` 的 hover 与 svg 尺寸也一并搬到 `_footer.css`（唯一源）了。 */

/* 底部小浮层（福利区运费用：卡上不写运费，点开/结算时才提示） */
.sheet{ position:fixed; inset:0; z-index:125; opacity:0; pointer-events:none; transition:opacity 200ms var(--ease) }
.sheet.on{ opacity:1; pointer-events:auto }
.sheet .mask{ position:absolute; inset:0; background:rgba(16,20,19,.32); -webkit-backdrop-filter:blur(5px); backdrop-filter:blur(5px) }
.sheet .box{ position:absolute; left:50%; bottom:calc(84px + env(safe-area-inset-bottom,0px)); transform:translate(-50%,12px);
  width:min(406px, calc(100% - 24px)); background:var(--card); border-radius:var(--r22); padding:16px 16px 14px;
  box-shadow:0 20px 50px -20px rgba(16,20,19,.45); transition:transform 300ms var(--spring) }
.sheet.on .box{ transform:translate(-50%,0) }
.sheet .box b{ display:block; font:900 14.5px/1.4 var(--f) }
.sheet .box p{ margin:6px 0 13px; font:600 12.5px/1.7 var(--f); color:var(--sub) }
.sheet .box p b{ display:inline; font-weight:900; color:var(--brand) }

/* 主色跳转窗（2026-09-29 用户要求：点快捷入口先弹蓝色窗口，再自动跳转）
   · 遮罩 + 居中方块，从 0.86 弹到 1（spring），主色底白字
   · 进度线用 CSS 动画循环，绝不依赖 JS 计时（JS 只管开与关）
   ⛔ 每次跳转都必须有终点：JS 里 setTimeout 到点就 location.href，不存在卡住。 */
.jump{ position:fixed; inset:0; z-index:130; display:grid; place-items:center;
  background:rgba(16,20,19,.30); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  opacity:0; pointer-events:none; transition:opacity 200ms var(--ease) }
.jump.on{ opacity:1; pointer-events:auto }
/* 🔴 用户 2026-09-29：「方块的样式，要跟原来的一样，只是同格式放大！！！」
   ⇒ 弹窗**不做第二套设计**，就是快捷入口卡片 .item 的**同一套格式整体放大 --k 倍**：
      底色 / 圆角 / 内边距 / 图标块尺寸与圆角 / 字号行高 全部由同一个 --k 等比推出。
      等比的好处是「起始帧」天然等于卡片本身（scale = 卡片宽 ÷ 窗宽），
      看起来就是这张卡被抬起来放大 —— 而不是另一块东西飞过来。
   ⛔ 曾经做过「蓝底白字、图标居中、文字居中」的版本，与卡片不是一套格式，已被否。 */
.jump .box{ --k:1.45;
  width:calc(196px * var(--k));
  background:var(--card); color:var(--ink);
  border-radius:calc(var(--r16) * var(--k));
  padding:calc(13px * var(--k)) calc(12px * var(--k));
  display:flex; flex-direction:column; align-items:flex-start;
  gap:calc(8px * var(--k));
  transform-origin:center; transform:none; opacity:1;
  transition:transform 340ms var(--spring), opacity 260ms var(--ease) }
.jump .box .ic{ width:calc(36px * var(--k)); height:calc(36px * var(--k)); flex:none;
  border-radius:calc(var(--r12) * var(--k)); background:var(--card2); color:var(--ink);
  display:grid; place-items:center; font:900 calc(16px * var(--k))/1 var(--f) }
.jump .box b{ display:block; font:900 calc(14.5px * var(--k))/calc(20.3px * var(--k)) var(--f);
  letter-spacing:.2px }
@keyframes jumpgo{ from{ transform:translateX(-105%) } to{ transform:translateX(240%) } }

/* 商品图（真实品牌图，独立文件放 img/，不内联） */
.pimg{position:relative;aspect-ratio:4/3;border-radius:var(--r16);overflow:hidden;background:var(--card2)}
.pimg img{width:100%;height:100%;object-fit:cover;display:block}
.pimg .pill{position:absolute;left:9px;top:9px;background:rgba(253,253,253,.92);color:var(--brand);
  font:800 10.5px/1 var(--f);padding:5px 9px;border-radius:var(--r999);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}

/* 数据块 · 主色底白字（2026-09-29 用户要求试效果：原来用墨绿黑） */
.kpi.brand{ background:var(--brand); color:#fff }
.kpi.brand .lab{ color:rgba(255,255,255,.82) }
.kpi.brand .hint{ color:rgba(255,255,255,.88) }
.kpi.brand .hint b{ color:#fff; font-weight:900 }
.kpi.brand .num small{ color:rgba(255,255,255,.86) }
.kpi.brand .more{ color:#fff }

/* ══ 🔴🔴🔴 2026-10-21 用户令（核心能力卡两处）═══════════════════════════════
   ①「管理体系 / 核心配方 / 权威背书，**用一个颜色**。」
      ⇒ 「权威背书」原来被 `<b>` 包着，命中 `.kpi.brand .hint b{color:#fff;font-weight:900}`
         ⇒ 比旁边两个更白更粗。HTML 里已去掉 <b>（⛔ 别再加回来）。
         这两条规则**保留**是给别处万一还有 `<b>` 用，但 `.kpi.brand` 卡里不再出现。
   ②「**4、127、6，这一排字应该高度一致**，在有的手机上面显示的这一排字高度不一致。」
      真因＝**行盒**，不是字号：`.num` 是 `127` + `<small>项</small>` 组成的可换行行内盒，
      窄屏（≤360）下会在「127」与「项」之间断行 ⇒ 中间那列变两行 ⇒ 三个标签基线被顶下去。
      ⚠️ 只在部分手机上复现 ⇒ 这种 bug 用桌面浏览器永远看不到，必须按"最窄屏"写死。
   修法（三条一起，缺一条就还会复发）：
      ① `white-space:nowrap` —— 掐死换行这条路；
      ② `display:flex;flex-direction:column` + `min-width:0` —— 三列结构完全同构，
         高度只由内容决定，顶边严格对齐；
      ③ 三列统一 `padding-left`（原来只有第 2/3 列有 ⇒ 第 1 列内容比它们靠左 14px）。
   ⚠️ 作用域限定在 `.kpi.brand`（4 个页面的同一组件），⛔ 别直接改全局 `.num` ——
      账户档案等处也用它，全局改动会牵连别的卡。 */
.kpi.brand .kpiRow{ align-items:stretch }
.kpi.brand .kpiCol{ display:flex; flex-direction:column; justify-content:flex-start; min-width:0; padding-left:14px }
/* ⚠️ 只作用在 `.kpiCol` 里的 `.num`（＝核心能力卡）。
   ⛔ 别写成 `.kpi.brand .num` —— 会员中心的「账户档案」也在这套 `.kpi.brand` 里，
      那边的 `.num` 是金额（`¥19,920.00`），一旦 nowrap 又遇 `.kpi.brand{overflow:hidden}`
      就会把高位数金额**裁掉**（比换行更糟）。 */
.kpi.brand .kpiCol > .num{ display:block; white-space:nowrap; line-height:1.05 }
.kpi.brand .kpiCol > .hint{ margin-top:5px }
/* 超窄屏（≤340，老机型/分屏）再缩一档：宁可字小一点，也⛔ 不许换行、⛔ 不许溢出 */
@media (max-width:340px){
  .kpi.brand .kpiCol{ padding-left:9px }
  .kpi.brand .kpiCol > .num{ font-size:29px; letter-spacing:-1px }
  .kpi.brand .kpiCol > .num small{ font-size:12.5px; margin-left:4px }
}

/* 紧凑商品卡：一行两个（用户要求：不要大图） */
.pgrid{ display:grid; grid-template-columns:1fr 1fr; gap:9px }
.pcard{ background:var(--card); border:1px solid var(--line); border-radius:var(--r16);
  padding:8px; display:flex; flex-direction:column; gap:7px; min-width:0 }
.pcard .pimg{ aspect-ratio:1/1; border-radius:var(--r12); background:var(--card2);
  position:relative; overflow:hidden }
.pcard .pimg img{ width:100%; height:100%; object-fit:cover; display:block }
.pcard .pimg .pill{ position:absolute; left:6px; top:6px; background:rgba(253,253,253,.92);
  color:var(--brand); font:800 9.5px/1 var(--f); padding:4px 7px; border-radius:var(--r999) }
/* 🔴🔴 2026-10-01 用户令：「上面 4 个方框要锁死格式，不管在任何手机上，字体大小都不能换行。」
   实测（canvas 量同字体自然宽）：最长标题「雅之林®丨痛风高尿酸健康管理」12.5px 下**自然宽 173px**，
        而卡片标题框：320 屏 **124px** / 360 屏 144px / 375 屏 151px / 390 屏 159px / 430 屏 179px。
   ⇒ **固定字号在窄屏一定换行**（320 屏要 ≤8.9px 才放得下）。所以改成「按视口线性收缩」：
        font = min(12.5px, 3.6vw − 3px)  →  320≈8.5 / 375≈10.5 / 390≈11.0 / 430≈12.5
        与实测的「单行上限」逐档比过：390 需 ≤11.5、430 需 ≤12.9、375 需 ≤10.9 ⇒ 都留了余量。
   ⛔ 不要改回 `-webkit-line-clamp:2` —— 那正是**会换行**的写法（也是这次要锁掉的东西）。
   ⚠️ 万一某台真机字体渲染更宽，兜底是 `ellipsis`（截断成 …）而**不是换行** ⇒ 4 张卡高度永远一致、布局不会崩。
   📌 `min-height:34px`（原为两行预留）已去掉：单行时 4 个标题等高等宽，卡面自然齐平。 */
.pcard h3{ font-weight:900; font-size:min(12.5px, calc(3.6vw - 3px)); line-height:1.35;
  font-family:var(--f); letter-spacing:0;
  margin:0; min-height:0; display:block;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.pcard .spec{ font:600 10.5px/1.4 var(--f); color:var(--sub); margin:0;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.pcard .pr{ display:flex; align-items:baseline; gap:5px; margin-top:auto }
.pcard .pr b{ font:900 15px/1 var(--f); font-variant-numeric:tabular-nums }
.pcard .pr s{ font:700 10.5px/1 var(--f); color:var(--mute); text-decoration:line-through }
.pcard:active{ transform:scale(.98) }

/* 胶囊标签（交互 10：选中放大 + 相邻让位） */
.chips{display:flex;gap:7px;overflow-x:auto;padding:2px 0 4px;scrollbar-width:none}
.chips::-webkit-scrollbar{display:none}
.chip{
  flex:none;height:31px;padding:0 14px;border-radius:var(--r999);border:1px solid var(--line);
  background:var(--card);color:var(--sub);font:800 12px/29px var(--f);white-space:nowrap;
  transition:transform var(--t) var(--spring),background var(--t) var(--ease),color var(--t) var(--ease),border-color var(--t) var(--ease);
}
.chip[aria-selected="true"]{background:var(--brand);border-color:var(--brand);color:var(--brand-ink);transform:scale(1.06)}
.chip:active{transform:scale(.95)}

/* 按钮 */
.cta{
  display:flex;align-items:center;justify-content:center;gap:7px;width:100%;height:46px;
  border-radius:var(--r16);background:var(--brand);color:var(--brand-ink);font:900 14.5px/1 var(--f);
  transition:transform var(--t-fast) var(--ease);
}
.cta:active{transform:scale(.975)}
.cta.ghost{background:var(--card);border:1px solid var(--line);color:var(--ink)}
.cta.dark{background:var(--deep);color:var(--on-deep)}

/* 进度条（交互 06：推进带回弹） */
.bar{height:6px;border-radius:var(--r999);background:var(--line2);overflow:hidden}
.bar i{display:block;height:100%;border-radius:var(--r999);background:var(--brand);
  transition:width var(--t-slow) var(--spring)}

/* 文本展开（交互 05：展开后下方整体让位，而不是挤走已有内容） */
.exp{overflow:hidden;transition:height var(--t-slow) var(--ease)}
.exp[hidden]{display:block;height:0}
.more{font:800 11.5px/1 var(--f);color:var(--brand-ink);display:inline-flex;align-items:center;gap:4px;padding:4px 0}
.more svg{width:12px;height:12px;stroke:currentColor;fill:none;stroke-width:2.6;stroke-linecap:round;transition:transform var(--t) var(--ease)}
.more[aria-expanded="true"] svg{transform:rotate(180deg)}

/* 底部导航：液态玻璃悬浮胶囊（唯一源） */
/* ══════════════════════════════════════════════════════════════════════════
   🔴🔴 2026-10-02 统一底栏：`#tabbar` 的外壳值**改为引用 `_footer.css` 里的 `--lx-*`**
   —— 因为商品详情页的 `.gfoot` 也换成了同一套悬浮胶囊，两份定义必须收成一份。
   ⚠️ 每个 `var()` 都带**兜底**（原字面值）：`抽奖.html` 引了本文件却没引 `_footer.css`，
      没有兜底它会直接塌掉。
   ⚠️ 数值**逐字未变** ⇒ 4 个主页的计算样式必须 0 变化，由 `_t_底栏基线.mjs diff` 守住。
   ══════════════════════════════════════════════════════════════════════════ */
#tabbar{
  position:fixed;left:50%;transform:translateX(-50%);
  /* 🔴🔴🔴 2026-10-21 修安卓「底栏自动隐藏，要上拉页面才显示」——见 `_footer.css` 里 `--lx-lift` 那段长注释。
     三层写法（顺序不能乱，⛔ 也别把 env()/max() 再塞回 var() 兜底里）：
       ① 纯长度保底（老内核唯一认的一条）
       ② 纯长度变量（各页可覆盖，值仍是纯长度）
       ③ @supports 里才用 env()（现代内核 = 原来的逐像素行为：安卓 2px / iPhone max(2px, 34-14)=20px） */
  bottom:2px;
  bottom:var(--lx-lift,2px);
  width:var(--lx-w,min(406px, calc(100% - 24px)));height:var(--lx-h,62px);display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  align-items:stretch;gap:var(--lx-gap,4px);padding:var(--lx-pad,5px);z-index:70;border-radius:var(--lx-r,24px);
  background:var(--lx-bg,rgba(253,253,253,.84));
  -webkit-backdrop-filter:var(--lx-blur,blur(22px) saturate(180%));backdrop-filter:var(--lx-blur,blur(22px) saturate(180%));
  box-shadow:var(--lx-sh,inset 0 1px 0 rgba(255,255,255,.78),inset 0 -1px 0 rgba(255,255,255,.34),0 18px 40px -18px rgba(18,24,48,.40),0 2px 10px rgba(18,24,48,.08));
}
/* ③ 有安全区（iPhone 底部横条）时按原公式抬高：与改动前**逐像素一致**。
   ⚠️ 老内核不认 `@supports` 的条件（`max()`/`env()`）⇒ 整块跳过 ⇒ 用上面 ①② 的 2px。 */
@supports (bottom: max(2px, calc(env(safe-area-inset-bottom, 0px) - 14px))){
  #tabbar{ bottom:max(2px, calc(env(safe-area-inset-bottom, 0px) - 14px)) }
}
#tabbar a{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  border-radius:var(--lx-cell-r,19px);color:rgba(48,54,52,.70);font:700 10.5px/1.15 var(--f);transition:color var(--t) var(--ease)}
#tabbar a svg{width:23px;height:23px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
#tabbar a::before{content:"";position:absolute;inset:0;left:0;top:0;right:0;bottom:0;
  width:auto;height:auto;margin:0;transform:none;border-radius:var(--lx-cell-r,19px);opacity:0;
  background:var(--brand-soft);transition:opacity var(--t) var(--ease)}
#tabbar a[aria-selected="true"]{color:var(--brand);font-weight:900}
#tabbar a[aria-selected="true"]::before{opacity:1;background:color-mix(in srgb,var(--brand) 18%,#FFFFFF)}
#tabbar a[aria-selected="true"] svg{transform:translateY(-1px) scale(1.06)}
#tabbar a>span{position:relative;z-index:1}
/* 🔴 底栏「健康中心」右上角的**未核销奖品红点**（数字＝未核销件数，0 件不显示）。
   定位：图标是居中的，所以从 50% 往右偏 6px 就是图标右上角。 */
#tabbar a .tab-num{position:absolute;left:calc(50% + 6px);top:1px;min-width:17px;height:17px;padding:0 4px;
  border-radius:9px;background:#E5484D;color:#fff;font:900 10.5px/17px var(--f);text-align:center;
  box-shadow:0 2px 6px rgba(229,72,77,.45);z-index:2}
#tabbar a:active{transform:scale(.96)}
/* ══ 🔴🔴 2026-10-07 用户令（底栏 4 页 + 慢病）══════════════════════════════════
   原话：「4 个页面底部的导航栏，底色稍微深一点；更换动画效果，要那种**液体滑动**效果，
          按一下要有**动画反馈**，最好加上**震动反馈**（如果手机支持）；4 个图标也加上动态效果。」
   ⇒ 实现（全部靠这一处共享 CSS + `_tabdot.js` 里 8 行 JS，7 个页面同时生效）：
     ① 底色：由原来的 `…84` 半透明改成更实、更深一档（`--tb-bg`，可被单页覆盖）；
     ② 液体滑动：`#tabbar::after` 当**滑块**，位置/宽度由 JS 写 `--tb-x/--tb-w`
        （`MutationObserver` 盯 `aria-selected`），过渡用带回弹的贝塞尔 ⇒ 视觉上是"液滴滑过去"；
        同时把旧的"每项自带高亮"关掉（`.a::before` 选中态透明），避免两层高亮打架；
     ③ 按压反馈：`:active` 时图标回弹一下；④ 震动在 `_tabdot.js`（`navigator.vibrate(12)`）。
   ⚠️ 尊重 `prefers-reduced-motion`。 */
/* ══ 🔴🔴 2026-10-07 用户选定【方案 A · 白玻璃悬浮胶囊】══
   原话：「方案 A 白玻璃悬浮胶囊用这个方案，要改成我们相应的图标和文字。」
   ⇒ 图标/文字**保留各页原有的**（站内 sprite 图标 + 中文标签），这里只统一「容器长相」：
      · 白磨砂玻璃 + 1px 淡描边（⛔ 不是上一版那种发灰发绿的实底 —— 用户明确说难看）；
      · 更靠下（bottom 8px）、更高（74px）、图标 27px（原 23px，用户说“按钮有点小”）；
      · 选中项＝一块会**滑过去**的浅品牌色块（`:has()` 定位，见文件末尾）。
   ⚠️ 总占位 74+8＝82 ≤ 原来的 62+24＝86 ⇒ `_footer.css` 的让位高度**不用改**。 */
/* ⛐⛐ ⚠️ 刷新前的错误版（已废）：我曾写成 `left:12px;right:12px` 却**没清掉原来的
   `left:50% + transform:translateX(-50%)`** ⇒ 整条又被左移了半个宽度、右半边跑到屏幕外
   ⇒ 用户只看得到 **2 个按钮**。
   ⇒ 正确做法：**位置一律不碰**（继续用原来的 `left:50%` 居中），
      只改"尺寸 + 外观"：更高、更宽、白玻璃、圆角。 */
#tabbar{
  width:min(430px, calc(100% - 20px));height:74px;border-radius:26px;
  background:rgba(255,255,255,.9);border:1px solid rgba(16,20,19,.07);
  -webkit-backdrop-filter:blur(18px) saturate(1.6);backdrop-filter:blur(18px) saturate(1.6);
  box-shadow:0 10px 26px -12px rgba(16,20,19,.3)}
#tabbar a svg{width:27px;height:27px}
#tabbar a>span{font-size:11.5px;font-weight:800}
#tabbar::after{content:"";position:absolute;left:var(--tb-x,0px);width:var(--tb-w,0px);top:7px;bottom:7px;
  border-radius:19px;background:color-mix(in srgb,var(--brand) 11%,#FFFFFF);
  transition:left .34s cubic-bezier(.34,1.56,.64,1),width .34s cubic-bezier(.34,1.56,.64,1);
  pointer-events:none;z-index:0}
#tabbar a{position:relative;z-index:1}
#tabbar a[aria-selected="true"]::before{opacity:0}
#tabbar a[aria-selected="true"] svg{animation:tbPop .38s cubic-bezier(.34,1.56,.64,1) both;transform-origin:50% 62%}
@keyframes tbPop{0%{transform:translateY(0) scale(1)}45%{transform:translateY(-3px) scale(1.14)}100%{transform:translateY(-1px) scale(1.06)}}
#tabbar a:active svg{animation:tbTap .22s ease both}
@keyframes tbTap{0%{transform:scale(1)}50%{transform:scale(.86)}100%{transform:scale(1)}}
@media (prefers-reduced-motion:reduce){
  #tabbar::after{transition:none}
  #tabbar a[aria-selected="true"] svg,#tabbar a:active svg{animation:none}
}


/* ══════════════════════════════════════════════════════════════════════════
   积分转盘 · 健康中心最下方「抽奖区」                     2026-10-01
   ----------------------------------------------------------------------------
   🔴 用户令：「这个转盘是放在健康中心最下面的，也就是现在『福利专区』的位置，
      而且是用积分兑换的。」⇒ 原「福利专区」四张商品卡 → 转盘；
      转盘下方一条链接 → 弹出「奖品与产品展示」。
   ⛔ 转盘**不用彩虹色**：整盘走单色阶蓝，只有「免疫力」与「谢谢参与」用稍亮那档；
      指针用品牌金（金只出现在这里与中奖态，不上浅底当文字）。
   ⛔ 零 innerHTML（项目铁律）—— 转盘扇区用 createElementNS 构建。
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 积分行 ── */
.lot-credit{margin-top:11px;display:flex;align-items:center;gap:10px;border-radius:var(--r16);padding:13px 14px;
  background:var(--lc-bg,var(--brand));color:var(--lc-fg,var(--brand-ink));
  --lc-bg:var(--brand);--lc-fg:var(--brand-ink);--lc-sub:rgba(255,255,255,.78);--lc-em:var(--gold)}
.lot-credit .k{flex:1;min-width:0}
.lot-credit .k i{display:block;font:600 11px/1 var(--f);font-style:normal;letter-spacing:.14em;color:var(--lc-sub)}
.lot-credit .k b{display:block;margin-top:6px;font:900 24px/1 var(--f);letter-spacing:-.6px;font-variant-numeric:tabular-nums}
.lot-credit .k b em{font-style:normal;font-size:12.5px;font-weight:800;opacity:.82;margin-left:3px}
.lot-credit .c{text-align:right;font:700 11.5px/1.5 var(--f);color:var(--lc-sub)}
.lot-credit .c b{display:block;font:900 15px/1.3 var(--f);color:var(--lc-fg)}
.lot-credit .c em{font-style:normal;color:var(--lc-em);font-size:16px}

/* ⛔⛔ `.lot-hero` / `.lot-hero-sub`（字标「转 / 盘」＋「抽大奖」，含 ltTurn / ltBeat 两个动效）
   **已整段删除** —— 用户 2026-10-01 令：「你把那个『转盘抽大奖』这几个字都给我去掉，太难看了。」
   ⛔ 别再恢复：转盘上面不放任何标题字。 */

/* ── 转盘 ── */
.lot-wrap{position:relative;width:min(296px,calc(100vw - 56px));aspect-ratio:1;margin:18px auto 0}
/* 🔴 旋转的是**盘面**（#lotSpin 这个 <g>），不是 <svg> 画布本身。
   转画布的话，方形画布转起来四角会伸出容器 ⇒ 320 屏横向溢出 9px（实测）。
   转内部 <g>：超出 viewBox 的部分被 SVG 自动裁掉，容器尺寸恒定。 */
.lot-wrap > svg{width:100%;height:100%;display:block}
.lot-wrap > svg > g#lotSpin{transform-origin:100px 100px;
  transition:transform 5.2s cubic-bezier(.13,.72,.16,1)}
.lot-ring{position:absolute;inset:-10px;border-radius:50%;border:1px solid var(--brand-line);z-index:-1;
  background:radial-gradient(circle at 50% 40%,var(--card) 0%,var(--brand-soft) 100%)}
.lot-ptr{position:absolute;left:50%;top:-7px;transform:translateX(-50%);z-index:2;width:0;height:0;
  border-left:11px solid transparent;border-right:11px solid transparent;border-top:16px solid var(--gold);
  filter:drop-shadow(0 3px 5px rgba(201,162,74,.5))}
.lot-hub{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:94px;height:94px;border-radius:50%;
  background:var(--card);border:0;cursor:pointer;font-family:inherit;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  box-shadow:0 10px 26px -12px rgba(0,26,99,.55),inset 0 0 0 1px var(--line)}
.lot-hub b{font:900 16px/1 var(--f);color:var(--brand);letter-spacing:.5px}
.lot-hub i{font-style:normal;font:800 10px/1 var(--f);color:var(--sub)}
.lot-hub:disabled{opacity:.6;cursor:default}
.lot-hub:active{transform:translate(-50%,-50%) scale(.95)}

/* ⛔⛔ `.lot-res`（开奖结果条）**整块已删除** ——
   用户 2026-10-01 令：「正在开奖和本次未中奖的这些字都去掉。」
   ⛔ 别恢复：反馈走「圆钮上的文字 + 中奖提示窗」，页面上不再有结果条。 */

/* ── 「奖品与产品展示」入口链接（转盘下方）── */
.lot-more{margin-top:11px;width:100%;display:flex;align-items:center;gap:11px;cursor:pointer;text-align:left;
  position:relative;font-family:inherit;border-radius:var(--r16);padding:13px 14px;
  border:1px solid var(--brand-line);background:var(--brand-soft);color:var(--brand)}
/* 入口右上角的**未核销红点**（🔴 用户令：中 1 个显 1、中 2 个显 2；0 件不显示） */
.lot-num{position:absolute;top:-7px;right:-7px;min-width:19px;height:19px;padding:0 5px;border-radius:10px;
  background:#E5484D;color:#fff;font:900 11.5px/19px var(--f);text-align:center;
  box-shadow:0 2px 8px rgba(229,72,77,.45)}
.lot-more .tx{flex:1;min-width:0}
.lot-more .tx b{display:block;font:900 13.5px/1.4 var(--f)}
.lot-more .tx i{display:block;margin-top:3px;font-style:normal;font:600 11.5px/1.6 var(--f);color:var(--sub)}
.lot-more .go{flex:none;width:26px;height:26px;border-radius:50%;padding-bottom:1px;
  background:var(--brand);color:var(--brand-ink);display:grid;place-items:center;font:900 15px/1 var(--f)}
.lot-more:active{transform:scale(.985)}

/* ── 概率卡 ── */
.lot-card{margin-top:11px;border-radius:var(--r16);background:var(--card);border:1px solid var(--line);padding:14px}
.lot-card > h2{margin:0 0 9px;font:900 14px/1.3 var(--f)}
.lot-card .fine{margin:10px 0 0;font:600 11.5px/1.7 var(--f);color:var(--mute)}
.lot-card .fine b{color:var(--ink)}
/* ⛔ `.lot-odds`（概率公示列表）整段已删 —— 用户 2026-10-01 令：中奖概率不对客户公示。
   ⛔ 别再恢复这套样式，恢复就等于把概率搬回页面。 */

/* ── 「奖品与产品展示」抽屉 ── */
.lot-sheet{position:fixed;inset:0;z-index:210;display:flex;align-items:flex-end;
  background:rgba(16,20,19,.5);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.lot-sheet[hidden]{display:none}
.lot-sheet-box{width:100%;max-height:86vh;display:flex;flex-direction:column;overflow:hidden;
  background:var(--card);border-radius:var(--r22) var(--r22) 0 0;animation:lotUp .32s var(--ease) both}
@keyframes lotUp{from{transform:translateY(100%)}to{transform:none}}
@keyframes lotIn{from{opacity:0;transform:translateY(14px) scale(.98)}to{opacity:1;transform:none}}
@media (min-width:560px){
  .lot-sheet{align-items:center;justify-content:center;padding:18px}
  .lot-sheet-box{width:min(520px,100%);border-radius:var(--r22);animation:lotIn .3s var(--ease) both}
}
.lot-sheet-hd{flex:none;display:flex;align-items:flex-start;gap:10px;padding:16px 16px 12px;border-bottom:1px solid var(--line2)}
.lot-sheet-hd h3{margin:5px 0 0;font:900 16px/1.3 var(--f)}
.lot-sheet-x{margin-left:auto;flex:none;width:32px;height:32px;border:0;border-radius:50%;cursor:pointer;
  background:var(--card2);color:var(--sub);font:700 19px/1 var(--f);font-family:inherit}
.lot-sheet-bd{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:0 16px 16px}
.lot-sheet-bd::-webkit-scrollbar{width:0}
.lot-sheet-ft{flex:none;padding:12px 16px calc(12px + env(safe-area-inset-bottom,0px));border-top:1px solid var(--line2)}
.lot-sheet-ft p{margin:0 0 10px;font:600 11.5px/1.7 var(--f);color:var(--mute)}
.lot-sheet-ft p b{color:var(--ink)}
.lot-sheet-ft button{width:100%;height:46px;border:0;border-radius:13px;cursor:pointer;font-family:inherit;
  background:var(--brand);color:var(--brand-ink);font:900 14px/1 var(--f)}
.lot-gset h4{margin:16px 0 9px;display:flex;align-items:baseline;gap:7px;font:900 13.5px/1.3 var(--f)}
.lot-gset h4 em{flex:none;align-self:center;width:18px;height:18px;border-radius:6px;font-style:normal;
  background:var(--brand-soft);color:var(--brand);font:900 10px/1 var(--f);display:grid;place-items:center}
.lot-gset h4 span{font:600 11px/1.3 var(--f);color:var(--mute)}
.lot-gset > p{margin:9px 0 0;font:600 11.5px/1.7 var(--f);color:var(--sub)}

/* ── 「我的奖品」弹窗里的中奖记录卡 ────────────────────────────────────────
   🔴 2026-10-01 用户令：抽奖兑换从「我的订单」移到转盘下方这一行的弹窗里。 */
.pz-card{padding:12px;margin-bottom:10px;border-radius:var(--r12);
  background:var(--card);border:1px solid var(--line)}
.pz-hd{display:flex;align-items:baseline;gap:8px}
.pz-hd b{flex:1;min-width:0;font:900 14px/1.4 var(--f);color:var(--ink)}
.pz-st{flex:none;font:900 10.5px/1;border-radius:7px;padding:4px 7px;white-space:nowrap;
  color:#C24318;background:rgba(194,67,24,.12);border:1px solid rgba(194,67,24,.3)}
.pz-st.used{color:var(--sub);background:var(--card2);border-color:var(--line)}
.pz-meta{margin:7px 0 0;font:600 11.5px/1.6 var(--f);color:var(--sub);font-variant-numeric:tabular-nums}
.pz-qr{margin-top:10px;display:flex;justify-content:center;padding:10px;border-radius:12px;background:var(--card2)}
.pz-qr canvas{width:150px;height:150px;display:block}

/* ── 已核销的自动折叠（2026-10-04 用户令）─────────────────────────────────────
   「前台核销完，**自动折叠起来留存到底部**，留存的位置**只显示简单的信息**，
     点开可以查看中奖和核销的信息。」
   ⇒ 已核销卡：默认 `folded` —— 只留「奖品 + 已核销 + 时间」，兑换码/二维码收进 `.pz-body`；
      整卡可点展开（键盘 Enter/空格也行）。
   ⚠️ 折叠动画走 `grid-template-rows: 0fr → 1fr`（不用 `max-height` 猜高度，
      也不动 `display`）—— 关掉不支持的浏览器时只是**不animate**，折叠本身照样生效。 */
.pz-card.used{border-style:dashed;background:var(--card2)}
.pz-card.tapable{cursor:pointer;-webkit-tap-highlight-color:transparent}
.pz-card.tapable:active{transform:scale(.994)}
.pz-brief{margin:6px 0 0}
.pz-chev{display:block;margin-top:8px;font:700 11.5px/1.5 var(--f);color:var(--brand);text-align:right}
.pz-body{display:grid;grid-template-rows:1fr;opacity:1;margin-top:2px;
  transition:grid-template-rows .34s cubic-bezier(.22,1,.36,1),opacity .22s ease}
.pz-card.folded .pz-body{grid-template-rows:0fr;opacity:0}
.pz-inner{overflow:hidden;min-height:0;transition:visibility 0s linear 0s;visibility:visible}
/* ⚠️ 折叠后内容只是"高度 0"，仍然可被 Tab 聚焦、也能被点到 ⇒ 收完再把它藏掉。
   延迟 .34s 是因为要等折叠动画播完（立即 hidden 会让动画看不见）。 */
.pz-card.folded .pz-inner{visibility:hidden;transition:visibility 0s linear .34s}

/* ── 下拉刷新指示条（2026-10-22 第 56 轮）────────────────────────────────────
   用户令：「我的奖品，下拉要能够刷新这一页。」
   高度由 JS 从 0 长出来（`_lottery.js` 的 bindPzPull），⛔ 不要给它固定高度：
   否则列表会被永久顶下去一截。 */
.pz-ptr{height:0;overflow:hidden;display:flex;align-items:center;justify-content:center;
  font:700 11.5px/1.5 var(--f);color:var(--sub);letter-spacing:.4px;
  transition:height .16s ease;user-select:none;-webkit-user-select:none;pointer-events:none}

/* ── 「刚刚被核销」高亮（2026-10-22 第 56 轮）────────────────────────────────
   为什么要有：卡片被核销后会**自动沉到列表最底部**（用户令：「自动退到最底部」），
   不给一下高亮，用户会以为"我的奖怎么没了"。
   ⚠️ 只亮 2.2 秒（`_lottery.js` 里定时移除），⛔ 不要改成常驻样式。 */
.pz-card.pz-just{animation:pzJust 1.1s ease-out 2}
@keyframes pzJust{
  0%{box-shadow:0 0 0 0 rgba(201,162,74,.0);border-color:var(--brand)}
  35%{box-shadow:0 0 0 3px rgba(201,162,74,.28)}
  100%{box-shadow:0 0 0 0 rgba(201,162,74,0)}
}
@media (prefers-reduced-motion: reduce){
  .pz-card.pz-just{animation:none}
  .pz-ptr{transition:none}
}

.lot-empty{padding:34px 0;text-align:center;color:var(--sub)}
.lot-empty b{display:block;font:900 15px/1.6 var(--f);color:var(--ink)}
.lot-empty span{display:block;margin-top:6px;font:600 12.5px/1.6 var(--f)}

/* 商品小卡（抽屉内用，**不套 .pcard** —— 那边 h3 被锁成单行省略，这里是两行制） */
.ggrid{display:grid;grid-template-columns:1fr 1fr;gap:9px}
.gcard{display:flex;flex-direction:column;padding:7px;border-radius:var(--r12);
  background:var(--card);border:1px solid var(--line)}
.gcard .im{position:relative;aspect-ratio:1/1;border-radius:9px;overflow:hidden;background:var(--card2)}
.gcard .im img{width:100%;height:100%;object-fit:cover;display:block}
/* ⛔ 2026-10-01 用户令：「4 个日用品的图片显示不全」⇒ **取消裁切，完整显示**。
   背景：那 4 张日用品主图自带「会员福利 / 免费兑换 / 0 元」促销带，
        上一版为了把它切掉做了 10:7 裁底，结果图被裁掉 30% 用户不满意。
   ⇒ 现在一律 `1:1` 完整显示（`.gcard.cut` 规则已删）。
   📌 若以后要去掉图上促销带：**正确做法是重新出图**，⛔ 不要再靠 CSS 裁。 */
.gcard b{margin:8px 0 0;font:800 11.5px/1.4 var(--f);color:var(--ink);overflow:hidden;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.gcard b sup{font-size:.7em;line-height:0;position:relative;top:-.35em}
.gcard i{display:block;margin-top:4px;font-style:normal;font:600 10.5px/1.45 var(--f);color:var(--sub)}

/* ── 中奖提示窗（大尺寸克莱因蓝）──────────────────────────────────────────
   🔴🔴 2026-10-01 用户令：「中奖后的核销码不需要弹出来，只需给用户一个提示，
      让他去『会员中心』的『我的订单』里面查看。提示可以使用一个大尺寸的克莱因蓝窗口。」
   ⛔ `.lot-cert*`（旧的中奖凭证弹层，带二维码）**整段已删** —— 别恢复。
   ⛔ 也别把二维码/凭证号加进这个窗口：核销码只在「我的订单 → 抽奖兑换」里出现。
   ⚠️ 金色只用在蓝底上（本项目铁律：金不上浅底）；深色模式下窗口改浅蓝底 + 深字。 */
.lot-win{position:fixed;inset:0;z-index:220;display:flex;align-items:center;justify-content:center;padding:20px;
  background:rgba(16,20,19,.55);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
.lot-win[hidden]{display:none}
.lot-win-box{width:min(420px,100%);padding:30px 22px 22px;border-radius:var(--r22);text-align:center;
  background:var(--brand);color:var(--w-fg);
  --w-fg:#fff;--w-sub:rgba(255,255,255,.88);--w-btn-bg:#fff;--w-btn-fg:var(--brand);
  box-shadow:0 30px 70px -24px rgba(0,20,80,.66);animation:lotWinIn .34s var(--spring) both}
@keyframes lotWinIn{from{opacity:0;transform:translateY(20px) scale(.94)}to{opacity:1;transform:none}}
.lot-win-box .wk{display:block;font-size:46px;line-height:1}
.lot-win-box .wt{display:block;margin-top:15px;font:900 24px/1.3 var(--f);letter-spacing:-.4px;color:var(--w-fg)}
.lot-win-box .wn{margin:14px 0 0;font:600 13.5px/1.85 var(--f);color:var(--w-sub)}
.lot-win-box .wn b{color:var(--gold)}
.lot-win-box .wb{width:100%;height:50px;margin-top:22px;border:0;border-radius:14px;cursor:pointer;font-family:inherit;
  background:var(--w-btn-bg);color:var(--w-btn-fg);font:900 15px/1 var(--f)}
.lot-win-box .wb:active{transform:scale(.98)}
@media (prefers-reduced-motion:reduce){ .lot-win-box{animation:none} }

/* 📌 2026-10-04：统一提示窗（`.yz-toast`）的样式**不在本文件里**，而在 `_toast.css`。
   为什么不留在这里（本轮验收实测踩到的）：**商品详情.html 与 支付.html 根本没加载 `yzl.css`**
   （它们只引 `_footer.css` + 自己的内联 `<style>`）⇒ 样式和 `--brand` 令牌在它们那儿都不存在，
   提示窗会退化成"挂在文档最末尾的一条无样式文字"（= 用户根本看不见，正是本项目踩过一次的老坑）。
   ⇒ 提示窗是**全站每个页面都要有**的组件，它的样式必须跟它自己的 JS 放在一起
       （`_toast.js` + `_toast.css`），由 **8 个页面各自显式引入**，⛔ 不依赖某个页面是否装了设计系统。
   本文件仍然是**栏目色令牌（--brand 四色轴）的唯一源**，提示窗只是消费它。
   ⛔ 不要为了图省事把 `.yz-toast` 再加回这里 —— 那会变成"两处都有"，改一处漏一处。 */

/* ── 底栏滑块：**纯 CSS 定位**（`_tabdot.js` 只负责震动；滑块靠 `:has()` 选中项自己找位置）
   🔴🔴🔴 2026-10-24（第 78 轮）：这里原本是「4 格 / 5 格两组百分比规则」，
   **现已整段删除**，原因有两条，缺一条都不该动：
     ① 它们**从来没有生效过** —— 下面 852 行的 `left:0!important` 与 876 行那组
        `left/width + !important` 早就把它们完全覆盖了，属于典型"看着像在用、其实死了"的死代码；
     ② 它们的分母是 **4**（`left:calc(100%*n/4)`），而底栏从第 77 轮起**只剩 3 个按钮**
        （工作站并入会员中心后 `#tabbar` 里只有 3 个 `<a>`）—— 分母 4 就是这次
        「3 个按钮排列不平均」的根因之一。
   ⇒ 现在滑块位置/宽度的唯一生效处在下面 852~886 那段（3 格数学），⛔ 别在这里重新加规则。 */

/* ── 🔴 2026-10-07 用户令：① 「已冻结」做成**红色胶囊**（更显眼）
   ② 提现/转账面板只要有冻结金额，就在金额行下面挂一条提示（用户报「点『全部』没有提示」） */
.fz-pill{display:inline-block;margin-left:4px;padding:1px 7px;border-radius:999px;
  background:#FDECEC;color:#C0392B;border:1px solid #F3C9C9;
  font:800 11px/1.5 var(--f,-apple-system,"PingFang SC","HarmonyOS Sans SC","HarmonyOS Sans","MiSans","OPPO Sans","vivo Sans","Source Han Sans SC","Noto Sans CJK SC","Noto Sans SC","Microsoft YaHei",sans-serif);
  vertical-align:middle;white-space:nowrap}
.fz-tip{margin:6px 0 0;padding:6px 9px;border-radius:9px;background:#FDECEC;color:#C0392B;
  font:700 11.5px/1.5 var(--f,-apple-system,"PingFang SC","HarmonyOS Sans SC","HarmonyOS Sans","MiSans","OPPO Sans","vivo Sans","Source Han Sans SC","Noto Sans CJK SC","Noto Sans SC","Microsoft YaHei",sans-serif)}

/* 🔴🔴 2026-10-07 用户报：「收益明细里『全球董事分红 747』下面那个『已冻结』红色胶囊**太长了**，
   缩短到只包住『已冻结』三个字就行。」
   真因：副标题那一格是 **flex 容器**（或块级）⇒ 我注入的那个 `inline` 胶囊被当成 flex 项
        **拉伸到了整行宽度**（`align-items:stretch` 的默认行为）⇒ 看起来就是一条长红条。
   ⇒ 三件事一起做才稳：`align-self:flex-start`（不拉伸）+ `flex:0 0 auto`（不参与伸缩）
      + `width:auto/max-width:max-content`（宽度由文字决定）。
   ⚠️ 收益明细与金额行两处都用同一个 `.fz-pill`，这一条同时修好两处外观。 */
.fz-pill{align-self:flex-start;flex:0 0 auto;width:auto;max-width:max-content;display:inline-block}

/* ══════════════════════════════════════════════════════════════════════════════
   🔴🔴🔴 2026-10-12 20:23 用户令：「**方案 v2（浮动胶囊 · 可点）要用这套方案哦**」
   ------------------------------------------------------------------------------
   这是在**现有那套之上**做，⛔ 不是另起一套（现有：`--lx-*` token + `#tabbar` 白玻璃胶囊
   + `:has()` 槽位滑块 + `_tabdot.js` 的按压震动）。
   本段一律**追加在文件末尾** ⇒ 同优先级后写者胜，只覆盖需要改的几项，其余原样保留。

   一、**「基本是跳转的」的真凶**（这次定位到根因）：
       原滑块是 `#tabbar:has(...)::after{left:calc(100% * N / 4)}` —— 用 **`left` 定位**。
       `left` 走**布局**（每帧重排、不进 GPU），必然掉帧 ⇒ 观感就是"啪"地跳过去。
       ✅ 改成 **`transform: translateX()`**（只走合成器）：
          · 宽度固定 `calc(100% / 4 | 5)`（由 `:has(> a:nth-child(5))` 分流，沿用原逻辑）
          · 位置改由 `--tb-i` 驱动：`transform:translateX(calc(var(--tb-i,0) * 100%))`
            （百分比是相对**自身宽**＝一个槽位，正好一格）
          · `:has()` 规则只负责**给 `--tb-i` 赋值**（0..4），⛔ 不再写 left/width
          · `will-change:transform` 提前提层
       ⚠️ 这是"同一套逻辑换实现"，槽位数学与原来**逐格对应**，⛔ 不要顺手改分母。

   二、**更透明**（用户：「要有透明的效果」）：`.9` → `.34`，blur 18 → 28、saturate 1.6 → 2，
       并换成 1px 亮边（原来那条 `rgba(16,20,19,.07)` 深描边会让玻璃显脏）。
       ⛔ **尺寸一律不动**（用户铁律「大小不要改」）：仍 `min(430px, 100% - 20px)` / `74px`。
       圆角 26 → `999px`（这是"形式"，不是"大小"；参考图 iOS 就是全胶囊）。

   三、**补齐预览 v2/v3 那几层**：滑块拉伸 · 拖尾 · 整条底栏受压 · 每个图标弹跳（含失去选中的）。

   ⚠️ `prefers-reduced-motion` 下**全部停**（本段末尾）。
   ══════════════════════════════════════════════════════════════════════════════ */
#tabbar{
  background:rgba(255,255,255,.34)!important;
  -webkit-backdrop-filter:blur(28px) saturate(2)!important;
  backdrop-filter:blur(28px) saturate(2)!important;
  border:1px solid rgba(255,255,255,.62)!important;
  border-radius:999px!important;
  box-shadow:0 10px 30px rgba(16,20,19,.18),inset 0 1px 0 rgba(255,255,255,.8)!important;
  /* 🔴🔴 2026-10-12 本地预验抓到的**致命坑**：⛔ 绝不能在这里裸写 `transform:translateZ(0)` ——
     `#tabbar` 是用 `left:50%` ＋ `transform:translateX(-50%)` 居中的，
     裸写一个 transform 会把"居中那半句"**覆盖掉** ⇒ 整条右移半个宽度、右半边出屏，
     用户只看得到 2 个按钮（本文件上面 485 行附近记过同一条血案，我这次又踩了一次）。
     ✅ 正确写法＝**把原句带上一起写**：translateX(-50%) 管居中，translateZ(0) 管提成合成层。 */
  transform:translateX(-50%) translateZ(0);
  /* 🔴🔴🔴 2026-10-12 20:53 用户附实拍：「**健康中心的按钮和会员中心的按钮的卡片边缘，
     比底部整个导航栏的横条溢出了**」⇒ 真因有两层，光调宽度治不好：
     ① 底栏是全胶囊（圆角 999）⇒ 最左/最右那格的方块角会**戳进两端的圆弧里**；
     ② 滑块宽度按 100%/n 算比格子宽（grid 有 gap）⇒ 又多了几像素。
     ① 的根治办法是 ****：让横条把滑块**裁在自己的胶囊形状内**
        —— iOS 的 App Store 就是这么做的（选中块在胶囊两端会被圆角切齐）。
     ⚠️ 副作用可接受：滑块自带的投影会被裁掉一点（视觉上无感）；
        按压动效是加在**横条自己**的  上（不是子元素）⇒ 不受影响。
     ⛔ 宽度那层已经单独修过（扣 gap），两层缺一不可。 */
  overflow:hidden;
  /* 🔴🔴 2026-10-12 21:00 用户令：「换手机也是一个样。**再往里面收一点。不要顶到头**」
     ⇒ 底栏**横向内边距 5 → 14px**（ 作唯一源）：
        ① 4 个按钮整体向中间收，不再贴着两端圆弧；
        ② 滑块的左起 / 宽度都改成**按内边距扣**，否则它按 padding box 算又会比格子宽 ⇒ 与格子错位。 */
  --tb-pad:14px;
  /* 🔴 2026-10-12 21:02 用户令：「**不要完全重合，要小一点！**」
     ⇒ 选中卡再比格子**每边小 4px**（）。
     ⛔⛔ 关键：滑块宽度变小后，位移步长**必须改成绝对算法** ——
         是相对**滑块自身宽**的，滑块一变小步长就跟着变小 ⇒ 立刻错位。
        正解：步长 = 格宽 + gap = (100% + 2*inset + gap)（因为 100% 现在＝格宽-2*inset）。 */
  --tb-inset:4px;
  padding-left:var(--tb-pad)!important;
  padding-right:var(--tb-pad)!important;
  --tb-dur:.52s}

/* ── 滑块：改成 transform 驱动 ─────────────────────────────────────────────── */
#tabbar::after{
  left:0!important;
  /* 🔴🔴 2026-10-12 20:52 修「选中卡片边缘戳出横条圆弧」（用户附实拍：健康中心/会员中心两端溢出）：
     底栏是 grid 且带 gap ⇒ **每格比 1/4 窄**，而滑块写 100%/4 就比格子宽 ⇒
     停在第 1/最末格时，滑块的方角越过胶囊两端的圆弧 ⇒ 看起来溢出。
     正解：宽度扣掉 (n-1) 个 gap；位移步长 = 格宽 + gap ⇒ translateX(calc(i * (100% + gap)))。 */
  width:calc((100% - 2 * var(--lx-gap,4px)) / 3);
  transform:translateX(calc(var(--tb-i,0) * (100% + 2 * var(--tb-inset,4px) + var(--lx-gap,4px))));
  transition:transform var(--tb-dur,.52s) cubic-bezier(.34,1.32,.42,1);
  will-change:transform;
  background:rgba(255,255,255,.58)!important;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95),0 4px 14px rgba(16,20,19,.12)!important}
#tabbar:has(> a:nth-child(5))::after{width:calc((100% - 2 * var(--tb-pad,14px) - 4 * var(--lx-gap,4px)) / 5 - 2 * var(--tb-inset,4px))}
/* 槽位：只赋 `--tb-i`（⛔ 不再写 left/width —— left 会重排，那正是"跳"的根因） */
#tabbar:has(> a:nth-child(1)[aria-selected="true"])::after{--tb-i:0}
#tabbar:has(> a:nth-child(2)[aria-selected="true"])::after{--tb-i:1}
#tabbar:has(> a:nth-child(3)[aria-selected="true"])::after{--tb-i:2}
#tabbar:has(> a:nth-child(4)[aria-selected="true"])::after{--tb-i:3}
#tabbar:has(> a:nth-child(5)[aria-selected="true"])::after{--tb-i:4}
/* 原来的 `left` 百分比规则必须**整段清掉**（它们写在前面，靠 `!important` 压不住语义）。
   🔴🔴🔴 2026-10-12 20:42 修一个**我自己造的溢出 bug**（用户报「健康中心左边 / 会员中心右边溢出界面」）：
      我上一版图省事，把**4 格和 5 格两组**都重置成了 `width:calc(100% / 4)` ——
      ⇒ **5 个 tab 的页面上滑块宽度是 1/4（应是 1/5）** ⇒ 滑到最后一格时**右边溢出**。
      ✅ 现在按组分开：4 格 → `1/4`，5 格 → `1/5`（与原槽位数学逐格一致）。 */
/* 🔴🔴🔴 2026-10-24（第 78 轮）用户令：「**底部3个按钮要分列，平均空间**」
   ---------------------------------------------------------------------------
   根因（量出来的，不是猜）：第 77 轮删掉「工作站」后 `#tabbar` 只剩 **3 个 `<a>`**，
   而这套底栏的**网格列数与滑块分母都还是 4**：
     · `grid-template-columns:repeat(4,…)` ⇒ 3 个按钮只占前 3 列，
       **最右边空出一整列**（截图里三个按钮整体偏左、间距看着不匀，就是这个）；
     · 滑块 `width` 按 `/4` 算、`left` 又固定 14+4 ⇒ 停在任一格都对不齐。
   ⇒ 三处同时改成 3 格（n 格公式：格宽 =(100% - 2*pad -(n-1)*gap)/n）：
       ① 网格 `repeat(3,…)`（见上面 471 行那条）
       ② 本节默认滑块 `width`
       ③ 下面这组按 `--tb-i` 置位的槽位，把原来的 `nth-child(4)` 那一行删掉
   ⚠️ 滑块**位移步长**不用改：它写成 `100% + 2*inset + gap`（`100%` 是**滑块自身宽**），
      与格数无关，换格数自动正确 —— 这正是当初改用 transform 驱动换来的好处。
   ⛔ 5 格那组（`nth-child(5)`）保留：当前没有 5 格页面，但它不影响 3 格，留着当下次加栏的样板。
   ⛔ 别把 `nth-child(4)` 加回来，除非你真的放回第 4 个按钮。 */
#tabbar:has(> a:nth-child(1)[aria-selected="true"])::after,
#tabbar:has(> a:nth-child(2)[aria-selected="true"])::after,
#tabbar:has(> a:nth-child(3)[aria-selected="true"])::after{
  left:calc(var(--tb-pad,14px) + var(--tb-inset,4px))!important;width:calc((100% - 2 * var(--tb-pad,14px) - 2 * var(--lx-gap,4px)) / 3 - 2 * var(--tb-inset,4px))}
#tabbar:has(> a:nth-child(5)):has(> a:nth-child(1)[aria-selected="true"])::after,
#tabbar:has(> a:nth-child(5)):has(> a:nth-child(2)[aria-selected="true"])::after,
#tabbar:has(> a:nth-child(5)):has(> a:nth-child(3)[aria-selected="true"])::after,
#tabbar:has(> a:nth-child(5)):has(> a:nth-child(4)[aria-selected="true"])::after,
#tabbar:has(> a:nth-child(5)):has(> a:nth-child(5)[aria-selected="true"])::after{
  left:calc(var(--tb-pad,14px) + var(--tb-inset,4px))!important;width:calc((100% - 2 * var(--tb-pad,14px) - 4 * var(--lx-gap,4px)) / 5 - 2 * var(--tb-inset,4px))}

/* ── 拉伸 · 拖尾 · 受压 · 图标弹跳（与预览 v3 同一套语言）──────────────────── */
#tabbar.tbm-press{animation:tbmBar var(--tb-dur,.52s) cubic-bezier(.3,1.35,.45,1)}
@keyframes tbmBar{0%{scale:1 1}22%{scale:1.022 .975}58%{scale:.994 1.006}100%{scale:1 1}}
#tabbar::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  opacity:0;transition:opacity .2s}
#tabbar a svg{transform-origin:50% 50%}
#tabbar a.tbm-tap svg{animation:tbmTap calc(var(--tb-dur,.52s) * .72) cubic-bezier(.3,1.4,.45,1) both}
@keyframes tbmTap{0%{scale:1 1}30%{scale:.84 .9}62%{scale:1.06 1.04}100%{scale:1 1}}
#tabbar a.tbm-leave svg{animation:tbmLeave calc(var(--tb-dur,.52s) * .6) ease-out both}
@keyframes tbmLeave{0%{scale:1 1}42%{scale:.9 .94}100%{scale:1 1}}
#tabbar a[aria-selected="true"] svg{animation:tbmSettle calc(var(--tb-dur,.52s) * .9) cubic-bezier(.34,1.3,.5,1)}
@keyframes tbmSettle{0%{transform:translateY(1.5px)}100%{transform:translateY(-1px) scale(1.06)}}

@media (prefers-reduced-motion:reduce){
  #tabbar::after{transition:none}
  #tabbar.tbm-press,#tabbar a.tbm-tap svg,#tabbar a.tbm-leave svg,
  #tabbar a[aria-selected="true"] svg{animation:none!important}
}

/* 🔴🔴🔴 2026-10-12 20:33 用户令：「**4 个按钮，应该是底部横条内**」
   ＋ （同一话题）「移除了底部的白色横条了！**横条要再长一点**」
   ------------------------------------------------------------------------------
   读法确认（两句连起来才清楚）：**不是**要把底栏改回通栏、也**不是**要加第二条白带，
   而是——现在这条胶囊**太短了**，4 个按钮显得是"飘在空中的小胶囊"，用户要的是
   "4 个按钮装在一条（更长的）底部横条里"。
   ⚠️ 触发场景主要是**宽屏**：原宽 `min(430px, 100% - 20px)` 在桌面上只有 **430px**，
      而本页内容列是 **560px** ⇒ 横条明显比内容窄一截，看着就"太短"。
      （手机 390 宽下是 370，本来就接近满宽 ⇒ 用户看到的九成是桌面宽度下的样子。）
   ✅ 改成跟**内容列同宽**：`min(556px, 100% - 20px)`（左右仍各留 10px，⛔ 不贴屏边
      —— 这条是用户早先明确要的「不是全覆盖底部」）。
   ⛔ **高度 74px、圆角、材质、按钮尺寸一律不动**（用户铁律「大小不要改」指的是按钮大小）。
   ⛔ 不要再动 `_footer.css` 的让位高度：高度没变，让位就不用变。 */
/* 🔴🔴🔴 2026-10-12 20:42 用户报「**健康中心的左边和会员中心的右边，依然是溢出界面**」
   ⇒ 上面这条宽度**从 `%` 改成 `vw` 基准**，这是"结构上防溢出"的写法：
     · `%` 是相对**包含块**算的；`#tabbar` 虽然是 `position:fixed`，
       但**只要任一祖先带 `transform`/`filter`/`backdrop-filter`，它的包含块就会变成那个祖先**
       （这是 CSS 的既定行为，不是 bug）⇒ 那个祖先比视口宽时，横条就**比屏幕还宽** ⇒ 左右溢出。
     · `vw` 恒等于**视口宽度**，与任何容器无关 ⇒ 无论包含块被谁劫持，横条都不会超出屏幕。
   ⚠️ 再补一条 `max-width` 兜底（有些内核对 `100vw` 含不含滚动条有差异，取两者更小的那个）。
   ⛔ 高度 74 / 圆角 / 材质 / 按钮尺寸仍然一律不动。 */
#tabbar{
  /* 🔴 2026-10-12 20:47 用户令：「**底部的长的横条，左右加长一点**」⇒
     左右边距 10px → **4px**、桌面上限 556 → **600**（手机 390：370 → 382；桌面 1440：556 → 600）。
     ⛔ 仍**不贴屏边**（用户早先明确「不是全覆盖底部」），高度/圆角/材质/按钮尺寸一律不动。 */
  width:min(600px, calc(100vw - 8px))!important;
  max-width:calc(100vw - 8px)!important}
