/* ============================================================
   Uwhats — UI Design System v2「Vivid」
   更年轻化的视觉语言：鲜艳品牌渐变 / 大圆角 / 柔和彩色阴影 /
   玻璃质感 / 清晰按压反馈 / 全触摸目标 ≥44px
   作者：UI Designer
   ------------------------------------------------------------
   结构：① 设计令牌  ② 基础重置  ③ 按钮体系  ④ 表单
        ⑤ 登录  ⑥ 壳层(顶栏/底栏)  ⑦ 列表  ⑧ 聊天
        ⑨ 语音与录音  ⑩ 通话  ⑪ 抽屉  ⑫ 动效与可访问性  ⑬ 暗色模式
   ============================================================ */

/* ═══════════════ ① 设计令牌 ═══════════════ */
:root{
  /* 品牌 —— 与 uu.money 同源的绿（其 favicon 主色 #0CCC00）：两个色阶承载白字，亮绿只做点缀 */
  --brand-50:#EAFBE4;  --brand-100:#D4F6C8; --brand-200:#AEEB9A;
  --brand-300:#7EDD62; --brand-400:#3FC51F; --brand-500:#0E8A00;
  --brand-600:#096B00; --brand-700:#064D00;
  --brand-bright:#22C409;                 /* 亮绿点缀：logo / 徽标 / 图标（不承载白字） */
  --brand-text:#096B00;                   /* 浅底上的品牌文字 */
  --brand-line:#0E8A00;                   /* 输入聚焦描边 */
  --brand-grad:linear-gradient(135deg,#0E8A00 0%,#096B00 100%);
  --brand-grad-soft:linear-gradient(135deg,#EAFBE4,#D4F6C8);

  /* 强调色 —— 用于状态、亮点 */
  --mint:#00D68F; --coral:#FF6B81; --amber:#FFB020;

  /* 语义色 */
  --success:#00C48C; --success-grad:linear-gradient(135deg,#26E0A0,#00C48C);
  --warning:#FFAA00;
  --danger:#FF4757; --danger-grad:linear-gradient(135deg,#FF6B81,#FF4757);
  --danger-text:#D32F3F;                                 /* 文字专用：白底 4.96:1 */
  --danger-soft:#FFECEF; --danger-soft-text:#C62828;     /* 浅红块文字：4.95:1 */
  --badge-bg:linear-gradient(135deg,#E03040,#C02535);    /* 白字 4.51:1+ */

  /* 中性色阶 */
  --ink-900:#0F172A; --ink-800:#1E293B; --ink-700:#334155; --ink-600:#475569;
  --ink-500:#64748B; --ink-400:#94A3B8; --ink-300:#CBD5E1; --ink-200:#E2E8F0;
  --ink-100:#F1F5F9; --ink-50:#F8FAFC;

  /* 语义化映射（暗色模式只覆盖这一段） */
  --bg:#F5F6FB;
  --bg-grad:linear-gradient(180deg,#F8F9FE 0%,#F3F4FA 100%);
  --surface:#FFFFFF;
  --surface-glass:rgba(255,255,255,.94);
  --text:var(--ink-900);
  --muted:var(--ink-500);
  --line:var(--ink-200);
  --bubble-in:var(--surface);
  --bubble-out:var(--brand-grad);

  /* 圆角体系 */
  --r-xs:8px; --r-sm:12px; --r-md:16px; --r-lg:20px;
  --r-xl:24px; --r-2xl:28px; --r-full:999px;

  /* 间距体系（4pt 基准） */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px;
  --s-5:20px; --s-6:24px; --s-8:32px; --s-10:40px;

  /* 阴影体系（带品牌色彩倾向，比纯黑阴影更"活"） */
  --sh-xs:0 1px 2px rgba(15,23,42,.05);
  --sh-sm:0 2px 10px -2px rgba(14,138,0,.10), 0 1px 2px rgba(15,23,42,.04);
  --sh-md:0 10px 28px -10px rgba(14,138,0,.22), 0 2px 6px rgba(15,23,42,.04);
  --sh-lg:0 24px 52px -20px rgba(14,138,0,.30);
  --sh-brand:0 10px 24px -8px rgba(22,169,2,.55);
  --sh-danger:0 10px 24px -8px rgba(255,71,87,.55);
  --sh-mint:0 10px 24px -8px rgba(0,196,140,.55);

  /* 动效 */
  --e-out:cubic-bezier(.22,1,.36,1);
  --e-spring:cubic-bezier(.34,1.4,.64,1);
  --t-fast:90ms; --t-base:180ms; --t-slow:380ms;

  /* 交互：全站最小触摸目标（WCAG 2.5.5 / iOS HIG 均为 44px） */
  --tap:44px;

  /* 微信/iOS 字体栈 */
  --font:15px/1.55 -apple-system,BlinkMacSystemFont,"PingFang SC","HarmonyOS Sans SC",
         "Segoe UI","Microsoft YaHei",system-ui,sans-serif;

  /* ── WhatsApp 规格色板（v1.26.0）─────────────────────────────
     聊天界面严格对齐这套值：顶栏 #008069、聊天底 #EFEAE2（带点阵纹理）、
     自己气泡 #D9FDD3、对方气泡 #FFFFFF、正文 #111B21、气泡内时间 #667781、
     已读勾 #53BDEB、未读徽标 #25D366、分隔线 #E9EDEF。
     暗色一套在 ⑬ 暗色模式里覆盖（#202C33 / #0B141A / #005C4B）。
     说明：对齐的是**配色与信息布局**，logo 与名称仍是 Uwhats 自有品牌资产。 */
  --wa-header:#008069;         /* 顶栏（聊天头 / 列表头） */
  --wa-header-ink:#FFFFFF;
  --wa-chat-bg:#EFEAE2;        /* 聊天区底色 */
  --wa-bubble-in:#FFFFFF;      /* 对方气泡 */
  --wa-bubble-out:#D9FDD3;     /* 自己气泡 */
  --wa-bubble-ink:#111B21;     /* 气泡正文（两种气泡都用深字） */
  --wa-meta:#667781;           /* 气泡内时间 / 会话行预览 */
  --wa-tick-read:#53BDEB;      /* 已读双勾 */
  --wa-unread:#25D366;         /* 未读徽标 */
  --wa-line:#E9EDEF;           /* 列表分隔线 */
  --wa-panel:#FFFFFF;          /* 列表 / 输入栏底色 */
  --wa-input:#FFFFFF;          /* 输入框底 */
  --wa-icon:#8696A0;           /* 工具栏图标 */
  --wa-accent-text:#008069;   /* 浅底上的强调色（激活 Tab / 链接）—— 深绿在深底读不出来，暗色另有值 */
  /* v1.30.0：悬浮底栏（半透明 + 毛玻璃）。用半透明而不是纯色，才能透出下面的内容 ——
     这就是"悬浮"的观感来源；边框给一点极淡的描边，免得在浅色内容上糊成一片。 */
  /* v1.45.0：透明度从 .86 放到 .74 —— 产品方反馈"看不出是半透明"。
     磨砂要能被**看出来**才算数：.86 在浅色内容上几乎等同实心白。 */
  /* v1.125.0（2026-10-22）：.74 → .72，配合更强的模糊（20px → 22px、saturate 180% → 200%）。
     ★ 这里有个容易搞反的点：**"看得出是半透明"主要靠 blur，不靠 alpha**。
       真机上 blur 把下面的内容糊成一片色，alpha 再高也一眼是玻璃；
       而 alpha 调太低一旦碰到 blur 不生效的环境（老 WebView / 省电模式），
       内容会**清清楚楚穿过底栏**，比不透明还脏。所以 alpha 只小幅下探。 */
  --wa-bar-bg:rgba(255,255,255,.72);
  --wa-bar-line:rgba(15,23,42,.07);
  /* ★ 底栏选中项的高亮胶囊（WhatsApp 新版：选中的那一格有一层淡淡的色块，
     不再是"只有字变色"）。用极淡的品牌青，保证文字对比不降。 */
  --wa-active-pill:rgba(0,128,105,.10);

  /* ── WhatsApp 新版（v1.29.0）：顶栏去绿、改中性 ──────────────────────
     2024 之后 WhatsApp 把标志性的绿色顶栏去掉了，改白/黑底 + 中性图标与文字，
     绿色只留在"小细节"上：品牌标题、FAB、未读徽标、选中 Tab、发送键。
     下面这套就是新版的顶栏与过滤器色（对比度都是算过的，见注释里的比值）。 */
  --wa-appbar:#FFFFFF;         /* 首页顶栏 / 聊天页顶栏底色 */
  --wa-appbar-ink:#111B21;     /* 顶栏图标与文字（17.46:1） */
  --wa-appbar-title:#008069;   /* 品牌标题用绿（4.89:1） */
  --wa-fab:#00A884;            /* FAB 底：纯图标，非文本 3:1 达标（3.03） */
  --wa-chip-bg:#F0F2F5;        /* 过滤器 chip 底（深字 15.57:1） */
  --wa-chip-ink:#111B21;
  --wa-chip-on:#E7FCE3;        /* 选中 chip：浅绿底 + 深绿字（4.53:1 ✅） */
  --wa-chip-on-ink:#008069;

  /* ── WhatsApp 规格：按钮（v1.28.0）────────────────────────────
     对齐它的按钮语言：**纯色填充（无渐变）、胶囊形、无彩色投影、按下是 Material 水波纹**
     （不是 iOS 缩放）。结构上分四级：填充 primary / 文字 ghost / 列表行 btn-soft / 危险红字。

     ⚠️ 颜色是**算出来**的，不是照抄字面值：
        WhatsApp 的亮青 #00A884 + 白字只有 **3.03:1**，不达 WCAG AA（正文要 4.5:1）；
        它自家的深青 #008069 是 **4.89:1** ✅ —— 同色系、观感一致。
        所以「承载白字」的填充按钮一律用 --wa-btn；
        --wa-accent（#00A884）只给**纯图标**按钮（发送/麦克风）用：
        非文本对比只要求 3:1，实测 3.03 刚好达标 —— 最大化还原度的同时不牺牲可读性。 */
  --wa-btn:#008069;            /* 填充按钮底（白字 4.89:1） */
  --wa-btn-press:#006B58;      /* 按下态（白字 6.47:1） */
  --wa-btn-ink:#FFFFFF;
  --wa-accent:#00A884;         /* 纯图标按钮底 / 需要更亮时的强调（非文本 3.03:1 ≥3） */
  --wa-btn-outline:#008069;    /* 描边与文字按钮的色（白底 4.89:1） */
  --wa-btn-off-bg:#E9EDEF;     /* 禁用底。注：WCAG 1.4.3 对「非活动控件」有明确豁免，
                                  所以这里沿用 WhatsApp 的灰底灰字，不强行拉到 4.5:1 */
  --wa-btn-off-ink:#8696A0;
  --wa-btn-h:48px;             /* WhatsApp 填充按钮高 48px（仍 ≥44 触摸下限） */
}

/* ═══════════════ ② 基础重置 ═══════════════ */
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{height:100%;margin:0;-webkit-text-size-adjust:100%;overscroll-behavior-y:none}

/* ═══════════════ 点击灵敏度（v1.49.0）═══════════════
   用户反馈"手机 App 点击反应要灵敏"。用真实触摸事件量过（tools/tap-bench.cjs）：
   按下 50ms 内都有反馈、到画面更新 7–32ms，**已经够快**；剩两处能再稳一点：
   ① `touch-action:manipulation` —— 明确告诉浏览器"这块只做点击/滚动，不做双击缩放判定"。
      浏览器因此可以立刻派发 click，不必等它判断是不是双击（部分浏览器/场景会等 ~300ms）。
      保留滚动与双指缩放，所以不影响列表滑动。
   ② iOS Safari 有个老规矩：页面里**没有 touchstart 监听**时，非 `<button>` 的可点元素
      **不会**进 `:active`（我们的列表行 `.item` 正是 div）→ 点下去毫无反馈。
      所以 app.js 里加了一个**什么都不做**的 touchstart 监听（只为了满足这个前提）。
   ③ 顺带 `user-select:none`：长按不再选中文字、也不弹"拷贝/查询"菜单，点着更干净。
      ⚠️ **不要**把 `.msg`（消息气泡）加进来 —— 那里面要能选文字（验证码、地址要复制）。 */
button,a,.item,.fchip,.chip,.mbtn,.setting-row,.mm-act,.iconbtn,.tabbtn,
.dl-btn,.dl-all,.ai-chip,.sms-code,.biz-sys,.biz-item{
  touch-action:manipulation;
  -webkit-user-select:none;user-select:none;
}
/* 输入框与消息区保持可选（复制验证码/地址） */
input,textarea,.msg,.sel-count{ -webkit-user-select:text;user-select:text; }
body{
  font:var(--font);
  color:var(--text);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}
.hide{display:none !important}
.sub{color:var(--ink-500);font-size:13px}
.err{color:var(--danger-text);font-size:13px;min-height:18px;margin:6px 0 0;font-weight:500}

/* ── 图标（v1.28.0）────────────────────────────────────────────
   全部换成**线性矢量图**，颜色靠 currentColor 继承。
   为什么必须换掉 emoji：emoji 有自己的固有色、**不跟随 currentColor**，
   于是"按钮按下/选中变色"这种状态在图标上看不见 —— 而我们刚把底栏选中态
   从"顶部指示条"改成了"整体变色"，emoji 会让它几乎看不出来。
   图形是通用线稿（气泡/话筒/人像/回形针/相机…），不是任何第三方的美术素材。 */
svg.ico{
  display:block;flex:0 0 auto;
  width:22px;height:22px;
  fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round;
}
/* v1.45.0：WhatsApp 的图标是**实心（filled）**的，我们此前全是线性描边 ——
   底栏"看着不像"的主因就在这里（形状对、笔触不对）。
   加一个 .ico-fill 变体：填充取 currentColor、关掉描边，颜色状态照旧跟随文字。
   ⚠️ 实心图标一旦写了 stroke，边缘会"胖一圈"变糊，所以这里必须显式 stroke:none。 */
svg.ico-fill{
  fill:currentColor;
  stroke:none;
  stroke-width:0;
}
.tabbtn .ico{width:24px;height:24px}
.composer .icon .ico{width:22px;height:22px}
.composer .icon.send .ico{width:21px;height:21px}

/* 全局按压反馈：WhatsApp 用的是 **Material 水波纹**（从按下处扩散一层高光），
   不是 iOS 的缩放回弹 —— 所以这里不再对 button 做 transform:scale。 */
button{
  font:inherit;cursor:pointer;border:0;background:transparent;color:inherit;
  transition:background-color var(--t-fast) linear,
             color var(--t-fast) linear,
             box-shadow var(--t-base) var(--e-out),
             opacity var(--t-fast) linear;
}
button:focus-visible{outline:2px solid var(--wa-btn);outline-offset:2px}
button:disabled{opacity:.5;pointer-events:none}

/* ── 水波纹：一套规则覆盖所有按钮，靠 currentColor 自动配色 ──
   填充按钮是白字 → 白色波纹；文字按钮是青字 → 青色波纹；图标按钮 → 图标色波纹。

   ★★★ 2026-10-22（体感优化）：原来这里是 `width:0;height:0` 过渡到 `260%` ——
   **width/height 是布局属性**，浏览器每一帧都要重排（实测按住 490ms 触发 **26 次 layout**、
   帧间隔 p95 掉到 29ms）。现在改成**尺寸固定、只动 transform:scale**：
   形状与配色完全不变，但动画只走合成层，不再触发布局。

   ★ 位置改成 `var(--rx,50%)/var(--ry,50%)`：默认仍在中心（其它按钮不变），
   底栏由 JS 在 pointerdown 时写入手指坐标 ⇒ 波纹**从按下的地方**扩散（WhatsApp 的手感）。 */
.primary,.ghost,.btn-soft,.btn-danger-soft,.danger,.mbtn,.iconbtn,.chip,
.dl-btn,.more-menu button,.composer .icon,.msg.voice .vplay,.msg.voice .vmore{
  position:relative;overflow:hidden;
}
.primary::after,.ghost::after,.btn-soft::after,.btn-danger-soft::after,.danger::after,.mbtn::after,
.iconbtn::after,.chip::after,.dl-btn::after,.more-menu button::after,
.composer .icon::after,.msg.voice .vplay::after,.msg.voice .vmore::after{
  content:'';position:absolute;left:var(--rx,50%);top:var(--ry,50%);
  /* ★ 固定尺寸（不参与过渡）⇒ 不触发布局。
     ★★ 260% → 150%：底栏格子只有约 80×60，260%（208px）在 150ms 时就铺满了，
        用户看到的是"整块闪一下"，不是"一圈水在长大"。150% 的椭圆刚好覆盖对角线
        （a=60,b=45 时对角点代入仍 <1），既盖得满、又能看见边缘扩开。
        大按钮同样够用：.primary 200×48 ⇒ 300×72，覆盖有余。 */
  width:150%;height:150%;
  border-radius:50%;background:currentColor;opacity:0;pointer-events:none;
  transform:translate(-50%,-50%) scale(0);
  transform-origin:center center;
}
.primary:active::after,.ghost:active::after,.btn-soft:active::after,.btn-danger-soft:active::after,
.danger:active::after,.mbtn:active::after,.iconbtn:active::after,
.chip:active::after,.dl-btn:active::after,.more-menu button:active::after,
.composer .icon:active::after,.msg.voice .vplay:active::after,.msg.voice .vmore:active::after{
  transform:translate(-50%,-50%) scale(1);
  /* v1.125.0：.18 → .22。改尺寸换成缩放之后，波纹的"面积增长"更快（scale 一帧就到 0.4+），
     同样的 .18 在**半透明底栏**上偏淡、像一层灰；提到 .22 才看得出是一团从指下散开的水。
     其它按钮沿用同一个值 —— 一套规则只能有一个数，否则又是一份"看不见的分叉"。
     ★ 时长也从 --t-slow(380ms) 收到 260ms：380ms 有"洇开"的拖沓感，260ms 才是"按下去就有回应"。 */
  opacity:.22;
  transition:transform 260ms var(--e-out),
             opacity 140ms linear;
}

/* ═══════════════ ③ 按钮体系（WhatsApp 规格 v1.28.0）═══════════════
   四级：填充 primary（主操作）/ 文字 ghost（对话框动作）/ 列表行 btn-soft（抽屉选项）/
        危险 danger & btn-danger-soft（挂断、删除）。共同点：纯色、胶囊、无水波纹以外的特效。 */
/* 一级：实心胶囊（纯色，无渐变无彩色投影） */
.primary{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s-2);
  min-height:var(--wa-btn-h);padding:0 var(--s-6);
  border-radius:var(--r-full);
  background:var(--wa-btn);color:var(--wa-btn-ink);
  font-weight:600;font-size:15px;letter-spacing:.01em;
  box-shadow:none;
}
.primary:active{background:var(--wa-btn-press)}
.primary:disabled{background:var(--wa-btn-off-bg);color:var(--wa-btn-off-ink);opacity:1}

/* 二级：文字按钮（WhatsApp 对话框里的动作就是"纯青色文字、无底"） */
.ghost{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:var(--tap);padding:0 var(--s-4);
  border-radius:var(--r-full);
  background:transparent;color:var(--wa-btn-outline);
  font-weight:600;font-size:14px;
}
.ghost:active{background:rgba(0,128,105,.10)}

/* 三级：列表行（抽屉 / 设置里的选项 —— WhatsApp 的抽屉项就是"无底深字 + 按下灰一下"） */
.btn-soft{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:var(--wa-btn-h);width:100%;margin:var(--s-1) 0;padding:0 var(--s-4);
  border-radius:var(--r-full);
  background:transparent;color:var(--text);
  font-weight:500;font-size:15px;
}
.btn-soft:active{background:var(--ink-100)}

/* 危险-文字级（双方删除 / 退出群聊：WhatsApp 里这类是不可逆红字，不是红块） */
.btn-danger-soft{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:var(--wa-btn-h);width:100%;margin:var(--s-1) 0;padding:0 var(--s-4);
  border-radius:var(--r-full);
  background:transparent;color:var(--danger-text);
  font-weight:600;font-size:15px;
}
.btn-danger-soft:active{background:rgba(211,47,63,.10)}

/* 实心危险（通话挂断）：WhatsApp 的挂断是纯红圆钮，不是红渐变 */
.danger{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:var(--wa-btn-h);padding:0 var(--s-6);
  border-radius:var(--r-full);
  background:#EA0038;color:#fff;                /* 白字 4.61:1 ✅ */
  font-weight:600;font-size:15px;box-shadow:none;
}
.danger:active{background:#C40030}

/* 必填块级主按钮 */
.primary.block{width:100%;margin:var(--s-2) 0;display:flex}

/* 群成员移出：小号红字按钮（WhatsApp 里移除成员就是一行红字） */
.mbtn{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:var(--tap);padding:0 var(--s-3);
  border-radius:var(--r-full);
  background:transparent;color:var(--danger-text);
  font-size:13px;font-weight:600;
}
.mbtn:active{background:rgba(211,47,63,.10)}

/* ═══════════════ ④ 表单 ═══════════════ */
/* 16px 起（同时满足 iOS 防聚焦缩放 与 移动端可读性） */
input{
  font:inherit;font-size:16px;
  width:100%;height:52px;padding:0 var(--s-4);
  border:1.5px solid var(--ink-200);border-radius:var(--r-sm);
  background:var(--surface);color:var(--text);outline:none;
  transition:border-color var(--t-fast) linear,
             box-shadow var(--t-base) var(--e-out),
             background-color var(--t-fast) linear;
}
input::placeholder{color:var(--ink-500)}
input:focus{border-color:var(--brand-line);box-shadow:0 0 0 4px rgba(14,138,0,.16)}
input.valid{border-color:var(--success)}
input.invalid{border-color:var(--danger)}
.form{display:grid;gap:var(--s-3)}

/* v1.42.0：注册页的"邮箱前缀 + @域名"。
   前缀那一栏和普通输入框完全一致（高度/圆角/焦点态都复用），
   只把右边做成一个**看起来像输入框一部分**的后缀块 —— 这样用户不会
   以为"域名也能改"，也不会漏看域名是什么。 */
.mail-field{display:flex;align-items:stretch;gap:0}
.mail-field input{
  border-top-right-radius:0;border-bottom-right-radius:0;
  border-right-width:0;
}
.mail-field input:focus{box-shadow:0 0 0 4px rgba(14,138,0,.16);z-index:1}
.mail-field .mail-suffix{
  display:inline-flex;align-items:center;padding:0 var(--s-3);
  height:52px;white-space:nowrap;
  border:1.5px solid var(--ink-200);border-left:0;
  border-radius:0 var(--r-sm) var(--r-sm) 0;
  background:var(--ink-50);color:var(--ink-600,var(--muted));
  font-size:14px;
}

/* ═══════════════ ⑤ 登录 / 注册 ═══════════════ */
.auth{
  min-height:100%;min-height:100dvh;
  display:grid;place-items:center;padding:var(--s-6);
  background:
    radial-gradient(80% 55% at 12% 8%, rgba(34,196,9,.22), transparent 62%),
    radial-gradient(70% 55% at 88% 12%, rgba(0,214,143,.16), transparent 60%),
    radial-gradient(90% 65% at 50% 102%, rgba(255,107,129,.14), transparent 62%),
    linear-gradient(160deg,#FAFBFF 0%,#F2F3FF 100%);
}
.auth-card{
  width:100%;max-width:392px;
  padding:var(--s-6) var(--s-5) 28px;
  border-radius:var(--r-2xl);
  background:rgba(255,255,255,.88);
  backdrop-filter:blur(22px) saturate(170%);
  -webkit-backdrop-filter:blur(22px) saturate(170%);
  border:1px solid rgba(255,255,255,.75);
  box-shadow:var(--sh-lg);
}
/* ── 品牌区（2026-10-19 时尚化）────────────────────────────────
 * 三处改动都为了"第一眼更高级"，但都不加图片、不加依赖：
 *   · logo 用 drop-shadow 做柔光（比给容器加 box-shadow 更贴合不规则图形）
 *   · 标题加大到 30px 并收紧字距 —— 大字距松会显廉价
 *   · 副标题放开字距（.06em）并压低对比 —— 中文小字放开字距才显得克制
 */
.brand{text-align:center;margin-bottom:var(--s-5)}
.brand svg{
  filter:drop-shadow(0 10px 22px rgba(14,138,0,.34)) drop-shadow(0 2px 6px rgba(14,138,0,.18));
  transition:transform var(--t-base) cubic-bezier(.22,.61,.36,1);
}
.brand h1{
  margin:var(--s-3) 0 2px;
  font-size:30px;font-weight:850;letter-spacing:-.03em;
  background:linear-gradient(135deg,#0A6A00 0%,#17B404 52%,#0B7A00 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.brand .sub{
  margin:0;color:var(--ink-500);font-size:12.5px;
  letter-spacing:.06em;font-weight:500;
}

/* 分段切换器（胶囊滑块）—— 2026-10-19：底色更浅、选中项加渐变与浮起感 */
.tabs{
  display:flex;gap:var(--s-1);
  padding:4px;
  background:rgba(15,23,42,.055);
  border-radius:var(--r-full);
  margin:var(--s-4) 0 var(--s-5);
}
.tab{
  flex:1;min-height:var(--tap);border-radius:var(--r-full);
  color:var(--ink-500);font-weight:650;font-size:14px;
  transition:background-color var(--t-fast) linear,color var(--t-fast) linear,box-shadow var(--t-fast) linear;
}
.tab.active{
  background:linear-gradient(180deg,#fff 0%,#F6FBF4 100%);
  color:var(--brand-text);
  box-shadow:0 1px 2px rgba(15,23,42,.06),0 6px 16px -10px rgba(15,23,42,.35);
}

/* ═══════════════ 下载入口（登录卡下方，方便从网页找到安装包） ═══════════════
   设计要求：一眼看出"这里是下载"、三个平台等宽好点、触摸目标 ≥44px、
   浅底与暗底两种模式下的文字对比度都要达标。 */
.dl-block{
  margin-top:var(--s-5);padding-top:var(--s-4);
  border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:var(--s-3);
}
.dl-title{
  text-align:center;color:var(--ink-600);
  font-size:12px;font-weight:650;letter-spacing:.02em;
}
.dl-title .dl-ver{color:var(--brand-text);margin-left:6px;font-weight:700}
.dl-btns{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-2)}
/* 下载键按 WhatsApp 的按钮语言：**描边胶囊**（边与字同色、无底），主路径（安卓）用实心胶囊 */
.dl-btn{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  min-height:var(--tap);padding:var(--s-2) 6px;
  border:1.5px solid var(--wa-btn-outline);border-radius:var(--r-full);
  background:transparent;color:var(--wa-btn-outline);
  font-size:11.5px;font-weight:600;line-height:1.25;text-align:center;text-decoration:none;
  transition:background-color var(--t-fast) linear,
             border-color var(--t-fast) linear, color var(--t-fast) linear;
}
.dl-btn .dl-ico{font-size:17px;line-height:1}
.dl-btn:active{background:rgba(0,128,105,.10)}
/* 安卓是"一点即下"的主路径 → 实心级 */
.dl-btn#dl-android{background:var(--wa-btn);border-color:var(--wa-btn);color:var(--wa-btn-ink)}
.dl-btn#dl-android:active{background:var(--wa-btn-press);border-color:var(--wa-btn-press)}
.dl-all{
  align-self:center;display:inline-flex;align-items:center;
  min-height:var(--tap);padding:0 var(--s-2);
  color:var(--wa-btn-outline);font-size:12.5px;font-weight:600;text-decoration:none;
}
.dl-all:active{opacity:.72}

/* ═══════════════ ⑤b 用户端一体入口：左智体 + 右登录（v1.18.0） ═══════════════
   配色原则：左侧面板是固定品牌渐变，**不参与暗色模式变量切换**，
   所以它内部一律「深底 + 白字」，且深底用黑色半透明叠加 —— 保证亮暗两种模式下
   对比度都稳定（变量在暗色下会翻转，用它做左面板文字底色会直接失守）。 */
/* 被嵌套提示：托管平台会放开 frame-ancestors（允许任意嵌套），应用侧只能提醒，详见 app.js 注释 */
.frame-warn{
  width:100%;max-width:1108px;margin:0 auto var(--s-3);
  padding:10px var(--s-4);border-radius:var(--r-md);
  background:#FFF4E5;border:1px solid #FFD8A8;color:#8A5A00;
  font-size:13px;font-weight:620;text-align:center;line-height:1.5;
}
/* v1.55.0：左侧那套「独立智库 AI 顾问」面板下线后，登录页只剩一张登录卡 ——
   这里从"两栏 grid（智体 | 登录）"退化成**单列**，宽度交给 .auth-card 自己定。
   .auth 是 place-items:center，单列时自然居中。 */
.auth-shell{
  width:100%;max-width:1108px;
  display:grid;grid-template-columns:1.06fr .94fr;
  gap:var(--s-6);align-items:stretch;
}

/* ── 窄屏（手机）：智库上、登录卡下 ──────────────────────────────
 * ★★★ 2026-10-18 修「手机上智库不显示」：
 *   原来 `.auth-card{order:1}` / `.ai-panel{order:2}` —— 意图是"先给登录"，
 *   但实测登录卡在 390 视口下高 **649px**，几乎占满 844 的屏幕，
 *   于是智库被排到 top=649 的位置：DOM 在、display:flex、opacity:1，
 *   却整块落在首屏之外 —— 用户看不到，和"没渲染"是同一个观感。
 *   ⇒ 改为**智库在上、限高 34vh**（约 287px，含标题/两三条对话/输入栏），
 *     登录卡在下；两者合计约 790px，一屏内都能看到。
 *   ★ 为什么要限高：智库内容会随对话增长，不限高会一路把登录卡顶出屏幕
 *     （那只是把"看不到智库"换成"看不到登录"，问题没解决）。
 *   ★ 小屏隐藏 chips 与脚注：它们是辅助信息（推荐问题、隐私说明），
 *     首屏优先保证「智库能聊 + 登录能填」。 */
@media (max-width:900px){
  .auth{padding:var(--s-4)}
  .auth-shell{grid-template-columns:1fr;gap:var(--s-3);max-width:460px}
  /* ★★ 必须带 `.auth-shell` 前缀提高特异性：`.ai-panel{min-height:540px}` 这条
     桌面规则定义在本媒体查询**之后**，同优先级下后者胜 ⇒ 直接写 `.ai-panel{min-height:0}`
     会被它覆盖（实测手机上高度一直卡在 540px，正是这条在起作用）。 */
  .auth-shell .ai-panel{order:1;min-height:0;max-height:34vh;padding:var(--s-4)}
  .auth-shell .ai-log{max-height:11vh;min-height:44px}
  .auth-shell .ai-chips{display:none}
  .auth-shell .ai-foot{display:none}
  .auth-shell .ai-composer{padding:4px;gap:6px}
  .auth-shell .ai-composer input{min-height:38px;font-size:14px}
  .auth-shell .ai-composer button{min-height:38px;padding:0 14px;font-size:13.5px}
  .auth-shell .auth-card{order:2}

  /* ── 手机端视觉精致化（2026-10-18）─────────────────────────────
   * ★ 副标题原来 `white-space:nowrap` + ellipsis，在 358px 宽里被截成
   *   "先把「给谁用、要什…" —— 一句话看不全，等于没有说明。
   *   改成最多两行、超出才省略；标题区因此长高约 18px，仍在 34vh 预算内。
   * ★ 层次感靠"两层阴影"而不是加深颜色：近处一层薄的贴合卡片，
   *   远处一层大扩散做悬浮感。纯加深会把浅色背景压脏。 */
  .auth-shell .ai-sub{white-space:normal;display:-webkit-box;
    -webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;line-height:1.35}
  .auth-shell .ai-panel{box-shadow:0 18px 44px -22px rgba(7,92,0,.62)}
  .auth-shell .auth-card{
    border-radius:26px;
    box-shadow:0 24px 60px -30px rgba(15,23,42,.42),0 2px 10px rgba(15,23,42,.05);
  }
  /* 输入框聚焦给一圈柔光，手指点进去时知道自己在哪一栏 */
  .auth-shell .auth-card input:focus{
    border-color:rgba(22,169,2,.5);
    box-shadow:0 0 0 4px rgba(22,169,2,.12);
  }
  /* ★★★ 2026-10-22 修：这里原本把 `.auth-shell .auth-card .primary` 一起写进了渐变 +
     彩色投影的规则里，**直接推翻了 v1.28.0 的按钮规格**（填充必须纯色、不许彩色投影）。
     因为这段在文件后段、特异性也更高，级联上必然胜出 —— 于是"写着一套、渲染出另一套"，
     而 shell-contract 只检查"存在一条 .primary{...background:var(--wa-btn)}"，看不出被覆盖
     （实测 924/924 全绿，而真浏览器里读到的是 linear-gradient）。
     现在只保留**智库发送键**这条独立图标按钮，主按钮交回上面的 `.primary`（--wa-btn 纯色 + 水波纹）。 */
  .auth-shell .ai-composer button{
    background:linear-gradient(135deg,#22C409 0%,#0E8A00 100%);
    box-shadow:0 10px 22px -12px rgba(22,169,2,.75);
  }
  /* 入场：两块依次淡入上移，制造层次（不是同时出现） */
  .auth-shell .ai-panel{animation:uwFadeUp .44s cubic-bezier(.22,.61,.36,1) both}
  .auth-shell .auth-card{animation:uwFadeUp .44s .07s cubic-bezier(.22,.61,.36,1) both}

  /* ── 智库默认收起（2026-10-18 需求：手机上不要占首屏）──────────
   * 收起态只留**一条**（约 56px），点「展开对话」再撑开到 34vh。
   * ★★★ 2026-10-19 修：只设 max-height 是不够的 —— 头部里 logo + 标题 +
   *   「AI 顾问」标签 + 「连接中…」状态 + 按钮 全挤在 358px 宽里放不下，
   *   结果「独立智库」被压成**竖排单字**，整条看起来是"一坨看不懂的东西"。
   *   ⇒ 收起时把次要元素一起藏掉，只留 图标 + 标题 + 展开按钮，
   *     标题强制 nowrap（绝不竖排），头部垂直居中。 */
  .auth-shell .ai-toggle{display:inline-flex;align-items:center;justify-content:center}
  .auth-shell .ai-panel.is-collapsed{max-height:56px;min-height:48px;padding:0 var(--s-4);justify-content:center}
  .auth-shell .ai-panel.is-collapsed .ai-head{gap:10px;align-items:center}
  .auth-shell .ai-panel.is-collapsed .ai-log,
  .auth-shell .ai-panel.is-collapsed .ai-chips,
  .auth-shell .ai-panel.is-collapsed .ai-composer,
  .auth-shell .ai-panel.is-collapsed .ai-foot,
  .auth-shell .ai-panel.is-collapsed .ai-sub,
  .auth-shell .ai-panel.is-collapsed .ai-tag,
  .auth-shell .ai-panel.is-collapsed .ai-state{display:none}
  .auth-shell .ai-panel.is-collapsed .ai-logo{
    flex:0 0 30px;width:30px;height:30px;border-radius:10px;font-size:15px;
  }
  .auth-shell .ai-panel.is-collapsed .ai-head-main{flex:1;min-width:0}
  .auth-shell .ai-panel.is-collapsed .ai-title{
    font-size:14px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
}
@keyframes uwFadeUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
/* ★ 尊重系统「减少动态效果」：装饰性入场动画不该强行播给会不适的人
   （与既有的心跳动画同一规矩，shell-contract 里有对应断言）。 */
@media (prefers-reduced-motion:reduce){
  .auth-shell .ai-panel,.auth-shell .auth-card{animation:none}
}

/* ═══════════ 登录卡时尚化层（2026-10-19）═══════════════════════
 * 只加视觉，不动结构与关键尺寸（分段控件仍是 --tap=44px、输入框高度不变）。
 * 放在文件末尾：靠后定义覆盖上面的 .auth-card 基础规则；
 * 移动端那条 `.auth-shell .auth-card` 特异性更高（0,2,0 > 0,1,0），不会被这里顶掉。
 */
.auth-card{
  border-radius:30px;
  position:relative;
  overflow:hidden;                 /* 让顶部高光带被圆角裁切干净 */
  box-shadow:
    0 1px 2px rgba(15,23,42,.04),
    0 18px 50px -24px rgba(15,23,42,.28),
    0 2px 10px rgba(15,23,42,.05);
}
/* 顶边一条极细高光：玻璃卡"被顶光打亮"的观感，成本几乎为零 */
.auth-card::before{
  content:'';position:absolute;left:12%;right:12%;top:0;height:1px;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.95),transparent);
  pointer-events:none;
}
/* ★★★ 2026-10-22 删掉了一条 `.auth-card button.primary` 的覆盖规则。
   它当时（2026-10-19「登录卡时尚化」）给主按钮加了：
     · background: linear-gradient(180deg,#22C409,#0E8A00)   ← 违反"填充=纯色"
     · box-shadow: …0 10px 22px -12px rgba(22,169,2,.75)     ← 违反"不许彩色投影"
     · :active{transform:scale(.985)}                        ← 违反"按压用水波纹，不许 scale"
   三条全部与 HANDOVER 第八章的按钮规格冲突，而且写在文件后段 ⇒ 一定生效。
   ⛔ 以后要给登录卡加质感，请改卡片本身（圆角/边框/高光带），**不要动按钮的填充与按压方式**。 */
/* 输入框：更柔的底 + 聚焦柔光（桌面端同样生效，不只是移动端） */
.auth-card input{
  border-radius:14px;
  background:rgba(255,255,255,.72);
  border:1px solid rgba(15,23,42,.09);
  transition:border-color var(--t-fast) linear,box-shadow var(--t-fast) linear,
             background-color var(--t-fast) linear;
}
.auth-card input:focus{
  background:#fff;
  border-color:rgba(22,169,2,.55);
  box-shadow:0 0 0 4px rgba(22,169,2,.13);
}
/* 入场：卡片轻微浮起 */
@keyframes uwCardIn{from{opacity:0;transform:translateY(8px) scale(.995)}to{opacity:1;transform:none}}
.auth-card{animation:uwCardIn .42s cubic-bezier(.22,.61,.36,1) both}
@media (prefers-reduced-motion:reduce){ .auth-card{animation:none} }

/* ★★ 2026-10-19：错误行与戒指提示**空着的时候不要占位**。
   它们原本各有 min-height（18px / 16px）用于"出现时不抖"，但登录页常态是空的，
   结果卡片底部拖出一条 100px 左右的空白，显得头重脚轻。
   用 `:empty` 让它们在无内容时彻底收起 —— 代价是提示出现时页面会轻微上移，
   只在"登录出错/戒指连上"这种瞬间发生，可以接受；视觉收益更大。 */
.auth-card .err:empty,
.auth-card #li-ring-hint:empty{display:none;min-height:0;margin:0}

/* ★★ 2026-10-19：后台关掉「独立智库」时，容器退回**单列并居中**。
   不加这条的话，grid 仍是 `1.06fr .94fr` 两列，登录卡会落进第一列（约 574px 宽的位置）
   ⇒ 卡片偏左、右侧空一大片。实测修复前 left=86（1280 视口下应 ≈444 才居中）。 */
.auth-shell.no-ai{
  grid-template-columns:1fr;
  max-width:460px;
  justify-items:center;
}

.ai-panel{
  position:relative;overflow:hidden;
  display:flex;flex-direction:column;
  min-height:540px;max-height:78vh;
  padding:var(--s-5);
  border-radius:var(--r-2xl);
  color:#fff;
  background:linear-gradient(158deg,#075C00 0%,#0B7300 52%,#0E8A00 100%);
  box-shadow:var(--sh-lg);
}
.ai-panel::after{        /* 一角柔光：大面积纯色会显平 */
  content:'';position:absolute;right:-18%;top:-34%;width:70%;height:70%;
  background:radial-gradient(closest-side,rgba(255,255,255,.20),transparent 72%);
  pointer-events:none;
}
.ai-head{display:flex;align-items:center;gap:var(--s-3);position:relative;z-index:1}
/* 桌面端不出现「收起/展开」按钮：桌面是两栏布局，智库本身就是主视觉，收起来没意义。
   窄屏才显示（见 @media max-width:900px 里的 .auth-shell .ai-toggle）。 */
.ai-toggle{
  flex:0 0 auto;display:none;align-items:center;justify-content:center;
  min-height:30px;padding:0 10px;border-radius:var(--r-full);
  background:rgba(0,0,0,.26);border:1px solid rgba(255,255,255,.30);
  color:#fff;font-size:12px;font-weight:650;cursor:pointer;
  transition:background-color var(--t-fast) linear;
}
.ai-toggle:active{background:rgba(0,0,0,.42)}
.ai-logo{
  flex:0 0 40px;width:40px;height:40px;border-radius:13px;
  display:flex;align-items:center;justify-content:center;font-size:19px;color:#fff;
  background:rgba(0,0,0,.26);border:1px solid rgba(255,255,255,.26);
}
.ai-head-main{flex:1;min-width:0}
.ai-title{font-size:15.5px;font-weight:750;display:flex;align-items:center;gap:6px;color:#fff}
.ai-tag{
  padding:1px 7px;border-radius:var(--r-full);
  background:rgba(0,0,0,.3);font-size:11px;font-weight:650;color:#fff;
}
.ai-sub{margin-top:3px;font-size:12.5px;color:#fff;opacity:.92;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ai-state{
  flex:0 0 auto;padding:4px 9px;border-radius:var(--r-full);
  font-size:11px;font-weight:650;color:#fff;
  background:rgba(0,0,0,.3);border:1px solid rgba(255,255,255,.24);
}
.ai-state.off{background:rgba(0,0,0,.5)}

.ai-log{
  flex:1;min-height:0;margin:var(--s-4) 0 var(--s-3);
  display:flex;flex-direction:column;gap:var(--s-2);
  overflow-y:auto;overscroll-behavior:contain;position:relative;z-index:1;
  scrollbar-width:thin;
}
.ai-row{display:flex}
.ai-row.user{justify-content:flex-end}
.ai-bubble{
  max-width:88%;padding:9px 12px;border-radius:14px;
  font-size:13.5px;line-height:1.62;white-space:pre-wrap;word-break:break-word;
  background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.18);color:#fff;
}
.ai-row.user .ai-bubble{background:#fff;color:#0F172A;border-color:transparent;font-weight:600}
.ai-row.note .ai-bubble{
  max-width:100%;font-size:12.5px;background:rgba(0,0,0,.34);
  border-color:rgba(255,255,255,.16);color:#fff;
}
.ai-bubble.warn{background:rgba(0,0,0,.46);border-color:#FF9AA8;color:#fff}
.ai-bubble.typing::after{content:'▍';margin-left:2px;animation:aiBlink 1s steps(2) infinite}
@keyframes aiBlink{0%,100%{opacity:1}50%{opacity:0}}

.ai-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:var(--s-3);position:relative;z-index:1}
.ai-chip{
  padding:0 14px;border-radius:var(--r-full);
  min-height:var(--tap);              /* 与全站一致：触摸目标 ≥44px（33px 高的胶囊手指点不准） */
  display:inline-flex;align-items:center;
  background:rgba(0,0,0,.26);border:1px solid rgba(255,255,255,.28);
  color:#fff;font-size:12.5px;font-weight:600;
}
.ai-chip:active{background:rgba(0,0,0,.42)}

/* 多智体切换器：登录页（深底）与工作台（灰白）两套配色各自覆盖 ——
   同一个 DOM 节点会在两处出现，靠背景色写死一种配色必然有一处读不清。 */
.ai-switch{
  display:flex;gap:6px;overflow-x:auto;margin:var(--s-2) 0 0;
  padding-bottom:2px;position:relative;z-index:1;scrollbar-width:none;
}
.ai-switch::-webkit-scrollbar{display:none}
.ai-switch-btn{
  flex:0 0 auto;min-height:34px;padding:0 13px;border-radius:var(--r-full);
  background:rgba(0,0,0,.26);border:1px solid rgba(255,255,255,.26);color:#fff;
  font-size:12.5px;font-weight:650;white-space:nowrap;
}
.ai-switch-btn.on{background:#fff;color:#0B7300;border-color:transparent}

.ai-composer{display:flex;gap:var(--s-2);position:relative;z-index:1}
.ai-composer input{
  flex:1;min-width:0;min-height:var(--tap);padding:0 var(--s-4);border-radius:var(--r-full);
  background:#fff;color:#0F172A;border:1px solid rgba(255,255,255,.5);font-size:14px;
}
.ai-composer input::placeholder{color:#64748B}
.ai-composer input:disabled{background:rgba(255,255,255,.62)}
.ai-composer button{
  flex:0 0 auto;padding:0 var(--s-5);min-height:var(--tap);border-radius:var(--r-full);
  background:#fff;color:#096B00;font-weight:720;font-size:14px;
}
.ai-composer button:disabled{opacity:.6}
.ai-foot{margin:var(--s-3) 0 0;font-size:11.5px;color:#fff;opacity:.9;position:relative;z-index:1}

.banner{
  display:flex;align-items:center;gap:var(--s-2);
  margin:var(--s-3) var(--s-3) 0;padding:var(--s-3) var(--s-4);
  background:linear-gradient(135deg,#FFF7E8,#FFF0D8);
  border:1px solid #FFE0A8;border-radius:var(--r-md);
  font-size:13.5px;color:#8A5A00;font-weight:500;
}
.banner .ghost{
  margin-left:auto;min-height:var(--tap);padding:0 var(--s-3);
  font-size:13px;color:#8A5A00;background:rgba(255,255,255,.65);
}

/* ═══════════════ ⑥ 壳层：顶栏 / 底栏 ═══════════════ */
.app{
  height:100%;height:100dvh;
  /* 横向布局：左边独立智库工作台，右边通讯主区（窄屏时左栏被隐藏） */
  display:flex;flex-direction:row;
  justify-content:center;
  gap:var(--s-5);
  background:var(--bg-grad);
}
/* 通讯主区：承接原来 .app 的职责（定宽 + 纵向排布） */
.app-main{
  position:relative;              /* v1.30.0：悬浮底栏与 FAB 都以它为定位上下文 */
  flex:1 1 auto;min-width:0;min-height:0;
  max-width:860px;
  display:flex;flex-direction:column;
}
.topbar{
  position:relative;z-index:6;
  display:flex;align-items:center;justify-content:flex-start;gap:var(--s-1);
  padding:calc(8px + env(safe-area-inset-top)) var(--s-2) 8px var(--s-3);
  background:var(--wa-appbar);              /* v1.29.0：中性底（WhatsApp 新版去掉了绿顶栏） */
  color:var(--wa-appbar-ink);
  border-bottom:1px solid var(--wa-line);
}
.topbar-title{color:var(--wa-appbar-title)}
.topbar-title,.topbar-right{position:relative;z-index:1}
.topbar-title{font-size:19px;font-weight:750;letter-spacing:.005em}
.topbar-right{display:flex;align-items:center;gap:var(--s-1);margin-left:auto}
.topbar .ghost{
  color:var(--wa-appbar-title);min-height:var(--tap);padding:0 var(--s-4);
  font-size:13.5px;font-weight:600;background:transparent;
}
.topbar .ghost:active{background:rgba(134,150,160,.16)}
.me{
  display:none;
  font-size:12.5px;color:var(--wa-icon);opacity:1;max-width:120px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
@media (min-width:520px){ .me{display:inline} }

.view{flex:1;display:flex;flex-direction:column;min-height:0}

/* ★ 2026-10-22（v1.125.0）：切页淡入。
   此前 setView 只是把 .hide 翻一下 ⇒ 画面**硬切**，像"页面闪了一下"。
   这里加一层 130ms 的淡入：从 display:none 变回可见时浏览器会自动重播这条动画，
   点当前页（display 没变）则不会播 —— 不需要 JS 参与。

   ⚠️ 只动 opacity，**绝不能用 transform**：.view 内部有 position:absolute 的子元素
   （未读徽标、通话视频层、戒指面板等），给 .view 加 transform 会让它变成新的包含块，
   把这些元素的定位基准整体换掉 —— 这类 bug 不报错，只是位置悄悄错了。 */
@keyframes viewIn{from{opacity:0}to{opacity:1}}
.view:not(.hide){animation:viewIn 130ms var(--e-out)}
@media (prefers-reduced-motion:reduce){ .view:not(.hide){animation:none} }

/* 底栏：玻璃质感 + 图标 + 激活指示条 */
/* .tabbar 已移到 ⑯（v1.30.0：悬浮胶囊 + 半透明毛玻璃） */
.tabbtn{
  position:relative;flex:1;
  min-height:58px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
  color:var(--wa-icon);font-weight:500;font-size:12px;
  transition:color var(--t-base) var(--e-out), background-color var(--t-base) var(--e-out);
  /* ★ 2026-10-22：圆角放在**格子**上（不是只放在 active 态）。
     原因：水波纹一定会被 overflow:hidden 裁掉，格子若是直角，
     按下瞬间看到的就是一块**生硬的灰色方块**（截图确认过）。圆角一致后，
     波纹、选中胶囊、格子边界三者同一个形状，才像"一层水在格子里铺开"。
     overflow:hidden 同时负责把波纹裁在格子里。 */
  border-radius:14px;overflow:hidden;
}
/* WhatsApp 的底栏选中态：**图标与文字一起变青**，加粗一档。
   没有顶部指示条、也没有放大回弹（::after 让给水波纹用，见 ③ 按钮体系）。
   图标放在 HTML 里（svg.ico），不在这里用 ::before —— 见 svg.ico 上方的注释。

   ★ 2026-10-22（v1.125.0）：补一层**选中胶囊**。此前选中只有"变青 + 加粗"，
   在半透明底栏上不够"抓得住"；WhatsApp 新版的选中格有一块很淡的色底。
   只加底色、不加缩放（缩放在底栏上会让文字发虚，而且会触发布局）。 */
.tabbtn.active{color:var(--wa-accent-text);font-weight:600;
  background:var(--wa-active-pill);   /* 圆角继承 .tabbtn 的 14px，见上面的注释 */
}

/* ── 底栏专用水波纹：JS 驱动（v1.125.0）─────────────────────────────
   为什么底栏**不**用上面那套 `:active::after`：
   ① `:active` 只在**按住期间**成立。点底栏时手指接触也就 80~120ms，
      波纹来不及扩开就消失，用户看到的是"闪一下"就没了；
   ② 移动浏览器进入 `:active` 之前要判断"这是不是一次滚动"，有 50~100ms 延迟 ——
      底栏恰恰是最需要"按下即有"的地方，等不起。
   JS 在 pointerdown 里**立刻**插入一个 span 起动画（不等任何判定），
   松手后动画照常播完再淡出 —— 这才是 Material / WhatsApp 的真实行为。
   ★ 全程只动 transform 与 opacity（合成层），不触发布局；
     节点在 animationend 时移除，另有 setTimeout 兜底（动画被打断也要清掉）。 */
.rip{
  position:absolute;border-radius:50%;background:currentColor;
  pointer-events:none;
  transform:translate(-50%,-50%) scale(0);opacity:0;
  animation:ripGo 520ms var(--e-out) forwards;
}
@keyframes ripGo{
  /* ★ 数值比全局水波纹（.22）高一档：底栏用的是灰 currentColor，且压在**半透明**底栏上，
     同一个 .22 在白色胶囊上几乎看不出（截图确认过）。.rip 只用于底栏，不存在连带影响。 */
  0%{transform:translate(-50%,-50%) scale(0);opacity:.34}
  55%{transform:translate(-50%,-50%) scale(1);opacity:.26}
  100%{transform:translate(-50%,-50%) scale(1.08);opacity:0}
}
@media (prefers-reduced-motion:reduce){ .rip{display:none} }
.tabbtn .badge{position:absolute;top:6px;right:calc(50% - 30px)}

/* ═══════════════ ⑦ 列表 / 通讯录（WhatsApp 规格） ═══════════════
   会话行按 WhatsApp 的信息层级来：49px 正圆头像 + 名称 + 灰色预览 + 右侧时间/未读徽标，
   行高 72px、底部分隔线。原来的"卡片式"（圆角+描边+投影+外边距）是最不像 WhatsApp 的地方。 */
.list{flex:1;overflow:auto;padding:0 0 92px;background:var(--wa-panel)}
#view-list .list{padding-bottom:152px}   /* 给右下角 FAB 让位，否则最后一条会话被压住 */
.item{
  display:flex;gap:13px;align-items:center;
  padding:0 16px;
  min-height:72px;
  background:var(--wa-panel);
  border-bottom:1px solid var(--wa-line);
  transition:background-color var(--t-fast) linear;
  cursor:pointer;
}
.item:active{background:rgba(0,0,0,.055)}
.item .main{flex:1;min-width:0}
.item .name{display:flex;align-items:center;gap:var(--s-2);font-weight:400;font-size:17px;color:var(--wa-bubble-ink)}
.item .last{
  margin-top:2px;color:var(--wa-meta);font-size:14px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.item .meta{
  flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;gap:6px;
  color:var(--wa-meta);font-size:12px;
}
.item .name .dot{width:8px;height:8px;border-radius:50%;background:var(--wa-unread)}
/* 头像：WhatsApp 是正圆 49px */
.av{
  flex:0 0 49px;width:49px;height:49px;
  display:grid;place-items:center;
  border-radius:50%;
  background:var(--brand-grad);color:#fff;
  font-weight:600;font-size:19px;
  overflow:hidden;
}
.av.gray{background:linear-gradient(160deg,var(--ink-200),var(--ink-300));color:var(--ink-500)}
.av img{width:100%;height:100%;object-fit:cover;border-radius:inherit}

.badge{
  display:inline-grid;place-items:center;
  min-width:20px;height:20px;padding:0 6px;
  border-radius:var(--r-full);
  background:var(--wa-unread);color:#fff;
  font-size:11.5px;font-weight:600;letter-spacing:.01em;
}
.section-title{
  padding:var(--s-4) 18px var(--s-2);
  color:var(--ink-500);font-size:11.5px;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;
}
/* 搜索框：WhatsApp 是"浅灰胶囊"（白底输入框在白色列表上看不出边界） */
.searchbar{display:flex;gap:var(--s-2);padding:8px 12px;background:var(--wa-panel)}
.searchbar input{
  flex:1;height:38px;border-radius:var(--r-full);
  background:var(--ink-100);border:1px solid transparent;padding:0 16px;
}
.searchbar input:focus{background:var(--wa-panel);border-color:var(--wa-header)}
.searchbar button{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:var(--tap);padding:0 var(--s-5);
  border-radius:var(--r-full);
  background:var(--wa-btn);color:var(--wa-btn-ink);
  font-weight:600;font-size:14px;
}
.searchbar button:active{background:var(--wa-btn-press)}
/* 通讯录搜索栏里的「扫一扫」：**图标按钮**，与右边绿色的「添加」并排。
   做成浅底图标（而不是第二个绿色实心块）：两颗同样重的按钮并排会让人分不清主次 ——
   手输用户名是主路，扫码是更快的旁路。命中区仍是 var(--tap)，不会变小。 */
.searchbar .scan-ic{
  flex:0 0 var(--tap);width:var(--tap);padding:0;
  background:var(--ink-100);color:var(--ink-500);
}
.searchbar .scan-ic:active{background:var(--ink-200)}
.searchbar .scan-ic .ico{width:21px;height:21px}

.group-create{display:grid;gap:var(--s-3);padding:0 var(--s-4) 110px}
.group-create .primary{width:100%}
.chips{display:flex;flex-wrap:wrap;gap:var(--s-2)}
.chip{
  display:inline-flex;align-items:center;
  min-height:var(--tap);padding:0 15px;
  border-radius:var(--r-full);
  background:transparent;border:1px solid var(--wa-line);
  color:var(--text);font-size:13px;font-weight:500;
  transition:background-color var(--t-fast) linear,
             border-color var(--t-fast) linear, color var(--t-fast) linear;
}
.chip:active{background:var(--ink-100)}
/* 选中 = 实心胶囊（和主按钮同一档视觉，一眼知道"已选"） */
.chip.on{background:var(--wa-btn);color:var(--wa-btn-ink);border-color:var(--wa-btn)}

#my-card{margin:var(--s-3) var(--s-3) 0;box-shadow:var(--sh-sm);border-radius:var(--r-lg)}
#my-card .ghost{margin-left:auto;color:var(--wa-btn-outline);background:transparent}
#view-contacts .list{padding-bottom:220px}

/* ═══════════════ ⑧ 聊天 ═══════════════ */
.chat{background:var(--bg-grad)}
.chat-head{
  position:relative;z-index:4;
  display:flex;align-items:center;gap:var(--s-2);
  padding:var(--s-1) var(--s-3);
  background:var(--wa-appbar);          /* v1.29.0：新版聊天头同样是中性底，不再是绿栏 */
  color:var(--wa-appbar-ink);
  border-bottom:1px solid var(--wa-line);
}
.chat-title{font-weight:700;font-size:16px;letter-spacing:.005em}
.chat-sub{color:var(--ink-500);font-size:12px;margin-left:auto}
.chat-head .ghost{
  min-height:var(--tap);padding:0 var(--s-3);
  font-size:14px;color:var(--wa-appbar-ink);background:transparent;
}
/* WhatsApp 的头部图标按钮就是"透明底 + 白色图标 + 按下才出现圆形高光"，没有常驻底色 */
.chat-head .ghost:active{background:rgba(134,150,160,.18)}
.chat-head .ghost[title="语音通话"]{min-width:var(--tap);padding:0;font-size:17px}

/* 聊天区：WhatsApp 的米色底 + 极淡点阵纹理（纯色会显得太平，纹理也是它的辨识特征） */
.messages{
  flex:1;overflow:auto;
  /* ★ v1.56.0：关掉浏览器的**滚动锚定**。
     往顶部补历史时我们自己会精确补偿 scrollTop（见 loadOlderMessages），
     而 Chrome/Edge 默认也会按它自己的锚点再调一次 —— 两者叠加的结果是差 16px
     （实测：app 自己读到 4647，浏览器随后又改了内容高度，最终 4663）。
     "手动补偿 + 自动锚定"必然打架，标准做法就是关掉自动那个。 */
  overflow-anchor:none;
  padding:12px 6% 14px;
  display:flex;flex-direction:column;gap:2px;
  background-color:var(--wa-chat-bg);
  background-image:radial-gradient(rgba(0,0,0,.035) 1px,transparent 1px);
  background-size:22px 22px;
}
.msg{
  position:relative;max-width:65%;
  padding:6px 7px 8px 9px;
  border-radius:7.5px;
  background:var(--wa-bubble-in);
  color:var(--wa-bubble-ink);
  box-shadow:0 1px .5px rgba(11,20,26,.13);
  word-break:break-word;
  font-size:14.2px;line-height:1.45;
  animation:msgIn var(--t-base) var(--e-out) both;
}
/* 自己：浅绿气泡 + 右下收角（尾巴单独画） */
.msg.mine{
  align-self:flex-end;
  background:var(--wa-bubble-out);color:var(--wa-bubble-ink);
  border-bottom-right-radius:0;
}
.msg:not(.mine):not(.system){border-bottom-left-radius:0}
/* 气泡尾巴：6×12 的直角三角形，颜色跟着气泡走（用 clip-path 就不必再背一张 SVG/图片资源） */
.msg.mine::after,.msg:not(.mine):not(.system)::after{
  content:'';position:absolute;bottom:0;width:6px;height:12px;background:inherit;
}
.msg.mine::after{right:-6px;clip-path:polygon(0 0,100% 100%,0 100%)}
.msg:not(.mine):not(.system)::after{left:-6px;clip-path:polygon(100% 0,100% 100%,0 100%)}
.msg img{display:block;max-width:100%;border-radius:6px}
/* 群聊里的发送者名：WhatsApp 用彩色名字区分成员 */
.msg .from{font-size:12.5px;color:#06CF9C;font-weight:600;margin-bottom:2px}
/* 时间浮在气泡右下，正文自然环绕（float 而不是块级右对齐，才像 WhatsApp 那样"贴着最后一行"） */
.msg .time{
  float:right;margin:6px -2px -3px 10px;
  display:inline-flex;align-items:center;gap:3px;
  font-size:11px;color:var(--wa-meta);
  font-variant-numeric:tabular-nums;letter-spacing:.01em;
  white-space:nowrap;
}
.msg .state{font-size:11px;color:var(--wa-meta)}
.msg .state.read{color:var(--wa-tick-read)}       /* 已读双勾是蓝色 */
/* ── 乐观回显的三个状态（v1.49.0）──
   点发送后消息**立刻上屏**（pending），服务器回来才变实心勾。
   这样在手机网络上（往返 100–500ms）用户看到的是"秒发出去"，
   而不会以为没点上、又点一次。 */
.msg.pending{opacity:.62}
.msg .state.pending{opacity:.75;letter-spacing:0}
.msg.failed{background:rgba(211,47,63,.14)!important;cursor:pointer}
.msg.failed .state.failed{
  display:inline-flex;align-items:center;justify-content:center;
  width:15px;height:15px;border-radius:50%;background:#D32F3F;color:#fff;
  font-size:11px;font-weight:800;line-height:1;letter-spacing:0;
}
.msg.failed:active{background:rgba(211,47,63,.22)!important}
.msg .file{
  display:flex;gap:var(--s-2);align-items:center;
  text-decoration:none;color:inherit;font-size:14px;
}
/* 系统消息：居中小胶囊 */
.msg.system{
  align-self:center;max-width:92%;
  padding:5px 12px;
  background:var(--wa-bubble-in);
  box-shadow:0 1px .5px rgba(11,20,26,.13);
  color:var(--wa-meta);
  font-size:12.5px;border-radius:7.5px;
  text-align:center;line-height:1.4;
}
.msg.system::after{content:none}
.typing{padding:var(--s-1) 18px 0;color:var(--ink-500);font-size:12px}

/* ── v1.56.0：编辑消息提示条 / 加载更早消息的提示 / 「已编辑」标记 ──
   编辑条挂在 .composer **上方**（不在里面）：输入栏是横向 flex，塞进去会把输入框挤窄。
   左侧那条竖线是"编辑态"最强的视觉信号 —— 不靠颜色很难一眼看出"我现在改的是旧消息"。 */
.edit-bar{
  display:flex;align-items:center;gap:var(--s-2);
  margin:0 6% 6px;padding:8px 12px;
  border-radius:var(--r-md);
  background:var(--wa-panel);
  border:1px solid var(--wa-line);
  border-left:3px solid var(--wa-accent);
  color:var(--ink-700);font-size:13px;
}
.edit-bar .ico{width:16px;height:16px;flex:0 0 auto;color:var(--wa-accent)}
.edit-bar-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:650}
.edit-bar .ghost{min-height:32px;padding:0 var(--s-3);font-size:12.5px}
/* 补更早历史时的顶部提示：内容行高不固定，没有它用户只看到画面"卡一下" */
.chat-older{padding:6px 0 10px;text-align:center;color:var(--ink-500);font-size:12px}
/* 「已编辑」：与时间同一行、同一行高（float:right 的 .time 里是个 inline-flex） */
.msg .time .edited{font-weight:500;opacity:.85}

@keyframes msgIn{from{opacity:0;transform:translateY(10px) scale(.97)}to{opacity:1;transform:none}}

/* ── v1.59.0：消息拖动重排（长按抬起 → 上下移动 → 松手落位）────────────────
   三个状态：.drag-armed（长按已触发、手指还没动）/ .dragging（正在拖）/ .drop-line（插入位置）。
   ⚠️ 前两个都必须 `animation:none`：气泡有入场动画 msgIn（用 transform 做的），
      动画会盖掉我们写在 inline style 上的 transform ——
      表现就是"手指在动、气泡纹丝不动"，而代码看起来完全没问题。 */
.msg.drag-armed{animation:none !important;transform:scale(.97);opacity:.85;
  box-shadow:0 10px 24px -8px rgba(15,23,42,.42)}
.msg.dragging{animation:none !important;position:relative;z-index:30;opacity:.96;
  box-shadow:0 16px 32px -10px rgba(15,23,42,.5);transition:none}
/* 插入指示线：拖动时告诉用户"松手会落在这里" */
.drop-line{height:2px;margin:3px 6%;border-radius:2px;background:var(--wa-accent);
  box-shadow:0 0 0 3px rgba(22,169,2,.16)}

/* 输入栏：WhatsApp 是白底 + 胶囊输入框 + 纯图标按钮（没有背景块） */
.composer{
  display:flex;gap:4px;align-items:center;
  padding:7px 8px;
  padding-bottom:calc(7px + env(safe-area-inset-bottom));
  background:var(--wa-panel);
}
.composer input{
  flex:1;width:100%;min-height:42px;padding:0 14px;
  border-radius:21px;
  background:var(--wa-input);border:1px solid var(--wa-line);
  font-size:15px;color:var(--wa-bubble-ink);
}
.composer input::placeholder{color:var(--wa-icon)}
.composer input:focus{border-color:var(--wa-header);box-shadow:none;background:var(--wa-input)}
/* ★ 触摸下限仍是 44px（WhatsApp 的图标按钮本来就是这个尺寸，视觉上也吻合） */
.composer .icon{
  flex:0 0 var(--tap);
  width:var(--tap);height:var(--tap);
  display:grid;place-items:center;
  border-radius:50%;
  background:transparent;color:var(--wa-icon);
  font-size:20px;line-height:1;
}
.composer .icon:active{background:rgba(134,150,160,.16)}
/* 发送键：WhatsApp 最标志性的那颗**圆形亮青钮**（纯图标，非文本比对只要求 3:1，实测 3.03 ✅） */
.composer .icon.send{background:var(--wa-accent);color:#fff;font-size:18px}
.composer .primary{
  min-height:var(--tap);padding:0 18px;
  border-radius:var(--r-full);font-size:14px;
  background:var(--wa-header);color:#fff;
}

/* ═══════════════ ⑨ 语音消息 / 录音 ═══════════════
   v1.31.2 按参考图重排：语音是**长条**，不是方疙瘩。参考图量出来的形态：
     · 气泡宽 ≈ 屏宽的 60%（固定宽度；不随时长膨胀成很宽的一条）
     · 高 ≈ 宽的 0.28 —— 所以是**两行**：
         上行「裸三角 ▶ + 波形（很多根细竖条）」，下行「时长 … 时间/勾」
     · 播放键是**裸三角**（没有圆形底），旧版那个 44px 圆底是"方疙瘩"的主因之一
   高度预算：padding 6+8=14 + 上行 32 + 行距 2 + 下行 16 ≈ 64px */
.msg.voice{width:62%;min-width:196px;max-width:264px;display:flex;flex-direction:column;gap:2px}
.msg.voice .vrow{display:flex;align-items:center;gap:8px;height:32px}
/* ★ 触摸目标仍要 ≥44：视觉上只占 32px 的一行，靠**负外边距**把 44×44 的命中区挂出去。
   若把这一行直接撑到 44px，气泡又会变回方疙瘩 —— 那正是这次要修的问题。 */
.msg.voice button.vplay{
  flex:0 0 var(--tap);width:var(--tap);height:var(--tap);margin:-6px 0 -6px -8px;
  display:grid;place-items:center;
  border-radius:50%;background:transparent;
  color:inherit;line-height:0;
}
.msg:not(.mine).voice button.vplay{color:var(--wa-icon)}
.msg.voice .vplay .ico{width:20px;height:20px}
.msg.voice .vwave{flex:1;min-width:0;display:flex;align-items:center;gap:3px;height:22px}
.msg.voice .vwave i{flex:1 1 0;min-width:2px;max-width:4px;border-radius:2px;background:currentColor;opacity:.42}
.msg.voice .vfoot{display:flex;align-items:center;gap:6px;min-height:16px}
.msg.voice .vdur{margin-right:auto;font-size:11.5px;opacity:.75;font-variant-numeric:tabular-nums}
/* ⋯ 收成不可见：参考图里没有它，而长按/点气泡本来就能出操作菜单（元素保留在 DOM 里，
   行为不变 —— browser-check 仍然会点它验证菜单能开）。 */
.msg.voice .vmore{
  position:absolute;width:1px;height:1px;padding:0;opacity:0;overflow:hidden;pointer-events:none;
}
/* 时间进第二行：float 在 flex 行里失效，margin 也要显式归零，否则错位 */
.msg.voice .time{float:none;margin:0;font-size:11px}

/* 录音条 */
.rec-bar{
  display:flex;align-items:center;gap:var(--s-3);
  padding:var(--s-3) var(--s-3);
  background:linear-gradient(135deg,#FFF7E8,#FFEFD6);
  border-top:1px solid #FFE0A8;
  color:#8A5A00;font-size:14px;
}
.rec-dot{
  flex:0 0 10px;width:10px;height:10px;border-radius:50%;
  background:var(--danger);animation:pulse 1.2s infinite;
}
@keyframes pulse{
  0%{opacity:1;box-shadow:0 0 0 0 rgba(255,71,87,.5)}
  70%{opacity:.55;box-shadow:0 0 0 9px rgba(255,71,87,0)}
  100%{opacity:1;box-shadow:0 0 0 0 rgba(255,71,87,0)}
}
#rec-time{font-weight:700;font-variant-numeric:tabular-nums}
.rec-bar .rec-hint{margin-right:auto;color:#8A5A00;font-size:12px}
.rec-bar .ghost{min-height:var(--tap);color:#8A5A00;background:rgba(255,255,255,.6)}
.rec-bar .primary{min-height:var(--tap);padding:0 var(--s-4);font-size:14px}

/* ═══════════════ ⑩ 通话浮层（沉浸式） ═══════════════ */
.call-overlay{
  position:fixed;inset:0;z-index:80;
  display:flex;align-items:center;justify-content:center;
  background:radial-gradient(120% 95% at 50% 0%,#2C2555 0%,#191632 55%,#0E0C1F 100%);
  animation:fadeIn var(--t-base) var(--e-out);
}
.call-card{
  display:flex;flex-direction:column;align-items:center;gap:var(--s-2);
  width:min(92vw,360px);padding:var(--s-6);
  text-align:center;color:#fff;
  background:transparent;
}
.call-avatar .ico{width:44px;height:44px;stroke-width:1.5}
.call-avatar{
  display:grid;place-items:center;
  width:104px;height:104px;margin-bottom:var(--s-3);
  border-radius:36px;
  background:var(--brand-grad);
  font-size:40px;
  box-shadow:0 24px 56px -22px rgba(34,196,9,.95);
  animation:breathe 2.8s var(--e-out) infinite;
}
@keyframes breathe{0%,100%{transform:scale(1)}50%{transform:scale(1.05)}}
.call-name{font-size:22px;font-weight:750;letter-spacing:.005em}
.call-status{color:rgba(255,255,255,.62);font-size:13.5px}
.call-timer{
  min-height:22px;font-size:17px;font-weight:700;
  color:#3FC51F;font-variant-numeric:tabular-nums;letter-spacing:.02em;
}
.call-actions{display:flex;gap:var(--s-4);margin-top:var(--s-4)}
.call-actions .primary{background:var(--wa-btn);box-shadow:none}   /* 纯色（白字 4.89:1），不用渐变+彩色投影 */
.call-actions .ghost{color:#fff;background:rgba(255,255,255,.14);min-height:var(--tap)}
/* 「开启声音」：只在浏览器拦截自动播放时出现。
   没有这个按钮的话，用户看到的就是"通话中但没声音"，而且完全无从下手。 */
#call-sound{background:#FFB020;color:#3A2400;font-weight:800}   /* 纯色，去掉渐变 */
.call-hint{min-height:14px;color:rgba(255,255,255,.62);font-size:11.5px;text-align:center;line-height:1.5}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}

/* ── 视频通话（v1.52.0）────────────────────────────────────────────
   **单独一层**，与语音那条路完全分开：远端画面铺满，名字/状态/计时浮在顶部、
   控制条沉到底部。语音的 .call-card 默认样式一行没改，48 条既有断言原样成立。 */
.call-video{position:absolute;inset:0;z-index:0;background:#0B141A}
.call-remote{width:100%;height:100%;object-fit:cover;background:#0B141A;display:block}
/* 上下渐变遮罩：白字压在**实时画面**上也要读得清（与相机浮层同一条理由） */
.call-video::before,.call-video::after{content:'';position:absolute;left:0;right:0;pointer-events:none}
.call-video::before{top:0;height:200px;background:linear-gradient(180deg,rgba(0,0,0,.66),transparent)}
.call-video::after{bottom:0;height:240px;background:linear-gradient(0deg,rgba(0,0,0,.74),transparent)}
.call-video-off{
  position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
  text-align:center;color:rgba(255,255,255,.72);font-size:14px;font-weight:600;
}
/* 本地画中画：默认右下，点一下换到右上（对方的脸被挡住时能躲开） */
.call-pip{
  position:absolute;z-index:2;right:var(--s-4);
  bottom:calc(env(safe-area-inset-bottom) + 116px);
  width:104px;height:146px;border-radius:16px;overflow:hidden;background:#111B21;
  box-shadow:0 10px 26px -10px rgba(0,0,0,.8),0 0 0 1.5px rgba(255,255,255,.16);
  transition:top var(--t-base) var(--e-out),bottom var(--t-base) var(--e-out);
}
.call-pip.pip-top{top:calc(env(safe-area-inset-top) + 96px);bottom:auto}
.call-local{width:100%;height:100%;object-fit:cover;display:block}
.call-local.mirror{transform:scaleX(-1)}       /* 自拍镜像：**只**镜像本地预览 */
.call-local-btn{position:absolute;inset:0;background:transparent;border:0}
.call-local-btn:active{background:rgba(255,255,255,.10)}
/* 视频态：卡片变成"铺满 + 文字浮上去"；头像呼吸圈收起来（有画面就不需要它） */
.call-overlay.is-video{background:#0B141A}
.call-overlay.is-video .call-card{
  width:100%;height:100%;z-index:1;gap:4px;justify-content:flex-start;
  padding:calc(env(safe-area-inset-top) + var(--s-5)) var(--s-5) calc(env(safe-area-inset-bottom) + var(--s-5));
}
.call-overlay.is-video .call-avatar{display:none}
.call-overlay.is-video .call-name,.call-overlay.is-video .call-status,.call-overlay.is-video .call-hint{text-shadow:0 1px 4px rgba(0,0,0,.72)}
.call-overlay.is-video .call-actions{margin-top:auto;flex-wrap:wrap;justify-content:center;gap:var(--s-3)}
/* 5 个带文字的按钮在 390px 上必然溢出 → 视频态收成圆形图标钮（文字进 aria-label）。
   这是"少即是多"：单手可达、每个都是 48px 触摸目标，和系统相机一个观感。 */
.call-overlay.is-video .call-actions button{
  width:var(--wa-btn-h);height:var(--wa-btn-h);min-height:var(--wa-btn-h);
  padding:0;border-radius:50%;font-size:0;gap:0;display:grid;place-items:center;
}
.call-actions button.off{background:#FFFFFF;color:#0B141A}   /* 已静音 / 已关摄像头：反白，一眼看出状态 */

/* ═══════════════ ⑪ 抽屉 ═══════════════ */
.overlay{
  position:fixed;inset:0;z-index:50;
  display:flex;align-items:flex-end;justify-content:center;
  background:rgba(15,23,42,.5);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  animation:fadeIn var(--t-base) var(--e-out);
}
.sheet{
  width:100%;max-width:520px;max-height:84vh;
  display:flex;flex-direction:column;
  background:var(--surface);
  border-radius:var(--r-2xl) var(--r-2xl) 0 0;
  box-shadow:0 -24px 56px -24px rgba(15,23,42,.5);
  animation:sheetUp var(--t-slow) var(--e-out);
  overflow:hidden;
}
/* 顶部拖拽把手：给用户"可下拉关闭"的手感暗示 */
.sheet::before{
  content:'';flex:0 0 auto;
  width:40px;height:4px;margin:10px auto 2px;
  border-radius:var(--r-full);background:var(--ink-300);
}
.sheet-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:var(--s-3) var(--s-4) var(--s-3);
  font-size:16px;font-weight:700;
  border-bottom:1px solid var(--line);
}
.sheet-body{padding:var(--s-2) var(--s-4) calc(26px + env(safe-area-inset-bottom));overflow:auto}
.sheet .row{display:flex;gap:var(--s-2);align-items:center;margin:var(--s-3) 0}
.sheet .row label{min-width:64px;color:var(--ink-500);font-size:13px;font-weight:620}
.sheet .row input{height:var(--tap);border-radius:var(--r-sm)}
.sheet .row .primary{min-height:var(--tap);padding:0 var(--s-4);font-size:14px;box-shadow:none}
.sheet .sec{
  margin:var(--s-4) 0 var(--s-2);
  color:var(--ink-500);font-size:12px;font-weight:620;
  letter-spacing:.02em;line-height:1.5;
}
/* 抽屉内的危险块按钮（退出群聊等）与上方内容留出呼吸空间 */
.sheet-body > .btn-danger-soft:last-child{margin-top:var(--s-4)}

@keyframes sheetUp{from{transform:translateY(24px);opacity:.6}to{transform:none;opacity:1}}

/* ═══════════════ ⑪之二 智能戒指悬浮面板（v1.63.0）═══════════════
   与通用抽屉同一套动效，只是**更高**（92vh）且中间多一条分区切换：
   戒指要同时放得下"当前值 + 趋势 + 设置"，84vh 会一直滚。 */
.ring-panel{
  flex:1 1 auto;min-height:0;overflow:auto;-webkit-overflow-scrolling:touch;
  padding:var(--s-3) var(--s-4) calc(26px + env(safe-area-inset-bottom));
}
/* 指标网格：两列起步，宽屏三列。每格一张卡（名字 / 值 / 单位 / 来源角标） */
.ring-grid{display:grid;gap:var(--s-2);grid-template-columns:repeat(2,minmax(0,1fr))}
@media(min-width:520px){.ring-grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
.ring-card{
  padding:12px;border-radius:var(--r-md);
  background:var(--ink-100);border:1px solid var(--line);
  display:flex;flex-direction:column;gap:2px;min-width:0;
}
.ring-card .k{font-size:12px;color:var(--ink-500);font-weight:620}
.ring-card .v{
  font-size:22px;font-weight:800;line-height:1.15;
  font-variant-numeric:tabular-nums;letter-spacing:-.01em;
}
.ring-card .u{font-size:11px;color:var(--ink-500)}
.ring-card .src{font-size:10.5px;color:var(--ink-500);margin-top:2px}
/* 数据来源角标：能直读是绿的，暂不能直读是灰的 —— 不做"点了永远 0"的假按钮 */
.ring-chip{
  display:inline-flex;align-items:center;gap:4px;
  padding:0 7px;min-height:18px;border-radius:var(--r-full);
  font-size:10.5px;font-weight:700;
}
.ring-chip.ble{background:var(--brand-50);color:var(--brand-text)}
.ring-chip.vendor{background:rgba(120,120,140,.16);color:var(--ink-600)}
.ring-chip.manual{background:rgba(120,120,140,.16);color:var(--ink-600)}
.ring-note{margin:var(--s-2) 0 0;color:var(--ink-500);font-size:12px;line-height:1.6}
/* ★ v1.118.0 线：说明文案里的**内联代码**（如 `6e400005` / `{0x12,1}`）。
   以前 setElText 只处理 `**`，反引号会**原样显示**在界面上（用户看到一串怪符号）；
   现在渲染成等宽小块。用 rgba 而不是令牌：中性灰对明暗两套底都可读，也不会"令牌写错静默失效"。 */
.ring-note .md-code,.ring-sub .md-code,.ring-mesub .md-code,.wa-note .md-code,.wa-row-sub .md-code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.92em;padding:0 3px;border-radius:3px;background:rgba(127,127,127,.14)}
.ring-sec{margin:var(--s-4) 0 var(--s-2);color:var(--ink-500);font-size:12px;font-weight:700}
/* 目标进度条 */
.ring-bar{height:8px;border-radius:var(--r-full);background:var(--ink-100);overflow:hidden;margin-top:6px}
.ring-bar > i{display:block;height:100%;background:var(--brand-500);border-radius:var(--r-full)}
/* 睡眠分段条：深睡/浅睡/REM/清醒 按比例排一行 */
.ring-sleepbar{display:flex;height:14px;border-radius:var(--r-full);overflow:hidden;background:var(--ink-100)}
.ring-sleepbar > i{display:block;height:100%}
.ring-sleepbar .deep{background:#4338CA}
.ring-sleepbar .light{background:#60A5FA}
.ring-sleepbar .rem{background:#22D3EE}
.ring-sleepbar .awake{background:#F59E0B}
.ring-legend{display:flex;flex-wrap:wrap;gap:10px;margin-top:6px;font-size:11.5px;color:var(--ink-600)}
.ring-legend span{display:inline-flex;align-items:center;gap:5px}
.ring-legend i{width:8px;height:8px;border-radius:2px;display:inline-block}
/* 开关行（提醒与同步）：整行可点，触摸目标 ≥44px */
.ring-switch{
  display:flex;align-items:center;gap:var(--s-3);
  min-height:var(--tap);padding:var(--s-2) 0;border-bottom:1px solid var(--ink-100);
}
.ring-switch .grow{flex:1;min-width:0}
.ring-switch .grow b{display:block;font-size:14px;font-weight:650}
.ring-switch .grow span{display:block;font-size:12px;color:var(--ink-500)}
.ring-switch input[type=checkbox]{width:22px;height:22px;flex:0 0 auto}
/* 扫描结果：整行可点的按钮（原生 BLE 两段式的第二步） */
.ring-pick{
  display:flex;width:100%;text-align:left;font:inherit;color:inherit;cursor:pointer;
  background:transparent;border:0;border-bottom:1px solid var(--ink-100);
  min-height:var(--tap);padding:var(--s-2) 0;
}
.ring-pick:disabled{opacity:.55}

/* ══════════ 戒指图表（v1.64.0）══════════
   ★ 全部是**手写 SVG**（零依赖、可打印、可被 CDP 量到像素），不是 canvas：
     ① 矢量图在任意 DPI 与缩放下的刻度都是清晰的；
     ② ★ 验收要能"看见"—— SVG 的每个段都是 DOM 节点，测试可以直接数 <rect>/<path>，
        而 canvas 里画了什么，脚本一个字也读不出来（上一版"图形没做"就是这么漏过去的）。
   ★ 颜色一律走 CSS 变量：暗色模式由 ⑬ 那段统一覆盖，图表自己不写死底色。 */
.rc{
  background:var(--surface);border:1px solid var(--ink-200);border-radius:var(--r-md);
  padding:var(--s-3);margin-top:var(--s-2);
}
.rc + .rc{margin-top:var(--s-2)}
.rc-h{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2)}
.rc-h b{font-size:13px;font-weight:680;color:var(--text)}
.rc-h span{font-size:11.5px;color:var(--ink-500)}
.rc svg{display:block;width:100%;height:auto;margin-top:var(--s-2);overflow:visible}
.rc-empty{padding:var(--s-4) 0;text-align:center;color:var(--ink-400);font-size:12px}
/* 环形图按 viewBox 是正方形，铺满面板宽度会变成一张巨图 —— 单独限宽居中 */
.rc-donut svg{max-width:190px;margin-left:auto;margin-right:auto}
/* 折线：网格用最浅的中性色，线用品牌色，末点加重 */
.rc-grid{stroke:var(--ink-200);stroke-width:1;shape-rendering:crispEdges}
.rc-zero{stroke:var(--ink-300);stroke-width:1;stroke-dasharray:3 3}
.rc-area{fill:var(--brand-300);opacity:.28}
.rc-line{fill:none;stroke:var(--brand-500);stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.rc-dot{fill:var(--surface);stroke:var(--brand-500);stroke-width:1.6}
.rc-dot-last{fill:var(--brand-500);stroke:var(--surface);stroke-width:1.6}
.rc-txt{fill:var(--ink-500);font-size:9.5px;font-family:inherit}
.rc-txt.strong{fill:var(--text);font-weight:680}
/* 环形进度（步数 / 目标） */
.rc-arc-track{fill:none;stroke:var(--ink-100);stroke-width:10}
.rc-arc{fill:none;stroke:var(--brand-500);stroke-width:10;stroke-linecap:round}
.rc-num{fill:var(--text);font-size:19px;font-weight:750;text-anchor:middle;font-family:inherit}
.rc-sub{fill:var(--ink-500);font-size:9.5px;text-anchor:middle;font-family:inherit}
/* 柱状（近 N 天） */
.rc-bar{fill:var(--brand-300)}
.rc-bar.on{fill:var(--brand-500)}
.rc-bar-axis{stroke:var(--ink-200);stroke-width:1;shape-rendering:crispEdges}
/* 睡眠分期色（语义色，不随主题变——分期颜色本身就是图例的一部分） */
.rc-s-deep{fill:#4338CA}
.rc-s-light{fill:#60A5FA}
.rc-s-rem{fill:#22D3EE}
.rc-s-awake{fill:#F59E0B}
.rc-s-gap{fill:var(--ink-100)}
/* 戒指设备插画：戒圈描边 + 电量弧 + 宝石 */
.ring-art{display:flex;align-items:center;gap:var(--s-3)}
.ring-art svg{width:78px;height:78px;flex:0 0 auto}
.ring-art .ra-band{fill:none;stroke:var(--ink-300);stroke-width:9}
.ring-art .ra-fill{fill:none;stroke:var(--brand-500);stroke-width:9;stroke-linecap:round}
.ring-art .ra-gem{fill:var(--brand-400)}
.ring-art .ra-gem-edge{fill:none;stroke:var(--brand-600);stroke-width:1.5}

/* ══════════ 官方戒指 App 版式（v1.64.0） ══════════
   只借官方 App 的版式（设备条 / 大环 / 网格卡），颜色一律走 CSS 变量，
   暗色模式由下面 ⑬ 段一并覆盖 —— 图表与卡片都不许写死底色。 */
/* 顶部设备状态条：状态点 + 名字 + 电量胶囊 */
.ring-devbar{
  display:flex;align-items:center;gap:var(--s-2);
  padding:var(--s-2) var(--s-3);border-radius:var(--r-md);
  background:var(--ink-100);margin-bottom:var(--s-3);
}
.ring-devbar .grow{display:flex;flex-direction:column;min-width:0}
.ring-devbar .grow b{font-size:13.5px;color:var(--text);font-weight:680;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ring-devbar .grow span{font-size:11px;color:var(--ink-500)}
.ring-dot{width:9px;height:9px;border-radius:var(--r-full);flex:0 0 auto;background:var(--ink-300)}
.ring-dot.on{background:var(--brand-500);box-shadow:0 0 0 3px rgba(14,138,0,.16)}
.ring-dot.idle{background:var(--warning);box-shadow:0 0 0 3px rgba(255,170,0,.16)}
.ring-dot.off{background:var(--ink-400)}
.ring-batt{
  display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;
  padding:3px 8px;border-radius:var(--r-full);background:var(--surface);
  font-size:11.5px;color:var(--ink-600);
}
.ring-batt svg{width:15px;height:15px}
.ring-batt b{font-weight:680;color:var(--text)}
.ring-batt.low b,.ring-batt.low svg{color:var(--danger)}
/* 大环（官方戒指 App 首页主视觉） */
.ring-hero{display:flex;flex-direction:column;align-items:center;gap:var(--s-2);
  padding:var(--s-2) 0 var(--s-1)}
.ring-hero svg{width:196px;height:196px;flex:0 0 auto}
.rc-arc-track.hero{stroke-width:13}
.rc-arc.hero{stroke-width:13}
.rc-num.hero{font-size:38px;font-weight:780}
.rc-sub.hero{font-size:11.5px}
.rc-badge{fill:var(--brand-600);font-size:12px;font-weight:720;text-anchor:middle;font-family:inherit}
.ring-hero-ft{display:flex;gap:var(--s-2);width:100%}
.ring-hero-cell{
  flex:1 1 0;display:flex;flex-direction:column;align-items:center;gap:1px;
  padding:var(--s-2);border-radius:var(--r-md);background:var(--ink-100);
}
.ring-hero-cell span{font-size:11px;color:var(--ink-500)}
.ring-hero-cell b{font-size:17px;font-weight:740;color:var(--text);line-height:1.15}
.ring-hero-cell i{font-size:10.5px;color:var(--ink-500);font-style:normal}
/* 指标网格卡：图标 + 标签 + 值 + 迷你趋势 + 来源角标 */
.ring-grid-3{grid-template-columns:repeat(2,minmax(0,1fr))}
@media(min-width:520px){.ring-grid-3{grid-template-columns:repeat(3,minmax(0,1fr))}}
.ring-metric{gap:2px}
.ring-metric-h{display:flex;align-items:center;gap:5px;min-width:0}
.ring-metric-h span{font-size:11.5px;color:var(--ink-500);font-weight:640;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ring-ico{display:inline-flex;flex:0 0 auto;color:var(--brand-600)}
.ring-ico svg{width:15px;height:15px}
.ring-card .v.dim{color:var(--ink-400);font-weight:600}
.ring-spark{height:30px;display:flex;align-items:center;margin:2px 0}
.ring-spark svg{width:100%;height:30px}
.ring-spark-none{font-size:10px;color:var(--ink-400)}
.rc-spark-line{fill:none;stroke:var(--brand-500);stroke-width:1.6;stroke-linejoin:round;stroke-linecap:round}
.rc-spark-dot{fill:var(--brand-500)}
/* 可点的行 / 卡：给一个右箭头，别让人猜"这行能不能点" */
.ring-tap{cursor:pointer}
.ring-tap:active{background:var(--ink-100)}
.ring-chev{color:var(--ink-400);font-size:15px;flex:0 0 auto;padding-left:var(--s-2)}

/* ══════════════════════════════════════════════════════════════════
   iOS 27 风格（v1.65.0）：Liquid Glass 修订版
   ──────────────────────────────────────────────────────────────────
   依据 iOS 27 公开的设计变化，取这四条（不是"加点毛玻璃"就叫 iOS）：
     ① **深色描边**：玻璃元素四周有一圈压暗的边 —— 这是 iOS 27 为修可读性新加的，
        没有它，浅底上的玻璃块与背景糊在一起，看着"脏"。
     ② **更亮的镜面高光**：顶部一道 1px 亮线，玻璃才有厚度。
     ③ **更有效的背景扩散**：blur + saturate 一起用（只 blur 会发灰）。
     ④ **统一圆角**：外层 26 / 卡 20 / 内件 14，**同心**（外 = 内 + 内边距），
        圆角不一致是"看着不像原生"最常见的来源。
   另外沿用 iOS 27 的重点：**对比度优先**（玻璃默认更不透明，不做"看不清"的那种炫）。
   颜色全部走变量，暗色在下面一段覆盖。
   ══════════════════════════════════════════════════════════════════ */
:root{
  --gl-fill:rgba(255,255,255,.66);
  --gl-fill-2:rgba(255,255,255,.82);
  --gl-edge:rgba(15,23,42,.10);      /* ① 深色描边 */
  --gl-spec:rgba(255,255,255,.92);   /* ② 顶部高光 */
  --gl-blur:blur(26px) saturate(180%);
  --gl-r:26px; --gl-r-card:20px; --gl-r-inner:14px;
  --gl-shadow:0 1px 1px rgba(15,23,42,.05), 0 12px 32px -14px rgba(15,23,42,.28);
}
@media (prefers-color-scheme: dark){
  :root{
    --gl-fill:rgba(28,32,44,.60);
    --gl-fill-2:rgba(34,39,53,.78);
    --gl-edge:rgba(255,255,255,.10);
    --gl-spec:rgba(255,255,255,.16);
    --gl-shadow:0 1px 1px rgba(0,0,0,.4), 0 14px 34px -14px rgba(0,0,0,.7);
  }
}
/* 玻璃基件：所有卡片共用这一份材质 —— 各写各的迟早会出现"两张卡质感不一样" */
.ring-glass{
  background:var(--gl-fill);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  border:.5px solid var(--gl-edge);
  box-shadow:inset 0 .5px 0 var(--gl-spec), var(--gl-shadow);
}

/* 顶部设备条 */
.ring-devbar{
  background:var(--gl-fill);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  border:.5px solid var(--gl-edge);
  box-shadow:inset 0 .5px 0 var(--gl-spec), 0 1px 1px rgba(15,23,42,.05);
  border-radius:var(--gl-r-card);
  padding:10px 12px;min-height:var(--tap);
}
/* 卡片：统一玻璃 + 同心圆角 */
.ring-card{
  background:var(--gl-fill);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  border:.5px solid var(--gl-edge);
  box-shadow:inset 0 .5px 0 var(--gl-spec), 0 1px 1px rgba(15,23,42,.04);
  border-radius:var(--gl-r-card);padding:14px;
}
.ring-card .v{font-size:24px;font-weight:760;letter-spacing:-.02em}
.ring-card .k{font-size:12.5px;font-weight:600}
.ring-hero-cell{
  background:var(--gl-fill);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  border:.5px solid var(--gl-edge);
  box-shadow:inset 0 .5px 0 var(--gl-spec);
  border-radius:var(--gl-r-inner);padding:12px 10px;
}
.ring-hero-cell b{font-size:19px;font-weight:760;letter-spacing:-.02em}
.ring-devbar .ring-batt{background:var(--gl-fill-2);border:.5px solid var(--gl-edge)}
.ring-chip{border:.5px solid var(--gl-edge)}

/* ── 官方戒指 App 式大数字块：步数是主角，数字给到最大 ── */
.ring-big{display:flex;flex-direction:column;align-items:center;gap:2px;margin:var(--s-2) 0 0}
.ring-big .n{
  font-size:56px;font-weight:780;line-height:1;color:var(--text);
  font-variant-numeric:tabular-nums;letter-spacing:-.035em;
}
.ring-big .u{font-size:13px;color:var(--ink-500);font-weight:600}
.ring-goalchip{
  display:inline-flex;align-items:center;gap:6px;margin-top:10px;
  padding:6px 12px;border-radius:var(--r-full);
  background:var(--brand-50);color:var(--brand-text);
  font-size:12.5px;font-weight:680;border:.5px solid var(--gl-edge);
}
/* ── iOS 设置风格的列表（分组卡 + 分隔线 + 右侧值/箭头） ── */
.ring-group{
  margin:0 0 var(--s-3);border-radius:var(--gl-r-card);overflow:hidden;
  background:var(--gl-fill);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  border:.5px solid var(--gl-edge);
  box-shadow:inset 0 .5px 0 var(--gl-spec), 0 1px 1px rgba(15,23,42,.04);
}
.ring-group > .ring-row + .ring-row{border-top:.5px solid var(--ink-100)}
.ring-row{
  display:flex;align-items:center;gap:var(--s-3);width:100%;box-sizing:border-box;
  min-height:var(--tap);padding:11px 14px;background:transparent;border:0;
  font:inherit;color:inherit;text-align:left;
}
.ring-row.tap{cursor:pointer}
.ring-row.tap:active{background:var(--ink-100)}
.ring-row .grow{flex:1;min-width:0}
.ring-row .grow b{display:block;font-size:14.5px;font-weight:620;color:var(--text)}
.ring-row .grow span{display:block;font-size:12px;color:var(--ink-500);margin-top:1px;line-height:1.45}
.ring-row .val{font-size:13.5px;color:var(--ink-500);font-variant-numeric:tabular-nums;flex:0 0 auto}
.ring-row .ico{color:var(--ink-500)}
/* iOS 风格开关（真会滑动的那种）。
   ★ 不用 input::after 画滑块：input 是替换元素，Blink/WebKit 不渲染它的伪元素 ——
     写出来在 Chrome 上"看着像"，一到别的内核就变成没滑块的方块。所以用 label + i。 */
.ring-toggle{display:inline-flex;flex:0 0 auto;cursor:pointer;position:relative}
.ring-toggle input{position:absolute;opacity:0;width:0;height:0;margin:0}
.ring-toggle > i{
  display:block;width:52px;height:31px;border-radius:var(--r-full);
  background:var(--ink-300);transition:background .22s ease;position:relative;
  box-shadow:inset 0 1px 2px rgba(15,23,42,.14);
}
.ring-toggle > i::after{
  content:'';position:absolute;top:2px;left:2px;width:27px;height:27px;border-radius:50%;
  background:#fff;box-shadow:0 2px 5px rgba(15,23,42,.28);
  transition:transform .22s cubic-bezier(.32,.72,0,1);
}
.ring-toggle input:checked + i{background:var(--brand-500)}
.ring-toggle input:checked + i::after{transform:translateX(21px)}
.ring-toggle input:focus-visible + i{outline:2px solid var(--brand-500);outline-offset:2px}
/* 分段选择（单位设置那种） */
.ring-seg{display:inline-flex;gap:2px;padding:2px;border-radius:var(--r-full);background:var(--ink-100)}
.ring-seg button{
  border:0;background:transparent;color:var(--ink-600);font:inherit;font-size:12.5px;font-weight:640;
  min-height:30px;padding:0 12px;border-radius:var(--r-full);cursor:pointer;
}
.ring-seg button.on{background:var(--surface);color:var(--text);box-shadow:0 1px 2px rgba(15,23,42,.14)}
/* 首页大数字块（官方戒指 App 首页那个"303 步"）：环当背景，数字压在上面 */
.ring-hero-ring{position:relative;width:200px;height:200px;flex:0 0 auto}
.ring-hero-ring > svg{position:absolute;inset:0;width:200px;height:200px}
.ring-hero-c{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px}
.ring-hero-c .n{
  font-size:54px;font-weight:780;line-height:1;color:var(--text);
  font-variant-numeric:tabular-nums;letter-spacing:-.035em;
}
.ring-hero-c .u{font-size:13px;color:var(--ink-500);font-weight:620}
/* 可点的分区标题（右侧带箭头） */
.ring-sec-link{display:flex;align-items:center;justify-content:space-between;cursor:pointer;gap:var(--s-2)}
.ring-sec-link:active{opacity:.7}
/* 运动模式 chips 的容器 */
.ring-sec-wrap{display:flex;flex-wrap:wrap;gap:6px;margin:var(--s-1) 0 var(--s-2)}
/* 账号卡（我的页顶部） */
.ring-acc{
  display:flex;align-items:center;gap:var(--s-3);width:100%;box-sizing:border-box;
  padding:14px;margin-bottom:var(--s-3);border-radius:var(--gl-r-card);
  background:var(--gl-fill);border:.5px solid var(--gl-edge);font:inherit;color:inherit;
  text-align:left;cursor:pointer;
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  box-shadow:inset 0 .5px 0 var(--gl-spec), 0 1px 1px rgba(15,23,42,.04);
}
.ring-acc:active{background:var(--ink-100)}
.ring-acc .grow{flex:1;min-width:0}
.ring-acc .grow b{display:block;font-size:15px;font-weight:700;color:var(--text)}
.ring-acc .grow span{display:block;font-size:12px;color:var(--ink-500)}
.ring-acc-av{
  width:44px;height:44px;border-radius:50%;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;
  background:var(--brand-500);color:#fff;font-size:19px;font-weight:700;
}
/* 设备页头部 */
.ring-devhead{
  display:flex;align-items:center;gap:var(--s-3);padding:14px;margin-bottom:var(--s-3);
  border-radius:var(--gl-r-card);background:var(--gl-fill);
  border:.5px solid var(--gl-edge);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  box-shadow:inset 0 .5px 0 var(--gl-spec), 0 1px 1px rgba(15,23,42,.04);
}
.ring-devhead .grow{flex:1;min-width:0}
.ring-devhead .grow b{display:block;font-size:16.5px;font-weight:720;color:var(--text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ring-devhead .grow span{display:block;font-size:12px;color:var(--ink-500)}
/* 解绑的两步确认条 */
.ring-confirm{
  display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;
  padding:12px;border-radius:var(--gl-r-inner);margin-top:var(--s-2);
  background:var(--danger-soft);color:var(--danger-soft-text);
  font-size:12.5px;line-height:1.5;
}
.ring-confirm > span{flex:1 1 100%;font-weight:620}
.ring-confirm > button{flex:0 0 auto}
/* 问答 / 说明书卡片：标题就是问题，正文是答案 */
.ring-faq{margin-bottom:var(--s-2)}
.ring-faq .k{font-size:14px;font-weight:680;color:var(--text);line-height:1.45}
.ring-faq .ring-note{margin-top:4px}
/* 面板内的轻提示（不打断操作，6 秒自动消失） */
.ring-notice{
  margin:0 0 var(--s-2);padding:10px 12px;border-radius:var(--gl-r-inner);
  background:var(--gl-fill-2);border:.5px solid var(--gl-edge);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  color:var(--text);font-size:12.5px;
}
/* ══════════ 情绪频率（v1.66.0 · 融合 情绪功能） ══════════ */
.rc-radar-grid{fill:none;stroke:var(--ink-100);stroke-width:1}
.rc-radar-axis{stroke:var(--ink-100);stroke-width:1}
.rc-radar-area{fill:rgba(14,138,0,.16);stroke:var(--brand-500);stroke-width:2;stroke-linejoin:round}
.rc-radar-dot{fill:var(--brand-500);stroke:var(--surface);stroke-width:1.6}
.ring-emo-top{margin-top:var(--s-2)}
.ring-emo-top .v{font-size:26px}
/* 情绪色点：颜色本身就是语义（六态各一色），不随主题变 */
.ring-emo-dot{
  width:10px;height:10px;border-radius:50%;flex:0 0 auto;display:inline-block;
  box-shadow:0 0 0 3px rgba(0,0,0,.04);
}
.ring-emo-days{display:flex;flex-direction:column;gap:2px;margin-bottom:var(--s-2)}
.ring-emo-day{
  display:flex;align-items:center;gap:10px;min-height:44px;padding:6px 12px;
  border-radius:var(--gl-r-inner);background:var(--gl-fill);
  border:.5px solid var(--gl-edge);
}
.ring-emo-day .grow{flex:1;min-width:0}
.ring-emo-day .grow b{display:block;font-size:13.5px;font-weight:640;color:var(--text)}
.ring-emo-day .grow span{display:block;font-size:11.5px;color:var(--ink-500)}
.ring-emo-day > i{width:10px;height:44px;border-radius:4px;flex:0 0 auto}
/* 六态选择：按钮自带该态的颜色（选中时才上色，未选中保持中性，避免一片花） */
.ring-emo-seg{flex-wrap:wrap;width:100%;gap:4px}
.ring-emo-seg > button{--emo:#94A3B8}
.ring-emo-seg > button.on{background:var(--emo);color:#fff;box-shadow:0 1px 2px rgba(15,23,42,.18)}
.ring-emo-del{
  flex:0 0 auto;font-size:12px;padding:4px 10px;min-height:30px;
  color:var(--danger-text);border:.5px solid var(--gl-edge);border-radius:var(--r-full);
  background:transparent;cursor:pointer;
}
/* 原始帧的十六进制：等宽字体 + 允许换行（一帧几十字节，不换行会被截断得看不出东西） */
/* 客户端版本落后的警示条（v1.67.0）—— 用琥珀色而不是红色：
   它要用户"去做一件事"，不是"出错了"；红色会让人以为戒指坏了。 */
.ring-warn{
  margin:0 0 var(--s-3);padding:11px 13px;border-radius:var(--gl-r-inner);
  background:rgba(245,158,11,.13);border:.5px solid rgba(245,158,11,.42);
  border-left:3px solid #F59E0B;
}
.ring-warn .k{font-size:13.5px;font-weight:700;color:var(--text);margin-bottom:3px}
.ring-warn .ring-note{margin:0}

/* 手动填 MAC 的输入框（v1.67.0）—— 触摸目标 ≥44px，等宽感（MAC 是地址，不是句子） */
.ring-input{
  width:100%;box-sizing:border-box;min-height:44px;padding:0 12px;margin-bottom:var(--s-2);
  border:.5px solid var(--gl-edge);border-radius:var(--gl-r-inner);
  background:var(--gl-fill-2);color:var(--text);
  font:inherit;font-size:15px;letter-spacing:.05em;
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
}
.ring-input::placeholder{color:var(--ink-500);letter-spacing:0;font-size:13px}
.ring-input:focus{outline:none;border-color:var(--brand-500);box-shadow:0 0 0 3px var(--brand-100)}

/* v1.87.0：生产工作栏 —— 点开一行后展开的操作区。
   淡底色 + 下边框，和上面那一行"看得出是一组"；颜色全走既有变量，暗色模式自动跟随。 */
.ring-inv-act{
  padding:2px 12px 12px;border-bottom:.5px solid var(--line);
  background:var(--gl-fill-2);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
}
.ring-inv-act .ring-input{width:100%}

/* ══════════ 中医诊断知识库（v1.71.0）══════════
   只加这一块需要的样式，全部走既有变量（暗色模式由上面那套 Liquid Glass 变量统一接管，
   这里**不写死任何颜色**，否则暗色下会白底白字）。 */
.ring-chips{display:flex;flex-wrap:wrap;gap:6px;margin:var(--s-2) 0}
.ring-chip{
  min-height:34px;padding:0 12px;border-radius:999px;cursor:pointer;
  border:.5px solid var(--gl-edge);background:var(--gl-fill-2);color:var(--text);
  font:inherit;font-size:13px;
}
.ring-chip.on{background:var(--brand-50);color:var(--brand-text);border-color:var(--brand-500)}
.ring-dx-src{margin:var(--s-2) 0;padding:8px 12px;border-radius:var(--gl-r-inner);
  border:.5px solid var(--gl-edge);background:var(--gl-fill-2)}
.ring-dx-src>summary{cursor:pointer;font-size:13px;color:var(--ink-600);min-height:28px;line-height:28px}
.ring-dx-src .ring-note{margin:6px 0 0}
.ring-dx-card{padding:12px;margin:var(--s-2) 0;border-radius:var(--gl-r-inner);
  border:.5px solid var(--gl-edge);background:var(--gl-fill-2)}
.ring-dx-h{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}
.ring-dx-h b{font-size:17px}
.ring-dx-tag,.ring-dx-tag2{font-size:11px;padding:2px 8px;border-radius:999px;
  background:var(--brand-50);color:var(--brand-text)}
.ring-dx-tag2{background:rgba(120,120,140,.16);color:var(--ink-600)}
.ring-dx-f{margin:6px 0;font-size:13px;line-height:1.55;display:flex;gap:8px}
.ring-dx-f i{flex:0 0 84px;font-style:normal;color:var(--ink-500)}
.ring-dx-f span{flex:1}
.ring-dx-selbar{margin-top:var(--s-3)}
.ring-dx-selrow{display:flex;flex-direction:column;gap:6px}

.ring-mono{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:10.5px;line-height:1.5;color:var(--ink-600);
  word-break:break-all;white-space:normal;
}

.member{
  display:flex;align-items:center;gap:var(--s-3);
  padding:var(--s-3) 0;border-bottom:1px solid var(--ink-100);
}
.member .grow{flex:1;min-width:0}
.member .last{color:var(--ink-500);font-size:12px}

/* ═══════════════ ⑫ 动效偏好与可达性 ═══════════════ */
/* 尊重系统「减弱动态效果」：关闭所有动效，但保留状态变化 */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
}
/* iOS 聚焦字号保护（16px 基础已满足，此处为外部内容兜底） */
@media (max-width:700px){ input,textarea,select{font-size:16px} }
/* PWA 独立窗口 */
@media (display-mode:standalone){
  body{background:var(--surface)}
  .topbar{padding-top:calc(12px + env(safe-area-inset-top))}
}
/* 滚动惯性 + 防整页跟手 */
.messages,.list,.sheet-body{overscroll-behavior:contain;-webkit-overflow-scrolling:touch}

/* 桌面/平板：抽屉居中、卡片圆角（底栏不在这里改 —— 见下面说明） */
@media (min-width:700px){
  /* ★ v1.30.0：**删掉了**这里原来把底栏改成 `position:static;width:100%` 的那条规则。
     那是"贴边底栏"时代的做法，会让宽屏下的**悬浮胶囊**被压回满宽实心条
     （实测 left=13 / right=-11，看着就是没居中）。
     当年写那条是为了修"底栏缩成 179px"的老 bug —— 那个 bug 的成因是
     `margin:0 auto` 在列向 flex 容器里让子项按内容收缩；现在底栏是
     `position:absolute + left/right` 定位，宽度是确定值，不会再有那个问题。
     内容区底部留白也一起保留（底栏是悬浮的，宽屏同样会盖住内容）。 */
  .overlay{align-items:center}
  .sheet{border-radius:var(--r-2xl)}
  .group-create{padding-bottom:var(--s-6)}
}


/* 宽屏：把通讯窗做成一整台「手机」居中摆放
   右栏锁 9:16 竖屏手机比例（口语里的"手机 16:9"就是竖着看的那块屏）：
   高度吃满可视区，宽度由 aspect-ratio 反推，整体像桌面上一台手机；
   窗口不够高时跟着变窄，永远不出现"手机被拉变形"。
   v1.55.0：左侧工作台（独立智库面板）下线后，它自己居中。 */
@media (min-width:1180px){
  .app{padding:var(--s-5) var(--s-4);align-items:center}
  /* 通讯窗：定高 → 宽按 9/16 反推；圆角 + 描边 + 投影让它读起来是"一台手机" */
  .app-main{
    flex:0 0 auto;
    width:auto;height:min(820px,100%);aspect-ratio:9 / 16;
    max-width:min(520px,100%);
    overflow:hidden;
    border-radius:var(--r-2xl);
    border:1px solid var(--line);
    background:var(--surface);
    box-shadow:var(--sh-lg);
  }
}

/* ═══════════════ ⑬ 暗色模式 ═══════════════ */
@media (prefers-color-scheme: dark){
  :root{
    --bg:#0F1117;
    --bg-grad:linear-gradient(180deg,#12141C 0%,#0E1017 100%);
    --surface:#191C26;
    --surface-glass:rgba(25,28,38,.94);
    --text:#E9EBF2;
    --muted:#8A92A6;
    --line:#272C3A;
    --bubble-in:#222634;

    --ink-900:#EEF0F6; --ink-800:#DDE1EC; --ink-700:#C3C9D8;
    --ink-600:#A6AEC0; --ink-500:#8A92A6; --ink-400:#6C7488;
    --ink-300:#3C4254; --ink-200:#2C3140; --ink-100:#21252F; --ink-50:#1A1D26;

    --brand-50:#0C1F0A; --brand-100:#12300F; --brand-200:#17441A;
    --brand-text:#5BDD3A; --brand-line:#3FC51F;   /* 暗底上换成亮绿，否则深绿读不出来 */

    --danger-soft:#3A1E24; --danger-soft-text:#FF7C88;
    --danger-text:#FF6B7A;            /* 深底上的错误文字：6.18:1 */

    /* WhatsApp 暗色规格（官方深色主题取值） */
    --wa-header:#202C33;
    --wa-header-ink:#E9EDEF;
    --wa-chat-bg:#0B141A;
    --wa-bubble-in:#202C33;
    --wa-bubble-out:#005C4B;
    --wa-bubble-ink:#E9EDEF;
    --wa-meta:#8696A0;
    --wa-tick-read:#53BDEB;
    --wa-unread:#25D366;
    --wa-line:#222D34;
    --wa-panel:#111B21;
    --wa-input:#2A3942;
    --wa-icon:#8696A0;
    --wa-accent-text:#00A884;   /* 深底上换亮一档的绿 */
    /* 按钮：暗色下**描边/文字按钮**改用亮青（#008069 在深底读不出来，4.9→3.9）；
       填充按钮保持同一色 —— 白字对比只取决于按钮自身底色（4.89:1），与页面底色无关。 */
    --wa-btn-outline:#00A884;
    --wa-btn-off-bg:#2A3942; --wa-btn-off-ink:#8696A0;
    --wa-bar-bg:rgba(31,44,52,.80);
    --wa-bar-line:rgba(255,255,255,.08);
    /* 暗色下的选中胶囊：亮青的一层薄光（深底上不能再用暗青，会看不见） */
    --wa-active-pill:rgba(0,168,132,.16);
    /* 新版顶栏的暗色一套：黑底 + 浅字，标题用亮青（#00A884 on #111B21 = 5.77:1） */
    --wa-appbar:#111B21; --wa-appbar-ink:#E9EDEF; --wa-appbar-title:#00A884;
    --wa-chip-bg:#202C33; --wa-chip-ink:#E9EDEF;
    --wa-chip-on:#0A3D31; --wa-chip-on-ink:#6BDFC0;

    --sh-xs:0 1px 2px rgba(0,0,0,.35);
    --sh-sm:0 2px 10px -2px rgba(0,0,0,.45);
    --sh-md:0 10px 28px -10px rgba(0,0,0,.55);
    --sh-lg:0 24px 52px -20px rgba(0,0,0,.65);
  }
  .auth{
    background:
      radial-gradient(80% 55% at 12% 8%, rgba(34,196,9,.28), transparent 62%),
      radial-gradient(70% 55% at 88% 12%, rgba(0,214,143,.14), transparent 60%),
      radial-gradient(90% 65% at 50% 102%, rgba(255,107,129,.12), transparent 62%),
      linear-gradient(160deg,#151728 0%,#0E1017 100%);
  }
  .auth-card{
    background:rgba(25,28,38,.86);
    border-color:rgba(255,255,255,.07);
  }
  .item{border-color:rgba(255,255,255,.05);box-shadow:none}
  .msg{border-color:rgba(255,255,255,.05)}
  .msg.system{background:rgba(255,255,255,.07)}
  .banner{background:linear-gradient(135deg,#2E2716,#2A2313);border-color:#4A3D1C;color:#E8C77A}
  .banner .ghost{color:#E8C77A;background:rgba(255,255,255,.08)}
  .rec-bar{background:linear-gradient(135deg,#2E2716,#2A2313);border-color:#4A3D1C;color:#E8C77A}
  .rec-bar .ghost{color:#E8C77A;background:rgba(255,255,255,.08)}
  .rec-bar .rec-hint{color:#C9A75A}
  .call-overlay{background:radial-gradient(120% 95% at 50% 0%,#221D45 0%,#12101F 55%,#08070F 100%)}
}

/* ═══════════════ ⑭ WhatsApp 式布局（结构对齐） ═══════════════
   说明：对齐的是「信息架构与交互范式」（多 Tab / 会话行 / 输入栏 / 长按操作），
   配色与图标仍为 Uwhats 自有品牌资产，不使用第三方品牌视觉。 */

/* 顶栏与聊天头的圆形图标按钮 */
/* 顶栏（含聊天头）里的圆形图标按钮：WhatsApp 是"透明的白色图标"，不是白底药丸 */
.iconbtn{
  flex:0 0 var(--tap);
  width:var(--tap);height:var(--tap);
  display:grid;place-items:center;
  border-radius:50%;
  background:transparent;color:var(--wa-appbar-ink);
  font-size:19px;line-height:1;
}
.iconbtn:active{background:rgba(134,150,160,.18)}
.chat-head .iconbtn{background:transparent}
.chat-head .iconbtn:active{background:rgba(134,150,160,.18)}

/* 顶栏「更多」下拉菜单 */
/* ── 右上角「我的头像」+「新聊天」面板（v1.31.1） ──
   产品方要求：右上角从 ⋮ 三点改成**图片 + 功能**。所以：
     · 触发按钮是一枚**头像图片**（me-av）
     · 面板是**整屏**的（参考图就是这个形态），不再是原来那个右上角小下拉；
       内容顺序照参考图：我的头像（图片）→ 搜索 → 四个功能 → 最常联系
   ⚠️ 原 ⋮ 菜单里的项已融进「自己」页，这里不重复放账号设置/退出登录。 */
.me-btn{padding:0}
.me-av{
  width:30px;height:30px;border-radius:50%;overflow:hidden;
  display:grid;place-items:center;
  background:var(--wa-chip-bg);color:var(--wa-accent-text);
  font-size:13px;font-weight:600;
}
.me-av img{width:100%;height:100%;object-fit:cover;display:block}

.more-menu{
  position:absolute;inset:0;z-index:40;
  display:flex;flex-direction:column;
  background:var(--wa-panel);
  animation:fadeIn var(--t-fast) var(--e-out);
}
.mm-head{
  display:flex;align-items:center;gap:6px;
  padding:calc(6px + env(safe-area-inset-top)) var(--s-2) 6px;
  background:var(--wa-appbar);border-bottom:1px solid var(--wa-line);
}
.mm-title{flex:1;text-align:center;font-size:17px;font-weight:600;color:var(--wa-appbar-ink);margin-right:44px}
.mm-scroll{flex:1;overflow:auto;padding-bottom:var(--s-5)}
.mm-me{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-4) var(--s-4) var(--s-3)}
.mm-av{
  flex:0 0 56px;width:56px;height:56px;border-radius:50%;overflow:hidden;
  display:grid;place-items:center;
  background:var(--wa-chip-bg);color:var(--wa-accent-text);
  font-size:22px;font-weight:600;
}
.mm-av img{width:100%;height:100%;object-fit:cover;display:block}
.mm-me-main{flex:1;min-width:0}
.mm-me-name{font-size:18px;font-weight:600;color:var(--wa-bubble-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mm-me-handle{margin-top:2px;font-size:13px;color:var(--wa-meta)}
.searchbar.mm-search{padding:0 16px 8px}
.mm-acts{display:flex;flex-direction:column;padding:2px 0 6px}
.mm-act{
  display:flex;align-items:center;gap:var(--s-4);
  min-height:56px;padding:0 16px;
  color:var(--wa-bubble-ink);font-size:16px;font-weight:500;text-align:left;
  transition:background-color var(--t-fast) linear;
}
.mm-act:active{background:var(--wa-chip-bg)}
.mm-ico{
  flex:0 0 44px;width:44px;height:44px;display:grid;place-items:center;
  border-radius:50%;background:var(--wa-chip-bg);color:var(--wa-accent-text);
}
.mm-ico .ico{width:22px;height:22px}
.mm-sec{padding:16px 16px 6px;font-size:13.5px;font-weight:600;color:var(--wa-meta)}
.mm-list{display:flex;flex-direction:column}
.mm-empty{padding:10px 16px 14px;font-size:13.5px;color:var(--wa-meta)}

/* 底栏 Tab 图标：v1.28.0 起改为 HTML 里的 svg.ico（emoji 不跟随 currentColor） */

/* 聊天头部：返回 + 对方头像 + 名称/状态 + 操作（顶栏在聊天页隐藏，故此处承担状态栏留白） */
.chat-head{padding:calc(6px + env(safe-area-inset-top)) var(--s-2) 6px;gap:6px}
.chat-avatar{flex:0 0 auto}
.chat-avatar .av{
  flex:0 0 40px;width:40px;height:40px;
  border-radius:50%;font-size:16px;
}
.chat-info{flex:1;min-width:0;line-height:1.25}
.chat-info .chat-title{font-size:16px;font-weight:600;color:var(--wa-appbar-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-info .chat-sub{margin-left:0;font-size:12.5px;color:var(--wa-icon);opacity:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* 输入栏：输入框在左，附件/相机/麦克风↔发送 在右（WhatsApp 行为） */
.composer{gap:6px}
.composer-field{flex:1;min-width:0;position:relative;display:flex;align-items:center}
.composer-field input{width:100%;padding-left:48px}   /* 给框内的表情按钮留位 */
/* 框内的表情按钮：仍是 44×44 命中区（项目硬标准），只是视觉上贴在输入框左内侧 */
.composer-field .icon{
  position:absolute;left:2px;top:50%;transform:translateY(-50%);
  z-index:1;background:transparent;
}
.composer .icon.send{
  background:var(--wa-accent);color:#fff;
  box-shadow:none;font-size:17px;
}
.composer .icon.send:active{background:var(--wa-btn-press)}

/* 消息状态勾选（单勾=已发送 / 双勾=已读） */
.msg .state{
  font-size:11.5px;font-weight:700;opacity:.9;
  margin-left:5px;letter-spacing:-.06em;
}
.msg.mine .state.read{color:#7EE0FF}

/* 通话记录 */
.call-item .last.missed{color:var(--danger-text)}
.call-item .meta{flex-direction:row;align-items:center;gap:var(--s-2)}
.list .item .meta{flex-direction:row;align-items:center;gap:var(--s-2)}
.list .item .meta .icon{
  flex:0 0 var(--tap);width:var(--tap);height:var(--tap);min-width:var(--tap);
  display:grid;place-items:center;border-radius:var(--r-full);
  background:var(--brand-50);color:var(--brand-text);font-size:16px;
}

/* 设置页（分组列表） */
.settings-scroll{flex:1;overflow:auto;padding-bottom:92px}
.profile-row{
  display:flex;align-items:center;gap:var(--s-3);
  margin:var(--s-3) var(--s-3) var(--s-4);padding:var(--s-4);
  border-radius:var(--r-lg);background:var(--surface);
  box-shadow:var(--sh-sm);border:1px solid rgba(226,232,240,.75);
}
.profile-row .av{
  flex:0 0 58px;width:58px;height:58px;
  border-radius:18px;font-size:21px;
}
.profile-row .main{flex:1;min-width:0}
.profile-row .name{font-size:17px;font-weight:720}
.profile-row .last{color:var(--ink-500);font-size:13px;margin-top:2px}
.settings-group{
  margin:0 var(--s-3);
  border-radius:var(--r-lg);overflow:hidden;
  background:var(--surface);border:1px solid rgba(226,232,240,.75);
  box-shadow:var(--sh-xs);
}
.setting-row{
  display:flex;align-items:center;gap:var(--s-3);
  min-height:60px;padding:var(--s-3) var(--s-4);
  border-bottom:1px solid var(--ink-100);cursor:pointer;
  transition:background-color var(--t-fast) linear;
}
.setting-row:last-of-type{border-bottom:0}
.setting-row:active{background:var(--brand-50)}
.setting-row .si{flex:0 0 26px;font-size:19px;text-align:center}
.setting-row .st{flex:1;min-width:0}
.setting-row .st-title{font-size:15px;font-weight:620}
.setting-row .st-sub{margin-top:1px;font-size:12.5px;color:var(--ink-500)}
.setting-row .chev{color:var(--ink-300);font-size:20px}
#settings-body .btn-danger-soft{margin:var(--s-4) 0 0}

/* ═══════════════ ⑰ 关于 Uwhats / 升级提示（v1.17.0） ═══════════════ */

/* 「关于 Uwhats」那行的可升级标记（红底白字，亮暗模式都 ≥4.5:1） */
.setting-row.has-update .st-title::after{
  content:'可升级';margin-left:8px;padding:2px 7px;border-radius:var(--r-full);
  font-size:11px;font-weight:700;color:#fff;background:var(--badge-bg);
  vertical-align:1px;
}

.about-head{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-4)}
.about-logo{
  flex:0 0 52px;width:52px;height:52px;border-radius:16px;
  display:flex;align-items:center;justify-content:center;
  font-size:24px;font-weight:800;color:#fff;background:var(--brand-grad);
  box-shadow:var(--sh-brand);
}
.about-name{font-size:17px;font-weight:720}
.about-sub{color:var(--ink-500);font-size:13px;margin-top:2px}
.about-card{
  border-radius:var(--r-md);background:var(--ink-50);
  border:1px solid var(--line);padding:var(--s-1) var(--s-4);
}
.about-line{display:flex;justify-content:space-between;gap:var(--s-3);padding:9px 0;font-size:14px}
.about-line+.about-line{border-top:1px solid var(--ink-100)}
.about-line .k{color:var(--ink-500)}
.about-line .v{font-weight:680;font-variant-numeric:tabular-nums}
/* 只加粗不换色：品牌色变量在暗色模式下未重定义，换色会在暗底上失守 */
.about-line.hl .v{font-weight:750}
.about-tip{margin-top:var(--s-3);font-size:13.5px;color:var(--ink-500)}
.about-tip.ok{margin-top:var(--s-3);font-size:13.5px;font-weight:650;color:var(--ink-600)}
.about-update{
  margin-top:var(--s-4);padding:var(--s-4);border-radius:var(--r-md);
  background:var(--brand-50);border:1px solid var(--brand-200);
}
.about-update-title{font-size:15px;font-weight:720;color:var(--text)}
.about-update-sub{margin-top:6px;font-size:13px;color:var(--ink-600);line-height:1.55}
.about-foot{margin-top:var(--s-5);text-align:center;font-size:12px;color:var(--ink-500)}

/* 账号中心底部的「版本与更新」块（v1.31.0）：复用关于页那一套卡片/提示样式，
   只把外边距收一下 —— 它上面紧跟着「退出登录」，不要太松。 */
.acct-version{margin-bottom:var(--s-3)}
.acct-version .about-card{background:var(--wa-chip-bg);border-color:var(--wa-line)}
.acct-version .about-update{margin-top:var(--s-3)}
#sheet-body .btn-soft.block{margin-top:var(--s-3)}

/* 暗色模式补充 */
@media (prefers-color-scheme: dark){
  /* 头部图标按钮在暗色下仍保持"透明底 + 浅色图标"（WhatsApp 就是这么做的）；
     给它铺一块底色反而变成另一种风格。 */
  .iconbtn{background:transparent;color:var(--wa-appbar-ink);box-shadow:none}
  .iconbtn:active{background:rgba(134,150,160,.18)}
  .chat-head .iconbtn{background:transparent}
  .composer .icon.send{background:var(--wa-accent);color:#fff}
  .profile-row,.settings-group{border-color:rgba(255,255,255,.06)}
  .call-item .meta .icon{background:var(--brand-100)}
}

/* ═══════════════ ⑱ WhatsApp 新版结构（v1.29.0）═══════════════
   对齐要点：顶栏改中性（见 --wa-appbar 那一组）、底栏四项（聊天/动态/社群/通话）、
   聊天列表上方加过滤器、右下角 FAB；动态与社群是我们还没有的功能 —— 结构照摆、内容留空。 */

/* ── 聊天过滤器（全部 / 未读 / 收藏 / 群组）── */
.fchips{
  display:flex;gap:var(--s-2);
  padding:0 var(--s-3) 6px;
  background:var(--wa-panel);
  overflow-x:auto;-webkit-overflow-scrolling:touch;
}
.fchips::-webkit-scrollbar{display:none}
/* ★ WhatsApp 的过滤器 chip 视觉上只有 32px 高，但项目的触摸下限是硬标准 44px。
   做法：按钮本体 44px（命中区达标），**胶囊底画在 ::before 上、只有 32px 高**，
   再用 z-index:-1 把它压到文字下面 —— 观感与 WhatsApp 一致，同时不牺牲可点面积。 */
.fchip{
  position:relative;z-index:0;flex:0 0 auto;
  display:inline-flex;align-items:center;
  min-height:44px;padding:0 14px;
  background:transparent;color:var(--wa-chip-ink);
  font-size:13.5px;font-weight:600;
  transition:color var(--t-fast) linear;
}
.fchip::before{
  content:'';position:absolute;left:0;right:0;top:50%;height:32px;
  border-radius:var(--r-full);background:var(--wa-chip-bg);
  transform:translateY(-50%);z-index:-1;
  transition:background-color var(--t-fast) linear;
}
.fchip.on{color:var(--wa-chip-on-ink)}
.fchip.on::before{background:var(--wa-chip-on)}
.fchip:active::before{background:var(--ink-200)}

/* ── v1.57.0：右下角那颗 FAB 撤掉了 ────────────────────────────────
   产品方要求撤掉右下角的 AI 图标。原来这里是一整块「.fab + .fab.fab-ai」的样式
   （主操作圆钮 → 白圆钮套蓝徽章 → 鲸形图形），现在**全部删除**：
   入口搬到「自己」页的一行（`.setting-row`，id=`btn-ai-entry`），走本页既有的行样式。
   ★ 图形（鲸）没有消失：它现在是那一行的行图标（app.js 的 `DEEPSEEK_GLYPH`）；
     悬浮窗头部那枚徽章也还是同一套画法（见下面的 .ds-mark）。
   ★ 顺带把 `.fab{...}` 的媒体查询覆盖（`.fab{bottom:calc(...)}`）一起删掉 ——
     元素没了还留着定位规则，是"死代码"，以后改布局的人会以为还有一颗按钮。 */

/* ── DeepSeek 悬浮窗（v1.36.0 起）──────────────────────────────────────
   形态：手机上从底部升起（与抽屉一致），桌面居中成对话框。
   它承载的是"点一下**必定**有反馈"这件事，所以信息层级给足：
   状态（能不能通）→ 逐项实测 → 为什么嵌不了 → 两个动作。
   全部用现有 CSS 变量，深色模式自动跟随。 */
.ds{position:fixed;inset:0;z-index:60;display:flex;align-items:flex-end;justify-content:center}
.ds-backdrop{
  position:absolute;inset:0;background:rgba(15,23,42,.5);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  animation:fadeIn var(--t-base) var(--e-out);
}
.ds-card{
  position:relative;z-index:1;width:100%;max-width:520px;max-height:88vh;
  display:flex;flex-direction:column;
  background:var(--surface);color:var(--text);
  border-radius:var(--r-2xl) var(--r-2xl) 0 0;
  box-shadow:0 -24px 56px -24px rgba(15,23,42,.5);
  animation:sheetUp var(--t-slow) var(--e-out);overflow:hidden;
}
.ds-head{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-4) var(--s-4) var(--s-3);border-bottom:1px solid var(--line)}
.ds-mark{
  flex:0 0 auto;width:38px;height:38px;border-radius:11px;
  display:grid;place-items:center;
  background:linear-gradient(160deg,#5B7CFA 0%,#2E56E8 55%,#1B3BC4 100%);
  box-shadow:0 2px 10px -3px rgba(46,86,232,.45);
}
/* 与 FAB 上那枚徽章同一套画法（同一份 glyph），只是小一号。
   v1.55.0：22px → 26px（38px 徽章里放 26px）—— 同一个"图形悬空"的问题在这里也存在：
   图形本身留白多，塞小一号就会浮在徽章中央。 */
.ds-mark svg{width:26px;height:26px;display:block;fill:#fff}
.ds-head-main{flex:1;min-width:0}
.ds-title{font-size:16px;font-weight:700}
.ds-url{margin-top:2px;color:var(--muted);font-size:12.5px}
.ds-x{min-height:36px;padding:0 var(--s-3);font-size:13px}
.ds-body{padding:var(--s-4);overflow:auto;display:flex;flex-direction:column;gap:var(--s-4)}
.ds-status{display:flex;gap:var(--s-3);align-items:flex-start;padding:var(--s-3);border-radius:var(--r-md);background:var(--ink-50);border:1px solid var(--line)}
.ds-dot{flex:0 0 auto;width:10px;height:10px;margin-top:5px;border-radius:50%;background:var(--ink-400)}
.ds-checking .ds-dot{background:var(--ink-400);animation:dsPulse 1.2s ease-in-out infinite}
@keyframes dsPulse{0%,100%{opacity:.35}50%{opacity:1}}
.ds-ok .ds-dot{background:var(--success);box-shadow:0 0 0 3px rgba(0,196,140,.18)}
.ds-warn .ds-dot{background:var(--warning);box-shadow:0 0 0 3px rgba(255,170,0,.18)}
.ds-bad .ds-dot{background:var(--danger);box-shadow:0 0 0 3px rgba(255,71,87,.16)}
.ds-status-main{flex:1;min-width:0}
.ds-status-title{font-size:14.5px;font-weight:650;line-height:1.4}
.ds-status-sub{margin-top:3px;color:var(--muted);font-size:12.5px;line-height:1.5}
.ds-checks{display:flex;flex-direction:column;gap:var(--s-2)}
.ds-check{display:flex;align-items:baseline;gap:var(--s-2);font-size:13px}
.ds-check .k{flex:0 0 auto;min-width:104px;color:var(--muted)}
.ds-check .v{flex:1;min-width:0;font-weight:600;color:var(--text);word-break:break-word}
.ds-check .v.ok{color:var(--success)}
.ds-check .v.bad{color:var(--danger-text)}
.ds-embed{padding:var(--s-3);border-radius:var(--r-md);border:1px dashed var(--line)}
.ds-embed-title{font-size:13.5px;font-weight:650}
.ds-embed-text{margin-top:var(--s-2);color:var(--muted);font-size:12.5px;line-height:1.6;word-break:break-word}
.ds-embed-text code{background:var(--ink-100);padding:1px 5px;border-radius:6px;font-size:12px;color:var(--text)}
.ds-feedback{min-height:18px;color:var(--muted);font-size:12.5px;line-height:1.5}
.ds-actions{
  display:flex;gap:var(--s-2);
  padding:var(--s-3) var(--s-4) calc(var(--s-4) + env(safe-area-inset-bottom));
  border-top:1px solid var(--line);
}
.ds-actions .primary{flex:1;min-height:var(--tap)}
.ds-actions .ghost{flex:0 0 auto;min-height:var(--tap);padding:0 var(--s-4)}
/* 桌面：居中对话框（手机上从底部升起，与抽屉一致） */
@media (min-width:760px){
  .ds{align-items:center}
  .ds-card{border-radius:var(--r-2xl);max-height:84vh;box-shadow:var(--sh-lg)}
}

/* ── 动态 / 社群页的分节骨架 ── */
.wa-section{flex:1;overflow:auto;padding-bottom:96px}
.wa-section-title{
  padding:14px 16px 6px;
  color:var(--wa-icon);font-size:13px;font-weight:600;
}
.wa-row{
  display:flex;align-items:center;gap:var(--s-3);
  min-height:64px;padding:10px 16px;
  background:var(--wa-panel);
}
.wa-row-ico{
  flex:0 0 44px;width:44px;height:44px;
  display:grid;place-items:center;border-radius:50%;
  background:var(--wa-chip-bg);color:var(--wa-accent-text);
}
.wa-row-main{flex:1;min-width:0}
.wa-row-title{font-size:16px;font-weight:500;color:var(--wa-bubble-ink)}
.wa-row-sub{margin-top:2px;font-size:13.5px;color:var(--wa-meta)}
.wa-empty-note{
  margin:6px 16px 0;font-size:13.5px;line-height:1.6;color:var(--wa-meta);
}

/* ── 设置页改 WhatsApp 的扁平分组列表（原来是卡片 + 阴影）── */
.settings-scroll{background:var(--wa-panel)}
.profile-row{
  display:flex;align-items:center;gap:var(--s-3);
  margin:0;padding:16px;
  border-radius:0;background:var(--wa-panel);
  box-shadow:none;border:0;border-bottom:1px solid var(--wa-line);
}
.profile-row .av{flex:0 0 64px;width:64px;height:64px;border-radius:50%;font-size:22px}
.profile-row .name{font-size:19px;font-weight:500;color:var(--wa-bubble-ink)}
.profile-row .last{color:var(--wa-meta)}
.settings-group{
  margin:0;border-radius:0;overflow:visible;
  background:var(--wa-panel);border:0;box-shadow:none;
}
.setting-row{
  gap:var(--s-4);
  min-height:56px;padding:10px 16px;
  border-bottom:1px solid var(--wa-line);
}
.setting-row:active{background:var(--wa-line)}
.setting-row .si{flex:0 0 24px;color:var(--wa-icon)}
.setting-row .si .ico{width:22px;height:22px}
.setting-row .st-title{font-size:16px;font-weight:500;color:var(--wa-bubble-ink)}
.setting-row .st-sub{margin-top:2px;color:var(--wa-meta)}
.setting-row .chev{color:var(--wa-icon);font-size:18px}
/* 「待接入」的行：结构与 WhatsApp 一致（照样有右箭头），只是点了不做事。
   视觉上刻意不做区分 —— 产品方要求"先空着"，不是"标出来是空的"。 */
.setting-row.wa-todo,.wa-todo{cursor:default}
#settings-body .btn-danger-soft{margin:16px 16px 0}

/* ═══════════════ ⑮ UU 会员页（底部第 4 个 Tab） ═══════════════ */

.uu-wrap{
  flex:1;overflow:auto;
  display:flex;flex-direction:column;gap:var(--s-4);
  padding:var(--s-4) var(--s-3) 92px;
}

/* 算力节点（ZogToken 扩展）：内容区整块交给同源内嵌的控制台。
   顶部只留一条说明条 —— 讲清「这里的额度从哪来、能怎么用」，不喧宾夺主。 */
.zog-wrap{
  flex:1;min-height:0;
  display:flex;flex-direction:column;
  padding:0;gap:0;overflow:hidden;
  background:var(--surface);
}
.zog-bar{
  flex:0 0 auto;display:flex;align-items:center;gap:var(--s-2);
  padding:9px var(--s-3);
  background:var(--ink-50);border-bottom:1px solid var(--line);
  font-size:12px;color:var(--ink-600);
}
.zog-bar .txt{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.zog-bar-act{color:var(--brand-text);font-weight:650;white-space:nowrap;padding:4px 2px}
.zog-frame{flex:1;width:100%;min-height:0;border:0;background:#fff}
.zog-fallback{flex:1;padding:var(--s-4) var(--s-3);display:flex;flex-direction:column;gap:var(--s-3);justify-content:center}
/* 会员卡：品牌渐变 + 右上柔光，和顶栏同源语言 */
.uu-card{
  position:relative;overflow:hidden;
  padding:var(--s-6) var(--s-5) 28px;
  border-radius:var(--r-2xl);
  background:var(--brand-grad);color:#fff;
  box-shadow:var(--sh-lg);
}
.uu-card::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 100% at 100% 0%,rgba(255,255,255,.26),transparent 58%);
}
.uu-badge{
  position:relative;z-index:1;
  display:inline-flex;align-items:center;gap:6px;
  min-height:28px;padding:0 12px;
  border-radius:var(--r-full);
  background:rgba(255,255,255,.22);
  font-size:12px;font-weight:700;letter-spacing:.02em;
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
}
.uu-title{
  position:relative;z-index:1;
  margin:var(--s-3) 0 6px;
  font-size:26px;font-weight:800;letter-spacing:-.015em;
}
.uu-desc{
  position:relative;z-index:1;
  font-size:13.5px;line-height:1.55;opacity:.95;max-width:22em;
}
.uu-actions{display:flex;flex-direction:column;gap:var(--s-2);margin-top:var(--s-1)}
.uu-note{
  margin:0 var(--s-1);
  color:var(--ink-500);font-size:12.5px;line-height:1.65;
}
.uu-link{
  display:flex;align-items:center;gap:var(--s-2);
  margin:0 var(--s-1);padding:var(--s-3) var(--s-4);
  border-radius:var(--r-md);
  background:var(--surface);border:1px solid var(--line);
  color:var(--ink-500);font-size:12px;line-height:1.5;
  word-break:break-all;
}
@media (prefers-color-scheme: dark){
  .uu-link{border-color:rgba(255,255,255,.07)}
}

/* 会员窗口预览：把「会在应用内弹出小窗」这件事提前说清楚，降低跳出焦虑 */
.uu-window{
  border-radius:var(--r-lg);overflow:hidden;
  background:var(--surface);border:1px solid var(--line);
  box-shadow:var(--sh-sm);
}
.uu-window-bar{
  display:flex;align-items:center;gap:6px;
  min-height:38px;padding:0 var(--s-3);
  background:var(--ink-100);
  border-bottom:1px solid var(--line);
}
.uu-dot{width:9px;height:9px;border-radius:50%;background:var(--ink-300);flex:0 0 9px}
.uu-window-host{
  margin-left:auto;font-size:11.5px;font-weight:650;color:var(--ink-500);
  display:inline-flex;align-items:center;gap:4px;
}
.uu-window-body{padding:var(--s-4)}
.uu-window-title{font-size:15px;font-weight:700}
.uu-window-sub{margin-top:4px;font-size:12.5px;line-height:1.55;color:var(--ink-500)}
@media (prefers-color-scheme: dark){
  .uu-window{border-color:rgba(255,255,255,.07)}
  .uu-window-bar{background:var(--ink-50)}
}

/* 内嵌态：内容区交给原生内嵌页，H5 侧留白（保证与 App 连成一体、无缝隙） */
.uu-inline-host{padding:0;gap:0;overflow:hidden;background:var(--surface)}

/* 网页版内嵌态：经同源代理的 iframe 撑满内容区（v1.19.0）
   按需求不再显示"来源提示条"，内容区整块交给会员页。 */
.uu-frame-host{position:relative;padding:0;gap:0;overflow:hidden;background:var(--surface)}
.uu-frame{flex:1;width:100%;min-height:0;border:0;background:#fff}
.uu-loading{
  position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
  text-align:center;font-size:13px;color:var(--ink-500);
  padding:0 var(--s-4);
}
/* 卡住时的兜底块：标题 + 说明 + 两个出口（别只留一行灰字让人干等） */
.uu-stuck-title{font-size:15px;font-weight:700;color:var(--text);margin-bottom:6px}
.uu-loading .uu-note{margin:0 auto var(--s-3);max-width:19em}
.uu-loading .primary.block,.uu-loading .ghost.block{
  width:min(260px,100%);margin:0 auto var(--s-2);min-height:var(--tap);
  display:flex;align-items:center;justify-content:center;
}
.uu-fallback{padding:var(--s-4) var(--s-3) 92px}

/* ═══════════════ ⑯ 备注名 / 邀请好友 / 时间修改（v1.14.0） ═══════════════ */

/* 注：消息时间「已改」标记与后台审计记录均已按要求移除（v1.16.0）。
   改时间现在直接改写 messages.created_at，不保留原始时间、不写审计行，
   因此这条消息在数据库、接口与后台里都只是一条普通消息，没有任何"被改过"的痕迹。 */

/* 联系人资料头部 */
.contact-head{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-2)}
.contact-head .av{flex:0 0 56px;width:56px;height:56px;border-radius:16px;font-size:20px}
.contact-head .main{flex:1;min-width:0}
.contact-head .name{font-size:17px;font-weight:720}
.contact-head .last{color:var(--ink-500);font-size:13px;margin-top:2px}

/* 我的邀请码卡片 */
.invite-card{
  position:relative;overflow:hidden;
  padding:var(--s-5);border-radius:var(--r-lg);
  background:var(--brand-grad);color:#fff;text-align:center;
  box-shadow:var(--sh-brand);
}
.invite-card::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 100% at 100% 0%,rgba(255,255,255,.26),transparent 58%);
}
.invite-label{position:relative;z-index:1;font-size:12px;opacity:.92;font-weight:600}
.invite-code{
  position:relative;z-index:1;
  margin:6px 0 4px;font-size:27px;font-weight:800;letter-spacing:.06em;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  word-break:break-all;
}
.invite-sub{position:relative;z-index:1;font-size:12px;opacity:.92}

/* 时间快捷选择 */
.time-quick{display:flex;gap:var(--s-2);flex-wrap:wrap;margin:var(--s-2) 0}
.time-quick .chip{min-height:38px}
.sheet-body input[type="datetime-local"]{min-height:46px;font-variant-numeric:tabular-nums}

/* ═══════════════ ⑯ v1.30.0：悬浮底栏 / 「自己」页 / 相机 / 二维码 ═══════════════
   底栏从"贴边的整条栏"改成 **悬浮胶囊 + 半透明毛玻璃**（WhatsApp 新版的形态）：
   左右留边、圆角、浮在内容之上。所以下面所有"给底栏让位"的底部留白要一起调。 */
.tabbar{
  /* ★ 用 absolute 而不是 fixed：宽屏下布局是「左工作台 + 右侧手机窗」，
     fixed 会以**浏览器窗口**为准居中 —— 实测左 1px / 右 40px，明显偏。
     absolute 贴 .app-main（手机窗）就天然对齐，手机上两者视觉等价。
     ★ v1.31.0：参考图里这条底栏**不是贴边的整条**，而是左右各留 8%、整条居中
     的一条胶囊（量参考图：五个 Tab 的文字中心在屏宽 16.4%/32.1%/48.0%/63.8%/79.8%，
     反推条体 = 8%~92%，即 84% 宽）。所以左右内缩改成百分比，跟屏宽一起缩放。 */
  position:absolute;left:8%;right:8%;bottom:calc(10px + env(safe-area-inset-bottom));
  z-index:20;
  display:flex;
  border-radius:var(--r-full);          /* 完整胶囊（62px 高的条，圆角取满） */
  background:var(--wa-bar-bg);                 /* 半透明 */
  -webkit-backdrop-filter:blur(22px) saturate(200%);
  backdrop-filter:blur(22px) saturate(200%);
  border:1px solid var(--wa-bar-line);
  /* 内高光：玻璃在顶部有一道极淡的亮边，这是"这是玻璃、不是白纸"的关键细节。
     放在 box-shadow 里（inset）而不是另加伪元素 —— 底栏的 ::after 要留给水波纹体系。 */
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55),
             0 10px 30px -12px rgba(0,0,0,.28),0 2px 8px rgba(0,0,0,.06);
  overflow:hidden;                            /* 水波纹不溢出圆角 */
}
/* 五项挤在一些：左右内边距收一点，标签 11.5px（仍保证触摸目标 ≥44 高） */
.tabbtn{min-height:60px;padding:6px 0;font-size:11.5px}
.tabbtn .ico{width:23px;height:23px}
/* ★ 2026-10-22：按下时图标轻微下沉（0.90）。
   为什么只动图标、不动整格：格子整体缩放会让 11.5px 的标签发虚（子像素渲染），
   而图标是矢量、缩一点只是更"实"。这一下是"按得动"的物理暗示 ——
   只有颜色变化时，手指会怀疑"到底点到了没有"。 */
.tabbtn .ico{transition:transform 150ms var(--e-out)}
.tabbtn:active .ico{transform:scale(.90)}
@media (prefers-reduced-motion:reduce){ .tabbtn .ico{transition:none} .tabbtn:active .ico{transform:none} }

/* ★★★ 2026-10-22：**毛玻璃不可用时的降级**。
   半透明底栏只有配上 backdrop-filter 才成立 —— 模糊把下面的内容压成一片雾，
   图层才"浮"得起来。若环境不支持（老 WebView / 关掉了 GPU 合成 / 某些省电模式），
   同一个 .66 的白色就会让列表的头像和文字**清清楚楚地穿过底栏**，比不透明还难看。
   这条规则把那种环境自动换成接近不透明的底，代价是没有玻璃感，收益是"永远不难看"。
   ⚠️ 判据要写 `-webkit-` 分支：iOS Safari 长期只有前缀版本。 */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .tabbar{background:rgba(255,255,255,.94)}
  [data-theme="dark"] .tabbar{background:rgba(31,44,52,.96)}
}

/* ══════════ v1.45.0：左上角 ⋯ 菜单 / 多选（对齐 WhatsApp） ══════════ */

/* 左上角 ⋯ 的下拉。放在顶栏下方左侧 —— 与 WhatsApp 首页的位置一致。
   ⚠️ 它挂在 .app-main 上（不是 .topbar 里），见 index.html 的注释。 */
.top-menu{
  position:absolute;top:calc(8px + 56px);left:10px;z-index:32;
  min-width:196px;padding:6px;
  background:var(--surface);color:var(--text);
  border:1px solid var(--wa-line);border-radius:14px;
  box-shadow:0 18px 40px -18px rgba(15,23,42,.42),0 2px 8px rgba(15,23,42,.06);
  animation:tmIn 140ms ease-out;
}
@keyframes tmIn{from{opacity:0;transform:translateY(-6px) scale(.98)}to{opacity:1;transform:none}}
.top-menu button{
  display:block;width:100%;min-height:44px;padding:0 14px;
  text-align:left;font-size:14.5px;
  background:transparent;border:0;border-radius:10px;color:inherit;cursor:pointer;
}
.top-menu button:hover,.top-menu button:focus-visible{background:var(--ink-100)}

/* ══════════ v1.47.0：短信（移动物联） ══════════ */
/* 注册页那个「开通短信助手」的勾选：块级、可点区域够大（手机上不会点不中） */
.reg-check{display:flex;align-items:flex-start;gap:8px;margin:2px 0 6px;font-size:13px;color:var(--ink-600);cursor:pointer;line-height:1.5}
.reg-check input{margin-top:2px;flex:none;width:16px;height:16px}
.reg-check em{font-style:normal;color:var(--ink-500);font-size:12px}

.m2m-actions{display:flex;gap:8px;flex-wrap:wrap;padding:0 12px 10px}
.m2m-actions .ghost{min-height:38px;padding:0 14px;font-size:13px;border-radius:var(--r-full)}
/* 通道提示：没配通道时必须能看见（否则用户以为"卡插上就有短信"） */
.m2m-note{margin:0 12px 10px;padding:10px 12px;border-radius:var(--r-sm);font-size:12.5px;line-height:1.6;
  background:var(--ink-100);color:var(--ink-600)}
.m2m-cards{display:flex;flex-direction:column;gap:8px;padding:0 12px 8px}
.m2m-card{border:1px solid var(--wa-line);border-radius:var(--r-sm);padding:10px 12px;background:var(--wa-panel)}
.m2m-card .top{display:flex;align-items:center;gap:8px;justify-content:space-between}
.m2m-card .name{font-weight:600;font-size:14.5px;color:var(--wa-bubble-ink)}
.m2m-card .num{font-size:12.5px;color:var(--ink-500);margin-top:2px}
.m2m-card .meta{display:flex;gap:12px;font-size:12px;color:var(--ink-500);margin-top:6px;flex-wrap:wrap}
.m2m-card .mini{min-height:32px;padding:0 12px;font-size:12.5px;border-radius:var(--r-full)}
.sms-item .sms-body{white-space:pre-wrap;word-break:break-word;font-size:14px;color:var(--wa-bubble-ink);margin-top:2px;font-weight:400}
.sms-item.unread .sms-body{font-weight:500}
/* 验证码：高亮 + 一键复制 —— 这才是"短信助手"真正的用处 */
.sms-code{display:inline-flex;align-items:center;gap:8px;margin-top:8px;padding:5px 10px;border-radius:var(--r-full);
  background:var(--brand-50);color:var(--brand-text);font-size:12.5px;border:0;cursor:pointer}
.sms-code b{font-size:15px;letter-spacing:1.5px}

/* ── 业务（v1.48.0）：跨境业务的询盘/订单回流 ── */
.biz-systems{display:flex;flex-direction:column;gap:8px;padding:0 12px 10px}
.biz-sys{border:1px solid var(--wa-line);border-radius:var(--r-sm);padding:10px 12px;background:var(--wa-panel);
  display:flex;align-items:center;gap:10px;justify-content:space-between}
.biz-sys .who{min-width:0}
.biz-sys .name{font-weight:600;font-size:14.5px;color:var(--wa-bubble-ink)}
.biz-sys .hint2{font-size:12px;color:var(--ink-500);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.biz-sys .go{min-height:36px;padding:0 14px;font-size:13px;border-radius:var(--r-full);flex:0 0 auto}
.biz-item .biz-head{display:flex;align-items:center;gap:8px;justify-content:space-between}
.biz-item .biz-kind{font-size:11.5px;padding:2px 8px;border-radius:var(--r-full);background:var(--ink-100);color:var(--ink-600);flex:0 0 auto}
.biz-item .biz-title{font-weight:600;font-size:14.5px;color:var(--wa-bubble-ink);margin-top:4px;word-break:break-word}
.biz-item .biz-sum{font-size:12.5px;color:var(--ink-500);margin-top:3px;white-space:pre-wrap;word-break:break-word;font-weight:400}
.biz-item .biz-meta{display:flex;gap:10px;flex-wrap:wrap;align-items:center;font-size:12px;color:var(--ink-500);margin-top:7px}
.biz-item .biz-amount{font-weight:700;color:var(--brand-text);font-size:14px}
.biz-item.unread{background:var(--brand-50)}
.biz-item.unread .biz-title::after{content:'';display:inline-block;width:7px;height:7px;border-radius:50%;
  background:var(--brand-500);margin-left:7px;vertical-align:middle}
.biz-item .biz-open{min-height:32px;padding:0 12px;font-size:12.5px;border-radius:var(--r-full);flex:0 0 auto}
.biz-empty{padding:22px 14px;text-align:center;color:var(--ink-500);font-size:13px;line-height:1.7}

/* 多选时的勾选圈（WhatsApp 是圆形空心 → 选中变实心带白勾） */
.item .selbox{
  width:22px;height:22px;flex:0 0 auto;box-sizing:border-box;
  border:2px solid var(--ink-300);border-radius:50%;background:transparent;
  transition:background-color var(--t-fast) linear,border-color var(--t-fast) linear;
}
.item.sel .selbox{
  border-color:var(--brand-500);background:var(--brand-500);
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9.55 16.2 5.4 12.05l-1.5 1.5 5.65 5.65L20.1 8.6 18.6 7.1z' fill='white'/></svg>");
  background-repeat:no-repeat;background-position:center;background-size:13px 13px;
}
.item.sel{background:var(--ink-100)}

/* 多选操作条：贴在底栏胶囊**之上**（底栏是悬浮的，所以这里要按它的高度让位） */
.sel-bar{
  position:absolute;left:8%;right:8%;z-index:21;
  bottom:calc(10px + 60px + 16px + env(safe-area-inset-bottom));
  display:flex;align-items:center;gap:var(--s-3);
  padding:9px 12px;
  border-radius:var(--r-full);
  background:var(--wa-bar-bg);
  -webkit-backdrop-filter:blur(20px) saturate(180%);
  backdrop-filter:blur(20px) saturate(180%);
  border:1px solid var(--wa-bar-line);
  box-shadow:0 10px 30px -12px rgba(0,0,0,.28),0 2px 8px rgba(0,0,0,.06);
}
.sel-count{flex:1;min-width:0;font-size:13.5px;color:var(--muted);padding-left:6px}
.sel-bar .ghost,.sel-bar .primary{min-height:38px;padding:0 14px;font-size:13.5px;border-radius:var(--r-full)}
/* 内容区底部留白：底栏高 60 + 底部偏移 10 + 呼吸 14 */
.list{padding-bottom:96px}
/* ⚠️ 用 :not(.uu-frame-host)：内嵌态要把整块内容区交给会员页，
   多出 96px 底部留白会让 iframe 比内容区矮一截（ui-check 会红）。 */
.wa-section,.settings-scroll,.zog-wrap{padding-bottom:96px}
.uu-wrap:not(.uu-frame-host){padding-bottom:96px}
/* v1.30.0 起底栏是 absolute 贴在 .app-main 里，宽屏不用再单独覆盖 */

/* ── 「自己」页 ── */
.you-profile{
  display:flex;align-items:center;gap:var(--s-4);
  padding:var(--s-5) var(--s-4) var(--s-4);
  background:var(--wa-panel);
  border-bottom:1px solid var(--wa-line);
  cursor:pointer;
}
.you-av{position:relative;flex:0 0 auto}
.you-av .av{width:64px;height:64px;font-size:24px}
/* 头像右下角的相机角标：点它就是"拍照换头像" */
.you-cam{
  position:absolute;right:-4px;bottom:-4px;
  width:28px;height:28px;display:grid;place-items:center;
  border-radius:50%;
  background:var(--wa-fab);color:#fff;
  box-shadow:0 2px 6px rgba(0,0,0,.25);
}
.you-cam .ico{width:16px;height:16px;stroke-width:2}
.you-main{flex:1;min-width:0}
.you-name{font-size:20px;font-weight:600;color:var(--wa-bubble-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.you-about{margin-top:2px;font-size:13.5px;color:var(--wa-meta);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.you-handle{margin-top:2px;font-size:12px;color:var(--wa-icon)}
/* v1.114.0：删掉了 .you-edit（资料卡里那颗重复的「编辑」按钮）——
   编辑入口由顶栏 #btn-top-edit 承担，资料卡整体仍可点。删 DOM 就同步删样式，不留死 CSS。 */
/* 「自己」页的分组行沿用 .setting-row；补一个"整段待接入"的样式（帮助页里用） */
.wa-todo-row{padding:var(--s-3) var(--s-4);opacity:.75}
.wa-todo-row .st-title{font-size:14.5px;font-weight:600;color:var(--text)}
.wa-todo-row .st-sub{margin-top:2px;font-size:12.5px;color:var(--wa-meta)}
.av-edit-row{flex-wrap:wrap}

/* ══════════════════════════════════════════════════════════════════════
   相机浮层（v1.50.0 按 WhatsApp 相机规格重做）
   ──────────────────────────────────────────────────────────────────────
   对齐 WhatsApp 的六条（每条都在 tools/camera-ui-probe.cjs 里有量测）：
     ① **全屏取景**：预览 position:absolute;inset:0 + object-fit:cover，
        工具条浮在它上面。老版把预览关在一个 flex 区里，底部留出 172px 的
        #0B141A 实底色带 —— 取景只占屏 79.6%，一眼就不像相机。
     ② 顶部 ✕ 左 / 用途居中 / 闪光灯右；底部只有「相册缩略图 · 快门 · 翻转」三件。
     ③ 快门**绝对居中**（左文字右图标时 space-between 会让它偏；实测老版偏右 3px，
        且偏移 = (左控件宽 − 右控件宽)/2，换个更长的文案就会更大）。
     ④ 上下各一条「黑→透明」渐变遮罩：白图标压在实时画面上也读得清，且不出现实底色块。
     ⑤ 前置预览**镜像**（跟 WhatsApp 一致：看到的是照镜子，不是左右反的）。
     ⑥ 全部可点控件 ≥44px（WCAG 2.5.5 / iOS HIG）+ safe-area 内缩（刘海、小白条）。
   刻意**不做**的（宁可少一个控件，也不要一个点下去没反应的按钮）：
     · 视频页签 —— 我们只能拍照，摆一个切不过去的页签是假 UI；
     · 1×/2× 变焦条 —— 多数桌面设备与 headless 都验不了（getCapabilities().zoom 为空），
       没法证明它在真机上可用，所以不做；闪光灯只在设备真的报支持 torch 时才出现。
   ══════════════════════════════════════════════════════════════════════ */
.cam-overlay{
  position:fixed;inset:0;z-index:90;overflow:hidden;
  background:#0B141A;                               /* WhatsApp 暗色相机底 */
  animation:fadeIn var(--t-base) var(--e-out);
}
.cam-video{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;background:#0B141A;
}
.cam-video.cam-mirror{transform:scaleX(-1)}         /* 前置：镜像 */

/* 上下渐变遮罩。两条都**不是实底色块** —— 实底会把"全屏取景"切成三段。
   顶部这条给到 .66，是为了让白字在**最亮的白色画面**上也有 4.5:1（算过的值见报告）。 */
.cam-scrim{position:absolute;left:0;right:0;pointer-events:none;z-index:1}
.cam-scrim-top{
  top:0;height:calc(112px + env(safe-area-inset-top));
  background:linear-gradient(180deg,rgba(0,0,0,.66) 0%,rgba(0,0,0,.42) 58%,rgba(0,0,0,0) 100%);
}
.cam-scrim-bottom{
  bottom:0;height:248px;
  background:linear-gradient(0deg,rgba(0,0,0,.72) 0%,rgba(0,0,0,.46) 52%,rgba(0,0,0,0) 100%);
}

/* ── 扫码取景框（只有扫码模式显示）──
   纯视觉引导：一个方形取景区 + 四角 + 一条上下扫的线 + 一句提示。
   ★ pointer-events:none —— 它是"画在画面上的",不能把触摸吃掉（否则点哪都不对焦/关不掉）。 */
.cam-scan{
  position:absolute;inset:0;z-index:2;pointer-events:none;
  display:grid;place-items:center;align-content:center;gap:var(--s-4);
  padding:0 var(--s-6);
}
.cam-scan-box{
  position:relative;
  width:min(66vw,260px);aspect-ratio:1/1;
  border-radius:var(--r-lg);
  background:rgba(255,255,255,.06);
  box-shadow:0 0 0 100vmax rgba(0,0,0,.28);   /* 框外压暗，把注意力收进框里 */
}
.cam-scan-c{position:absolute;width:26px;height:26px;border:3px solid #FFFFFF;border-radius:4px}
.cam-scan-c:nth-child(1){left:-1px;top:-1px;border-right:0;border-bottom:0;border-top-left-radius:var(--r-md)}
.cam-scan-c:nth-child(2){right:-1px;top:-1px;border-left:0;border-bottom:0;border-top-right-radius:var(--r-md)}
.cam-scan-c:nth-child(3){left:-1px;bottom:-1px;border-right:0;border-top:0;border-bottom-left-radius:var(--r-md)}
.cam-scan-c:nth-child(4){right:-1px;bottom:-1px;border-left:0;border-top:0;border-bottom-right-radius:var(--r-md)}
.cam-scan-line{
  position:absolute;left:8%;right:8%;height:2px;top:10%;
  background:linear-gradient(90deg,rgba(37,211,102,0),#25D366,rgba(37,211,102,0));
  box-shadow:0 0 10px rgba(37,211,102,.75);
  animation:scanSweep 2.1s var(--e-out) infinite;
}
.cam-scan-tip{
  font-size:14px;font-weight:600;color:#FFFFFF;
  text-shadow:0 1px 4px rgba(0,0,0,.7);text-align:center;
}
@keyframes scanSweep{0%{top:10%}50%{top:88%}100%{top:10%}}
@media (prefers-reduced-motion:reduce){.cam-scan-line{animation:none;top:50%}}

/* ── 顶部工具条 ── */
.cam-top{
  position:absolute;left:0;right:0;top:0;z-index:2;
  display:flex;align-items:center;gap:var(--s-2);
  min-height:calc(56px + env(safe-area-inset-top));
  padding:calc(env(safe-area-inset-top) + var(--s-2)) var(--s-3) var(--s-2);
}
/* 相机里的圆形图标钮：44px 触摸目标 + 半透明底 —— 在实时画面上"看得见边界" */
.cam-ic{
  flex:0 0 var(--tap);width:var(--tap);height:var(--tap);
  display:grid;place-items:center;border-radius:50%;
  background:rgba(255,255,255,.18);color:#FFFFFF;
  transition:background var(--t-fast) linear,transform var(--t-fast) var(--e-out);
}
.cam-ic .ico{width:24px;height:24px;stroke-width:2}
.cam-ic:active{background:rgba(255,255,255,.34);transform:scale(.92)}
.cam-ic[aria-pressed="true"]{background:#FFFFFF;color:#0B141A}   /* 手电开着：反白，一眼看出状态 */
/* 顶栏那两颗不加底：WhatsApp 顶部是纯白图标压在渐变遮罩上，加个圆底显笨 */
.cam-top .cam-ic{background:transparent}
.cam-top .cam-ic:active{background:rgba(255,255,255,.20)}
.cam-top .cam-ic[aria-pressed="true"]{background:rgba(255,255,255,.92);color:#0B141A}
.cam-title{
  flex:1;min-width:0;text-align:center;
  font-size:14px;font-weight:600;letter-spacing:.01em;
  color:#FFFFFF;text-shadow:0 1px 3px rgba(0,0,0,.55);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

/* ── 底部纵向栈：提示 → 主控行 → 授权门/免授权出口 ──
   为什么做成一个栈：授权卡与"用系统相机"必须能**同时**出现且互不遮盖。
   老版一个是绝对居中的卡、一个是固定底栏，窄屏上会叠在一起。 */
.cam-controls{
  position:absolute;left:0;right:0;bottom:0;z-index:2;
  display:flex;flex-direction:column;gap:var(--s-3);
  padding:var(--s-3) var(--s-4) calc(env(safe-area-inset-bottom) + var(--s-4));
}
.cam-hint{
  text-align:center;color:#FFFFFF;font-size:13px;line-height:1.5;
  padding:0 var(--s-2);text-shadow:0 1px 4px rgba(0,0,0,.7);
}
.cam-hint:empty{display:none}                       /* 没话说时不留空档 */

.cam-bottom{position:relative;min-height:72px;display:flex;align-items:center;justify-content:space-between}

/* 相册缩略图（WhatsApp 左下那颗圆角方片）：把"从相册选"从一行文字按钮收成一个图标，
   底部就只剩三件东西 —— 这是"像相机"而不是"像表单"的关键一步。 */
.cam-thumb{
  flex:0 0 var(--tap);width:var(--tap);height:var(--tap);
  display:grid;place-items:center;border-radius:var(--r-sm);
  background:rgba(255,255,255,.18);color:#FFFFFF;
  box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.34);
}
.cam-thumb .ico{width:21px;height:21px}
.cam-thumb:active{background:rgba(255,255,255,.34)}

/* ★ 快门：**绝对居中**。用 space-between 的话，快门中心 = 屏幕中心 + (左控件宽 − 右控件宽)/2
   —— 老版左边是"取消"文字(60px)、右边是图标(54px)，于是快门偏右 3px；
   文案一改偏移就跟着变。绝对定位之后与两侧宽度彻底无关。 */
.shutter{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:72px;height:72px;border-radius:50%;
  background:transparent;border:4px solid #FFFFFF;
  box-shadow:0 0 0 1px rgba(0,0,0,.22),0 2px 10px rgba(0,0,0,.32);
  transition:transform var(--t-fast) var(--e-out);
}
/* 内盘：white ring → 4px 间隙 → 实心白盘（WhatsApp 那颗快门的构造）。
   按下时内盘缩到 .70 —— 这一下"缩"就是"我拍到了"的第一反馈。 */
.shutter::before{
  content:'';position:absolute;inset:5px;border-radius:50%;
  background:#FFFFFF;transform:scale(.86);
  transition:transform 140ms var(--e-out),background 140ms linear;
}
.shutter:active::before{transform:scale(.70);background:#E9EDEF}
.shutter:active{transform:translate(-50%,-50%) scale(.96)}

/* ── 授权门（产品方要求"先提示授权"）/ 免授权出口 ── */
.cam-sheet{display:flex;flex-direction:column;gap:var(--s-2)}
.cam-gate{
  display:flex;flex-direction:column;align-items:center;gap:10px;
  padding:var(--s-5) var(--s-4) var(--s-4);
  border-radius:var(--r-lg);
  background:rgba(31,44,52,.94);                    /* WhatsApp 暗色面板 #1F2C34 */
  border:1px solid rgba(255,255,255,.10);
  box-shadow:0 18px 40px -18px rgba(0,0,0,.75);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  animation:sheetUp var(--t-base) var(--e-out);
}
.cam-gate-ring{
  width:64px;height:64px;display:grid;place-items:center;border-radius:50%;
  background:rgba(0,168,132,.18);color:#25D366;
}
.cam-gate-ring .ico{width:30px;height:30px}
.cam-gate-title{font-size:17px;font-weight:700;color:#E9EDEF}
/* 正文 #C7D0D6：折到最亮白画面后对卡片底仍有 ≥7.5:1（AA 只要 4.5:1）——
   这么留余量是因为遮罩背后是**实时画面**，亮度不可控。 */
.cam-gate-sub{font-size:13.5px;line-height:1.7;color:#C7D0D6;text-align:center}
.cam-gate-btn{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:var(--wa-btn-h);padding:0 var(--s-6);margin-top:2px;
  border-radius:var(--r-full);
  background:#00A884;color:#0B141A;                 /* 6.14:1 ✅（算过的，见报告） */
  font-size:15px;font-weight:700;
  transition:background var(--t-fast) linear;
}
.cam-gate-btn:active{background:#017561}
.cam-fallback{display:flex}
.cam-pill{
  flex:1;display:inline-flex;align-items:center;justify-content:center;gap:var(--s-2);
  min-height:48px;padding:0 var(--s-5);border-radius:var(--r-full);
  background:#00A884;color:#0B141A;font-weight:700;font-size:15px;
  transition:background var(--t-fast) linear;
}
.cam-pill:active{background:#017561}

/* ── 点按对焦环（WhatsApp/系统相机的手感：点哪对焦哪，先给看得见的确认）── */
.cam-focus{position:absolute;z-index:3;width:0;height:0;pointer-events:none}
.cam-focus::before{
  content:'';position:absolute;left:-34px;top:-34px;width:68px;height:68px;
  border-radius:50%;border:1.5px solid rgba(255,255,255,.92);
  box-shadow:0 0 0 1px rgba(0,0,0,.28);opacity:0;
}
.cam-focus.on::before{animation:focusPulse 700ms var(--e-out) forwards}
@keyframes focusPulse{
  0%{transform:scale(1.3);opacity:0}
  22%{transform:scale(1);opacity:1}
  62%{transform:scale(1);opacity:1}
  100%{transform:scale(.9);opacity:0}
}
/* ── 拍摄白闪（快门按下的一瞬间全屏白闪一下，和系统相机一致）── */
.cam-flashfx{position:absolute;inset:0;z-index:4;background:#FFFFFF;opacity:0;pointer-events:none}
.cam-flashfx.on{animation:shotFlash 240ms linear}
@keyframes shotFlash{0%{opacity:.7}100%{opacity:0}}

/* ── 我的二维码 ── */
.qr-who{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-3)}
.qr-who .av{width:44px;height:44px;font-size:16px}
.qr-name{font-size:14.5px;font-weight:600;color:var(--text)}
.qr-box{
  display:grid;place-items:center;
  padding:var(--s-4);margin:0 auto;
  background:#FFFFFF;border-radius:var(--r-md);
  box-shadow:var(--sh-sm);
  width:min(72vw,280px);
}
.qrsvg{width:100%;height:auto;display:block}
.qr-fallback{font-size:13px;color:var(--danger-text);text-align:center}
.qr-hint{margin:var(--s-3) 0;text-align:center;font-size:12.5px;color:var(--wa-meta)}
.qr-link{display:flex;gap:var(--s-2)}
.qr-link-input{
  flex:1;min-width:0;height:44px;font-size:13px;
  border-radius:var(--r-full);background:var(--ink-100);border:1px solid var(--line);
}

/* ═══════════════ ⑰ v1.31.0：按参考图补齐「更新 / 通话 / 个人主页」的版式 ═══════════════
   参考图（WhatsApp 新版）在这三页上用的是**大标题**：页面内容里一行 22px 加粗的
   标题，顶栏不再重复一遍（所以 VIEW_TITLES 里这三页留空）。 */
.big-title{
  padding:8px 16px 2px;
  font-size:23px;font-weight:700;line-height:1.25;
  color:var(--wa-bubble-ink);
}

/* ── 通话页：四个「图标在上、文字在下」的快捷块（四项等分整行） ── */
.call-quick{
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:4px;padding:6px 8px 10px;
}
.cq-item{
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
  gap:7px;min-height:76px;padding:8px 2px 6px;
  border-radius:var(--r-md);
  transition:background-color var(--t-fast) linear;
}
.cq-item:active{background:var(--wa-chip-bg)}
.cq-ico{
  width:46px;height:46px;display:grid;place-items:center;
  border-radius:50%;background:var(--wa-chip-bg);color:var(--wa-accent-text);
}
.cq-ico .ico{width:23px;height:23px}
.cq-t{font-size:12.5px;font-weight:500;color:var(--wa-bubble-ink);white-space:nowrap}

/* ── 通话记录行：右侧只留时间（参考图形态），方向用一个小箭头带出来 ── */
.call-item .call-dir{margin-right:4px;font-size:12px}
.call-item .call-time{font-size:12.5px;color:var(--wa-meta);font-variant-numeric:tabular-nums}

/* ── 更新页：说明文案 / 查找频道 / 频道行 / 创建频道 ── */
.wa-note{
  margin:2px 16px 8px;
  font-size:13.5px;line-height:1.65;color:var(--wa-meta);
}
.searchbar.wa-searchbar{padding:4px 16px 8px}
.searchbar.wa-searchbar input{border-radius:var(--r-full)}
/* 频道行与消息行同规格，右边挂一个「关注」描边小按钮（参考图就是这样） */
.chan-item .name{font-size:16.5px}
.chan-follow{
  flex:0 0 auto;min-height:36px;padding:0 16px;
  border-radius:var(--r-full);
  border:1px solid var(--wa-btn-outline);color:var(--wa-btn-outline);
  font-size:14px;font-weight:600;
  background:transparent;
}
.chan-follow:active{background:var(--wa-chip-bg)}
.wa-create-wrap{display:flex;justify-content:center;padding:10px 16px 4px}
.wa-create-btn{
  min-height:40px;padding:0 18px;
  border-radius:var(--r-full);
  border:1px solid var(--wa-btn-outline);color:var(--wa-btn-outline);
  font-size:14px;font-weight:600;background:transparent;
}
.wa-create-btn:active{background:var(--wa-chip-bg)}
/* 待接入的元素：结构和触摸目标都在，只是不绑行为（产品方要求"先空着"）。
   只降一点透明度示意，不去掉、不画成禁用灰 —— 免得看起来像坏了。 */
.wa-todo{opacity:.72}

/* ── 个人主页：头像块 + 「左标签 / 右值 / 右箭头」的字段行 ── */
.pe-head{
  display:flex;flex-direction:column;align-items:center;gap:8px;
  padding:var(--s-5) var(--s-4) var(--s-4);
}
.pe-av .av{width:104px;height:104px;font-size:40px;border-radius:50%}
.pe-photo{
  min-height:40px;padding:0 16px;border-radius:var(--r-full);
  background:var(--wa-chip-bg);color:var(--wa-accent-text);
  font-size:14px;font-weight:600;
}
.pe-album{min-height:36px;padding:0 12px;font-size:13px;color:var(--wa-btn-outline)}
.pe-list{display:flex;flex-direction:column}
.pe-row{
  display:flex;align-items:center;gap:var(--s-2);
  min-height:58px;padding:8px 16px;
  background:var(--wa-panel);
  border-bottom:1px solid var(--wa-line);
}
.pe-editable{cursor:pointer}
.pe-editable:active{background:var(--wa-chip-bg)}
.pe-k{flex:0 0 auto;font-size:15px;color:var(--wa-meta);min-width:74px}
.pe-v{
  flex:1;min-width:0;text-align:right;font-size:15px;color:var(--wa-bubble-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.pe-v.ph{color:var(--wa-icon)}
.pe-row .chev{flex:0 0 auto;color:var(--wa-icon);font-size:20px;line-height:1}
.pe-input{
  flex:1;min-width:0;height:40px;text-align:right;
  border-radius:var(--r-sm);border:1px solid var(--line);background:var(--wa-input);
  color:var(--wa-bubble-ink);
}
.pe-save{
  flex:0 0 auto;min-height:36px;padding:0 14px;border-radius:var(--r-full);
  background:var(--wa-btn);color:var(--wa-btn-ink);font-size:14px;font-weight:600;
}
.pe-save:active{background:var(--wa-btn-press)}

/* ── 底栏最后一项（自己）用头像（正常态 24px 圆片，无头像退化成首字母） ── */
.tab-av{
  width:24px;height:24px;border-radius:50%;
  display:grid;place-items:center;overflow:hidden;
  background:var(--wa-chip-bg);color:var(--wa-accent-text);
  font-size:12px;font-weight:600;
}
.tab-av img{width:100%;height:100%;object-fit:cover;display:block}

/* ══════════════════════════════════════════════════════════════════
   v1.72.0 · 戒指应用「年轻化」主题层（作用域：仅 #ring-overlay）
   ──────────────────────────────────────────────────────────────────
   需求：把智能戒指这一块做成"更年轻、更好用"的样子（其余界面不动）。

   ★★ 三条做法上的硬约束（都是为了"改得漂亮、不弄坏东西"）：
     ① **作用域限定 `#ring-overlay`** —— 聊天/登录/后台一点都受影响不到；
        同时它也保证后面的规则**盖得住**历史段（特异性更高）。
     ② **零 DOM 改动、不改任何 id / 类名** —— 视觉一律靠 CSS 覆盖；
        新装饰（顶部渐变条、分组标题的色点）全部用 ::before / ::after 画，
        不往 DOM 里插节点（插节点会改 textContent，可能打破既有断言）。
     ③ **每个颜色都算过对比度**，不是凭感觉挑的：正文/次要文字 ≥4.5:1，
        图形与色块 ≥3:1，渐变按钮按**最浅端**算（按平均色算会偏乐观）。
        实测数据见 DESIGN.md 的对照表；工具：tools/ring-ui-probe.cjs。

   配色思路（年轻 = 高饱和但不刺眼、且成体系）：
     电紫（主）· 薄荷青（活力）· 珊瑚（温度）· 蜜黄（能量）· 天蓝（睡眠）
     每种色都分三档，用的时候不会拿错：
       --rg-c*     鲜艳档：只用于**大色块 / 图形 / 渐变起点**
       --rg-deep-* 深档：承载**文字、细线、图标**（浅底上 ≥4.5:1）
       --rg-tint-* 浅底档：胶囊/标签底色，**配 deep 档文字**
   ══════════════════════════════════════════════════════════════════ */
#ring-overlay{
  /* ① 鲜艳档（图形与大色块） */
  --rg-c1:#6C5CE7; --rg-c2:#00C2A8; --rg-c3:#FF7A70; --rg-c4:#FFB020; --rg-c5:#4CC9F0;
  /* ② 深档（文字/细线/图标；浅底实测 ≥4.5:1） */
  --rg-deep-1:#4B3BC7; --rg-deep-2:#0E8F7A; --rg-deep-3:#D93B2B; --rg-deep-4:#B45309; --rg-deep-5:#2563EB;
  /* ③ 浅底档（配深档文字；实测 ≥4.74:1） */
  --rg-tint-1:#EFECFF; --rg-tint-2:#E6FBF7; --rg-tint-3:#FFEFED; --rg-tint-4:#FFF6E5; --rg-tint-5:#EAF2FF;
  --rg-bg:#F4F6FF;
  /* 次要文字：原来是 --ink-500(#64748B)，压在冷底上只有 4.41:1（不达标）→ 换成同族更深的 */
  --rg-muted:#5C6880;
  --rg-grad:linear-gradient(135deg,#6C5CE7 0%,#4B3BC7 100%);   /* 白字 4.86:1（最浅端）*/
  --rg-grad-2:linear-gradient(135deg,#22D3EE 0%,#0E8F7A 100%);
  --rg-grad-3:linear-gradient(135deg,#FF9A8B 0%,#D93B2B 100%);
  --rg-shadow-brand:0 10px 24px -10px rgba(108,92,231,.60);
  --rg-shadow-c2:0 10px 24px -10px rgba(0,194,168,.55);
  /* ④ 触摸目标下限：44px（WCAG 2.5.5 / iOS HIG）—— 让"更好按"成为可断言的数字 */
  --tap:44px;
  /* ⑤ 玻璃材质年轻化：更冷、更亮、描边带一点紫（原来是中性灰描边） */
  --gl-fill:rgba(255,255,255,.72);
  --gl-fill-2:rgba(255,255,255,.88);
  --gl-edge:rgba(76,58,199,.14);
  --gl-spec:rgba(255,255,255,.95);
  --gl-shadow:0 1px 1px rgba(31,32,80,.05), 0 14px 34px -14px rgba(76,58,199,.30);
  /* ⑥ 圆角同心：外 30 = 卡 22 + 内边距，内件 16 */
  --gl-r:30px; --gl-r-card:22px; --gl-r-inner:16px;
  background:var(--rg-bg);
}
@media (prefers-color-scheme: dark){
  #ring-overlay{
    /* 暗色单独定档（同一批色在深底上会塌：深紫 #4B3BC7 压深底只有 3 点几） */
    --rg-hi-1:#A78BFA; --rg-hi-2:#5EEAD4; --rg-hi-3:#FFB4A8; --rg-hi-4:#FFD166;
    --rg-deep-1:#A78BFA; --rg-deep-2:#5EEAD4; --rg-deep-3:#FFB4A8; --rg-deep-4:#FFD166; --rg-deep-5:#93B4FF;
    --rg-tint-1:rgba(167,139,250,.18); --rg-tint-2:rgba(94,234,212,.16);
    --rg-tint-3:rgba(255,180,168,.16); --rg-tint-4:rgba(255,209,102,.16); --rg-tint-5:rgba(147,180,255,.16);
    --rg-bg:#12131C;
    --rg-muted:#A6AEC0;
    /* ★ 主按钮渐变**暗色也用同一档**：先试过更亮的 #7C5CFF，白字只有 4.35:1（不达标）。
       "暗色模式就把品牌色调亮一点"是本能反应，但白字压上去就掉到 4.5 以下 —— 只能验算，不能凭感觉。 */
    --rg-grad:linear-gradient(135deg,#6C5CE7 0%,#4B3BC7 100%);
    --rg-shadow-brand:0 10px 24px -10px rgba(0,0,0,.75);
    --gl-fill:rgba(30,34,52,.62);
    --gl-fill-2:rgba(34,38,58,.82);
    --gl-edge:rgba(255,255,255,.12);
    --gl-spec:rgba(255,255,255,.18);
    --gl-shadow:0 1px 1px rgba(0,0,0,.45), 0 16px 36px -14px rgba(0,0,0,.8);
  }
}



/* ── 胶囊 / 分段控件 / 输入框：全部提到 44px ── */
#ring-overlay .ring-chip{
  min-height:var(--tap);padding:0 14px;font-weight:600;
  background:var(--rg-tint-1);color:var(--rg-deep-1);border-color:transparent;
}
#ring-overlay .ring-chip.on{background:var(--rg-grad);color:#fff;border-color:transparent;
  box-shadow:var(--rg-shadow-brand)}
/* 数据来源角标（蓝牙直读 / 需厂商协议 / 暂不能直读）—— 三档颜色区分，一眼能扫 */
#ring-overlay .ring-chip.ble{background:var(--rg-tint-2);color:var(--rg-deep-2)}
#ring-overlay .ring-chip.vendor{background:var(--rg-tint-5);color:var(--rg-deep-5)}
#ring-overlay .ring-chip.manual{background:var(--rg-tint-4);color:var(--rg-deep-4)}
#ring-overlay .ring-input{min-height:var(--tap)}
/* 面板里还有一批用全局 `.input` 类的输入框（日记/记一次数值/资料页），实测 36px。
   ★ 排除 checkbox/radio/range：给它们塞 min-height:44px 会把勾选框撑成一团，
     而这类"一刀切"正是改版时最容易把功能改坏的地方。 */
#ring-overlay .input,
#ring-overlay input:not([type="checkbox"]):not([type="radio"]):not([type="range"]){
  min-height:var(--tap);
}
#ring-overlay .ring-seg button{min-height:var(--tap);min-width:56px}
#ring-overlay .ring-switch{min-height:var(--tap);min-width:var(--tap)}
/* 触屏兜底：宽度过了断点但仍是手指操作（iPad mini 横屏就落在这一档） */
@media (hover:none),(pointer:coarse){
  #ring-overlay .ring-row.tap{min-height:56px}
  #ring-overlay button{min-height:var(--tap)}
}

/* ── 说明文字 / 分组标题：修对比度，同时让层次更年轻 ── */
#ring-overlay .ring-note{color:var(--rg-muted)}
#ring-overlay .ring-sec{
  color:var(--rg-deep-1);font-weight:700;letter-spacing:.02em;
  display:flex;align-items:center;gap:7px;
}
/* 分组标题前的彩色小圆点：靠伪元素，不改变 textContent（既有断言读的是文本） */
#ring-overlay .ring-sec::before{
  content:'';width:7px;height:7px;border-radius:99px;flex:none;
  background:var(--rg-grad);box-shadow:0 0 0 3px rgba(108,92,231,.14);
}
@media (prefers-color-scheme: dark){
  #ring-overlay .ring-sec{color:var(--rg-hi-1)}
  #ring-overlay .ring-sec::before{background:var(--rg-hi-1);box-shadow:0 0 0 3px rgba(167,139,250,.18)}
}

/* ── 首页英雄数字：改成渐变文字（年轻化的视觉焦点） ──
   ★ 渐变文字也必须算对比度：最浅端 #6C5CE7 在冷底上 4.51:1（大文本门槛 3:1，余量充足） */
#ring-overlay .ring-hero-c .n{
  font-size:60px;font-weight:800;letter-spacing:-.02em;
  background:var(--rg-grad);-webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
}
@media (prefers-color-scheme: dark){
  #ring-overlay .ring-hero-c .n{background:linear-gradient(135deg,#A78BFA 0%,#6C5CE7 100%);
    -webkit-background-clip:text;background-clip:text}
}

/* ── 按钮层级：一级用品牌渐变 + 品牌色投影；次级用紫浅底 ── */
#ring-overlay button.primary{
  background:var(--rg-grad);color:#fff;border:none;min-height:var(--tap);
  border-radius:var(--r-full);font-weight:680;box-shadow:var(--rg-shadow-brand);
}
#ring-overlay button.primary:active{transform:scale(.97)}
#ring-overlay .btn-soft{
  background:var(--rg-tint-1);color:var(--rg-deep-1);border:none;min-height:var(--tap);
  border-radius:var(--gl-r-inner);font-weight:640;
}
#ring-overlay .btn-soft:active{transform:scale(.98)}
@media (prefers-color-scheme: dark){
  #ring-overlay .btn-soft{background:var(--rg-tint-1);color:var(--rg-hi-1)}
}

/* ── 卡片：圆角 22（同心），入场做一次轻上浮（尊重"减少动态"偏好） ── */
#ring-overlay .ring-card,#ring-overlay .ring-group{border-radius:var(--gl-r-card)}
@keyframes rg-rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
#ring-overlay .ring-card{animation:rg-rise .34s cubic-bezier(.22,1,.36,1) both}
@media (prefers-reduced-motion:reduce){
  #ring-overlay .ring-card{animation:none}
  #ring-overlay button.primary:active,#ring-overlay .btn-soft:active{transform:none}
}

/* ── 数据来源与状态：把"能直读 / 需协议 / 暂不能"做成一眼能扫的三色语义 ── */
#ring-overlay .ring-batt{font-weight:700}
#ring-overlay .ring-batt.low{color:var(--rg-deep-3)}
#ring-overlay .ring-dot.on{background:var(--rg-c2)}
#ring-overlay .ring-dot.off{background:var(--rg-c3)}
#ring-overlay .ring-dx-tag{background:var(--rg-tint-1);color:var(--rg-deep-1)}
#ring-overlay .ring-dx-tag2{background:var(--rg-tint-5);color:var(--rg-deep-5)}

/* ══ v1.72.0 · 健康图标：彩色圆角块 + 同色图标（iOS 27 / 健康 App 的语言） ══
   为什么这么做：图标本身只是形状，**颜色才是让"片指标"一眼分家的东西**。
   做法是给图标容器一个家族色（--ic 主色 / --ib 底色），30 个 key 各自一档，
   配色全部落在前面那套 5 色家族里（电紫/薄荷青/珊瑚/蜜黄/天蓝），所以整片卡片看着是一套体系。
   ★ 深色单独换 --ic（同一批深色压在深底上会糊掉）。 */
#ring-overlay .ring-ico{
  width:32px;height:32px;border-radius:11px;flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--ib,var(--rg-tint-1));color:var(--ic,var(--rg-deep-1));
}
#ring-overlay .ring-ico .ico,#ring-overlay .ring-ico svg{
  width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
}
/* 家族色：生命体征 */
#ring-overlay .i-hr{--ic:#D93B2B;--ib:#FFEFED}
#ring-overlay .i-temp{--ic:#D93B2B;--ib:#FFEFED}
#ring-overlay .i-spo2{--ic:#2563EB;--ib:#EAF2FF}
#ring-overlay .i-ambient{--ic:#2563EB;--ib:#EAF2FF}
#ring-overlay .i-bp{--ic:#4B3BC7;--ib:#EFECFF}
#ring-overlay .i-ecg{--ic:#4B3BC7;--ib:#EFECFF}
#ring-overlay .i-hrv{--ic:#0E8F7A;--ib:#E6FBF7}
/* 状态与环境 */
#ring-overlay .i-stress{--ic:#B45309;--ib:#FFF6E5}
#ring-overlay .i-sleep{--ic:#4F46E5;--ib:#EEF2FF}
/* 活动 */
#ring-overlay .i-steps{--ic:#0E8F7A;--ib:#E6FBF7}
#ring-overlay .i-sport{--ic:#0E8F7A;--ib:#E6FBF7}
#ring-overlay .i-calories{--ic:#B45309;--ib:#FFF6E5}
#ring-overlay .i-distance{--ic:#2563EB;--ib:#EAF2FF}
#ring-overlay .i-sedentary{--ic:#4B3BC7;--ib:#EFECFF}
/* 设备 */
#ring-overlay .i-battery{--ic:#0E8F7A;--ib:#E6FBF7}
#ring-overlay .i-wear,#ring-overlay .i-device,#ring-overlay .i-ota{--ic:#4B3BC7;--ib:#EFECFF}
#ring-overlay .i-find{--ic:#2563EB;--ib:#EAF2FF}
/* 个人与周期 */
#ring-overlay .i-profile,#ring-overlay .i-gender{--ic:#4B3BC7;--ib:#EFECFF}
#ring-overlay .i-age{--ic:#B45309;--ib:#FFF6E5}
#ring-overlay .i-heightCm{--ic:#2563EB;--ib:#EAF2FF}
#ring-overlay .i-weightKg,#ring-overlay .i-strideCm{--ic:#0E8F7A;--ib:#E6FBF7}
#ring-overlay .i-cycle{--ic:#D93B2B;--ib:#FFEFED}
/* 提醒 */
#ring-overlay .i-water{--ic:#2563EB;--ib:#EAF2FF}
#ring-overlay .i-alarm{--ic:#4B3BC7;--ib:#EFECFF}
#ring-overlay .i-weather{--ic:#B45309;--ib:#FFF6E5}
#ring-overlay .i-call{--ic:#0E8F7A;--ib:#E6FBF7}
#ring-overlay .i-sms{--ic:#2563EB;--ib:#EAF2FF}
#ring-overlay .i-info{--ic:#5C6880;--ib:#EEF1F6}
/* 医生听筒（AI 中医）：跟"医疗/生命体征"用同一档薄荷青，和旁边的 info 灰拉开 */
#ring-overlay .i-doctor{--ic:#0E8F7A;--ib:#E6FBF7}
@media (prefers-color-scheme: dark){
  #ring-overlay .ring-ico{--ib:rgba(255,255,255,.08)}
  #ring-overlay .i-hr,#ring-overlay .i-temp,#ring-overlay .i-cycle{--ic:#FFB4A8;--ib:rgba(255,180,168,.16)}
  #ring-overlay .i-spo2,#ring-overlay .i-ambient,#ring-overlay .i-distance,
  #ring-overlay .i-find,#ring-overlay .i-heightCm,#ring-overlay .i-water,
  #ring-overlay .i-sms{--ic:#93B4FF;--ib:rgba(147,180,255,.16)}
  #ring-overlay .i-bp,#ring-overlay .i-ecg,#ring-overlay .i-profile,
  #ring-overlay .i-gender,#ring-overlay .i-device,#ring-overlay .i-wear,
  #ring-overlay .i-ota,#ring-overlay .i-alarm,#ring-overlay .i-sedentary{--ic:#A78BFA;--ib:rgba(167,139,250,.16)}
  #ring-overlay .i-hrv,#ring-overlay .i-steps,#ring-overlay .i-sport,
  #ring-overlay .i-battery,#ring-overlay .i-weightKg,#ring-overlay .i-strideCm,
  #ring-overlay .i-call,#ring-overlay .i-doctor{--ic:#5EEAD4;--ib:rgba(94,234,212,.16)}
  #ring-overlay .i-stress,#ring-overlay .i-calories,#ring-overlay .i-age,
  #ring-overlay .i-weather{--ic:#FFD166;--ib:rgba(255,209,102,.16)}
  #ring-overlay .i-sleep{--ic:#A5B4FC;--ib:rgba(165,180,252,.16)}
  #ring-overlay .i-info{--ic:#A6AEC0;--ib:rgba(255,255,255,.08)}
}

/* ══ v1.72.0 · 数据展示年轻化：图表与进度条换色（原先是全站品牌绿） ══ */
#ring-overlay .rc-line,#ring-overlay .rc-spark-line{stroke:var(--rg-c1);stroke-width:2.2}
#ring-overlay .rc-dot{stroke:var(--rg-c1)}
#ring-overlay .rc-dot-last,#ring-overlay .rc-spark-dot{fill:var(--rg-c1);stroke:var(--surface)}
#ring-overlay .rc-area{fill:var(--rg-c1);opacity:.16}
#ring-overlay .rc-bar{fill:rgba(108,92,231,.26)}
#ring-overlay .rc-bar.on{fill:var(--rg-c1)}
#ring-overlay .rc-arc{stroke:var(--rg-c1)}
#ring-overlay .rc-arc.hero{stroke:var(--rg-c1)}
#ring-overlay .rc-badge{fill:var(--rg-deep-1)}
#ring-overlay .rc-radar-area{fill:rgba(108,92,231,.16);stroke:var(--rg-c1)}
#ring-overlay .rc-radar-dot{fill:var(--rg-c1)}
#ring-overlay .rc-num{fill:var(--text)}
#ring-overlay .rc-sub,#ring-overlay .rc-txt,#ring-overlay .rc-h span{fill:var(--rg-muted);color:var(--rg-muted)}
/* 睡眠分期用"夜晚色系"（深靛 / 中蓝 / 青 / 琥珀），比绿色更贴合"睡眠"这件事 */
#ring-overlay .rc-s-deep{fill:#4338CA}
#ring-overlay .rc-s-light{fill:#60A5FA}
#ring-overlay .rc-s-rem{fill:#22D3EE}
#ring-overlay .rc-s-awake{fill:#F59E0B}

/* ★ 列表行的次级文字：原来是 --ink-500(#64748B)，压在冷底上 4.41:1（不达标） */
/* ★★ v1.106.0：`:not(.ring-ico):not(.ico)` 不是洁癖 —— `.ring-ico` 本身就是个 <span>，
   下面这条 `span{color:...}` 的权重（1,1,1）**高于** `.ring-ico` 的基础规则（1,1,0），
   会把图标容器连同它的 currentColor 一起涂成灰色（图标"不像"的又一个来源）。 */
#ring-overlay .ring-row span:not(.ring-ico):not(.ico){color:var(--rg-muted)}

/* ══ v1.72.0 · 首页快捷操作条（「更方便用」的落点） ══
   三颗 44px+ 的大按钮，图标用家族色、主标签加粗、副标签一行小字。
   ★ 触摸目标按 --tap 定，与面板其余控件同一套标准（不再出现"这里大那里小"）。 */
#ring-overlay .ring-quick{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:var(--s-2) 0 var(--s-3);
}
#ring-overlay .ring-quick-b{
  display:flex;flex-direction:column;align-items:center;gap:5px;
  min-height:88px;padding:12px 8px;cursor:pointer;
  border-radius:var(--gl-r-card);border:none;
  background:var(--gl-fill-2);color:var(--text);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  box-shadow:inset 0 .5px 0 var(--gl-spec), 0 6px 18px -12px rgba(76,58,199,.4);
  transition:transform var(--t-fast) var(--e-out), box-shadow var(--t-base) var(--e-out);
}
#ring-overlay .ring-quick-b b{font-size:13px;font-weight:680;color:var(--text)}
/* ★★ 同上：副标签要灰色，但**图标容器也是 span** —— 少了 :not(.ring-ico)，
   三颗快捷按钮的图标就全变成灰色（家族色白定了）。真机取证：AI 中医那枚
   实测 color = #5C6880（--rg-muted）而不是 i-doctor 的 --ic=#0E8F7A。 */
#ring-overlay .ring-quick-b span:not(.ring-ico){font-size:11px;color:var(--rg-muted)}
#ring-overlay .ring-quick-b:active{transform:scale(.965)}
#ring-overlay .ring-quick-b .ring-ico{width:34px;height:34px;border-radius:12px}

/* ══════════════════════════════════════════════════════════════════
   v1.73.0 · 舌象采集浮层 + 舌诊/脉诊结果卡片
   ──────────────────────────────────────────────────────────────────
   ★ 为什么要**另开**一个浮层（#tongue-overlay），而不是复用聊天那个相机浮层：
     那个浮层里 19 个 id 都有测试钉着，而且它的用途是「拍一张发给别人」——
     取景是通用构图。舌象要的是**另一种取景**：把舌头塞进一个**舌形框**里，
     还要在按快门前就告诉你光线够不够。两者的约束不一样，硬合并只会两边都别扭。
   ★ 复用是有的：相机能力探测（camCanPreview / 安全上下文 / 权限门文案）
     全部沿用既有那套函数，没有第二份实现。
   ══════════════════════════════════════════════════════════════════ */
#tongue-overlay{
  position:fixed;inset:0;z-index:70;background:#0B0C14;
  display:flex;flex-direction:column;overscroll-behavior:contain;
}
#tongue-overlay.hide{display:none}
/* ★★ 用 contain 而不是 cover。理由（这条是被量出来的，不是口味问题）：
   手机的相机流多为 4:3 横向，屏幕是 390×844 的竖屏 —— 用 cover 会把帧放大 2.6 倍
   并裁掉两侧，于是按帧比例算出来的引导框有 490px 宽，比 390px 的屏幕还宽，
   左右直接顶出屏幕（实测如此）。contain 则把整帧完整显示在中间，
   框永远落在屏幕内，而且**屏幕上看的框就是算法真正取样的那块**。 */
#tongue-video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#000;
}
/* 前置镜头：**显示**镜像才符合直觉。但抓帧用的 canvas 不镜像 ——
   送去分析的像素是真实的（镜像对颜色判读也没影响，这里纯粹为了"看着自然"）。 */
#tongue-video.mirror{transform:scaleX(-1)}
/* 舌形引导 + 遮罩（v1.106.0：由"圆/椭圆"改成**舌头形状**）。
   结构：一个覆盖整屏的 SVG（viewBox 0 0 100 100 + preserveAspectRatio:none ⇒ 坐标即百分比）
     · .tongue-dim  = 整屏压暗层，用 fill-rule:evenodd 在同一条 path 里挖出舌形的洞
                      （原先是 box-shadow 打洞 —— 那只对 border-radius 能表达的形状有效）
     · .tongue-oval = 沿同一条曲线描的虚线框（类名沿用：测试与"框"的语义都还认它）
   ★ 轮廓点来自 TongueAnalyze.tongueOutline() —— 与分析掩膜**同一条曲线**。 */
.tongue-mask{position:absolute;inset:0;pointer-events:none}
.tongue-guide{position:absolute;inset:0;width:100%;height:100%;display:block}
.tongue-dim{fill:rgba(6,8,16,.58)}
/* ★★ 框的位置与形状都由 JS 按**帧的可见区域**精确算出来（tongueSyncOval），不写死百分比。
   原因：预览用 contain 居中显示，写死的百分比在竖屏下会比算法真正取的区域大出一倍 ——
   于是用户把舌头填满虚线圈，算法却只看中间那一小块，判读自然不准。 */
.tongue-oval{
  stroke:rgba(255,255,255,.86);stroke-width:2;stroke-dasharray:7 7;stroke-linejoin:round;
  animation:tg-breathe 2.6s ease-in-out infinite;
}
@keyframes tg-breathe{0%,100%{stroke:rgba(255,255,255,.86)}50%{stroke:rgba(255,255,255,.5)}}
@media (prefers-reduced-motion:reduce){.tongue-oval{animation:none}}
.tongue-top{
  position:relative;z-index:2;display:flex;align-items:center;gap:10px;
  padding:calc(env(safe-area-inset-top,0px) + 12px) 14px 12px;
}
.tongue-top .t{
  flex:1;color:#fff;font-size:13px;font-weight:620;line-height:1.45;
  text-shadow:0 1px 6px rgba(0,0,0,.6);
}
.tongue-top button{
  flex:none;min-width:44px;min-height:44px;border-radius:99px;border:none;cursor:pointer;
  background:rgba(255,255,255,.18);color:#fff;font-size:13px;font-weight:640;
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
}
.tongue-hint{
  position:relative;z-index:2;margin:0 14px;padding:9px 12px;border-radius:14px;
  font-size:12.5px;line-height:1.5;color:#fff;
  background:rgba(255,255,255,.14);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
}
.tongue-hint.ok{background:rgba(0,194,168,.30)}
.tongue-hint.warn{background:rgba(255,176,32,.30)}
.tongue-hint.bad{background:rgba(255,90,80,.34)}
.tongue-hint.hide{display:none}
.tongue-bottom{
  position:relative;z-index:2;margin-top:auto;padding:16px 0 calc(env(safe-area-inset-bottom,0px) + 22px);
  display:flex;align-items:center;justify-content:center;
}
/* ★ 快门**绝对居中**：靠一层 absolute 的左右按钮 + 中间一个固定宽度的快门，
   不用 flex 的 gap —— gap 会随旁边按钮文案变宽而把快门推偏。 */
#tongue-shoot{
  width:74px;height:74px;border-radius:99px;cursor:pointer;
  border:4px solid rgba(255,255,255,.9);background:rgba(255,255,255,.22);
  transition:transform .12s;
}
#tongue-shoot:active{transform:scale(.94)}
#tongue-shoot:disabled{opacity:.45}
.tongue-side{
  position:absolute;left:0;right:0;bottom:calc(env(safe-area-inset-bottom,0px) + 30px);
  display:flex;justify-content:space-between;padding:0 26px;pointer-events:none;
  z-index:3;
}
.tongue-side button{
  pointer-events:auto;min-height:44px;padding:0 14px;border-radius:99px;border:none;cursor:pointer;
  background:rgba(255,255,255,.16);color:#fff;font-size:12.5px;font-weight:640;
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
}
.tongue-gate{
  position:absolute;inset:0;z-index:4;display:flex;align-items:center;justify-content:center;
  padding:24px;background:rgba(8,10,18,.94);
}
.tongue-gate.hide{display:none}
.tongue-gate .card{max-width:330px;border-radius:22px;padding:20px;background:#171A28;color:#EDEFF7}
.tongue-gate h3{margin:0 0 10px;font-size:16px;font-weight:700}
.tongue-gate p{margin:0 0 10px;font-size:13px;line-height:1.6;color:#B9C0D4}
.tongue-gate button{
  width:100%;min-height:46px;margin-top:6px;border-radius:14px;border:none;cursor:pointer;
  font-size:14px;font-weight:660;background:linear-gradient(135deg,#6C5CE7,#4B3BC7);color:#fff;
}
.tongue-gate button.ghost{background:rgba(255,255,255,.12);color:#EDEFF7}

/* ── 舌诊 / 脉诊结果卡片（两条通道共用同一套渲染函数） ── */
#ring-overlay .dx-dim{
  display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:10px;
  padding:11px 0;border-bottom:1px solid var(--gl-edge);
}
#ring-overlay .dx-dim:last-child{border-bottom:none}
#ring-overlay .dx-dim .lb{font-size:13px;font-weight:640;color:var(--text)}
#ring-overlay .dx-dim .vl{font-size:15px;font-weight:760;color:var(--rg-deep-1);text-align:right}
#ring-overlay .dx-bar{height:5px;border-radius:99px;background:rgba(108,92,231,.16);overflow:hidden;min-width:52px}
#ring-overlay .dx-bar i{display:block;height:100%;border-radius:99px;background:var(--rg-c1)}
#ring-overlay .dx-bar.low i{background:var(--rg-c3)}
#ring-overlay .dx-bar.mid i{background:var(--rg-c4)}
#ring-overlay .dx-ev{grid-column:1/-1;font-size:11.5px;line-height:1.55;color:var(--rg-muted);margin-top:2px}
#ring-overlay .dx-flag{
  border-radius:var(--gl-r-inner);padding:13px 14px;margin:0 0 10px;
  background:var(--rg-tint-3);border:1px solid rgba(217,59,43,.32);
}
#ring-overlay .dx-flag b{display:block;font-size:14px;font-weight:760;color:var(--rg-deep-3);margin-bottom:5px}
#ring-overlay .dx-flag p{margin:0;font-size:12.5px;line-height:1.6;color:var(--text)}
#ring-overlay .dx-hit{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
#ring-overlay .dx-hit span{
  font-size:11.5px;padding:3px 9px;border-radius:99px;
  background:rgba(108,92,231,.12);color:var(--rg-deep-1);font-weight:620;
}
#ring-overlay .dx-note{
  font-size:12px;line-height:1.6;color:var(--rg-muted);
  border-left:3px solid var(--rg-c4);padding:2px 0 2px 10px;margin:8px 0;
}
#ring-overlay .dx-pick{display:flex;flex-wrap:wrap;gap:8px;margin:10px 0}
/* ★ 单向宽度不够也算不达标：单个汉字的按钮（滑/涩/弦…）只有 39px 宽。
   这条是 tools/ring-ui-probe.cjs 在新页面上量出来的 —— 高度够了不代表能按准。 */
#ring-overlay .dx-pick button{
  min-height:44px;min-width:44px;padding:0 12px;border-radius:12px;border:1px solid var(--gl-edge);
  background:var(--gl-fill-2);color:var(--text);font-size:12.5px;font-weight:620;cursor:pointer;
}
#ring-overlay .dx-pick button.on{background:var(--rg-grad);color:#fff;border-color:transparent}
#ring-overlay .dx-step{display:flex;gap:11px;padding:12px 0;border-bottom:1px solid var(--gl-edge)}
#ring-overlay .dx-step:last-child{border-bottom:none}
#ring-overlay .dx-step .n{
  flex:none;min-width:26px;height:26px;padding:0 7px;border-radius:9px;background:var(--rg-tint-1);
  color:var(--rg-deep-1);font-size:13px;font-weight:760;white-space:nowrap;
  display:flex;align-items:center;justify-content:center;
}
/* ↑ v1.109.0：`n` 从"只放数字/·"变成也放"光源/姿势"这类两字标签 ⇒ 宽度必须自适应并留内边距，
   否则两字标签会被 26px 的定宽裁掉（本机实测：定宽 + nowrap ⇒ "光源"溢出成一个方块）。 */
#ring-overlay .dx-step .b{flex:1;font-size:13px;line-height:1.6;color:var(--text)}
#ring-overlay .dx-step .b i{display:block;font-style:normal;font-size:11.5px;color:var(--rg-muted);margin-top:2px}
#ring-overlay .dx-num{
  width:100%;min-height:48px;border-radius:14px;border:1px solid var(--gl-edge);
  background:var(--gl-fill-2);color:var(--text);text-align:center;
  font-size:24px;font-weight:780;letter-spacing:.04em;
}
#ring-overlay .dx-num:focus{outline:none;border-color:var(--rg-c1);box-shadow:0 0 0 3px rgba(108,92,231,.18)}
#ring-overlay .dx-src{
  font-size:11px;font-weight:660;padding:2px 8px;border-radius:99px;
  background:rgba(108,92,231,.12);color:var(--rg-deep-1);
}
#ring-overlay .dx-src.ring{background:var(--rg-tint-2);color:var(--rg-deep-2)}
#ring-overlay .dx-src.user{background:var(--rg-tint-4);color:var(--rg-deep-4)}

/* ═══════════════ ㉛ WHOOP 风格戒指面板层（v1.92.0）═══════════════
   产品方要求"参考 whoop 的界面修改 UI"。WHOOP 的界面语言拆出来是四件事：
     ① **一个深色状态板**：三枚霓虹环形量表（Recovery / Strain / Sleep 那三环）
        —— 深底、细环、大数字，一眼就知道"今天怎么样"；
     ② **微标签**：小字号 + 宽字距 + 全大写感（中文用字距替代大小写）；
     ③ **卡片**：深色玻璃 + 1px 冷描边 + 大圆角，**靠留白分层，不靠投影堆**；
     ④ **强调色只有四个**：绿(达标) / 青(心率·电量) / 紫(睡眠) / 琥珀(待协议)。

   ★ 两条不越界的地方（比"像不像"更重要）：
     · 面板底色仍跟主题走（浅色模式下整块变黑会让 App 像两个产品）；
       变深的是**状态板**这一块 —— 它本身就是"一块仪表"，深底是它的语义。
     · 环只画**有分母的量**（步数/目标、睡眠/目标、电量%）。
       心率没有目标值 → 它去下面的数字行，**不硬凑一个环**（凑出来的环是假指标）。
   ══════════════════════════════════════════════════════════════ */
#ring-overlay{
  --w-green:#00D26A; --w-cyan:#38BDF8; --w-purple:#A78BFA; --w-amber:#FFB020; --w-red:#FF5C5C;
  --w-board:#0A0E14; --w-board-2:#141B24;
  --w-line:rgba(255,255,255,.10); --w-ink:#F2F5F9; --w-sub:#9BA6B4;
}
#ring-overlay .ring-whoop{
  margin:12px 0 4px;padding:16px 14px 14px;border-radius:22px;
  background:radial-gradient(120% 120% at 50% -20%,#1B2531 0%,var(--w-board) 62%);
  border:1px solid var(--w-line);
  box-shadow:0 18px 40px -22px rgba(0,0,0,.85);
}
#ring-overlay .w-row{display:flex;gap:10px}
#ring-overlay .w-g{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;gap:6px}
#ring-overlay .w-ring{position:relative;width:100%;max-width:104px}
#ring-overlay .w-ring svg{display:block;width:100%;height:auto}
/* 环：轨道留 12% 白、进度用各自强调色；圆头收笔（WHOOP 的环都是圆头） */
#ring-overlay .w-arc-track{fill:none;stroke:rgba(255,255,255,.12);stroke-width:7}
#ring-overlay .w-arc{fill:none;stroke-width:7;stroke-linecap:round;stroke:var(--w-green);
  transition:stroke-dashoffset 600ms cubic-bezier(.22,.61,.36,1)}
#ring-overlay .w-g.cy .w-arc{stroke:var(--w-cyan)}
#ring-overlay .w-g.pu .w-arc{stroke:var(--w-purple)}
#ring-overlay .w-c{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
#ring-overlay .w-c b{font-size:22px;font-weight:800;letter-spacing:-.02em;color:var(--w-ink);line-height:1}
#ring-overlay .w-c i{font-style:normal;font-size:10px;font-weight:700;color:var(--w-sub);margin-top:2px}
/* 微标签：小字号 + 宽字距（WHOOP 的排版签名），中文靠字距而不是大小写 */
#ring-overlay .w-lb{font-size:11.5px;font-weight:700;letter-spacing:.14em;color:var(--w-ink)}
#ring-overlay .w-basis{font-size:10px;color:var(--w-sub);letter-spacing:.02em}
#ring-overlay .w-stats{display:flex;margin-top:14px;padding-top:12px;border-top:1px solid var(--w-line)}
#ring-overlay .w-stat{flex:1;min-width:0;text-align:center}
#ring-overlay .w-stat + .w-stat{border-left:1px solid var(--w-line)}
#ring-overlay .w-stat b{display:block;font-size:17px;font-weight:800;color:var(--w-ink);letter-spacing:-.01em}
#ring-overlay .w-stat span{display:block;font-size:10px;color:var(--w-sub);letter-spacing:.12em;margin-top:3px}
#ring-overlay .w-stat b.dim{color:var(--w-sub);font-weight:700}
/* 「需厂商协议」的标记在 WHOOP 层里换成琥珀（与"待办"语义一致）。
   ⚠️ 这几个**只在暗色模式换色**：霓虹绿/琥珀压在浅底上对比度只有 1.9:1 左右，
      浅色模式必须继续用原来那套"浅底档 + 深档文字"（那是算过对比度的）。 */
/* 分区标题：小号 + 宽字距（WHOOP 的分节就是这个手感） */
#ring-overlay .ring-sec{letter-spacing:.16em;font-size:12px}
@media (prefers-color-scheme: dark){
  #ring-overlay .ring-chip.vendor{background:rgba(255,176,32,.16);color:var(--w-amber)}
  #ring-overlay .ring-chip.ble{background:rgba(0,210,106,.16);color:var(--w-green)}
  /* 大数字（英雄环里的步数）：WHOOP 的绿→青霓虹渐变字 */
  #ring-overlay .ring-hero-c .n{
    background:linear-gradient(135deg,var(--w-green) 0%,var(--w-cyan) 100%);
    -webkit-background-clip:text;background-clip:text;
  }
  #ring-overlay .rc-arc.hero{stroke:var(--w-green)}
  #ring-overlay .rc-arc{stroke:var(--w-green)}
  #ring-overlay .rc-bar.on{fill:var(--w-green)}
}
@media (prefers-reduced-motion: reduce){
  #ring-overlay .w-arc{transition:none}
}

/* ── ㉜ 厂商指标测量按钮组（v1.93.0）─────────────────────────
   五个指标（血压/血氧/HRV/压力/心电）各一颗按钮：两列铺开，
   每个都保持 --tap（44px）触控下限 —— 这一类按钮最忌"点不准"。 */
#ring-overlay .ring-vendor-btns{display:flex;flex-wrap:wrap;gap:8px;margin:2px 0 8px}
#ring-overlay .ring-vendor-btns .btn-soft{
  flex:1 1 calc(50% - 4px);min-height:var(--tap);
  padding:8px 10px;font-size:13.5px;font-weight:650;
}
#ring-overlay .ring-mono{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11.5px;word-break:break-all}

/* ── ㉝ 今日概览 + 取数（v1.95.0）───────────────────────────────
   版式照官方 App 的「健康」页：一行"距离目标达成还差 N 步"的进度，
   下面四格关键读数（心率 / 血氧 / 血压 / HRV），再一颗"读取戒指数据"主按钮。
   ★ 只用已存在的戒指令牌（--gl-fill-2 / --gl-edge / --gl-r-card / --rg-grad / --rg-muted）——
     写一个不存在的变量名会静默退回 #fff，暗色模式下就是一块刺眼的白卡。 */
#ring-overlay .ring-goal{
  margin:12px 0 10px;padding:12px 14px;border-radius:var(--gl-r-inner);
  background:var(--gl-fill-2);border:1px solid var(--gl-edge);
}
#ring-overlay .ring-goal-t{display:flex;align-items:baseline;gap:8px;margin-bottom:8px}
#ring-overlay .ring-goal-t b{flex:1;font-size:14px;font-weight:700;letter-spacing:.01em}
#ring-overlay .ring-goal-t span{font-size:12px;font-weight:700;color:var(--rg-muted)}
#ring-overlay .ring-goal-bar{height:8px;border-radius:99px;overflow:hidden;background:rgba(127,127,127,.20)}
#ring-overlay .ring-goal-bar i{
  display:block;height:100%;border-radius:99px;background:var(--rg-grad);
  transition:width 600ms cubic-bezier(.22,.61,.36,1);
}
#ring-overlay .ring-board{
  margin:0 0 12px;padding:14px 12px 10px;border-radius:var(--gl-r-card);
  background:var(--gl-fill-2);border:1px solid var(--gl-edge);
}
#ring-overlay .ring-board-r{display:flex}
#ring-overlay .ring-board-r + .ring-board-r{margin-top:12px;padding-top:12px;border-top:1px solid var(--gl-edge)}
#ring-overlay .ring-board-c{flex:1;min-width:0;text-align:center}
#ring-overlay .ring-board-lb{display:block;font-size:11px;font-weight:700;letter-spacing:.12em;color:var(--rg-muted)}
#ring-overlay .ring-board-c b{display:inline-block;font-size:26px;font-weight:800;letter-spacing:-.02em;line-height:1.15;margin-top:2px}
#ring-overlay .ring-board-c b.dim{color:var(--rg-muted);font-weight:700}
#ring-overlay .ring-board-c i{font-style:normal;font-size:11px;font-weight:700;color:var(--rg-muted);margin-left:3px}
#ring-overlay .ring-fetch-out{
  white-space:pre-wrap;font-size:13px;line-height:1.55;
  margin:2px 0 6px;color:var(--rg-muted);
}
#ring-overlay .ring-decoded{display:flex;flex-wrap:wrap;gap:8px;margin:2px 0 8px}
#ring-overlay .ring-decoded-c{
  flex:1 1 calc(50% - 4px);min-width:0;padding:10px 12px;border-radius:var(--gl-r-inner);
  background:var(--gl-fill-2);border:1px solid var(--gl-edge);
}
#ring-overlay .ring-decoded-lb{display:block;font-size:11px;font-weight:700;letter-spacing:.1em;color:var(--rg-muted)}
#ring-overlay .ring-decoded-c b{font-size:20px;font-weight:800;letter-spacing:-.01em}
#ring-overlay .ring-decoded-c i{font-style:normal;font-size:11px;color:var(--rg-muted);margin-left:4px}
@media (prefers-reduced-motion: reduce){
  #ring-overlay .ring-goal-bar i{transition:none}
}

/* ── ㉞ 自动读取（v1.96.0）+ 指标卡照参考图放大 ──────────────────
   参考图上的指标块是"标签小字 + 大数字 + 单位"的排法，一屏能扫完。
   这里只调**字号与间距**，结构与类名不动（.ring-metric / .ring-spark 被测试数着）。 */
#ring-overlay .ring-auto{
  margin:10px 0;padding:12px 14px;border-radius:var(--gl-r-card);
  background:var(--gl-fill-2);border:1px solid var(--gl-edge);
}
#ring-overlay .ring-auto-h{display:flex;align-items:center;gap:10px}
#ring-overlay .ring-auto-state{flex:1;min-width:0}
#ring-overlay .ring-auto-line{display:flex;align-items:center;gap:7px}
#ring-overlay .ring-auto-line b{font-size:14px;font-weight:750;letter-spacing:.01em}
#ring-overlay .ring-auto-sub{display:block;font-size:11.5px;color:var(--rg-muted);margin-top:3px}
#ring-overlay .ring-auto-err{display:block;font-size:11.5px;color:var(--rg-deep-3);margin-top:3px}
#ring-overlay .ring-auto-dot{
  width:9px;height:9px;border-radius:50%;flex:0 0 auto;background:var(--rg-muted);
  box-shadow:0 0 0 3px rgba(127,127,127,.14);
}
#ring-overlay .ring-auto-dot.on{background:var(--rg-c2);box-shadow:0 0 0 3px rgba(0,194,168,.18)}
#ring-overlay .ring-auto-dot.busy{background:var(--rg-c5);box-shadow:0 0 0 3px rgba(76,201,240,.20);animation:ringAutoPulse 1.1s ease-in-out infinite}
#ring-overlay .ring-auto-dot.off{background:var(--rg-muted);opacity:.5}
@keyframes ringAutoPulse{0%,100%{opacity:1}50%{opacity:.35}}
@media (prefers-reduced-motion: reduce){ #ring-overlay .ring-auto-dot.busy{animation:none} }
#ring-overlay .ring-sw{
  flex:0 0 auto;min-height:var(--tap);min-width:72px;padding:0 12px;border-radius:99px;
  font-size:12.5px;font-weight:700;border:1px solid var(--gl-edge);background:transparent;color:inherit;
}
#ring-overlay .ring-sw.on{background:var(--rg-grad);border-color:transparent;color:#fff}
#ring-overlay .ring-auto-btns{display:flex;gap:8px;margin:8px 0 2px}
#ring-overlay .ring-auto-btns .btn-soft{flex:1;min-height:var(--tap);font-size:12.5px;font-weight:650}
#ring-overlay .ring-auto-out{
  white-space:pre-wrap;font-size:12.5px;line-height:1.55;color:var(--rg-muted);margin-top:6px;
}
/* 指标卡：照参考图放大数字（结构不动，只改排版） */
#ring-overlay .ring-metric{padding:12px 12px 10px}
#ring-overlay .ring-metric .v{font-size:26px;font-weight:800;letter-spacing:-.02em;line-height:1.1;margin-top:6px}
#ring-overlay .ring-metric .u{font-size:11px;font-weight:700;color:var(--rg-muted);margin-top:1px}
#ring-overlay .ring-metric-h span{font-size:12px;font-weight:700}

/* ── ㉟ 「我的」里的戒指状态卡（v1.98.0）──────────────────────────
   电量 / 连接状态两格：产品要求把首页的电池显示与操作项都收到「我的」，
   这两格回答"设备现在怎么样"，下面的目标进度与取数块回答"我要做什么"。 */
#ring-overlay .ring-mecard{display:flex;gap:10px;margin:2px 0 10px}
#ring-overlay .ring-mecell{
  flex:1;min-width:0;padding:12px;border-radius:var(--gl-r-card);
  background:var(--gl-fill-2);border:1px solid var(--gl-edge);
}
#ring-overlay .ring-mecell-h{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:700;color:var(--rg-muted)}
#ring-overlay .ring-mecell-h svg{width:14px;height:14px;flex:0 0 auto}
#ring-overlay .ring-mebig{display:block;font-size:24px;font-weight:800;letter-spacing:-.02em;margin:6px 0 2px}
/* 低电量用主题里的告警色；★ 不写死颜色 —— 亮/暗两套各有自己的合规色 */
#ring-overlay .ring-mebig.low{color:var(--rg-c5)}
#ring-overlay .ring-mebig.dim{opacity:.4;font-weight:700}
#ring-overlay .ring-mesub{display:block;font-size:11.5px;color:var(--rg-muted);line-height:1.4}

/* ═══════════════ ㊱ v1.99.0 戒指面板：心形图标 + 自适应（底栏部分已在 v1.100.0 移除）═══════
   ★ ① 那条"分区菜单栏吸底"是 v1.99.0 的做法，v1.100.0 已按产品要求改成**左上角 ⋯ 菜单**，
     规则连同它加的 panel padding 一起删掉了（见 ㊲ 层）——**别让它复活**：底栏和 App 自己的
     底栏会叠成两条，那正是这一版要解决的问题。
   剩下两件事：
     ② 底部 Tab 的「戒指」图标改成**心形 + 心率数值**；
     ③ 修 16:9 手机上的**横向溢出**（实测元凶：panel 里的 select 被最长 option 撑到 446px）。
   用 `#ring-overlay` 前缀提高特异性，覆盖上面 ⑲/㉛ 两段旧规则 —— 追加在文件末尾，
   同选择器下后者胜出，不必回头改老规则（老规则还要管别的场景）。 */


/* ── ③ 修横向溢出（16:9 手机实测：select 宽 446px 把 360px 的面板撑开） ──
   ★ 根因：select 的固有宽度由**最长的 option** 决定，而 flex 子项默认 min-width:auto
     ⇒ 它不肯收缩，整页横向溢出（这就是"进入页面变形"）。
   ★ 修法：让 select 与所有面板子项都允许收缩到容器宽度以内。 */
#ring-overlay .ring-panel select{max-width:100%;min-width:0;width:auto;box-sizing:border-box}
#ring-overlay .ring-panel select.input{width:100%;text-overflow:ellipsis}
/* ★★ v1.104.0：「定位字节排布」那一行变形的真身 —— 右侧控件一旦宽到吃满整行，
   左边的说明文字会被压成**宽度 0**，中文竖排换行把整行撑到 400px+（实测 401px）。
   ⚠️ 上面那条 `select.input{width:100%}` 是给"整行只有它一个控件"的场景用的，
      在 .ring-switch 这种"左说明 + 右控件"的行里是错的 —— 所以这里给 .grow 兜一道底：
      无论右边的控件多宽，说明文字至少留得住 96px（够放 5~6 个汉字，不会竖排）。
   ⚠️ 选择器要写到 `.ring-panel .ring-switch > .grow`：
      同文件那条 `#ring-overlay .ring-switch > *{min-width:0}` 是它被压成 0 的直接原因，
      特异性必须比它高才压得住。 */
#ring-overlay .ring-panel .ring-switch > .grow{min-width:96px}
#ring-overlay select.ring-sel-mini{width:132px;flex:0 0 auto}
#ring-overlay .ring-panel > *,
#ring-overlay .ring-row,
#ring-overlay .ring-row > *,
#ring-overlay .ring-switch,
#ring-overlay .ring-switch > *,
#ring-overlay .ring-group,
#ring-overlay .ring-sec,
#ring-overlay .ring-metric,
#ring-overlay .ring-mecell{min-width:0}
#ring-overlay .ring-panel{overflow-x:hidden}

/* ── ② 底部「戒指」图标：心形 + 心率数值 ─────────────────────────────
   ★ v1.106.0（产品要求"心型大点、数字大点、换红色、带跳动"）：
     · 心形 26 → **30px**、心率数字 8.5 → **11px**；
     · 心形固定**红色**（原来是 currentColor = 品牌绿/选中色）。它是一枚"生命体征"的
       记号，红心比绿心更像"心脏"；选中态仍由下面那行文字的颜色表达，信息没丢。
     · 数字改用**白色**：心形变成红底之后，原来的"页面底色"字（白底页里就是白字）
       压在同为红色的心上会糊成一片（对比度不足）。白字压 #E4342A 约 4.5:1。
     · 加一个**心跳**动效（两下快、一下慢，1.5s 一轮）。★ 必须给
       `prefers-reduced-motion` 留关闭开关 —— 前庭敏感的人会被常驻动画影响。 */
.tabbtn .tab-heart{position:relative;display:block;width:30px;height:30px;margin:0 auto}
.tabbtn .tab-heart svg{
  width:30px;height:30px;display:block;color:#E4342A;fill:currentColor;
  transform-origin:50% 58%;animation:tab-heartbeat 1.5s ease-in-out infinite;
}
@keyframes tab-heartbeat{
  0%,100%{transform:scale(1)}
  12%{transform:scale(1.15)}
  24%{transform:scale(1)}
  36%{transform:scale(1.09)}
  52%{transform:scale(1)}
}
@media (prefers-reduced-motion:reduce){ .tabbtn .tab-heart svg{animation:none} }
.tabbtn .tab-hr{
  position:absolute;left:0;right:0;top:9px;text-align:center;
  font-size:11px;font-weight:800;font-style:normal;letter-spacing:-.04em;
  color:#fff;line-height:1;pointer-events:none;
  text-shadow:0 0 2px rgba(0,0,0,.28);
}

/* ── 补充：「我的」戒指状态卡新增的两种小样式 ────────────────────── */
#ring-overlay .ring-mebig.sm{font-size:15px;font-weight:750;letter-spacing:0;line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#ring-overlay .ring-mesub.low{color:var(--rg-c5)}
/* 两格现在是 <button>：重置浏览器默认的边框/内边距/字体，只保留卡片观感 */
/* 心率数字由 attr(data-hr) 渲染（节点本身是空的 ⇒ 不污染 textContent） */
.tabbtn .tab-hr::before{content:attr(data-hr)}

#ring-overlay button.ring-mecell{
  border:1px solid var(--gl-edge);font:inherit;text-align:left;color:inherit;
  cursor:pointer;-webkit-appearance:none;appearance:none;
}

/* ═══════════════ ㊲ v1.100.0 戒指面板导航：左上角 ⋯ 菜单 + 二级页「返回」 ═══════════════
   把「首页 / 运动 / 关爱 / 我戒」从**底部四格栏**收进**左上角下拉菜单**。为什么：
     · 面板里一条底栏、App 底上还有一条 —— 上下两条叠着，看着像"App 里套了个 App"；
     · 收进菜单后内容区完整还给数据（不再被一条栏压着底部）；
     · 顺带补上一直缺的**二级页「返回」**（以前进了设备/心电，只能再点某个分区才退得出来）。

   ★ 菜单用**绝对定位**而不是插进文档流：插进去会推挤内容，展开那一瞬间页面会跳一下
     （用户正在看的数据跟着移位）。绝对定位只叠在上面，内容一动不动。
   ★ 条目一律 ≥ var(--tap)（44px）：这是导航，点不准等于不能用。
   ★ 不用"整块高亮底色"标当前项 —— 底色在亮/暗两套主题下都要重算对比度；
     这里用**左侧竖线 + 字重 + 尾标"所在"**，与主题无关、也不依赖颜色。
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 头部：[⋯] 标题 …… [返回] [关闭] ─────────────────────────── */
#ring-overlay .ring-head{justify-content:flex-start;gap:var(--s-2);padding-left:var(--s-2)}
#ring-overlay .ring-head-r{margin-left:auto;display:flex;align-items:center;gap:2px}
#ring-overlay #ring-sheet-title{
  flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:15.5px;
}
#ring-overlay .ring-mbtn{
  flex:0 0 auto;width:var(--tap);height:var(--tap);padding:0;
  display:inline-flex;align-items:center;justify-content:center;
  border:0;border-radius:var(--r-full);background:transparent;color:var(--ink-600);
  cursor:pointer;-webkit-appearance:none;appearance:none;
}
#ring-overlay .ring-mbtn svg{width:22px;height:22px;display:block}
#ring-overlay .ring-mbtn[aria-expanded="true"]{background:var(--ink-100)}
#ring-overlay #ring-back{min-height:var(--tap);padding:0 var(--s-2)}

/* ── 下拉菜单 ─────────────────────────────────────────────── */
#ring-overlay .ring-menu{
  position:absolute;z-index:6;top:calc(var(--tap) + var(--s-2));left:var(--s-2);
  min-width:188px;max-width:min(78vw,300px);
  max-height:min(64vh,460px);overflow:auto;
  padding:6px;border-radius:var(--gl-r-card);
  background:var(--gl-fill-2);border:1px solid var(--gl-edge);
  -webkit-backdrop-filter:var(--gl-blur);backdrop-filter:var(--gl-blur);
  box-shadow:0 18px 40px -20px rgba(15,23,42,.55), 0 2px 8px -4px rgba(15,23,42,.22);
}
#ring-overlay .ring-mi-h{
  padding:8px 10px 4px;font-size:11px;font-weight:700;letter-spacing:.12em;
  color:var(--rg-muted);
}
#ring-overlay .ring-mi{
  display:flex;align-items:center;width:100%;
  min-height:var(--tap);padding:0 10px;
  border:0;border-radius:var(--r-sm);background:transparent;color:var(--text);
  font-size:14.5px;font-weight:600;text-align:left;cursor:pointer;
  -webkit-appearance:none;appearance:none;
}
#ring-overlay .ring-mi:active{background:var(--ink-100)}
#ring-overlay .ring-mi.on{font-weight:750;box-shadow:inset 3px 0 0 0 var(--rg-c2)}
#ring-overlay .ring-mi.on::after{
  content:'所在';margin-left:auto;font-size:10.5px;font-weight:700;color:var(--rg-muted);
}
@media (prefers-reduced-motion: reduce){
  #ring-overlay .ring-mi{transition:none}
}

/* ═══════════════ ㊳ v1.101.0：戒指从「浮层」变成「App 内的一页」 ═══════════════
   产品要求：把戒指功能**嵌入 Uwhats**、**去掉右上角「关闭」**、
             **左右划切换分区**（首页→运动→关爱→我戒）、**下栏菜单不能挡住**。

   三条实现要点：
     ① `#view-ring` 是底栏第 1 项对应的**页面**（与聊天/通话/社群/自己同一层）：
        没有 `.overlay`、没有 `.ring-sheet`、没有「关闭」，进出全由底栏完成。
     ② `#ring-overlay` 这个 id **保留** —— 它是**戒指主题的作用域锚点**
        （本文件里 250 条规则与 --rg-* 令牌都挂在它上面），**已不再是遮罩**。
        改名要动 250 处、收益为零，故保留；看到它请按「戒指页根节点」理解。
     ③ 内容区底部要留出**底栏高度 + 间距**：底栏是 absolute 悬浮胶囊
        （高 62 + 离底 10），不让位的话最后一张卡会被压在底下点不到 ——
        这正是产品说的「下栏菜单不能挡住」。
   ══════════════════════════════════════════════════════════════════════════ */
#view-ring{min-height:0}
/* 页面根：纵向排布（头部固定、面板滚动），整页不滚动（滚动交给 .ring-panel） */
#ring-overlay{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden}
/* ★ 「底栏不许挡内容」的落点：84px = 底栏 62 + 离底 10 + 间距 12 */
#ring-overlay .ring-panel{
  flex:1 1 auto;min-height:0;overflow:auto;-webkit-overflow-scrolling:touch;
  padding-bottom:calc(84px + env(safe-area-inset-bottom));
  scroll-padding-bottom:calc(84px + env(safe-area-inset-bottom));
  overscroll-behavior-y:contain;   /* 划到底不把整页带着滚（左右划要在这一层稳住） */
}
/* ★ 这一页隐藏了 App 顶栏（它自带头部），所以**状态栏安全区要由头部承接** ——
   与 .chat-head 同一套做法；不接的话状态栏会压住「⋯ / 标题」。 */
#ring-overlay .ring-head{padding-top:calc(var(--s-3) + env(safe-area-inset-top))}
/* 页面头部不再需要浮层那种「顶在整块之上」的观感：底部一条分隔线即可 */
#ring-overlay .ring-head{border-bottom:1px solid var(--gl-edge)}

/* ══════════════════════════════════════════════════════════════════════════
   v1.107.0 · 心电波形分析（ECG + PPG 双路特征提取）
   ──────────────────────────────────────────────────────────────────────────
   ★ 全部用**已存在的令牌**（--gl-* / --rg-*），不写不存在的变量 ——
     写不存在的令牌会静默退回 #fff，暗色模式下就是一块白卡（本项目踩过）。
   ★ 波形图给的是 SVG（宽 320 高 66），外面套一层横向可滚动的壳：
     手机上窄屏也能看清；不缩到 100% 是刻意的 —— 心电的 R 波只有一两个点宽，
     压扁就看不见了（"图上看着没心跳"是最糟的一种错）。
   ══════════════════════════════════════════════════════════════════════════ */
#ring-overlay .ecg-wave-ta{
  width:100%;box-sizing:border-box;min-height:104px;padding:10px 12px;
  border-radius:14px;border:1px solid var(--gl-edge);background:var(--gl-fill-2);color:var(--text);
  font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  resize:vertical;
}
#ring-overlay .ecg-wave-ta:focus{outline:none;border-color:var(--rg-c1);box-shadow:0 0 0 3px rgba(108,92,231,.18)}
#ring-overlay .ecg-wave-btns{display:flex;gap:8px;margin:8px 0 0}
#ring-overlay .ecg-wave-btns .btn-soft{flex:1;min-height:44px}
#ring-overlay .ecg-wave-out{margin-top:10px;display:flex;flex-direction:column;gap:4px}
#ring-overlay .ecg-wave-k{font-size:14px;font-weight:720;line-height:1.5;color:var(--text)}
#ring-overlay .ecg-wave-sub{font-size:11.5px;line-height:1.5;color:var(--rg-muted)}
#ring-overlay .ecg-wave-bad{
  font-size:12.5px;line-height:1.55;color:var(--rg-deep-3);
  background:var(--rg-tint-3);border-radius:12px;padding:9px 11px;margin:0;
}
#ring-overlay .ecg-wave-chart{margin-top:10px}
#ring-overlay .ecg-wave-panel{position:relative;margin-bottom:6px}
#ring-overlay .ecg-wave-cap{
  display:block;font-size:11px;font-weight:700;letter-spacing:.06em;
  color:var(--rg-muted);margin-bottom:2px;
}
#ring-overlay .ecg-wave-wrap{
  overflow-x:auto;-webkit-overflow-scrolling:touch;
  border-radius:14px;border:1px solid var(--gl-edge);background:var(--gl-fill-2);padding:8px 10px;
}
#ring-overlay .ecg-wave-wrap svg{display:block;width:320px;height:66px}
#ring-overlay .ecg-wave-cap2{font-size:11px;line-height:1.5;color:var(--rg-muted);margin-top:4px}
#ring-overlay .ecg-wave-ecg{stroke:var(--rg-c1);stroke-width:1.4}
#ring-overlay .ecg-wave-ppg{stroke:var(--rg-c2);stroke-width:1.4}
#ring-overlay .ecg-peak-dot{fill:var(--rg-c3);stroke:var(--surface);stroke-width:1}
#ring-overlay .ppg-peak-dot{fill:var(--rg-c4);stroke:var(--surface);stroke-width:1}

/* ══ v1.108.0：「问老中医」对话面板 ═══════════════════════════════════════════
   ★ 颜色只走 #ring-overlay 里**已经定义**的令牌（--rg-tint-* / --rg-deep-* / --gl-edge / --rg-grad）。
     ⚠️ 别凭空写 --rg-ink / --rg-card 这种"听起来该有"的名字 ——
        不存在的令牌会**静默失效**（退回默认值），暗色下就是一块白卡（本项目栽过一次）。
   ★ 触摸目标：输入行与发送键 44px（--tap）。气泡本身不是点击目标，不参与这条。 */
#ring-overlay .tcm-chat{margin-top:10px;border:1px solid var(--gl-edge);border-radius:var(--gl-r-inner);overflow:hidden}
#ring-overlay .tcm-chat-head{display:flex;align-items:center;gap:10px;padding:10px 12px;background:var(--rg-tint-1)}
#ring-overlay .tcm-chat-emoji{font-size:22px;line-height:1}
#ring-overlay .tcm-chat-head b{display:block;font-size:14px}
#ring-overlay .tcm-chat-warn{margin:0;padding:8px 12px;font-size:11.5px;line-height:1.5;color:var(--rg-deep-4);background:var(--rg-tint-4)}
#ring-overlay .tcm-chat-msgs{max-height:min(46vh,340px);overflow-y:auto;padding:10px 12px;display:flex;flex-direction:column;gap:8px;-webkit-overflow-scrolling:touch}
#ring-overlay .tcm-msg{display:flex}
#ring-overlay .tcm-msg.user{justify-content:flex-end}
#ring-overlay .tcm-msg-body{max-width:82%;padding:8px 11px;border-radius:12px;font-size:13px;line-height:1.6;white-space:pre-wrap;word-break:break-word}
#ring-overlay .tcm-msg.assistant .tcm-msg-body{background:var(--rg-tint-2);border-top-left-radius:4px}
#ring-overlay .tcm-msg.user .tcm-msg-body{background:var(--rg-grad);color:#fff;border-top-right-radius:4px}
#ring-overlay .tcm-msg.typing .tcm-msg-body::after{content:'…';opacity:.55}
#ring-overlay .tcm-msg.warn .tcm-msg-body{background:var(--rg-tint-3);color:var(--rg-deep-3)}
#ring-overlay .tcm-chat-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 12px 10px}
#ring-overlay .tcm-chat-row{display:flex;gap:8px;align-items:center;padding:10px 12px;border-top:1px solid var(--gl-edge)}
#ring-overlay .tcm-chat-row .input{flex:1 1 auto;min-width:0;height:var(--tap)}
#ring-overlay .tcm-chat-row button.primary{flex:0 0 auto;padding:0 16px}

/* ══ v1.109.0：舌象 → 体质倾向（规范 §七 规则引擎的展示）══════════════════════
   ★ 颜色只走 #ring-overlay 里**已经定义**的令牌（--rg-tint-* / --rg-deep-* / --rg-muted /
     --gl-edge / --rg-grad）。⛔ 别写"听起来该有"的令牌名 —— 不存在的令牌会静默失效，
     暗色下就是一块白底黑字或白字白底（本项目栽过一次）。 */
#ring-overlay .dx-conclusion{
  font-size:20px;font-weight:780;letter-spacing:-.01em;color:var(--rg-deep-1);
  margin:4px 0 6px;
}
#ring-overlay .dx-tea{
  margin-top:8px;padding:11px 13px;border-radius:var(--gl-r-inner);
  background:var(--rg-tint-2);border:1px solid var(--gl-edge);
}
#ring-overlay .dx-tea b{display:block;font-size:14px;font-weight:740;color:var(--rg-deep-2)}
#ring-overlay .dx-tea .ring-note{margin-top:5px}
/* 标准 JSON：可展开。等宽 + 横向可滚 —— 结构化数据折行后基本没法看。 */
#ring-overlay .dx-json{
  margin:8px 0 0;padding:10px 12px;border-radius:var(--gl-r-inner);border:1px solid var(--gl-edge);
  background:var(--rg-tint-1);color:var(--text);
  font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;line-height:1.5;
  white-space:pre;overflow-x:auto;-webkit-overflow-scrolling:touch;
}

/* ══ v1.110.0：戒指面板的**骨架屏** ══════════════════════════════════════════
   起因：弱网下（真机实测每条 API 900ms）面板上只有一行"正在加载…"配一大片空白，
   用户报的是"白屏等待"。骨架屏让"在动"看得见；超过 1.5s 再给出慢网说明 + 重试按钮。
   ★ 颜色只走 #ring-overlay 里**已经定义**的令牌（--gl-edge / --gl-fill-2 / --rg-muted）。 */
#ring-overlay .ring-skel{display:flex;flex-direction:column;gap:10px;padding-top:4px}
#ring-overlay .ring-skel-bar{height:44px;border-radius:var(--gl-r-card);background:var(--gl-fill-2);border:1px solid var(--gl-edge)}
#ring-overlay .ring-skel-cards{display:flex;gap:10px}
#ring-overlay .ring-skel-card{
  flex:1 1 0;min-width:0;height:74px;border-radius:var(--gl-r-card);
  background:var(--gl-fill-2);border:1px solid var(--gl-edge);
  animation:ring-skel-pulse 1.15s ease-in-out infinite;
}
#ring-overlay .ring-skel-card:nth-child(2){animation-delay:.16s}
#ring-overlay .ring-skel-card:nth-child(3){animation-delay:.32s}
@keyframes ring-skel-pulse{0%,100%{opacity:.55}50%{opacity:1}}
@media (prefers-reduced-motion:reduce){#ring-overlay .ring-skel-card{animation:none;opacity:.8}}
#ring-overlay .ring-skel-slow{margin-top:6px}

/* ══ v1.111.0：我的戒指列表（多枚 + 改名 + 试着写进戒指）════════════════════════
   起因：产品说"戒指可能有多个款式，绑定后要能编辑名字，看能不能直接写进戒指里"。
   三件事在同一块 UI 上：认得出哪枚是哪枚 / 改得动名字 / 试得出硬件收不收。
   ★ 颜色只走 #ring-overlay 里**已经定义**的令牌（--rg-tint-1/2 / --rg-deep-1/2 /
     --rg-muted / --gl-edge / --gl-r-inner）—— 都带暗色覆盖。
     ⛔ 别写"听起来该有"的令牌名：不存在的令牌会**静默失效**，暗色下就是一块白底或白字白底。 */
#ring-overlay .ring-devlist{margin-top:6px}
#ring-overlay .ring-devrow{
  padding:10px 12px;margin-bottom:8px;border-radius:var(--gl-r-inner);
  background:var(--rg-tint-1);border:1px solid var(--gl-edge);
}
#ring-overlay .ring-tag{
  display:inline-block;margin-left:6px;padding:1px 7px;border-radius:99px;vertical-align:2px;
  font-size:11px;font-weight:700;background:var(--rg-tint-2);color:var(--rg-deep-2);
}
#ring-overlay .ring-tag.on{background:var(--rg-deep-1);color:var(--rg-tint-1)}
#ring-overlay .ring-devacts{display:flex;gap:8px;margin-top:8px}
#ring-overlay .ring-devacts button{flex:1 1 0;min-width:0}
#ring-overlay .ring-devform{margin-top:10px;padding-top:10px;border-top:1px dashed var(--gl-edge)}
#ring-overlay .ring-name-input{
  width:100%;box-sizing:border-box;padding:9px 11px;border-radius:var(--gl-r-inner);
  border:1px solid var(--gl-edge);background:var(--rg-tint-2);color:var(--text);font-size:15px;
}
#ring-overlay .ring-devopt{
  display:flex;gap:8px;align-items:flex-start;margin-top:8px;
  font-size:12.5px;line-height:1.45;color:var(--rg-muted);
}
#ring-overlay .ring-devopt input{margin-top:2px;flex:none}
#ring-overlay .ring-devform-bar{display:flex;gap:8px;margin-top:10px}
#ring-overlay .ring-devform-bar button{flex:1 1 0;min-width:0}
#ring-overlay .ring-devres{margin-top:8px}
#ring-overlay .ring-devline{
  display:flex;gap:7px;align-items:flex-start;margin:5px 0;
  font-size:13px;line-height:1.5;color:var(--rg-muted);
}
#ring-overlay .ring-devdot{
  flex:none;width:17px;height:17px;margin-top:1px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-size:11px;font-weight:800;background:var(--rg-tint-2);color:var(--rg-deep-2);
}
#ring-overlay .ring-devdot.ok{background:var(--rg-deep-1);color:var(--rg-tint-1)}
#ring-overlay .ring-devline.ok{color:var(--rg-deep-1);font-weight:600}

/* ══ v1.112.0：「自己」页那批设置页与数据页 ══════════════════════════════════
   复用已有的 .setting-row（标题/说明/箭头那一套），新增的只是"右侧控件""星标卡"
   "群发逐条结果"这几块。
   ★ 只用**已定义**的令牌（--ink-100/300/500、--brand-50、--s-3/4、--r-full、--t-fast、--text），
     拿不准的一律写 fallback —— 不存在的令牌会**静默失效**（本项目栽过：暗色下一块白底）。 */
.set-row .set-ctrl{flex:none;display:flex;align-items:center;gap:8px}
.set-sw{width:20px;height:20px;accent-color:var(--brand-600, #4B3BC7);cursor:pointer}
.set-sel{
  max-width:150px;padding:6px 10px;border-radius:10px;font-size:14px;
  border:1px solid var(--ink-100);background:transparent;color:var(--text);
}
.set-inp{
  width:110px;padding:6px 9px;border-radius:10px;font-size:14px;
  border:1px solid var(--ink-100);background:transparent;color:var(--text);
}
.set-inp.set-num{width:80px}
.set-list{display:flex;flex-direction:column}
.set-hint{
  margin:10px 0 0;padding:8px 10px;border-radius:10px;font-size:13px;
  background:var(--brand-50);color:var(--ink-700, var(--text));
  opacity:0;transition:opacity var(--t-fast) linear;
}
.set-hint.on{opacity:1}
.set-hint.err{background:#FFEFED;color:#B4231A}
.set-usage{margin-bottom:6px}
.set-usage-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:6px 0 4px}
.set-usage-cell{padding:9px 11px;border-radius:12px;background:var(--ink-100)}
.set-usage-cell .k{font-size:12px;color:var(--ink-500)}
.set-usage-cell .v{margin-top:1px;font-size:15px;font-weight:640}
.set-block-list{margin-bottom:6px}
.set-block-add{display:flex;gap:8px;align-items:center;margin:8px 0}
.set-block-add .set-inp{flex:1;width:auto;min-width:0}
.set-label{border-bottom:1px solid var(--ink-100);padding:4px 0}
.set-label-row{display:flex;align-items:center;gap:8px;padding:8px 0}
.set-label-row .st{flex:1;min-width:0}
.set-label-row .st-title{font-size:15px;font-weight:620}
.set-label-row .st-sub{font-size:12.5px;color:var(--ink-500)}
.set-label-dot{flex:none;width:12px;height:12px;border-radius:50%}
.set-label-members{padding:4px 0 10px}
.set-mem-item{display:flex;align-items:center;gap:8px;padding:6px 2px;font-size:14px}
.star-list{display:flex;flex-direction:column;gap:10px}
.star-item{padding:10px 12px;border-radius:12px;background:var(--ink-100)}
.star-head{display:flex;justify-content:space-between;gap:8px;font-size:12.5px;color:var(--ink-500)}
.star-from{font-weight:600}
.star-text{margin:5px 0 8px;font-size:15px;line-height:1.45;word-break:break-word}
.star-acts{display:flex;gap:8px}
.bc-picks{margin-bottom:8px}
.bc-pick-list{display:flex;flex-direction:column;max-height:230px;overflow:auto}
.bc-pick{display:flex;align-items:center;gap:8px;padding:8px 2px;font-size:15px;border-bottom:1px solid var(--ink-100)}
.bc-text{
  width:100%;box-sizing:border-box;padding:10px;border-radius:12px;font-size:15px;font-family:inherit;
  border:1px solid var(--ink-100);background:transparent;color:var(--text);
}
.bc-results{margin-top:10px}
.bc-line{display:flex;gap:7px;align-items:flex-start;margin:5px 0;font-size:13.5px;line-height:1.45}
.bc-dot{
  flex:none;width:17px;height:17px;border-radius:50%;background:var(--ink-100);
  display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;
}
.bc-line.ok .bc-dot{background:#0E8F7A;color:#fff}
.bc-line.err .bc-dot{background:#D93B2B;color:#fff}

/* ══ v1.117.0：老中医的「联网资料」与「我的病历」════════════════════════════
   两块东西会同时出现在**戒指页内的对话气泡**和**抽屉里的病历卡**里，
   所以颜色一律走带 fallback 的写法（--rg-tint-1 只有戒指页里有；
   不写 fallback 的话在抽屉里会**静默失效**，表现是"一块看不见的底"）。 */
.tcm-src{margin-top:8px;padding:8px 10px;border-radius:10px;background:var(--rg-tint-1, rgba(127,127,127,.10))}
.tcm-src-h{font-size:12px;color:var(--rg-muted, #8a8a8a);margin-bottom:4px}
.tcm-src-a{display:block;font-size:13px;line-height:1.4;margin:3px 0;word-break:break-all;color:var(--rg-deep-1, #4B3BC7);text-decoration:none}
.tcm-save{margin-top:8px}
.tcm-saved{margin-top:8px;font-size:13px;font-weight:600;color:#0E8F7A;background:none;border:0}
.tcm-cases-entry{margin:0 0 10px}
.tcm-case{padding:10px 12px;border-radius:12px;margin-bottom:10px;background:var(--rg-tint-1, rgba(127,127,127,.10))}
.tcm-case-h{font-size:12.5px;color:var(--rg-muted, #8a8a8a)}
.tcm-case-k{margin-top:4px;font-size:14px;color:var(--text)}
.tcm-case-advice{margin-top:6px;font-size:14.5px;line-height:1.5;white-space:pre-wrap;color:var(--text)}
.tcm-case-del{margin-top:8px;font-size:13px}

/* ══ v1.118.0：软件更新提示 —— 底栏「自己」上的闪烁红点 ══════════════════════
   为什么是**闪烁**而不是静态红点：静态小红点在有未读消息的 App 里天天都在，
   用户早就学会了无视它。而"有新版本"是偶发的、且**错过就一直用旧版**（旧版可能
   正是有 bug 的那版），需要被看见 ⇒ 用脉冲放大提醒，但不弹窗、不打断。
   ★ 位置用 `calc(50% - 18px)` 而不是照抄 `.tabbtn .badge` 的 30px：
     底栏每一项宽度 = 屏宽/5，"自己"那个图标（`.tab-av`）是比数字角标更靠内的元素，
     照抄 30px 会让红点飘到项与项的缝里。
   ★ 必须给 `prefers-reduced-motion` 留静止版：闪烁对前庭功能敏感的人是负担，
     而"知不知道有更新"不依赖动画（红点本体在）。 */
/* ★ 颜色**不复用 `--wa-unread`**：那个令牌在这个设计系统里是 WhatsApp 绿（#25D366），
   用于"未读消息"；而这个是"你装的包旧了"，用户要的是**红点**，两者必须一眼区分开。
   取 `--badge-bg` 那一族的红（#E03040，项目里角标用的红，白字对比度已算过 4.51:1）。 */
#badge-update{top:2px;right:calc(50% - 18px)}
.badge.dot{min-width:9px;height:9px;padding:0;border-radius:50%;
  background:#E03040;box-shadow:0 0 0 2px var(--wa-panel)}
.badge.dot:not(.hide){animation:uw-dot-pulse 1.15s ease-in-out infinite}
@keyframes uw-dot-pulse{
  0%,100%{transform:scale(1);opacity:.95}
  50%    {transform:scale(1.5);opacity:.5}
}
@media (prefers-reduced-motion: reduce){
  .badge.dot:not(.hide){animation:none}
}

/* ═══════════════ v1.119.0：把脉（脉象推理引擎） ═══════════════ */
.pe-file{display:block;width:100%;font-size:12.5px;color:var(--ink-600);margin:var(--s-2) 0}
.pe-ta{width:100%;box-sizing:border-box;font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;padding:8px 10px;border-radius:10px;border:1px solid var(--ink-200);background:var(--ink-50);color:var(--ink-800);resize:vertical}
.pe-chips{display:flex;flex-wrap:wrap;gap:6px;margin:var(--s-2) 0}
.pe-chip{display:inline-flex;align-items:center;padding:4px 11px;border-radius:999px;font-size:13px;font-weight:700;background:var(--danger-soft);color:var(--danger-soft-text)}
.pe-chip.ok{background:var(--brand-50);color:var(--brand-text)}
.pe-line{display:grid;grid-template-columns:auto 1fr;gap:8px;font-size:12px;color:var(--ink-600);margin-top:5px;line-height:1.55}
.pe-line b{color:var(--ink-800);white-space:nowrap}
.pe-text{margin-top:var(--s-3);padding-top:var(--s-3);border-top:1px dashed var(--ink-200)}
.pe-text>b{font-size:13px;color:var(--ink-800)}
.pe-advice{margin:var(--s-2) 0 0;font-size:12.5px;line-height:1.65;color:var(--ink-700);background:var(--brand-50);border-radius:10px;padding:8px 10px}
.pe-ecg{margin:var(--s-3) 0;padding:10px 12px;border-radius:12px;background:var(--danger-soft);color:var(--danger-soft-text)}
.pe-ecg>b{display:block;font-size:12.5px;margin-bottom:4px}
.pe-ecg>p{margin:0;font-size:12.5px;line-height:1.6}
.pe-retest{padding:12px 14px;border-radius:12px;background:var(--danger-soft);color:var(--danger-soft-text)}
.pe-retest>b{display:block;margin-bottom:4px}
.pe-retest>p{margin:0;font-size:12.5px;line-height:1.6}
.pe-wave{margin-top:var(--s-3)}
.pe-wave-bg{fill:var(--ink-50)}
.pe-wave-line{fill:none;stroke:var(--brand-500);stroke-width:1.6;stroke-linejoin:round}
.pe-field{display:grid;grid-template-columns:1fr 100px;gap:8px;align-items:center;margin-top:6px}
.pe-fl{font-size:12px;color:var(--ink-600)}
.pe-fi{width:100%;box-sizing:border-box;font-size:13px;padding:6px 8px;border-radius:8px;border:1px solid var(--ink-200);background:var(--ink-50);color:var(--ink-800)}

/* ═══ v1.121.0：账号中心「软件更新」里"网页是缓存的旧版"那条警告 ═══
   ★ 它必须**看起来像警告**：以前没有这个类，写成 `about-tip warn` 会退化成
     普通的灰小字（用户以为那只是一句说明而略过）—— 样式缺失**不报错**，只表现为"不显眼"。 */
.about-tip.warn{margin-top:var(--s-3);padding:10px 12px;border-radius:10px;
  background:var(--danger-soft);color:var(--danger-soft-text);
  font-size:13px;line-height:1.6;font-weight:600}
.about-tip.warn b{font-weight:800}

/* ══════════════════════════════════════════════════════════════════════════
   v1.122.0：老人关怀（社群页）—— 关怀对象的大概位置与心率
   ──────────────────────────────────────────────────────────────────────────
   ★ v1.123.0：位置区已经是**真地图**（中国地图框），但底图是**服务端出的 PNG** ——
     这一块**不含任何地理边界数据**，也不允许在这里画：边界由腾讯位置服务渲染，
     我们只是把那张图显示出来。"自己画一张中国地图"在合规上是红线（边界画错即违规）。
   ★ 心率那颗心只用**当前文字色**（currentColor）取色：
     不要写死颜色 —— 写了死色，暗色模式下就变成"看不清的一个红点"。
   ★ 心只在**实时**时跳动（.care-hr.on）：拿不到数据时它不跳，
     跳不跳本身就是一种状态提示，"没有数据也一直在跳"是骗人的。
   ══════════════════════════════════════════════════════════════════════════ */
.care-section{padding-bottom:0}
.care-head{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
  padding:0 var(--s-4) var(--s-2)}
.care-manage{flex:0 0 auto;min-height:32px;padding:0 var(--s-3);
  border:1px solid var(--wa-accent-text,#0a7c5a);border-radius:var(--r-full);
  background:transparent;color:var(--wa-accent-text,#0a7c5a);font-size:13px;cursor:pointer}
.care-manage:active{background:rgba(0,168,132,.12)}
/* 名单：它是 .wa-section 里的普通块，**不能再套一层自己的滚动**（嵌套滚动 = 手势打架）。 */
.care-list{flex:0 0 auto;overflow:visible;padding:0;background:transparent}
.care-item{cursor:default}
.care-item:active{background:var(--wa-panel)}
/* 名字 + 名字旁边那颗心：名字可以省略号，心**永远不压缩**（它带着心率数字） */
.care-name-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.care-sub{display:flex;align-items:center;gap:6px}
.care-warn{color:#E5484D;font-size:12px}
/* 名字旁边那一颗心 + 心率 */
.care-hr{flex:0 0 auto;display:inline-flex;align-items:center;gap:4px;font-size:12px;line-height:1;
  font-style:normal;color:var(--wa-meta)}
.care-hr-ico{display:inline-flex;flex:0 0 auto}
.care-hr-ico svg{width:13px;height:13px;display:block;fill:currentColor;stroke:none}
.care-hr.on{color:#E5484D;font-weight:600}
.care-hr.on .care-hr-ico svg{animation:careBeat 1.8s var(--e-out) infinite}
@keyframes careBeat{
  0%,78%,100%{transform:scale(1)}
  10%{transform:scale(1.2)}
  20%{transform:scale(1)}
  30%{transform:scale(1.12)}
}
/* 跟随系统的"减少动态效果"：心跳是装饰，不该强行播给会不适的人 */
@media (prefers-reduced-motion: reduce){.care-hr.on .care-hr-ico svg{animation:none}}

/* 位置区（产品叫"地图"；本轮是"按城市分组"的总览，不接瓦片） */
.care-map{margin:0 var(--s-4) var(--s-3);border:1px solid var(--wa-line);
  border-radius:var(--r-md);background:var(--wa-chip-bg,rgba(0,0,0,.03));overflow:hidden}
.care-map-in{padding:var(--s-3)}
.care-map-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:var(--s-2);margin-bottom:var(--s-3)}
.care-map-title{font-size:13px;font-weight:600;color:var(--wa-bubble-ink)}
.care-map-sub{font-size:11px;color:var(--wa-meta)}
.care-map-none{margin:0;font-size:13px;line-height:1.6;color:var(--wa-meta)}

/* ── v1.123.0：地图本体（服务端出图） ──
   ★ 图片用 width:100% + height:auto：底图是按 760×620 出的，这里只是等比缩到容器宽，
     所以**不能给它固定高度**（固定高度 + object-fit 会把地图裁掉一块 ——
     而用户看到"地图少一块"会以为是功能坏了）。
   ★ "正在生成地图…"与"地图暂时出不来"共用 .care-map-none，看起来是同一种东西：
     对用户来说它们确实都是"这一块现在没有地图"，不需要两套样式。 */
.care-map-slot{display:block}
.care-map-fig{margin:0}
.care-map-img{display:block;width:100%;height:auto;border-radius:var(--r-sm);
  border:1px solid var(--wa-line);background:var(--wa-panel)}
/* 图例（图下那一列）：静态图上是死的，读屏和视力不好的人只能靠这里拿信息。 */
.care-map-legend{margin-top:var(--s-2);display:flex;flex-direction:column}
.care-lg-row{display:flex;align-items:center;gap:var(--s-2);min-height:28px;
  border-bottom:1px solid var(--wa-line);font-size:13px}
.care-lg-row:last-child{border-bottom:0}
.care-lg-name{flex:0 0 auto;max-width:38%;font-weight:600;color:var(--wa-bubble-ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.care-lg-city{flex:1;text-align:right;font-size:12px;color:var(--wa-meta);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.care-map-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:var(--s-2)}
.care-city{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-2) var(--s-3);
  border:1px solid var(--wa-line);border-radius:var(--r-sm);background:var(--wa-panel)}
.care-city-mark{flex:0 0 8px;width:8px;height:8px;border-radius:50%;
  background:var(--wa-unread);box-shadow:0 0 0 3px rgba(37,211,102,.18)}
.care-city-name{display:flex;align-items:baseline;gap:6px;flex:1;min-width:0}
.care-city-label{font-size:14px;font-weight:600;color:var(--wa-bubble-ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.care-city-n{flex:0 0 auto;font-size:11px;color:var(--wa-meta)}
.care-city-faces{display:flex;align-items:center;flex:0 0 auto}
.care-face{flex:0 0 22px;width:22px;height:22px;font-size:11px;
  margin-left:-7px;border:1.5px solid var(--wa-panel)}
.care-city-faces .care-face:first-child{margin-left:0}
.care-face-more{margin-left:5px;font-size:11px;color:var(--wa-meta)}

/* 管理关怀对象（弹层里） */
.care-manage-block{margin-top:var(--s-3)}
.care-manage-block .sec{font-size:12px;font-weight:600;color:var(--wa-meta);margin-bottom:var(--s-1)}
.care-manage-row{display:flex;align-items:center;gap:var(--s-2);min-height:44px;
  border-bottom:1px solid var(--wa-line)}
.care-manage-name{flex:1;min-width:0;font-size:15px;color:var(--wa-bubble-ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.care-manage-tag{flex:0 0 auto;padding:1px 8px;border:1px solid var(--wa-line);
  border-radius:var(--r-full);font-size:11px;color:var(--wa-meta)}
.care-manage-btn{flex:0 0 auto;min-height:32px;min-width:56px;padding:0 var(--s-3);
  border:1px solid transparent;border-radius:var(--r-full);
  background:var(--brand-grad);color:#fff;font-size:13px;cursor:pointer}
.care-manage-btn.off{background:transparent;border-color:var(--wa-line);color:var(--wa-meta)}
.care-manage-btn:disabled{opacity:.5}

/* 关怀设置页里的附加块（我的城市 / 谁在关心我） */
.care-set-extra{margin-top:var(--s-3)}
.care-city-block,.care-watch-block{margin-top:var(--s-3)}
.care-city-line{display:flex;align-items:center;gap:var(--s-2);min-height:44px;
  border-bottom:1px solid var(--wa-line)}
.care-city-val{flex:1;min-width:0;font-size:15px;color:var(--wa-bubble-ink)}
.care-locate-btn{flex:0 0 auto;min-height:32px;padding:0 var(--s-3);
  border:1px solid var(--wa-line);border-radius:var(--r-full);background:transparent;
  color:var(--wa-accent-text,#0a7c5a);font-size:13px;cursor:pointer}
.care-locate-btn:disabled{opacity:.5}
.care-watch-row{display:flex;align-items:center;gap:var(--s-2);min-height:38px;
  border-bottom:1px solid var(--wa-line);font-size:14px}
.care-watch-name{flex:0 0 auto;font-weight:600;color:var(--wa-bubble-ink)}
.care-watch-state{flex:1;text-align:right;font-size:12px;color:var(--wa-meta)}
.care-watch-state.on{color:var(--wa-accent-text,#0a7c5a)}

@media (prefers-color-scheme: dark){
  .care-hr.on{color:#FF6B6B}
  .care-warn{color:#FF8A8A}
  .care-map{background:rgba(255,255,255,.05)}
  .care-manage:active{background:rgba(0,168,132,.20)}
}

/* ═══════════════════════════════════════════════════════════════
   登录页视觉 v2（2026-10-22）—— 「智库默认关闭」这一版的重设计
   ═══════════════════════════════════════════════════════════════
   设计取舍（每条都说清为什么，免得下一轮又改回去）：

   ① **只改视觉，不动结构骨架**。`#form-login` / `#li-user` / `#tab-login` / `#ver-auth`
      这些 id 被 13 个测试脚本与 app.js 引着；改结构省下的那点样式，代价是一堆断言连锁失败。

   ② **不加图片、不加字体、不加依赖**。光环是 conic-gradient，胶囊是 border-radius，
      网格纹理都不上 —— 登录页是首屏，多一个资源就多一次"白屏等图"。

   ③ 放在 append 位置、并**自己带上暗色覆盖**。原因：`⑬ 暗色模式` 那段在 1830 行，
      比这里的亮色规则更早 ⇒ 同特异性下本段胜出，暗色块里的 .auth-card / input 会被顶掉。
      所以暗色必需项在文件最末尾再写一遍，不靠"暗色段写得晚"这种巧合。

   ④ 顺手修了两个**实测出来的**可读性问题（不是审美偏好，是数据）：
      · 暗色下输入框 `rgba(255,255,255,.72)` 白底 + 浅色文字 → 对比度 **1.19:1**，
        等于看不见自己打的是什么。改成半透明白 6% 的深底。
      · 分段控件选中项「白底 + 深绿字」实测 **3.11:1**，14px 正文要求 4.5:1 ⇒ 不达标。
        改成「品牌绿实心 + 白字」，实测 5.02:1。
   --------------------------------------------------------------- */

/* ── 背景：四层柔光叠出纵深 ────────────────────────────────────
   三枚彩色光斑给"活"的感觉，顶部一层冷白给"被光打亮"的感觉。
   光斑都用 `closest-side`/百分比定位，不依赖视口宽高，手机上不会跑偏。 */
.auth{
  background:
    radial-gradient(58% 42% at 50% -6%, rgba(255,255,255,.92), transparent 68%),
    radial-gradient(78% 52% at 10% 4%, rgba(34,196,9,.20), transparent 62%),
    radial-gradient(66% 50% at 92% 8%, rgba(0,214,143,.17), transparent 60%),
    radial-gradient(96% 60% at 50% 104%, rgba(255,107,129,.13), transparent 64%),
    linear-gradient(168deg,#FAFCFF 0%,#F3F5FE 52%,#EEF1FB 100%);
}

/* ── 卡片：更大圆角 + 顶部身份线 + 三层阴影 ────────────────────
   身份线（::before）从"1px 白光"换成"56px 宽的品牌渐变短条"：
   白光在浅底上基本看不见（尤其手机上对比度低的屏幕），渐变短条是当下卡片
   最省的"品牌印记"，不占空间、不需要资源。 */
.auth-card{
  border-radius:32px;
  padding:30px var(--s-5) 26px;
  background:rgba(255,255,255,.90);
  border:1px solid rgba(255,255,255,.86);
  box-shadow:
    0 1px 1px rgba(15,23,42,.03),
    0 12px 26px -14px rgba(15,23,42,.16),
    0 34px 70px -34px rgba(14,138,0,.30),
    0 2px 8px rgba(15,23,42,.04);
}
.auth-card::before{
  content:'';position:absolute;left:50%;right:auto;top:0;transform:translateX(-50%);
  width:64px;height:3px;border-radius:0 0 3px 3px;
  background:linear-gradient(90deg,#3ED81B,#0E8A00 55%,#00D68F);
  pointer-events:none;
}

/* ── 品牌区 ─────────────────────────────────────────────────────
   logo 套一层会缓慢旋转的锥形光环（conic-gradient + blur）：
   比静态 drop-shadow 更有"这是活的"的感觉，成本只有一层合成。
   ★ 不转时（prefers-reduced-motion）样式仍然成立，只是不动。 */
.brand{text-align:center;margin-bottom:var(--s-4)}
.brand-mark{
  position:relative;display:inline-grid;place-items:center;
  width:60px;height:60px;margin:0 auto;
  isolation:isolate;
}
.brand-mark svg{
  position:relative;z-index:1;display:block;border-radius:17px;
  filter:drop-shadow(0 8px 16px rgba(14,138,0,.30)) drop-shadow(0 2px 4px rgba(14,138,0,.16));
}
.brand-mark::before{                 /* 旋转光环 */
  content:'';position:absolute;inset:-4px;border-radius:22px;z-index:0;
  background:conic-gradient(from 0deg,#3ED81B,#00D68F,#FFB020,#3FC51F,#3ED81B);
  filter:blur(7px);opacity:.55;
  animation:uwHaloSpin 9s linear infinite;
}
@keyframes uwHaloSpin{to{transform:rotate(1turn)}}

.brand h1{
  margin:var(--s-3) 0 0;
  font-size:32px;font-weight:850;letter-spacing:-.035em;line-height:1.15;
  background:linear-gradient(132deg,#0B7300 0%,#1CBE07 46%,#0A6A00 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
/* 三枚属性胶囊：原来那句「安全 · 即时 · 多端同步」是一串灰字，读起来像免责声明；
   拆成胶囊后同样是三个词，但一眼能"扫"过去，而且给了品牌区一个横向的节奏。 */
.brand-tags{
  display:flex;align-items:center;justify-content:center;flex-wrap:wrap;
  gap:6px;margin:10px 0 0;padding:0;list-style:none;
}
.brand-tags li{
  padding:3px 10px;border-radius:var(--r-full);
  background:rgba(255,255,255,.72);
  border:1px solid rgba(15,23,42,.075);
  color:var(--ink-600);
  font-size:11.5px;font-weight:600;letter-spacing:.02em;line-height:1.45;
}
/* 版本号：给排查的人看的一行。刻意比品牌低一级（不抢视觉），但**不能低到读不出** ——
   ink-400 实测只有 2.56:1（11px 小字远低于 4.5:1），改 ink-500 = 4.76:1 达标。
   靠字号与字距做"退后"，而不是靠颜色。 */
.brand .sub{
  margin:10px 0 0;color:var(--ink-500);
  font-size:11px;letter-spacing:.06em;font-weight:500;
}

/* ── 分段控件：选中项改成品牌绿实心 ───────────────────────────
   ★ 这是可读性修复，不只是换色：原「白底 + 深绿字」实测 3.11:1，
     14px 正文要 4.5:1。绿底白字 = 5.02:1，同时视觉上也更"当代"。
   ★ 高度仍是 --tap(44px)：这是触摸下限，不许为了好看压到 40 以下。 */
.tabs{
  gap:4px;padding:4px;
  background:rgba(15,23,42,.05);
  border-radius:var(--r-full);
  margin:var(--s-4) 0 var(--s-4);
}
.tab{
  min-height:var(--tap);border-radius:var(--r-full);
  color:var(--ink-500);font-weight:650;font-size:14px;letter-spacing:.01em;
  transition:background-color var(--t-fast) linear,color var(--t-fast) linear,
             box-shadow var(--t-fast) linear;
}
.tab.active{
  background:linear-gradient(180deg,#0E8A00,#0A7A00);
  color:#FFFFFF;
  box-shadow:0 1px 1px rgba(10,122,0,.20),0 6px 14px -8px rgba(10,122,0,.62);
}

/* ── 输入框：内阴影 + 更大圆角 ────────────────────────────────
   height 保持全局那 52px（iOS 聚焦防缩放要求字号 16px，高度与字号是配套的，
   单独把高度改到 58 会让注册页 5 个框挤满一屏）。 */
.auth-card input{
  border-radius:16px;
  background:rgba(255,255,255,.86);
  border:1px solid rgba(15,23,42,.10);
  box-shadow:inset 0 1px 2px rgba(15,23,42,.035);
}
.auth-card input:focus{
  background:#fff;
  border-color:rgba(14,138,0,.58);
  box-shadow:inset 0 1px 2px rgba(15,23,42,.02),0 0 0 4px rgba(14,138,0,.13);
}

/* ── 手机（≤900px）：更紧凑、更像原生 App ──────────────────────
   ★ 智库默认关闭后，这一屏只剩登录卡 —— 卡片可以给得更"满"：
     实测 390 视口下卡片 358×523、上下留白各 147px，看着像"缩在中间的一块"。
     这里把卡片**纵向撑开一点**（min-height + 更大的内边距），让它在首屏里占主要面积，
     而不是加一堆装饰填空 —— 首屏的"高级感"主要来自比例，不是来自元素数量。
   ★ 只改 min-height 与内边距：注册表单更长时卡片自然会更高，不会被压回 523。 */
@media (max-width:900px){
  .auth{padding:var(--s-4) var(--s-4) calc(var(--s-4) + env(safe-area-inset-bottom))}
  .auth-shell.no-ai{max-width:100%}
  .auth-shell .auth-card{
    border-radius:30px;
    padding:34px var(--s-5) 30px;
    box-shadow:
      0 1px 1px rgba(15,23,42,.03),
      0 14px 30px -16px rgba(15,23,42,.20),
      0 36px 72px -36px rgba(14,138,0,.34);
  }
  .brand{margin-bottom:var(--s-5)}
  .brand-mark{width:56px;height:56px}
  .brand h1{font-size:30px}
  .brand-tags li{font-size:11px;padding:2px 9px}
}

/* ── 暗色必需项（**必须留在文件最末**，见文件头 ③）───────────── */
@media (prefers-color-scheme: dark){
  .auth{
    background:
      radial-gradient(58% 42% at 50% -6%, rgba(120,160,255,.10), transparent 68%),
      radial-gradient(78% 52% at 10% 4%, rgba(34,196,9,.20), transparent 62%),
      radial-gradient(66% 50% at 92% 8%, rgba(0,214,143,.12), transparent 60%),
      radial-gradient(96% 60% at 50% 104%, rgba(255,107,129,.10), transparent 64%),
      linear-gradient(168deg,#141724 0%,#101220 52%,#0D0F1A 100%);
  }
  .auth-card{
    background:rgba(25,28,38,.90);
    border-color:rgba(255,255,255,.075);
    box-shadow:
      0 1px 1px rgba(0,0,0,.30),
      0 14px 30px -16px rgba(0,0,0,.55),
      0 36px 72px -36px rgba(0,0,0,.70);
  }
  /* 深底上深绿渐变读不出来 ⇒ 换亮绿一档。品牌色在暗色下本来就有 --brand-text 的
     亮色版（#5BDD3A），这里沿用同一族，不另起一套配色。 */
  .brand h1{
    background:linear-gradient(132deg,#7DEF5C 0%,#B6FA9E 46%,#4FD62E 100%);
    -webkit-background-clip:text;background-clip:text;color:transparent;
  }
  .brand-tags li{
    background:rgba(255,255,255,.055);
    border-color:rgba(255,255,255,.09);
    color:var(--ink-600);
  }
  /* 深底上的版本号：实测 ink-400(#8A92A6) 在合成后的卡片底(#181B25)上只有 3.67:1，
     11px 小字不够 ⇒ 提到 ink-600(#A6AEC0) = 5.6:1。
     ★ 这一条**必须写在这里**：`⑬ 暗色模式` 段里的 --ink-400 变量是全局的，
       改了会影响列表/气泡等一大片；只把"这一处文字"抬亮，影响面最小。 */
  .brand .sub{color:var(--ink-600)}
  .tabs{background:rgba(255,255,255,.06)}
  .tab{color:var(--ink-500)}
  /* ★ 修 bug：原来这里没覆盖，浅色那条 rgba(255,255,255,.72) 直接漏进暗色 ⇒
     白底 + 浅灰字（实测 1.19:1）。深色半透明底 + 浅色字才是对的。 */
  .auth-card input{
    background:rgba(255,255,255,.06);
    border-color:rgba(255,255,255,.11);
    box-shadow:inset 0 1px 2px rgba(0,0,0,.20);
  }
  .auth-card input:focus{
    background:rgba(255,255,255,.10);
    border-color:rgba(63,197,31,.62);
    box-shadow:inset 0 1px 2px rgba(0,0,0,.14),0 0 0 4px rgba(63,197,31,.16);
  }
}
/* 尊重系统「减少动态效果」：旋转光环是纯装饰，不该强行播 */
@media (prefers-reduced-motion:reduce){
  .brand-mark::before{animation:none}
}
