/* 检测证书查询系统 — 便当盒(Bento Grid)风格
   原则: 浅色画布 + 圆角磁贴卡片 + 大小不一但严格对齐的网格 + 低饱和底色池 + 全站单一强调色。
   分工: 概览信息由 .bento/.tile 网格承载(1×1/2×1/2×2 磁贴, 固定行高严格对齐);
         密集数据(表格/表单)由 .card 承载, 保证信息密度与可用性。
   禁止: 玻璃拟态(backdrop-filter) / 复杂渐变卡片 / 高饱和彩色卡墙 / 圆角 < 12px。 */
:root {
  /* ---------- 便当盒基础令牌 ---------- */
  --canvas:     #ffffff;
  --canvas-alt: #f5f5f7;
  --ink:        #1d1d1f;
  --ink-muted:  #6e6e73;
  --ink-subtle: #8e8e93;
  --accent:     #0071e3;      /* 唯一强调色 */

  --card-radius: 20px;
  --gap:         16px;        /* 磁贴/卡片间距 */
  --card-pad:    24px;

  /* ---------- 磁贴底色池(低饱和) ---------- */
  --tile-1: #eef2ff;  /* 浅蓝 */
  --tile-2: #f5f0ff;  /* 浅紫 */
  --tile-3: #e8f5ee;  /* 浅绿 */
  --tile-4: #fff7e6;  /* 浅黄 */
  --tile-5: #fdf0ef;  /* 浅橙 */
  --tile-6: #f0f4f8;  /* 浅青 */

  /* ---------- 语义色(浅底调深, 保对比度) ---------- */
  --primary:      #0071e3;
  --primary-dark: #0058b0;
  --danger:       #d70015;
  --warn:         #a05a00;
  --success:      #1a7f4b;
  --border:       rgba(0, 0, 0, .08);

  /* ---------- 描边 / 阴影 / 聚焦环 ---------- */
  --line:        1px solid rgba(0, 0, 0, .06);
  --line-strong: 1px solid rgba(0, 0, 0, .12);
  --shadow-card:    0 1px 2px rgba(0, 0, 0, .04), 0 8px 24px rgba(0, 0, 0, .06);
  --shadow-raised:  0 2px 4px rgba(0, 0, 0, .05), 0 12px 32px rgba(0, 0, 0, .09);
  --shadow-modal:   0 24px 64px rgba(0, 0, 0, .22);
  --shadow-pressed: inset 0 0 0 1px rgba(0, 0, 0, .06);
  --focus-ring:     0 0 0 3px rgba(0, 113, 227, .18);

  /* ---------- 供内联样式/组件复用的补充变量 ---------- */
  --bg-pressed:  #f0f0f2;
  --radius-pill: 999px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: -apple-system, "Segoe UI", "Inter", "PingFang SC", "Microsoft YaHei", sans-serif;
  background: var(--canvas-alt);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.6;
  min-height: 100vh;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--primary-dark); }

/* =============== 顶栏(兼容旧页面) =============== */
.topbar {
  background: var(--canvas);
  border-bottom: var(--line);
  padding: 0 20px;
  height: 60px;
  display: flex; align-items: center; justify-content: space-between;
  position: sticky; top: 0; z-index: 10;
}
.brand { font-weight: 600; font-size: 17px; color: var(--ink); letter-spacing: .3px; }
.topbar .right { display: flex; align-items: center; gap: 14px; }

/* =============== 布局 =============== */
.container { max-width: 1240px; margin: 24px auto; padding: 0 16px; }

/* =============== 便当盒网格 + 磁贴 =============== */
.bento {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 150px;
  grid-auto-flow: dense;
  gap: var(--gap);
  margin-bottom: var(--gap);
}
.tile {
  grid-column: span 1;
  grid-row: span 1;
  min-width: 0;
  background: var(--canvas);
  border: var(--line);
  border-radius: var(--card-radius);
  padding: var(--card-pad);
  box-shadow: var(--shadow-card);
  display: flex; flex-direction: column; gap: 8px;
  transition: transform .2s ease, box-shadow .2s ease;
}
.tile:hover { transform: translateY(-2px); box-shadow: var(--shadow-raised); }

