/* ============================================================================
   组件：按钮 / 输入 / 筛选 / 列表行 / 标签 / 键值 / 空状态 / Toast / 弹窗
   ============================================================================ */
.btn{
  height:32px;padding:0 13px;border-radius:var(--r-sm);border:1px solid var(--line2);
  background:var(--surface);font-size:13px;font-weight:500;color:var(--ink2);
  display:inline-flex;align-items:center;gap:7px;
  transition:background .12s var(--move),border-color .12s var(--move);
}
.btn:hover{background:var(--surface3)}
.btn.pri{background:var(--brand);border-color:var(--brand);color:#fff}
.btn.pri:hover{background:var(--brand-ink)}
.btn.dg{color:var(--danger);border-color:#e6c6c1}
.btn.dg:hover{background:var(--danger-w)}
.btn[disabled]{opacity:.5;cursor:not-allowed}
.btn.sm{height:27px;padding:0 10px;font-size:12.5px}

.fld{
  height:30px;padding:0 9px;border-radius:var(--r-sm);border:1px solid var(--line2);
  background:var(--surface);font-size:12.5px;color:var(--ink2);
}
.fld:focus{border-color:var(--brand);outline:none}

/* 复选框 / 单选框的全局基线。
   页面里凡是裸的 checkbox/radio 都会被容器里的 `input{width:100%}` 类规则撑成大色块，
   与其让每个页面自己写内联样式兜底（会散成十几处），不如在这里定一次。
   accent-color 让原生控件跟随主题主色，省掉自绘。 */
input[type="checkbox"],
input[type="radio"]{
  width:auto;height:auto;min-width:0;padding:0;margin:0;
  flex:0 0 auto;accent-color:var(--brand);cursor:pointer;
}
/* 「复选 + 文字」的整行写法 */
.opt{display:inline-flex;align-items:center;gap:8px;font-size:13px;color:var(--ink2);line-height:1.5;cursor:pointer}
.opt:hover{color:var(--ink)}
.opt input{flex:0 0 auto}
.opt .desc{display:block;font-size:11.5px;color:var(--ink3);margin-top:1px}
.search{
  height:32px;min-width:190px;padding:0 11px;border-radius:var(--r-sm);
  border:1px solid var(--line2);background:var(--surface2);font-size:13px;
}
.search::placeholder{color:var(--ink3)}
.search:focus{border-color:var(--brand);outline:none;background:var(--surface)}

.filters{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--line)}
.count{font-size:12px;color:var(--ink3);margin-left:auto}
.count b{color:var(--ink);font-variant-numeric:tabular-nums}

/* ---------- 列表行 ---------- */
.rows{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.row{
  display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  padding:10px 14px;border-bottom:1px solid var(--line);position:relative;
  transition:background .1s var(--move);
}
.row:last-child{border-bottom:0}
.row:hover{background:var(--surface2)}
.row[aria-selected="true"]{background:var(--brand-w)}
.row[aria-selected="true"]::before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--brand)}
.row.is-active{box-shadow:inset 3px 0 0 var(--brand)}
.row .r-main{flex:1;min-width:0}
.row .r-t{font-size:13.5px;font-weight:500;display:flex;align-items:center;gap:7px}
.row .r-s{font-size:12px;color:var(--ink3);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.row .r-v{
  flex:0 0 auto;display:flex;align-items:center;gap:9px;
  text-align:right;font-size:12.5px;color:var(--ink2);font-variant-numeric:tabular-nums;
}
.row .r-score{
  display:inline-block;min-width:44px;padding:1px 7px;border-radius:4px;
  background:var(--surface3);color:var(--ink);font-weight:600;text-align:center;
}
.mono{font-family:var(--mono);font-size:12px}
@keyframes flash{from{background:var(--brand-w)}to{background:transparent}}
.row.saved{animation:flash .9s var(--move)}

/* 行内编辑 */
.cell-edit{
  border:1px solid var(--brand);border-radius:4px;padding:2px 6px;font-size:13.5px;
  background:var(--surface);min-width:90px;box-shadow:0 0 0 3px var(--brand-w);
}
.cell-edit:focus{outline:none}
.cell-hint{display:inline-block;font-size:11px;color:var(--brand);margin-left:8px}

/* 标签 */
.tag{
  display:inline-flex;align-items:center;height:19px;padding:0 7px;border-radius:4px;
  font-size:11.5px;font-weight:600;border:1px solid var(--line2);color:var(--ink2);background:var(--surface2);
  white-space:nowrap;
}
.tag.ok{color:var(--ok);border-color:var(--brand-t);background:var(--brand-w)}
.tag.run{color:var(--brand-ink);border-color:var(--brand-t);background:var(--brand-w)}
.tag.dg{color:var(--danger);border-color:#e6c6c1;background:var(--danger-w)}
.tag.wn{color:var(--warn);border-color:#e8d9b8;background:var(--warn-w)}

/* 键值 */
.kv{display:grid;grid-template-columns:82px 1fr;gap:9px 12px;font-size:13px;align-items:baseline}
.kv dt{color:var(--ink3);font-size:12.5px}
.kv dd{color:var(--ink);min-width:0;word-break:break-word}
.sec-t{
  font-size:11px;font-weight:700;color:var(--ink3);letter-spacing:.07em;text-transform:uppercase;
  margin:20px 0 9px;padding-bottom:6px;border-bottom:1px solid var(--line);
}

/* 空状态：区分「本来就没有」与「被筛掉了」，两种给不同动作 */
.empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:9px;padding:56px 20px;text-align:center;color:var(--ink3);font-size:13px;
}
.empty .big{font-size:15px;color:var(--ink2);font-weight:600}
.empty .btn{margin-top:5px}

/* 错误块：明确说「哪里出错 + 怎么办」，不写「出错了」这种空话 */
.err{
  display:flex;gap:11px;align-items:flex-start;padding:14px 16px;margin-bottom:12px;
  border-radius:var(--r);background:var(--danger-w);border:1px solid #e6c6c1;
  font-size:13px;line-height:1.7;color:var(--ink2);
}
.err b{color:var(--danger)}
.err .ic{color:var(--danger);flex:0 0 auto;margin-top:1px}

/* 行操作按钮组：默认淡出，悬停/聚焦才显形 —— 表格不因操作列而变吵 */
.row-ops{display:flex;gap:6px;opacity:0;transition:opacity .12s var(--move)}
.row:hover .row-ops,.row:focus-within .row-ops{opacity:1}
@media (hover:none){.row-ops{opacity:1}}

/* ---------- Toast ---------- */
.toast{
  position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(12px);
  background:var(--ink);color:var(--bg);padding:9px 16px;border-radius:var(--r-sm);
  font-size:13px;font-weight:500;box-shadow:var(--sh-pop);z-index:60;
  opacity:0;pointer-events:none;transition:opacity .18s var(--move),transform .18s var(--move);
  max-width:min(520px,90vw);
}
.toast[data-show="true"]{opacity:1;transform:translateX(-50%) translateY(0)}
.toast.err{background:var(--danger);color:#fff}

/* ---------- 密度切换 ---------- */
.density{display:flex;gap:4px;margin-left:auto}
.density button{
  width:28px;height:28px;border-radius:var(--r-sm);border:1px solid var(--line2);
  color:var(--ink3);display:flex;align-items:center;justify-content:center;font-size:11px;
}
.density button[aria-pressed="true"]{background:var(--brand-w);border-color:var(--brand-t);color:var(--brand-ink)}
body[data-density="compact"] .row{padding:6px 14px}
body[data-density="compact"] .row .r-s{display:none}
body[data-density="compact"] .row .r-score{display:none}

/* ---------- 弹窗 ---------- */
.modal-scrim{
  position:fixed;inset:0;background:rgba(23,26,31,.42);z-index:70;
  display:flex;align-items:center;justify-content:center;padding:24px;
}
.modal{
  background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--sh-pop);
  width:min(560px,100%);max-height:88vh;display:flex;flex-direction:column;
}
/* 宽表预览弹窗（换人预览、课表解析结果这类多列表格）
   页面里先前是用内联 style 改宽度兜的 —— 收成工具类，页面就不必写内联样式。 */
.modal.wide{width:min(880px,100%)}
.modal.xwide{width:min(1100px,100%)}
.modal-hd{padding:16px 18px 12px;border-bottom:1px solid var(--line);display:flex;align-items:flex-start;gap:10px}
.modal-hd h2{font-size:16px;font-weight:700}
.modal-bd{padding:16px 18px;overflow:auto;font-size:13px;line-height:1.75;color:var(--ink2)}
.modal-ft{padding:12px 18px;border-top:1px solid var(--line);display:flex;gap:8px;justify-content:flex-end;background:var(--surface2)}
/* 弹出层的关闭键（放在标题右侧）。多个页面都要「右上角一个 ×」，
   各自手写绝对定位会散成七八处，这里收成一处工具类。 */
.modal-x{
  width:30px;height:30px;flex:0 0 auto;margin-left:auto;border-radius:var(--r-sm);
  display:inline-flex;align-items:center;justify-content:center;color:var(--ink3);
}
.modal-x:hover{background:var(--surface3);color:var(--ink)}

/* 分页 */
.pager{display:flex;align-items:center;gap:6px;justify-content:flex-end;margin-top:12px;font-size:12.5px;color:var(--ink3)}
.pager button{
  min-width:28px;height:28px;padding:0 8px;border-radius:var(--r-sm);
  border:1px solid var(--line2);background:var(--surface);color:var(--ink2);font-size:12.5px;
}
.pager button[aria-current="true"]{background:var(--brand);border-color:var(--brand);color:#fff;font-weight:600}
.pager button[disabled]{opacity:.45;cursor:not-allowed}

/* 表格式列表（比卡片行更适合看数值对比） */
.tbl{width:100%;border-collapse:collapse;font-size:12.5px}
.tbl th{
  text-align:left;padding:9px 10px;font-size:11.5px;font-weight:700;color:var(--ink3);
  background:var(--surface2);border-bottom:1px solid var(--line);white-space:nowrap;position:sticky;top:0;z-index:1;
}
.tbl td{padding:9px 10px;border-bottom:1px solid var(--line);color:var(--ink2);white-space:nowrap}
.tbl tbody tr:hover td{background:var(--surface2)}
.tbl .num{text-align:right;font-variant-numeric:tabular-nums;font-family:var(--mono)}
.tbl-wrap{overflow:auto;background:var(--surface);border:1px solid var(--line);border-radius:var(--r)}
