/* ═══════════════════════════════════════════════════════════════════════════
   WHX 网页设计总规范 · 视觉语言层（§3 色彩/材质/纹理/圆角/字体/图标）
   管理端与用户端共用。

   ⚠ 本项目是纯 Web 页面（浏览器直接打开），不接入游戏客户端，
     因此豁免规范的 Chromium 75 兼容条款 —— 可自由使用现代 CSS：
     flex gap / aspect-ratio / inset / min()·max()·clamp() / :focus-visible /
     过渡与关键帧动画 / backdrop-filter。
     视觉语言（Token、材质、圆角、字体）仍然严格遵循 §3。
   ═══════════════════════════════════════════════════════════════════════════ */
:root{
  --wl-stone:#c4c0b1;--wl-panel:#aaa99c;--wl-surface:#ded7c4;--wl-slot:#817e70;
  --wl-border:#494940;--wl-shadow:#6b675b;--wl-highlight:#f2eddf;
  --wl-green:#627d36;--wl-wood:#825c38;--wl-gold:#a18235;--wl-water:#3b8ea5;
  --wl-warning:#80691f;--wl-danger:#8b3d2e;--wl-text:#272923;--wl-muted:#62645b;
  --ok-bg:#3f5423;--ok-tx:#e8f0d8;--warn-bg:#6b5a1d;--warn-tx:#f0e6c8;--err-bg:#7a4034;--err-tx:#f2ddd5;
  --wl-deep-bg:#2e2b23;
  --wl-edge:#7f7c6e;--wl-slot-dark:#6f6c60;--wl-text-strong:#3f4038;
  --wl-panel-deep:#9d9a8b;--wl-sep:rgba(73,73,64,.24);
  --wl-grain:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><rect x='1' y='2' width='3' height='2' fill='rgba(255,255,255,.03)'/><rect x='2' y='3' width='2' height='2' fill='rgba(255,255,255,.025)'/><rect x='9' y='1' width='2' height='1' fill='rgba(0,0,0,.025)'/><rect x='10' y='2' width='1' height='2' fill='rgba(0,0,0,.025)'/><rect x='15' y='4' width='3' height='1' fill='rgba(255,255,255,.028)'/><rect x='16' y='5' width='2' height='1' fill='rgba(255,255,255,.025)'/><rect x='20' y='8' width='2' height='2' fill='rgba(0,0,0,.025)'/><rect x='21' y='9' width='1' height='2' fill='rgba(0,0,0,.02)'/><rect x='4' y='9' width='2' height='1' fill='rgba(0,0,0,.025)'/><rect x='5' y='10' width='1' height='2' fill='rgba(0,0,0,.02)'/><rect x='11' y='12' width='3' height='2' fill='rgba(255,255,255,.028)'/><rect x='12' y='14' width='2' height='1' fill='rgba(255,255,255,.025)'/><rect x='18' y='15' width='2' height='1' fill='rgba(0,0,0,.025)'/><rect x='6' y='16' width='3' height='1' fill='rgba(255,255,255,.025)'/><rect x='7' y='17' width='2' height='1' fill='rgba(255,255,255,.02)'/><rect x='0' y='19' width='2' height='2' fill='rgba(0,0,0,.025)'/><rect x='13' y='19' width='2' height='1' fill='rgba(0,0,0,.02)'/><rect x='21' y='20' width='2' height='2' fill='rgba(255,255,255,.025)'/><rect x='3' y='22' width='2' height='1' fill='rgba(255,255,255,.028)'/><rect x='9' y='21' width='1' height='2' fill='rgba(0,0,0,.02)'/><rect x='16' y='22' width='3' height='1' fill='rgba(255,255,255,.02)'/><rect x='19' y='0' width='1' height='3' fill='rgba(255,255,255,.02)'/><rect x='0' y='0' width='1' height='1' fill='rgba(0,0,0,.025)'/></svg>");
  --font-ui:"Microsoft YaHei","PingFang SC","Segoe UI",system-ui,sans-serif;
  --font-num:'Courier New',Consolas,monospace;
  --ease:cubic-bezier(.2,.7,.3,1);
}
*{box-sizing:border-box}
[hidden]{display:none!important}
html{background:var(--wl-deep-bg);scroll-behavior:smooth}
body{
  margin:0;color:var(--wl-text);
  padding:clamp(26px,3vw,44px) clamp(26px,4vw,56px) 72px;
  font:13px/1.55 var(--font-ui);
  background-color:var(--wl-deep-bg);
  background-image:
    radial-gradient(ellipse 130% 90% at 50% 0%,rgba(255,244,214,.055),transparent 58%),
    radial-gradient(ellipse 170% 120% at 50% 115%,rgba(0,0,0,.34),transparent 62%),
    var(--wl-grain);
  background-size:auto,auto,96px 96px;
  image-rendering:pixelated;
  -webkit-font-smoothing:antialiased;
}
.num{font-family:var(--font-num);font-weight:700;font-variant-numeric:tabular-nums}
a{color:var(--wl-gold);text-decoration:none;transition:color .15s var(--ease)}
a:hover{text-decoration:underline}
:focus-visible{outline:2px solid var(--wl-gold);outline-offset:2px;border-radius:3px}
::selection{background:rgba(161,130,53,.32)}
::-webkit-scrollbar{width:14px;height:14px}
::-webkit-scrollbar-track{background:var(--wl-panel-deep);border-left:2px solid var(--wl-slot-dark)}
::-webkit-scrollbar-thumb{background:var(--wl-slot-dark);border:2px solid var(--wl-panel-deep);border-radius:2px}
::-webkit-scrollbar-thumb:hover{background:#5c5a50}

/* ── 窗体（§5.1）── */
.frame{
  max-width:1180px;margin:0 auto;position:relative;
  background:linear-gradient(180deg,#b5b1a2,var(--wl-panel));
  border:3px solid var(--wl-border);border-radius:14px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.35),
    inset 0 0 0 1px rgba(255,255,255,.16),
    6px 6px 0 rgba(0,0,0,.3),
    9px 10px 18px rgba(0,0,0,.24);
}
.frame::before{
  content:"";position:absolute;inset:0;border-radius:11px;
  background:var(--wl-grain);background-size:48px 48px;
  image-rendering:pixelated;pointer-events:none;opacity:.5;
}

/* ── 顶栏（§6）── */
.topbar{
  position:relative;z-index:2;min-height:58px;
  display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
  padding:9px 22px;
  background:linear-gradient(180deg,var(--wl-panel),var(--wl-panel-deep));
  border-bottom:3px solid var(--wl-border);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32);
  border-radius:11px 11px 0 0;
}
.tb-l{display:flex;align-items:center;gap:12px;min-width:0}
.tb-ic{width:30px;height:30px;flex-shrink:0;image-rendering:pixelated}
.topbar h1{font-size:16px;font-weight:700;margin:0;letter-spacing:.02em;text-shadow:1px 1px 0 rgba(255,255,255,.35)}
.tb-s{color:var(--wl-muted);font-size:11.5px;margin-top:3px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.tb-s .sep{color:var(--wl-edge)}
.tb-r{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.badge-env{
  font-size:11px;font-weight:700;color:var(--wl-gold);letter-spacing:.1em;
  border:2px solid #8a6e2c;background:rgba(161,130,53,.16);padding:2px 8px;border-radius:2px;
}
.badge-role{
  font-size:11px;font-weight:700;color:var(--ok-tx);border:2px solid rgba(0,0,0,.3);
  background:var(--ok-bg);padding:2px 8px;border-radius:2px;
}
.badge-role.limited{background:var(--wl-slot-dark);color:#ece7da}
.sig{display:inline-flex;align-items:flex-end;gap:2px;height:14px}
.sig i{width:4px;background:#8f8b7d;border:1px solid var(--wl-border);border-radius:1px;display:inline-block;transition:background .25s var(--ease)}
.sig i:nth-child(1){height:5px}.sig i:nth-child(2){height:7px}.sig i:nth-child(3){height:9px}
.sig i:nth-child(4){height:11px}.sig i:nth-child(5){height:13px}
.sig.s5 i{background:var(--wl-green)}
.sig.s3 i:nth-child(-n+3){background:var(--wl-gold)}
.sig.s3 i:nth-child(n+4){background:#8f8b7d}
.sig.s1 i:nth-child(-n+1){background:var(--wl-danger)}
.sig.s1 i:nth-child(n+2){background:#8f8b7d}
.sig.s0 i{background:var(--wl-danger)}
.clock{font-family:var(--font-num);font-weight:700;font-size:13px;letter-spacing:.06em;text-shadow:1px 1px 0 rgba(255,255,255,.35)}

/* ── 顶栏实时看板：监控圆点 + 并发 + 累计 ── */
.live{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;font-weight:700;color:var(--wl-text-strong);white-space:nowrap}
.live-dot{
  width:10px;height:10px;border-radius:50%;position:relative;flex-shrink:0;
  background:radial-gradient(circle at 34% 30%,#9ec468,#4f6b28);
  box-shadow:0 0 0 2px rgba(98,125,54,.22);
}
.live-dot::after{
  content:"";position:absolute;inset:-3px;border-radius:50%;
  border:2px solid currentColor;opacity:0;
  animation:ping 2s var(--ease) infinite;
}
@keyframes ping{0%{transform:scale(.7);opacity:.65}70%,100%{transform:scale(1.8);opacity:0}}
.live-dot.ok{color:#627d36;background:radial-gradient(circle at 34% 30%,#9ec468,#4f6b28);box-shadow:0 0 0 2px rgba(98,125,54,.22)}
.live-dot.warn{color:#a18235;background:radial-gradient(circle at 34% 30%,#e6c46b,#8a6e2c);box-shadow:0 0 0 2px rgba(161,130,53,.24)}
.live-dot.err{color:#8b3d2e;background:radial-gradient(circle at 34% 30%,#d8735c,#6f2f24);box-shadow:0 0 0 2px rgba(139,61,46,.26)}
.live-dot.err::after{animation-duration:.95s}
.live-dot.busy{color:#3b8ea5;background:radial-gradient(circle at 34% 30%,#79c2d6,#2c6f84);box-shadow:0 0 0 2px rgba(59,142,165,.24)}
.kpi{display:inline-flex;align-items:baseline;gap:5px;font-size:11px;color:var(--wl-muted);white-space:nowrap}
.kpi-k{color:var(--wl-muted)}
.kpi b{font-size:13px;color:var(--wl-text);transition:color .3s var(--ease)}
.kpi b.hot{color:var(--wl-green);animation:hot 1.3s var(--ease) infinite}
@keyframes hot{0%,100%{opacity:1}50%{opacity:.55}}
@media (max-width:900px){.tb-r .kpi{display:none}.tb-r .live{display:none}}

/* ── 标签页（§6）── */
.tabs{
  position:relative;z-index:2;background:rgba(129,126,112,.42);border-bottom:3px solid var(--wl-border);
  padding:7px 16px;display:grid;grid-template-columns:repeat(9,minmax(0,1fr));gap:6px;
}
.tab{
  font-size:13px;line-height:1.4;font-family:var(--font-ui);font-weight:700;color:var(--wl-text-strong);
  background:rgba(196,192,177,.55);border:2px solid var(--wl-edge);border-radius:4px;
  padding:6px 4px;cursor:pointer;text-align:center;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3);
  transition:background .18s var(--ease),transform .12s var(--ease),box-shadow .18s var(--ease);
}
.tab:hover{background:var(--wl-surface);transform:translateY(-1px)}
.tab:active{transform:translateY(0)}
.tab[aria-selected="true"]{
  background:var(--wl-surface);border-color:var(--wl-border);color:var(--wl-text);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5),inset 0 -3px 0 var(--wl-green);
}
.tab .cnt{font-family:var(--font-num);font-size:11px;color:var(--wl-muted);margin-left:4px}
/* 用户端只有 3 个标签 */
.tabs.tabs3{grid-template-columns:repeat(3,minmax(0,1fr))}

/* ── 标签行：数量不定的一排可选标签（比如用量页顶上那排「人」）──
   ⚠ 不能直接复用 .tabs —— 它是**固定 9 列**的网格（给顶部导航用的），
   人数不定时会被硬挤成 9 列，名字长一点就溢出、短的时候右边一大片空白。
   这里用 flex 自动换行，宽度跟着内容走。 */
.chips{
  position:relative;z-index:2;display:flex;flex-wrap:wrap;gap:6px;
  padding:8px 0 2px;align-items:center;
}
.chips .tab{flex:0 0 auto;padding:5px 11px;font-size:12.5px}
.chips .lb{font-size:12px;color:var(--wl-muted);margin-right:2px}
@media (max-width:680px){.tabs.tabs3{grid-template-columns:repeat(3,minmax(0,1fr))}}

/* ── 内容区 ── */
.body{position:relative;z-index:2;padding:16px 20px 24px;min-height:460px}
section[role="tabpanel"]{animation:fadeUp .22s var(--ease)}
@keyframes fadeUp{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
.sec-h{display:flex;align-items:baseline;justify-content:space-between;gap:10px;flex-wrap:wrap;margin:0 0 8px}
.sec-h h2{font-size:14px;margin:0;text-shadow:1px 1px 0 rgba(255,255,255,.35)}
.sec-h .r{font-size:11.5px;color:var(--wl-muted);display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.blk{margin-bottom:18px}
.blk:last-child{margin-bottom:0}
.dim{color:var(--wl-muted)}
.row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.row label{font-size:12px;color:var(--wl-text-strong);font-weight:700}
.hint{font-size:11.5px;color:var(--wl-muted)}

/* ── 状态砖：大字总量 + 小字分解 + 可选图形 ── */
.bricks{display:grid;grid-template-columns:repeat(auto-fit,minmax(310px,1fr));gap:10px}
.brick{
  background:var(--wl-surface);border:2px solid var(--wl-edge);border-radius:6px;padding:10px 12px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4),2px 2px 0 rgba(0,0,0,.18);
  transition:transform .16s var(--ease),box-shadow .16s var(--ease);
}
.brick:hover{transform:translateY(-2px);box-shadow:inset 0 1px 0 rgba(255,255,255,.4),3px 4px 0 rgba(0,0,0,.2)}
.brick h4{margin:0 0 4px;font-size:11.5px;font-weight:400;color:var(--wl-muted)}
.brick .big{font-family:var(--font-num);font-weight:700;font-size:clamp(18px,1.7vw,22px);color:var(--wl-wood);line-height:1.15;display:block}
.brick .sub{font-size:11px;line-height:1.5;color:var(--wl-muted);margin-top:4px;display:block}
.brick .big.ok{color:var(--wl-green)}
.brick .big.warn{color:var(--wl-warning)}
.brick .big.err{color:var(--wl-danger)}

/* ── 计量卡 ── */
.mgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:10px;margin:9px 0}
.mcard{
  background:var(--wl-surface);border:2px solid var(--wl-edge);border-radius:6px;padding:10px 12px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4),2px 2px 0 rgba(0,0,0,.18);
  transition:transform .16s var(--ease),box-shadow .16s var(--ease);
}
.mcard:hover{transform:translateY(-2px);box-shadow:inset 0 1px 0 rgba(255,255,255,.4),3px 4px 0 rgba(0,0,0,.2)}
.mcard .hd{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;margin-bottom:5px}
.mcard .hd>.tag{flex-shrink:0}
.mcard .nm{font-weight:700;font-size:12.5px;flex:1;min-width:0;line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* 渠道标识（如 workbuddy-native）太长时截断，不要换行把卡片撑乱 */
.mcard .nm em{font-style:normal;font-family:var(--font-num);font-size:11px;color:var(--wl-muted);font-weight:400;margin-left:6px;max-width:120px;display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
.mcard .main{font-family:var(--font-num);font-weight:700;font-size:20px;color:var(--wl-wood);line-height:1.15;display:block}
.mcard .main small{font-family:var(--font-ui);font-size:11px;font-weight:400;color:var(--wl-muted);margin-left:6px}
.mcard .sub2{display:block;margin-top:4px;font-size:11.5px;line-height:1.5;color:var(--wl-muted)}
.mcard .sub2 b{font-family:var(--font-num);font-weight:700;font-size:14px;color:var(--wl-text);margin:0 5px 0 2px}
.mcard .sub2 em{font-style:normal;font-size:11px;color:var(--wl-muted);display:inline}
/* 「累计」那一行：与上面「本区间」的用量区分开 —— 加一条细线，并且数字稍微收一点。
   不加区分的话两行大字挨在一起，会被读成「同一个量的两个数」，反而更乱。 */
.mcard .sub2.all{margin-top:6px;padding-top:6px;border-top:1px dashed var(--wl-sep)}
.mcard .sub2.all b{font-size:13px;color:var(--wl-text-strong)}
/* 「无 token 明细」标记：旧代理日志重建出来的调用没有 token 与费用，
   卡片上的 Token 与费用因此偏低。必须显眼 —— 否则会被读成「真的没花钱」。 */
.notok{display:inline-block;margin-left:6px;font-size:10px;font-weight:700;
  font-family:var(--font-ui);vertical-align:1px;cursor:help;
  color:#6d4a17;background:rgba(161,130,53,.28);border:1px solid #8a6e2c;
  border-radius:2px;padding:0 4px}
/* 同一行里嵌在数字列后面的版本（按天表用） */
td .notok{margin-left:5px;vertical-align:0}
.mcard .kv{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:3px 26px;margin-top:7px;padding-top:7px;
  border-top:1px dashed var(--wl-sep);font-size:11.5px;color:var(--wl-text-strong);
}
.mcard .kv span{display:flex;justify-content:space-between;white-space:nowrap}
.mcard .kv b{flex-shrink:0;white-space:nowrap;font-family:var(--font-num);font-weight:700;color:var(--wl-text);margin-left:6px}
.mcard .ft{
  display:flex;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-top:6px;padding-top:6px;
  border-top:1px dashed var(--wl-sep);font-size:11px;color:var(--wl-muted);
}
.mcard .ft b{font-family:var(--font-num);color:var(--wl-text)}
.mcard .acts{margin-top:7px;padding-top:7px;border-top:1px dashed var(--wl-sep);display:flex;gap:6px;flex-wrap:wrap}

.bar{
  height:9px;background:rgba(129,126,112,.4);border:1px solid var(--wl-slot-dark);border-radius:2px;
  margin-top:7px;overflow:hidden;box-shadow:inset 0 1px 2px rgba(0,0,0,.25);
}
.bar i{
  display:block;height:100%;width:0;
  background:repeating-linear-gradient(90deg,#627d36 0,#627d36 4px,#789a48 4px,#789a48 8px);
  transition:width .5s var(--ease);
}
.bar.warn i{background:repeating-linear-gradient(90deg,#80691f 0,#80691f 4px,#a18235 4px,#a18235 8px)}
.bar.err i{background:repeating-linear-gradient(90deg,#8b3d2e 0,#8b3d2e 4px,#a04b3a 4px,#a04b3a 8px)}
.sbar{
  display:flex;height:10px;border:1px solid var(--wl-slot-dark);border-radius:2px;overflow:hidden;
  background:rgba(129,126,112,.3);margin-top:6px;box-shadow:inset 0 1px 2px rgba(0,0,0,.22);
}
.sbar i{display:block;height:100%;transition:width .5s var(--ease)}
.sbar i:hover{filter:brightness(1.12)}

/* ── 图表 ── */
/* 左右两列顶部对齐：两边的说明文字要在同一条水平线上，否则读起来像两块不相干的内容 */
.chart-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:16px;align-items:start}
/* 列内纵向居中：说明 / 图 / 图例共用同一个中心线 */
.chart-box{display:flex;flex-direction:column;align-items:center}
.chart-box .lg{margin-top:8px;align-self:stretch}
/* 图表说明：标明这张图是哪个维度，避免左右两张图维度不同却看不出 */
.cap{font-size:11.5px;color:var(--wl-muted);margin-bottom:7px;letter-spacing:.2px;text-align:center}
.chart-row>div:not(.chart-box)>.cap{text-align:left}
.cap b{font-family:var(--font-num);font-weight:700;color:var(--wl-text-strong)}
.gaugewrap{margin-top:2px;display:flex;justify-content:center}
.legend{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:6px;font-size:11.5px;color:var(--wl-muted)}
.legend span b{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:5px;vertical-align:middle}
.legend2{display:flex;flex-direction:column}
.legend2 span{display:flex;align-items:center;font-size:11.5px;margin-bottom:5px;color:var(--wl-text-strong);min-width:0}
.legend2 span>span,.legend2 .lg-nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.legend2 b{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:7px;flex-shrink:0}
.legend2 em{font-style:normal;margin-left:auto;font-family:var(--font-num);font-weight:700;padding-left:12px}
/* 明文密钥行：等宽、可换行、带一点底，方便核对与选中复制 */
.keyline{display:flex;align-items:center;gap:8px;margin:6px 0 2px}
.keyline code{flex:1;min-width:0;font-family:var(--font-num);font-size:12.5px;font-weight:700;
  color:var(--wl-text-strong);background:rgba(242,237,223,.62);border:2px solid var(--wl-edge);
  border-radius:5px;padding:4px 8px;word-break:break-all;user-select:all;line-height:1.35}
.keyline .btn{flex-shrink:0}
.hbars{margin:2px 0}
.hbar{display:flex;align-items:center;gap:8px;margin-bottom:5px}
.hbar .hl{width:clamp(120px,22%,230px);flex-shrink:0;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hbar .ht{
  flex:1;height:15px;background:rgba(129,126,112,.34);border:1px solid var(--wl-slot-dark);border-radius:2px;
  overflow:hidden;box-shadow:inset 0 1px 2px rgba(0,0,0,.22);
}
.hbar .ht i{display:block;height:100%;width:0;transition:width .6s var(--ease)}
.hbar .hv{width:104px;flex-shrink:0;text-align:right;font-family:var(--font-num);font-weight:700;font-size:11.5px}
.hbar:hover .ht{box-shadow:inset 0 1px 2px rgba(0,0,0,.22),0 0 0 2px rgba(161,130,53,.35)}
svg.chart{display:block}

/* ── 表格 ── */
.tw{
  overflow:auto;border:2px solid var(--wl-edge);border-radius:6px;background:rgba(222,215,196,.5);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3);
}
table{width:100%;border-collapse:collapse;font-size:12.5px;min-width:560px;table-layout:auto}
th,td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--wl-sep);vertical-align:middle}
th{
  background:rgba(129,126,112,.3);font-weight:700;font-size:11.5px;letter-spacing:.03em;
  border-bottom:2px solid rgba(73,73,64,.4);white-space:nowrap;position:sticky;top:0;z-index:1;
}
tbody tr{transition:background .12s var(--ease)}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover{background:rgba(242,237,223,.55)}
td.n{font-family:var(--font-num);font-weight:700;text-align:right;white-space:nowrap}
td.c{text-align:center}

/* ── 徽章 / 状态点 ── */
.tag{
  display:inline-block;font-size:11px;font-weight:700;padding:1px 7px;border-radius:2px;
  border:2px solid rgba(0,0,0,.28);white-space:nowrap;
}
.tag.ok{background:var(--ok-bg);color:var(--ok-tx)}
.tag.warn{background:var(--warn-bg);color:var(--warn-tx)}
.tag.err{background:var(--err-bg);color:var(--err-tx)}
.tag.grey{background:var(--wl-slot-dark);color:#ece7da}
.tag.gold{background:#7a6326;color:#f4ecd4}
.dot{display:inline-block;width:8px;height:8px;border-radius:50%;vertical-align:middle;margin-right:6px;flex-shrink:0}
.dot.ok{background:var(--wl-green);box-shadow:0 0 0 3px rgba(98,125,54,.16)}
.dot.warn{background:var(--wl-gold);box-shadow:0 0 0 3px rgba(161,130,53,.16)}
.dot.err{background:var(--wl-danger);box-shadow:0 0 0 3px rgba(139,61,46,.18);animation:pulse 1.6s ease-in-out infinite}
/* 静止的红点：表示「没在用 / 空闲」。
   ⚠ 不能用 .dot.err —— 那个带 pulse 闪烁，语义是「出故障了」。
     一屏几十个闲置的 Key 全在闪红，看着像整个网关坏了。 */
.dot.off{background:var(--wl-danger);box-shadow:0 0 0 3px rgba(139,61,46,.10)}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.55}}

/* ── 按钮（§6）── */
.btn{
  font-size:12.5px;line-height:1;font-family:var(--font-ui);font-weight:700;color:#f2eddf;
  background:linear-gradient(180deg,var(--wl-panel-deep),#82806f);
  border:2px solid var(--wl-border);border-radius:6px;padding:6px 12px;cursor:pointer;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32),3px 3px 0 rgba(0,0,0,.26);
  text-shadow:1px 1px 0 rgba(0,0,0,.4);
  transition:background .16s var(--ease),transform .1s var(--ease),box-shadow .16s var(--ease);
}
.btn:hover{background:linear-gradient(180deg,#aaa798,#8d8a79)}
.btn:active{transform:translate(1px,1px);box-shadow:inset 0 1px 0 rgba(255,255,255,.32),2px 2px 0 rgba(0,0,0,.26)}
.btn.primary{border-radius:4px;background:linear-gradient(180deg,#789a48,#5c7733)}
.btn.primary:hover{background:linear-gradient(180deg,#84a852,#637f37)}
.btn.danger{background:linear-gradient(180deg,#a04b3a,#7c3527)}
.btn.danger:hover{background:linear-gradient(180deg,#ad5541,#8a3b2c)}
.btn.mini{font-size:11px;padding:3px 8px;border-radius:2px}
.btn[disabled]{opacity:.45;cursor:not-allowed;transform:none}
.btn.busy{opacity:.7;cursor:progress}

/* ── 输入 ── */
.inp,.sel,textarea.inp{
  font-size:12.5px;line-height:1.4;font-family:var(--font-ui);color:var(--wl-text);
  background:rgba(129,126,112,.34);border:2px solid var(--wl-slot-dark);border-radius:3px;
  padding:5px 8px;box-shadow:inset 0 1px 3px rgba(0,0,0,.22);
  transition:background .15s var(--ease),border-color .15s var(--ease);
}
.inp::placeholder{color:#6b6a5e;opacity:1}
.inp:focus,.sel:focus{background:rgba(242,237,223,.7);border-color:var(--wl-gold)}
.inp.w100{width:100px}.inp.w160{width:160px}.inp.w220{width:220px}.inp.w360{width:360px}
.inp.wfull{width:100%}
textarea.inp{width:100%;min-height:62px;resize:vertical;font-family:var(--font-num)}

/* ── 拉杆（§6：38×20 轨道 + 13px 滑块，小控件 3px 圆角）── */
.lever{
  width:38px;height:20px;border-radius:3px;background:#8f8b7d;border:2px solid var(--wl-border);
  position:relative;display:inline-block;cursor:pointer;vertical-align:middle;flex-shrink:0;
  transition:background .18s var(--ease);
}
.lever i{
  position:absolute;top:1px;left:1px;width:13px;height:13px;border-radius:2px;background:#e6e1d1;
  border:1px solid rgba(0,0,0,.4);transition:left .18s var(--ease);
}
.lever.on{background:var(--wl-green)}
.lever.on i{left:19px}
.lever.dis{opacity:.45;cursor:not-allowed}

/* ── 日志 ── */
.log{
  background:rgba(222,215,196,.5);border:2px solid var(--wl-edge);border-radius:6px;padding:8px 10px;
  max-height:260px;overflow:auto;font-size:12.5px;line-height:1.6;
}
/* 底部渐隐：内容比框高时，最后一行会被截在半途，看着像排版坏了。
   用一条吸底的渐变把它盖住，读起来就知道「下面还有，滚一下」而不是「这里断了」。
   滚到底时它会回到内容末尾，不会挡住最后一行。 */
.log::after{
  content:'';display:block;position:sticky;bottom:-8px;height:18px;margin:0 -10px -8px;
  background:linear-gradient(to bottom,rgba(222,215,196,0),rgba(222,215,196,.92));
  pointer-events:none;
}
.log div{padding:2px 4px;border-bottom:1px dashed var(--wl-sep);word-break:break-all;border-radius:2px;transition:background .12s var(--ease)}
.log div:last-child{border-bottom:0}
.log div:hover{background:rgba(242,237,223,.6)}
.log .t{font-family:var(--font-num);color:var(--wl-muted);margin-right:8px;font-size:11.5px}
.log .lv{font-weight:700;margin-right:6px}
.log .lv.ok{color:#41581f}.log .lv.warn{color:#6b5a1d}.log .lv.err{color:#7a4034}.log .lv.info{color:var(--wl-muted)}

/* ── 提示 ── */
.note{
  background:rgba(242,237,223,.62);border:2px solid #8a8574;border-left:6px solid var(--wl-gold);
  border-radius:6px;padding:8px 12px;font-size:12.5px;box-shadow:inset 0 1px 0 rgba(255,255,255,.4);
}
.note.danger{border-left-color:var(--wl-danger)}
.note.ok{border-left-color:var(--wl-green)}
.note+.note{margin-top:8px}

/* ── 弹层 ── */
.mask{
  position:fixed;inset:0;background:rgba(20,18,14,.62);backdrop-filter:blur(2px);
  display:flex;align-items:center;justify-content:center;z-index:50;padding:20px;
  animation:maskIn .16s var(--ease);
}
@keyframes maskIn{from{opacity:0}to{opacity:1}}
.modal{
  width:min(560px,100%);max-height:88vh;overflow:auto;
  background:linear-gradient(180deg,#b5b1a2,var(--wl-panel));
  border:3px solid var(--wl-border);border-radius:14px;padding:16px 18px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35),6px 6px 0 rgba(0,0,0,.3);
  animation:modalIn .2s var(--ease);
}
@keyframes modalIn{from{opacity:0;transform:translateY(10px) scale(.985)}to{opacity:1;transform:none}}
.modal.wide{width:min(720px,100%)}
.modal h3{margin:0 0 4px;font-size:15px}
.modal p{margin:6px 0;font-size:12.5px;color:var(--wl-text-strong)}
.modal .foot{display:flex;justify-content:flex-end;gap:8px;margin-top:14px}
.keybox{
  font-family:var(--font-num);font-weight:700;font-size:14px;background:rgba(129,126,112,.34);
  border:2px solid var(--wl-slot-dark);border-radius:3px;padding:9px 11px;margin:8px 0;
  word-break:break-all;box-shadow:inset 0 1px 3px rgba(0,0,0,.22);
}

/* ── 回执 ── */
.toast{
  position:fixed;left:50%;bottom:38px;transform:translateX(-50%);z-index:60;
  background:rgba(30,28,22,.94);color:#f2eddf;font-weight:700;font-size:13px;padding:9px 20px;
  border:2px solid var(--wl-border);border-radius:6px;max-width:80%;
  opacity:0;pointer-events:none;transition:opacity .2s var(--ease),transform .2s var(--ease);
}
.toast.on{opacity:1;transform:translateX(-50%) translateY(-4px)}
.toast.ok{color:#c8e0a4}.toast.warn{color:#f0d98c}.toast.err{color:#f0a898}

/* ── 空态 / 骨架屏 ── */
.empty{padding:16px;text-align:center;color:var(--wl-muted);font-size:12.5px}
.skel{
  background:linear-gradient(90deg,rgba(129,126,112,.22) 25%,rgba(129,126,112,.36) 37%,rgba(129,126,112,.22) 63%);
  background-size:400% 100%;animation:skel 1.3s ease-in-out infinite;border-radius:4px;height:12px;margin:6px 0;
}
@keyframes skel{0%{background-position:100% 50%}100%{background-position:0 50%}}

footer{
  position:relative;z-index:2;padding:10px 20px 14px;border-top:2px solid rgba(73,73,64,.3);
  font-size:11.5px;color:var(--wl-muted);display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;
}

/* ══════════════════════════════════════════════════════════════════════════
   移动端适配
   ══════════════════════════════════════════════════════════════════════════
   ⚠ 核心坑：`grid-template-columns:repeat(N,1fr)` 里的 `1fr` **最小值是 auto**，
     也就是「轨道不能窄于内容的 min-content 宽度」。
     9 个页签在 390px 的手机上，每个轨道只有 ~40px，而四个汉字的页签名就要 52px ——
     轨道撑不开就**把整个网格顶宽**，于是页面比屏幕宽、右侧被切掉。
     解法：写成 `minmax(0,1fr)`，把最小值钉成 0，轨道才肯收缩。
     下面所有窄屏规则都遵守这条。
   ══════════════════════════════════════════════════════════════════════════ */

/* 平板 / 窄窗口 */
@media (max-width:980px){
  .tabs{grid-template-columns:repeat(5,minmax(0,1fr))}
  .chart-row{grid-template-columns:minmax(0,1fr)}
  .chart-row .chart-box{justify-self:center}
  .mgrid{grid-template-columns:repeat(auto-fill,minmax(280px,1fr))}
}

/* 手机 */
@media (max-width:680px){
  /* 页签：9 个横排挤不下，改成**横向滑动**的一行（比缩成 3 列好认、也好点）。
     ⚠ 父级要能横向滚，子项要 flex:0 0 auto 不收缩，否则还是会被压扁。 */
  .tabs{
    display:flex;flex-wrap:nowrap;overflow-x:auto;gap:6px;
    padding:7px 12px;-webkit-overflow-scrolling:touch;
    scrollbar-width:none;
  }
  .tabs::-webkit-scrollbar{height:0}
  .tabs .tab{flex:0 0 auto;white-space:nowrap;padding:7px 12px;font-size:12.5px}
  .tabs.tabs3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr))}

  .body{padding:12px 12px 20px;min-height:0}
  .topbar{padding:9px 12px;gap:8px;min-height:0}
  .topbar h1{font-size:14px}
  .tb-r{gap:6px}
  .frame{border-radius:10px}
  .frame::before{border-radius:8px}

  /* 卡片网格一律降到一列 —— 手机上两列会把字挤到换行 */
  .mgrid{grid-template-columns:minmax(0,1fr)}
  .bricks{grid-template-columns:minmax(0,1fr)}
  .mcard .kv{grid-template-columns:minmax(0,1fr)}
  .legend{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:2px 8px}
  .hbar .hl{width:110px}

  /* 弹层：留够边距、按钮竖排（窄屏横排会挤成一团） */
  .mask{padding:10px}
  .modal{max-height:calc(100vh - 20px);padding:16px 14px}
  .modal .foot{flex-wrap:wrap;justify-content:stretch}
  .modal .foot .btn{flex:1 1 auto;justify-content:center}
  .modal .opts.two{grid-template-columns:minmax(0,1fr)}

  /* 表格：允许横向滚，别把页面顶宽 */
  .tw{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .tw table{min-width:520px}

  /* 点按区域：手机上按钮别小于 40px 高，手指点不准 */
  .btn{min-height:38px}
  .btn.mini{min-height:32px}
}

/* 小屏手机（iPhone SE 一类） */
@media (max-width:420px){
  .tabs .tab{padding:6px 10px;font-size:12px}
  .body{padding:10px 10px 18px}
  .sec-h h2{font-size:13.5px}
  .sec-h .r{font-size:11px}
  .mcard{padding:11px 12px}
  .row{flex-wrap:wrap}
  .row .inp.w220{width:100%}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
}

/* 「查管理卡片」跳过来时高亮的那张卡 —— 光有滚动还不够，得让人一眼看出是哪张 */
.mcard.findhit{border-color:var(--wl-gold);box-shadow:0 0 0 3px rgba(161,130,53,.35),6px 6px 0 rgba(0,0,0,.3)}

/* ══════════════ 全站实时数据带（用户端首屏）══════════════
   服主 2026-09-21 要的：「亮眼」地展示今日全站总调用 / 总 token / 平均耗时 + 首字 / tps。
   做法：一条横向数据带，数字用等宽粗体放大，配一条**缓慢流动的渐变高光**
   （只动背景位置，不引起重排，也不吃 CPU）。
   ⚠ 颜色一律走 --wl-* 变量（规范要求），不写死色值。
   ⚠ 数字用 Courier New 粗体（规范 §3：数值字体）。
   ⚠ 不引任何动画库；用 CSS 关键帧，且只用 transform / background-position（合成层，便宜）。 */
.livestrip {
  margin: 0 0 14px;
  padding: 12px 16px 14px;
  border: 2px solid var(--wl-edge);
  border-radius: 10px;
  background:
    linear-gradient(100deg,
      rgba(98,125,54,.10) 0%,
      rgba(98,125,54,.02) 38%,
      rgba(130,92,56,.10) 62%,
      rgba(98,125,54,.10) 100%);
  background-size: 260% 100%;
  box-shadow: 0 3px 0 var(--wl-slot-dark);
  animation: ls-flow 14s linear infinite;
  overflow: hidden;
  position: relative;
}
/* 缓慢流动的高光 —— 只动 background-position，不触发重排 */
@keyframes ls-flow {
  0%   { background-position:   0% 50%; }
  100% { background-position: 260% 50%; }
}
/* 尊重「减少动态效果」的系统设置 —— 有人晕动效，别硬放 */
@media (prefers-reduced-motion: reduce) {
  .livestrip { animation: none; }
}
.livestrip .ls-hd {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .5px;
  color: var(--wl-text-strong);
  margin-bottom: 10px;
}
.livestrip .ls-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--wl-ok-border, #627d36);
  box-shadow: 0 0 0 0 rgba(98,125,54,.55);
  animation: ls-pulse 2.4s ease-out infinite;
}
@keyframes ls-pulse {
  0%   { box-shadow: 0 0 0 0   rgba(98,125,54,.55); }
  70%  { box-shadow: 0 0 0 7px rgba(98,125,54,0); }
  100% { box-shadow: 0 0 0 0   rgba(98,125,54,0); }
}
.livestrip .ls-time {
  margin-left: auto;
  font-weight: 400;
  color: var(--wl-muted);
  font-size: 11px;
}
.livestrip .ls-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
}
.livestrip .ls-cell {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 6px 10px;
  border-left: 3px solid var(--wl-edge);
  background: rgba(255,255,255,.42);
  border-radius: 6px;
}
.livestrip .ls-k {
  font-size: 11px;
  color: var(--wl-muted);
  letter-spacing: .3px;
}
.livestrip .ls-v {
  font-family: "Courier New", Consolas, monospace;
  font-weight: 700;
  font-size: 22px;
  line-height: 1.15;
  color: var(--wl-text-strong);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* 窄视口：两列，别挤成一团 */
@media (max-width: 720px) {
  .livestrip .ls-grid { grid-template-columns: repeat(2, 1fr); }
  .livestrip .ls-v { font-size: 19px; }
}
