/* 值守台 · 移动端优先排班系统 */
:root{
  --bg:#0e1014; --sf:#151922; --sf2:#1b202b; --sf3:#222836; --line:#272e3c;
  --tx:#e7ebf3; --tx2:#a3adc0; --tx3:#8b96a9;
  /* ⚠️ `--a` / `--ok` 有**两个角色**，所以有六个变量（2026-09-29 拆开）。
     独立测试报告量到「白字按钮」对比度不足：白字 on --a(#5b8cff) = 3.16 : 1、
     on --ok(#2fbf87) = 2.35 : 1，AA 要 4.5。报告的建议是「把底色加深」，
     但**直接改 --a/--ok 会制造新违规** —— 它俩同时是暗底上的**文字色**：
     .navitem.on / .docbar a.d0 / .helpq:focus 都用 --a 当字色，在 #151922 上是
     5.56 : 1（达标）；换成 #3f6fe0 就掉到 3.82 : 1，导航文字当场不达标。
     一个变量不能既当"浅底上的字"又当"深底（白字）"，
     所以按角色拆名：--a/--ok 只做文字与浅底徽标，--a-fill/--ok-fill 只做实心按钮底。
     （同一个坑这仓库踩过：money 与 pct 曾各有一份实现、语义还不一样。） */
  --a:#5b8cff; --a-soft:rgba(91,140,255,.14); --a-fill:#3f6fe0;   /* 白字 on #3f6fe0 = 4.60 : 1 ✓ */
  --ok:#2fbf87; --ok-soft:rgba(47,191,135,.14); --ok-fill:#12855a; /* 白字 on #12855a = 4.64 : 1 ✓ */
  --warn:#f0b429; --warn-soft:rgba(240,180,41,.14);
  --dg:#f2685f;  --dg-soft:rgba(242,104,95,.14); --dg-fill:#c8392f; /* 白字 on #c8392f = 5.15 : 1 ✓ */
  /* --pp 提亮：#a274ff 在 --pp-soft 叠 --sf3 的底上只有 3.72 : 1（夜班格「紫字紫底」）。
     #b48cff 在同一底上 4.67 : 1 ✓，与 --tx2 仍拉得开。 */
  --pp:#b48cff; --pp-soft:rgba(162,116,255,.14);
  /* --ac / --ac-soft：**第四个班次色**，给「高峰班」（键 P）用。
     四个班次（E 早 / M 中 / N 夜 / P 高峰）各要一个不撞的颜色，而 P 一直没有：
     `.mini.mP{background:var(--ac-soft);color:var(--ac)}` 从写下那天起引用的就是
     **两个不存在的变量** —— CSS 遇到未定义变量会把整条声明作废，
     于是高峰班在日历格与图例里是全站唯一「没有颜色」的那一档，而且不报错。

     ⚠️ 两条实测教训，别再踩：
     ① 它**不能**写成 `--ac:var(--a)`。`--a` 在深色格子上是 4.11 : 1，本来就差一点；
        更要命的是自定义属性的替换在**声明它的那个元素**上就定死了 ——
        写在 `:root` 的 `var(--a)` 会用 html 上的值算完再往下继承，
        浅色主题把 `--a` 改在 body 上根本影响不到它。实测就是这样：浅色下
        `.mini.mP` 拿到的仍是 `#5b8cff`（2.74 : 1），而不是 `#3559cc`。
     ② 所以两套主题各写各的字面值，字色比自己那层淡底亮一档：
        暗色 #7ba4ff 在 --ac-soft 叠出来的底上 5.33 : 1 ✓（原方案 #5b8cff = 4.11 ✗）；
        浅色 #3559cc 5.28 : 1 ✓。淡底沿用强调色那层同色系，只是明度不同。 */
  --ac:#7ba4ff; --ac-soft:rgba(91,140,255,.14);
  --r:14px; --r-sm:10px;
  --tab-h:60px; --top-h:56px;
}
/* 浅色主题：**每个语义色都在浅底上重新算过**（2026-09-29）。
   独立测试报告只量了暗色（默认主题），在 light 那一行写的是「#8d95a3 接近达标，
   建议一并复核」。复核的结果是：不接近 —— 8d95a3 在白底上只有 3.02 : 1，
   浅色主题实测 118 处不达标。所以这一组不是"顺手调一下"，而是每个值都按
   「最暗的那个表面」重算：文字要能压住 --sf3(#eceed3) 这类偏暗的底，
   徽标要能压住自己那层 soft 淡底。括号里是对比度实测值。 */