/* 尺寸: 1×1(默认) / 2×1 / 3×1 / 4×1 / 1×2 / 1×3 */
.tile.w2 { grid-column: span 2; }
.tile.w3 { grid-column: span 3; }
.tile.w4 { grid-column: span 4; }
.tile.h2 { grid-row: span 2; }
.tile.h3 { grid-row: span 3; }

/* 底色池: 每张磁贴一个柔和底色, 全站强调色仍只有 --accent */
.tile.t1 { background: var(--tile-1); }
.tile.t2 { background: var(--tile-2); }
.tile.t3 { background: var(--tile-3); }
.tile.t4 { background: var(--tile-4); }
.tile.t5 { background: var(--tile-5); }
.tile.t6 { background: var(--tile-6); }
.tile.flat { box-shadow: none; }

/* 图标方块 */
.tile-icon {
  width: 40px; height: 40px;
  flex: 0 0 40px;
  border-radius: 12px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, .6);
  color: var(--accent);
}
.tile-icon svg { width: 22px; height: 22px; }
.tile-icon.accent { background: var(--accent); color: #fff; }

/* 磁贴文案 */
.tile-title { font-size: 19px; font-weight: 600; letter-spacing: -.2px; color: var(--ink); }
.tile-desc  { font-size: 14px; line-height: 1.5; color: var(--ink-muted); }
.tile-foot  { margin-top: auto; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* 横向磁贴: 图标左 + 文案右(小磁贴或整行条) */
.tile.row { flex-direction: row; align-items: center; gap: 14px; }
.tile.row .tile-icon { width: 42px; height: 42px; flex-basis: 42px; border-radius: 13px; }
.tile.row .tile-icon svg { width: 20px; height: 20px; }
.tile.row .tile-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tile.row .tile-title { font-size: 16px; }
.tile.row .tile-desc { font-size: 13px; }
.tile.row .tile-foot { margin: 0 0 0 auto; flex-wrap: nowrap; }

/* 指标磁贴 */
.stat { display: flex; flex-direction: column; justify-content: center; gap: 2px; height: 100%; }
.stat-num { font-size: 36px; font-weight: 600; letter-spacing: -.5px; line-height: 1.15; color: var(--ink); }
.stat-num.is-ok     { color: var(--success); }
.stat-num.is-warn   { color: var(--warn); }
.stat-num.is-danger { color: var(--danger); }
.stat-label { font-size: 13px; color: var(--ink-muted); }

/* 状态总览磁贴内的一行 */
.stat-row { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--ink); }
.stat-row .n { margin-left: auto; font-weight: 600; }
.stat-bar { display: flex; height: 8px; border-radius: var(--radius-pill); overflow: hidden; background: #f0f0f2; margin-top: auto; }
.stat-bar > span { height: 100%; display: block; transition: width .3s ease; }
.stat-bar .seg-valid    { background: var(--success); }
.stat-bar .seg-expiring { background: var(--warn); }
.stat-bar .seg-expired  { background: var(--danger); }

/* =============== 卡片(密集数据容器) =============== */
.card {
  background: var(--canvas);
  border: var(--line);
  border-radius: var(--card-radius);
  padding: 22px var(--card-pad);
  margin-bottom: var(--gap);
  box-shadow: var(--shadow-card);
}
.card h2 { font-size: 16px; font-weight: 600; margin-bottom: 12px; color: var(--ink); }

/* =============== 按钮(胶囊) =============== */
.btn {
  display: inline-block;
  background: var(--canvas);
  color: var(--ink);
  border: var(--line-strong);
  padding: 9px 20px;
  border-radius: var(--radius-pill);
  cursor: pointer;
  font-size: 14px;
  font-family: inherit;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
  transition: background .18s ease, box-shadow .18s ease, transform .18s ease, color .18s ease, border-color .18s ease;
  user-select: none;
}
.btn:hover { background: var(--canvas-alt); transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0, 0, 0, .08); }
.btn:active { transform: translateY(0); box-shadow: none; }
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
.btn.danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn.danger:hover { background: #b30012; border-color: #b30012; }
.btn.secondary { background: var(--canvas-alt); border-color: transparent; }
.btn.secondary:hover { background: #eaeaec; }
.btn.small { padding: 5px 14px; font-size: 13px; }
.btn:disabled { opacity: .45; cursor: not-allowed; box-shadow: none; transform: none; }

/* =============== 输入 =============== */
input, select, textarea {
  background: var(--canvas);
  border: var(--line-strong);
  border-radius: 12px;
  padding: 9px 14px;
  font-size: 14px;
  font-family: inherit;
  color: var(--ink);
  transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
input::placeholder, textarea::placeholder { color: var(--ink-subtle); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
select option { background: var(--canvas); color: var(--ink); }
input[type="date"] { color-scheme: light; }
label { display: block; margin-bottom: 8px; color: var(--ink-muted); font-size: 13px; }

.form-row { margin-bottom: 12px; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px 14px; }
/* 网格内的行距交给 gap 控制, 不再叠加 margin(否则行距忽大忽小) */
.form-grid .form-row { margin-bottom: 0; }
/* 网格内的控件一律撑满单元格: 否则 select(满宽)与 input(按内容宽)会参差不齐 */
.form-grid > .form-row > input,
.form-grid > .form-row > select,
.form-grid > .form-row > textarea { width: 100%; }
/* 网格表单后面直接跟按钮/提示时补间距 —— 网格内 .form-row 的 margin 已归零,
   若不补, 按钮会紧贴最后一排字段(表现为"连在一起") */
.form-grid + .btn,
.form-grid + button { margin-top: 18px; }
.form-grid + .form-note,
.form-grid + p { margin-top: 14px; }
/* 固定列数的变体: 字段较多或含长文本下拉时用, 避免被挤成窄条 */
.form-grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.form-grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* 表单底部提交区: 与最后一排字段拉开距离 */
.form-actions { margin-top: 20px; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.form-note { margin-top: 14px; font-size: 13px; line-height: 1.7; color: var(--ink-muted); }
@media (max-width: 900px) {
  .form-grid.cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .form-grid.cols-2, .form-grid.cols-3 { grid-template-columns: 1fr; }
}

/* =============== 表格(密集数据, 白底保可读性) =============== */
table { width: 100%; border-collapse: collapse; background: var(--canvas); }
th, td {
  padding: 10px 12px;
  text-align: left;
  border-bottom: 1px solid rgba(0, 0, 0, .06);
  font-size: 13px;
  vertical-align: middle;
  color: var(--ink);
}
th { background: var(--canvas-alt); color: var(--ink-muted); font-weight: 600; white-space: nowrap; }
tbody tr:hover td { background: #fafafa; }
tbody tr:last-child td { border-bottom: none; }

/* =============== 徽章(低饱和胶囊) =============== */
.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  white-space: nowrap;
  font-weight: 500;
  background: var(--canvas-alt);
  color: var(--ink-muted);
}
.badge.valid    { background: var(--tile-3); color: var(--success); }
.badge.expiring { background: var(--tile-4); color: var(--warn); }
.badge.expired  { background: var(--tile-5); color: var(--danger); }
.badge.void     { background: #f0f0f2; color: var(--ink-muted); }
.badge.active   { background: var(--tile-3); color: var(--success); }
.badge.disabled { background: var(--tile-5); color: var(--danger); }
.badge.admin    { background: var(--tile-1); color: var(--accent); }
/* 到期日未知(识别不出/待补全): 不是"有效"也不是"已过期", 用中性灰表态 */
.badge.unknown  { background: var(--tile-2); color: var(--ink-muted); }

/* =============== 上传后总表: 逐格编辑的反馈 ===============
   需求方 2026-11: "每次上传完以后有一个总表，让我方便改分类错的证书"。
   三件事必须一眼看得出来:
     · 哪一格与本系统读 PDF / 侧车对账的**结果不一致** → .diff-cell(浅黄底)
     · 哪一格刚保存成功 → .save-ok(浅绿边, 1.2s 后自动消失)
     · 哪一格保存失败 → .save-err(红边, 值不丢, 让人重试) */
.diff-cell { background: #fff8e1; }
.diff-cell input { background: #fffdf5; }
.up-in { border: 1px solid transparent; border-radius: 8px; padding: 3px 6px; }
.up-in:hover, .up-in:focus { border-color: var(--border); background: var(--canvas); }
.up-in.save-ok  { border-color: var(--success); background: #f2fbf4; }
.up-in.save-err { border-color: var(--danger);  background: #fff5f6; }

/* =============== 上传: 拖拽区 + 「选择」菜单 ===============
   浏览器没有"一个对话框同时选文件与文件夹"的控件, 所以入口做成:
   一个拖拽区(拖文件、拖文件夹都行) + 一个「选择…」按钮(弹出两个原生选择器)。
   用户看到的仍然只有**一个**上传入口。 */
.dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--card-radius);
  background: var(--canvas-alt);
  padding: 22px 18px;
  text-align: center;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.dropzone:hover, .dropzone:focus-visible { border-color: var(--accent); background: var(--canvas); outline: none; }
.dropzone.dz-over { border-color: var(--accent); background: var(--tile-1); }
.dropzone .dz-title { font-weight: 600; margin-bottom: 4px; }
.dropzone .dz-sub { font-size: 12px; color: var(--ink-muted); }

.menu-wrap { position: relative; display: inline-block; }
.menu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 40;
  min-width: 190px;
  padding: 6px;
  background: var(--canvas);
  border: var(--line-strong);
  border-radius: var(--card-radius);
  box-shadow: var(--shadow-raised);
}
.menu.show { display: block; }
.menu button {
  display: block;
  width: 100%;
  padding: 9px 12px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  text-align: left;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
}
.menu button:hover { background: var(--canvas-alt); }

/* =============== 工具栏/分页 =============== */
.toolbar { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-bottom: 16px; }
.toolbar input, .toolbar select { min-width: 140px; }

/* =============== 消息提示 =============== */
.msg {
  padding: 11px 16px;
  border-radius: 14px;
  margin: 10px 0;
  display: none;
  border: var(--line);
}
.msg.show { display: block; }
.msg.ok  { background: var(--tile-3); color: var(--success); border-color: rgba(26, 127, 75, .18); }
.msg.err { background: var(--tile-5); color: var(--danger);  border-color: rgba(215, 0, 21, .18); }

/* =============== 弹窗 =============== */
.modal-mask {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, .32);
  display: none; align-items: center; justify-content: center;
  z-index: 50;
  padding: 20px;
}
.modal-mask.show { display: flex; }
/* 预览弹窗必须压在**别的弹窗之上**：DOM 里 #preview-modal 排在 #complete-modal / #cert-modal
   前面，两个都是 .modal-mask(50) 时后出现的那个会把它整个盖住（实测：弹窗里点文件名预览，
   PDF 跑到弹窗后面去了）。单独给一层，与 DOM 顺序无关。 */
#preview-modal { z-index: 70; }
.modal {
  background: var(--canvas);
  border: var(--line);
  border-radius: 24px;
  padding: 26px 28px;
  width: 540px;
  max-width: 94vw;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: var(--shadow-modal);
}
.modal h3 { margin-bottom: 16px; color: var(--ink); font-weight: 600; }
.modal .actions { display: flex; gap: 12px; justify-content: flex-end; margin-top: 18px; }

/* ---------- 弹窗顶部的信息磁贴(便当盒语言) ----------
   .bento 是 150px 固定行高的页面网格, 弹窗里不能套它(会撑成 150px);
   这里复用 .tile.row(图标 + 标签 + 数值), 收成**单行**的紧凑信息条 ——
   弹窗里信息条是配角, 别做成整行大横幅(需求方 2026-11 反馈"有点太大了")。 */
.modal-meta { display: flex; margin: 0 0 14px; }
.modal-meta .tile { flex: 0 0 auto; padding: 8px 14px; border-radius: 14px; gap: 10px; }
.modal-meta .tile:hover { transform: none; box-shadow: none; }
.modal-meta .tile.row .tile-icon { width: 30px; height: 30px; flex-basis: 30px; border-radius: 9px; }
.modal-meta .tile.row .tile-icon svg { width: 16px; height: 16px; }
/* ⚠️ 必须是 `.tile.row .tile-body` 这一级选择器：`.tile.row .tile-body`(3 个类) 比
   `.modal-meta .tile-body`(2 个类) 特异度高, 写短了 flex-direction:column 会赢 —— 表现为
   标签/数值分两行、磁贴高 66px（实测踩过）。 */
.modal-meta .tile.row .tile-body { flex-direction: row; align-items: baseline; gap: 8px; }
.modal-meta .meta-label { font-size: 12px; color: var(--ink-muted); white-space: nowrap; }
.modal-meta .meta-value { font-size: 17px; font-weight: 600; letter-spacing: -.2px; color: var(--ink); white-space: nowrap; }

/* =============== 其它 =============== */
.empty { text-align: center; color: var(--ink-muted); padding: 44px 0; }
.muted { color: var(--ink-muted); font-size: 13px; }
.pager { margin-top: 14px; display: flex; justify-content: center; gap: 8px; align-items: center; }
.file-chip { font-size: 12px; color: var(--ink-muted); }
.file-chip a { margin-right: 8px; }

/* =============== 页签(兜底, 内联样式可覆盖) =============== */
.tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
.tab {
  padding: 9px 20px;
  cursor: pointer;
  border-radius: var(--radius-pill);
  font-size: 14px;
  font-family: inherit;
  color: var(--ink);
  background: var(--canvas);
  border: var(--line-strong);
  transition: background .18s ease, color .18s ease, border-color .18s ease;
  user-select: none;
}
.tab:hover { background: var(--canvas-alt); }
.tab.active { color: var(--accent); font-weight: 600; background: var(--tile-1); border-color: transparent; }
.tab-pane { display: none; }
.tab-pane.active { display: block; }

/* =============== 上传进度条 =============== */
.progress-track {
  background: var(--bg-pressed);
  border-radius: var(--radius-pill);
  height: 12px;
  overflow: hidden;
  box-shadow: var(--shadow-pressed);
}
.progress-fill {
  height: 100%;
  background: var(--accent);
  border-radius: var(--radius-pill);
  transition: width .25s ease;
}

/* =============== 结果摘要 =============== */
.result-summary {
  display: flex; gap: 24px; flex-wrap: wrap;
  margin: 12px 0; padding: 14px 18px;
  background: var(--canvas-alt);
  border: var(--line);
  border-radius: 14px;
}
.result-summary b { font-size: 18px; font-weight: 600; }
.ok { color: var(--success); } .warnc { color: var(--warn); } .errc { color: var(--danger); }
.match-row.warn td { background: var(--tile-4); }
.unmatch-row td { background: var(--tile-5); }

/* =============== 移动端 =============== */
@media (max-width: 720px) {
  .container { padding: 0 10px; }
  .toolbar { flex-direction: column; align-items: stretch; }
  .card { padding: 18px; }
  .topbar { padding: 0 12px; }
}

/* ==========================================================================
   布局骨架 — 侧边栏工作台(便当盒皮肤)
   ========================================================================== */
body.shell-body { background: var(--canvas-alt); }

.shell {
  display: flex;
  min-height: 100vh;
  gap: var(--gap);
  padding: var(--gap);
  max-width: 1560px;
  margin: 0 auto;
}

/* ---------- 侧边栏(独立磁贴) ---------- */
.sidebar {
  width: 232px;
  flex: 0 0 232px;
  position: sticky;
  top: var(--gap);
  align-self: flex-start;
  height: calc(100vh - 32px);
  display: flex;
  flex-direction: column;
  padding: 18px 14px;
  border-radius: var(--card-radius);
  background: var(--canvas);
  border: var(--line);
  box-shadow: var(--shadow-card);
}
.side-brand {
  display: flex; align-items: center; gap: 12px;
  padding: 6px 10px 18px;
  margin-bottom: 12px;
}
.brand-logo {
  width: 42px; height: 42px; flex: 0 0 42px;
  border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent);
  color: #fff;
}
.brand-logo svg { width: 22px; height: 22px; }
.brand-text { line-height: 1.3; }
.brand-text .t1 { font-size: 15px; font-weight: 600; color: var(--ink); letter-spacing: .2px; }
.brand-text .t2 { font-size: 11px; color: var(--ink-muted); }

.side-nav { display: flex; flex-direction: column; gap: 6px; flex: 1; overflow: visible; }
.side-item {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px 11px 18px;
  border-radius: 14px;
  color: var(--ink);
  font-size: 14px;
  cursor: pointer;
  user-select: none;
  border: 1px solid transparent;
  background: transparent;
  font-family: inherit;
  text-align: left;
  width: 100%;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
  position: relative;
}
.side-item svg { width: 18px; height: 18px; flex: 0 0 18px; color: var(--ink-muted); }
.side-item:hover { background: var(--canvas-alt); }
.side-item.active {
  background: var(--tile-1);
  color: var(--accent);
  font-weight: 600;
}
.side-item.active svg { color: var(--accent); }
/* active 指示点: 位于项内左侧内边距区域(不越界, 不被裁剪/遮挡) */
.side-item.active::before {
  content: "";
  position: absolute; left: 6px; top: 50%;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
  transform: translateY(-50%);
  animation: dotPulse 2.2s ease-in-out infinite;
  z-index: 2;
}
.side-foot { margin-top: 12px; padding-top: 14px; border-top: var(--line); }

/* ---------- 主区 ---------- */
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.page-head {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px;
  padding: 6px 4px 18px;
}
.page-head h1 { font-size: 28px; font-weight: 600; color: var(--ink); letter-spacing: -.4px; }
.page-head .sub { font-size: 13px; color: var(--ink-muted); margin-top: 2px; }
.page-head .actions { display: flex; align-items: center; gap: 10px; }
.user-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 16px;
  border-radius: var(--radius-pill);
  font-size: 13px; color: var(--ink);
  background: var(--canvas);
  border: var(--line);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
}
.user-chip .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--success); }
.user-chip .name { color: var(--ink); font-weight: 500; }

.content { width: 100%; }

/* ---------- 动效: 入场 ---------- */
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes scaleIn {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes dotPulse {
  0%, 100% { opacity: .55; transform: translateY(-50%) scale(.85); }
  50%      { opacity: 1;   transform: translateY(-50%) scale(1.1); }
}
@keyframes shimmer {
  0%   { background-position: -400px 0; }
  100% { background-position: 400px 0; }
}

/* pane 切换动画 */
.pane-anim-in > .tab-pane.active { animation: fadeUp .26s ease-out both; }
.tab-pane.active.pane-in { animation: fadeUp .24s ease-out both; }
/* 卡片/磁贴入场(浅色皮肤无 blur, 可安全位移) */
.card-anim .card, .card-anim .tile { animation: fadeUp .34s ease-out both; }
.card-anim .bento > .tile:nth-child(2) { animation-delay: .04s; }
.card-anim .bento > .tile:nth-child(3) { animation-delay: .08s; }
.card-anim .bento > .tile:nth-child(4) { animation-delay: .12s; }
.card-anim .bento > .tile:nth-child(5) { animation-delay: .16s; }
.card-anim .bento > .tile:nth-child(6) { animation-delay: .20s; }

/* 模态动效 */
.modal-anim { animation: scaleIn .18s ease-out both; }
.modal-mask.show.modal-fade { animation: fadeIn .18s ease-out both; }

/* 卡片悬浮 */
.card.lift { transition: transform .2s ease, box-shadow .2s ease; }
.card.lift:hover { transform: translateY(-2px); box-shadow: var(--shadow-raised); }

/* 骨架屏 */
.skeleton-wrap { position: relative; }
.skeleton-wrap.loading::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  background:
    linear-gradient(90deg, transparent, rgba(255, 255, 255, .9), transparent),
    rgba(0, 0, 0, .03);
  background-size: 400px 100%;
  animation: shimmer 1.4s linear infinite;
  z-index: 5;
}

/* 状态呼吸点 */
.status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 2px; vertical-align: 1px; flex: 0 0 8px; }
.status-dot.valid    { background: var(--success); }
.status-dot.expiring { background: var(--warn); }
.status-dot.expired  { background: var(--danger); animation: dotPulse2 2s infinite; }
@keyframes dotPulse2 {
  0%, 100% { opacity: .5; transform: scale(.85); }
  50%      { opacity: 1;  transform: scale(1.1); }
}

/* 细滚动条 */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, .14); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, .26); }

