/*
  组件层 · v0.72.0
  ------------------------------------------------------------------
  为什么有这个文件。四张参考图（候选人报告 / 岗位向导 / HR 工作台 / 落地页）
  逐元素对照下来的结论是：**缺的不是框架，是一层同名同义的组件**。此前
  .btn / .card / .badge / .tabs 在 exam_view / landing / portal / cookie-policy
  里各写一份，同一件事四个名字四个值 —— 这才是「看着不统一」的根，与配色无关。

  为什么一律 ui- 前缀。上面那四个裸类名**已被那些页面的内联样式占用**。本文件
  一挂上去就全站生效，用裸名 = 挂上去的瞬间把现有页面外观改掉（那是「改页面」，
  不是「加组件层」）。ui- 是干净命名空间，全仓零占用，因此可以做到
  「只加类名、一个页面 DOM 都不动」。

  标尺。字号只用 --fs-*，圆角只用 --r-*，间距只用 calc(var(--sp-base) * n)，
  阴影只用 --shadow-*，色值只用 tokens.css 里的令牌 —— 与 tokens.css 同一把尺，
  不在这里开第二套。色带第 3 段复用 --ok-line，第 4 段用 --ok，避免为了四段
  再发明四个新色名。
  ------------------------------------------------------------------
*/

/* 盒模型自带。不依赖外部那条 `*{box-sizing:border-box}` —— 它只活在 admin.html
   的内联样式里，样张页 / 将来别的页没有，实测量出来 .ui-step .ui-dot 会从 24 变 26。
   只列 ui- 命名空间，不写全局 `*`（全局重置正是 preflight 被关掉的原因）。
   v0.72.3：textarea 一并列进来 —— 它的宽度是 100%，漏了盒模型就会比同一行的
   input 多出 2px（左右各一条 border），通栏域比同行域宽出一截。 */
[class^="ui-"],[class*=" ui-"],
.ui-field input,.ui-field select,.ui-field textarea{box-sizing:border-box}

/* ---- 1. 按钮 ---- */
.ui-btn{display:inline-flex;align-items:center;justify-content:center;
  gap:calc(var(--sp-base) * 2);
  font-family:var(--ff-sans);font-size:var(--fs-md);line-height:1.2;font-weight:500;
  padding:calc(var(--sp-base) * 2) calc(var(--sp-base) * 4);
  border:1px solid var(--brand);border-radius:var(--r-sm);
  background:var(--brand);color:#fff;cursor:pointer;text-decoration:none;
  transition:background .15s,border-color .15s,color .15s,box-shadow .15s}
.ui-btn:hover{background:var(--brand-dk);border-color:var(--brand-dk)}
.ui-btn:focus-visible{outline:none;box-shadow:var(--ring)}
.ui-btn.ghost{background:var(--card);color:var(--brand)}
.ui-btn.ghost:hover{background:var(--brand-soft);border-color:var(--brand-line);
  color:var(--brand-dk)}
.ui-btn.pill{border-radius:var(--r-full);
  padding:calc(var(--sp-base) * 2.5) calc(var(--sp-base) * 5)}
.ui-btn.sm{font-size:var(--fs-sm);
  padding:var(--sp-base) calc(var(--sp-base) * 3)}
.ui-btn[disabled]{opacity:.55;cursor:not-allowed}
.ui-btn[disabled]:hover{background:var(--brand);border-color:var(--brand)}

/* ---- 2. 卡片 ---- */
.ui-card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  box-shadow:var(--shadow-1);overflow:hidden}
.ui-card.flat{box-shadow:none}
.ui-card-h{display:flex;align-items:center;justify-content:space-between;
  gap:calc(var(--sp-base) * 2);
  padding:calc(var(--sp-base) * 3) calc(var(--sp-base) * 4);
  border-bottom:1px solid var(--line);
  font-size:var(--fs-lg);font-weight:600;color:var(--text)}