body[data-theme="light"]{
  --bg:#f4f5f7; --sf:#ffffff; --sf2:#f5f6f8; --sf3:#eceed3; --line:#e3e7ed;
  --tx:#171b22; --tx2:#5b6472; --tx3:#666c79;   /* 4.83 : 1 on --bg ✓（原 #8d95a3 = 2.77 ✗） */
  --a:#3559cc;                                  /* 5.43 : 1 on --a-soft ✓（原 #5b8cff = 2.82 ✗） */
  --ok:#0b6b48; --warn:#7d5600; --dg:#b82f26; --pp:#6230e0;
  /* 实心红底（白字徽标用）：浅色下 --dg 本身已经够深（白字 6.05 : 1），
     与 --a/--ok 一样把角色写全 —— 免得下次有人以为「浅色不需要这一格」。 */
  --dg-fill:#b82f26;
  /* 高峰班色（见上方 :root 里那段注释）：浅色主题必须**自己再写一遍** ——
     它不能继承暗色那格，也不能写成 var(--a)（替换发生在声明处，会定死在暗色的值上）。 */
  --ac:#3559cc; --ac-soft:rgba(91,140,255,.11);   /* 5.28 : 1 on 自己的淡底 ✓ */
  --ok-soft:rgba(18,160,110,.11); --warn-soft:rgba(201,138,0,.11);
  --dg-soft:rgba(217,72,60,.11); --pp-soft:rgba(124,77,255,.11);
  /* --a-soft / --*-soft 是**独立角色**（一层很淡的底），不跟着上面的字色改：
     它们是 .14/.11 的透明色叠在表面上，改字色时"淡底"没有理由一起变深。
     暗色那边同理。 */
  --a-soft:rgba(91,140,255,.11);
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0}
/* 键盘焦点必须看得见（WCAG 2.4.7）。用 :focus-visible 而不是 :focus ——
   鼠标点击不画圈，只有 Tab / 方向键走过来才画。
   这一条是「导航改成 <button>」的可见收益：原先 <div> 连焦点都拿不到，也就无从画起。
   下面 .helpq:focus / .f input:focus 那几处自己换了视觉（描边/底色），
   选择器特异性更高，会照旧生效 —— 那是刻意的，不是被这条盖掉。 */
:focus-visible{outline:2px solid var(--a);outline-offset:2px}
body{
  background:var(--bg);color:var(--tx);
  font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei","Helvetica Neue",Arial,sans-serif;
  font-size:14.5px;line-height:1.6;-webkit-font-smoothing:antialiased;
  padding-bottom:calc(var(--tab-h) + env(safe-area-inset-bottom));
}
#app{max-width:640px;margin:0 auto;min-height:100vh}

/* ── 未认证：骨架不可见 ──
   index.html 里 #app 自带内联 visibility:hidden（第一道，不依赖 CSS 是否加载）；
   这条是第二道 —— 谁把内联样式删了，body.preauth 还在兜着。
   身份确认后由 js/auth.js :: unlockApp() 摘掉 body.preauth 并清掉内联样式。 */
body.preauth #app{visibility:hidden;pointer-events:none}

/* ── 顶栏 ── */
.topbar{
  position:sticky;top:0;z-index:50;height:var(--top-h);
  display:flex;align-items:center;justify-content:space-between;
  padding:0 14px;background:color-mix(in srgb,var(--bg) 88%,transparent);
  backdrop-filter:blur(14px);border-bottom:1px solid var(--line);
}
.logo{font-size:17px;font-weight:800;letter-spacing:-.3px}
.logo span{color:var(--a)}
.tb-sub{font-size:11px;color:var(--tx3);margin-top:-2px}
.tb-r{display:flex;align-items:center;gap:8px}
.ghost{background:var(--sf2);border:1px solid var(--line);color:var(--tx);
  border-radius:9px;width:32px;height:32px;cursor:pointer;font-size:14px}
.rolesel{background:var(--sf2);border:1px solid var(--line);color:var(--tx);
  border-radius:9px;height:32px;padding:0 8px;font-size:12.5px;font-family:inherit;max-width:130px}
.ghost.txt{width:auto;padding:0 11px;font-size:12.5px;font-weight:650}

/* 说明中心 */
.docbar{display:flex;gap:6px;overflow-x:auto;padding-bottom:8px;margin-bottom:10px;
  border-bottom:1px solid var(--line)}
.docbar a{color:var(--tx2);text-decoration:none;font-size:12.5px;padding:4px 10px;
  border-radius:8px;background:var(--sf2);white-space:nowrap;flex:none}
/* 目录条：d0 = 返回说明中心，d1/d2/d3 = 文档的 1/2/3 级标题。
   注：类名以前写成 .dl1/.dl2/.dl3，而 CSS 里写的是 .d2 —— 对不上，
   于是「二级标题加粗」这个样式从来没生效过。现在两边统一为 d + 级别。 */
.docbar a.d0{font-weight:750;color:var(--a);border:1px solid var(--a);background:var(--a-soft)}
.docbar a.d1{font-weight:700;color:var(--tx)}
.docbar a.d3{color:var(--tx3)}
.md{font-size:14px;color:var(--tx2);line-height:1.78}
.md h1,.md h2,.md h3,.md h4{color:var(--tx);margin:18px 0 8px;line-height:1.4}
.md h1{font-size:19px}.md h2{font-size:16.5px;border-left:3px solid var(--a);padding-left:9px}
.md h3{font-size:14.5px}
.md p{margin:8px 0}
.md ul{padding-left:20px;margin:8px 0}.md li{margin:4px 0;color:var(--tx2)}
.md blockquote{margin:10px 0;padding:9px 13px;background:var(--sf2);
  border-left:3px solid var(--warn);border-radius:0 8px 8px 0;color:var(--tx2)}