/* 页面整体入场 */
body.ui-ready .shell > .sidebar { animation: fadeUp .3s ease-out both; }
body.ui-ready .shell > .main { animation: fadeUp .38s ease-out both; }

/* ========== 窄屏: 便当网格降列 ========== */
@media (max-width: 1100px) {
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tile.w3, .tile.w4 { grid-column: span 2; }
}
@media (max-width: 880px) {
  .shell { flex-direction: column; padding: 10px; gap: 12px; }
  .sidebar {
    position: static;
    width: 100%; flex: none;
    height: auto;
    flex-direction: row;
    align-items: center;
    padding: 10px 12px;
    gap: 8px;
    overflow-x: auto;
  }
  .side-brand { padding: 2px 8px 2px 2px; margin: 0; flex: none; }
  .brand-logo { width: 36px; height: 36px; flex-basis: 36px; border-radius: 12px; }
  .side-nav { flex-direction: row; gap: 6px; flex: 1; }
  .side-item { white-space: nowrap; padding: 9px 13px; }
  .side-item.active::before { display: none; }
  .side-foot { margin: 0; padding: 0; border: none; flex: none; }
  .page-head h1 { font-size: 22px; }
}
@media (max-width: 640px) {
  .bento { grid-template-columns: 1fr; grid-auto-rows: auto; }
  .tile { grid-column: span 1 !important; grid-row: auto !important; padding: 18px; }
  .stat { height: auto; }
  .stat-bar { margin-top: 12px; }
}

