/* =========================================================
   移动端设计系统
   ========================================================= */
:root {
  --bg: #F4F6FA;
  /* 页面顶部比底部略亮一点。
     整屏一个纯色会「平」—— 卡片浮在一个没有光感的底上，
     再好的投影也出不来体积感。这一点点渐变（约 3% 明度差）
     就是「高级感」里最便宜也最有效的一招：光从上方来。 */
  --bg-top: #F9FBFE;
  --surface: #FFFFFF;
  --surface-2: #F7F9FC;
  --surface-3: #EFF3F9;
  --text: #101828;
  --text-2: #667085;
  --text-3: #98A2B3;
  --line: #EBEFF5;
  --line-2: #F2F5F9;
  --accent: #2F6BFF;
  --accent-soft: #EDF3FF;
  --green: #12B76A;
  --green-soft: #E7F8F0;
  --red: #F04438;
  --red-soft: #FEECEB;
  --amber: #F79009;
  --amber-soft: #FEF4E6;
  --purple: #7A5AF8;
  --purple-soft: #F1EEFE;
  /* 投影：单层改成双层。
     单层投影只有两种结果 —— 要么太淡（卡片发平，没有体积感），
     要么太重（边缘发脏，像贴了一张灰纸）。
     双层是「一层贴边定轮廓 + 一层扩散给体积」，这是最省事的
     高级感来源：卡片看起来是「浮在」页面上，而不是「画在」上面。 */
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .04), 0 4px 16px rgba(16, 24, 40, .05);
  /* 向上投影：底部固定栏（底部导航 / 输入栏）专用。
     方向必须朝上 —— 用向下投影的话，阴影会落在栏体下方、
     也就是屏幕外，等于白加。朝上的阴影让内容「从栏下滑进去」，
     底部栏就有了浮起来的层次，而不是贴一条边框了事。 */
  --shadow-up: 0 -1px 3px rgba(16, 24, 40, .04), 0 -6px 20px rgba(16, 24, 40, .06);
  --shadow-lg: 0 16px 44px rgba(16, 24, 40, .16);
  --r: 14px;

  /* =========================================================
     设计刻度（这是「尺子」，不是变量）
     ---------------------------------------------------------
     加这一层的原因：加之前全站用了 **30 种间距值、25 种圆角值**，
     里面混着 1 / 1.5 / 2.5 / 3 / 7 / 9 / 11 / 13px 这种随手写的数。
     单看每一处都不觉得有问题，但整屏扫下来会「发毛」——
     这就是「排版不舒服、不够高级」的真实来源，
     它不是某一处丑，而是**没有节奏**。

     ⚠ 这里刻意写成注释而不是 `--sp-8: 16px` 这类自定义属性。
     试过做成变量，结果是**一堆定义了却没人引用的死令牌**：
     全站 400 多处间距不可能都改成 var()（可读性反而变差，
     读 `padding: var(--sp-8) var(--sp-8)` 还得跳回顶部才知道是 16px），
     于是变量名看着像「改一处就全站生效」，实际什么都不动 ——
     这比没有变量更危险。所以：**尺子写在这里，值写在使用处。**

     真正需要动态变化的才做成变量：字号（--fs / --fsRoot）、
     过渡（--dur / --dur-slow / --ease）、主题色、语义色。

     ── 间距尺（4 为基准，保留 2 / 6 / 10 / 14 半步）──
       2  4  6  8  10  12  14  16  20  24  28  32  40
     半步是必要的：390px 宽下只用 4 的整数倍，
     小控件（角标、图标底）要么太挤要么太空。
     同类元素用同一档：卡片内边距 16，列表行竖向 12，
     页面左右留白统一 16（这是「对齐」的基准线）。

     ── 圆角尺（25 种 → 6 种）──
       6  小控件（角标 / 标签）
      10  中控件（按钮 / 输入框）
      14  卡片
      18  大面板
      22  弹层
     999  胶囊
     （手机外壳的 42px 不在此列 —— 那是设备外形，不是 UI 圆角）

     ── 字号尺（23 种 → 9 种，写在使用处并乘 --fs）──
      10.5  11.5  12.5  13.5  15  17  20  24
     半步（12.5 / 13.5 / 14.5 / 15.5）保留 ——
     中文在 390px 宽上，整数档之间确实需要半步才排得舒服。

     ── 行高尺（16 种 → 4 种）──
      1.3（标题 / 单行）  1.45（列表副标题）
      1.55（说明文字）    1.65（长段落）

     ── 阴影尺（3 档，都在用）──
      --shadow-sm   卡片 / 浮起控件（全站默认）
      --shadow-up   底部固定栏（底部导航 / 输入栏），方向朝上
      --shadow-lg   弹层 / 模态
     ========================================================= */

  /* 语义色：正文里那几个反复出现的「深绿 / 深红 / 深橙」文字色。
     之前是硬编码十六进制，深色主题下不跟着变，会变成暗底上的暗字。
     收成变量后两套主题各自取值。 */
  --on-green: #027A48;
  --on-red: #B42318;
  --on-amber: #B54708;
  --on-purple: #4E3FD4;
  /* 过渡时长：之前 .12s / .13s / .15s / .2s 混用，动效会「不齐」——
     同一屏里两个元素按下时的响应速度不一样，看着就不像一套东西。 */
  --dur: .16s;
  --dur-slow: .22s;
  --ease: cubic-bezier(.32, .72, .32, 1);
}

[data-theme="dark"] {
  --bg: #0B0F18;
  --bg-top: #101725;
  --surface: #141A26;
  --surface-2: #1A2130;
  --surface-3: #212938;
  --text: #E9EEF8;
  --text-2: #8D9AB1;
  --text-3: #5E6B82;
  --line: #232C3D;
  --line-2: #1C2434;
  --accent: #4B82FF;
  --accent-soft: #17203A;
  --green-soft: #12291F;
  --red-soft: #2A1614;
  --amber-soft: #2A1F0E;
  --purple-soft: #1E1A33;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-up: 0 -1px 3px rgba(0, 0, 0, .35), 0 -6px 20px rgba(0, 0, 0, .42);
  --shadow-lg: 0 16px 44px rgba(0, 0, 0, .62);
  /* 深色主题下「深绿 / 深红 / 深橙」必须换成亮色，
     否则是暗底上的暗字 —— 这正是硬编码色值最容易出的问题。 */
  --on-green: #5BE49B;
  --on-red: #FDA29B;
  --on-amber: #FDB022;
  --on-purple: #B9A8FF;
}

* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; }
body {
  /* =========================================================
     字体栈（全部可商用 · 零外部加载）
     ---------------------------------------------------------
     版权上唯一要紧的一条：**本项目不内嵌、不下载任何字体文件**。
     没有 @font-face，没有 fonts.googleapis，没有 CDN ——
     只写 font-family 名字，由浏览器从**用户自己的操作系统**里取。
     系统自带字体的授权随操作系统走，页面引用不构成再分发，
     所以不存在字体侵权问题。

     顺序是有讲究的，不是随便堆：
       ① 拉丁字母 / 数字走系统 UI 字体 —— 字形紧凑，数字等宽感好；
       ② 中文走各系统的默认黑体。放在拉丁之后，是因为浏览器
          会「逐字回退」：英文用 ①，汉字落到 ②，混排最干净；
          把中文字体放前面，英文也会被它接管，字形反而变差。
       ③ 兜底 sans-serif。

     列进来的中文黑体都是「随系统免费分发、明确允许商用」的：
       PingFang SC（苹果）/ HarmonyOS Sans SC（华为）/ MiSans（小米）
       Noto Sans CJK SC · Source Han Sans SC（思源黑体，SIL OFL）
       Microsoft YaHei（微软雅黑）/ Hiragino Sans GB（冬青黑体）
     装了的系统就用，没装的直接跳过 —— 不会因此多下载任何东西。
     ========================================================= */
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI",
    "PingFang SC", "HarmonyOS Sans SC", "MiSans", "Noto Sans CJK SC",
    "Source Han Sans SC", "Microsoft YaHei", "Hiragino Sans GB",
    "Noto Sans SC", sans-serif;
  font-size: calc(15px * var(--fs)); color: var(--text); background: #E4E9F2;
  display: grid; place-items: center; overflow: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* 让数字在各处等宽 —— 列表里的时间、金额、人数、票数
     左右对齐才不会「跳」。手机号 / ID 尤其明显。 */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
[data-theme="dark"] body { background: #05080F; }
button, input, textarea, select { font-family: inherit; font-size: inherit; color: inherit; border: none; background: none; outline: none; }
button { cursor: pointer; }
ul, li { list-style: none; }
img { display: block; max-width: 100%; }

::-webkit-scrollbar { width: 0; height: 0; }

/* =========================================================
   手机外壳
   ========================================================= */
.phone {
  width: 390px; height: 844px; max-height: 100vh;
  background: var(--bg);
  border-radius: 42px;
  overflow: hidden;
  display: flex; flex-direction: column;
  position: relative;
  box-shadow: 0 0 0 11px #12161F, 0 0 0 13px #2A303C, 0 32px 70px rgba(10, 16, 30, .45);

  /* =========================================================
     全局字号倍率（无障碍）
     ---------------------------------------------------------
     全站 410 处 font-size 都写成 calc(Npx * var(--fs))。
     calc(Npx * 1) 与原值完全等价 —— 默认观感不变，
     只在切换档位时整站等比缩放，不必为每个档位维护一套样式。

     两个变量而不是一个，是为了让「全局档位」与「局部微调」能相乘：
       --fsRoot  全局档位（由 data-fs 属性切换）
       --fs      当前生效倍率
     .chat-wrap 里会把 --fs 重定义成 calc(--fsRoot * .90) 来收一档，
     如果只有一个变量，这里就成了「自己乘自己」，CSS 会判定循环引用而失效。
     ========================================================= */
  --fsRoot: 1;
  --fs: var(--fsRoot);
}
.phone[data-fs="sm"] { --fsRoot: .90; }
.phone[data-fs="lg"] { --fsRoot: 1.16; }
.phone[data-fs="xl"] { --fsRoot: 1.34; }
@media (max-height: 880px) { .phone { border-radius: 0; box-shadow: none; } }

/* =========================================================
   真机适配（窄屏 / 已装到桌面）
   ---------------------------------------------------------
   桌面浏览器里 .phone 是「模拟手机外壳」：圆角、阴影，还有一条
   自绘的状态栏（时间 + 信号 + WiFi + 电量）和底部横条。
   那是给桌面预览用的道具。

   到了真机上，这三样全是多余的 —— 系统自带状态栏和手势条，
   再画一条就成了「手机里套手机」。而且那条假状态栏的时间和电量
   是写死的，老板截图反馈「多了一栏电量时间，不好看」，
   说的就是它：真机上一眼就能看出是假的。

   所以窄屏 / 独立模式下：
     ① 外壳去掉圆角和阴影，铺满全屏
     ② 隐藏 .statusbar 和 .homebar
     ③ 用 safe-area-inset 把隐藏掉的高度补回来 ——
        index.html 的 viewport 带 viewport-fit=cover，
        页面会延伸到刘海 / 挖孔区，不补的话顶部导航会被
        系统状态栏压住，那就从「多一条」变成「缺一块」了。

   ⚠️ 用 (display-mode: standalone) 兜一层：PWA 装到桌面后
   哪怕屏幕够宽（平板），也不需要这套假外壳。
   ========================================================= */
@media (max-width: 460px), (display-mode: standalone) {
  .phone {
    width: 100vw;
    height: 100vh;
    /* 支持 dvh 的浏览器走这行：手机浏览器地址栏收起/展开时，
       100vh 会算成「地址栏收起后的高度」，于是页面底部凭空多出
       一截滚动条。dvh 跟着可视高度实时变，不会。 */
    height: 100dvh;
    border-radius: 0; box-shadow: none;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  body { background: var(--bg); }

  /* ⚠️ 这里必须写成 `.phone .statusbar`，不能只写 `.statusbar`。
     ---------------------------------------------------------
     `.statusbar { display: flex }` 和 `.homebar { display: grid }`
     定义在**本媒体查询之后**（文件下方），优先级同为 0,1,0，
     同优先级下后写的赢 —— 只写类名的话，这条 display:none
     会被那两条原样盖掉，状态栏照样显示。
     实测就踩了这个：.phone 的圆角已经变成 0（说明媒体查询生效了），
     但状态栏纹丝不动，看起来像「改了没保存」。
     多一层 .phone 把优先级提到 0,2,0，就稳了。 */
  .phone .statusbar,
  .phone .homebar { display: none; }
}

.statusbar {
  height: 46px; flex: 0 0 46px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 24px 0 32px;
  font-size: calc(13.5px * var(--fs)); font-weight: 600;
  color: var(--text);
  background: var(--surface);
  position: relative; z-index: 30;
}
.sb-right { display: flex; align-items: center; gap: 6px; opacity: .92; }

.screen {
  flex: 1; min-height: 0;
  position: relative; overflow: hidden;
  /* 顶部微亮的竖向渐变（见 --bg-top 的说明）。
     渐变挂在 .screen 上而不是 .page-body 上 ——
     挂在滚动容器上会跟着内容一起滚走，变成「背景在移动」，
     反而显得廉价。挂在外层是固定的，读起来像环境光。 */
  background: linear-gradient(180deg, var(--bg-top) 0%, var(--bg) 280px, var(--bg) 100%);
  display: flex; flex-direction: column;
}

.homebar {
  height: 22px; flex: 0 0 22px;
  background: var(--surface);
  display: grid; place-items: center;
}
.homebar::after {
  content: ''; width: 128px; height: 5px; border-radius: 4px;
  background: var(--text); opacity: .22;
}
.tabbar ~ .homebar { background: var(--surface); }

/* =========================================================
   页面骨架
   ========================================================= */
.page { height: 100%; display: flex; flex-direction: column; min-height: 0; }
.page-body { flex: 1; overflow-y: auto; overflow-x: hidden; min-height: 0; -webkit-overflow-scrolling: touch; }
.page-foot { flex: 0 0 auto; }

/* =========================================================
   顶部导航
   ========================================================= */
.navbar {
  flex: 0 0 auto;
  min-height: 50px;
  display: flex; align-items: center; gap: 6px;
  padding: 0 8px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: relative; z-index: 20;
}
.nav-btn {
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center; color: var(--text);
  transition: background var(--dur) var(--ease);
}
.nav-btn:active { background: var(--surface-2); }
.nav-spacer { width: 38px; height: 38px; flex: 0 0 38px; }
.nav-title {
  flex: 1; min-width: 0; text-align: center;
  font-size: calc(16.5px * var(--fs)); font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.nav-sub { font-size: calc(11.5px * var(--fs)); font-weight: 500; color: var(--text-2); margin-top: 2px; }
.nav-actions { display: flex; align-items: center; gap: 2px; min-width: 38px; justify-content: flex-end; }
.nav-actions .nav-btn { color: var(--accent); }

/* 右上角下拉菜单（社区页那「三条横线」）——
   老板要求把「社区设置 / 社区审核 / 社区规则 / 退出 / 加入 / 搜索」
   都收进这里，参考的是 Telegram 频道页右上角那个菜单。 */
.nav-menu-wrap { position: relative; display: flex; }
.nav-menu {
  display: none;
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  min-width: 176px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow-lg);
}
.nav-menu.on { display: block; }
.nm-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 12px; border-radius: 8px;
  font-size: calc(13.5px * var(--fs)); color: var(--text);
  text-align: left; background: transparent; white-space: nowrap;
  transition: background var(--dur) var(--ease);
}
.nm-item:active { background: var(--surface-2); }
.nm-item.danger { color: #F04438; }

/* 大标题页头 */
.hero-head {
  padding: 6px 16px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.hero-title { font-size: calc(26px * var(--fs)); font-weight: 800; letter-spacing: -.5px; }
.hero-head .searchbar { margin: 12px 0 0; }

/* =========================================================
   底部导航
   ========================================================= */
.tabbar {
  flex: 0 0 auto;
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--line);
  /* 向上投影让底部导航「浮」在内容之上。
     只有 border-top 时它是「贴」在页面底部的最后一块；
     加一层朝上的阴影后，滚动内容从它下面滑过去，
     层次一下就出来了 —— 这是最省力的「高级感」。 */
  box-shadow: var(--shadow-up);
  padding: 6px 0 4px;
  position: relative; z-index: 30;
}
.tab {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 4px 0; color: var(--text-3);
  transition: color var(--dur) var(--ease);
}
.tab.on { color: var(--accent); }
.tab-ico { position: relative; display: grid; place-items: center; }
.tab-t { font-size: calc(10.5px * var(--fs)); font-weight: 600; }
.tab.on .tab-t { font-weight: 700; }
.tab-badge {
  position: absolute; top: -4px; left: 13px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 10px; background: var(--red); color: #fff;
  font-size: calc(10px * var(--fs)); font-weight: 700; font-style: normal;
  display: grid; place-items: center;
  border: 2px solid var(--surface); box-sizing: content-box;
}

/* =========================================================
   头像
   ========================================================= */
.av {
  border-radius: 50%;
  display: grid; place-items: center;
  color: #fff; font-weight: 700;
  flex: 0 0 auto; position: relative; user-select: none;
  font-size: calc(15px * var(--fs));
}
.av.sq { border-radius: 14px; }
.av.xs { width: 26px; height: 26px; font-size: calc(11px * var(--fs)); }
.av.sm { width: 38px; height: 38px; font-size: calc(14px * var(--fs)); }
.av.md { width: 48px; height: 48px; font-size: calc(17px * var(--fs)); }
.av.lg { width: 62px; height: 62px; font-size: calc(22px * var(--fs)); }
.av.xl { width: 82px; height: 82px; font-size: calc(30px * var(--fs)); }
.av.xxl { width: 96px; height: 96px; font-size: calc(34px * var(--fs)); }
.av.sq.xs { border-radius: 10px; }
.av.sq.sm { border-radius: 10px; }
.av.sq.md { border-radius: 14px; }
.av.sq.lg { border-radius: 18px; }
.av.sq.xl { border-radius: 18px; }

/* 图片头像（用户自己从相册选的图）。
   要点：
   1. object-fit: cover —— 用户拍的图长宽比千奇百怪，拉伸会把脸压扁。
      裁掉边缘比变形更容易接受。
   2. 圆角用 border-radius: inherit 跟着外层 .av 走。
      **不能用 overflow: hidden 裁** —— .av-badge / .av-dot 是刻意
      溢出到头像外沿的角标（-4px），父级一裁就全没了。
   3. 外层的底色保留：PNG 透明区域、图片解码前的一瞬间都会露出来，
      有底色就不会闪出一块空白。 */
.av-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  border-radius: inherit;
}
.av-badge {
  position: absolute; right: -4px; bottom: -4px;
  min-width: 18px; height: 18px; padding: 0 4px;
  border-radius: 6px; color: #fff;
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
  display: grid; place-items: center;
  border: 2px solid var(--surface); box-sizing: content-box;
}
.av-dot {
  position: absolute; right: 0; bottom: 1px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--green); border: 2.5px solid var(--surface);
}

/* =========================================================
   角色徽章 / 标签
   ========================================================= */
.role-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  font-size: calc(11px * var(--fs)); font-weight: 700; white-space: nowrap;
}
.role-chip.sm { padding: 2px 6px; font-size: calc(10px * var(--fs)); border-radius: 6px; }
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 12px; border-radius: 18px;
  background: var(--surface-2); color: var(--text-2);
  font-size: calc(13px * var(--fs)); font-weight: 600; white-space: nowrap;
  border: 1px solid var(--line);
}
.chip.on { background: var(--accent); color: #fff; border-color: var(--accent); }
/* 特殊技能（高风险工种）的勾选标签。
   选中后不是蓝色而是红色系 —— 它和普通工种不是同一类东西：
   普通工种选了就生效，特殊技能选了还要过证件认证。
   用同一个颜色会让用户以为「选完就完事了」。 */
.chip.special { border-style: dashed; border-color: var(--red); color: var(--red); background: transparent; }
.chip.special.on { background: var(--red); border-color: var(--red); border-style: solid; color: #fff; }
/* 工种多选的容器 */
.prof-pick { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.prof-pick .chip { font-size: calc(12.5px * var(--fs)); padding: 8px 12px; }
/* 按风险等级分组。平铺 20 个标签的话，
   「哪个要考证」这个最要紧的信息会被淹掉。 */
.tk-group + .tk-group { margin-top: 16px; }
.tk-group-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tk-group-n {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: calc(11px * var(--fs)); font-weight: 700; color: var(--red);
}
.tk-group-n svg { width: 11px; height: 11px; }
.tk-hint {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 8px; font-size: calc(11.5px * var(--fs));
  color: var(--text-3); line-height: 1.65;
}
.tk-hint svg { width: 12px; height: 12px; flex: 0 0 auto; margin-top: 2px; }
.tk-picked { font-size: calc(12px * var(--fs)); color: var(--text-2); margin-top: 8px; }
.tag {
  display: inline-block; padding: 2px 8px; border-radius: 6px;
  background: var(--accent-soft); color: var(--accent);
  font-size: calc(11.5px * var(--fs)); font-weight: 600; margin-right: 6px;
}

/* =========================================================
   列表行
   ========================================================= */
.row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  background: var(--surface);
  cursor: pointer;
  position: relative;
  transition: background var(--dur) var(--ease);
}
.row:active { background: var(--surface-2); }
.row.disabled { opacity: .45; pointer-events: none; }
.row-ico {
  width: 36px; height: 36px; border-radius: 10px;
  display: grid; place-items: center; flex: 0 0 auto;
}
.row-main { flex: 1; min-width: 0; }
.row-t {
  font-size: calc(15px * var(--fs)); font-weight: 500; color: var(--text);
  display: flex; align-items: center; gap: 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.row-d {
  font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 说明性副标题：允许换行，最多两行。
   用在「认证标识体系」这类**以解释为目的**的列表里 ——
   截断成「…认」「…平」等于没写。 */
.row-d.wrap {
  white-space: normal; text-overflow: clip; overflow: hidden;
  line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.row-arrow { color: var(--text-3); flex: 0 0 auto; display: grid; place-items: center; }
.row-divide + .row-divide { border-top: 1px solid var(--line-2); }

.sec-label {
  padding: 16px 16px 8px;
  font-size: calc(12.5px * var(--fs)); font-weight: 700; color: var(--text-3);
  display: flex; align-items: center; justify-content: space-between;
}
.sec-right { font-weight: 500; font-size: calc(12px * var(--fs)); }

/* 可折叠的分区标题（点标题行展开 / 收起）。
   场景：「我加入的社区」—— 内容和「联系人 → 我的群组」重复，
   默认收起，需要时才铺开。 */
.sec-toggle { cursor: pointer; }
.sec-toggle .sec-right { display: inline-flex; align-items: center; gap: 2px; color: var(--accent); }
.sec-chev { display: inline-flex; transition: transform var(--dur) var(--ease); }
.sec-chev.open { transform: rotate(90deg); }

/* 开关 */
.switch {
  width: 46px; height: 28px; border-radius: 14px;
  background: var(--surface-3); position: relative;
  transition: background var(--dur-slow) var(--ease); flex: 0 0 auto;
}
.switch::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .22);
  transition: transform var(--dur-slow) var(--ease);
}
.switch.on { background: var(--green); }
.switch.on::after { transform: translateX(18px); }

/* =========================================================
   搜索条
   ========================================================= */
.searchbar {
  display: flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 12px;
  margin: 0 16px 12px;
  background: var(--surface-2);
  border-radius: 18px;
  color: var(--text-3); font-size: calc(13.5px * var(--fs));
  cursor: pointer;
}
/* 入口条的占位文案必须**永远单行**。
   原来没有 nowrap，长一点的提示（「搜索地区 / 社区 / 商家 / 工种 / 招聘 /
   商品 / 服务人员」）会折成两行，而 .searchbar 是固定 38px 高 ——
   折行后第二行直接贴着下边缘，看起来像被裁掉一截。
   文案本身也一并缩短，双保险。

   ⚠️ 选择器必须限定到具名类 `.sb-ph`，**不能写成 `.searchbar > span`** ——
   真搜索框里还有一个 span 是「清除」按钮，被这条规则一起命中后
   拿到 `flex: 1`，于是被撑成一条横贯搜索框的灰条，X 挤在最左边。
   表现是「搜索框里多出一块方的」，而且完全不报错。
   凡是「元素名 + 结构」型的选择器，只要容器里以后可能加同类元素，
   就会静默误伤 —— 改成具名类，多写一个 class 换一个不会踩的坑。 */
.searchbar > .sb-ph {
  flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.searchbar > svg { flex: 0 0 auto; }

/* 真搜索框里的 input。
   ⚠️ 之前**完全没有这条规则** —— input 用的是浏览器默认样式：
   白底 + 2px 内凹边框 + 固定宽度（约 170px）。放进圆角胶囊里
   就是一块突兀的白色方框，老板说的「割裂感」就是从这里来的。
   加了一条「元素名 + 结构」型选择器（`.searchbar > span`）却没加
   input 的，是因为入口条里根本没有 input —— 只照着入口条写样式，
   真搜索框那条链路就被漏掉了。

   min-width: 0 是必须的：flex 子项默认 `min-width: auto`，
   placeholder 一长就把整条撑破，而不是省略号。 */
.searchbar > input {
  flex: 1 1 auto; min-width: 0; height: 100%;
  padding: 0; border: none; outline: none; background: transparent;
  color: var(--text); font-family: inherit;
  font-size: calc(13.5px * var(--fs));
}
.searchbar > input::placeholder { color: var(--text-3); }

/* 「清除」按钮。裸图标，**不带底色和内边距** ——
   点击区靠 width/height 撑到 28px，够手指点，但视觉上只有那个 X。
   `flex: 0 0 auto` 必须显式写：不写就会被上面那条（现在已改具名的）
   兄弟规则或者未来的某条规则撑宽。

   ⚠️ 它默认是**隐藏**的（`display: none`），有输入才 `on`。
   常显的话，输入框空着的时候点它什么也不会发生 ——
   用户会得出「这个按钮是坏的」的结论。一个按了没反应的按钮，
   比没有这个按钮更糟。 */
.searchbar > .search-x {
  flex: 0 0 auto; display: none;
  width: 28px; height: 28px; margin: 0 -6px 0 0;
  align-items: center; justify-content: center;
  border-radius: 50%; background: transparent;
  color: var(--text-3); cursor: pointer;
}
.searchbar > .search-x.on { display: inline-flex; }
.searchbar > .search-x:active { background: var(--surface-3); color: var(--text-2); }
.searchbar:active { background: var(--surface-3); }

/* =========================================================
   会话列表
   ========================================================= */
.chat-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  background: var(--surface);
  cursor: pointer; position: relative;
  transition: background var(--dur) var(--ease);
}
.chat-item:active { background: var(--surface-2); }
.ci-main { flex: 1; min-width: 0; }
.ci-r1 { display: flex; align-items: baseline; gap: 6px; }
.ci-name {
  /* 老板要求：比联系人页的名字（.row-t = 15px/500）大两号并加粗 → 17px/700。
     会话列表是「扫一眼找人」的场景，名字必须比联系人页更抢眼；
     但也不能像之前那样被覆盖成 19px/800 —— 那样一行放不下、
     长名字全被省略号截断，反而更难找人。 */
  font-size: calc(17px * var(--fs)); font-weight: 700; flex: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: flex; align-items: center; gap: 6px;
}
.ci-time { font-size: calc(11.5px * var(--fs)); color: var(--text-3); flex: 0 0 auto; }
.ci-r2 { display: flex; align-items: center; gap: 6px; margin-top: 4px; }
.ci-prev {
  flex: 1; font-size: calc(13px * var(--fs)); color: var(--text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ci-badge {
  min-width: 19px; height: 19px; padding: 0 6px;
  border-radius: 10px; background: var(--red); color: #fff;
  font-size: calc(11px * var(--fs)); font-weight: 700;
  display: grid; place-items: center; flex: 0 0 auto;
}
.ci-badge.mute { background: var(--text-3); }
.ci-mute { color: var(--text-3); display: grid; place-items: center; }

/* =========================================================
   聊天页
   ========================================================= */
.chat-body {
  flex: 1; overflow-y: auto; min-height: 0;
  padding: 16px 0 12px;
  background: var(--bg);
  background-image: radial-gradient(circle at 1px 1px, rgba(140, 153, 176, .14) 1px, transparent 0);
  background-size: 24px 24px;
}
.msg-day { display: flex; justify-content: center; margin: 12px 0 10px; }
.msg-day span {
  padding: 4px 12px; border-radius: 10px;
  background: rgba(16, 24, 40, .06); color: var(--text-2);
  font-size: calc(11px * var(--fs)); font-weight: 600;
}
[data-theme="dark"] .msg-day span { background: rgba(255, 255, 255, .08); }
.msg-sys { display: flex; justify-content: center; margin: 8px 0; }
.msg-sys span {
  max-width: 78%; padding: 6px 12px; border-radius: 10px;
  background: rgba(16, 24, 40, .06); color: var(--text-2);
  font-size: calc(12px * var(--fs)); text-align: center; line-height: 1.45;
}
[data-theme="dark"] .msg-sys span { background: rgba(255, 255, 255, .08); }

.msg-row {
  display: flex; align-items: flex-end; gap: 8px;
  padding: 4px 16px;
  animation: msgIn var(--dur-slow) cubic-bezier(.22, 1, .36, 1);
}
@keyframes msgIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.msg-row.out { flex-direction: row-reverse; }
.msg-row.same .av { visibility: hidden; }

.msg-col { max-width: 74%; display: flex; flex-direction: column; min-width: 0; }
.msg-row.out .msg-col { align-items: flex-end; }
.msg-sender { font-size: calc(12px * var(--fs)); font-weight: 700; margin: 0 0 4px 4px; }

.bubble {
  padding: 10px 12px; border-radius: 18px;
  background: var(--surface); color: var(--text);
  font-size: calc(15px * var(--fs)); line-height: 1.45;
  box-shadow: var(--shadow-sm);
  word-break: break-word; white-space: pre-wrap;
}
.msg-row.out .bubble {
  background: linear-gradient(135deg, #2F6BFF, #4B82FF);
  color: #fff; box-shadow: 0 2px 10px rgba(47, 107, 255, .24);
}
.bubble.first { border-bottom-left-radius: 5px; }
.msg-row.out .bubble.first { border-bottom-left-radius: 16px; border-bottom-right-radius: 5px; }

/* 消息元信息行：时间 · 已读 ·（管理员可见的）删除按钮。
   flex 是为了让删除按钮与文字垂直居中对齐 ——
   写成两个独立规则也能生效，但「同一个类在两个地方各写一半」
   是后面改坏它的最常见原因，所以合并成一处。 */
.msg-meta {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: calc(10.5px * var(--fs)); color: var(--text-3); margin: 4px 4px 0;
}

/* 纯文字气泡才需要 pre-wrap（保留用户输入里的换行）。
   卡片类气泡内部是缩进换行的 HTML 模板，pre-wrap 会把缩进空格与换行
   当成真实文字渲染 → 每个块之间凭空多出 2 行（line-height×2 ≈ 45px）空洞，
   行首 12 个缩进空格还会把内容顶到右边被 overflow:hidden 裁掉。
   所以卡片气泡必须显式重置回 normal。 */
.bubble.card { padding: 0; overflow: hidden; background: var(--surface); color: var(--text); white-space: normal; }
.msg-row.out .bubble.card { background: var(--surface); color: var(--text); }
.bubble.card .feed-mini, .bubble.card .svc-card, .bubble.card .file-msg, .bubble.card .ch-post { white-space: normal; }

/* 图片消息 */
/* 图片气泡：直接铺照片本身（photoArt 生成的 SVG）。
   以前这里是一块紫蓝渐变 + 一行「图片」文字 ——
   同一个东西在「最近照片」里是照片、在聊天里是色块，
   两处长得不一样，就是割裂。现在两处用同一个 photoArt()。 */
.img-msg {
  width: 210px; height: 150px; position: relative; overflow: hidden;
  background: var(--surface-2);
}
.img-msg .ph-art { width: 100%; height: 100%; display: block; }
.img-msg .img-cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 24px 12px 10px;
  background: linear-gradient(transparent, rgba(0, 0, 0, .62));
  color: #fff; font-size: calc(11.5px * var(--fs)); line-height: 1.45;
}
/* 图片气泡整体可点（点开查看器），给一点按下反馈 */
.img-bubble { cursor: pointer; transition: opacity var(--dur) var(--ease); }
.img-bubble:active { opacity: .86; }
/* 文件消息 */
.file-msg { display: flex; align-items: center; gap: 12px; min-width: 200px; }
.file-ico {
  width: 40px; height: 40px; border-radius: 10px;
  background: var(--accent-soft); color: var(--accent);
  display: grid; place-items: center; flex: 0 0 auto;
}
.file-name { font-size: calc(14px * var(--fs)); font-weight: 600; }
.file-size { font-size: calc(11.5px * var(--fs)); color: var(--text-2); margin-top: 2px; line-height: 1.45; }
/* 被安全策略拦下的文件气泡：不给下载入口，所以也不给可点击的样子 ——
   灰显 + 无 active 反馈，避免用户反复去点。 */
.file-msg.blocked { min-width: 200px; }
.file-msg.blocked .file-ico.blocked { background: var(--red-soft); color: var(--red); }
.file-msg.blocked .file-name { color: var(--text-2); text-decoration: line-through; }

/* =========================================================
   文件与链接安全（安全传输）
   ========================================================= */
/* 发送文件弹层里的待发清单 */
.fp-note {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 10px 12px; margin-bottom: 10px; border-radius: 14px;
  background: var(--accent-soft); color: var(--text-2);
  font-size: calc(12px * var(--fs)); line-height: 1.6;
}
.fp-note svg { flex: 0 0 auto; margin-top: 2px; color: var(--accent); }
.fp-list { display: flex; flex-direction: column; gap: 8px; }
.fp-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--line);
  transition: background var(--dur) var(--ease);
}
.fp-row:active { background: var(--surface-2); }
/* 被禁的行不做灰化 —— 用户需要看清「为什么不行」，
   灰掉反而让人以为点不动、看不到原因。用左侧红边提示即可。 */
.fp-row.bad { border-left: 3px solid var(--red); }
.fp-ico {
  width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center; flex: 0 0 auto;
}
.fp-main { flex: 1; min-width: 0; }
.fp-n { display: block; font-size: calc(13.5px * var(--fs)); font-weight: 600; word-break: break-all; }
.fp-d { display: block; font-size: calc(11.5px * var(--fs)); color: var(--text-2); margin-top: 2px; line-height: 1.45; }
.fp-tag {
  flex: 0 0 auto; padding: 4px 8px; border-radius: 6px;
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.fp-foot {
  display: flex; gap: 8px; align-items: flex-start;
  margin-top: 12px; font-size: calc(11.5px * var(--fs)); color: var(--text-3); line-height: 1.6;
}
.fp-foot svg { flex: 0 0 auto; margin-top: 2px; }

/* 策略页 */
.fpo-hero {
  display: flex; gap: 12px; align-items: flex-start;
  margin: 0 16px 12px; padding: 16px 16px; border-radius: 14px;
  background: linear-gradient(135deg, #2F6BFF 0%, #7A5AF8 100%);
  color: #fff;
}
.fpo-hero svg { flex: 0 0 auto; margin-top: 2px; }
.fpo-t { font-size: calc(15.5px * var(--fs)); font-weight: 800; }
.fpo-d { font-size: calc(12px * var(--fs)); line-height: 1.6; margin-top: 4px; opacity: .92; }
.fpo-stat {
  display: flex; gap: 6px; margin: 0 16px 6px;
}
.fpo-stat span {
  flex: 1; min-width: 0; text-align: center;
  padding: 10px 4px; border-radius: 10px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: calc(10.5px * var(--fs)); color: var(--text-3); line-height: 1.4;
}
.fpo-stat b { display: block; font-size: calc(15px * var(--fs)); font-weight: 800; color: var(--text); }
.fpo-card { margin: 0 16px 12px; padding: 4px 0; }
.fpo-row { display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px; }
.fpo-ico {
  width: 32px; height: 32px; border-radius: 10px;
  display: grid; place-items: center; flex: 0 0 auto;
}
.fpo-main { flex: 1; min-width: 0; }
.fpo-n { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
/* 扩展名 chip 会换行，所以必须 flex-wrap —— 不换行会横向溢出屏幕 */
.fpo-exts { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.fpo-ext {
  padding: 2px 6px; border-radius: 6px;
  background: var(--surface-3); color: var(--text-2);
  font-size: calc(10.5px * var(--fs)); font-weight: 600;
}
.fpo-ext.bad { background: var(--red-soft); color: var(--red); }
.fpo-ext.ok { background: var(--green-soft); color: var(--green); }
.fpo-reasons { margin-top: 6px; }
.fpo-r { font-size: calc(11.5px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.fpo-r b { color: var(--text); font-weight: 700; margin-right: 6px; }
.fpo-rule { padding: 12px 16px; }
.fpo-rule-t { font-size: calc(13px * var(--fs)); font-weight: 700; }
.fpo-rule-c { font-size: calc(12px * var(--fs)); color: var(--text-2); line-height: 1.6; margin-top: 4px; }

/* 拦截记录 */
.sb-item {
  margin: 0 16px 10px; padding: 12px 16px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--line);
}
.sb-h { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.sb-kind {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs)); font-weight: 700;
}
.sb-time { font-size: calc(11px * var(--fs)); color: var(--text-3); }
.sb-target {
  font-size: calc(13px * var(--fs)); font-weight: 600; margin-top: 8px;
  word-break: break-all; line-height: 1.45;
}
.sb-reason { font-size: calc(11.5px * var(--fs)); color: var(--text-2); line-height: 1.6; margin-top: 4px; }
.sb-foot {
  display: flex; justify-content: space-between; gap: 8px;
  margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line-2);
  font-size: calc(11px * var(--fs)); color: var(--text-3);
}

/* 语音 */
.voice-msg { display: flex; align-items: center; gap: 10px; min-width: 120px; }
.voice-ico {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent); color: #fff;
  display: grid; place-items: center; flex: 0 0 auto;
}
.wave { display: flex; align-items: center; gap: 2px; height: 20px; flex: 1; }
.wave i { display: block; width: 2.5px; border-radius: 4px; background: currentColor; opacity: .5; }
.voice-msg.playing .wave i { animation: waveA .85s ease-in-out infinite; opacity: .9; }
@keyframes waveA { 0%, 100% { transform: scaleY(.45); } 50% { transform: scaleY(1); } }
.voice-dur { font-size: calc(11.5px * var(--fs)); opacity: .75; }
/* 通话记录 */
.call-msg { display: flex; align-items: center; gap: 10px; min-width: 170px; }
.call-ico {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--green-soft); color: var(--green);
  display: grid; place-items: center; flex: 0 0 auto;
}
.call-t { font-size: calc(14px * var(--fs)); font-weight: 600; }
.call-d { font-size: calc(11.5px * var(--fs)); color: var(--text-2); margin-top: 2px; }
/* 服务通知卡 */
.svc-card { width: 244px; padding: 16px; background: var(--surface); }
.svc-t { font-size: calc(14.5px * var(--fs)); font-weight: 700; margin-bottom: 6px; }
.svc-d { font-size: calc(13px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.svc-btn {
  margin-top: 12px; padding: 8px 16px; border-radius: 10px;
  background: var(--accent); color: #fff; font-size: calc(13px * var(--fs)); font-weight: 600;
}
/* 公域内容消息（社区频道内） */
/* 会话里分享的内容卡（窄态）：宽度必须跟着父级走。
   原先写死 width:250px，而父级 .msg-col 被 max-width:74% 压到 ~236px，
   子元素比父元素宽 14px → 被 .bubble.card 的 overflow:hidden 从右侧裁掉，
   表现就是时间「今天 09:05」和正文里的数字被切一半。 */
.feed-mini { width: 100%; padding: 12px; background: var(--surface); box-sizing: border-box; }
.feed-mini .fm-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.feed-mini .fm-name { font-size: calc(13px * var(--fs)); font-weight: 700; flex: 1; min-width: 0; }
.feed-mini .fm-time { font-size: calc(11px * var(--fs)); color: var(--text-3); margin-left: auto; flex: 0 0 auto; }
.feed-mini .fm-title { font-size: calc(14.5px * var(--fs)); font-weight: 700; margin-bottom: 6px; }
.feed-mini .fm-text { font-size: calc(13px * var(--fs)); color: var(--text-2); line-height: 1.6; }

/* =========================================================
   社区频道 · 图文宣传卡（满宽，图片 + 文字）
   频道是「只读宣传窗口」，卡片自己承载作者/时间/类型，
   因此不再需要 msg-row 的头像、发送者名与气泡外的时间戳。
   ========================================================= */
.ch-post-wrap { padding: 6px 16px; }
.ch-post {
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--shadow-sm); overflow: hidden; cursor: pointer;
  transition: transform var(--dur) var(--ease);
}
.ch-post:active { transform: scale(.99); }
.ch-post .cp-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 12px 0;
}
.ch-post .cp-who { flex: 1; min-width: 0; }
.ch-post .cp-name {
  font-size: calc(13.5px * var(--fs)); font-weight: 700;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.ch-post .cp-meta { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 2px; }
.ch-post .cp-type {
  flex: 0 0 auto; padding: 4px 10px; border-radius: 6px;
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.ch-post .cp-title {
  padding: 12px 12px 0;
  font-size: calc(15.5px * var(--fs)); font-weight: 700; line-height: 1.45;
}
.ch-post .cp-text {
  padding: 6px 12px 0;
  font-size: calc(13.5px * var(--fs)); color: var(--text-2); line-height: 1.7;
}
.ch-post .cp-tags { padding: 10px 12px 0; }
.ch-post .cp-foot {
  display: flex; align-items: center; gap: 16px;
  margin-top: 12px; padding: 10px 12px;
  border-top: 1px solid var(--line-2);
  font-size: calc(12.5px * var(--fs)); color: var(--text-3);
}
.ch-post .cp-foot .spacer { flex: 1; }
.ch-post .cp-go { color: var(--accent); font-weight: 600; display: inline-flex; align-items: center; gap: 2px; }

/* 图片占位块（零依赖：渐变底 + 图标 + 说明，模拟配图） */
.photo-block {
  position: relative; margin-top: 10px;
  display: grid; overflow: hidden;
  /* 基础高度必须有：之前只有「频道卡 / 信息流卡」两种场景写了高度，
     聊天气泡里的图文卡（.fm-）没有，于是那一块塌成一条细缝 ——
     正是老板说的「排版不好看」。下面三个场景各自覆盖，互不影响。 */
  height: 150px;
}
/* 图片铺满整块。用 grid-area 叠在同一格里，
   这样容器的显式 height 与图片尺寸互不干扰。 */
.photo-block > .ph-art { grid-area: 1 / 1; width: 100%; height: 100%; display: block; }
/* 真照片（<img class="ph-art">）要 object-fit: cover ——
   SVG 插画会自己撑满，位图不会：不加这句，一张竖图会被拉扁。
   注意选择器要带 img，不然会覆盖到 SVG 上（对它无效但容易误读）。 */
img.ph-art { object-fit: cover; }
.photo-block .ph-cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 20px 12px 10px; text-align: left;
  background: linear-gradient(transparent, rgba(0, 0, 0, .62));
  color: #fff;
  font-size: calc(11.5px * var(--fs)); font-weight: 600;
}
.photo-block.inset { border-radius: 10px; margin-left: 12px; margin-right: 12px; }
.ch-post .photo-block.inset { margin-bottom: 0; }
.ch-post .photo-block { height: 168px; }
.feed-card .photo-block { height: 152px; border-radius: 10px; }
.feed-mini .photo-block { height: 118px; border-radius: 10px; }

/* 输入区 */
.composer {
  flex: 0 0 auto;
  background: var(--surface);
  border-top: 1px solid var(--line);
  /* 与底部导航同理：输入栏是聊天页最下沿的固定层，
     朝上的阴影让消息从它下面滑进去。 */
  box-shadow: var(--shadow-up);
  padding: 8px 12px 10px;
}
.composer-tools { display: flex; gap: 6px; padding-bottom: 8px; overflow-x: auto; }
.composer-tools::-webkit-scrollbar { display: none; }
.ctool {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 12px; border-radius: 14px;
  background: var(--surface-2); color: var(--text-2);
  font-size: calc(12.5px * var(--fs)); font-weight: 600; white-space: nowrap;
  border: 1px solid var(--line);
}
.ctool:active { background: var(--accent-soft); color: var(--accent); }
.composer-box {
  display: flex; align-items: flex-end; gap: 8px;
  background: var(--surface-2); border-radius: 18px;
  padding: 6px 6px 6px 16px;
  border: 1px solid var(--line);
}
.composer-box:focus-within { border-color: var(--accent); }
.composer-box textarea {
  flex: 1; resize: none; max-height: 90px; min-height: 24px;
  font-size: calc(15px * var(--fs)); line-height: 1.45; padding: 4px 0;
}
.composer-box textarea::placeholder { color: var(--text-3); }
.send-btn {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--accent); color: #fff;
  display: grid; place-items: center; flex: 0 0 auto;
}
.send-btn:disabled { opacity: .4; }
.composer-foot {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px 12px;
  background: var(--surface); border-top: 1px solid var(--line);
  font-size: calc(12.5px * var(--fs)); color: var(--text-2);
}
.composer-foot .cf-text { flex: 1; }

/* =========================================================
   按钮
   ========================================================= */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 12px 20px; border-radius: 14px;
  font-size: calc(15px * var(--fs)); font-weight: 700;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.btn:active { transform: scale(.97); }
.btn.primary { background: var(--accent); color: #fff; }
.btn.green { background: var(--green); color: #fff; }
.btn.danger { background: var(--red); color: #fff; }
.btn.ghost { background: var(--surface-2); color: var(--text-2); border: 1px solid var(--line); }
.btn.line { background: transparent; color: var(--accent); border: 1.5px solid var(--accent); }
.btn.block { width: 100%; }
.btn.sm { padding: 8px 16px; font-size: calc(13px * var(--fs)); border-radius: 10px; }
.btn:disabled { opacity: .45; pointer-events: none; }

/* =========================================================
   卡片
   ========================================================= */
.card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.card-pad { padding: 16px; }
.card-t { font-size: calc(15.5px * var(--fs)); font-weight: 700; margin-bottom: 8px; }
.card-d { font-size: calc(13.5px * var(--fs)); color: var(--text-2); line-height: 1.6; }

/* 社区头卡 */
.cm-hero {
  padding: 20px 16px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.cm-hero-top { display: flex; align-items: center; gap: 12px; }
.cm-hero-info { flex: 1; min-width: 0; }
.cm-hero-name { font-size: calc(19px * var(--fs)); font-weight: 800; display: flex; align-items: center; gap: 6px; }
.cm-hero-sub { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 4px; }
/* 社区页顶部：成员概览（点进成员页）+ 搜索。
   紧贴导航栏、上边不加分隔线，和导航栏读成一整块；
   下边用一条分隔线收口，和下面的简介 / 评议庭分开。 */
.cm-top {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
/* 2026-09-21 改版：这一行原来堆了四组计数（成员 / 认证商家 / 服务人员 /
   招聘）再加两行角色（社区长 / 管理员），老板要求「只显示一个人数，
   点一下和地区」，详细名册收进成员页。
   所以现在整行只有「N 成员 · 地区」+ 一个指向成员页的箭头，点整行进成员页。
   2026-09-21 二次收敛：连「全部成员」四个字也去掉（老板要「只显示一个人数」），
   只留一个淡箭头 —— 名册入口退到背景里，但整行依然可点。 */
.cm-people {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px;
  transition: background var(--dur) var(--ease);
}
.cm-people:active { background: var(--surface-2); }
/* 成员数：现在是首屏唯一一行「社区规模」信息，
   字号比原来那四组弱化色计数大一档，让它在整行里立得住。 */
.cm-people > .cmp-u {
  flex: 0 0 auto; white-space: nowrap;
  font-size: calc(12.5px * var(--fs)); color: var(--text-2);
}
.cm-people > .cmp-u b {
  font-size: calc(15px * var(--fs)); font-weight: 800; color: var(--text);
  margin-right: 2px;
}
/* 分隔圆点：用元素而不是「·」字符 ——
   用字符时换行会在行首留下一个孤零零的圆点。 */
.cm-people > i {
  width: 3px; height: 3px; border-radius: 50%; background: var(--text-3);
  opacity: .45; flex: 0 0 auto;
}
/* 地区：窄屏用省略号收尾，绝不换行（换行会把整行撑成两行）。 */
.cmp-addr {
  flex: 1; min-width: 0;
  font-size: calc(12.5px * var(--fs)); color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 成员页入口箭头：只留一个「›」，颜色压到最淡。
   老板要的是「只显示一个人数」，所以这里不能有字；
   但整行可点这件事需要一点提示，用最弱的灰箭头承担。 */
.cmp-go {
  flex: 0 0 auto; display: inline-flex; align-items: center;
  color: var(--text-3); opacity: .7;
}

/* 社区成员页 */
.cmr-hero {
  margin: 0 16px 16px; padding: 16px 16px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
}
/* 头部：社区头像 + 名称 + 人数/地区（对齐 QQ 群 / Telegram 频道的群资料页） */
.cmr-head { display: flex; align-items: center; gap: 12px; }
.cmr-headmain { flex: 1; min-width: 0; }
.cmr-name {
  font-size: calc(16px * var(--fs)); font-weight: 800;
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
}
.cmr-sub { font-size: calc(12px * var(--fs)); color: var(--text-3); margin-top: 4px; }
.cmr-t { font-size: calc(17px * var(--fs)); font-weight: 800; }
.cmr-d { font-size: calc(12px * var(--fs)); color: var(--text-2); margin-top: 4px; line-height: 1.45; }

/* 一排操作按钮：参考 Telegram 频道页那四个 ——
   图标在上、文字在下，等宽平分。 */
.cmr-acts {
  display: flex; gap: 8px; margin-top: 14px;
  padding-top: 14px; border-top: 1px solid var(--line-2);
}
.cmr-act {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 10px 4px; border-radius: 10px;
  background: var(--surface-2); color: var(--text-2);
  font-size: calc(11.5px * var(--fs)); font-weight: 600;
  transition: background var(--dur) var(--ease);
}
.cmr-act:active { background: var(--surface-3); }
.cmr-act.danger { color: #F04438; }

/* 成员行里的角色徽章（社区长 / 管理员）——
   老板要求「管理有管理的图标」，这一条就是那个图标。 */
.cmr-role {
  display: inline-flex; align-items: center; gap: 3px;
  margin-left: 6px; padding: 2px 6px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs)); font-weight: 700; vertical-align: 1px;
}
.cmr-hint { font-weight: 500; font-size: calc(11.5px * var(--fs)); color: var(--text-3); }
.cmr-card { margin: 0 16px 12px; padding: 4px 0; }
.cmr-chip {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 6px; padding: 2px 6px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs)); font-weight: 700; vertical-align: 1px;
}
.cmr-me {
  display: inline-block; margin-left: 6px; padding: 2px 6px;
  border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 800;
  background: var(--accent-soft); color: var(--accent);
}
/* 社区简介：必须带左右留白，否则文字会顶到屏幕边缘 */
.cm-intro {
  font-size: calc(13.5px * var(--fs)); color: var(--text-2); line-height: 1.6;
  margin-top: 12px; padding: 0 16px;
}

/* 社区内部模块宫格 */
.mod-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px; padding: 0 16px;
}
.mod-cell {
  position: relative;
  background: var(--surface); border-radius: 14px;
  padding: 16px 8px 12px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  box-shadow: var(--shadow-sm);
  cursor: pointer; transition: transform var(--dur) var(--ease);
}
.mod-cell:active { transform: scale(.96); }
.mod-cell .mc-ico {
  width: 38px; height: 38px; border-radius: 14px;
  display: grid; place-items: center;
}
.mod-cell .mc-t {
  font-size: calc(12.5px * var(--fs)); font-weight: 600;
  line-height: 1.3; text-align: center;
}
/* 数量角标绝对定位在图标右上角 —— 若按文档流多占一行，
   带计数的格子会比不带计数的高出 23px，宫格高度参差不齐 */
.mod-cell .mc-n {
  position: absolute; top: 7px; right: 8px;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--surface-3); color: var(--text-2);
  font-size: calc(10px * var(--fs)); font-weight: 700;
}

/* =========================================================
   公域信息流卡片
   ========================================================= */
.feed-card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px;
  box-shadow: var(--shadow-sm);
}
.feed-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.feed-card.is-pin { border: 1px solid var(--accent-weak, rgba(47,107,255,.28)); }
.pin-flag svg { width: 12px; height: 12px; }
.feed-who { flex: 1; min-width: 0; }
.feed-name { font-size: calc(14px * var(--fs)); font-weight: 700; display: flex; align-items: center; gap: 6px; }
.feed-meta { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 2px; }
.feed-type {
  padding: 2px 8px; border-radius: 6px; font-size: calc(11px * var(--fs)); font-weight: 700;
}
.feed-title { font-size: calc(15.5px * var(--fs)); font-weight: 700; line-height: 1.45; margin-bottom: 6px; }
.feed-text { font-size: calc(14px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.feed-img {
  height: 152px; border-radius: 10px; margin-top: 10px;
  display: grid; place-items: center;
  color: rgba(255, 255, 255, .93); font-size: calc(12.5px * var(--fs)); font-weight: 600;
}
.feed-tags { margin-top: 10px; }
.feed-foot {
  display: flex; align-items: center; gap: 16px;
  margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--line-2);
  font-size: calc(12.5px * var(--fs)); color: var(--text-3);
}
.feed-act { display: inline-flex; align-items: center; gap: 4px; }
.feed-act.on { color: var(--red); font-weight: 700; }
.feed-foot .spacer { flex: 1; }
.pin-flag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  background: var(--amber-soft); color: var(--amber);
  font-size: calc(10.5px * var(--fs)); font-weight: 700;
}

/* =========================================================
   商家卡
   ========================================================= */
/* ---------------- 商家卡（单行列表态） ---------------- */
.mch-card {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 10px; padding: 12px 12px;
  box-shadow: var(--shadow-sm); cursor: pointer;
  transition: transform var(--dur) var(--ease);
}
.mch-card:active { transform: scale(.985); }
.mch-card .av { flex: 0 0 auto; }
.mch-card .row-arrow { margin-left: 2px; }
.mch-main { flex: 1; min-width: 0; }
.mch-top { display: flex; align-items: center; gap: 12px; }
.mch-info { flex: 1; min-width: 0; }
.mch-name { font-size: calc(15.5px * var(--fs)); font-weight: 700; display: flex; align-items: center; gap: 6px; }
.mch-desc { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 4px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.mch-tags { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px; }
.mch-acts { display: flex; gap: 8px; margin-top: 12px; }

.goods-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 0; border-top: 1px solid var(--line-2);
}
.goods-img {
  width: 52px; height: 52px; border-radius: 10px;
  display: grid; place-items: center; color: #fff;
  font-size: calc(15px * var(--fs)); font-weight: 700; flex: 0 0 auto;
}
.goods-main { flex: 1; min-width: 0; }
.goods-name { font-size: calc(14.5px * var(--fs)); font-weight: 600; }
.goods-desc { font-size: calc(12px * var(--fs)); color: var(--text-2); margin-top: 2px; }
.goods-price { font-size: calc(16px * var(--fs)); font-weight: 800; color: var(--red); flex: 0 0 auto; }
.goods-price small { font-size: calc(11px * var(--fs)); font-weight: 700; }

/* =========================================================
   任务卡
   ========================================================= */
.task-card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px;
  box-shadow: var(--shadow-sm);
}
.task-top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.task-type {
  padding: 4px 10px; border-radius: 6px; font-size: calc(11.5px * var(--fs)); font-weight: 700;
}
.task-reward { margin-left: auto; font-size: calc(17px * var(--fs)); font-weight: 800; color: var(--red); }
.task-reward small { font-size: calc(11px * var(--fs)); }
.task-title { font-size: calc(15px * var(--fs)); font-weight: 700; margin-bottom: 6px; }
.task-desc { font-size: calc(13px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.task-foot {
  display: flex; align-items: center; gap: 10px;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line-2);
  font-size: calc(12px * var(--fs)); color: var(--text-3);
}
.task-foot .spacer { flex: 1; }

/* =========================================================
   投诉
   ========================================================= */
.cp-card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px;
  box-shadow: var(--shadow-sm); cursor: pointer;
}
.cp-top { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.cp-no { font-size: calc(11.5px * var(--fs)); color: var(--text-3); font-family: ui-monospace, monospace; }
.cp-status {
  margin-left: auto; padding: 4px 10px; border-radius: 6px;
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.cp-title { font-size: calc(15px * var(--fs)); font-weight: 700; margin-bottom: 6px; }
.cp-desc { font-size: calc(13px * var(--fs)); color: var(--text-2); line-height: 1.6;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* 时间线 */
.timeline { padding: 4px 0; }
.tl-item { display: flex; gap: 12px; padding-bottom: 16px; position: relative; }
.tl-item:not(:last-child)::before {
  content: ''; position: absolute; left: 6.5px; top: 16px; bottom: 0;
  width: 1.5px; background: var(--line);
}
.tl-dot {
  width: 14px; height: 14px; border-radius: 50%; flex: 0 0 auto;
  background: var(--accent); margin-top: 2px;
  border: 3px solid var(--accent-soft); box-sizing: content-box;
}
.tl-item:first-child .tl-dot { background: var(--green); border-color: var(--green-soft); }
.tl-main { flex: 1; min-width: 0; }
.tl-t { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
.tl-n { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 4px; line-height: 1.6; }
.tl-time { font-size: calc(11px * var(--fs)); color: var(--text-3); margin-top: 4px; }

/* =========================================================
   表单
   ========================================================= */
.field { margin-bottom: 16px; }
.field > label {
  display: block; font-size: calc(13px * var(--fs)); font-weight: 700;
  color: var(--text-2); margin-bottom: 8px;
}
.field input, .field textarea, .field select {
  width: 100%; padding: 12px 12px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 10px; font-size: calc(15px * var(--fs));
  transition: border-color var(--dur) var(--ease);
}
.field input:focus, .field textarea:focus, .field select:focus { border-color: var(--accent); }
.field textarea { resize: none; line-height: 1.6; }
.field .hint { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 6px; line-height: 1.6; }
.field .hint.err { color: var(--red); }
.field .hint.ok { color: var(--green); }

.opt-list { display: flex; flex-direction: column; gap: 8px; }
.opt {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-radius: 14px;
  background: var(--surface-2); border: 1.5px solid var(--line);
  cursor: pointer; transition: all var(--dur) var(--ease);
}
.opt.on { border-color: var(--accent); background: var(--accent-soft); }
.opt-ico {
  width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center; flex: 0 0 auto;
  background: var(--surface); color: var(--text-2);
}
.opt.on .opt-ico { background: var(--accent); color: #fff; }
.opt-main { flex: 1; min-width: 0; }
.opt-t { font-size: calc(14.5px * var(--fs)); font-weight: 600; }
.opt-d { font-size: calc(12px * var(--fs)); color: var(--text-2); margin-top: 2px; }
.opt-check { color: var(--accent); opacity: 0; }
.opt.on .opt-check { opacity: 1; }

/* ---------------- 选择器字段（点开底部弹层选，替代挤成一排的选项组） ----------------
   用法：类型多到一行放不下时（任务类型 14 项 / 工种 32 项 / 岗位类型 8 项），
   表单里只占一行显示当前选中项，点开弹层看完整列表。 */
.pick-row {
  width: 100%; display: flex; align-items: center; gap: 10px;
  padding: 12px 12px; text-align: left;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 10px; transition: border-color var(--dur) var(--ease);
}
.pick-row:active { border-color: var(--accent); }
.pr-ico {
  width: 30px; height: 30px; flex: 0 0 30px; border-radius: 10px;
  display: grid; place-items: center;
}
.pr-main { flex: 1; min-width: 0; }
.pr-t { display: block; font-size: calc(14.5px * var(--fs)); font-weight: 600; }
.pr-d {
  display: block; font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pr-arrow { flex: 0 0 auto; color: var(--text-3); display: flex; }

.pick-list { max-height: 52vh; overflow-y: auto; margin: -4px 0 8px; }
.pick-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 4px; border-bottom: 1px solid var(--line-2);
  cursor: pointer;
}
.pick-item:last-child { border-bottom: 0; }
.pi-ico {
  width: 34px; height: 34px; flex: 0 0 34px; border-radius: 10px;
  display: grid; place-items: center;
}
.pi-main { flex: 1; min-width: 0; }
.pi-t {
  display: flex; align-items: center; gap: 6px;
  font-size: calc(14.5px * var(--fs)); font-weight: 600;
}
.pi-tag {
  padding: 2px 6px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs)); font-weight: 700; flex: 0 0 auto;
}
.pi-d {
  font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 4px; line-height: 1.45;
}
.pi-check { flex: 0 0 auto; color: var(--accent); opacity: 0; }
.pick-item.on .pi-check { opacity: 1; }
.pick-item.on .pi-t { color: var(--accent); }
.pick-group {
  font-size: calc(11.5px * var(--fs)); font-weight: 700; color: var(--text-3);
  padding: 12px 4px 6px; letter-spacing: .3px;
}
.pick-group:first-child { padding-top: 2px; }

.check-row {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 0; cursor: pointer;
}
.check-box {
  width: 21px; height: 21px; border-radius: 6px;
  border: 2px solid var(--line); flex: 0 0 auto; margin-top: 2px;
  display: grid; place-items: center; color: transparent;
  transition: all var(--dur) var(--ease);
}
.check-row.on .check-box { background: var(--accent); border-color: var(--accent); color: #fff; }
.check-txt { font-size: calc(13.5px * var(--fs)); line-height: 1.6; color: var(--text-2); }

/* =========================================================
   权限矩阵表
   ========================================================= */
.perm-table { width: 100%; border-collapse: collapse; font-size: calc(12.5px * var(--fs)); }
.perm-table th, .perm-table td {
  padding: 10px 4px; text-align: center; border-bottom: 1px solid var(--line-2);
}
.perm-table th { font-size: calc(11px * var(--fs)); color: var(--text-3); font-weight: 700; }
.perm-table td:first-child, .perm-table th:first-child { text-align: left; padding-left: 4px; }
.perm-table td { color: var(--text-2); }
.perm-yes { color: var(--green); font-weight: 800; }
.perm-no { color: var(--text-3); }
.perm-role-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 4px;
}

/* =========================================================
   底部弹层 / 弹窗 / Toast
   ========================================================= */
#sheetRoot, #modalRoot { position: absolute; inset: 0; z-index: 200; pointer-events: none; }
#sheetRoot.open, #modalRoot.open { pointer-events: auto; }
#toastWrap {
  position: absolute; left: 0; right: 0; bottom: 96px;
  z-index: 300; display: flex; flex-direction: column;
  align-items: center; gap: 8px; pointer-events: none; padding: 0 24px;
}

.sheet-mask {
  position: absolute; inset: 0; background: rgba(10, 15, 26, .42);
  display: flex; align-items: flex-end;
  animation: fadeIn .18s ease;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.sheet {
  width: 100%; background: var(--surface);
  border-radius: 18px 18px 0 0;
  padding: 8px 0 10px;
  max-height: 82%; overflow-y: auto;
  animation: sheetUp .26s cubic-bezier(.22, 1, .36, 1);
}
@keyframes sheetUp { from { transform: translateY(100%); } to { transform: none; } }
.sheet-title {
  padding: 16px 20px 12px; font-size: calc(15px * var(--fs)); font-weight: 700; text-align: center;
  border-bottom: 1px solid var(--line-2);
}
.sheet-body { padding: 6px 0; }
.sheet-item {
  display: flex; align-items: center; gap: 12px;
  padding: 16px 20px; font-size: calc(15.5px * var(--fs)); cursor: pointer;
}
.sheet-item:active { background: var(--surface-2); }
.sheet-item .si-ico { color: var(--text-2); display: grid; place-items: center; }
.sheet-item.danger { color: var(--red); }
.sheet-item.danger .si-ico { color: var(--red); }
.sheet-cancel {
  width: calc(100% - 24px); margin: 8px 12px 2px;
  padding: 16px; border-radius: 14px;
  background: var(--surface-2); font-size: calc(15.5px * var(--fs)); font-weight: 700;
  color: var(--text-2);
}

.modal-mask {
  position: absolute; inset: 0; background: rgba(10, 15, 26, .46);
  display: grid; place-items: center; padding: 24px;
  animation: fadeIn .18s ease;
}
.modal {
  width: 100%; max-height: 84%; overflow-y: auto;
  background: var(--surface); border-radius: 18px;
  animation: popIn .24s cubic-bezier(.22, 1, .36, 1);
}
@keyframes popIn { from { opacity: 0; transform: translateY(12px) scale(.97); } to { opacity: 1; transform: none; } }
.modal-head {
  padding: 16px 20px 10px;
  display: flex; align-items: flex-start; gap: 10px;
}
.modal-title { flex: 1; font-size: calc(17px * var(--fs)); font-weight: 700; line-height: 1.4; }
.modal-x { color: var(--text-3); display: grid; place-items: center; padding: 2px; }
.modal-body { padding: 0 20px 16px; }
.modal-foot {
  padding: 12px 20px 16px; display: flex; gap: 10px;
}
.modal-foot .btn { flex: 1; }
.confirm-text { font-size: calc(14.5px * var(--fs)); color: var(--text-2); line-height: 1.7; }

.toast {
  padding: 12px 16px; border-radius: 14px;
  background: rgba(16, 24, 40, .93); color: #fff;
  font-size: calc(13.5px * var(--fs)); font-weight: 500;
  display: flex; align-items: center; gap: 8px;
  box-shadow: var(--shadow-lg);
  animation: toastIn .24s cubic-bezier(.22, 1, .36, 1);
  max-width: 100%; line-height: 1.45;
}
/* 图标尺寸现在由 ic() 统一给默认值（18px）并写成内联样式，
   所以下面这些 .xxx svg 规则只是「第二道防线」（防手写 svg 漏尺寸）。
   注意：内联样式优先级高于这里的规则，若某处图标尺寸不对，
   改 ic() 的第三个参数，不要只改 CSS —— 会被内联样式盖掉。 */
.toast svg { flex: 0 0 auto; width: 18px; height: 18px; }
.toast.warn { background: rgba(240, 68, 56, .96); }
.toast.ok { background: rgba(18, 183, 106, .96); }
@keyframes toastIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.toast.out { animation: toastOut var(--dur-slow) ease forwards; }
@keyframes toastOut { to { opacity: 0; transform: translateY(6px); } }

/* =========================================================
   空态 / 提示条
   ========================================================= */
.empty {
  padding: 60px 32px; text-align: center; color: var(--text-3);
  display: flex; flex-direction: column; align-items: center; gap: 12px;
}
.empty svg { opacity: .45; }
.empty-t { font-size: calc(13.5px * var(--fs)); line-height: 1.6; }

.privacy-note {
  display: flex; gap: 8px; align-items: flex-start;
  margin: 0 16px 12px; padding: 12px 12px;
  background: var(--surface-2); border-radius: 10px;
  font-size: calc(11.5px * var(--fs)); color: var(--text-3); line-height: 1.6;
}
.privacy-note svg { flex: 0 0 auto; margin-top: 2px; }

.banner {
  margin: 0 16px 12px; padding: 12px 16px; border-radius: 14px;
  display: flex; align-items: center; gap: 12px;
}
.banner .bn-main { flex: 1; min-width: 0; }
.banner .bn-t { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
.banner .bn-d { font-size: calc(12px * var(--fs)); margin-top: 4px; line-height: 1.6; opacity: .9; }
.banner.info { background: var(--accent-soft); color: var(--accent); }
.banner.warn { background: var(--amber-soft); color: var(--on-amber); }
.banner.green { background: var(--green-soft); color: var(--on-green); }
.banner.red { background: var(--red-soft); color: var(--on-red); }
[data-theme="dark"] .banner.warn { color: #FDB022; }
[data-theme="dark"] .banner.green { color: #5BE49B; }
[data-theme="dark"] .banner.red { color: #FDA29B; }

/* =========================================================
   我的页
   ========================================================= */
.me-hero {
  padding: 20px 16px 20px; background: var(--surface);
  display: flex; align-items: center; gap: 16px;
  border-bottom: 1px solid var(--line);
}
.me-info { flex: 1; min-width: 0; }
/* 名字只负责字号字重 —— 认证标识移到 .nm-line 里了，
   名字自己不能再是 flex 容器：flex 容器上的 text-overflow 不生效，
   长名字会把标识挤出可视区（截断的应该是名字，不是标识）。 */
.me-name { font-size: calc(20px * var(--fs)); font-weight: 800; }
.me-sig { font-size: calc(13px * var(--fs)); color: var(--text-2); margin-top: 6px; }

.me-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px 6px;
  box-shadow: var(--shadow-sm);
}
.me-cell {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 6px 2px; cursor: pointer; border-radius: 10px;
}
.me-cell:active { background: var(--surface-2); }
.me-cell .v { font-size: calc(17px * var(--fs)); font-weight: 800; }
.me-cell .k { font-size: calc(11px * var(--fs)); color: var(--text-3); }

/* =========================================================
   统计条
   ========================================================= */
.stat-strip {
  display: flex; background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px 0; box-shadow: var(--shadow-sm);
}
.stat-item { flex: 1; text-align: center; position: relative; }
.stat-item:not(:last-child)::after {
  content: ''; position: absolute; right: 0; top: 4px; bottom: 4px;
  width: 1px; background: var(--line);
}
.stat-item .v { font-size: calc(18px * var(--fs)); font-weight: 800; }
.stat-item .k { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 2px; }

/* 分段控件 */
.seg {
  display: flex; gap: 4px; padding: 4px;
  background: var(--surface-2); border-radius: 10px;
  margin: 0 16px 12px;
}
.seg button {
  flex: 1; padding: 8px 0; border-radius: 10px;
  font-size: calc(13.5px * var(--fs)); font-weight: 600; color: var(--text-2);
  transition: all var(--dur) var(--ease);
}
.seg button.on { background: var(--surface); color: var(--accent); font-weight: 700; box-shadow: var(--shadow-sm); }

/* 横向滚动分类条 */
.hscroll {
  display: flex; gap: 8px; padding: 0 16px 12px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
}
/* ★ 子项禁止压缩。
   flex 子项默认 flex-shrink: 1 —— 标签会被压缩到容器宽度之内，
   于是永远不产生溢出，也就永远滑不动（老板反馈的
   「后边没有显示完还无法滑动」）。必须显式 flex: 0 0 auto，
   内容才会横向溢出、滚动才成立。 */
.hscroll > * { flex: 0 0 auto; }
.hscroll::-webkit-scrollbar { display: none; }

/* 网格（搜索分类） */
.cat-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px; padding: 0 16px 16px;
}
.cat-cell {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 4px 12px; border-radius: 14px;
  background: var(--surface); box-shadow: var(--shadow-sm);
  cursor: pointer; transition: transform var(--dur) var(--ease);
}
.cat-cell:active { transform: scale(.95); }
.cat-cell .cc-ico {
  width: 36px; height: 36px; border-radius: 10px;
  display: grid; place-items: center; color: #fff;
}
.cat-cell .cc-t { font-size: calc(12px * var(--fs)); font-weight: 600; }
.cat-cell.on { background: var(--accent); }
.cat-cell.on .cc-t { color: #fff; }

/* 日志 */
.log-item {
  padding: 12px 16px; background: var(--surface);
  border-bottom: 1px solid var(--line-2);
}
.log-top { display: flex; align-items: center; gap: 8px; }
.log-act { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
.log-time { margin-left: auto; font-size: calc(11px * var(--fs)); color: var(--text-3); }
.log-detail { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 4px; line-height: 1.6; }
.log-item.warn .log-act { color: var(--amber); }

/* =========================================================
   本轮新增组件 · 认证 / 权限 / 商家 / 工种 / 招聘 / 投诉 / 导航大厅
   ========================================================= */

/* ---------------- 认证徽章（谁 · 有没有认证 · 什么身份 · 谁认证） ---------------- */
.cert-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  font-size: calc(11.5px * var(--fs)); font-weight: 700; white-space: nowrap;
}
.cert-chip svg { width: 12px; height: 12px; flex: 0 0 auto; }
.cert-chip.sm { padding: 2px 6px; font-size: calc(10.5px * var(--fs)); }
.cert-chip.sm svg { width: 11px; height: 11px; }
.perm-wrap { display: flex; flex-wrap: wrap; gap: 6px; }
.id-badges { display: flex; flex-wrap: wrap; gap: 6px; }
.id-head { display: flex; align-items: flex-start; gap: 12px; }
.id-ico {
  width: 38px; height: 38px; flex: 0 0 38px; border-radius: 14px;
  display: grid; place-items: center;
}
.id-state { font-size: calc(12px * var(--fs)); font-weight: 700; flex: 0 0 auto; }

/* 认证链路步骤 */
.cert-steps { display: flex; flex-direction: column; }
.cs-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 0; border-bottom: 1px solid var(--line-2);
}
.cs-item:last-child { border-bottom: none; }
.cs-no {
  width: 21px; height: 21px; flex: 0 0 21px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface-3); color: var(--text-3);
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.cs-item.done .cs-no { background: var(--green-soft); color: var(--green); }
.cs-item.pending .cs-no { background: var(--amber-soft); color: var(--amber); }
.cs-item.missing .cs-no { background: var(--red-soft); color: var(--red); }
.cs-main { flex: 1; min-width: 0; }
.cs-t { font-size: calc(13px * var(--fs)); font-weight: 700; }
.cs-d { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 4px; line-height: 1.45; }
.cs-state { font-size: calc(11.5px * var(--fs)); font-weight: 700; flex: 0 0 auto; }

/* 状态点 / 数量角标 */
.st-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  flex: 0 0 auto;
}
.badge-num {
  display: inline-grid; place-items: center;
  min-width: 18px; height: 18px; padding: 0 6px; border-radius: 10px;
  background: var(--red); color: #fff; font-size: calc(10.5px * var(--fs)); font-weight: 700;
}

/* ---------------- 综合评分条（商家等级不看充值） ---------------- */
.sc-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.sc-n { flex: 0 0 78px; font-size: calc(12px * var(--fs)); color: var(--text-2); }
.sc-bar {
  flex: 1; height: 7px; border-radius: 4px;
  background: var(--surface-3); overflow: hidden;
}
.sc-bar i { display: block; height: 100%; border-radius: 4px; background: var(--accent); }
.sc-v { flex: 0 0 40px; text-align: right; font-size: calc(11.5px * var(--fs)); color: var(--text-3); font-family: ui-monospace, monospace; }
.sc-total {
  display: flex; align-items: baseline; gap: 6px;
  padding: 10px 0 4px; border-bottom: 1px solid var(--line-2); margin-bottom: 6px;
}
.sc-total b { font-size: calc(22px * var(--fs)); font-weight: 800; }
.sc-total span { font-size: calc(12px * var(--fs)); color: var(--text-3); }

/* ---------------- 导航大厅（村口指示牌） ---------------- */
.nav-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px; padding: 0 16px 12px;
}
.nav-cell {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 4px 10px; border-radius: 14px;
  background: var(--surface); box-shadow: var(--shadow-sm);
  transition: transform var(--dur) var(--ease);
}
.nav-cell:active { transform: scale(.95); }
.nc-ico {
  width: 40px; height: 40px; border-radius: 14px;
  display: grid; place-items: center;
}
.nc-t { font-size: calc(12px * var(--fs)); font-weight: 600; text-align: center; line-height: 1.3; }
.nc-d { font-size: calc(10.5px * var(--fs)); color: var(--text-3); text-align: center; }
.nc-n {
  position: absolute; top: 6px; right: 7px;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--surface-3); color: var(--text-2);
  font-size: calc(10px * var(--fs)); font-weight: 700;
}
.nav-hint {
  font-size: calc(12px * var(--fs)); color: var(--text-3); line-height: 1.6;
  padding: 0 16px 10px;
}
.nav-sub-row {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; background: var(--surface);
  border-bottom: 1px solid var(--line-2);
}
.ns-e { flex: 1; min-width: 0; }
.ns-n { font-size: calc(14px * var(--fs)); font-weight: 600; }
.ns-e .ns-d { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 4px; }

/* 「我要…」快捷入口
   关键约束：单行不折行。cell = (390-32-12)/3 = 115.3px
   → 内容 115.3-12 = 103.3 → 扣掉图标 24 + 间距 5 = 74.3px 留给文字
   → 最长标签 5 个汉字 @12px = 60px，富余 14px，永不换行 */
.quick-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px; padding: 0 16px 12px;
}
.quick-cell {
  display: flex; align-items: center; gap: 6px;
  padding: 10px 6px; border-radius: 10px;
  background: var(--surface); box-shadow: var(--shadow-sm);
  text-align: left; transition: transform var(--dur) var(--ease);
}
.quick-cell:active { transform: scale(.96); }
.qc-ico {
  width: 24px; height: 24px; flex: 0 0 24px; border-radius: 6px;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
}
.qc-t {
  font-size: calc(12px * var(--fs)); font-weight: 600; letter-spacing: -.2px;
  white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis;
}

/* ---------------- 商家 / 服务人员 通用 hero（头像在左） ---------------- */
.mch-hero, .wk-hero {
  display: flex; align-items: center; gap: 16px;
  padding: 20px 16px; background: var(--surface);
}
.mch-main, .wk-who, .uh-info, .mh-info { flex: 1; min-width: 0; }

/* 用户主页头部单独走**纵向居中**，与「会话信息页」同一版式。
   ---------------------------------------------------------
   为什么不跟商家 / 服务人员共用「头像在左」的横向布局：
   横向时留给名字与标签的宽度只有约 260px，而一个
   「实名 + 企业 + 招聘方」的账号光三个标识就要 240px 以上 ——
   加上名字必然换行，最后一个标识掉到名字下面去，
   看起来就是「认证标识跑到名字下面了」。
   纵向之后可用宽度是整屏，名字不用截断、标识不用换行；
   而且个人主页本来就是一张「名片」，头像在上更符合直觉。 */
.usr-hero {
  display: flex; flex-direction: column; align-items: center;
  gap: 12px; padding: 24px 16px 20px; text-align: center;
  background: var(--surface);
}
.usr-hero .uh-info { flex: none; width: 100%; }
.usr-hero .nm-line { justify-content: center; }
.usr-hero .nm-id { margin-top: 6px; }
.mch-main .mch-t { font-size: calc(18px * var(--fs)); font-weight: 800; }
.mch-main .mch-s { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 4px; }
.mch-cat {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  background: var(--surface-3); color: var(--text-2);
  font-size: calc(11px * var(--fs)); font-weight: 600;
}
.mch-tier {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  font-size: calc(11.5px * var(--fs)); font-weight: 700;
}
.mch-stat {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  background: var(--surface); margin: 0 16px 12px;
  border-radius: var(--r); box-shadow: var(--shadow-sm); overflow: hidden;
}
.mch-stat > div {
  padding: 12px 6px; text-align: center;
  border-right: 1px solid var(--line-2);
}
.mch-stat > div:last-child { border-right: none; }
.mch-stat b { display: block; font-size: calc(16px * var(--fs)); font-weight: 800; }
.mch-stat span { display: block; font-size: calc(11px * var(--fs)); color: var(--text-3); margin-top: 4px; }

.mh-name { font-size: calc(19px * var(--fs)); font-weight: 800; }
.mh-sub { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 6px; line-height: 1.45; }
/* 副标题里混徽章时走 flex —— 纯 inline 排布会让徽章和文字基线对不齐，
   徽章底边会比文字低 1~2px，看着就是「没对齐」。 */
.mh-sub-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

.uh-name { font-size: calc(18px * var(--fs)); font-weight: 800; }

/* ---------------- 服务人员卡 ---------------- */
.wk-card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px; box-shadow: var(--shadow-sm);
}
.wk-head { display: flex; align-items: center; gap: 12px; }
.wk-name { font-size: calc(15.5px * var(--fs)); font-weight: 700; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.wk-sub { font-size: calc(12px * var(--fs)); color: var(--text-2); margin-top: 4px; }
.wk-on {
  padding: 4px 8px; border-radius: 6px; flex: 0 0 auto;
  background: var(--green-soft); color: var(--green);
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.wk-warn {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 10px; padding: 10px 12px; border-radius: 10px;
  background: var(--amber-soft); color: var(--on-amber);
  font-size: calc(11.5px * var(--fs)); font-weight: 600; line-height: 1.6;
}
.wk-warn svg { width: 13px; height: 13px; flex: 0 0 auto; margin-top: 2px; }
/* 工种标签（多选）。
   生效的实色、待认证的虚线框 —— 两者必须一眼分得开。
   只靠颜色区分不够（色弱用户看不出来），所以待认证的额外带「· 待认证」四个字。 */
.wk-profs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.wk-prof {
  padding: 4px 8px; border-radius: 6px; border: 1px solid transparent;
  font-size: calc(11px * var(--fs)); font-weight: 700; white-space: nowrap;
}
.wk-prof.wait {
  background: transparent; color: var(--text-3);
  border: 1px dashed var(--line); font-weight: 600;
}
/* 接单简介：用户自己写的「我能接什么活」。
   比结构化标签更自由，所以给它独立的排版 ——
   和下面的「可做什么 / 可服务区域」拉开层级，不然会读成一类东西。 */
.wk-intro {
  font-size: calc(12.5px * var(--fs)); color: var(--text); line-height: 1.7;
  padding: 10px 12px; border-radius: 10px; background: var(--surface-2);
  margin-bottom: 10px;
}
/* 「本人自述」标记。
   简介是用户自己写的，平台没核验过 —— 必须让读者知道这一点。
   不标的话，「电工证齐全」这句话会被读成平台背书。 */
.wk-by {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 6px;
  background: var(--surface-3); color: var(--text-3);
  font-size: calc(10.5px * var(--fs)); font-weight: 600; vertical-align: 1px;
}
.wk-body { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line-2); }
.wk-line { font-size: calc(12.5px * var(--fs)); color: var(--text-2); line-height: 1.7; }
.wk-line b { color: var(--text); font-weight: 700; margin-right: 6px; }

/* ---------------- 招聘卡（必须展示 8 个字段） ---------------- */
.job-card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px; box-shadow: var(--shadow-sm);
}
.job-card.blocked { background: var(--red-soft); box-shadow: none; }
.jc-top { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.jc-subject { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
.jc-title { font-size: calc(15.5px * var(--fs)); font-weight: 700; line-height: 1.45; }
.jc-meta {
  display: flex; flex-wrap: wrap; gap: 6px 16px;
  margin-top: 10px; font-size: calc(12.5px * var(--fs)); color: var(--text-2);
}
.jc-meta span { display: inline-flex; align-items: center; gap: 4px; }
.jc-meta svg { width: 13px; height: 13px; color: var(--text-3); }
.jc-foot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--line-2);
  font-size: calc(11.5px * var(--fs)); color: var(--text-3);
}
.jc-tag {
  padding: 2px 8px; border-radius: 6px;
  background: var(--accent-soft); color: var(--accent);
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.jc-c { flex: 1; min-width: 0; }
.jc-time { flex: 0 0 auto; }
.jc-verified {
  display: flex; align-items: center; gap: 6px;
  margin-top: 10px; padding: 8px 10px; border-radius: 10px;
  background: var(--green-soft); color: var(--on-green);
  font-size: calc(11.5px * var(--fs)); font-weight: 600;
}
.jc-blocked {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 10px; padding: 8px 10px; border-radius: 10px;
  background: rgba(240, 68, 56, .12); color: var(--red);
  font-size: calc(11.5px * var(--fs)); font-weight: 700; line-height: 1.45;
}

/* ---------------- 处罚记录卡（六要素必须齐） ---------------- */
.pn-card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px; box-shadow: var(--shadow-sm);
}
.pn-top { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.pn-type {
  padding: 4px 10px; border-radius: 6px;
  font-size: calc(11.5px * var(--fs)); font-weight: 700;
}
.pn-ap { margin-left: auto; font-size: calc(11.5px * var(--fs)); font-weight: 700; }
.pn-target { font-size: calc(14px * var(--fs)); font-weight: 700; margin-bottom: 10px; }
.pn-grid { display: flex; flex-direction: column; gap: 8px; }
.pn-grid > div { font-size: calc(12.5px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.pn-grid b { display: block; font-size: calc(11px * var(--fs)); font-weight: 700; color: var(--text-3); margin-bottom: 2px; }
.pn-lock {
  display: flex; align-items: center; gap: 6px;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--line-2);
  font-size: calc(11px * var(--fs)); color: var(--text-3);
}

/* ---------------- 三级投诉进度条 ---------------- */
.lv-bar { display: flex; align-items: center; margin-top: 12px; }
.lv-item { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.lv-dot {
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface-3); color: var(--text-3);
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.lv-item.on .lv-dot { background: var(--accent); color: #fff; }
.lv-item.done .lv-dot { background: var(--green); color: #fff; }
.lv-t { font-size: calc(10.5px * var(--fs)); font-weight: 700; color: var(--text-2); text-align: center; line-height: 1.3; }
.lv-d { font-size: calc(9.5px * var(--fs)); color: var(--text-3); text-align: center; }
.lv-line { flex: 0 0 18px; height: 2px; background: var(--line); margin-top: -20px; }
.lv-no {
  width: 26px; height: 26px; flex: 0 0 26px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--purple-soft); color: var(--purple);
  font-size: calc(11.5px * var(--fs)); font-weight: 800;
}

.cp-level-line { margin-top: 4px; }
.cp-flag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  background: var(--red-soft); color: var(--red);
  font-size: calc(10.5px * var(--fs)); font-weight: 700;
}
.cp-t { font-size: calc(15px * var(--fs)); font-weight: 700; margin-bottom: 6px; }
.cp-d { font-size: calc(13px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.cp-foot {
  display: flex; align-items: center; gap: 10px;
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--line-2);
  font-size: calc(12px * var(--fs)); color: var(--text-3);
}
.cp-foot .spacer { flex: 1; }
.cp-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }

/* ---------------- 社区卡（列表态：头像 + 文字 + 箭头 单行卡） ---------------- */
.cm-card {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 10px; padding: 12px 12px;
  box-shadow: var(--shadow-sm); cursor: pointer;
  transition: transform var(--dur) var(--ease);
}
.cm-card:active { transform: scale(.985); }
.cm-main { flex: 1; min-width: 0; }
.cm-name {
  font-size: calc(15px * var(--fs)); font-weight: 700; line-height: 1.3;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.cm-sub {
  font-size: calc(12px * var(--fs)); color: var(--text-2); line-height: 1.45; margin-top: 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cm-meta { font-size: calc(11.5px * var(--fs)); color: var(--text-3); line-height: 1.45; margin-top: 4px; }
/* 社区长 / 管理员行已并入社区页顶部的 .cm-people，旧的 .cm-roles 已删除 */
.cm-card .row-arrow { margin-left: 2px; }
.cm-card .av { flex: 0 0 auto; }

/* ---------------- 群组 / 聊天信息行 ---------------- */
.gc-main, .gr-main { flex: 1; min-width: 0; }
.gc-n, .gr-n { font-size: calc(14.5px * var(--fs)); font-weight: 700; }
.gc-p, .gr-p { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 4px; }
.gc-d, .gr-d { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 4px; }

/* 聊天列表补充 */
.ci-cm {
  padding: 2px 6px; border-radius: 6px;
  background: var(--surface-3); color: var(--text-3);
  font-size: calc(10px * var(--fs)); font-weight: 600; flex: 0 0 auto;
}
.ci-who { font-size: calc(12px * var(--fs)); font-weight: 600; }
.ci-at { font-size: calc(10.5px * var(--fs)); color: var(--text-3); }
.ci-d { font-size: calc(12.5px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.ci-e { font-size: calc(11.5px * var(--fs)); color: var(--text-3); }
.ci-h { display: flex; align-items: center; gap: 10px; }
.ci-lv {
  padding: 2px 8px; border-radius: 6px;
  background: var(--amber-soft); color: var(--amber);
  font-size: calc(10.5px * var(--fs)); font-weight: 700;
}

/* ---------------- 搜索 ---------------- */
.search-head { padding: 4px 16px 10px; }
/* ⚠ 必须带 `.statusbar` 前缀。
   `.sb-` 这个前缀被三个不同的东西共用了：状态栏（statusbar）、
   安全拦截记录（security block）、搜索块（search block）。
   这条原本写成裸 `.sb-time`，因为位置靠后，会把「安全拦截记录」
   里那条 `.sb-time`（11px）也一起覆盖成等宽字体 11.5px ——
   两处共用类名，改动 A 会静默改到 B。
   加上父级作用域后，这条只管状态栏时钟。 */
.statusbar .sb-time { font-size: calc(11.5px * var(--fs)); color: var(--text-3); font-family: ui-monospace, monospace; }
/* ⚠️ 这里原来有一条裸 `.sb-clear`（胶囊样式：底色 + 内边距 + 圆角），
   是给搜索框的「清除」按钮写的。它和 `.sb-` 前缀下另外两个东西
   （状态栏 statusbar、安全拦截记录 security block）撞在同一个命名空间里，
   而且**按胶囊设计**放进搜索框就是错的 —— 搜索框里嵌一枚小胶囊，
   看起来像两个控件拼在一起。已删，改用作用域明确的 `.search-x`。 */
.sr-count { font-size: calc(12px * var(--fs)); color: var(--text-3); padding: 2px 16px 10px; }

.goods-card {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 10px; padding: 12px 12px; box-shadow: var(--shadow-sm);
  cursor: pointer; transition: transform var(--dur) var(--ease);
}
.goods-card:active { transform: scale(.985); }
.goods-card .av { flex: 0 0 auto; }
.goods-card .row-arrow { margin-left: 2px; }
.goods-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 0; border-bottom: 1px solid var(--line-2);
}
.goods-row:last-child { border-bottom: none; }

/* ---------------- 规则 / 权限说明 ---------------- */
.risk-line {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 0; border-bottom: 1px solid var(--line-2);
}
.risk-line:last-child { border-bottom: none; }
.risk-chip {
  padding: 2px 8px; border-radius: 6px; flex: 0 0 auto;
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.risk-t { font-size: calc(13px * var(--fs)); font-weight: 700; }
.risk-d { font-size: calc(11.5px * var(--fs)); color: var(--text-2); margin-top: 4px; line-height: 1.6; }

.mk-warn {
  display: flex; align-items: flex-start; gap: 6px;
  padding: 8px 10px; border-radius: 10px;
  background: var(--red-soft); color: var(--red);
  font-size: calc(11.5px * var(--fs)); font-weight: 600; line-height: 1.6;
}
.mk-warn svg { width: 13px; height: 13px; flex: 0 0 auto; margin-top: 2px; }

.tier-row { padding: 10px 16px; border-bottom: 1px solid var(--line-2); }
.tier-row:last-child { border-bottom: none; }
.tier-chip {
  display: inline-flex; align-items: center;
  padding: 2px 8px; border-radius: 6px;
  font-size: calc(11.5px * var(--fs)); font-weight: 700;
}
.tier-d { font-size: calc(12px * var(--fs)); color: var(--text-2); margin-top: 6px; line-height: 1.6; }

.cfg-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; padding: 0 16px 12px; }
.cfg-grid label { font-size: calc(12px * var(--fs)); color: var(--text-2); display: block; }
.cfg-grid input {
  width: 100%; margin-top: 6px; padding: 10px 12px;
  background: var(--surface-2); border-radius: 10px;
  font-size: calc(13.5px * var(--fs)); font-weight: 600;
}
/* 选项组：横向 chip 行，必须允许换行。
   ⚠️ 这里原本被一条误粘贴的「列表行」样式（padding:10px 14px; background:surface;
   border-bottom:1px solid line-2）覆盖，display:flex + align-items:center 且不换行，
   导致 5 个选项被压进同一行、每个只剩 ~74px，中文标签只能一个字一行竖排。
   现在改为 flex-wrap，并在选项超过 4 个时改用 UI.pickField（点开底部弹层选）。 */
.opt-row {
  display: flex; flex-wrap: wrap; gap: 10px;
  padding: 0; background: none; border-bottom: 0;
}
.opt-row > .opt { flex: 0 1 auto; }
.ps-row { display: flex; align-items: center; gap: 8px; padding: 8px 0; }

/* 时间线补充 */
.tl { padding: 2px 0; }
.tl-d { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 4px; line-height: 1.45; }

/* 公约定制段落 */
.cv-sec { padding: 12px 0; border-bottom: 1px solid var(--line-2); }
.cv-sec:last-child { border-bottom: none; }
.cv-t { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
.cv-c { font-size: calc(12.5px * var(--fs)); color: var(--text-2); line-height: 1.7; margin-top: 6px; }

/* 社区管理入口 */
.mg-entry {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; background: var(--surface);
  border-bottom: 1px solid var(--line-2);
}
.mg-entry:last-child { border-bottom: none; }
.mg-t { flex: 1; min-width: 0; font-size: calc(14px * var(--fs)); font-weight: 600; }
.mg-d { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 4px; }

/* =========================================================
   管理条（社区页 / 群页首屏的「管理后台」入口）
   ---------------------------------------------------------
   老板 2026-09-20：「社区管理设置后台放到下面要滑动很久，不好看。
   也没有明显的待审核通知。需要放到显眼位置。」

   所以它不是一条普通入口行，而是：
     · 有待办 → 橙红描边 + 数字角标 + 「去处理」
     · 无待办 → 绿色对勾 + 「暂无待处理」+ 「进入」
   ★ 「没有待办」也必须明确说出来。只写「社区管理后台」的话，
   用户分不清「没事要做」和「角标没加载出来」——
   而后者会让他以为功能坏了。
   ========================================================= */
.mg-bar {
  display: flex; align-items: center; gap: 12px;
  margin: 0 16px 12px; padding: 13px 14px;
  background: var(--surface); border-radius: var(--r);
  border: 1px solid var(--line); box-shadow: var(--shadow-sm);
  cursor: pointer;
}
/* 有待办：用琥珀色描边 + 淡底，在整屏白卡里一眼跳出来。
   不用红色 —— 红色在这个产品里表示「违规 / 危险」，
   待办只是「有事要做」，语义不同。 */
.mg-bar.has-todo {
  /* ⚠️ 这里刻意**不用 `color-mix()`** —— 全项目只有它一处用，
     而它的支持面比其它属性窄。一个属性不被支持时整条声明失效，
     边框会退回 --line（浅灰），「有待办」就完全看不出来了，
     而且不报错。用纯色最稳。 */
  border-color: var(--amber);
  background: linear-gradient(180deg, var(--amber-soft), var(--surface));
}
.mb-ico {
  width: 34px; height: 34px; flex: none; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent);
}
.mg-bar.has-todo .mb-ico { background: var(--amber-soft); color: var(--amber); }
.mb-main { flex: 1; min-width: 0; }
.mb-t {
  font-size: calc(14.5px * var(--fs)); font-weight: 600;
  display: flex; align-items: center; gap: 7px;
}
/* 角标：数字本身要够大够重，否则「有待办」这件事传达不到 */
.mb-dot {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--amber); color: #fff;
  font-size: calc(11.5px * var(--fs)); font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1;
}
.mb-d {
  font-size: calc(11.5px * var(--fs)); color: var(--text-3);
  margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mb-d b { color: var(--amber); font-weight: 700; }
.mb-go {
  flex: none; display: inline-flex; align-items: center; gap: 2px;
  font-size: calc(12.5px * var(--fs)); color: var(--accent); font-weight: 600;
}
.mg-bar.has-todo .mb-go { color: var(--amber); }

/* =========================================================
   加入方式选择器（公开 / 需审核）
   ---------------------------------------------------------
   两个大选项卡而不是一个 switch 开关：
   开关只有「开/关」，说不清「开」对应哪一种行为，
   而这里两个选项都有实质后果（谁能进、要不要审），
   必须把后果写在选项里，不能靠用户猜。
   ========================================================= */
.jm-wrap { margin: 0 16px 12px; display: flex; flex-direction: column; gap: 10px; }
.jm-opt {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px; background: var(--surface); border-radius: var(--r);
  border: 1.5px solid var(--line); cursor: pointer;
}
.jm-opt.on {
  border-color: var(--accent);
  background: linear-gradient(180deg, var(--accent-soft), var(--surface));
}
.jm-wrap.locked .jm-opt { opacity: .55; cursor: not-allowed; }
.jm-radio {
  width: 20px; height: 20px; flex: none; border-radius: 50%;
  border: 1.5px solid var(--line); margin-top: 1px;
  display: flex; align-items: center; justify-content: center;
  color: #fff;
}
.jm-opt.on .jm-radio { background: var(--accent); border-color: var(--accent); }
.jm-t { font-size: calc(14.5px * var(--fs)); font-weight: 600; }
.jm-d { font-size: calc(12px * var(--fs)); color: var(--text-3); margin-top: 4px; line-height: 1.6; }

/* 公告卡 / 二手卡 */
.notice-card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 16px; box-shadow: var(--shadow-sm);
  border-left: 3px solid var(--red);
}
.type-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  font-size: calc(11px * var(--fs)); font-weight: 700;
}
.chain-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 0; border-bottom: 1px dashed var(--line);
}
.chain-item:last-child { border-bottom: none; }
.mc-n { font-size: calc(12px * var(--fs)); font-weight: 700; color: var(--text-2); }

/* 首页 hero 补充 */
.hh-top { display: flex; align-items: center; gap: 10px; }
.hh-title { font-size: calc(20px * var(--fs)); font-weight: 800; flex: 1; }
.hh-sub { font-size: calc(12px * var(--fs)); color: var(--text-3); margin-top: 4px; }

/* 任务匹配提示 */
.tk-top { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.tk-title { font-size: calc(15px * var(--fs)); font-weight: 700; }
.tk-desc { font-size: calc(13px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.tk-reward { margin-left: auto; font-size: calc(16px * var(--fs)); font-weight: 800; color: var(--red); }
.tk-foot {
  display: flex; align-items: center; gap: 10px;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line-2);
  font-size: calc(12px * var(--fs)); color: var(--text-3);
}
.tk-foot .spacer { flex: 1; }
.tk-match {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 8px; border-radius: 6px;
  background: var(--green-soft); color: var(--green);
  font-size: calc(11px * var(--fs)); font-weight: 700;
}

/* 群组卡主体 */
.gc-m { flex: 1; min-width: 0; }

/* =========================================================
   会话信息页 · 群资料
   ---------------------------------------------------------
   ⚠ 这里原本用的是 `ci-` 前缀，和「会话列表」的 `ci-*`
   （.chat-item / .ci-main / .ci-r1 / .ci-name / .ci-time …）撞了名。
   两处都定义了裸选择器 `.ci-name`，且属性冲突 ——
   CSS 里后定义的赢，于是**会话列表的名字被这里覆盖成 19px/800**，
   还白捡了一个 11px 上边距。页面不报错、不崩溃，
   只是「明明改小了字号却没变化」。
   改成 `cix-`（chat info eXtended）前缀，边界才清楚。
   ========================================================= */
.cix-head { padding: 24px 16px 20px; text-align: center; background: var(--surface); }
.cix-name { font-size: calc(19px * var(--fs)); font-weight: 800; margin-top: 12px; }
.cix-sub { font-size: calc(12.5px * var(--fs)); color: var(--text-3); margin-top: 6px; }
.cix-flag {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 10px; padding: 4px 12px; border-radius: 18px;
  font-size: calc(11.5px * var(--fs)); font-weight: 700;
}
.cix-flag.owner { background: var(--purple-soft); color: var(--purple); }
.cix-flag.admin { background: var(--accent-soft); color: var(--accent); }

.cix-doc { margin: 0 16px 12px; padding: 16px; }
.cix-sec-t {
  display: flex; align-items: center; gap: 6px;
  font-size: calc(12.5px * var(--fs)); font-weight: 700; color: var(--text-3);
}
.cix-notice {
  margin-top: 8px; padding: 10px 12px; border-radius: 10px;
  background: var(--surface-2);
  font-size: calc(13.5px * var(--fs)); color: var(--text); line-height: 1.7;
}
.cix-rules { margin: 8px 0 0; padding-left: 20px; }
.cix-rules li { font-size: calc(13px * var(--fs)); color: var(--text-2); line-height: 1.7; }

/* =========================================================
   群管理面板
   ========================================================= */
.gm-hero { padding: 16px; }
.gm-hero-t { font-size: calc(17px * var(--fs)); font-weight: 800; }
.gm-hero-d { font-size: calc(12.5px * var(--fs)); color: var(--text-3); margin-top: 6px; }
.gm-hero-badges { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.gm-badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 10px; border-radius: 18px;
  background: var(--surface-2); color: var(--text-2);
  font-size: calc(11.5px * var(--fs)); font-weight: 600;
}
.gm-badge.on { background: var(--green-soft); color: var(--green); }

.gm-stat {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 0 16px 12px; padding: 16px 8px;
  background: var(--surface); border-radius: var(--r); box-shadow: var(--shadow-sm);
}
.gm-stat-i { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.gm-stat-i b { font-size: calc(17px * var(--fs)); font-weight: 800; }
.gm-stat-i span { font-size: calc(11px * var(--fs)); color: var(--text-3); }

/* 成员行 */
.gmb-row {
  display: flex; align-items: center; gap: 12px;
  margin: 0 16px 8px; padding: 12px 12px;
  background: var(--surface); border-radius: 14px; box-shadow: var(--shadow-sm);
}
.gmb-main { flex: 1; min-width: 0; }
.gmb-t {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: calc(14.5px * var(--fs)); font-weight: 600;
}
.gmb-me {
  padding: 2px 6px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 700;
  background: var(--surface-3); color: var(--text-3);
}
.gmb-role { padding: 2px 8px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 700; }
.gmb-mute {
  padding: 2px 8px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 700;
  background: var(--red-soft); color: var(--red);
}
.gmb-d {
  font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gmb-act {
  flex: 0 0 auto; padding: 6px 12px; border-radius: 10px;
  background: var(--surface-2); color: var(--accent);
  font-size: calc(12.5px * var(--fs)); font-weight: 700;
}
.gm-mem-head { display: flex; align-items: center; gap: 12px; padding: 2px 4px 0; }

/* =========================================================
   群机器人设置
   ========================================================= */
.gm-bot-hero { padding: 16px; }
.gbh-top { display: flex; align-items: center; gap: 12px; }
.gbh-main { flex: 1; min-width: 0; }
.gbh-t { display: flex; align-items: center; gap: 6px; font-size: calc(15.5px * var(--fs)); font-weight: 700; }
.gbh-d { font-size: calc(12px * var(--fs)); color: var(--text-3); margin-top: 4px; line-height: 1.6; }
.gbh-stat {
  display: flex; gap: 16px; margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--line-2);
  font-size: calc(12px * var(--fs)); color: var(--text-2);
}
.gbh-stat span { display: inline-flex; align-items: center; gap: 4px; }

.gb-rule {
  display: flex; align-items: flex-start; gap: 12px;
  margin: 0 16px 8px; padding: 12px;
  background: var(--surface); border-radius: 14px; box-shadow: var(--shadow-sm);
  transition: opacity var(--dur) var(--ease);
}
.gb-rule.off { opacity: .55; }
.gbr-ico {
  width: 34px; height: 34px; flex: 0 0 34px; border-radius: 10px;
  display: grid; place-items: center;
}
.gbr-main { flex: 1; min-width: 0; }
.gbr-t { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: calc(14.5px * var(--fs)); font-weight: 700; }
.gbr-act { padding: 2px 8px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 700; }
.gbr-d { font-size: calc(12px * var(--fs)); color: var(--text-3); margin-top: 4px; line-height: 1.6; }
.gbr-params { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.gbr-param {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 10px; border-radius: 10px;
  background: var(--surface-2); color: var(--text-2);
  font-size: calc(11.5px * var(--fs)); font-weight: 600;
}
.gbr-param b { color: var(--text); font-weight: 800; }
.gb-rule > .switch { flex: 0 0 auto; margin-top: 4px; }

.gb-test-h { font-size: calc(12.5px * var(--fs)); color: var(--text-2); line-height: 1.6; margin-bottom: 10px; }
#botTestText {
  width: 100%; padding: 10px 12px; border-radius: 10px; box-sizing: border-box;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text);
  font-size: calc(13px * var(--fs)); font-family: inherit; resize: none; line-height: 1.6;
}
.gb-test-row { display: flex; gap: 10px; margin-top: 10px; }
.gb-test-row select {
  flex: 1; min-width: 0; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text);
  font-size: calc(12.5px * var(--fs)); font-family: inherit;
}
.gb-test-row .btn { flex: 0 0 auto; }
.gb-test-out { margin-top: 12px; }
.gb-test-res {
  display: flex; gap: 10px; padding: 12px 12px;
  border-radius: 10px; border: 1px solid var(--line); background: var(--surface-2);
  animation: toastIn .22s cubic-bezier(.22, 1, .36, 1);
}
.gb-test-res > div { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.gb-test-res b { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
.gb-test-res span { font-size: calc(11.5px * var(--fs)); color: var(--text-3); line-height: 1.6; }
.gb-test-res.ok { border-color: rgba(18, 183, 106, .35); }
.gb-test-res.hit { border-width: 1.5px; }
.gbt-act {
  width: 30px; height: 30px; flex: 0 0 30px; border-radius: 10px;
  display: grid; place-items: center;
}
.gb-test-safe { font-style: italic; opacity: .8; }

/* =========================================================
   违规记录
   ========================================================= */
.gv-bar { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
/* 名称给弹性宽度、进度条给弹性宽度：
   过去名称写死 96px，长一点的条款名会被截成「R3 禁止刷屏与…」，
   而分布图恰恰是靠条款名来读的，截断等于把信息删了。 */
.gv-bar-n {
  flex: 0 1 auto; min-width: 0; font-size: calc(12px * var(--fs)); color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gv-bar-t { flex: 1 1 56px; height: 7px; border-radius: 4px; background: var(--surface-3); overflow: hidden; }
.gv-bar-t i { display: block; height: 100%; border-radius: 4px; background: var(--accent); }
.gv-bar-c { flex: 0 0 24px; text-align: right; font-size: calc(12px * var(--fs)); font-weight: 700; color: var(--text-2); }

.gv-row {
  display: flex; align-items: flex-start; gap: 12px;
  margin: 0 16px 8px; padding: 12px 12px;
  background: var(--surface); border-radius: 14px; box-shadow: var(--shadow-sm);
}
.gv-main { flex: 1; min-width: 0; }
.gv-t { display: flex; align-items: center; gap: 6px; font-size: calc(14px * var(--fs)); font-weight: 700; }
.gv-src { padding: 2px 8px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 700; }
.gv-src.bot { background: var(--purple-soft); color: var(--purple); }
.gv-src.man { background: var(--accent-soft); color: var(--accent); }
.gv-rule { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 4px; }
.gv-text {
  margin-top: 8px; padding: 8px 10px; border-radius: 10px;
  background: var(--surface-2); color: var(--text-2);
  font-size: calc(12px * var(--fs)); line-height: 1.6; word-break: break-all;
}
.gv-foot { font-size: calc(11px * var(--fs)); color: var(--text-3); margin-top: 6px; }
.gv-act { flex: 0 0 auto; padding: 4px 10px; border-radius: 6px; font-size: calc(11px * var(--fs)); font-weight: 700; }

/* =========================================================
   群机器人消息 / 被拦截消息
   ========================================================= */
.bot-wrap { padding: 8px 16px; }
.bot-msg {
  padding: 12px 12px; border-radius: var(--r);
  background: var(--surface); box-shadow: var(--shadow-sm);
  border-left: 3px solid var(--purple);
}
.bm-head { display: flex; align-items: center; gap: 10px; }
.bm-who { flex: 1; min-width: 0; }
.bm-name { display: flex; align-items: center; gap: 6px; font-size: calc(13px * var(--fs)); font-weight: 700; }
.bm-official {
  padding: 2px 6px; border-radius: 4px; font-size: calc(9.5px * var(--fs)); font-weight: 700;
  background: var(--accent-soft); color: var(--accent);
}
.bm-rule { font-size: calc(11px * var(--fs)); color: var(--text-3); margin-top: 2px; }
.bm-act { flex: 0 0 auto; padding: 4px 10px; border-radius: 6px; font-size: calc(11px * var(--fs)); font-weight: 700; }
.bm-text { font-size: calc(13px * var(--fs)); color: var(--text-2); line-height: 1.7; margin-top: 10px; }
.bm-hit {
  margin-top: 8px; padding: 8px 10px; border-radius: 10px;
  background: var(--surface-2); color: var(--text-2);
  font-size: calc(11.5px * var(--fs)); word-break: break-all;
}
.bm-more {
  display: inline-flex; align-items: center; gap: 2px;
  margin-top: 10px; font-size: calc(12px * var(--fs)); font-weight: 600; color: var(--accent);
}

/* 被机器人拦下的消息：只对发送者可见，灰显并说明原因 */
.bubble.blocked { opacity: .62; }
.blk-tag {
  display: block; margin-top: 6px; padding-top: 6px;
  border-top: 1px dashed currentColor;
  font-size: calc(11px * var(--fs)); font-weight: 700; opacity: .85;
}

/* =========================================================
   违规记录卡 / 申诉 / 审判 / 管理员账本 / 规则条款
   ---------------------------------------------------------
   这一块的排版原则：**每条记录是一张独立卡片，信息按「谁 → 依据 →
   证据 → 处置 → 申诉」自上而下排**。
   过去把这几层塞进一行 flex，右边再挂一个处置徽章，结果徽章把
   中间的文字挤成竖排（老板截图里那个方块就是这个成因）。
   现在统一改为纵向堆叠，只有头像行是横向 flex，且中间列 min-width:0。
   ========================================================= */

/* 统计条上的「待审判」用琥珀色提一下，但不用红 —— 待审判不是错误 */
.gm-stat-i.warn b { color: var(--amber); }

/* ---------- 违规记录卡 ---------- */
.vio {
  margin: 0 16px 10px; padding: 12px 16px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow-sm);
}
/* compact 只是内边距略小，**左右留白必须与全站一致**。
   之前写成 margin:0 0 10px，卡片直接顶到屏幕边缘，
   而它上面的群名标签却是缩进 16px 的 —— 同一组内容两种缩进，看着就散。 */
.vio.compact { margin: 0 16px 10px; padding: 12px 12px; }
.vio-h { display: flex; align-items: center; gap: 10px; }
.vio-hm { flex: 1; min-width: 0; }
.vio-t {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: calc(14px * var(--fs)); font-weight: 700; line-height: 1.3;
}
.vio-src { padding: 2px 8px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 700; }
.vio-src.bot { background: var(--purple-soft); color: var(--purple); }
.vio-src.man { background: var(--accent-soft); color: var(--accent); }
.vio-renamed { padding: 2px 8px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 700; background: var(--amber-soft); color: var(--amber); }
.vio-snap {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px;
  font-size: calc(11px * var(--fs)); color: var(--text-3); margin-top: 4px; line-height: 1.4;
}
.vio-snap svg { flex: 0 0 auto; }
/* 「处罚时身份」四个字必须整体不折行：
   之前没有 nowrap，容器一窄就被拆成「处罚时身 / 份：」，非常难看。 */
.vs-label { flex: 0 0 auto; white-space: nowrap; }
.vs-region { flex: 0 1 auto; min-width: 0; margin-left: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vio-act { flex: 0 0 auto; align-self: flex-start; padding: 4px 10px; border-radius: 6px; font-size: calc(11px * var(--fs)); font-weight: 700; white-space: nowrap; }

/* 条款引用：可以点开看原文 —— 处罚依据必须能被当事人自己核实 */
.vio-clause { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.vio-clause-btn {
  padding: 4px 10px; border-radius: 6px; border: 1px solid var(--line);
  background: var(--surface-2); color: var(--text); cursor: pointer;
  font-size: calc(12px * var(--fs)); font-weight: 700; font-family: inherit; line-height: 1.4;
}
.vio-clause-btn:active { background: var(--surface-3); }
.vio-clause-id { font-size: calc(11px * var(--fs)); font-weight: 700; color: var(--text-3); letter-spacing: .3px; }

.vio-hit { font-size: calc(12px * var(--fs)); color: var(--text-2); margin-top: 8px; line-height: 1.45; }
.vio-text {
  margin-top: 8px; padding: 8px 10px; border-radius: 10px;
  background: var(--surface-2); border-left: 3px solid var(--line);
  font-size: calc(12.5px * var(--fs)); color: var(--text-2); line-height: 1.6;
  word-break: break-word;
}
.vio-foot { font-size: calc(11px * var(--fs)); color: var(--text-3); margin-top: 8px; }

/* 申诉区：第一行「状态徽章 …… 动作按钮」，第二行整行放申诉/审判说明。
   之前说明和按钮挤在同一行，说明文字被按钮压成三行窄条，
   读起来像被折断的句子。 */
.vio-ap {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line);
}
.vio-ap-b { flex: 0 0 auto; padding: 4px 8px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 700; }
.vio-ap-note { flex: 1 1 100%; font-size: calc(11.5px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.vio-btn {
  flex: 0 0 auto; margin-left: auto; padding: 6px 12px; border-radius: 10px; border: none;
  background: var(--accent); color: #fff; cursor: pointer;
  font-size: calc(12px * var(--fs)); font-weight: 700; font-family: inherit;
}
.vio-btn.off { background: var(--surface-3); color: var(--text-3); cursor: default; }
.vio-g {
  display: flex; align-items: center; gap: 6px;
  margin: 0 16px 6px; font-size: calc(11.5px * var(--fs)); font-weight: 700; color: var(--text-3);
}

/* ---------- 审判台 / 账本 / 条款页的顶部说明卡 ---------- */
.ap-hero { padding: 16px 16px; }
.ap-hero-t { display: flex; align-items: center; gap: 8px; font-size: calc(15px * var(--fs)); font-weight: 800; }
.ap-hero-t svg { flex: 0 0 auto; color: var(--accent); }
.ap-hero-d { font-size: calc(12.5px * var(--fs)); color: var(--text-2); line-height: 1.6; margin-top: 8px; }
.ap-hero-rule {
  display: flex; align-items: center; gap: 6px;
  margin-top: 10px; padding: 8px 10px; border-radius: 10px;
  background: var(--amber-soft); color: var(--amber);
  font-size: calc(12px * var(--fs)); font-weight: 700; line-height: 1.45;
}
.ap-hero-rule svg { flex: 0 0 auto; }

/* ---------- 管理员账本 ---------- */
.led-row {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 0 16px 8px; padding: 12px 12px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow-sm);
}
.led-row.flagged { border-color: rgba(240, 68, 56, .38); background: var(--red-soft); }
.led-main { flex: 1; min-width: 0; }
.led-t { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: calc(14px * var(--fs)); font-weight: 700; }
.led-flag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  background: var(--red); color: #fff; font-size: calc(10.5px * var(--fs)); font-weight: 700;
}
.led-d { font-size: calc(11.5px * var(--fs)); color: var(--text-2); margin-top: 6px; line-height: 1.6; }
/* 每条一行的条形图（不是并排 flex）：
   并排时两条 width 相加超过 100% 会被 flex-shrink 按比例压缩，
   画出来的长度就不代表真实比例了，等于把图读歪。 */
.led-bars { margin-top: 10px; }
.led-b {
  display: flex; align-items: center; justify-content: flex-end;
  height: 16px; border-radius: 6px; padding: 0 8px; margin-top: 4px;
  font-size: calc(10px * var(--fs)); font-weight: 700; color: #fff; white-space: nowrap;
  min-width: 52px; max-width: 100%; box-sizing: border-box;
}
.led-b1 { background: var(--accent); }
.led-b2 { background: var(--red); }
.mis-row { padding: 10px 0; border-bottom: 1px solid var(--line-2); }
.mis-row:last-child { border-bottom: none; padding-bottom: 0; }
.mis-t { font-size: calc(13px * var(--fs)); font-weight: 700; }
.mis-d { font-size: calc(11.5px * var(--fs)); color: var(--text-2); margin-top: 4px; line-height: 1.6; }

/* ---------- 规则条款 ---------- */
.cl-row { padding: 12px 0; border-bottom: 1px solid var(--line-2); }
.cl-row:last-child { border-bottom: none; padding-bottom: 0; }
.cl-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cl-id {
  padding: 2px 8px; border-radius: 6px; background: var(--surface-3);
  color: var(--text-2); font-size: calc(10.5px * var(--fs)); font-weight: 800; letter-spacing: .4px;
}
.cl-n { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
.cl-cap { margin-left: auto; font-size: calc(11px * var(--fs)); font-weight: 700; }
.cl-c { font-size: calc(12px * var(--fs)); color: var(--text-2); line-height: 1.6; margin-top: 6px; }

.cl-detail { padding: 2px 0; }
.cl-d-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cl-d-cat { padding: 2px 8px; border-radius: 6px; background: var(--surface-3); color: var(--text-2); font-size: calc(10.5px * var(--fs)); font-weight: 700; }
.cl-d-t { font-size: calc(13.5px * var(--fs)); line-height: 1.7; margin-top: 12px; }
.cl-d-n {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 12px; padding: 10px 12px; border-radius: 10px;
  background: var(--surface-2); font-size: calc(11.5px * var(--fs)); color: var(--text-2); line-height: 1.6;
}
.cl-d-n svg { flex: 0 0 auto; margin-top: 2px; }

/* 处罚阶梯 / 申诉状态行（规则条款页与处罚阶梯共用 .ps-row） */
.ps-i {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.ps-m { flex: 1; min-width: 0; }
.ps-t { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: calc(13px * var(--fs)); font-weight: 700; }
.ps-tag { padding: 2px 6px; border-radius: 6px; background: var(--surface-3); color: var(--text-2); font-size: calc(10px * var(--fs)); font-weight: 700; }
.ps-d { font-size: calc(11.5px * var(--fs)); color: var(--text-2); margin-top: 4px; line-height: 1.6; }

/* 分布条下方的提示（避免和 .gv-bar 抢样式，单独一个类） */
.gv-tip {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line-2);
  font-size: calc(11.5px * var(--fs)); color: var(--text-3); line-height: 1.6;
}
.gv-tip svg { flex: 0 0 auto; margin-top: 2px; }

/* ---------- 审判弹层 ---------- */
.rv-box {
  padding: 12px 12px; border-radius: 10px;
  background: var(--surface-2); margin-bottom: 16px;
}
.rv-t { font-size: calc(13.5px * var(--fs)); font-weight: 700; line-height: 1.45; }
.rv-d { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 6px; }
.rv-q { font-size: calc(12.5px * var(--fs)); color: var(--text-2); margin-top: 10px; line-height: 1.6; }

/* ---------- 管理员删除群消息 ---------- */
/* 删除入口挂在消息元信息行（时间 · 已读 之后），只对群主 / 管理员、
   且只对别人发的消息出现。做成小号描边按钮，避免抢走消息本身的注意力。 */
.msg-del {
  padding: 2px 8px; border-radius: 6px; border: 1px solid var(--line);
  background: var(--surface); color: var(--text-3);
  font-size: calc(10.5px * var(--fs)); font-weight: 700; font-family: inherit;
  cursor: pointer; line-height: 1.6;
}
.msg-del:active { background: var(--red-soft); color: var(--red); border-color: transparent; }

/* 被删消息的墓碑：留「谁删的 / 依据哪条 / 什么时候」，不做成彻底消失 */
.bubble.tomb {
  background: var(--surface-2); border: 1px dashed var(--line);
  color: var(--text-3); display: flex; flex-direction: column; gap: 4px;
}
.tomb-t { font-size: calc(12px * var(--fs)); font-weight: 700; }
.tomb-d { font-size: calc(10.5px * var(--fs)); opacity: .92; line-height: 1.45; }

/* =========================================================
   社区评议庭（陪审团）
   ---------------------------------------------------------
   视觉分工：评议庭品牌色用紫色（--purple），与「违规红 / 通过绿 /
   警示橙」区分开 —— 评议庭本身不是处罚，它是「先评议、后裁决」。
   官方通道单独用深红盾牌色，因为它是兜底通道，必须一眼看到。
   ========================================================= */

/* ---------- 首屏醒目区块（社区 Tab / 评议庭列表页共用） ---------- */
.jury-hero {
  margin: 0 16px 12px; padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #4E3FD4 0%, #6E52F0 52%, #9B7BFF 100%);
  color: #fff; box-shadow: 0 10px 24px rgba(90, 70, 220, .28);
}
.jh-top { display: flex; align-items: center; gap: 10px; }
.jh-badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 999px;
  background: rgba(255, 255, 255, .2);
  font-size: calc(12.5px * var(--fs)); font-weight: 800; letter-spacing: .2px;
}
.jh-badge svg { flex: 0 0 auto; width: 15px; height: 15px; }
.jh-more {
  margin-left: auto; display: inline-flex; align-items: center; gap: 2px;
  font-size: calc(12px * var(--fs)); font-weight: 700; color: rgba(255, 255, 255, .9);
  cursor: pointer; flex: 0 0 auto;
}
.jh-more svg { flex: 0 0 auto; width: 14px; height: 14px; }
.jh-t { font-size: calc(15px * var(--fs)); font-weight: 800; line-height: 1.4; margin-top: 12px; }
.jh-d { font-size: calc(12px * var(--fs)); line-height: 1.6; color: rgba(255, 255, 255, .84); margin-top: 6px; }
.jh-stats {
  display: flex; gap: 16px; flex-wrap: wrap;
  margin-top: 12px; font-size: calc(11.5px * var(--fs)); color: rgba(255, 255, 255, .82);
}
.jh-stats b { font-size: calc(15px * var(--fs)); font-weight: 800; color: #fff; margin-right: 4px; }

.jh-list { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.jh-item {
  padding: 12px 12px; border-radius: 14px;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .18);
  cursor: pointer;
}
.jh-item:active { background: rgba(255, 255, 255, .22); }
.jhi-h { display: flex; align-items: center; gap: 8px; }
.jhi-h svg { flex: 0 0 auto; }
.jhi-target {
  font-size: calc(12.5px * var(--fs)); font-weight: 700; color: #fff;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.jhi-tag {
  flex: 0 0 auto; padding: 2px 8px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs)); font-weight: 700;
  display: inline-flex; align-items: center; gap: 4px;
}
.jhi-tag svg { flex: 0 0 auto; width: 10px; height: 10px; }
.jhi-tag.responded { background: rgba(18, 183, 106, .3); color: #C6F7DE; }
.jhi-tag.waiting { background: rgba(255, 255, 255, .2); color: rgba(255, 255, 255, .9); }
.jhi-tag.voted { margin-left: auto; background: rgba(255, 255, 255, .26); color: #fff; }
.jhi-t { font-size: calc(13px * var(--fs)); font-weight: 600; line-height: 1.45; margin-top: 8px; }
.jhi-f {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 8px; font-size: calc(11px * var(--fs)); color: rgba(255, 255, 255, .82);
}
.jhi-f span { min-width: 0; }

/* 三段分布条：表态分布。子项必须 flex:0 0 auto，
   否则 inline 的 width 百分比会被 flex 压缩，比例就失真了。 */
.jh-bar, .jrc-bar {
  display: flex; height: 6px; border-radius: 999px;
  overflow: hidden; background: var(--surface-3);
}
/* 社区首屏 hero 里的分布条压在半透明深色底上，需要更亮的底色 + 上间距。
   带 `.jury-hero` 前缀而不是裸 `.jh-bar` ——
   裸选择器会让这条顺带改到别处同名的 `.jh-bar`。 */
.jury-hero .jh-bar { margin-top: 10px; background: rgba(255, 255, 255, .22); }
.jh-bar > i, .jrc-bar > i, .jury-bar3 > i { flex: 0 0 auto; height: 100%; display: block; }

.jh-empty {
  display: flex; align-items: center; gap: 8px;
  margin-top: 12px; padding: 12px 12px; border-radius: 14px;
  background: rgba(255, 255, 255, .13);
  font-size: calc(12px * var(--fs)); color: rgba(255, 255, 255, .86);
}
.jh-empty svg { flex: 0 0 auto; width: 14px; height: 14px; }

.jh-acts { display: flex; gap: 10px; margin-top: 12px; }
.jh-acts .btn { flex: 1; justify-content: center; }
.jury-hero .btn.ghost {
  background: rgba(255, 255, 255, .18); color: #fff;
  border-color: rgba(255, 255, 255, .3);
}
.jury-hero .btn.ghost:active { background: rgba(255, 255, 255, .3); }

/* 官方通道常驻入口：做在 hero 内部，但用深色块压住，
   保证「醒目」不等于「和 hero 糊成一片」 */
.jh-official {
  display: flex; align-items: center; gap: 10px;
  margin-top: 12px; padding: 12px 12px; border-radius: 14px;
  background: rgba(12, 10, 40, .34);
  border: 1px solid rgba(255, 255, 255, .16);
  cursor: pointer;
}
.jh-official:active { background: rgba(12, 10, 40, .5); }
.jh-official > svg { flex: 0 0 auto; width: 15px; height: 15px; }
.jh-official > div { flex: 1; min-width: 0; }
.jho-t { font-size: calc(12.5px * var(--fs)); font-weight: 800; color: #fff; }
.jho-d { font-size: calc(11px * var(--fs)); line-height: 1.6; color: rgba(255, 255, 255, .8); margin-top: 4px; }
.jh-official .row-arrow { flex: 0 0 auto; color: rgba(255, 255, 255, .75); }
.jh-official .row-arrow svg { width: 15px; height: 15px; }

/* ---------- 评议案卡片（列表页） ---------- */
.jrc-card {
  background: var(--surface); border-radius: var(--r);
  margin: 0 16px 12px; padding: 12px 16px;
  box-shadow: var(--shadow-sm); cursor: pointer;
}
.jrc-card:active { background: var(--surface-2); }
.jrc-h { display: flex; align-items: center; gap: 8px; }
.jrc-no {
  font-size: calc(11px * var(--fs)); font-weight: 700; color: var(--text-3);
  font-variant-numeric: tabular-nums; flex: 0 0 auto;
}
.jrc-st {
  margin-left: auto; flex: 0 0 auto;
  padding: 2px 8px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
}
.jrc-body { display: flex; align-items: flex-start; gap: 10px; margin-top: 10px; }
.jrc-body > svg, .jrc-body > .avatar { flex: 0 0 auto; }
.jrc-main { flex: 1; min-width: 0; }
.jrc-t { font-size: calc(14px * var(--fs)); font-weight: 700; line-height: 1.45; }
.jrc-d {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 6px; line-height: 1.45;
}
.jrc-d svg { flex: 0 0 auto; width: 12px; height: 12px; }
.jrc-bar-wrap { margin-top: 10px; }
.jrc-bar-f {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 6px; font-size: calc(11px * var(--fs)); color: var(--text-3);
}
.jrc-bar-f span { min-width: 0; }
.jrc-foot {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--line-2);
  font-size: calc(11.5px * var(--fs)); color: var(--text-3);
}
.jrc-foot > span { display: inline-flex; align-items: center; gap: 4px; }
.jrc-foot svg { flex: 0 0 auto; width: 12px; height: 12px; }
.jrc-tag {
  padding: 2px 8px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs)); font-weight: 700;
  display: inline-flex; align-items: center; gap: 4px;
}
.jrc-tag svg { flex: 0 0 auto; width: 11px; height: 11px; }
.jrc-tag.ok { background: var(--green-soft); color: var(--on-green); }
.jrc-tag.wait { background: var(--amber-soft); color: var(--on-amber); }
.jrc-tag.mine { background: var(--purple-soft); color: var(--purple); }
.jrc-esc {
  display: flex; align-items: center; gap: 6px;
  margin-top: 10px; padding: 8px 10px; border-radius: 10px;
  background: var(--red-soft); color: var(--red);
  font-size: calc(11.5px * var(--fs)); font-weight: 700; line-height: 1.45;
}
.jrc-esc svg { flex: 0 0 auto; width: 12px; height: 12px; }
.jrc-ruling {
  display: flex; align-items: flex-start; gap: 8px;
  margin-top: 10px; padding: 10px 12px; border-radius: 10px;
  background: var(--surface-2);
}
.jcr-b { flex: 0 0 auto; padding: 2px 8px; border-radius: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 800; }
.jcr-n { flex: 1; min-width: 0; font-size: calc(11.5px * var(--fs)); color: var(--text-2); line-height: 1.6; }
.jrc-card.compact { padding: 12px 12px; }
.jrc-card.compact .jrc-t { font-size: calc(13px * var(--fs)); }

/* ---------- 双方陈述：等宽两块，权重一样 ---------- */
.party-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; margin: 0 16px 12px; }
.party {
  padding: 12px 16px; border-radius: 14px;
  background: var(--surface); box-shadow: var(--shadow-sm);
  border-left: 3px solid var(--line);
}
.party-a { border-left-color: var(--red); }
.party-b { border-left-color: #0BA5EC; }
.party-b.pending { background: var(--surface-2); box-shadow: none; }
.party-h { display: flex; align-items: center; gap: 8px; }
.party-h svg, .party-h .avatar { flex: 0 0 auto; }
.party-badge {
  flex: 0 0 auto; padding: 2px 8px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
}
.party-badge.a { background: var(--red-soft); color: var(--red); }
.party-badge.b { background: rgba(11, 165, 236, .13); color: #0BA5EC; }
.party-n {
  font-size: calc(12.5px * var(--fs)); font-weight: 700; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.party-t { font-size: calc(13px * var(--fs)); line-height: 1.7; color: var(--text-2); margin-top: 10px; }
.party-t.muted { color: var(--text-3); font-size: calc(12.5px * var(--fs)); }
.party-ev {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 10px; font-size: calc(11px * var(--fs)); color: var(--text-3);
}
.ev-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 6px;
  background: var(--surface-3); color: var(--text-2);
  font-size: calc(10.5px * var(--fs)); font-weight: 600;
}
.ev-chip svg { flex: 0 0 auto; width: 11px; height: 11px; }
.party-at { margin-top: 10px; font-size: calc(10.5px * var(--fs)); color: var(--text-3); }

/* ---------- 陪审表决 ---------- */
/* 评议案详情页的分布条比列表卡里的粗一档（8px vs 6px）——
   这里是详情页唯一的主视觉，卡片里只是缩略。
   单独写全而不是「基础组里挂一个 + 后面再覆盖高度」，
   避免同一个类名出现两次裸定义。 */
.jury-bar3 {
  display: flex; height: 8px; border-radius: 999px;
  overflow: hidden; background: var(--surface-3);
}
.jury-legend {
  display: flex; gap: 16px; flex-wrap: wrap;
  margin-top: 10px; font-size: calc(11.5px * var(--fs)); color: var(--text-2);
}
.jury-legend > span { display: inline-flex; align-items: center; gap: 6px; }
.jury-legend i { width: 9px; height: 9px; border-radius: 4px; flex: 0 0 auto; display: block; }
.jury-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin-top: 12px; padding: 10px 12px; border-radius: 10px;
  background: var(--purple-soft); color: var(--on-purple);
  font-size: calc(11.5px * var(--fs)); line-height: 1.6;
}
.jury-note svg { flex: 0 0 auto; margin-top: 2px; width: 13px; height: 13px; }
.jury-note span { flex: 1; min-width: 0; }

.jury-vote { display: flex; gap: 8px; margin-top: 12px; }
.jv-btn {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 12px 4px; border-radius: 14px;
  background: var(--surface-2); border: 1.5px solid var(--line);
  font-size: calc(11.5px * var(--fs)); font-weight: 700; color: var(--text-2);
  cursor: pointer; line-height: 1.3; text-align: center;
}
.jv-btn svg { flex: 0 0 auto; width: 14px; height: 14px; color: var(--text-3); }
.jv-btn span { min-width: 0; }
.jv-btn:active { background: var(--surface-3); }
.jv-btn.on { border-color: var(--jc); color: var(--jc); }
.jv-btn.on svg { color: var(--jc); }
.jury-vote-hint { margin-top: 8px; font-size: calc(11px * var(--fs)); color: var(--text-3); line-height: 1.6; }

/* ---------- 最终裁决 ---------- */
.ruling-card {
  margin: 0 16px 12px; padding: 16px; border-radius: 14px;
  background: var(--surface); box-shadow: var(--shadow-sm);
  border-left: 4px solid var(--line);
}
.ruling-card.upheld { border-left-color: var(--red); background: var(--red-soft); }
.ruling-card.rejected { border-left-color: var(--green); background: var(--green-soft); }
.rc-h { display: flex; align-items: center; gap: 8px; }
.rc-h svg { flex: 0 0 auto; width: 16px; height: 16px; }
.ruling-card.upheld .rc-h svg, .ruling-card.upheld .rc-t { color: var(--red); }
.ruling-card.rejected .rc-h svg, .ruling-card.rejected .rc-t { color: var(--on-green); }
.rc-t { font-size: calc(15px * var(--fs)); font-weight: 800; }
.rc-at { margin-left: auto; flex: 0 0 auto; font-size: calc(11px * var(--fs)); color: var(--text-3); }
.rc-by { margin-top: 8px; font-size: calc(12px * var(--fs)); color: var(--text-2); font-weight: 600; }
.rc-n { margin-top: 8px; font-size: calc(13px * var(--fs)); line-height: 1.7; color: var(--text); }
.rc-link {
  display: flex; align-items: center; gap: 6px;
  margin-top: 12px; padding: 10px 12px; border-radius: 10px;
  background: rgba(255, 255, 255, .7); color: var(--red);
  font-size: calc(11.5px * var(--fs)); font-weight: 700; line-height: 1.45; cursor: pointer;
}
[data-theme="dark"] .rc-link { background: rgba(0, 0, 0, .28); }
.rc-link svg { flex: 0 0 auto; width: 13px; height: 13px; }

/* ---------- 已移交官方 ---------- */
.esc-card {
  margin: 0 16px 12px; padding: 16px; border-radius: 14px;
  background: var(--red-soft); border: 1px solid rgba(240, 68, 56, .22);
}
.esc-h {
  display: flex; align-items: center; gap: 8px;
  font-size: calc(14.5px * var(--fs)); font-weight: 800; color: var(--red);
}
.esc-h svg { flex: 0 0 auto; width: 16px; height: 16px; }
.esc-d { margin-top: 10px; font-size: calc(12.5px * var(--fs)); line-height: 1.6; color: var(--text-2); }
.esc-n {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(240, 68, 56, .18);
  font-size: calc(11.5px * var(--fs)); line-height: 1.6; color: var(--text-3);
}

/* 弹层里的官方通道说明块 */
.esc-hero {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px; border-radius: 14px; margin-bottom: 16px;
  background: var(--red-soft);
}
.esc-hero > svg { flex: 0 0 auto; width: 20px; height: 20px; color: var(--red); margin-top: 2px; }
.esc-hero > div { flex: 1; min-width: 0; }
.esc-t { font-size: calc(13.5px * var(--fs)); font-weight: 800; color: var(--red); }
.esc-hero .esc-d { font-size: calc(11.5px * var(--fs)); line-height: 1.6; color: var(--text-2); margin-top: 6px; }

/* ---------- 官方通道 CTA（评议案详情页底部，必须醒目） ---------- */
.official-cta {
  display: flex; align-items: center; gap: 12px;
  margin: 0 16px 12px; padding: 16px 16px; border-radius: 14px;
  background: linear-gradient(135deg, #B42318 0%, #E0342A 55%, #F04438 100%);
  color: #fff; cursor: pointer;
  box-shadow: 0 8px 20px rgba(224, 52, 42, .28);
}
.official-cta:active { transform: translateY(1px); }
.official-cta > svg { flex: 0 0 auto; width: 20px; height: 20px; }
.oc-main { flex: 1; min-width: 0; }
.oc-t { font-size: calc(14px * var(--fs)); font-weight: 800; }
.oc-d { font-size: calc(11.5px * var(--fs)); line-height: 1.6; color: rgba(255, 255, 255, .88); margin-top: 4px; }
.official-cta .row-arrow { flex: 0 0 auto; color: rgba(255, 255, 255, .85); }
.official-cta .row-arrow svg { width: 16px; height: 16px; }

/* ---------- 官方通道专页 ---------- */
.official-hero {
  margin: 0 16px 12px; padding: 20px 16px; border-radius: 18px;
  background: linear-gradient(135deg, #101828 0%, #2A1B1A 60%, #4A1D18 100%);
  color: #fff; text-align: center;
  box-shadow: 0 10px 24px rgba(16, 24, 40, .3);
}
.official-hero > svg { width: 26px; height: 26px; color: #FF8A80; }
.oh-t { font-size: calc(16px * var(--fs)); font-weight: 800; margin-top: 10px; }
.oh-d { font-size: calc(12px * var(--fs)); line-height: 1.7; color: rgba(255, 255, 255, .82); margin-top: 8px; text-align: left; }

.oc-list { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.oc-item {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 10px 12px; border-radius: 10px;
  background: var(--surface-2);
  font-size: calc(12px * var(--fs)); line-height: 1.6; color: var(--text-2);
}
.oc-item svg { flex: 0 0 auto; margin-top: 2px; width: 14px; height: 14px; color: var(--red); }
.oc-item span { flex: 1; min-width: 0; }

/* ---------- 评论区 ---------- */
.cmt { display: flex; align-items: flex-start; gap: 10px; padding: 12px 0; }
.cmt + .cmt { border-top: 1px solid var(--line-2); }
.cmt > svg, .cmt > .avatar { flex: 0 0 auto; }
.cmt-main { flex: 1; min-width: 0; }
.cmt-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cmt-n { font-size: calc(12.5px * var(--fs)); font-weight: 700; color: var(--text); }
.cmt-side {
  flex: 0 0 auto; padding: 2px 8px; border-radius: 6px;
  font-size: calc(10px * var(--fs)); font-weight: 800;
}
.cmt-at { margin-left: auto; flex: 0 0 auto; font-size: calc(10.5px * var(--fs)); color: var(--text-3); }
.cmt-t { font-size: calc(13px * var(--fs)); line-height: 1.7; color: var(--text-2); margin-top: 6px; word-break: break-word; }
.cmt-ev { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }

.jury-cmt-foot {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 12px;
}
.jury-cmt-foot .hint {
  flex: 1; min-width: 0;
  font-size: calc(11px * var(--fs)); color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- 评议规则弹层 ---------- */
.jr-list { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
.jr-item { padding: 12px 12px; border-radius: 10px; background: var(--surface-2); }
.jr-t { font-size: calc(13px * var(--fs)); font-weight: 800; color: var(--text); }
.jr-c { font-size: calc(12px * var(--fs)); line-height: 1.7; color: var(--text-2); margin-top: 6px; }

/* =========================================================
   商家运营（社区长 / 管理员）：下架 / 私域 / 收录
   ========================================================= */
.mo-card {
  margin: 0 16px 12px; padding: 12px 16px;
  border: 1px solid var(--line); border-radius: 14px; background: var(--surface);
}
/* 已下架卡片整体降饱和 —— 一屏里能一眼分出「在营」和「已停」两类 */
.mo-card.off { background: var(--surface-2); border-style: dashed; }
.mo-h { display: flex; align-items: center; gap: 10px; }
.mo-main { flex: 1; min-width: 0; }
.mo-t {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: calc(14.5px * var(--fs)); font-weight: 800; color: var(--text);
}
.mo-d { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-top: 4px; line-height: 1.45; }
.mo-st { font-size: calc(10.5px * var(--fs)); font-weight: 800; padding: 2px 8px; border-radius: 6px; }
.mo-st.on { background: var(--green-soft); color: var(--green); }
.mo-st.off { background: var(--red-soft); color: var(--red); }

.mo-why {
  display: flex; gap: 8px; align-items: flex-start;
  margin-top: 10px; padding: 10px 12px; border-radius: 10px;
  background: var(--red-soft); color: var(--on-red);
  font-size: calc(11.5px * var(--fs)); line-height: 1.6;
}
.mo-why svg { flex: 0 0 auto; margin-top: 2px; }
.mo-why b { font-weight: 800; }

.mo-priv {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line-2);
}
.mo-pk { font-size: calc(11.5px * var(--fs)); color: var(--text-3); margin-right: 2px; }
/* 私域入口小开关：开着用实心绿，关着用描边 ——
   两个状态必须一眼可辨，否则社区长会分不清自己到底关了没关。 */
.mo-pb {
  font-size: calc(11px * var(--fs)); font-weight: 700; padding: 4px 10px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text-3);
  cursor: pointer;
}
.mo-pb.on { background: var(--green-soft); color: var(--on-green); border-color: transparent; }
.mo-pb:disabled { opacity: .45; cursor: not-allowed; }

.mo-acts { display: flex; gap: 8px; margin-top: 12px; }
.mo-acts .btn { flex: 1; }
.btn.danger { background: var(--red); color: #fff; border-color: transparent; }
.btn.ghost.danger { background: transparent; color: var(--red); border-color: var(--red-soft); }
.mo-self {
  display: flex; align-items: center; gap: 6px;
  margin-top: 10px; font-size: calc(11px * var(--fs)); color: var(--text-3); line-height: 1.45;
}
.mo-self svg { flex: 0 0 auto; }
.mo-why-inline {
  padding: 10px 12px; border-radius: 10px; background: var(--surface-2);
  font-size: calc(12.5px * var(--fs)); color: var(--text); line-height: 1.6;
}

/* =========================================================
   公域展示排序与置顶
   ========================================================= */
.no-sub { margin-top: 12px; }
.no-sub-h {
  display: flex; align-items: baseline; gap: 6px;
  font-size: calc(12.5px * var(--fs)); font-weight: 700; color: var(--text-2);
  padding-bottom: 6px; border-bottom: 1px solid var(--line-2);
}
.no-cnt { font-size: calc(11px * var(--fs)); font-weight: 500; color: var(--text-3); }
.no-row {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 0; border-bottom: 1px solid var(--line-2);
}
.no-row:last-child { border-bottom: none; }
.no-row.pinned { background: linear-gradient(90deg, rgba(247,144,9,.10), transparent 62%); }
.no-idx {
  flex: 0 0 22px; display: grid; place-items: center;
  font-size: calc(11px * var(--fs)); font-weight: 800; color: var(--text-3);
}
.no-row.pinned .no-idx { color: var(--amber); }
.no-n {
  flex: 1; min-width: 0; font-size: calc(13px * var(--fs)); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.no-tag {
  font-size: calc(10.5px * var(--fs)); font-weight: 800; padding: 2px 6px; border-radius: 6px;
  background: var(--amber-soft); color: var(--on-amber);
}

/* =========================================================
   商家页 · 下架提示（商家主页仍可访问，但必须一次说清）
   ========================================================= */
.delist-box {
  margin: 12px 16px 0; padding: 16px;
  border: 1px solid var(--red-soft); border-radius: 14px;
  background: var(--red-soft);
}
.delist-box .db-h {
  display: flex; align-items: center; gap: 8px;
  font-size: calc(14.5px * var(--fs)); font-weight: 800; color: var(--on-red);
}
.db-rows { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.db-r { display: flex; gap: 8px; font-size: calc(12px * var(--fs)); line-height: 1.6; }
.db-k { flex: 0 0 56px; color: var(--text-3); }
.db-v { flex: 1; min-width: 0; color: var(--text); }
.db-clause {
  margin-left: 6px; font-size: calc(10.5px * var(--fs)); font-weight: 800;
  padding: 2px 6px; border-radius: 6px; background: rgba(240,68,56,.14); color: var(--on-red);
}
.db-ap {
  display: flex; gap: 8px; align-items: flex-start;
  margin-top: 10px; padding: 10px 12px; border-radius: 10px;
  background: var(--surface); font-size: calc(11.5px * var(--fs)); line-height: 1.6; color: var(--text-2);
}
.db-ap svg { flex: 0 0 auto; margin-top: 2px; }
.db-ap.pending { color: var(--on-amber); }
.db-ap b { font-weight: 800; }

/* 私域入口被社区关闭时的置灰行 */
.ps-row.off { opacity: .55; }
.ps-row.off .row-t { color: var(--text-3); }

/* 后台角标：有下架商家时用警示色 */
.badge-num.warn { background: var(--amber); }

/* ---------- 深色主题覆盖 ---------- */
[data-theme="dark"] .mo-why { color: #FDA29B; }
[data-theme="dark"] .delist-box .db-h { color: #FDA29B; }
[data-theme="dark"] .db-clause { background: rgba(240,68,56,.22); color: #FDA29B; }
[data-theme="dark"] .mo-st.off { color: #FDA29B; }
[data-theme="dark"] .mo-pb.on { color: #5BE49B; }
[data-theme="dark"] .no-row.pinned { background: linear-gradient(90deg, rgba(247,144,9,.16), transparent 62%); }
[data-theme="dark"] .no-tag { color: #FDB022; }
[data-theme="dark"] .db-ap.pending { color: #FDB022; }

/* =========================================================
   身份标识（认证徽章 / 唯一 ID / 未实名）
   ---------------------------------------------------------
   老板原话：「所有认证标识必须跟随这个人，到任何窗口位置，
   必须显眼，明显。防止冒充，假冒。」

   所以这里刻意不用以前的 role-chip 那套「浅底 + 深字」——
   浅底小标签在长列表里几乎看不见，防冒充就落空了。
   改成「实心色块 + 白字 + 图标」：色块是唯一身份色，
   一眼能扫到，且和旁边的普通文字有强对比。

   未实名用「灰色虚线描边」而不是「灰色实心」——
   要让「没有认证」和「认证了但颜色不同」在扫视时就能分开。
   ========================================================= */
.id-tag {
  display: inline-flex; align-items: center; gap: 4px;
  flex: 0 0 auto; vertical-align: middle;
  font-size: calc(11px * var(--fs)); font-weight: 700; line-height: 1.3;
  padding: 4px 8px; border-radius: 6px;
  white-space: nowrap;
}
.id-tag.sm { font-size: calc(10px * var(--fs)); padding: 2px 6px; border-radius: 6px; }
.id-tag.verified {
  background: var(--ic, #12B76A); color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .16);
}
.id-tag.unverified {
  background: transparent; color: var(--text-3);
  border: 1px dashed var(--line); font-weight: 600;
}
/* 折叠的认证标签。用「实线描边 + 中性底」——
   和未实名的「虚线描边」区分开：一个表示「还有别的认证」，
   一个表示「一个认证都没有」，两者的视觉语言不能混。 */
.id-tag.more {
  background: var(--surface-2); color: var(--text-2);
  border: 1px solid var(--line); font-weight: 600;
}
.id-tag.handle {
  background: var(--surface-2); color: var(--text-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 600; letter-spacing: -.2px;
}

/* 名字 + 标签：标签紧跟名字，但允许整组换行。
   用 flex + wrap 而不是纯 inline —— inline 的长标签在窄屏
   会把名字挤成「一行一个字」。 */
.uname { font-weight: 600; }
.uname-tags { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; margin-left: 6px; }

/* 名字下面那行的 @ID */
.handle-chip {
  display: inline-flex; align-items: center;
  font-size: calc(11px * var(--fs));
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--text-3); background: var(--surface-2);
  padding: 2px 6px; border-radius: 6px; letter-spacing: -.2px;
}
.handle-chip.sm { font-size: calc(10px * var(--fs)); padding: 2px 6px; }

/* 未实名账号的会话顶部警示：常驻、不可关闭 */
.risk-banner {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 12px 0 4px; padding: 12px 12px;
  border-radius: 14px; background: var(--amber-soft);
  border: 1px solid rgba(247, 144, 9, .3);
}
.risk-banner svg { flex: 0 0 auto; color: var(--amber); margin-top: 2px; }
.rb-main { flex: 1; min-width: 0; }
.rb-t { font-size: calc(12.5px * var(--fs)); font-weight: 800; color: var(--on-amber); }
.rb-d { font-size: calc(11.5px * var(--fs)); color: var(--on-amber); opacity: .85; line-height: 1.6; margin-top: 4px; }

/* 陌生人信息条（TG 式开放私信的配套）。
   ---------------------------------------------------------
   和 .risk-banner 刻意用**不同颜色**：
     · risk-banner = 警告（琥珀）——「这条你必须看，有风险」
     · stranger-bar = 信息（蓝）——「这几条信息帮你判断」
   两处都用琥珀的话，用户会把每条陌生私信都当成警告，
   两天就脱敏了 —— 真出事那一条反而没人看。
   警告的稀缺性就是它的有效性。

   版式分两行而不是挤一行：
   375px 的手机上，图标 + 两行文字 + 「添加好友」「屏蔽」
   挤在一行会把文字压成很窄一条（实测中文会断成 3 个字一行）。
   所以第一行图标+文字、第二行按钮，且按钮缩进对齐文字。 */
.stranger-bar {
  display: flex; flex-direction: column; gap: 8px;
  margin: 12px 0 4px; padding: 10px 12px;
  border-radius: 14px; background: var(--accent-soft);
  border: 1px solid var(--line);
}
.stranger-bar .sb-row1 { display: flex; gap: 10px; align-items: flex-start; }
.stranger-bar .sb-row1 svg { flex: 0 0 auto; color: var(--accent); margin-top: 2px; }
.stranger-bar .sb-main { flex: 1; min-width: 0; }
.stranger-bar .sb-t { font-size: calc(12.5px * var(--fs)); font-weight: 800; color: var(--text); }
.stranger-bar .sb-d { font-size: calc(11.5px * var(--fs)); color: var(--text-2); line-height: 1.6; margin-top: 3px; }
/* 按钮缩进 27px = 图标 17px + 间距 10px，和上面的文字左边缘对齐 */
.stranger-bar .sb-acts { display: flex; gap: 8px; margin-left: 27px; }
.stranger-bar .sb-acts .btn { flex: 0 0 auto; }
/* 已屏蔽态：红色。这时用户的诉求是「别再让他找我」，
   是行动而不是判断，所以用警示色是对的。 */
.stranger-bar.blocked { background: var(--red-soft); }
.stranger-bar.blocked .sb-row1 svg { color: var(--red); }

/* 聊天区局部收档。
   老板反馈「聊天页面的字体有点偏大」，但整站基准不能跟着降 ——
   聊天是长文本、列表是短文本，两者合适的字号本来就不同。
   所以在聊天页外面包一层，把 --fs 乘 .90，与全局档位叠加：
   用户把全局调到「特大」时，聊天区同样是 1.34 × .90，仍然跟着放大。 */
.chat-wrap { --fs: calc(var(--fsRoot) * .90); }

/* 消息列表容器（实时追加的锚点）。
   ---------------------------------------------------------
   这一层是给「收到新消息」用的：realtime.js 只往这里 appendChild，
   不重建整页 —— 重建会把正在输入的草稿、光标、焦点全冲掉。

   ★ 它**刻意不设任何布局属性**。
   消息之间的间距（.msg-day / .msg-sys / .msg-row 的 margin）
   都是各自元素上的，不依赖父级是不是 flex、有没有 gap，
   所以中间多包一层不会改变任何间距 —— 这一点是查过才敢包的。

   写这条规则是为了过「JS 里出现的类名必须在 CSS 里有定义」那条体检：
   它抓的是「元素完全没有样式」这类问题。一个纯结构容器如果漏了，
   症状会非常隐蔽（大多数时候看着是对的，只在某些继承属性上出偏差）。 */
.msg-list { display: block; }

/* =========================================================
   字体大小设置页
   ========================================================= */
.fs-preview {
  margin: 0 16px 4px; padding: 16px;
  border: 1px solid var(--line); border-radius: 14px; background: var(--surface);
}
.fs-pv-row { display: flex; align-items: flex-start; gap: 8px; }
.fs-pv-row + .fs-pv-row { margin-top: 12px; }
.fs-pv-row.out { justify-content: flex-end; }
.fs-pv-col { min-width: 0; max-width: 82%; }
.fs-pv-name {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: calc(12px * var(--fs)); font-weight: 700; margin-bottom: 4px;
}
.fs-pv-row.out .fs-pv-col { text-align: right; }
/* 预览里的气泡不能用 .msg-row 的左右对齐逻辑（这里没有 data 层） */
.fs-pv-col .bubble { display: inline-block; text-align: left; }
.fs-pv-col .bubble.out {
  background: linear-gradient(135deg, #2F6BFF, #4B82FF);
  color: #fff; border-radius: 18px; border-bottom-right-radius: 5px;
}
.fs-pv-list {
  margin-top: 16px; padding-top: 12px; border-top: 1px dashed var(--line);
  display: flex; flex-direction: column; gap: 10px;
}
.fs-pv-li { display: flex; flex-direction: column; gap: 2px; }
.fs-pv-li b { font-size: calc(14px * var(--fs)); font-weight: 700; }
.fs-pv-li span { font-size: calc(11.5px * var(--fs)); color: var(--text-3); }

/* 档位单选圈：选中用实心，未选用空心描边 */
.fs-pick {
  width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid var(--line); flex: 0 0 auto;
  display: grid; place-items: center; color: #fff;
}
.fs-pick.on { background: var(--accent); border-color: var(--accent); }

/* =========================================================
   唯一 ID 设置页
   ========================================================= */
.uhx-hero {
  display: flex; flex-direction: column; align-items: center;
  gap: 8px; padding: 4px 16px 16px; text-align: center;
}
.uhx-name { font-size: calc(17px * var(--fs)); font-weight: 800; }


.hx-input {
  display: flex; align-items: center; gap: 0;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); overflow: hidden;
}
.hx-input:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.hx-at {
  padding: 0 4px 0 12px; color: var(--text-3);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: calc(15px * var(--fs));
}
.hx-input input {
  flex: 1; min-width: 0; padding: 12px 8px 12px 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: -.3px;
}
.hx-check {
  flex: 0 0 auto; padding: 0 12px; align-self: stretch;
  font-size: calc(12.5px * var(--fs)); font-weight: 700; color: var(--accent);
  border-left: 1px solid var(--line-2); cursor: pointer;
}
.hx-check:active { background: var(--surface-2); }

/* 实时校验结果：三种状态必须一眼可分 */
.hx-result:empty { display: none; }
.hx-result {
  margin-top: 10px; padding: 12px 12px; border-radius: 10px;
  font-size: calc(12px * var(--fs)); line-height: 1.6;
}
.hx-result.ok { background: var(--green-soft); color: var(--on-green); }
.hx-result.bad { background: var(--red-soft); color: var(--on-red); }
.hx-result.idle { background: var(--surface-2); color: var(--text-2); }
.hx-result b { font-weight: 800; }
.hx-result code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: rgba(0, 0, 0, .07); padding: 2px 6px; border-radius: 6px;
  letter-spacing: -.3px;
}

/* ---------- 深色主题覆盖 ---------- */
[data-theme="dark"] .id-tag.unverified { border-color: #475467; color: #98A2B3; }
[data-theme="dark"] .id-tag.handle { color: #D0D5DD; }
[data-theme="dark"] .risk-banner { border-color: rgba(247, 144, 9, .38); }
[data-theme="dark"] .rb-t, [data-theme="dark"] .rb-d { color: #FDB022; }
[data-theme="dark"] .hx-result.ok { color: #5BE49B; }
[data-theme="dark"] .hx-result.bad { color: #FDA29B; }
[data-theme="dark"] .hx-result code { background: rgba(255, 255, 255, .12); }

/* =========================================================
   导航栏里的身份区（私聊窗口标题）
   ---------------------------------------------------------
   版式与「会话信息页」一致（老板指定的）：
     第一行 = 名字 + 认证标识（标识在名字**后面**，同一行）
     第二行 = @ID（单独一行，在名字下面）

   为什么不能用 .nav-sub 那种「两行文字」的做法：
   .nav-sub 是纯文字，而第一行里要放的是 flex 标签组。
   也不能沿用旧的 .ni-tags —— 那是「名字一行、徽章和 @ID
   一起挤在第二行」，结果就是老板看到的
   「图标和 id 挤在一起」。两行现在各司其职：
   第一行回答「是谁」，第二行回答「怎么区分同名的人」。

   .navbar 是 min-height 而不是固定高度，两行会自然撑高一点。
   这里要显式解掉 .nav-title 的 nowrap —— 否则标签组会被
   当成一行文字截断成「实名认…」。
   ========================================================= */
.nav-ident {
  display: flex; flex-direction: column; align-items: center;
  gap: 2px; min-width: 0;
}
.ni-name {
  font-size: calc(15.5px * var(--fs)); font-weight: 700; line-height: 1.3;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 导航栏是最窄的地方（左右各 38px 按钮），所以第一行**不换行**：
   宁可把名字截断，也不能让标签掉到第二行去 ——
   掉下去之后「名字 / 标签 / @ID」会变成三行，把导航栏撑高，
   聊天区白白少一截。截断的是名字，认证标识始终完整可见。 */
.nav-ident .ni-line { flex-wrap: nowrap; justify-content: center; max-width: 100%; }
.nav-ident .ni-line > .ni-name { flex: 0 1 auto; min-width: 0; }
/* 第二行的 @ID。用 chip 形态（与会话信息页一致），
   但在导航栏里把内边距收紧一档 —— 同一套版式，不同的呼吸量。 */
.nav-ident .ni-id {
  margin-top: 1px;
  padding: 2px 10px; border-radius: 6px;
  font-size: calc(10.5px * var(--fs));
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 我的页面：@ID 与实名状态同一行 */

/* =========================================================
   商家页 · 经营者（把「商家」和「背后的人」连起来）
   ========================================================= */
.mch-owner {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin: 12px 16px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 14px; background: var(--surface);
}
.mch-owner:active { background: var(--surface-2); }
.mco-k { flex: 0 0 auto; font-size: calc(11.5px * var(--fs)); color: var(--text-3); }
.mco-none { font-size: calc(12px * var(--fs)); color: var(--text-3); }
.mch-owner .row-arrow { margin-left: auto; }

/* =========================================================
   身份标识 · 只出图标态（实名认证专用）
   ---------------------------------------------------------
   老板原话：「这个实名认证这个显示有点长了，就显示个已实名或
   直接给出一个绿色的这个盾牌小标就好了……其他的地方只需要带
   前面的标识就好了。不需要带实名认证账号或者实名这个字」

   为什么要专门做一个「实心小方块」而不是沿用浅底描边：
   实名标是**全站出现频率最高**的元素（每条消息、每个列表项、
   每个评论都跟着），浅底标签在密集列表里几乎扫不到，
   防冒充就落空了。实心绿块 + 白盾牌是「一眼可见」的最小面积方案。

   尺寸刻意做成正方形（padding 均等），图标居中 ——
   留白不均会让它看起来像个被裁掉的文字标签。
   ========================================================= */
.id-tag.icon-only,
.cert-chip.icon-only {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 4px; border-radius: 6px; gap: 0;
  background: var(--ic, #12B76A); color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .16);
}
.id-tag.icon-only.sm, .cert-chip.icon-only.sm { padding: 2px; border-radius: 6px; }
.id-tag.icon-only svg, .cert-chip.icon-only svg { display: block; }

/* 折叠标签（身份太多、版面不够时把后面几个收起来）。
   它**必须也是图标框**：同一个身份，没折叠的地方是彩色图标方块、
   折叠之后变成一段灰字，用户会以为这是两种不同的东西 ——
   老板的原话是「有的地方有图标框，有的地方怎么只显示字」。
   折叠只是省版面，不该换掉身份的视觉形态。
   超过 1 个时在图标后补一个数字：数字是「还有几个」，
   颜色沿用第一个被折叠身份的颜色（至少让人知道收起来的是什么色系）。 */
.id-tag.icon-only.more.has-n { padding: 4px 6px 4px 4px; gap: 1px; }
.id-tag.icon-only.more.has-n.sm { padding: 2px 6px 2px 2px; }
.id-tag.icon-only .id-n {
  font-style: normal; font-weight: 800; line-height: 1;
  font-size: 9.5px; opacity: .92;
}

/* 深色主题下实心绿块本来就够亮，把投影去掉免得发灰 */
[data-theme="dark"] .id-tag.icon-only,
[data-theme="dark"] .cert-chip.icon-only { box-shadow: none; }

/* =========================================================
   姓名行 · 统一规则
   ---------------------------------------------------------
   老板定的规则，全站一律照此办理：
     「账号id可以留在名字下面的中间，这样看起来舒适一点，
       认证标识在名字的后面」

   所以：名字 + 认证标识**同一行**，账号 ID 单独一行在名字下面。
   标识另起一行会独占整行，名字与标识之间出现断层；
   同行之后「谁 + 什么认证」是一眼读完的一件事。

   .nm-line 同时服务左对齐（头像在左的头部）与居中（头像在上的头部）——
   它自己不设 text-align，由父容器决定，这样一套类能用两种版式。
   ========================================================= */
.nm-line {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  min-width: 0;
}
/* 名字可以截断，但标识不能被挤掉 —— 截断的是名字，认证必须始终看得见。
   用 flex: 0 1 auto + min-width: 0 让名字先让位。 */
.nm-line > .nm-n,
.nm-line > .me-name,
.nm-line > .uh-name,
.nm-line > .uhx-name,
.nm-line > .mh-name {
  flex: 0 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 名字下面那行 @ID —— 全站唯一一处定义。
   以前这里有三套（.me-handle / .uh-handle / .uhx-id），
   字号分别是 12 / 12.5 / 13px，谁都看不出差别、合起来就是「不齐」。
   现在统一走 .nm-id，只在「ID 设置页」加 .chip 变体 ——
   那一页的主题就是 ID 本身，用胶囊强调一下是有意义的；
   其他页面（我的 / 用户主页 / 会话信息）保持安静的纯文字。 */
.nm-id {
  margin-top: 6px;
  font-size: calc(12px * var(--fs));
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--text-3); letter-spacing: -.2px;
}
.nm-id.chip {
  display: inline-block; margin-top: 0;
  background: var(--surface-2); color: var(--text-2);
  padding: 4px 12px; border-radius: 10px;
}

/* 头像在上、内容居中的头部（私聊信息页） */
.nm-hero {
  display: flex; flex-direction: column; align-items: center;
  gap: 10px; padding: 24px 16px 20px; text-align: center;
  background: var(--surface);
}
.nm-hero .nm-line { justify-content: center; }
.nm-hero .nm-n { font-size: calc(19px * var(--fs)); font-weight: 800; }
.nm-hero .nm-id {
  margin-top: 0; background: var(--surface-2);
  padding: 4px 10px; border-radius: 10px;
}

/* =========================================================
   个人资料页 · 头像区
   ---------------------------------------------------------
   这一块解决的是「资料页不能换头像」。既然要让人**发现**它能点，
   头像就不能只是一张静图：
     1. 相机角标 —— 「这里可以点」的信号，和微信 / Telegram 一致
     2. 按下时整体轻微缩小 —— 手机上这是「我点到了」的即时反馈
   角标不承担点击，点的是整个 96px 的圆 ——
   手指去够一个 28px 的角标是很别扭的。
   ========================================================= */
.pf-hero {
  display: flex; flex-direction: column; align-items: center;
  gap: 12px; padding: 24px 16px 20px;
  background: var(--surface);
}
.pf-av { position: relative; cursor: pointer; transition: transform var(--dur) var(--ease); }
.pf-av:active { transform: scale(.97); }
.pf-av .av { box-shadow: 0 6px 18px rgba(16, 24, 40, .13); }
.pf-cam {
  position: absolute; right: -2px; bottom: -2px;
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent); color: #fff;
  border: 2.5px solid var(--surface);
  box-shadow: 0 2px 6px rgba(16, 24, 40, .18);
}
.pf-who { text-align: center; min-width: 0; max-width: 100%; }
.pf-who .nm-line { justify-content: center; }
/* 名字可以让位，认证标识不能让 —— 与 .nm-line 的通用规则同一原则。 */
.pf-name {
  flex: 0 1 auto; min-width: 0;
  font-size: calc(19px * var(--fs)); font-weight: 800;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* =========================================================
   更换头像面板（底部弹层）
   ---------------------------------------------------------
   两种方式平级呈现（相册 / 文字），顶部一块实时预览。
   .sheet-body 自己不带左右内边距（.sheet-item 自带 20px），
   所以这里的每一段都要自己留 20px。
   ========================================================= */
.av-edit {
  display: flex; flex-direction: column; align-items: center;
  gap: 8px; padding: 10px 20px 16px;
}
.av-prev { line-height: 0; filter: drop-shadow(0 8px 20px rgba(16, 24, 40, .16)); }
.av-state { font-size: calc(12px * var(--fs)); color: var(--text-3); }
.av-sec { border-top: 1px solid var(--line); padding: 16px 20px; }
.av-sec-t { font-size: calc(13.5px * var(--fs)); font-weight: 700; margin-bottom: 4px; }
.av-sec-d {
  font-size: calc(12px * var(--fs)); color: var(--text-3);
  line-height: 1.55; margin-bottom: 10px;
}
.av-txt { display: flex; gap: 8px; align-items: center; }
.av-txt input {
  flex: 1; min-width: 0; height: 40px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2); color: var(--text);
  font-size: calc(14px * var(--fs));
}
.av-txt input:focus { border-color: var(--accent); outline: none; }
.av-colors { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.av-c {
  width: 32px; height: 32px; border-radius: 50%;
  border: 2px solid transparent;
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .55);
  transition: transform var(--dur) var(--ease);
}
.av-c:active { transform: scale(.92); }
/* 选中的配色用一圈深色描边 —— 不用打勾图标：
   32px 的圆里塞个勾会看不清，而描边不占地方、颜色也不受底色影响。 */
.av-c.on { border-color: var(--text); }
.av-note {
  display: flex; gap: 8px; align-items: flex-start;
  border-top: 1px solid var(--line); padding: 12px 20px 4px;
  font-size: calc(11.5px * var(--fs)); color: var(--text-3); line-height: 1.6;
}
.av-note svg { flex: 0 0 auto; margin-top: 2px; }
.av-note b { color: var(--text-2); }

/* =========================================================
   商家页 · 头部与简介连成一块
   ---------------------------------------------------------
   简介本来就是头部信息的延续。原来给它套一层卡片、再写一遍
   「商家简介」四个字，等于把一块内容切成两段 —— 读起来就是割裂。
   这里让头部与简介共用同一块白底，中间不画线、不加标题，
   只用间距分层。这就是老板要的「像 TG 一样简洁」。
   ========================================================= */
/* 商家主页头部区（头像 + 名称 + 简介连成一块白底）。
   ⚠ 不能叫 .mch-top —— 那个名字已经被「商家列表卡片」的头部占了
   （.mch-top { display:flex; align-items:center; gap:12px }）。
   两者属性不冲突、会静默合并，结果是这个包裹层被当成 flex 行，
   里面的 .mh-info 被压成 95px 宽、认证标被迫换行 ——
   正是老板抱怨的「标识跑到名字下面」。
   类名撞车不报错，只会长得不对劲，所以这类体检必须常跑。 */
.mch-head { background: var(--surface); }
.mch-head .mch-hero { background: transparent; padding-bottom: 12px; }
.mch-intro {
  padding: 0 16px 20px;
  font-size: calc(13.5px * var(--fs)); color: var(--text-2);
  line-height: 1.65;
}

/* =========================================================
   最近照片 · 网格（TG 风格）
   ---------------------------------------------------------
   3 列正方形。照片从真实消息推导，不是写死的相册 ——
   写死的话聊天里发了新图这里不更新，就成了假的展示位。
   只铺前 6 张，最后一格盖「+N」：这一块的作用是
   「一眼看到有照片，点进去看全部」，不是把页面撑长。
   ========================================================= */
.ph-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px; margin: 0 16px 12px;
  border-radius: var(--r); overflow: hidden;
}
.ph-cell {
  position: relative; aspect-ratio: 1 / 1;
  overflow: hidden; background: var(--surface-2);
  cursor: pointer; transition: opacity var(--dur) var(--ease);
}
.ph-cell:active { opacity: .8; }
.ph-cell .ph-art { width: 100%; height: 100%; display: block; }
.ph-more {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(12, 18, 30, .52); color: #fff;
  font-size: calc(15px * var(--fs)); font-weight: 800;
  letter-spacing: .3px;
}

/* =========================================================
   照片查看器（全屏 + 底部缩略图带）
   ---------------------------------------------------------
   老板原话：「这样用户就可以点它的时候第一时间看到菜单了」。
   底部那条缩略图带就是「菜单」：一眼看到全部、知道在第几张、
   可以直接跳。没有它，用户只能一张张点「下一张」，
   不知道自己错过了什么。

   z-index 180 —— 在底部导航（30）之上、确认弹层（200）之下：
   查看器开着的时候弹确认框，弹层必须压在上面。
   ========================================================= */
.phv {
  position: absolute; inset: 0; z-index: 180;
  display: flex; flex-direction: column;
  animation: phvIn var(--dur) var(--ease);
}
@keyframes phvIn { from { opacity: 0; } to { opacity: 1; } }
/* 遮罩：接近不透明 + 背景虚化。
   只调不透明度不够 —— 底下的正文是高对比的深色字，
   5% 的透出就足以让人**读出**背后的文字（截图里能看清「蜀香麻辣烫」
   「认证信息链路」），观感是「脏」，不是「有层次」。
   加一层 backdrop-filter 之后，透出来的是模糊色块而不是可读文字，
   既保住「背后还有东西」的空间感，又不干扰看图。 */
.phv-mask {
  position: absolute; inset: 0;
  background: rgba(6, 9, 15, .97);
  -webkit-backdrop-filter: blur(20px) saturate(120%);
  backdrop-filter: blur(20px) saturate(120%);
}

.phv-top {
  position: relative; z-index: 2;
  display: flex; align-items: center; gap: 10px;
  padding: 16px 16px 10px; color: #fff;
}
.phv-x {
  width: 34px; height: 34px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .14); color: #fff; border: none;
}
.phv-x:active { background: rgba(255, 255, 255, .26); }
.phv-meta { flex: 1; min-width: 0; }
.phv-from { font-size: calc(13.5px * var(--fs)); font-weight: 700; }
.phv-time { font-size: calc(11.5px * var(--fs)); opacity: .68; margin-top: 2px; }
.phv-sp { width: 34px; flex: 0 0 auto; }

.phv-stage {
  position: relative; z-index: 2;
  flex: 1; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 0 12px;
}
.phv-img {
  width: 100%; max-height: 100%; aspect-ratio: 1 / 1;
  border-radius: var(--r); overflow: hidden;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .5);
}
.phv-img .ph-art { width: 100%; height: 100%; display: block; }
.phv-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 34px; height: 34px; border-radius: 50%; z-index: 3;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .16); color: #fff; border: none;
}
.phv-nav.prev { left: 14px; }
/* 「下一张」用 chev（本身就是右箭头），**不能**再 rotate(180deg) ——
   转了之后按钮功能是「下一张」、图标却指向左，用户会点反。
   两个按钮各自用语义正确的图标：prev 用 back（左）、next 用 chev（右）。 */
.phv-nav.next { right: 14px; }
.phv-nav:active { background: rgba(255, 255, 255, .3); }

.phv-info {
  position: relative; z-index: 2;
  padding: 12px 20px 4px; color: #fff; text-align: center;
}
.phv-t { font-size: calc(14px * var(--fs)); font-weight: 700; }
.phv-c { font-size: calc(12.5px * var(--fs)); opacity: .74; margin-top: 4px; line-height: 1.55; }

.phv-strip {
  position: relative; z-index: 2;
  display: flex; gap: 6px; overflow-x: auto;
  padding: 12px 16px 20px;
  scrollbar-width: none;
}
.phv-strip::-webkit-scrollbar { display: none; }
.phv-th {
  width: 46px; height: 46px; flex: 0 0 auto;
  border-radius: 10px; overflow: hidden; padding: 0; border: none;
  background: none; cursor: pointer;
  opacity: .45; transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.phv-th .ph-art { width: 100%; height: 100%; display: block; }
.phv-th.on { opacity: 1; box-shadow: 0 0 0 2px #fff; }
.phv-th:active { transform: scale(.94); }

/* =========================================================
   认证行（会话信息页 · 私聊）
   ---------------------------------------------------------
   只有「徽章 + 认证方」两件东西，所以做成一行而不是一张带小标题的卡 ——
   原来那版有 sectionLabel + 徽章 + 认证方三行、吃掉 110px 高度，
   而内容只有一行信息量，视觉上就是「空」。
   「认证方」不能省：它回答的是「这个认证谁给的」，
   是防冒充里最要紧的一环（认证方是平台官方，还是某个社区自证，
   可信度完全不同）。徽章本身回答不了这个问题。
   ========================================================= */
.cert-line {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 12px 16px 12px; padding: 12px 16px;
}
.cl-by { font-size: calc(12px * var(--fs)); color: var(--text-3); }

/* =========================================================
   登录 / 启动过渡
   ---------------------------------------------------------
   这两屏是接上服务端之后才出现的 —— 原型阶段打开就是主界面。
   设计上刻意「轻」：一张卡、两个输入框、一个按钮。
   登录页是用户见到产品第一眼的地方，堆功能只会让人犹豫。
   ========================================================= */
.boot-page {
  height: 100%; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 16px;
}
.boot-logo {
  width: 66px; height: 66px; border-radius: 18px;
  background: linear-gradient(145deg, var(--accent), #5B8CFF);
  color: #fff; font-size: 30px; font-weight: 800;
  display: grid; place-items: center; box-shadow: var(--shadow-sm);
}
.boot-text { font-size: calc(13px * var(--fs)); color: var(--text-2); }

.auth-page { min-height: 100%; padding: 0 24px 32px; }
.auth-head { padding: 56px 0 24px; text-align: center; }
.auth-logo {
  width: 60px; height: 60px; margin: 0 auto; border-radius: 18px;
  background: linear-gradient(145deg, var(--accent), #5B8CFF);
  color: #fff; font-size: 27px; font-weight: 800;
  display: grid; place-items: center; box-shadow: var(--shadow-sm);
}
.auth-name {
  font-size: calc(23px * var(--fs)); font-weight: 800;
  letter-spacing: 2px; margin-top: 16px; color: var(--text);
}
.auth-slogan {
  font-size: calc(12.5px * var(--fs)); color: var(--text-3);
  margin-top: 8px; line-height: 1.6;
}
.auth-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: 20px 16px 16px;
  box-shadow: var(--shadow-sm);
}
.auth-card .field:last-of-type { margin-bottom: 10px; }
/* 错误行常驻占位（min-height）——
   不留位置的话，出现错误时整个按钮会往下跳一格，
   而用户正要点它。 */
.auth-err {
  min-height: 19px; font-size: calc(12.5px * var(--fs));
  color: var(--red); line-height: 1.5; margin: 0 0 10px;
}
.auth-fp { margin-top: 10px; display: flex; align-items: center; justify-content: center; gap: 8px; }
.auth-switch {
  text-align: center; font-size: calc(13px * var(--fs));
  color: var(--text-2); margin-top: 16px;
}
.auth-switch a { color: var(--accent); font-weight: 600; cursor: pointer; }
.auth-note {
  margin-top: 12px; font-size: calc(11px * var(--fs));
  color: var(--text-3); line-height: 1.7;
}

/* 发送失败标记。
   刻意做成红色小字而不是「把气泡变红」——
   消息内容本身没问题，是发送这一步失败了，
   把整条消息涂红会让用户以为内容违规。 */
.msg-fail { color: var(--red); font-weight: 600; cursor: help; }

/* =========================================================
   社区圈
   ---------------------------------------------------------
   它是社区内容的展示窗口：一屏看完这个社区今天发生的事。

   与「公域动态」的区别是**视角**，不是数据：
     · 公域动态 = 经营视角（商家看今日推广额度、按类型筛、发布）
     · 社区圈   = 浏览视角（今天发生了什么、谁发的）
   两边读同一份数据（S.feedOf），不存在两套内容。

   ⚠️ 前缀是 circle-。
   .desk-* 那一套随服务台一起删掉了 —— 老板定的：找师傅并入
   社区的「服务人员」板块，不再单独维护一套师傅名录。
   两套名录并存的那段时间，用户看到两个地方列着同一批人，
   而数据还不一样（一边有电话、一边有认证）。
   ========================================================= */
.circle-slogan {
  font-size: calc(12.5px * var(--fs));
  color: var(--text-2); margin-top: 6px;
}

/* ---- 社区切换 ---- */
/* 第一排是社区、第二排是内容类型，两排长得几乎一样。
   所以区分靠内容本身（社区名 / 类型名+条数），不靠颜色 ——
   给两排配不同底色的话，用户会以为其中一排是「选中状态」。 */
.circle-switch { padding: 12px 16px 2px; }

/* ---- 社区头卡 ---- */
.circle-head {
  display: flex; align-items: flex-start; gap: 12px;
  margin: 8px 16px 4px; padding: 16px 16px;
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--shadow-sm); cursor: pointer;
}
.circle-head-main { flex: 1 1 auto; min-width: 0; }
.circle-head-nm {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: calc(15px * var(--fs)); font-weight: 700; color: var(--text);
}
.circle-head-sub {
  margin-top: 6px; font-size: calc(12px * var(--fs));
  color: var(--text-2); line-height: 1.6;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.circle-head-meta { margin-top: 6px; font-size: calc(11.5px * var(--fs)); color: var(--text-3); }
.circle-head-right { flex: 0 0 auto; text-align: center; padding-left: 4px; }
.circle-head-right b {
  display: block; font-size: calc(20px * var(--fs)); font-weight: 800;
  color: var(--accent); font-variant-numeric: tabular-nums; line-height: 1.1;
}
.circle-head-right span { font-size: calc(11px * var(--fs)); color: var(--text-3); }

/* ---- 类型筛选 ---- */
.circle-types { padding: 10px 16px 2px; }

/* ---- 空态 ---- */
/* 空社区是常态（刚建、或者社区长还没发过），
   所以它得是一个「有下一步」的页面，不是一句「暂无数据」。 */
.circle-blank {
  margin: 12px 16px; padding: 32px 24px; text-align: center;
  background: var(--surface-2); border-radius: var(--r); color: var(--text-3);
}
.circle-blank-t {
  margin-top: 10px; font-size: calc(14px * var(--fs));
  font-weight: 600; color: var(--text-2);
}
.circle-blank-d { margin-top: 8px; font-size: calc(12px * var(--fs)); line-height: 1.75; }
.circle-empty-note {
  margin: 0 16px 16px; text-align: center;
  font-size: calc(12px * var(--fs)); color: var(--text-3); line-height: 1.75;
}

/* ---- 脚注 ---- */
.circle-foot-note {
  display: flex; gap: 8px; align-items: flex-start;
  margin: 8px 16px 0; font-size: calc(11.5px * var(--fs));
  color: var(--text-3); line-height: 1.7;
}
.circle-foot-note svg { flex: 0 0 auto; margin-top: 2px; }

/* =========================================================
   真实晒单
   ---------------------------------------------------------
   ⚠️ 前缀是 rcpt-，不是 rc-。
   .rc-h / .rc-t / .rc-n / .rc-at / .rc-by / .rc-link 已经被
   别处占用了（见文件上半部分）。裸类名撞名的后果不是报错，
   是「属性只覆盖一半，另一半从旧规则漏过来」——
   服务台那次 .svc-card 撞上 width:244px 就是这么坏的：
   卡片被压窄，而页面看起来「只是有点怪」。
   cssdup.js 会拦这种撞名，别改回去。

   两个视觉决定：
   1. 待核验 / 已驳回的卡片整体变暗。用户需要一眼分辨
      「哪些已经生效了」，而不是逐条读小字标签。
   2. 金额用大号数字。它是这条晒单里最硬的信息 ——
      「花多少」是邻居决定去不去的第一依据。
   ========================================================= */

/* 社区首页的入口卡 */
.rcpt-entry {
  display: flex; align-items: center; gap: 12px;
  margin: 12px 16px 4px; padding: 16px 16px;
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--shadow-sm); cursor: pointer;
}
.rcpt-entry-ic {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
}
.rcpt-entry-main { flex: 1 1 auto; min-width: 0; }
.rcpt-entry-t { font-size: calc(14.5px * var(--fs)); font-weight: 600; color: var(--text); }
.rcpt-entry-d { margin-top: 4px; font-size: calc(12px * var(--fs)); color: var(--text-2); }

/* 汇总条 */
.rcpt-sum {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px;
  margin: 12px 16px 0; padding: 16px 6px;
  background: var(--surface); border-radius: var(--r); box-shadow: var(--shadow-sm);
}
.rcpt-sum-i { text-align: center; }
.rcpt-sum-i b {
  display: block; font-size: calc(17px * var(--fs)); font-weight: 700;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.rcpt-sum-i span { display: block; margin-top: 2px; font-size: calc(11px * var(--fs)); color: var(--text-3); }

.rcpt-bar { display: flex; gap: 10px; margin: 12px 16px 0; }
.rcpt-bar .btn { flex: 1 1 0; }

.rcpt-list { padding: 12px 16px 20px; }

/* 晒单卡片 */
.rcpt-card {
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--shadow-sm); padding: 16px 16px;
  margin-bottom: 12px; cursor: pointer;
}
/* 还没生效的（待核验 / 被驳回）整体变暗 */
.rcpt-card.dim { opacity: .62; }

.rcpt-top { display: flex; align-items: center; gap: 10px; }
.rcpt-ava {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  color: #fff; font-size: calc(14px * var(--fs)); font-weight: 600;
}
.rcpt-who { flex: 1 1 auto; min-width: 0; }
.rcpt-nm { font-size: calc(13.5px * var(--fs)); font-weight: 600; color: var(--text); }
.rcpt-when { margin-top: 2px; font-size: calc(11.5px * var(--fs)); color: var(--text-3); }

.rcpt-chip {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 8px; border-radius: 18px;
  font-size: calc(11px * var(--fs)); font-weight: 500;
}
.rcpt-chip svg { flex: 0 0 auto; }
.rcpt-chip.ok { background: var(--green-soft); color: var(--green); }
.rcpt-chip.wait { background: var(--amber-soft); color: var(--amber); }
.rcpt-chip.no { background: var(--red-soft); color: var(--red); }

.rcpt-merchant {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-top: 12px;
}
.rcpt-mk {
  font-size: calc(15px * var(--fs)); font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rcpt-amt {
  flex: 0 0 auto; font-size: calc(16px * var(--fs)); font-weight: 700;
  color: var(--text); font-variant-numeric: tabular-nums;
}

.rcpt-stars { display: flex; align-items: center; gap: 2px; margin-top: 8px; }
.rcpt-star { display: inline-flex; color: var(--line); }
.rcpt-star.on { color: var(--amber); }
.rcpt-star svg { flex: 0 0 auto; }
.rcpt-rate-t { margin-left: 6px; font-size: calc(12px * var(--fs)); color: var(--text-2); }

.rcpt-text {
  margin-top: 10px; font-size: calc(13px * var(--fs)); color: var(--text);
  line-height: 1.65; word-break: break-word;
}

.rcpt-foot {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line-2);
}
.rcpt-f-i {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: calc(11.5px * var(--fs)); color: var(--text-3);
}
.rcpt-f-i svg { flex: 0 0 auto; }

/* 状态行 */
.rcpt-hint-line { padding: 32px 16px; text-align: center; font-size: calc(13px * var(--fs)); color: var(--text-3); }
.rcpt-err {
  margin: 12px 16px 0; padding: 12px 16px; border-radius: var(--r);
  background: var(--red-soft); color: var(--red);
  font-size: calc(12.5px * var(--fs));
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}

.rcpt-empty { padding: 40px 24px; text-align: center; }
.rcpt-empty-t { font-size: calc(15px * var(--fs)); font-weight: 600; color: var(--text); }
.rcpt-empty-d {
  margin: 8px auto 16px; max-width: 260px;
  font-size: calc(12.5px * var(--fs)); color: var(--text-2); line-height: 1.7;
}

/* 详情页 */
.rcpt-d-card {
  margin: 16px 16px 0; padding: 20px 16px;
  background: var(--surface); border-radius: var(--r); box-shadow: var(--shadow-sm);
}
.rcpt-d-top { display: flex; align-items: center; gap: 10px; }
.rcpt-d-top > div:nth-child(2) { flex: 1 1 auto; min-width: 0; }
.rcpt-d-amt {
  display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap;
  margin-top: 16px;
}
.rcpt-d-num {
  font-size: calc(34px * var(--fs)); font-weight: 700; color: var(--text);
  letter-spacing: -.5px; font-variant-numeric: tabular-nums;
}
.rcpt-d-unit { font-size: calc(14px * var(--fs)); color: var(--text-2); }
.rcpt-d-stars { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.rcpt-d-label { margin-top: 6px; font-size: calc(12.5px * var(--fs)); color: var(--text-2); }
.rcpt-d-text {
  margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line-2);
  font-size: calc(14px * var(--fs)); color: var(--text); line-height: 1.75;
  word-break: break-word;
}
.rcpt-d-meta {
  display: flex; gap: 16px; flex-wrap: wrap;
  margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--line-2);
  font-size: calc(11.5px * var(--fs)); color: var(--text-3);
}
.rcpt-d-meta span { display: inline-flex; align-items: center; gap: 4px; }
.rcpt-d-meta svg { flex: 0 0 auto; }

/* 说明块 */
.rcpt-note {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 16px 16px 0; padding: 12px 16px; border-radius: var(--r);
  background: var(--accent-soft); color: var(--text-2);
  font-size: calc(12px * var(--fs)); line-height: 1.7;
}
.rcpt-note svg { flex: 0 0 auto; margin-top: 1px; color: var(--accent); }
.rcpt-note b { color: var(--text); }

.rcpt-acts { display: flex; gap: 10px; margin: 16px 16px 0; }
.rcpt-acts .btn { flex: 1 1 0; }

.rcpt-share-url {
  margin: 4px 0 10px; padding: 12px 16px; border-radius: var(--r);
  background: var(--surface-2); color: var(--text);
  font-size: calc(12.5px * var(--fs)); word-break: break-all;
  font-family: var(--font-mono, monospace);
}

/* 贡献值页 */
.rcpt-pt {
  margin: 16px 16px 0; padding: 20px 20px;
  background: var(--surface); border-radius: var(--r); box-shadow: var(--shadow-sm);
}
.rcpt-pt-lv {
  display: inline-block; padding: 4px 12px; border-radius: 18px;
  color: #fff; font-size: calc(12px * var(--fs)); font-weight: 600;
}
.rcpt-pt-num { display: flex; align-items: baseline; gap: 8px; margin-top: 12px; }
.rcpt-pt-num b {
  font-size: calc(38px * var(--fs)); font-weight: 700; color: var(--text);
  letter-spacing: -1px; font-variant-numeric: tabular-nums;
}
.rcpt-pt-num span { font-size: calc(12.5px * var(--fs)); color: var(--text-2); }
.rcpt-pt-sub { margin-top: 6px; font-size: calc(12px * var(--fs)); color: var(--text-2); }

.rcpt-prog {
  height: 6px; margin: 12px 16px 0; border-radius: 6px;
  background: var(--surface-3); overflow: hidden;
}
.rcpt-prog-bar { height: 100%; background: var(--accent); border-radius: 6px; }

.rcpt-stat {
  display: grid; grid-template-columns: repeat(3, 1fr);
  margin: 12px 16px 0; padding: 16px 6px;
  background: var(--surface); border-radius: var(--r); box-shadow: var(--shadow-sm);
}
.rcpt-stat > div { text-align: center; }
.rcpt-stat b {
  display: block; font-size: calc(17px * var(--fs)); font-weight: 700;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.rcpt-stat span { display: block; margin-top: 2px; font-size: calc(11px * var(--fs)); color: var(--text-3); }

.rcpt-sec-t {
  margin: 24px 16px 2px; font-size: calc(12.5px * var(--fs));
  font-weight: 600; color: var(--text-2);
}

/* 表单 */
.rcpt-form { padding: 16px 16px 24px; }
.rcpt-field { margin-bottom: 16px; }
.rcpt-label {
  margin-bottom: 8px; font-size: calc(12.5px * var(--fs));
  font-weight: 600; color: var(--text-2);
}
.rcpt-label i {
  font-style: normal; font-weight: 400;
  font-size: calc(11px * var(--fs)); color: var(--text-3); margin-left: 4px;
}
.rcpt-row { display: flex; gap: 12px; }
.rcpt-row .rcpt-field { flex: 1 1 0; min-width: 0; }

.rcpt-input {
  width: 100%; box-sizing: border-box;
  padding: 12px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--surface);
  font-size: calc(14px * var(--fs)); color: var(--text);
  font-family: inherit;
}
.rcpt-input:focus { outline: none; border-color: var(--accent); }
.rcpt-area { min-height: 84px; resize: vertical; line-height: 1.65; }

.rcpt-tip {
  margin-top: 8px; font-size: calc(11.5px * var(--fs));
  color: var(--text-3); line-height: 1.65;
}
.rcpt-tip b { color: var(--text-2); }

/* 拍照 / 选图 */
.rcpt-upload {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: 24px 16px; cursor: pointer;
  border: 1px dashed var(--line); border-radius: var(--r);
  background: var(--surface-2); color: var(--text-2);
}
.rcpt-upload span { font-size: calc(13.5px * var(--fs)); font-weight: 600; color: var(--text); }
.rcpt-upload em { font-style: normal; font-size: calc(11.5px * var(--fs)); color: var(--text-3); }
.rcpt-upload input[type="file"] { display: none; }

.rcpt-photo { position: relative; border-radius: var(--r); overflow: hidden; }
.rcpt-photo img { display: block; width: 100%; max-height: 260px; object-fit: cover; }
.rcpt-photo-x {
  position: absolute; right: 10px; bottom: 10px;
  padding: 8px 12px; border: 0; border-radius: 18px;
  background: rgba(16, 24, 40, .72); color: #fff;
  font-size: calc(12px * var(--fs)); font-family: inherit; cursor: pointer;
}

/* 打分 */
.rcpt-rate-row { display: flex; gap: 8px; }
.rcpt-rate-btn {
  flex: 1 1 0; padding: 12px 0;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); color: var(--line);
  cursor: pointer; font-family: inherit;
}
.rcpt-rate-btn span { font-size: calc(11px * var(--fs)); color: var(--text-3); }
.rcpt-rate-btn svg { flex: 0 0 auto; }
.rcpt-rate-btn.on {
  border-color: var(--amber); background: var(--amber-soft); color: var(--amber);
}
.rcpt-rate-btn.on span { color: var(--amber); }

.rcpt-submit { margin-top: 8px; }


/* =========================================================
   商家订单助手
   ---------------------------------------------------------
   前缀用 mord- 而不是 mo- —— mo- 已经被群治理模块占了
   （.mo-card / .mo-h / .mo-t / .mo-acts…）。
   类名撞了不会报错、不会白屏，只是样式互相覆盖 ——
   最典型的静默失效。这个坑在真实晒单那一轮踩过一次
   （rc- 撞了 .rc-h/.rc-t），所以这里先查了一遍再定前缀。

   ★ 颜色在这里不是装饰，是这个页面唯一的层级：
     · 未完成 → 蓝色 + 左侧蓝条（老板原话：「没有发货的会是一个蓝色的」）
     · 待取货 → 橙色（该你动手了）
     · 已出货 → 整卡降透明度（老板原话：「就会变暗」）
   ========================================================= */

/* ---- 顶部统计 ---- */
.mord-sum {
  display: flex; margin: 0 16px 12px;
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--shadow-sm); overflow: hidden;
}
.mord-sum-i {
  flex: 1 1 0; padding: 12px 4px; text-align: center;
  border-right: 1px solid var(--line-2);
}
.mord-sum-i:last-child { border-right: 0; }
.mord-sum-i b {
  display: block; font-size: calc(19px * var(--fs)); line-height: 1.15;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.mord-sum-i span { display: block; margin-top: 4px; font-size: calc(11px * var(--fs)); color: var(--text-3); }
/* 有待确认的单时把数字点成蓝色 ——
   商家扫一眼就知道「有活等着我」，不用去读小字标签。 */
.mord-sum-i.hot b { color: var(--accent); }

/* ---- 机器人说明条 ---- */
.mord-bot {
  margin: 0 16px 16px; padding: 12px 16px;
  background: var(--accent-soft); border-radius: var(--r);
}
.mord-bot-h {
  display: flex; align-items: center; gap: 6px;
  font-size: calc(13px * var(--fs)); font-weight: 600; color: var(--accent);
}
.mord-bot-h svg { flex: 0 0 auto; }
.mord-bot-d {
  margin-top: 6px; font-size: calc(12px * var(--fs));
  line-height: 1.6; color: var(--text-2);
}
.mord-bot-d b { color: var(--text); }
.mord-bot-a { display: flex; gap: 8px; margin-top: 12px; }

/* ---- 分组标题 ---- */
.mord-sec {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 16px 8px;
  font-size: calc(12px * var(--fs)); font-weight: 600; color: var(--text-2);
}
.mord-sec b {
  font-weight: 600; color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.mord-sec.dim { color: var(--text-3); }

/* ---- 订单卡片 ---- */
.mord-card {
  position: relative;
  margin: 0 16px 10px; padding: 12px 16px 12px;
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  border-left: 3px solid var(--accent);
  /* 时长用已有的 --dur / --dur-slow，不要现编一个名字。
     写成不存在的变量时，整条 transition 会**静默失效** ——
     不报错、不白屏，只是动效没了。这条是 _qa/cssdup.js 的
     变量体检抓出来的（--dur-fast 引用 1 次、定义 0 次）。 */
  transition: transform var(--dur) var(--ease), opacity var(--dur-slow) var(--ease);
}
.mord-card:active { transform: scale(.985); }
/* 已出货 / 已取消：变暗。
   用 opacity 而不是换一套灰色 —— 换灰色要重定义里面每一个颜色，
   加一个新元素就会漏一个，然后那一处是亮的、看着像没做完。 */
.mord-card.done {
  opacity: .52;
  border-left-color: var(--line);
  box-shadow: none;
  background: var(--surface-2);
}

.mord-h { display: flex; align-items: center; gap: 10px; }
.mord-ava {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: calc(14px * var(--fs)); font-weight: 600;
}
.mord-who { flex: 1 1 auto; min-width: 0; }
.mord-nm {
  font-size: calc(14px * var(--fs)); font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mord-src {
  margin-top: 2px; font-size: calc(11px * var(--fs)); color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mord-chip {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 8px; border-radius: 18px;
  font-size: calc(11px * var(--fs)); font-weight: 600;
}

/* 低置信度提示。橙色而不是红色 ——
   红色是「出事了」，这里只是「不确定」，语气差一个量级。 */
.mord-warn {
  display: flex; align-items: center; gap: 6px;
  margin-top: 10px; padding: 8px 10px;
  background: var(--amber-soft); border-radius: 10px;
  font-size: calc(11.5px * var(--fs)); color: var(--amber); font-weight: 500;
}
.mord-warn svg { flex: 0 0 auto; }

/* ---- 物品 ---- */
.mord-items { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
.mord-item { display: flex; align-items: baseline; gap: 8px; }
.mord-item b {
  flex: 0 0 auto; min-width: 26px;
  font-size: calc(14px * var(--fs)); color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.mord-card.done .mord-item b { color: var(--text-2); }
.mord-item span {
  font-size: calc(14px * var(--fs)); color: var(--text);
  line-height: 1.45; word-break: break-all;
}

.mord-note {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 8px; font-size: calc(12px * var(--fs)); color: var(--text-2);
  line-height: 1.5;
}
.mord-note svg { flex: 0 0 auto; margin-top: 2px; }

.mord-amt {
  margin-top: 8px; font-size: calc(15px * var(--fs)); font-weight: 600;
  color: var(--text); font-variant-numeric: tabular-nums;
}

/* ---- 机器人识别依据 ----
   这一段是这个功能能不能被信任的关键。
   商家在列表上就能看到「机器人是从哪句话记的」，
   不用点进聊天页去核对 —— 要跳进去才能判断的话，等于没省事。 */
.mord-quote {
  margin-top: 10px; padding: 8px 10px;
  background: var(--surface-3); border-radius: 10px;
  font-size: calc(11.5px * var(--fs)); line-height: 1.55;
}
.mord-quote-k { display: block; color: var(--text-3); }
.mord-quote-v { display: block; margin-top: 4px; color: var(--text-2); }

/* ---- 底部按钮 ---- */
.mord-foot {
  display: flex; align-items: center; gap: 8px;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--line-2);
}
.mord-btn {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 8px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--surface);
  font-size: calc(12.5px * var(--fs)); font-weight: 500;
  color: var(--text-2); font-family: inherit; cursor: pointer;
}
.mord-btn svg { flex: 0 0 auto; }
.mord-btn:active { background: var(--surface-3); }
.mord-btn.jump { color: var(--accent); border-color: var(--accent-soft); background: var(--accent-soft); }
.mord-btn.ghost { border-style: dashed; color: var(--text-3); cursor: default; }
/* 主按钮推到最右。
   「做好一单就按一下」—— 那个「一下」必须是这个按钮，
   不能被左边的次要按钮挤到中间去。 */
.mord-btn.primary {
  margin-left: auto; border-color: transparent;
  background: var(--accent); color: #fff; font-weight: 600;
}
.mord-btn.primary:active { background: #2559D8; }
.mord-card.done .mord-btn.primary { margin-left: auto; }
.mord-more {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 10px;
  border: 0; background: transparent; color: var(--text-3);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.mord-more:active { background: var(--surface-3); }

/* ---- 空态 / 错误 ---- */
.mord-empty { padding: 24px 24px 32px; text-align: center; }
.mord-empty-t { font-size: calc(15px * var(--fs)); font-weight: 600; color: var(--text); }
.mord-empty-d {
  margin: 8px 0 16px; font-size: calc(12.5px * var(--fs));
  line-height: 1.65; color: var(--text-2);
}
.mord-hint { padding: 20px; text-align: center; font-size: calc(13px * var(--fs)); color: var(--text-3); }
.mord-err {
  margin: 0 16px 12px; padding: 10px 12px;
  background: var(--red-soft); border-radius: 10px;
  font-size: calc(12.5px * var(--fs)); color: var(--red);
  display: flex; align-items: center; gap: 8px;
}
.mord-tip {
  margin: 0 0 16px; padding: 12px 12px;
  background: var(--surface-3); border-radius: 10px;
  font-size: calc(12.5px * var(--fs)); line-height: 1.6; color: var(--text-2);
}

/* ---- 聊天页里的兜底定位条 ----
   订单对应的消息不在首屏那 40 条里时显示。
   不能默默不跳：商家点了一下什么都没发生，
   会以为按钮坏了，然后回去翻聊天记录。 */
.mord-anchor {
  display: flex; gap: 8px; margin: 12px 16px 6px; padding: 12px 12px;
  background: var(--accent-soft); border-radius: 10px;
  font-size: calc(12px * var(--fs)); color: var(--text-2);
}
.mord-anchor svg { flex: 0 0 auto; color: var(--accent); margin-top: 1px; }
.mord-anchor-m { min-width: 0; }
.mord-anchor-t { font-weight: 600; color: var(--accent); }
.mord-anchor-q { margin-top: 4px; color: var(--text); line-height: 1.5; }
.mord-anchor-d { margin-top: 4px; font-size: calc(11px * var(--fs)); color: var(--text-3); }

/* ---- 跳转落点高亮 ----
   用 box-shadow 扩散而不是 padding / background ——
   box-shadow 不参与布局，不会把消息挤动一下。
   滚过去之后整块再动一下，比「滚过去但看不出是哪条」好得多。 */
.msg-row.mord-flash {
  border-radius: 14px;
  animation: mordFlash 2.8s cubic-bezier(.22, 1, .36, 1);
}
@keyframes mordFlash {
  0%   { background: rgba(47, 107, 255, .18); box-shadow: 0 0 0 10px rgba(47, 107, 255, .18); }
  55%  { background: rgba(47, 107, 255, .12); box-shadow: 0 0 0 10px rgba(47, 107, 255, .12); }
  100% { background: transparent; box-shadow: 0 0 0 10px rgba(47, 107, 255, 0); }
}

/* ---- 编辑弹层 ---- */
.mord-edit .hint { margin-top: 6px; }
.mord-rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.mord-erow { display: flex; align-items: center; gap: 6px; }

/* ⚠️ 这三个输入框的宽度必须挂在 `.mord-erow` 下面，不能只写 `.mord-eqty`。
   ---------------------------------------------------------
   弹层里的输入框有一条全局规则：`.field input { width: 100% }`，
   特异性是 (0,1,1)（一个类 + 一个元素）。
   而 `.mord-eqty` 只有 (0,1,0)（一个类）—— **压不过它**。

   结果：数量 / 单位 / 名称三个框全变成 100% 宽，
   前两个还带着 `flex-shrink: 0`，于是它们各占满一整行、
   把后面两个挤出容器，编辑弹层里只剩一个孤零零的「1」，
   物品名和单位根本看不见。

   这个 bug 不报错、不告警、页面也照常渲染 ——
   只有截图才看得出来。所以修的时候顺手把特异性写足：
   `.mord-erow .mord-eqty` 是 (0,2,0)，稳赢 (0,1,1)。 */
.mord-erow .mord-eqty,
.mord-erow .mord-eunit {
  width: 48px; flex: 0 0 auto; text-align: center;
  padding: 12px 4px;
}
.mord-erow .mord-ename { flex: 1 1 auto; width: auto; min-width: 0; }
.mord-edel {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--surface);
  color: var(--text-3); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.mord-edel:disabled { opacity: .35; cursor: default; }
.mord-edel:not(:disabled):active { background: var(--red-soft); color: var(--red); }

/* 一点就填的常用原因 ——
   手打的话，第三单就会偷懒打「不做了」，
   而以后回头看记录时那句话什么都说明不了。 */
.mord-presets { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.mord-preset {
  padding: 6px 10px; border-radius: 18px;
  border: 1px solid var(--line); background: var(--surface);
  font-size: calc(12px * var(--fs)); color: var(--text-2);
  font-family: inherit; cursor: pointer; text-align: left;
}
.mord-preset:active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-soft); }

/* ---- 「⋯」弹层里的次要操作 ---- */
.mord-acts { display: flex; flex-direction: column; gap: 8px; }
.mord-act {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 12px 16px; text-align: left;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); color: var(--text);
  font-size: calc(13.5px * var(--fs)); font-family: inherit; cursor: pointer;
}
.mord-act svg { flex: 0 0 auto; color: var(--text-2); }
.mord-act:active { background: var(--surface-3); }
.mord-act.danger { color: var(--red); }
.mord-act.danger svg { color: var(--red); }
.mord-act-hint { padding: 12px; text-align: center; font-size: calc(12.5px * var(--fs)); color: var(--text-3); }

/* =========================================================
   邻里帮带（接单侧 / 消费者侧 / 商家侧共用一套）
   ---------------------------------------------------------
   为什么三个角色共用一套 class 而不是各写一套：
   同一个订单在三个人手机上长得**不一样**是对的（信息不同），
   但**卡片骨架必须一样** —— 否则商家截图问「这是哪一单」，
   帮带人对着自己的界面找不到对应关系。

   三条排版决定：

   1. **占位头像用虚线边**，不用实心渐变。
      实心看着就是加载好了；虚线才一眼是「被遮了」。
      （见 views-helper.js 里 ava() 的说明）

   2. **取件码字号最大**。它是这个产品里唯一一个
      「必须在楼下、光线差、手忙脚乱时准确读出来」的信息。
      32px 起步，字距拉开，不跟任何东西挤一行。

   3. **「等你确认」用琥珀色，不用红色**。
      红色是错误色，而「东西到了等你确认」是正常流程 ——
      用红色会让用户以为出事了。
   ========================================================= */

/* ---------------- 占位头像 / 通用小头像 ---------------- */
.hpb-av {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; color: #fff; font-weight: 600; letter-spacing: 0;
  border: 1px solid transparent; overflow: hidden;
}
.hpb-av.anon {
  /* 淡色底 + 虚线边：一眼是「故意遮的」，不是「没加载出来」。
     颜色由订单派生（内联下发），所以这里不写死任何色值。 */
  border-style: dashed; border-width: 1.5px; font-weight: 500;
}

/* ---------------- 通用提示条 ---------------- */
.hpb-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 16px 12px; padding: 12px 12px;
  background: var(--accent-soft); color: var(--accent);
  border-radius: 14px; font-size: calc(12.5px * var(--fs)); line-height: 1.55;
}
.hpb-note svg { flex: 0 0 auto; margin-top: 1px; }
.hpb-note b { font-weight: 600; }

.hpb-load {
  margin: 0 16px; padding: 32px 0; text-align: center;
  font-size: calc(13px * var(--fs)); color: var(--text-3);
}

.hpb-err {
  margin: 0 16px 12px; padding: 12px 16px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--red-soft); color: var(--red);
  border-radius: 14px; font-size: calc(12.5px * var(--fs));
}

.hpb-sec {
  margin: 16px 16px 8px;
  font-size: calc(12.5px * var(--fs)); font-weight: 600; color: var(--text-2);
}

/* ---------------- 接单开关卡 ---------------- */
.hpb-sw { margin: 0 16px 12px; padding: 16px; border-radius: var(--r); border: 1px solid var(--line); background: var(--surface); }
.hpb-sw-h { display: flex; align-items: center; gap: 8px; font-size: calc(14px * var(--fs)); font-weight: 600; color: var(--text); }
.hpb-sw-d { margin: 8px 0 12px; font-size: calc(12.5px * var(--fs)); line-height: 1.6; color: var(--text-2); }
.hpb-sw-d b { color: var(--text); }
.hpb-sw-d b.warn { color: var(--amber); }
.hpb-sw-a { display: flex; gap: 8px; }
.hpb-sw.on { border-color: var(--green-soft); background: var(--surface); }
.hpb-sw.on .hpb-sw-h { color: var(--green); }
.hpb-sw.off { border-color: var(--accent-soft); }
.hpb-sw.off .hpb-sw-h { color: var(--accent); }
.hpb-sw.wait { border-color: var(--amber-soft); }
.hpb-sw.wait .hpb-sw-h { color: var(--amber); }

/* ---------------- 卡片 ---------------- */
.hpb-card {
  margin: 0 16px 10px; padding: 16px;
  border-radius: var(--r); border: 1px solid var(--line);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
.hpb-card.dim { opacity: .62; }
/* 「等你确认」的卡片给一道琥珀色左边框 ——
   比整块变色克制，扫列表时又能一眼挑出来。 */
.hpb-card.todo { border-left: 3px solid var(--amber); padding-left: 12px; }

.hpb-card-t { display: flex; align-items: center; gap: 10px; }
.hpb-card-n { flex: 1 1 auto; min-width: 0; }
.hpb-card-n b {
  display: block; font-size: calc(14px * var(--fs)); font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hpb-card-n span {
  display: block; margin-top: 2px;
  font-size: calc(12px * var(--fs)); color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hpb-card-d { flex: 0 0 auto; text-align: right; }
.hpb-card-d b { display: block; font-size: calc(13px * var(--fs)); font-weight: 600; color: var(--text); }
.hpb-card-d b.st { color: var(--text-2); font-weight: 500; }
.hpb-card-d b.todo { color: var(--amber); }
.hpb-card-d span { display: block; margin-top: 2px; font-size: calc(11.5px * var(--fs)); color: var(--text-3); }

.hpb-card-m { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.hpb-card-a { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.hpb-card-a .btn { flex: 0 0 auto; }
.hpb-card-a .btn.primary { flex: 1 1 auto; }

.hpb-tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 10px; border-radius: 999px;
  background: var(--surface-3); color: var(--text-2);
  font-size: calc(11.5px * var(--fs)); white-space: nowrap;
}
.hpb-tag.ok { background: var(--green-soft); color: var(--green); }
.hpb-tag.warn { background: var(--amber-soft); color: var(--amber); }
.hpb-tip { font-size: calc(11.5px * var(--fs)); color: var(--text-3); }

/* ---------------- 详情页 ---------------- */
.hpb-state {
  margin: 0 16px 12px; padding: 16px 16px;
  border-radius: var(--r); background: var(--surface-3);
}
.hpb-state.todo { background: var(--amber-soft); }
.hpb-state-t { font-size: calc(15px * var(--fs)); font-weight: 600; color: var(--text); }
.hpb-state.todo .hpb-state-t { color: var(--amber); }
.hpb-state-d { margin-top: 6px; font-size: calc(12.5px * var(--fs)); line-height: 1.6; color: var(--text-2); }

.hpb-dt {
  margin: 0 16px 12px; padding: 4px 16px;
  border-radius: var(--r); border: 1px solid var(--line); background: var(--surface);
}
.hpb-dt-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line-2); }
.hpb-dt-row:last-child { border-bottom: none; }
.hpb-dt-row > div { min-width: 0; }
.hpb-dt-row b { display: block; font-size: calc(13.5px * var(--fs)); font-weight: 600; color: var(--text); }
.hpb-dt-row span { display: block; margin-top: 2px; font-size: calc(11.5px * var(--fs)); color: var(--text-3); }

.hpb-priv {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 16px 12px; padding: 10px 12px;
  background: var(--surface-3); color: var(--text-2);
  border-radius: 10px; font-size: calc(12px * var(--fs)); line-height: 1.6;
}
.hpb-priv svg { flex: 0 0 auto; margin-top: 2px; color: var(--text-3); }

.hpb-dl {
  margin: 0 16px 12px; padding: 16px 16px;
  border-radius: var(--r); border: 1px solid var(--line); background: var(--surface);
}
.hpb-dl-h { display: flex; align-items: center; gap: 8px; font-size: calc(13.5px * var(--fs)); font-weight: 600; color: var(--text); }
.hpb-dl-h.ok { color: var(--green); }
.hpb-dl-d { margin-top: 6px; font-size: calc(12.5px * var(--fs)); line-height: 1.65; color: var(--text-2); }

/* ---- 取件码 ---- */
.hpb-code {
  margin: 0 16px 12px; padding: 16px;
  border-radius: var(--r); border: 1px dashed var(--accent);
  background: var(--accent-soft); text-align: center;
}
.hpb-code-t { font-size: calc(12px * var(--fs)); color: var(--accent); }
.hpb-code-v {
  margin: 6px 0 6px;
  font-size: calc(24px * var(--fs)); font-weight: 700;
  letter-spacing: 8px; text-indent: 8px; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
/* 消费者侧要大一号 —— 他要在楼下念给对方听 */
.hpb-code.big { padding: 20px 16px; }
.hpb-code.big .hpb-code-v { font-size: calc(32px * var(--fs)); letter-spacing: 12px; text-indent: 12px; }
.hpb-code-d { font-size: calc(11.5px * var(--fs)); line-height: 1.55; color: var(--text-2); }

.hpb-proof {
  margin: 0 16px 12px; padding: 16px 16px;
  border-radius: var(--r); border: 1px solid var(--line); background: var(--surface);
}
.hpb-proof-p { display: flex; align-items: center; gap: 8px; font-size: calc(12.5px * var(--fs)); color: var(--green); }
.hpb-proof-n { margin-top: 8px; font-size: calc(12.5px * var(--fs)); line-height: 1.6; color: var(--text-2); }

.hpb-done {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 16px 12px; padding: 12px 12px;
  border-radius: 10px; background: var(--green-soft); color: var(--green);
  font-size: calc(12px * var(--fs)); line-height: 1.6;
}
.hpb-done.warn { background: var(--amber-soft); color: var(--amber); }
.hpb-done svg { flex: 0 0 auto; margin-top: 1px; }

/* ---------------- 底部操作条 ---------------- */
.hpb-foot {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
}

/* ---------------- 安全提醒 ---------------- */
.hpb-alert {
  margin: 0 16px 10px; padding: 16px 16px;
  border-radius: var(--r); border: 1px solid var(--line); background: var(--surface);
}
.hpb-alert.read { opacity: .6; }
.hpb-alert-h { display: flex; align-items: center; gap: 8px; font-size: calc(13.5px * var(--fs)); color: var(--amber); }
.hpb-alert-h b { color: var(--text); }
.hpb-alert-b { margin-top: 8px; font-size: calc(12.5px * var(--fs)); line-height: 1.65; color: var(--text-2); }
.hpb-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--red);
  display: inline-block; margin-left: auto;
}

/* ---------------- 表单（接单设置） ---------------- */
.hpb-form {
  margin: 0 16px 12px; padding: 4px 16px;
  border-radius: var(--r); border: 1px solid var(--line); background: var(--surface);
}
.hpb-f { display: block; padding: 16px 0; border-bottom: 1px solid var(--line-2); }
.hpb-f:last-child { border-bottom: none; }
.hpb-f > span { display: block; margin-bottom: 8px; font-size: calc(13px * var(--fs)); color: var(--text-2); }
.hpb-f input[type="text"] {
  width: 100%; padding: 12px 12px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2); color: var(--text);
  font-size: calc(14px * var(--fs)); font-family: inherit;
}
.hpb-f input[type="text"]:focus { outline: none; border-color: var(--accent); background: var(--surface); }
.hpb-f-hint {
  display: flex; align-items: flex-start; gap: 6px; margin-top: 10px;
  font-size: calc(11.5px * var(--fs)); line-height: 1.6; color: var(--text-3);
}
.hpb-f-hint svg { flex: 0 0 auto; margin-top: 2px; }

.hpb-radio { display: flex; gap: 8px; }
.hpb-radio label { flex: 1 1 0; cursor: pointer; }
.hpb-radio input { position: absolute; opacity: 0; pointer-events: none; }
.hpb-radio i {
  display: block; padding: 10px 0; text-align: center; font-style: normal;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2); color: var(--text-2);
  font-size: calc(13px * var(--fs)); transition: all .15s var(--ease, ease);
}
.hpb-radio input:checked + i { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }

/* ---------------- 弹层内部 ---------------- */
.hpb-mo { display: flex; flex-direction: column; gap: 12px; }
.hpb-mo-t { font-size: calc(13.5px * var(--fs)); line-height: 1.6; color: var(--text); }
.hpb-mo-hint { font-size: calc(11.5px * var(--fs)); line-height: 1.65; color: var(--text-3); }
.hpb-mo .hpb-f { border-bottom: none; padding: 0; }

/* 交付方式二选一。整块可点，不用小圆点 ——
   在手机上点一个 16px 的 radio 很容易点空。 */
.hpb-choice { display: flex; flex-direction: column; gap: 8px; }
.hpb-ch {
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
  width: 100%; padding: 12px 16px; text-align: left; cursor: pointer;
  border: 1.5px solid var(--line); border-radius: 14px;
  background: var(--surface); color: var(--text);
  font-family: inherit; font-size: calc(13.5px * var(--fs));
}
.hpb-ch svg { color: var(--text-3); }
.hpb-ch b { font-weight: 600; }
.hpb-ch span { font-size: calc(11.5px * var(--fs)); color: var(--text-3); }
.hpb-ch.on { border-color: var(--accent); background: var(--accent-soft); }
.hpb-ch.on svg { color: var(--accent); }
.hpb-ch.on b { color: var(--accent); }

.hpb-spots { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.hpb-spot {
  padding: 10px 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2); color: var(--text-2);
  font-family: inherit; font-size: calc(12.5px * var(--fs));
}
.hpb-spot.on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }

/* 深色主题：以上全部走 var()，只有占位头像的淡色底是内联的
   （订单色带透明度），在深色底上依然可读，不需要额外覆盖。 */

/* =========================================================
   帖子评论区
   ---------------------------------------------------------
   内容详情页的评论列表与发表入口（产品功能）。
   ========================================================= */
.cmt-box { display: flex; flex-direction: column; gap: 10px; }
.cmt-tip {
  display: flex; align-items: center; gap: 8px;
  font-size: calc(12.5px * var(--fs)); color: var(--text-2);
  background: var(--accent-soft); border-radius: 10px;
  padding: 8px 12px;
}
.cmt-tip .cmt-act { margin-left: auto; color: var(--accent); font-weight: 600; }
.cmt-input { display: flex; align-items: center; gap: 8px; }
.cmt-input input {
  flex: 1; min-width: 0;
  padding: 10px 12px; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: calc(14px * var(--fs));
  transition: border-color var(--dur) var(--ease);
}
.cmt-input input:focus { border-color: var(--accent); }
.cmt-empty {
  padding: 20px 0; text-align: center;
  font-size: calc(12.5px * var(--fs)); color: var(--text-3);
}
/* ⚠️ `.cmt` / `.cmt-main` / `.cmt-at` **故意不在这里重复定义** ——
   它们是评议庭评论（第 2898 行那一段）已经定好的骨架，帖子评论
   直接复用。各写一份的话，同一个「评论」在两处会有两套行距与字号，
   而且体检脚本（cssdup.js）会以「裸类名重复且属性冲突」拦下来 ——
   这类冲突不会报错，只会让后加载的那份静默覆盖前一份。 */
.cmt-top { display: flex; align-items: baseline; gap: 8px; }
.cmt-top b { font-size: calc(13.5px * var(--fs)); color: var(--text); }
.cmt-text {
  font-size: calc(14px * var(--fs)); color: var(--text);
  line-height: 1.65; margin-top: 4px;
  word-break: break-word;
}
.cmt-foot { display: flex; gap: 16px; margin-top: 6px; }
.cmt-act {
  font-size: calc(12px * var(--fs)); color: var(--text-3);
  cursor: pointer;
}
.cmt-act.del { color: var(--red); }
/* 已撤下的评论 —— 只有作者 / 帖子作者 / 社区管理员看得到。
   用「降透明度 + 划掉正文」表达「这条已经不算数了」，
   而不是直接隐藏：管理员需要确认「我撤的是不是这一条」。
   透明度不要压到看不见（0.45 以下在深色主题下基本读不出来）。 */
.cmt.removed { opacity: .55; }
.cmt.removed .cmt-text { text-decoration: line-through; }
.cmt-rm {
  font-size: calc(11px * var(--fs)); font-weight: 600;
  color: var(--red); background: var(--red-soft);
  padding: 1px 6px; border-radius: 6px;
  margin-left: 2px;
}

/* =========================================================
   发帖的实拍照片（发布页）
   ---------------------------------------------------------
   和「配图示意图」并存：实拍照片优先，没照片才用示意图占位。
   两个按钮竖排、宽度撑满 —— 发布页是表单，按钮并排会让人
   以为「只能二选一」，而这里其实是「有就用、没有就兜底」。
   ========================================================= */
.pub-photo { display: block; }
.pub-photo-img {
  width: 100%; height: 168px; object-fit: cover;
  border-radius: 10px; margin-bottom: 10px;
  background: var(--surface-2);
}
.pub-photo-btns { display: block; }
.pub-photo-hint {
  font-size: calc(12px * var(--fs)); color: var(--text-3);
  line-height: 1.6; margin-top: 8px;
}