.md table{font-size:12.5px;margin:10px 0}
.md td{padding:7px 9px}
.md code{background:var(--sf3);padding:1px 5px;border-radius:5px;font-size:12.5px;color:var(--warn)}
.md pre{background:var(--sf2);border:1px solid var(--line);border-radius:10px;
  padding:11px 13px;overflow:auto;font-size:12.5px}
.md pre code{background:none;color:var(--tx2)}
.md hr{border:none;border-top:1px solid var(--line);margin:16px 0}

/* 工资明细 */
.paylist{margin-top:8px;border-top:1px solid var(--line);padding-top:6px}
.prow{display:flex;justify-content:space-between;font-size:13px;padding:4px 0;color:var(--tx2)}
.prow b{color:var(--tx)}
.prow.total{border-top:1px dashed var(--line);margin-top:5px;padding-top:8px;font-size:15px}
.prow.total b{color:var(--ok);font-size:17px}

/* ── 内容区 ── */
main{padding:14px 14px 8px}
.sec{margin-bottom:18px}
.sec-h{display:flex;align-items:center;justify-content:space-between;margin:0 2px 9px}
.sec-h h3{margin:0;font-size:14px;font-weight:750}
.sec-h .more{font-size:12px;color:var(--tx3)}

/* ── 区块标题旁的「?」解释 + 标题下方可折叠的详细说明 ──
   结构见 js/help.js。这里只负责长相。

   为什么用 data-tip + ::after 自己画，而不是原生 title：
   原生 title 悬停约 1 秒才弹（用户会以为没有解释），而且**手机上完全不显示**。
   做成 ::after 之后：Mac 悬停即弹；iPhone 点一下（:focus）也弹；键盘 Tab 同样弹。
   .card 没有 overflow:hidden（全文件搜过），所以浮层不会被裁掉。 */
.helpq{
  display:inline-flex;align-items:center;justify-content:center;
  vertical-align:-2px;margin-left:5px;
  width:15px;height:15px;flex:none;padding:0;
  border:1px solid var(--line);border-radius:50%;
  background:var(--sf2);color:var(--tx3);
  font-family:inherit;font-size:10.5px;font-weight:800;line-height:1;
  letter-spacing:0;cursor:help;position:relative;
}
.helpq:hover,.helpq:focus{outline:none;color:var(--a);border-color:var(--a);background:var(--a-soft)}
.helpq::after{
  content:attr(data-tip);
  position:absolute;top:calc(100% + 7px);left:50%;transform:translateX(-50%);
  z-index:80;width:max-content;max-width:min(300px,80vw);
  padding:8px 10px;border:1px solid var(--line);border-radius:9px;
  background:var(--sf3);color:var(--tx);
  font-size:12px;font-weight:500;letter-spacing:0;line-height:1.6;
  text-align:left;white-space:normal;
  box-shadow:0 10px 26px rgba(0,0,0,.3);
  opacity:0;visibility:hidden;pointer-events:none;transition:opacity .12s;
}
.helpq:hover::after,.helpq:focus::after{opacity:1;visibility:visible}

.hfold{
  margin:0 0 10px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--sf2);overflow:hidden;
}
.hfold>summary{
  display:flex;align-items:center;gap:6px;
  padding:8px 11px;font-size:12.5px;font-weight:650;color:var(--tx2);
  cursor:pointer;list-style:none;
}
.hfold>summary::-webkit-details-marker{display:none}
.hfold>summary::before{content:'▸';flex:none;color:var(--a);font-size:11px;transition:transform .15s}
.hfold[open]>summary::before{transform:rotate(90deg)}
.hfold[open]>summary{color:var(--tx);border-bottom:1px solid var(--line)}
.hfold-b{padding:10px 12px;font-size:13px;line-height:1.74;color:var(--tx2)}
.hfold-b b{color:var(--tx)}
.hfold-b p{margin:0 0 8px}
.hfold-b p:last-child{margin-bottom:0}
.hfold-b ul{padding-left:19px;margin:6px 0}
.hfold-b li{margin:3px 0}
.hfold-b table{font-size:12px;margin:8px 0}
.hfold-b td{padding:5px 8px;border-bottom:1px solid var(--line)}
.hfold-b code{background:var(--sf3);padding:1px 5px;border-radius:5px;font-size:12px;color:var(--warn)}
.hfold-b .hl{color:var(--tx);font-weight:700}

.card{background:var(--sf);border:1px solid var(--line);border-radius:var(--r);padding:14px 15px}
.card+.card{margin-top:10px}
.card.tight{padding:12px 13px}

