/*
  组件层 · 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)}