/* ========== 动画尊重系统设置 ========== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ================================================================ 客户选择器(二级菜单)
   客户上百家时原生 <select> 没法用; 上传证书第一道闸就是"选对客户", 选错等于串档。
   组件见 js/picker.js —— HTML 里仍是一个普通 <select>, 被接管控件后隐藏。 */
.picker { position: relative; width: 100%; }

.picker-native { display: none; }

.picker-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 9px 12px;
  font: inherit;
  color: var(--ink);
  text-align: left;
  background: var(--canvas);
  border: var(--line-strong);
  border-radius: 12px;
  cursor: pointer;
}
.picker-trigger:hover { background: var(--bg-pressed); }
.picker-trigger:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.picker-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.picker-value.is-empty { color: var(--ink-subtle); }
.picker-caret { color: var(--ink-muted); flex: none; }

.picker-panel {
  position: absolute;
  z-index: 60;
  top: calc(100% + 6px);
  left: 0;
  width: max(100%, 320px);
  max-height: 420px;
  overflow: hidden;
  display: none;
  flex-direction: column;
  background: var(--canvas);
  border: var(--line-strong);
  border-radius: 16px;
  box-shadow: var(--shadow-raised);
}
.picker-panel.show { display: flex; }

.picker-search-row { padding: 10px 10px 6px; }
.picker-search {
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  border: var(--line-strong);
  border-radius: 10px;
  background: var(--canvas-alt);
}
.picker-search:focus { outline: none; box-shadow: var(--focus-ring); }

.picker-group { overflow: auto; }
.picker-group[data-group="recent"] { border-bottom: var(--line); }
.picker-group[data-group="all"] { flex: 1; min-height: 0; }

.picker-group-title {
  position: sticky;
  top: 0;
  padding: 6px 14px;
  font-size: 12px;
  color: var(--ink-muted);
  background: var(--canvas);
}

.picker-list { padding: 0 6px 6px; }

.picker-item {
  padding: 7px 10px;
  border-radius: 10px;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.picker-item:hover, .picker-item.active { background: var(--bg-pressed); }
.picker-item.selected { color: var(--accent); font-weight: 600; }

.picker-more { padding: 6px 10px; font-size: 12px; }

.picker-empty { padding: 14px; text-align: center; color: var(--ink-muted); }