/* 今日大卡 */
.today{
  background:linear-gradient(135deg,var(--a-soft),transparent 62%),var(--sf);
  border:1px solid var(--line);border-radius:18px;padding:16px 17px;position:relative;overflow:hidden;
}
.today.rest{background:linear-gradient(135deg,var(--ok-soft),transparent 62%),var(--sf)}
.today .ttop{display:flex;justify-content:space-between;align-items:flex-start}
.today .tlabel{font-size:12px;color:var(--tx2)}
.today .tname{font-size:22px;font-weight:800;letter-spacing:-.5px;margin:2px 0 3px}
.today .twin{font-size:13px;color:var(--tx2);font-variant-numeric:tabular-nums}
.today .tcount{
  background:var(--sf3);border:1px solid var(--line);border-radius:999px;
  padding:4px 11px;font-size:12px;color:var(--tx2);white-space:nowrap;
}
.today .tcount b{color:var(--warn)}
.tacts{display:flex;gap:9px;margin-top:14px}
.btn{
  flex:1;border:1px solid var(--line);background:var(--sf2);color:var(--tx);
  border-radius:11px;padding:11px 12px;font-size:14px;font-weight:650;cursor:pointer;font-family:inherit;
}
.btn:active{transform:scale(.985)}
.btn.pri{background:var(--a-fill);border-color:var(--a-fill);color:#fff}
.btn.ok{background:var(--ok-fill);border-color:var(--ok-fill);color:#fff}
.btn.wide{flex:none;width:100%}
.btn.sm{padding:7px 11px;font-size:12.5px;flex:none;border-radius:9px}
.btn:disabled{opacity:.4;cursor:not-allowed}
.btn.danger{background:var(--dg-soft);border-color:color-mix(in srgb,var(--dg) 40%,var(--line));color:var(--dg)}

/* 指标网格 */
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.stat{background:var(--sf);border:1px solid var(--line);border-radius:var(--r);padding:11px 12px}
.stat .n{font-size:20px;font-weight:800;letter-spacing:-.4px;font-variant-numeric:tabular-nums}
.stat .l{font-size:11.5px;color:var(--tx3);margin-top:1px}
.stat .d{font-size:11px;margin-top:3px}
.up{color:var(--ok)}.down{color:var(--dg)}.flat{color:var(--tx3)}

/* 列表行 */
.row{display:flex;align-items:center;gap:11px;padding:11px 0;border-top:1px solid var(--line)}
.row:first-child{border-top:none}
.row .ava{width:34px;height:34px;border-radius:10px;background:var(--sf3);
  display:flex;align-items:center;justify-content:center;font-weight:750;font-size:13px;flex:none}
.row .rm{flex:1;min-width:0}
.row .rm b{display:block;font-size:14px;font-weight:650}
/* `>` 不能省：这条是给「第二行说明」上色的，而 `.rm` 里还有**徽标**（`<b>` 里的
   `<span class="bdg b-n">L1</span>`）。用后代选择器时 (0,2,1) 会盖掉 `.b-n` (0,1,0)，
   于是徽标的字色被换成三级灰 —— 深色主题下 4.94 : 1 恰好达标，看不出问题；
   浅色主题下同一格只有 4.44 : 1，直到复核浅色才现形。加 `>` 后只命中直接子元素。 */
.row .rm > span{font-size:12px;color:var(--tx3)}
.row .rv{font-size:13px;font-weight:700;text-align:right;flex:none}

/* 徽章 */
.bdg{display:inline-block;padding:2px 8px;border-radius:6px;font-size:11.5px;font-weight:700;border:1px solid transparent}
.b-a{background:var(--ok-soft);color:var(--ok);border-color:color-mix(in srgb,var(--ok) 30%,transparent)}
.b-b{background:var(--warn-soft);color:var(--warn);border-color:color-mix(in srgb,var(--warn) 30%,transparent)}
.b-c{background:var(--pp-soft);color:var(--pp);border-color:color-mix(in srgb,var(--pp) 30%,transparent)}
/* 中性徽标的字色是 --tx2 而不是 --tx3：它的底是 --sf3 —— **全站最暗的那个表面**。
   在 #eceed3 上，--tx3 无论取什么值都很难同时满足"≥4.5"和"看得出比 --tx2 淡一档"
   （实测 #666c79 在 #eceed3 上只有 4.45）。徽标本来就该是次要但**要看清**的东西，
   用 --tx2 最省事也最诚实：4.70 → 5.05 的实测值在下面那行注释里。 */
.b-n{background:var(--sf3);color:var(--tx2);border-color:var(--line)}
.b-ok{background:var(--ok-soft);color:var(--ok)}
.b-dg{background:var(--dg-soft);color:var(--dg)}
.b-wn{background:var(--warn-soft);color:var(--warn)}

/* 日历 / 排班表 */
.calhead{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.calhead .m{font-size:15px;font-weight:750;font-variant-numeric:tabular-nums}
.navb{display:flex;gap:6px}
.navb button{background:var(--sf2);border:1px solid var(--line);color:var(--tx);
  width:30px;height:30px;border-radius:8px;cursor:pointer;font-size:13px}
.weekrow{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;margin-bottom:5px}
.weekrow div{text-align:center;font-size:11px;color:var(--tx3);font-weight:650}
.weekrow div.we{color:var(--warn)}
.calgrid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}
.day{
  background:var(--sf);border:1px solid var(--line);border-radius:9px;
  min-height:76px;padding:4px 3px;position:relative;cursor:pointer;overflow:hidden;
}
.day.blank{background:transparent;border-color:transparent;cursor:default;min-height:0}
.day.we{background:color-mix(in srgb,var(--warn) 6%,var(--sf))}
.day.out{opacity:.35}
.day.today{border-color:var(--a);box-shadow:0 0 0 1px var(--a) inset}
.day .dn{font-size:11.5px;color:var(--tx2);text-align:center;font-variant-numeric:tabular-nums}
.day.today .dn{color:var(--a);font-weight:800}
.day .slots{margin-top:3px;display:flex;flex-direction:column;gap:2px}
.mini{display:flex;align-items:center;gap:2px;font-size:9.5px;line-height:1.5;
  border-radius:4px;padding:1px 3px;overflow:hidden;white-space:nowrap}
.mini i{font-style:normal;font-weight:800;width:9px;text-align:center;flex:none}
.mini.mA{background:var(--ok-soft);color:var(--ok)}
.mini.mB{background:var(--warn-soft);color:var(--warn)}
.mini.mC{background:var(--pp-soft);color:var(--pp)}
.mini.mP{background:var(--ac-soft);color:var(--ac)}
.mini.sel{outline:1.5px solid var(--a)}
.mini.dim{opacity:.2}

.legend{display:flex;gap:12px;flex-wrap:wrap;font-size:11.5px;color:var(--tx3);margin-top:9px}
.legend i{display:inline-block;width:8px;height:8px;border-radius:3px;margin-right:4px}

/* 表单 */
.f{margin-bottom:11px}
.f label{display:block;font-size:12px;color:var(--tx2);margin-bottom:5px;font-weight:600}
.f input,.f select,.f textarea{
  width:100%;background:var(--sf2);border:1px solid var(--line);color:var(--tx);
  border-radius:10px;padding:10px 11px;font-size:14px;font-family:inherit;
}
.f textarea{min-height:70px;resize:vertical}
.f input:focus,.f select:focus,.f textarea:focus{outline:none;border-color:var(--a)}
.f .hint{font-size:11px;color:var(--tx3);margin-top:4px}
.frow{display:grid;grid-template-columns:1fr 1fr;gap:9px}

/* 表格 */
.tbl{width:100%;border-collapse:collapse;font-size:12.5px}
.tbl th{background:var(--sf2);color:var(--tx2);font-weight:700;font-size:11.5px;
  text-align:left;padding:8px 9px;border-bottom:1px solid var(--line);position:sticky;top:0}
.tbl td{padding:8px 9px;border-bottom:1px solid var(--line);color:var(--tx2)}
.tbl td b{color:var(--tx)}
.tblwrap{max-height:420px;overflow:auto;border:1px solid var(--line);border-radius:var(--r)}

.in{width:100%;background:var(--sf2);border:1px solid var(--line);color:var(--tx);
  border-radius:8px;padding:5px 7px;font-size:12.5px;font-family:inherit}
.tbl td:has(.in){padding:5px 5px}
code{background:var(--sf3);padding:1px 5px;border-radius:5px;font-size:12px;color:var(--tx)}

/* 提示框 */
.callout{background:var(--sf);border:1px solid var(--line);border-left:3px solid var(--a);
  border-radius:10px;padding:11px 13px;font-size:13px;color:var(--tx2);margin:11px 0}
.callout.warn{border-left-color:var(--warn)}
.callout.ok{border-left-color:var(--ok)}
.callout.dg{border-left-color:var(--dg)}
.callout b{color:var(--tx)}

.empty{text-align:center;padding:34px 12px;color:var(--tx3);font-size:13px}

/* 底部导航 */
.tabbar{
  position:fixed;left:0;right:0;bottom:0;z-index:60;
  display:flex;background:color-mix(in srgb,var(--bg) 92%,transparent);
  backdrop-filter:blur(14px);border-top:1px solid var(--line);
  padding-bottom:env(safe-area-inset-bottom);
  max-width:640px;margin:0 auto;
}
/* ⚠️ 这两组导航项是 <button>（不是 <div>）—— 键盘用户要能用 Tab 走到、回车激活。
   <button> 自带 UA 样式（灰底、2px 立体边框、不继承字体），所以先把它们抹平；
   抹平的那几个属性必须写在**前面**，后面原有的 color/font-size 才盖得住。
   `.navitem` 已有 `border:1px solid transparent`，这里不重复。 */
.tabbar .tab{
  appearance:none;background:none;border:0;padding:0;font:inherit;text-align:center;
  flex:1;height:var(--tab-h);display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:2px;color:var(--tx3);font-size:10.5px;cursor:pointer;position:relative;
}
.tabbar .tab.on{color:var(--a)}
.tabbar .tab .ic{font-size:19px;line-height:1}
.tabbar .tab .dot{position:absolute;top:9px;right:calc(50% - 17px);width:7px;height:7px;
  border-radius:50%;background:var(--dg)}

/* toast & modal */
.toast{position:fixed;left:50%;transform:translateX(-50%);bottom:calc(var(--tab-h) + 18px);
  background:var(--tx);color:var(--bg);padding:9px 16px;border-radius:10px;font-size:13px;
  font-weight:650;z-index:200;opacity:0;pointer-events:none;transition:.22s;white-space:nowrap}
.toast.on{opacity:1;transform:translateX(-50%) translateY(-6px)}
.modal-wrap{position:fixed;inset:0;z-index:150;display:flex;align-items:flex-end;justify-content:center}
.modal-wrap.hidden{display:none}
.modal-bg{position:absolute;inset:0;background:rgba(0,0,0,.5)}
.modal{position:relative;background:var(--sf);width:100%;max-width:640px;
  border-radius:18px 18px 0 0;padding:16px 16px calc(20px + env(safe-area-inset-bottom));
  max-height:86vh;overflow:auto;animation:up .22s ease}
@keyframes up{from{transform:translateY(30px);opacity:.4}to{transform:none;opacity:1}}
.modal h3{margin:0 0 12px;font-size:16px}
.modal .mtop{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
.mclose{background:var(--sf2);border:1px solid var(--line);color:var(--tx);border-radius:8px;
  width:28px;height:28px;cursor:pointer}

@media(min-width:700px){
  .tabbar{border-radius:16px 16px 0 0;border-left:1px solid var(--line);border-right:1px solid var(--line)}
  .modal{border-radius:18px;margin-bottom:6vh}
  .modal-wrap{align-items:center}
}

/* ══════ KPI 分区标题（接得住 / 分得对 / 跟得完）══════ */
.kgroup{margin:16px 0 6px;padding:6px 10px;font-size:12px;font-weight:700;letter-spacing:.4px;
  color:var(--tx2,var(--tx));background:var(--sf2);border-left:3px solid var(--a);
  border-radius:0 6px 6px 0}
.kgroup:first-of-type{margin-top:6px}
.kgroup.ref{border-left-color:var(--tx3);color:var(--tx3);font-weight:600}
/* .mt：setup 第 1 步原来写的是 style="margin-top:16px"，
   改用类名，免得 kgH() 还要为它开一个「塞原始属性」的口子。 */
.kgroup.mt{margin-top:16px}



/* ══════ 设置面板分区导航 ══════ */
.setnav{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px}
.setnav a{padding:6px 11px;border-radius:999px;font-size:12px;font-weight:600;text-decoration:none;
  background:var(--sf2);border:1px solid var(--line);color:var(--tx);transition:.15s}
.setnav a:hover{border-color:var(--a);color:var(--a)}
.sec-anchor{scroll-margin-top:14px}

/* ══════ 数据自检结果 ══════ */
.chk{display:flex;gap:9px;align-items:flex-start;padding:9px 10px;border-radius:9px;
  background:var(--sf2);margin-bottom:6px;font-size:13px;line-height:1.5}
.chk .ic{flex:0 0 18px;text-align:center;font-weight:700}
.chk.ok .ic{color:var(--ok,#1a9c5b)}
.chk.warn .ic{color:var(--warn)}
.chk.err .ic{color:var(--dg,#e04b4b)}
.chk .fix{margin-left:auto;flex:0 0 auto}
.chk-sum{display:flex;gap:8px;margin-bottom:12px}
.chk-sum div{flex:1;text-align:center;padding:8px 4px;border-radius:9px;background:var(--sf2)}
.chk-sum b{display:block;font-size:19px}
.chk-sum span{font-size:11px;color:var(--tx3)}

/* ══════ 数据源列表行 ══════ */
.dsrow{display:flex;gap:8px;align-items:center;padding:8px 0;border-bottom:1px solid var(--line)}
.dsrow:last-child{border-bottom:0}
.dsrow .nm{flex:1;font-size:13px;font-weight:600}
.dsrow .meta{font-size:11px;color:var(--tx3);font-weight:400}

/* ══════ 配置向导（首次启动，名册由用户录入）══════ */
.setup-wrap{display:flex;justify-content:center;padding:8px 0 30px}
.setup-card{width:100%;max-width:660px}
.setup-top h2{margin:0 0 12px;font-size:17px;font-weight:650}
.setup-steps{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px}
.setup-steps span{padding:5px 10px;border-radius:999px;font-size:12px;
  background:var(--sf2);border:1px solid var(--line);opacity:.55}
.setup-steps span.done{opacity:.85;border-color:var(--ok,#1a9c5b);color:var(--ok,#1a9c5b)}
.setup-steps span.on{opacity:1;border-color:var(--a);color:var(--a);font-weight:600}
.setup-body{background:var(--sf);border:1px solid var(--line);border-radius:14px;padding:16px}
.setup-body textarea{width:100%;background:var(--sf2);border:1px solid var(--line);
  color:var(--tx);border-radius:9px;padding:9px 10px;font-size:13px;line-height:1.6;
  font-family:inherit;resize:vertical}
.setup-body textarea:focus{outline:none;border-color:var(--a)}

/* ── 班次模式预设卡片 ── */
.pgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:10px;margin-bottom:10px}
.pcard{background:var(--sf2);border:1px solid var(--line);border-radius:12px;padding:12px 13px;cursor:pointer;
  transition:border-color .15s,background .15s}
.pcard:hover{border-color:var(--a)}
.pcard.on{border-color:var(--ok);background:var(--ok-soft)}
.pcard .ph{display:flex;align-items:center;gap:6px;font-size:14px;margin-bottom:6px}
.pcard .pd{font-size:12.5px;color:var(--tx2);line-height:1.65}
.pcard .pw{font-size:12px;color:var(--warn);line-height:1.6;margin-top:8px;
  padding-top:8px;border-top:1px dashed var(--line)}
.inp.sm{padding:4px 6px;font-size:12.5px}
.hint{display:block;font-size:11.5px;color:var(--tx3);margin-top:4px}
/* 「次要但要看清楚」的文字。**不要再用 `style="opacity:.6"` 淡化文字** ——
   opacity 是朝底层颜色混，浅色主题（白底）下会把字混成 2.5 : 1 的灰，
   而它看起来"只是淡了一点"，所以没人会去查。用三级字色，两套主题各自达标。
   （2026-09-29 独立测试报告只量了暗色，浅色这 7 处是复核算出来的。） */
.mut{color:var(--tx3)}
code{background:var(--sf2);border:1px solid var(--line);border-radius:4px;padding:1px 5px;font-size:12px}

/* ════════ 多端布局：PC 左导航 ≥820px / 移动底 tabbar ≤819px ═══════
   设计令牌沿用上方 :root；这里只补「侧栏宽度」与「阴影/缓动」两个变量。
   移动端继续用底部 .tabbar（已在前面定义），PC 端改用左侧 .nav 并让出顶栏/内容区宽度。 */
:root{ --side-w:252px; --sh-2:0 6px 18px rgba(0,0,0,.30); --ease:cubic-bezier(.22,.61,.36,1); }

/* ── PC 左导航（移动端隐藏）── */
.nav{position:fixed;left:0;top:0;bottom:0;width:var(--side-w);z-index:40;
  background:var(--sf);border-right:1px solid var(--line);
  display:none;flex-direction:column;padding:14px 12px;gap:4px;overflow-y:auto}
.nav .brand{display:none}
.nav .grp{font-size:10.5px;font-weight:800;letter-spacing:1.2px;color:var(--tx3);
  padding:8px 12px 5px;text-transform:uppercase}
.navitem{appearance:none;background:none;font:inherit;text-align:left;width:100%;
  display:flex;align-items:center;gap:11px;padding:11px 12px;border-radius:12px;
  color:var(--tx2);cursor:pointer;font-size:14px;font-weight:600;position:relative;
  transition:.15s;border:1px solid transparent}
.navitem .ic{font-size:18px;width:22px;text-align:center;flex:none}
.navitem:hover{background:var(--sf2);color:var(--tx)}
.navitem.on{background:var(--a-soft);color:var(--a);border-color:color-mix(in srgb,var(--a) 30%,transparent)}
.navitem .dot{position:absolute;top:9px;right:12px;min-width:18px;height:18px;padding:0 5px;
  border-radius:999px;background:var(--dg-fill);color:#fff;font-size:10.5px;font-weight:800;
  display:flex;align-items:center;justify-content:center}
.nav .spacer{flex:1}
.nav .rolebox{font-size:11.5px;color:var(--tx3);padding:10px 12px;border-top:1px solid var(--line);
  margin-top:6px;line-height:1.5}

/* ── 首页 · 三步直达 大盘控件（与现有 .card/.row/.bdg/.btn 共存，不重定义）── */
.status{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px;flex-wrap:wrap;gap:12px}
.status .d1{font-size:12.5px;color:var(--tx3)}
.status .d2{font-size:23px;font-weight:800;letter-spacing:-.5px}
.direct{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px}
.dcard{position:relative;background:linear-gradient(135deg,var(--a-soft),transparent 70%),var(--sf);
  border:1px solid var(--line);border-radius:var(--r-lg,18px);padding:16px;cursor:pointer;min-height:112px;
  display:flex;flex-direction:column;justify-content:space-between;
  transition:transform .18s var(--ease),box-shadow .18s,border-color .18s}
.dcard:hover{border-color:color-mix(in srgb,var(--a) 50%,var(--line));box-shadow:var(--sh-2)}
.dcard:active{transform:scale(.98)}
.dcard .ic{width:40px;height:40px;border-radius:12px;display:flex;align-items:center;justify-content:center;
  font-size:20px;background:var(--sf3);margin-bottom:10px}
.dcard .t{font-size:15.5px;font-weight:750}
.dcard .h{font-size:12px;color:var(--tx3);margin-top:3px;line-height:1.5}
.dcard.wide{grid-column:span 2;flex-direction:row;align-items:center;min-height:auto;
  background:linear-gradient(135deg,var(--ok-soft),transparent 70%),var(--sf)}
.dcard.wide .ic{margin-bottom:0;margin-right:14px;background:var(--ok-soft);color:var(--ok)}
.dcard .badge{position:absolute;top:13px;right:13px;min-width:22px;height:22px;padding:0 7px;
  border-radius:999px;background:var(--dg-fill);color:#fff;font-size:11.5px;font-weight:800;
  display:flex;align-items:center;justify-content:center}
.cols{display:grid;grid-template-columns:1.7fr 1fr;gap:22px;align-items:start}
.glance{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
.tile{background:var(--sf);border:1px solid var(--line);border-radius:var(--r);padding:13px 15px}
.tile .n{font-size:21px;font-weight:800;letter-spacing:-.4px;font-variant-numeric:tabular-nums}
.tile .n.up{color:var(--ok)}.tile .n.dg{color:var(--dg)}
.tile .l{font-size:12px;color:var(--tx3);margin-top:3px}
.tile .d{font-size:11.5px;margin-top:4px;color:var(--tx2)}
.todo{background:var(--sf);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.trow{display:flex;align-items:center;gap:11px;padding:12px 15px;border-top:1px solid var(--line)}
.trow:first-child{border-top:none}
.trow .ava{width:34px;height:34px;border-radius:10px;background:var(--sf3);flex:none;
  display:flex;align-items:center;justify-content:center;font-weight:750;font-size:13px;color:var(--tx2)}
.trow .rm{flex:1;min-width:0}
.trow .rm b{display:block;font-size:14px;font-weight:650;line-height:1.35}
.trow .rm > span{font-size:12px;color:var(--tx3)}   /* 同上：别把徽标的颜色一起改掉 */
.trow .go{background:var(--sf2);border:1px solid var(--line);color:var(--tx);border-radius:9px;
  padding:6px 13px;font-size:12.5px;font-weight:650;cursor:pointer;white-space:nowrap}
.trow .go:active{transform:scale(.96)}
.status-on{display:flex;align-items:center;gap:6px;background:var(--ok-soft);
  border:1px solid color-mix(in srgb,var(--ok) 35%,transparent);color:var(--ok);
  border-radius:999px;padding:5px 12px;font-size:12.5px;font-weight:700;white-space:nowrap}
.status-on i{width:7px;height:7px;border-radius:50%;background:var(--ok);box-shadow:0 0 0 3px rgba(47,191,135,.25)}

/* ════════ PC ≥820：左导航 + 顶栏让位 + 内容区留白；隐藏底 tabbar ═══════ */
@media(min-width:820px){
  #app{max-width:none;margin:0}
  body{padding-bottom:0}
  .topbar{margin-left:var(--side-w);width:auto;z-index:55}
  main{margin-left:var(--side-w);padding:22px 28px 48px;max-width:1240px}
  .nav{display:flex}
  .nav .brand{display:flex;align-items:baseline;gap:2px;font-size:18px;font-weight:800;
    padding:10px 12px 14px;border-bottom:1px solid var(--line);margin-bottom:8px}
  .tabbar{display:none}
}
/* 移动 ≤819：保留底 tabbar，隐藏左导航，内容区底部留白给 tabbar */
@media(max-width:819px){
  .nav{display:none}
  main{padding-bottom:calc(var(--tab-h) + 16px)}
}

/* ══════ 机器人操作菜单 ══════ */
.bot-chats, .bot-binds, .bot-kick{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.sub{font-size:12px;font-weight:700;color:var(--tx2);margin:12px 0 2px;padding-left:2px}
.ck{display:flex;align-items:center;gap:6px;font-size:13px;margin-top:6px;cursor:pointer}
.cklist{display:flex;flex-direction:column;gap:8px;margin-top:4px}
.ckrow{display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border-radius:12px;
  border:1px solid var(--line);background:var(--sf)}
.ckrow .ckmark{flex:0 0 20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:800;margin-top:1px}
.ckrow.ok{border-color:color-mix(in srgb,var(--ok) 45%,transparent)}
.ckrow.ok .ckmark{background:var(--ok-soft);color:var(--ok)}
.ckrow.fail{border-color:color-mix(in srgb,var(--dg) 45%,transparent)}
.ckrow.fail .ckmark{background:var(--dg-soft);color:var(--dg)}
.ckbody{display:flex;flex-direction:column;gap:2px}
.ckbody b{font-size:13px;color:var(--tx)}
.ckbody span{font-size:12px;color:var(--tx2)}
/* 群发卡片里群名后面跟的「群 ID · 类型」补充说明 */
.mut{font-size:12px;color:var(--tx2);margin-left:8px}

/* ══════ 发送历史（群发 / 群公告）══════ */
.hlist{display:flex;flex-direction:column;max-height:52vh;overflow:auto;margin-top:4px}
.hrow{padding:10px 0;border-bottom:1px solid var(--line)}
.hrow:first-child{padding-top:4px}
.hrow:last-child{border-bottom:0;padding-bottom:0}
.hmeta{display:flex;align-items:center;flex-wrap:wrap;gap:8px;font-size:12px;color:var(--tx2)}
.hmeta b{color:var(--tx);font-weight:650}
/* 群发正文可能多行，历史里按原样换行显示 */
.hbody{font-size:13px;line-height:1.62;color:var(--tx);margin-top:5px;
  white-space:pre-wrap;word-break:break-word}
.hnote{font-size:11.5px;color:var(--tx3);margin-top:5px;line-height:1.55}

/* 权重网格：14 个考核权重输入框，紧凑三列 —— 它们是一组数，不该铺成一长条 */
.wgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px 10px;margin:2px 0 6px}
.wgrid .f{margin:0}
@media (max-width:560px){.wgrid{grid-template-columns:repeat(2,1fr)}}