.ui-card-b{padding:calc(var(--sp-base) * 4)}
/* 渐变头：图 3 右栏「AI 评语」那一卡的头部形状 */
.ui-card.gh .ui-card-h{background:linear-gradient(90deg,var(--brand-dk),var(--brand));
  color:#fff;border-bottom-color:transparent}
.ui-card.gh .ui-card-h .ui-badge{background:rgba(255,255,255,.18);color:#fff;
  border-color:rgba(255,255,255,.32)}

/* ---- 3. 徽章 / 标签 ---- */
.ui-badge{display:inline-flex;align-items:center;gap:var(--sp-base);
  font-family:var(--ff-sans);font-size:var(--fs-xs);line-height:1.6;
  padding:calc(var(--sp-base) * 1) calc(var(--sp-base) * 2.5);
  border-radius:var(--r-full);border:1px solid transparent;white-space:nowrap}
.ui-badge.ok{background:var(--ok-soft);color:var(--ok);border-color:var(--ok-line)}
.ui-badge.warn{background:var(--warn-soft);color:var(--warn);border-color:var(--warn-line)}
.ui-badge.bad{background:var(--bad-soft);color:var(--bad);border-color:var(--bad-line)}
.ui-badge.brand{background:var(--brand-soft);color:var(--brand);border-color:var(--brand-line)}
.ui-badge.mute{background:var(--bg);color:var(--muted);border-color:var(--line)}

/* ---- 4. 页签 ---- */
.ui-tabs{display:flex;gap:calc(var(--sp-base) * 5);
  border-bottom:1px solid var(--line);margin-bottom:calc(var(--sp-base) * 4)}
.ui-tabs button{font-family:var(--ff-sans);font-size:var(--fs-md);
  color:var(--muted);background:none;border:0;
  border-bottom:2px solid transparent;
  padding:calc(var(--sp-base) * 2) 0;margin-bottom:-1px;cursor:pointer;
  transition:color .15s,border-color .15s}
.ui-tabs button:hover{color:var(--text)}
.ui-tabs button.on{color:var(--brand);border-bottom-color:var(--brand);font-weight:600}

/* ---- 5. 带图标前缀与「已填」勾的表单域（图 2 的岗位向导）---- */
.ui-field{display:block;position:relative}
.ui-field > .ui-lbl{display:block;font-size:var(--fs-xs);color:var(--muted);
  margin-bottom:calc(var(--sp-base) * 1.5)}
.ui-field > .ui-ctl{position:relative;display:flex;align-items:center}
.ui-field .ui-ico{position:absolute;left:calc(var(--sp-base) * 2.5);
  font-size:var(--fs-lg);line-height:1;color:var(--muted);pointer-events:none}
.ui-field input,.ui-field select{
  width:100%;font-family:var(--ff-sans);font-size:var(--fs-md);color:var(--text);
  background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:calc(var(--sp-base) * 2.5) calc(var(--sp-base) * 10);
  outline:none;appearance:none;
  transition:border-color .15s,box-shadow .15s}
.ui-field input:focus,.ui-field select:focus{border-color:var(--brand);box-shadow:var(--ring)}
.ui-field.ok input,.ui-field.ok select{border-color:var(--ok-line)}
/* 多行域（图 2 第 2 步的 JD）。左内边距与单行域一样留出图标位 —— 不留的话
   通栏域会比它上面的输入框左边缘缩进 30px，一屏之内两个左基线。 */
.ui-field textarea{width:100%;font-family:var(--ff-sans);font-size:var(--fs-md);
  color:var(--text);background:var(--card);border:1px solid var(--line);
  border-radius:var(--r-sm);outline:none;resize:vertical;
  min-height:calc(var(--sp-base) * 22);
  padding:calc(var(--sp-base) * 2.5) calc(var(--sp-base) * 2.5)
          calc(var(--sp-base) * 2.5) calc(var(--sp-base) * 10)}
.ui-field textarea:focus{border-color:var(--brand);box-shadow:var(--ring)}
/* 多行域里的图标要顶对齐。`.ui-ico` 是绝对定位、只有 left，纵向落点由
   .ui-ctl 的 align-items 决定 —— 默认 center 会让它在 88px 高的框里飘到中间，
   而它标注的是**这个框**，不是框的中心。 */
.ui-field.tall .ui-ctl{align-items:flex-start}
.ui-field.tall .ui-ico{top:calc(var(--sp-base) * 2.5);bottom:auto}
/* 下拉箭头：appearance:none 会连原生箭头一起去掉，未填字段就看不出能点。
   用 CSS 三角而不是 data URI —— URI 里没法写 var()，箭头颜色会被硬编码成第二套色板。 */
.ui-field .ui-ctl:has(> select)::after{content:"";position:absolute;
  right:calc(var(--sp-base) * 2.5);pointer-events:none;
  border-left:var(--sp-base) solid transparent;
  border-right:var(--sp-base) solid transparent;
  border-top:calc(var(--sp-base) * 1.25) solid var(--muted)}
/* 勾与箭头同处右侧会叠：勾让到 --sp*8，箭头留在 --sp*2.5。 */
.ui-field .ui-tick{position:absolute;right:calc(var(--sp-base) * 8);
  font-size:var(--fs-sm);line-height:1;color:var(--ok);display:none}
.ui-field.ok .ui-tick{display:block}

/* ---- 6. 分步进度条（图 2 的 Step 1 / 2 / 3 / 4）----
   下边距挂在这里而不是靠外面包一层容器：向导的四个步骤**跨文件**装配
   （1~3 步在命名槽 admin-slots/job-wizard.html、第 4 步在 admin.html），
   开在 A 文件、闭在 B 文件的包裹标签是拼不出来的。 */
.ui-stepper{display:flex;align-items:center;
  margin-bottom:calc(var(--sp-base) * 4)}
.ui-step{display:flex;align-items:center;gap:calc(var(--sp-base) * 2);
  font-family:var(--ff-sans);font-size:var(--fs-sm);color:var(--muted);white-space:nowrap}
.ui-step .ui-dot{display:inline-flex;align-items:center;justify-content:center;
  width:calc(var(--sp-base) * 6);height:calc(var(--sp-base) * 6);
  border-radius:var(--r-circle);border:1px solid var(--line);
  background:var(--card);color:var(--muted);font-size:var(--fs-sm);flex:none}
.ui-step.on{color:var(--brand);font-weight:600}
.ui-step.on .ui-dot{background:var(--brand);border-color:var(--brand);color:#fff}
.ui-step.done .ui-dot{background:var(--brand-soft);border-color:var(--brand-line);
  color:var(--brand)}
.ui-step-line{flex:1;height:1px;background:var(--line);
  margin:0 calc(var(--sp-base) * 2);min-width:calc(var(--sp-base) * 4)}
.ui-step-line.done{background:var(--brand-line)}

/* ---- 7. 分档色带条（图 1 的档位条）----
   五段色从左到右 = 0-t1 / t1-t2 / t2-t3 / t3-t4 / t4-100；得分位置落一颗圆点。
   为什么是**五段**：阈值只有四个（ai_decision_t1..t4），但它们切出的是**五档**
   ——board.py 的分数分布就是按 0/20/40/60/80/100 切五段。上一版按参考图写了
   四段，与真实分档对不上，属于「照图猜」。
   阈值本身由页面决定（报告页从 /health 取，取不到回落 20/40/60/80），
   这里只提供形状与色阶。 */
.ui-band-row{margin-bottom:calc(var(--sp-base) * 4)}
.ui-band-row:last-child{margin-bottom:0}
.ui-band-top{display:flex;align-items:baseline;justify-content:space-between;
  font-size:var(--fs-sm);margin-bottom:var(--sp-base)}
.ui-band-top .ui-band-name{color:var(--text)}
.ui-band-top .ui-band-val{color:var(--muted);font-size:var(--fs-xs)}
.ui-band-bar{position:relative;display:flex;overflow:visible;
  height:calc(var(--sp-base) * 2);border-radius:var(--r-full);background:var(--bg)}
.ui-band-seg{flex:1}
.ui-band-seg:first-child{border-radius:var(--r-full) 0 0 var(--r-full)}
.ui-band-seg:last-child{border-radius:0 var(--r-full) var(--r-full) 0}
/* 段间白线。没有它，四段连成一条会被读成「进度条已完成 3/4」——
   而它表达的是**档位区间**（较差/一般/良好/优秀），不是进度。 */
.ui-band-seg + .ui-band-seg{border-left:1px solid var(--card)}
.ui-band-seg.s1{background:var(--t1)}
.ui-band-seg.s2{background:var(--t2)}
.ui-band-seg.s3{background:var(--t3)}
.ui-band-seg.s4{background:var(--t4)}
.ui-band-seg.s5{background:var(--t5)}
/* 圆点**不带档位色**。它压在某一段的底色上，再染一次色等于同一个档位说两遍，
   而且落在末段（--t5 是实绿）上时红点会被读成「异常标记」。用 --navy + 白环：
   在五段任何一段上都够对比度，且不替页面下结论。 */
.ui-band-mark{position:absolute;top:50%;
  width:calc(var(--sp-base) * 3.5);height:calc(var(--sp-base) * 3.5);
  border:2px solid var(--card);border-radius:var(--r-circle);
  background:var(--navy);transform:translate(-50%,-50%)}
/* 刻度**按百分比绝对定位**，不用 space-between。space-between 均分的是**盒子**
   不是**数值**——"100" 比 "0" 宽，末格会被挤偏，而刻度一旦对不准段界，
   整条带子传达的档位区间就是错的。首尾各贴边，中间居中。 */
.ui-band-scale{position:relative;height:calc(var(--sp-base) * 4);
  font-size:var(--fs-xs);color:var(--muted);margin-top:var(--sp-base)}
.ui-band-scale span{position:absolute;top:0;transform:translateX(-50%);
  white-space:nowrap}
.ui-band-scale span:first-child{transform:none}
.ui-band-scale span:last-child{transform:translateX(-100%)}

/* ---- 8. 指标带（图 3 顶部：一个大数 + 若干副指标 + 右侧动作）---- */
.ui-metrics{display:flex;align-items:flex-end;gap:calc(var(--sp-base) * 8);
  flex-wrap:wrap}
.ui-metric .ui-metric-k{font-size:var(--fs-xs);color:var(--muted)}
.ui-metric .ui-metric-v{font-size:var(--fs-display);font-weight:600;color:var(--text);
  line-height:1.2}
.ui-metric.sub .ui-metric-v{font-size:var(--fs-xl)}
.ui-metric .ui-metric-d{font-size:var(--fs-xs);color:var(--muted);margin-top:var(--sp-base)}

/* ---- 9. 岗位向导外壳（图 2）----
   分步条（.ui-stepper，见第 6 组）自带，这里只给「步骤之间的容器」与「底栏」。
   为什么不复用页面上那套页签（.jb-tabs + .jb-tab）：页签与步骤**语义不同**——
   页签可以任意跳、没有先后，步骤有「第几 / 共几」和「已完成」。同一个外观
   套在两种语义上，改一处就会让另一处说不通（这也正是 .jb-tabs 留在原地、
   供测评中心与面板页签继续用的原因）。 */
.ui-wz-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:calc(var(--sp-base) * 3) calc(var(--sp-base) * 3.5)}
.ui-wz-pane{display:none}
.ui-wz-pane.on{display:block}
.ui-wz-foot{display:flex;align-items:center;gap:calc(var(--sp-base) * 2.5);
  margin-top:calc(var(--sp-base) * 4.5)}
.ui-wz-foot .ui-wz-sp{flex:1}
/* 通栏域：整行铺满，不参与两列网格 */
.ui-field.wide{grid-column:1 / -1}
/* 勾选行（图 2 第 3 / 4 步）。与 .ui-field 是两种东西，不合成一个类：
   前者是「域 + 标签 + 勾」，后者是「一行说明 + 勾选框」。 */
.ui-chk{display:flex;gap:calc(var(--sp-base) * 2);align-items:flex-start;
  margin:calc(var(--sp-base) * 1.75) 0;cursor:pointer;font-size:var(--fs-lg)}
.ui-chk input{margin-top:calc(var(--sp-base) * 0.75);flex:none}
/* 勾选行里的 ✓ 是**行内**的（.ui-field 里的那颗是绝对定位在框右侧的），
   所以同一颗 ✓ 在这里要显式放开定位。显隐由 `input:checked ~` 决定，
   不靠 JS 打类 —— 少一处「勾了却忘了打类」的静默不同步。 */
.ui-chk .ui-tick{position:static;display:none;right:auto;color:var(--ok);
  font-size:var(--fs-sm)}
.ui-chk input:checked ~ .ui-tick{display:inline}
/* 步骤说明 / 边界说明。与页面上的 .sub 分开命名：.sub 是**页面方言**，
   挂在 admin.html 的内联样式上，样张页与将来别的页都没有。 */
.ui-hint{font-size:var(--fs-xs);color:var(--muted);
  margin:0 0 calc(var(--sp-base) * 1.5)}
/* 段标题 / 小号灰标签（不在 .ui-field 里的那种，例如第 3 步的「在线测评」抬头）。
   .ui-field > .ui-lbl 是同一个外观，但它要求父元素是 .ui-field —— 这里不是。 */
.ui-sec{font-size:var(--fs-xs);color:var(--muted);
  margin:0 0 calc(var(--sp-base) * 1.5)}
/* 从属设置行：挂在某个勾选框**下面**，左边缩进到勾选框文字的位置
   （勾选框 4+13+8 = 25px，取 26px）。缩进写在容器上而不是逐个子元素上，
   否则以后往这一行里加东西，一定会漏掉一个没缩进的。 */
.ui-wz-sub{display:flex;align-items:center;gap:calc(var(--sp-base) * 2);
  margin:calc(var(--sp-base) * 0.5) 0 var(--sp-base)
         calc(var(--sp-base) * 6.5)}
.ui-wz-sub .ui-sec,.ui-wz-sub .ui-hint{margin:0}
.ui-hint-in{margin-left:calc(var(--sp-base) * 6.5)}
/* 独立数字框（限时分钟数）。刻意不复用 .ui-field：那一套自带标签位与图标位，
   而这里要的是「跟在一段说明后面的一格数字」。 */
.ui-num{width:calc(var(--sp-base) * 19.5);font-family:var(--ff-sans);
  font-size:var(--fs-md);color:var(--text);background:var(--card);
  border:1px solid var(--line);border-radius:var(--r-sm);
  padding:calc(var(--sp-base) * 1.5) calc(var(--sp-base) * 2);outline:none;
  transition:border-color .15s,box-shadow .15s}
.ui-num:focus{border-color:var(--brand);box-shadow:var(--ring)}

/* 骨架屏原子（v0.75.6）。此前 #dash-skel（admin.html）与 #r-skel（room.html）
   各写了一份同款灰条 + 各自的 @keyframes；新加的三处首屏统一用这一条，
   高度/宽度由调用方行内给（骨架的形状本来就跟那一屏的版式绑定）。
   名字用 sk-i 而不是 .sk-block：room.html 里 .sk-block 已是一个 28px 高的具体形状，
   同名会被那边的规则接走。 */
.sk-i{display:block;height:var(--fs-md);border-radius:var(--r-md);
  background:var(--line);animation:sk-pulse 1.4s ease-in-out infinite}
@keyframes sk-pulse{0%,100%{opacity:.45}50%{opacity:.85}}

/* ===== v0.79.0 题库页：题目卡片 / 批量栏 / 试卷表（mockup） ===== */
.qb-bar{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.qb-batch{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:10px 0;
  padding:8px 10px;background:var(--brand-soft);border:1px solid var(--brand-line);
  border-radius:var(--r-md)}
.qb-sel{font-size:var(--fs-sm);font-weight:600;color:var(--brand)}
.qb-list{display:flex;flex-direction:column;gap:10px;margin-top:10px}
.qb-card{display:flex;gap:10px;padding:12px 14px;border:1px solid var(--line);
  border-radius:var(--r-md);background:var(--card)}
.qb-card > input{margin-top:3px;flex:none}
.qb-main{flex:1;min-width:0}
.qb-badges{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.qb-bd{font-size:var(--fs-xs);padding:1px 7px;border-radius:var(--r-full);
  background:#F2F5F9;color:#4B5563;white-space:nowrap}
.qb-bd-t{background:#E8F1FB;color:#185FA5}
.qb-bd-l{background:#F3F4F6;color:#6B7280}
.qb-bd-tag{background:#FFF4E5;color:#8A5A00}
.qb-bd-d1{background:#E8F6EE;color:#0F6E56}
.qb-bd-d2{background:#FFF6E5;color:#8A5A00}
.qb-bd-d3{background:#FDECEC;color:#B42318}
.qb-score{margin-left:auto;font-weight:600;font-size:var(--fs-md);color:var(--text)}
.qb-stem{margin-top:8px;font-size:var(--fs-md);line-height:1.55;word-break:break-word}
.qb-more{margin-top:8px;padding:8px 10px;background:#FAFBFC;border-radius:var(--r-sm);
  font-size:var(--fs-md);line-height:1.6}
.qb-opt{display:flex;flex-direction:column;gap:3px}
.qb-line{margin-top:6px;color:#374151;white-space:pre-wrap}
.qb-line > span{color:var(--muted);margin-right:6px;font-size:var(--fs-xs)}
.qb-ops{display:flex;gap:6px;margin-top:8px;flex-wrap:wrap}
.qb-mini{padding:2px 9px;font-size:var(--fs-xs)}
/* v0.102.0 表头排序：箭头只出现在**点过的那一列**，没点的列不留空位（用 ::after 而不是
   预置一个空的 span，否则每列都多出一段缩进，表头看着像没对齐）。 */
th[data-sort]{cursor:pointer;user-select:none}
th[data-sort]:hover{color:var(--brand)}
th[data-sort][data-dir="asc"]::after{content:"▲";margin-left:4px;font-size:var(--fs-xs)}
th[data-sort][data-dir="desc"]::after{content:"▼";margin-left:4px;font-size:var(--fs-xs)}
/* v0.99.0 题目页工具条：全选本页 / 结果提示 / 失败重试。放在列表之上单独一行，
   而不是塞进筛选行——筛选行已经有六个控件，再挤一个就分不清「筛」和「选」。 */
.qb-tools{display:flex;align-items:center;gap:10px;margin:8px 0;flex-wrap:wrap}
.qb-allf{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-sm);
  color:var(--muted);cursor:pointer;white-space:nowrap}
.qb-allf input{margin:0;cursor:pointer}
/* v0.99.0 自定义报表的导出区 */
.an-acts{display:flex;align-items:center;gap:10px;margin:8px 0 2px;flex-wrap:wrap}
/* ===== v0.88.0 题库：职业方向 / 重点题 / 评分标准 ===== */
/* 方向刻意与题型（蓝）、标签（橙）用不同色相：三个都在同一行，颜色撞了
   等于没有分类。靛蓝 #3730A3 与题型蓝 #185FA5 在小字号下也能分开。 */
.qb-bd-cat{background:#EEF2FF;color:#3730A3}
/* v0.98.0 批次标：刻意用最低调的一档灰，它是溯源信息，不该比方向/难度更抢眼 */
.qb-bd-b{background:#F1F5F9;color:#475569;font-variant-numeric:tabular-nums}
/* 重点题：两种状态共用一个按钮（★ 实心=已标 / ☆ 空心=未标），
   不做「加重点」「取消重点」两个按钮——两个按钮在一行里认不出哪个是当前态。 */
.qb-star{border:none;cursor:pointer;font-weight:600;background:#F3F4F6;color:#9CA3AF}
.qb-star.on{background:#FFF7DA;color:#8A5A00}
.qb-star:hover{filter:brightness(.97)}
/* 分值本来就靠 auto margin 右推；加了星标之后要把「星标 + 分值」当一个整体
   右推，否则星标会留在标签堆里、和分数隔着一整行空白。 */
.qb-right{margin-left:auto;display:flex;gap:6px;align-items:center}
.qb-right .qb-score{margin-left:0}
.qb-rub{margin-top:6px}
.qb-rub-row{display:flex;gap:8px;align-items:baseline;margin-top:3px;color:#374151}
.qb-rub-s{flex:none;min-width:16px;font-weight:600;color:var(--brand)}

/* ===== v0.89.0 后台三表：用户头像 / 角色下拉 / 权限开关 ===== */
/* 用户头像（图 2）：**没有上传功能**，用姓名首字母 + 按 id 取色的圆块。
   加这一列不是为了好看——纯文字邮箱扫一长列时没有视觉锚点，找一个人要逐行读。
   五个色相按 id 取模，同一个人每次刷新颜色稳定（不是随机的）。 */
.u-av{display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:30px;height:30px;border-radius:var(--r-full);font-size:var(--fs-sm);
  font-weight:600;color:#fff;background:#5B7FB0;text-transform:uppercase}
.u-av.a1{background:#4F7CC4}
.u-av.a2{background:#3F9D8A}
.u-av.a3{background:#B27B2E}
.u-av.a4{background:#8A6BB5}
.u-av.a5{background:#B4553F}
.u-cell{display:flex;align-items:center;gap:8px;min-width:0}
.u-cell > div{min-width:0}
.u-cell .u-mail{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:176px}
/* 角色下拉（图 2）：外观是 chip，点开是原生 select —— 不引组件库，
   键盘/触屏/读屏全都由浏览器自己保证。 */
.role-sel{border:1px solid var(--line);border-radius:var(--r-full);
  padding:1px 6px;font-size:var(--fs-sm);background:var(--card);cursor:pointer;
  max-width:124px}
/* 权限开关（图 6）：checked 时滑块右移 + 底色换品牌色。
   状态只有 PERMS[i].allowed 一份，靠 input 的 :checked 驱动外观，
   不另存一份 DOM 状态——两份状态迟早不同步。 */
.ui-sw{position:relative;display:inline-block;width:38px;height:20px;
  flex:none;vertical-align:middle}
.ui-sw input{position:absolute;opacity:0;width:0;height:0}
.ui-sw i{position:absolute;inset:0;background:#CFD6DF;border-radius:var(--r-full);
  transition:background .15s;cursor:pointer}
.ui-sw i:before{content:"";position:absolute;left:2px;top:2px;width:16px;height:16px;
  background:#fff;border-radius:var(--r-full);transition:transform .15s;
  box-shadow:0 1px 2px rgba(0,0,0,.18)}
.ui-sw input:checked + i{background:var(--brand)}
.ui-sw input:checked + i:before{transform:translateX(18px)}
.ui-sw input:focus-visible + i{outline:2px solid var(--brand-line);outline-offset:2px}
/* 面试官徽章：其余四个角色的配色在 admin.html 里，这里补最后一个空档，
   放在 ui.css 是因为新页面（面试页日历）也要用同一套。 */
.r-interviewer{color:#0F6E56;border-color:#B7E4D2;background:#E8F6F0}

/* ===== v0.90.0 面试周历 ===== */
.ivcal{display:flex;flex-direction:column;gap:12px;margin-top:12px}
.ivcal-hd{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ivcal-range{font-size:var(--fs-md);font-variant-numeric:tabular-nums}
.ivcal-sp{flex:1}
.ivcal-nav{padding:2px 10px;line-height:1.6}
/* 7 列均分：内容列约 830px ⇒ 每列约 113px。minmax(0,1fr) 而不是
   minmax(120px,1fr)——后者总和超过容器，日历会被迫横向滚动。 */
.ivcal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px}
.ivc-col{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:8px;min-height:150px;display:flex;flex-direction:column;gap:6px;min-width:0}
.ivc-col.today{border-color:var(--brand-line);box-shadow:inset 0 0 0 1px var(--brand-line)}
/* v0.100.0 拖拽改期：拖到哪一列，哪一列整体亮起。只改边框与底色，不动尺寸——
   尺寸一变列会抖，拖着的那块就跟着跳，落点判断就废了。 */
.ivc-col.drag-over{border-color:var(--brand);background:var(--brand-soft)}
.ivc-ev[draggable="true"]{cursor:grab}
.ivc-ev[draggable="true"]:active{cursor:grabbing}
.ivc-col-h{display:flex;justify-content:space-between;align-items:baseline;gap:4px;
  font-size:var(--fs-xs);color:var(--muted);padding-bottom:4px;
  border-bottom:1px solid var(--line);white-space:nowrap}
.ivc-col-h b{font-size:var(--fs-sm);color:var(--text)}
.ivc-ev{font-size:var(--fs-xs);line-height:1.45;padding:5px 7px;border-radius:var(--r-sm);
  background:#F4F8FC;border-left:3px solid #185FA5;cursor:pointer;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ivc-ev:hover{filter:brightness(.97)}
.ivc-ev b{font-variant-numeric:tabular-nums;margin-right:3px}
.ivc-ev span{display:block;color:var(--muted);overflow:hidden;text-overflow:ellipsis}
.ivc-ev .ivc-itor{color:#6B4EAF}
.ivc-ev.s-done{background:#E8F6F0;border-left-color:#0F6E56}
.ivc-ev.s-cancelled{background:#FCECEC;border-left-color:#A32D2D;opacity:.75}
.ivc-ev.s-pending{background:#FFF6E5;border-left-color:#C98A0B}
.ivc-none{color:var(--muted);font-size:var(--fs-xs);text-align:center;padding:8px 0}
.ivcal-foot{display:grid;grid-template-columns:220px minmax(0,1fr);gap:12px;align-items:start}
.ivcal-side,.ivcal-up{background:var(--card);border:1px solid var(--line);
  border-radius:var(--r-md);padding:10px 12px;min-width:0}
.ivcal-side-h{font-size:var(--fs-xs);color:var(--muted);font-weight:600;margin-bottom:6px}
.ivc-loadrow{display:flex;justify-content:space-between;align-items:center;gap:8px;
  font-size:var(--fs-sm);padding:4px 0;border-bottom:1px dashed var(--line)}
.ivc-loadrow:last-child{border-bottom:none}
.ivc-loadrow span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ivc-loadrow b{font-variant-numeric:tabular-nums;flex:none}
.ivc-uprow{display:flex;gap:10px;align-items:baseline;font-size:var(--fs-sm);
  padding:6px 0;border-bottom:1px dashed var(--line);cursor:pointer;min-width:0}
.ivc-uprow:last-child{border-bottom:none}
.ivc-uprow:hover{color:var(--brand)}
.ivc-upt{font-variant-numeric:tabular-nums;color:var(--muted);flex:none;min-width:86px}
.ivc-uprow > span:nth-child(2){flex:none;max-width:140px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.ivc-uprow .sub{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width:1100px){
  .ivcal-foot{grid-template-columns:1fr}
}

/* ===== v0.90.0 人才库统计卡 ===== */
/* 三张卡**不受筛选影响**（后端回的是全池口径）：跟着搜索变会让同一页
   出现「共 12 人」和「池内总数 3」两个互相打架的数字。 */
.tp-stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;
  margin:12px 0}
.tp-stat{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:10px 14px;display:flex;flex-direction:column;gap:2px;min-width:0}
.tp-stat-k{font-size:var(--fs-xs);color:var(--muted)}
.tp-stat b{font-size:var(--fs-display);line-height:1.2;font-variant-numeric:tabular-nums}
.tp-stat-s{font-size:var(--fs-xs);color:var(--muted)}
@media (max-width:760px){
  .tp-stats{grid-template-columns:1fr}
}
/* 角色徽章不折行：「平台运营方」在 7% 宽的列里会一字一行竖排成五层。 */
.role-chip{white-space:nowrap}
/* 操作列按钮组：横排而不是竖排。
   竖排的后果是每行被三个按钮顶到 130px 高——一屏只能看 4 个人，
   而这一页的用法正是「一屏扫完、挑人要授权」。放不下时折成两行，
   也比一路竖到底好读。 */
.u-ops{display:flex;gap:6px;flex-wrap:nowrap;align-items:center}
/* 按钮缩到 xs 字号 + 窄内边距：三个按钮在 28% 列宽里放得下才谈得上横排。
   11px 是表格里的工具按钮，不是主操作按钮——主操作在页头「创建账号」那里。 */
.u-ops button{margin:0;white-space:nowrap;font-size:var(--fs-xs);padding:2px 8px}
.u-name{white-space:nowrap}
/* 用户表用 fixed 布局：auto 下邮箱一长，整表就超容器、最右侧按钮被裁掉。
   fixed 之后表头的百分比才是权威值（与超管组织表 v0.52.1 同一条教训）。 */
.u-table{table-layout:fixed;width:100%}
.u-table th,.u-table td{overflow-wrap:normal}
/* 日志表同样用 fixed：详情列会被「admin@demo.com 退出登录（平台超管）」这种
   长句撑宽，auto 布局下整表超容器、最右侧被无声裁掉。 */
.log-table{table-layout:fixed;width:100%}
/* break-word 而不是 anywhere：anywhere 会把 `#9902` 断成 `#990`+`2`（真机截图），
   break-word 只在「整个词放不下」时才断，短编号就不会被劈开。 */
.log-table td{overflow-wrap:break-word}
/* 邮箱在自己的列里自适应：fixed 布局下列宽已经是权威值，
   再挂一个 176px 上限会让它提前截断。 */
.u-cell .u-mail{max-width:100%}
.qb-page{display:flex;gap:10px;align-items:center;margin-top:12px;font-size:var(--fs-sm)}
.qb-ptable{margin-top:10px;border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden}
.qb-prow{display:grid;grid-template-columns:minmax(0,1.8fr) 56px 72px minmax(0,1fr) 74px minmax(0,2.2fr);
  gap:8px;padding:10px 12px;border-bottom:1px solid var(--line);align-items:center;
  font-size:var(--fs-md)}
.qb-prow:last-child{border-bottom:none}
.qb-phead{background:#F7F9FC;color:var(--muted);font-size:var(--fs-xs)}
.qb-pn{min-width:0;font-weight:600;word-break:break-word}
.qb-pn .sub{margin:2px 0 0;font-weight:400}
.qb-st{font-style:normal;font-size:var(--fs-xs);padding:1px 7px;border-radius:var(--r-full);
  background:#F3F4F6;color:#6B7280;white-space:nowrap}
.qb-st.on{background:#E8F6EE;color:#0F6E56}
.qb-pops{display:flex;gap:4px;flex-wrap:wrap}
.qb-pdetail{grid-column:1 / -1;background:#FAFBFC;border-radius:var(--r-sm);padding:10px}
.qb-pform{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:8px}
.qb-pitems{display:flex;flex-direction:column;gap:6px}
.qb-pq{border-top:1px dashed var(--line);padding-top:6px}
.qb-pempty{padding:16px;color:var(--muted);font-size:var(--fs-md)}
/* v0.98.0 入库批次表：列宽与试卷表不同（时间是长串、操作只有一颗按钮），
   所以另起一组而不是复用 .qb-prow——把时间塞进 56px 会折成两行。 */
.qb-btable{margin-top:10px;border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden}
.qb-brow{display:grid;grid-template-columns:62px minmax(0,1.15fr) 58px minmax(0,1fr) minmax(0,1.7fr) 126px;
  gap:8px;padding:10px 12px;border-bottom:1px solid var(--line);align-items:center;
  font-size:var(--fs-md)}
.qb-brow:last-child{border-bottom:none}
.qb-bno{font-weight:600;font-variant-numeric:tabular-nums}
.qb-btime{min-width:0;color:var(--muted);font-size:var(--fs-sm)}
@media(max-width:900px){
  .qb-prow{grid-template-columns:1fr 1fr;row-gap:4px}
  .qb-phead{display:none}
  .qb-pops{grid-column:1 / -1}
  .qb-brow{grid-template-columns:1fr 1fr;row-gap:4px}
}

/* ---- AI 起草 JD（v0.84.0，岗位向导第 2 步） ----
   面板刻意用 brand-soft 而不是白卡：它是**草稿**，不是已保存内容；
   与下方 textarea 里的正文视觉上要能分开，否则 HR 会以为已经填进去了。 */
.ui-jd-rb{margin-left:calc(var(--sp-base) * 2)}
.ui-jd-panel{margin-top:calc(var(--sp-base) * 2);
  border:1px solid var(--brand-line);border-radius:var(--r-md);
  background:var(--brand-soft);padding:calc(var(--sp-base) * 4)}
.ui-jd-sum{margin:0 0 calc(var(--sp-base) * 3);
  font-size:var(--fs-md);color:var(--text)}
.ui-jd-g + .ui-jd-g{margin-top:calc(var(--sp-base) * 3)}
.ui-jd-h{font-size:var(--fs-xs);color:var(--muted);margin-bottom:var(--sp-base)}
.ui-jd-list{margin:0;padding-left:calc(var(--sp-base) * 5);
  font-size:var(--fs-sm);color:var(--text);line-height:1.65}
.ui-jd-list li + li{margin-top:var(--sp-base)}
.ui-jd-foot{display:flex;align-items:center;gap:calc(var(--sp-base) * 2);
  margin-top:calc(var(--sp-base) * 4);flex-wrap:wrap}
.ui-jd-warn{color:var(--warn);margin-top:calc(var(--sp-base) * 2)}

/* ---- 人才库「按岗位推荐」的匹配徽章（v0.84.0） ----
   分数放左边一颗药丸、理由跟在右边：HR 扫列表时先看分，想追问再看理由。
   不把理由折进 tooltip —— 移动端没有 hover，「为什么推荐他」就永远看不到。 */
.tp-mrow{display:flex;align-items:center;gap:calc(var(--sp-base) * 2);
  margin-top:var(--sp-base);flex-wrap:wrap}
.tp-mscore{display:inline-flex;align-items:center;justify-content:center;
  min-width:calc(var(--sp-base) * 10);padding:0 calc(var(--sp-base) * 1.5);
  font-size:var(--fs-xs);font-weight:600;line-height:1.8;color:var(--brand-dk);
  background:var(--card);border:1px solid var(--brand-line);border-radius:var(--r-full)}

/* ============ 面试出题工作台（v0.85.0）============
   左右分栏是这一页的主结构：左固定配置、右候选池独立滚动。
   旧的上下流布局让 HR 改一个参数就得上下滚两次，这是"丑"的直接来源。
   窄屏（≤980px）退回单列，配置在上——手机上双栏一定挤成一团。 */
.qg-wrap{display:grid;grid-template-columns:calc(var(--sp-base) * 85) minmax(0,1fr);
  gap:calc(var(--sp-base) * 4);align-items:start;margin-top:calc(var(--sp-base) * 3)}
.qg-side{display:flex;flex-direction:column;gap:calc(var(--sp-base) * 3);
  position:sticky;top:calc(var(--sp-base) * 9)}
.qg-box{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:calc(var(--sp-base) * 4)}
.qg-box-h{font-size:var(--fs-sm);font-weight:600;color:var(--text);
  margin-bottom:calc(var(--sp-base) * 2)}
.qg-adv>summary{cursor:pointer;list-style:none;margin-bottom:0}
.qg-adv>summary::-webkit-details-marker{display:none}
.qg-adv>summary::before{content:"▸";display:inline-block;width:calc(var(--sp-base) * 3)}
.qg-adv[open]>summary::before{content:"▾"}
.qg-lbl{display:block;font-size:var(--fs-xs);color:var(--muted);
  margin:calc(var(--sp-base) * 2.5) 0 var(--sp-base)}
.qg-ctl{width:100%;margin:0}
.qg-sub{font-size:var(--fs-xs);color:var(--muted);
  margin:calc(var(--sp-base) * 2.5) 0 var(--sp-base)}
.qg-chips{display:flex;flex-wrap:wrap;gap:calc(var(--sp-base) * 1.5)}
.qg-chip{display:inline-flex;align-items:center;gap:var(--sp-base);
  font-size:var(--fs-xs);line-height:1.7;padding:0 calc(var(--sp-base) * 2);
  border:1px solid var(--line);border-radius:var(--r-full);
  background:var(--bg);color:var(--muted)}
.qg-chip b{font-weight:600;color:var(--brand-dk)}
.qg-chip-btn{cursor:pointer;font-family:var(--ff-sans)}
.qg-chip-btn:hover{border-color:var(--brand-line);color:var(--text)}
.qg-chip-on{background:var(--brand-soft);border-color:var(--brand-line);color:var(--brand-dk)}
.qg-chip-off{opacity:.55;border-style:dashed}
.qg-2col{display:grid;grid-template-columns:1fr 1fr;gap:calc(var(--sp-base) * 2)}
.qg-rb{margin-top:calc(var(--sp-base) * 3)}
.qg-rb span{font-size:var(--fs-xs);line-height:1.5}
.qg-go{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:calc(var(--sp-base) * 3)}
.qg-go-row{display:flex;align-items:center;gap:calc(var(--sp-base) * 2);margin-bottom:calc(var(--sp-base) * 2)}
.qg-go-row .qg-lbl{margin:0;flex:none}
.qg-go-row input{width:calc(var(--sp-base) * 12);margin:0}
.qg-go-row select{width:auto;margin:0}
.qg-gen{width:100%;font-family:var(--ff-sans);font-size:var(--fs-md);font-weight:500;
  padding:calc(var(--sp-base) * 2.5);border:1px solid var(--brand);border-radius:var(--r-sm);
  background:var(--brand);color:#fff;cursor:pointer}
.qg-gen:hover{background:var(--brand-dk);border-color:var(--brand-dk)}
.qg-gen[disabled]{opacity:.55;cursor:not-allowed}
.qg-msg{font-size:var(--fs-xs);color:var(--muted);margin-top:calc(var(--sp-base) * 2);
  min-height:calc(var(--sp-base) * 4)}
.qg-link{color:var(--brand-dk);text-decoration:underline}
.qg-gate{padding:calc(var(--sp-base) * 2.5) calc(var(--sp-base) * 3);
  border:1px solid var(--warn-line);border-radius:var(--r-md);background:var(--warn-soft);
  font-size:var(--fs-sm);color:var(--warn);margin-top:calc(var(--sp-base) * 3)}

.qg-main{min-width:0}
.qg-main-h{display:flex;align-items:center;gap:calc(var(--sp-base) * 2);
  flex-wrap:wrap;padding-bottom:calc(var(--sp-base) * 2)}
.qg-count{font-size:var(--fs-xs);font-weight:600;color:var(--brand-dk);
  background:var(--brand-soft);border:1px solid var(--brand-line);
  border-radius:var(--r-full);padding:0 calc(var(--sp-base) * 2);line-height:1.7}
.qg-note{font-size:var(--fs-xs);color:var(--muted)}
.qg-main-ops{margin-left:auto;display:flex;gap:calc(var(--sp-base) * 1.5)}
.qg-btn{font-family:var(--ff-sans);font-size:var(--fs-xs);line-height:1.8;
  padding:0 calc(var(--sp-base) * 2.5);border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--card);color:var(--text);cursor:pointer}
.qg-btn:hover{border-color:var(--brand-line);color:var(--brand-dk)}
.qg-btn-p{background:var(--brand);border-color:var(--brand);color:#fff}
.qg-btn-p:hover{background:var(--brand-dk);border-color:var(--brand-dk);color:#fff}
.qg-btn[disabled]{opacity:.55;cursor:not-allowed}

.qg-stats{display:grid;grid-template-columns:1fr 1fr;gap:calc(var(--sp-base) * 3);
  background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:calc(var(--sp-base) * 3);margin-bottom:calc(var(--sp-base) * 3)}
.qg-stat-h{font-size:var(--fs-xs);color:var(--muted);margin-bottom:calc(var(--sp-base) * 1.5)}
.qg-bars{display:flex;flex-direction:column;gap:var(--sp-base)}
.qg-bar-row{display:flex;align-items:center;gap:calc(var(--sp-base) * 1.5)}
.qg-bar-l{flex:0 0 calc(var(--sp-base) * 14);font-size:var(--fs-xs);color:var(--text)}
.qg-bar-t{flex:1;height:calc(var(--sp-base) * 2);background:var(--bg);
  border-radius:var(--r-full);overflow:hidden}
.qg-bar{display:block;height:100%;background:var(--brand);border-radius:var(--r-full)}
.qg-bar-n{flex:0 0 calc(var(--sp-base) * 4);text-align:right;
  font-size:var(--fs-xs);color:var(--muted)}
.qg-bar.qg-t-situational{background:var(--warn)}
.qg-bar.qg-t-architecture{background:var(--navy)}
.qg-bar.qg-t-leadership{background:var(--ok)}

.qg-list{display:flex;flex-direction:column;gap:calc(var(--sp-base) * 2)}
.qg-card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:calc(var(--sp-base) * 3)}
.qg-card-on{border-color:var(--brand-line)}
.qg-card:hover{box-shadow:var(--ring)}
.qg-card-h{display:flex;align-items:center;gap:calc(var(--sp-base) * 1.5);flex-wrap:wrap}
.qg-chk{width:calc(var(--sp-base) * 4);height:calc(var(--sp-base) * 4);flex:none}
.qg-no{font-size:var(--fs-xs);color:var(--muted);min-width:calc(var(--sp-base) * 3)}
.qg-badge{font-size:var(--fs-xs);line-height:1.7;padding:0 calc(var(--sp-base) * 1.5);
  border:1px solid var(--line);border-radius:var(--r-full);color:var(--muted);background:var(--bg)}
.qg-badge.qg-t-behavioral{color:var(--brand-dk);background:var(--brand-soft);border-color:var(--brand-line)}
.qg-badge.qg-t-situational{color:var(--warn);background:var(--warn-soft);border-color:var(--warn-line)}
.qg-badge.qg-t-architecture{color:var(--navy);background:var(--bg);border-color:var(--ink-line)}
.qg-badge.qg-t-leadership{color:var(--ok);background:var(--ok-soft);border-color:var(--ok-line)}
.qg-dup{font-size:var(--fs-xs);color:var(--bad);background:var(--bad-soft);
  border:1px solid var(--bad-line);border-radius:var(--r-full);padding:0 calc(var(--sp-base) * 1.5)}
.qg-ops{margin-left:auto;display:flex;gap:var(--sp-base);flex:none}
.qg-mini{font-family:var(--ff-sans);font-size:var(--fs-xs);line-height:1.8;
  padding:0 calc(var(--sp-base) * 1.5);border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--card);color:var(--muted);cursor:pointer}
.qg-mini:hover{border-color:var(--brand-line);color:var(--brand-dk)}
.qg-mini-x:hover{border-color:var(--bad-line);color:var(--bad)}
/* v0.88.0 重点题：☆ 灰 = 未标 / ★ 金 = 已标。尺寸与其它 qg-mini 一致，
   只换颜色——卡片头已经有勾选框、序号、三个徽章和五个按钮，再大一圈就挤爆。 */
.qg-mini-star{color:#C9CDD4}
.qg-mini-star.on{color:#C68600;border-color:#F2D48A;background:#FFFAEB}
.qg-stem{margin-top:calc(var(--sp-base) * 1.5);font-size:var(--fs-md);
  line-height:1.6;color:var(--text)}
.qg-detail{margin-top:calc(var(--sp-base) * 2.5);padding-top:calc(var(--sp-base) * 2.5);
  border-top:1px dashed var(--line)}
.qg-d-sec+.qg-d-sec{margin-top:calc(var(--sp-base) * 2.5)}
.qg-d-h{font-size:var(--fs-xs);color:var(--muted);margin-bottom:var(--sp-base)}
.qg-d-t{font-size:var(--fs-sm);line-height:1.65;color:var(--text)}
.qg-d-list{margin:0;padding-left:calc(var(--sp-base) * 5);
  font-size:var(--fs-sm);line-height:1.65;color:var(--text)}
.qg-rub{display:flex;flex-direction:column;gap:var(--sp-base)}
.qg-rub-row{display:flex;align-items:flex-start;gap:calc(var(--sp-base) * 2)}
.qg-rub-s{flex:none;width:calc(var(--sp-base) * 5);height:calc(var(--sp-base) * 5);
  display:inline-flex;align-items:center;justify-content:center;
  font-size:var(--fs-xs);font-weight:600;color:var(--brand-dk);
  background:var(--brand-soft);border:1px solid var(--brand-line);border-radius:var(--r-circle)}
.qg-rub-d{font-size:var(--fs-sm);line-height:1.6;color:var(--text)}
.qg-empty{padding:calc(var(--sp-base) * 12) calc(var(--sp-base) * 4);text-align:center;
  color:var(--muted);font-size:var(--fs-sm);border:1px dashed var(--line);
  border-radius:var(--r-md);background:var(--card)}

@media(max-width:980px){
  .qg-wrap{grid-template-columns:minmax(0,1fr)}
  .qg-side{position:static}
  .qg-stats{grid-template-columns:1fr}
}

/* ============ 出题工作台：单题工坊与交付（v0.86.0）============
   工具条压在展开区里，卡头只留勾选/徽章/三颗按钮——十个按钮挤卡头，
   眼睛没有落点，也会把题干挤到折行。 */
.qg-deliver{display:flex;align-items:center;gap:calc(var(--sp-base) * 1.5);
  flex-wrap:wrap;margin-top:calc(var(--sp-base) * 2)}
.qg-paper{max-width:calc(var(--sp-base) * 62);margin:0}
.qg-prog{height:calc(var(--sp-base) * 1);background:var(--bg);border-radius:var(--r-full);
  overflow:hidden;margin-top:calc(var(--sp-base) * 2)}
.qg-prog>i{display:block;height:100%;width:40%;background:var(--brand);
  border-radius:var(--r-full);animation:qgind 1.1s ease-in-out infinite}
@keyframes qgind{0%{margin-left:-40%}100%{margin-left:100%}}
.qg-tools{display:flex;align-items:center;gap:var(--sp-base);flex-wrap:wrap;
  margin-bottom:calc(var(--sp-base) * 2.5);padding-bottom:calc(var(--sp-base) * 2);
  border-bottom:1px dashed var(--line)}
.qg-tools-l{font-size:var(--fs-xs);color:var(--muted)}
.qg-tools-sp{flex:1;min-width:0}
.qg-tool{font-family:var(--ff-sans);font-size:var(--fs-xs);line-height:1.8;
  padding:0 calc(var(--sp-base) * 1.5);border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--card);color:var(--text);cursor:pointer}
.qg-tool:hover{border-color:var(--brand-line);color:var(--brand-dk)}
.qg-tool[disabled]{opacity:.5;cursor:not-allowed}
.qg-tool-i{min-width:calc(var(--sp-base) * 6);padding:0}
.qg-busy{font-size:var(--fs-xs);color:var(--brand-dk)}
.qg-card-editing{border-color:var(--brand-line);background:var(--brand-soft)}
.qg-edit{margin-top:calc(var(--sp-base) * 1.5)}
.qg-edit-t{width:100%;box-sizing:border-box;font-family:var(--ff-sans);
  font-size:var(--fs-md);line-height:1.6;color:var(--text);padding:calc(var(--sp-base) * 1.5);
  border:1px solid var(--brand-line);border-radius:var(--r-sm);background:var(--card);
  resize:vertical}
.qg-edit-ops{display:flex;gap:calc(var(--sp-base) * 1.5);margin-top:calc(var(--sp-base) * 1.5)}
/* --rail 是侧栏宽度（228px），不是颜色——v0.85.0 这里误用过一次，
   浏览器把非法值丢掉后背景变透明，只有量 computed style 才看得出。 */
.qg-bi{margin-top:calc(var(--sp-base) * 2.5);padding:calc(var(--sp-base) * 2)
  calc(var(--sp-base) * 2.5);background:var(--bg);border-radius:var(--r-sm)}
.qg-bi-t{font-size:var(--fs-md);line-height:1.6;color:var(--text)}
.qg-bi-f{font-size:var(--fs-sm);color:var(--muted);margin-top:var(--sp-base)}
.qg-bi .qg-rub{margin-top:calc(var(--sp-base) * 1.5)}

/* v0.91.0：AI 面试的逐题点评（只出现在试卷驱动的场次，见 assess_tabs.aiintPaperBlock）。
   与维度条同处一个弹窗，所以节奏跟着弹窗走：卡片之间 4px、块内 6px。
   颜色只借已有的 --ok / --brand / --bad / --line，不引新色——这一块是**阅读区**，
   不是新的评分体系，三档标签只是让人一眼扫到「哪题偏弱」。 */
.as-pq{border:1px solid var(--line);border-radius:var(--r-sm);
  padding:calc(var(--sp-base) * 1.5) calc(var(--sp-base) * 2);
  margin-bottom:var(--sp-base);background:var(--card)}
.as-pq-h{display:flex;align-items:center;gap:var(--sp-base);font-size:var(--fs-sm);color:var(--muted)}
.as-pq-star{color:var(--warn);font-size:var(--fs-sm)}
.as-pq-lv{margin-left:auto;font-size:var(--fs-xs);border-radius:var(--r-full);
  padding:1px 8px;border:1px solid var(--line)}
.as-pq-good{color:var(--ok);border-color:var(--ok-line)}
.as-pq-ok{color:var(--brand);border-color:var(--brand-line)}
.as-pq-weak{color:var(--bad);border-color:var(--bad-line)}
.as-pq-q{font-size:var(--fs-md);line-height:1.6;color:var(--text);margin-top:var(--sp-base)}
.as-pq-c{font-size:var(--fs-md);line-height:1.7;color:var(--text);margin-top:var(--sp-base)}
.as-pq-ks{display:flex;gap:var(--sp-base);flex-wrap:wrap;margin-top:var(--sp-base)}
.as-pq-k{font-size:var(--fs-xs);border-radius:var(--r-full);
  padding:1px 8px;border:1px solid var(--line)}
.as-pq-hit{color:var(--ok);border-color:var(--ok-line);background:var(--ok-soft)}
.as-pq-miss{color:var(--bad);border-color:var(--bad-line);background:var(--bad-soft)}

/* v0.92.0：分析与报表页（#p-analytics，逻辑在 pages/analytics.js）。
   四个 Tab 共用一个容器，所以样式只描述「块」不描述「页」——
   换 Tab 时不会有一层套一层的卡片框。 */
.an-tabs{display:flex;flex-wrap:wrap;gap:var(--sp-base);margin:calc(var(--sp-base) * 3) 0;
  border-bottom:1px solid var(--line)}
.an-tab{background:none;border:0;border-bottom:2px solid transparent;border-radius:0;
  padding:calc(var(--sp-base) * 2) calc(var(--sp-base) * 2.5);font-size:var(--fs-md);
  color:var(--muted);cursor:pointer}
.an-tab.on{color:var(--brand);border-bottom-color:var(--brand);font-weight:600}
.an-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:calc(var(--sp-base) * 3)}
.an-kpi{background:var(--card);border:1px solid var(--line);border-radius:var(--r-md);
  padding:calc(var(--sp-base) * 3)}
.an-kpi-h{display:flex;justify-content:space-between;align-items:baseline;
  font-size:var(--fs-sm);color:var(--muted)}
.an-kpi-v{display:flex;align-items:baseline;gap:var(--sp-base);margin-top:var(--sp-base);
  font-size:var(--fs-display);font-weight:700;line-height:1.2}
.an-kpi-cap{font-size:var(--fs-xs);color:var(--muted)}
.an-kpi-row{display:flex;justify-content:space-between;align-items:baseline;
  gap:var(--sp-base);margin-top:calc(var(--sp-base) * 1.5);
  font-size:var(--fs-sm);color:var(--muted)}
.an-kpi-row b{color:var(--text)}
.an-dl{font-size:var(--fs-xs);font-weight:600;color:var(--muted)}
.an-dl.up{color:var(--ok)}
.an-dl.down{color:var(--bad)}
.an-sec{margin:calc(var(--sp-base) * 4) 0 calc(var(--sp-base) * 1.5);font-weight:600}
.an-note{margin-top:calc(var(--sp-base) * 2);line-height:1.7;
  font-size:var(--fs-sm);color:var(--muted)}
.an-empty{padding:calc(var(--sp-base) * 6);text-align:center;color:var(--muted);
  border:1px dashed var(--line);border-radius:var(--r-md)}
.an-table{width:100%;border-collapse:collapse}
.an-table th,.an-table td{border-bottom:1px solid var(--line);text-align:left;
  padding:calc(var(--sp-base) * 1.5) calc(var(--sp-base) * 2);white-space:nowrap}
.an-table th{font-size:var(--fs-sm);color:var(--muted);font-weight:600}
.an-table td{font-size:var(--fs-md)}
.an-mo{font-size:var(--fs-sm);color:var(--muted)}
.an-bar{display:inline-block;width:64px;height:6px;margin-right:var(--sp-base);
  border-radius:var(--r-full);background:var(--line);vertical-align:middle;overflow:hidden}
.an-bar i{display:block;height:100%;background:var(--brand)}
.an-build{display:flex;flex-wrap:wrap;gap:calc(var(--sp-base) * 3);align-items:center;
  margin-bottom:calc(var(--sp-base) * 2)}
.an-build label{display:flex;gap:var(--sp-base);align-items:center;white-space:nowrap;
  font-size:var(--fs-sm);color:var(--muted)}
/* select 必须给最小宽度：label 是 flex 容器且宽度由内容决定，只写 width:auto
   会让它缩到几十像素——真机上「行 / 列 / 排序」三个下拉全糊成一条竖线。 */
.an-build select{flex:0 0 auto;width:auto;min-width:120px}
.an-chks{display:flex;flex-wrap:wrap;gap:calc(var(--sp-base) * 2);
  margin-bottom:calc(var(--sp-base) * 3)}
.an-chk{display:flex;gap:var(--sp-base);align-items:center;font-size:var(--fs-sm)}

/* v0.94.0：账号簇并入蓝色欢迎横幅（原先品牌行 / 账号行 / 横幅占三行，中间那行只有
   一串中性文字）。这里只覆写「在深蓝渐变上」需要变的几处，.acct 本体与头像的布局
   规则仍留在 admin.html —— 候选人页那边也有同名 .tbr，不跟着改。 */
.welcome .acct{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.28);
  box-shadow:none;padding:4px 12px;border-radius:var(--r-full)}
.welcome .acct .who{color:#fff}
.welcome .acct .role-chip{background:rgba(255,255,255,.18);
  border-color:rgba(255,255,255,.34);color:#fff}
.welcome .acct .acct-av{background:rgba(255,255,255,.92);border-color:rgba(255,255,255,.6)}
/* 试用徽章的文字色是 auth.js 内联的（临期会标红 #B42318），深蓝底上红字读不清 ⇒ 底给白 */
.welcome .acct #acct-trial{background:#fff;border-color:#fff}
/* 两个动作换白底胶囊：半透明按钮落在渐变两端时对比度忽高忽低 */
.we-act{display:inline-block;background:#fff;border:1px solid #fff;color:var(--navy);
  font-weight:600;padding:5px 14px;border-radius:var(--r-full);
  font-size:var(--fs-md);line-height:1.5;cursor:pointer;text-decoration:none}
.we-act:hover{background:#EAF2FB;border-color:#EAF2FB}
/* 窄屏：横幅自然折成「问候 + 账号簇 / 动作」两行。**不要**给 .sp 加 flex-basis:100%
   强制换行——实测 760px 下反而折成三行更散；这里只把间距收紧、让账号簇内部自己折。
   选择器带 #welcome-bar：本文件在 admin.html 的 <style> 之前加载，同特异性会被它盖掉。 */
@media (max-width:900px){
  #welcome-bar{gap:10px}
  #welcome-bar .acct{flex-wrap:wrap}
  #welcome-bar .we-act{padding:5px 12px}
}

/* ================= v0.95.0：组织定制两列 + 订阅页套餐卡 =================
   两块都是**版式**改动：把竖排到底的表单/卡片重新分栏，不改任何业务判据。
   字号一律 --fs-*、圆角一律 --r-*（tokens.css 是标尺）；字号行不写绝对值——
   verify_v0860 会扫这一段，注释里提到那两个词也会被算进去（踩过一次）。 */

/* ---- 组织定制：左「基本信息」右「资源与入口」 ---- */
.br-grid{display:grid;grid-template-columns:minmax(0,1.6fr) minmax(0,1fr);
  gap:calc(var(--sp-base) * 4);align-items:start}
.br-side{display:flex;flex-direction:column;gap:calc(var(--sp-base) * 4)}
.br-url{display:flex;align-items:center;gap:var(--sp-base);margin:calc(var(--sp-base) * 2) 0;
  padding:8px 10px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card)}
.br-url code{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-family:ui-monospace,Menlo,Consolas,monospace;color:var(--text)}
.br-url code{font-size:var(--fs-sm)}
.br-open{display:inline-block;font-weight:600;color:var(--brand);text-decoration:none}
.br-open:hover{text-decoration:underline}
@media (max-width:1100px){.br-grid{grid-template-columns:1fr}}

/* ---- 订阅页：套餐卡 ---- */
.bil-hero{display:flex;flex-direction:column;gap:calc(var(--sp-base) * 2)}
.bil-hero-main{display:flex;align-items:flex-start;gap:calc(var(--sp-base) * 3);flex-wrap:wrap}
.bil-hero-l{flex:1 1 240px;min-width:0}
.bil-hero-r{display:flex;flex-direction:column;align-items:flex-end;gap:calc(var(--sp-base) * 1.5)}
.bil-kicker{color:var(--muted);letter-spacing:.05em;text-transform:uppercase}
.bil-kicker{font-size:var(--fs-xs)}
.bil-plan{font-weight:700;color:var(--navy);line-height:1.15;margin-top:2px}
.bil-plan{font-size:var(--fs-display)}
.bil-cyc{font-weight:400;color:var(--muted);margin-left:6px}
.bil-cyc{font-size:var(--fs-md)}
.bil-meta{color:var(--muted);margin-top:4px}
.bil-meta{font-size:var(--fs-sm)}
.bil-left{color:var(--brand);font-weight:600}
.bil-price{font-weight:700;color:var(--navy)}
.bil-price{font-size:var(--fs-xl)}
.bil-price span{font-weight:400;color:var(--muted);margin-left:3px}
.bil-price span{font-size:var(--fs-xs)}
.bil-cycle{display:flex;justify-content:space-between;gap:10px;color:var(--muted)}
.bil-cycle{font-size:var(--fs-xs)}
.bil-cycle-n{color:var(--muted)}
.bil-cycle-n{font-size:var(--fs-sm)}

/* ---- 订阅页：三格用量 ---- */
.bil-head{display:flex;align-items:center;gap:calc(var(--sp-base) * 2);flex-wrap:wrap;
  margin-bottom:4px}
.bil-head b{color:var(--navy)}
.bil-head b{font-size:var(--fs-lg)}
.bil-tag{padding:1px 8px;border-radius:var(--r-full);border:1px solid var(--line);
  color:var(--muted);background:var(--card)}
.bil-tag{font-size:var(--fs-xs)}
.bil-cap{color:var(--muted);line-height:1.55;margin:2px 0 10px}
.bil-cap{font-size:var(--fs-sm)}
.bil-warn{color:#B26A00;line-height:1.5}
.bil-warn{font-size:var(--fs-sm)}
.bil-warn-inline{color:#B26A00}
.bil-usage{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:calc(var(--sp-base) * 3);margin-top:calc(var(--sp-base) * 2)}
.bil-u{min-width:0}
.bil-u-l{color:var(--muted)}
.bil-u-l{font-size:var(--fs-sm)}
.bil-u-v{font-weight:700;color:var(--navy);margin:2px 0 6px}
.bil-u-v.hot{color:var(--bad)}
.bil-u-v{font-size:var(--fs-xl)}
.bil-u-n{color:var(--muted);margin-top:5px;line-height:1.5}
.bil-u-n{font-size:var(--fs-xs)}
.bil-bar{height:6px;border-radius:var(--r-sm);background:var(--line);overflow:hidden}
.bil-bar.wide{height:7px;margin:6px 0 2px}
.bil-bar.none{background:transparent}
.bil-bar i{display:block;height:100%;border-radius:var(--r-sm);
  background:linear-gradient(90deg,#2E7DD1,#4FA3E3)}
.bil-bar i.hot{background:var(--bad)}

/* ---- 订阅页：包含项表 + 档位卡 ---- */
.bil-tbl{width:100%;border-collapse:collapse}
.bil-tbl{font-size:var(--fs-sm)}
.bil-tbl th{text-align:left;font-weight:600;color:var(--muted);
  padding:6px 8px;border-bottom:1px solid var(--line)}
.bil-tbl td{padding:7px 8px;border-bottom:1px solid var(--line);vertical-align:top}
.bil-tbl tr:last-child td{border-bottom:0}
.bil-num{font-weight:600;color:var(--navy);white-space:nowrap}
.bil-plans{display:grid;grid-template-columns:1fr 1fr;
  gap:calc(var(--sp-base) * 2);margin-top:6px}
@media (max-width:1100px){
  .bil-usage{grid-template-columns:1fr}
  .bil-plans{grid-template-columns:1fr}
}
