/* ============ 安诚ERP 管理系统 - 统一样式 ============ */
:root {
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --primary-light: #eff6ff;
  --success: #16a34a;
  --success-light: #f0fdf4;
  --warn: #d97706;
  --warn-light: #fffbeb;
  --danger: #dc2626;
  --danger-light: #fef2f2;
  --gray-bg: #f1f5f9;
  --card-bg: #ffffff;
  --border: #e2e8f0;
  --text: #0f172a;
  --text-2: #475569;
  --text-3: #94a3b8;
  --radius: 10px;
  --shadow: 0 1px 3px rgba(15, 23, 42, .08), 0 4px 14px rgba(15, 23, 42, .06);
  --shadow-lg: 0 10px 40px rgba(15, 23, 42, .18);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif;
  background: var(--gray-bg);
  color: var(--text);
  font-size: 14px;
}
.hidden { display: none !important; }

/* ============ 按钮 ============ */
.btn {
  display: inline-flex; align-items: center; gap: 6px; justify-content: center;
  border: 1px solid var(--border); background: var(--card-bg); color: var(--text);
  border-radius: 8px; padding: 7px 14px; font-size: 13px; cursor: pointer;
  transition: all .15s; white-space: nowrap; line-height: 1.4;
}
.btn:hover { border-color: var(--primary); color: var(--primary); background: var(--primary-light); }
.btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); color: #fff; }
.btn-danger { color: var(--danger); }
.btn-danger:hover { border-color: var(--danger); color: var(--danger); background: var(--danger-light); }
.btn-success { color: var(--success); }
.btn-success:hover { border-color: var(--success); color: var(--success); background: var(--success-light); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-2); }
.btn-ghost:hover { background: rgba(37,99,235,.08); }
.btn-block { width: 100%; }
.btn-sm { padding: 4px 10px; font-size: 12px; border-radius: 6px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* ============ 登录页（商务风 · 左右分栏 + 节点网络图案） ============ */
.login-view { display: flex; min-height: 100vh; background: #f5f8fc; }

/* —— 左侧品牌区 —— */
.login-brand {
  position: relative; overflow: hidden; flex: 1 1 52%; min-width: 0;
  display: flex; flex-direction: column; justify-content: center;
  padding: 58px 56px; color: #fff;
  background: linear-gradient(160deg, #08182c 0%, #10305a 55%, #154a80 100%);
}
.lb-mesh { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.lb-glow {
  position: absolute; left: -120px; top: 18%; width: 560px; height: 560px; pointer-events: none;
  background: radial-gradient(closest-side, rgba(56,132,255,.35), transparent 72%);
}
/* 文案整块在品牌区里居中：宽度用百分比 + 上限（百分比负责宽屏居中，上限别让文字飘到中间），
   max() 里的 430px 是正文自然行宽，屏幕不够宽时不许被挤窄换行。@supports 兜一层老浏览器。
     ★ min-height 464px 用来把文案块撑到与右侧登录表单「首行齐平」
       （用户 2026-10-04 反馈：左栏文案整体比右侧低）。两栏都是垂直居中，而文案块只有 368px、
       比 .login-form（实测 447px）矮一截，居中后顶边必然低 39px，看着就不在一条水平线上。
       推导（左栏 padding 上下都是 58px，M = min-height）：
         左顶 = 58 + (100vh - 58*2 - M)/2 = 100vh/2 - M/2
         右顶 = (100vh - 447)/2          = 100vh/2 - 223.5
         M=447 时两块顶边严格重合；取 464（+17）是再抬高 8.5px，抵消左侧首行文字居中在
         46px logo 方块里造成的视觉下沉，让「安诚ERP」与「欢迎登录」两行字真正落在同一水平线。
       这个差值与视口高度无关 —— 窗口高矮、甚至内容把 .login-view 撑高时，两侧都同步升降。 */
.lb-inner { position: relative; width: 66%; max-width: 620px; margin: 0 auto; min-height: 464px; }
@supports (width: max(66%, 430px)) { .lb-inner { width: max(66%, 430px); } }
.lb-brandrow { position: relative; display: flex; align-items: center; gap: 13px; margin-bottom: 40px; }
.lb-mark {
  width: 46px; height: 46px; border-radius: 13px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(145deg, #3b82f6, #1d4ed8); color: #fff;
  font-size: 21px; font-weight: 700; box-shadow: 0 8px 22px rgba(37,99,235,.45);
}
.lb-name { font-size: 15px; font-weight: 600; letter-spacing: .18em; color: #dbe7f7; }
.lb-slogan {
  position: relative; font-size: 40px; font-weight: 700; line-height: 1.3;
  letter-spacing: .03em; margin-bottom: 16px;
}
.lb-slogan em { font-style: normal; color: #6fa8ff; }
.lb-desc { position: relative; font-size: 14px; line-height: 1.9; color: #a9bdd9; max-width: 430px; }
.lb-feats { position: relative; margin-top: 32px; list-style: none; display: flex; flex-direction: column; gap: 12px; }
.lb-feats li {
  display: flex; align-items: center; gap: 11px; font-size: 13.5px; color: #c9d8ec;
}
.lb-feats li::before {
  content: "✓"; width: 22px; height: 22px; border-radius: 6px; flex-shrink: 0; font-size: 12px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(59,130,246,.18); border: 1px solid rgba(96,165,250,.32); color: #82b6ff;
}

/* —— 右侧表单区 —— */
.login-panel {
  position: relative; overflow: hidden; flex: 1 1 48%; min-width: 0;
  display: flex; align-items: center; justify-content: center; padding: 48px 40px;
}
.login-panel::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .55;
  background-image: radial-gradient(#d8e0ec 1.1px, transparent 1.1px);
  background-size: 26px 26px;
}
.login-form { position: relative; width: 378px; max-width: 100%; }
.login-form h3 { font-size: 24px; font-weight: 700; letter-spacing: .05em; color: #0b1f3a; margin-bottom: 7px; }
.lf-hint { font-size: 13px; color: #8b98aa; margin-bottom: 30px; }
.role-tabs { display: flex; background: var(--gray-bg); border-radius: 10px; padding: 4px; margin-bottom: 20px; }
.role-tab {
  flex: 1; border: none; background: transparent; padding: 8px 4px; border-radius: 8px;
  font-size: 13px; cursor: pointer; color: var(--text-2); transition: all .15s;
}
.role-tab.active { background: var(--card-bg); color: var(--primary); font-weight: 600; box-shadow: 0 1px 4px rgba(15,23,42,.12); }
.login-field { margin-bottom: 17px; }
.login-field label {
  display: block; font-size: 12.5px; font-weight: 600; color: #46566e;
  letter-spacing: .04em; margin-bottom: 8px;
}
.login-field input {
  width: 100%; padding: 12px 14px; border: 1px solid #dee4ee; border-radius: 9px; background: #fff;
  font-size: 14px; outline: none; font-family: inherit; color: var(--text); transition: all .16s;
}
.login-field input::placeholder { color: #aab5c4; }
.login-field input:focus { border-color: var(--primary); box-shadow: 0 0 0 3.5px rgba(37,99,235,.13); }
.lf-row {
  display: flex; align-items: center; justify-content: space-between;
  margin: 2px 0 20px; font-size: 12.5px; color: #8b98aa;
}
.lf-row label { display: flex; align-items: center; gap: 7px; cursor: pointer; }
.lf-row input[type=checkbox] { width: 14px; height: 14px; accent-color: var(--primary); cursor: pointer; }
.lf-row a { color: var(--primary); text-decoration: none; }
.lf-row a:hover { text-decoration: underline; }
.login-submit {
  width: 100%; padding: 13px; border: none; border-radius: 10px; cursor: pointer;
  background: linear-gradient(135deg, #3b82f6, #1d4ed8); color: #fff;
  font-size: 15px; font-weight: 600; letter-spacing: .2em; text-indent: .2em; font-family: inherit;
  box-shadow: 0 10px 24px rgba(29,78,216,.32); transition: all .16s;
}
.login-submit:hover { transform: translateY(-1px); filter: brightness(1.06); box-shadow: 0 14px 30px rgba(29,78,216,.42); }
.login-submit:disabled { opacity: .6; cursor: not-allowed; transform: none; }
.login-error {
  background: var(--danger-light); color: var(--danger); font-size: 13px;
  border-radius: 8px; padding: 9px 12px; margin-bottom: 14px; text-align: left;
}
.login-tip { font-size: 12px; color: #98a3b3; line-height: 1.75; margin-top: 18px; }
.login-foot {
  margin-top: 20px; padding-top: 14px; border-top: 1px solid #eef1f6;
  font-size: 11px; color: #aab4c2; letter-spacing: .06em;
}

/* —— 窄屏：品牌区收成顶部条，表单占满 —— */
@media (max-width: 880px) {
  .login-view { flex-direction: column; }
  .login-brand { flex: 0 0 auto; padding: 26px 22px 24px; justify-content: flex-start; }
  .lb-inner { width: 100%; min-height: 0; }   /* 窄屏品牌条只留 logo 行，别撑出 447px 的空块 */
  .lb-brandrow { margin-bottom: 0; }
  .lb-slogan, .lb-desc, .lb-feats { display: none; }
  .login-panel { flex: 1 1 auto; align-items: flex-start; padding: 30px 22px 44px; }
  .login-form { width: 100%; max-width: 420px; margin: 0 auto; }
}

/* ============ 登录 ⇄ 主界面 过渡动画 ============
   思路：切页时把「离场方」提升为 fixed 覆盖层（z-index 200），
   这样它脱离文档流、不把对方挤下去，两边就能安全交叠 → 交叉淡入淡出。 */
.login-view.is-leaving,
.login-view.is-arriving { position: fixed; inset: 0; z-index: 200; }

/* 登录页退场（登录成功） */
.login-view.is-leaving { animation: loginFadeOut .34s ease both; pointer-events: none; }
@keyframes loginFadeOut {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(1.018); }
}
/* 登录页入场（退出登录） */
.login-view.is-arriving { animation: loginArrive .36s ease both; }
@keyframes loginArrive {
  from { opacity: 0; transform: scale(1.018); }
  to   { opacity: 1; transform: none; }
}

/* 主界面入场：整屏淡入 + 侧栏左滑 + 内容上浮（错开 80ms 做层次） */
.app-view.is-entering { animation: appFadeIn .4s ease both; }
@keyframes appFadeIn { from { opacity: 0; } to { opacity: 1; } }
.app-view.is-entering .sidebar { animation: navSlideIn .5s cubic-bezier(.22,.75,.28,1) both; }
@keyframes navSlideIn { from { opacity: 0; transform: translateX(-16px); } to { opacity: 1; transform: none; } }
.app-view.is-entering .main { animation: mainRiseIn .5s cubic-bezier(.22,.75,.28,1) .08s both; }
@keyframes mainRiseIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.app-view.is-leaving { pointer-events: none; }

/* 登录按钮加载态 */
.login-submit.is-loading { text-indent: 0; letter-spacing: .1em; cursor: progress; }
.btn-spin {
  display: inline-block; width: 14px; height: 14px; margin-right: 9px; vertical-align: -2px;
  border: 2px solid rgba(255,255,255,.35); border-top-color: #fff; border-radius: 50%;
  animation: btnSpin .7s linear infinite;
}
@keyframes btnSpin { to { transform: rotate(360deg); } }

/* 尊重系统「减少动态效果」设置：保留状态切换，去掉运动 */
@media (prefers-reduced-motion: reduce) {
  .login-view.is-leaving, .login-view.is-arriving,
  .app-view.is-entering, .app-view.is-entering .sidebar, .app-view.is-entering .main {
    animation-duration: .01ms !important;
  }
}

/* ============ 布局 ============ */
/* 2026-10-20：min-height → height + overflow:hidden。
   原来只写 min-height:100vh，内容一旦比视口高（异步数据回来前的中间态、维护横幅、
   某个表格行多出来一点），整个文档就长出滚动条；滚动条一出，可用宽度从 1512 掉到 1497，
   数据到位后滚动条消失又弹回 1512 —— 肉眼看到的就是「整个工作区横向抽了一下」。
   本系统所有内容都在 .page-tab 里自己滚（.page-tab { overflow-y: auto }），
   文档本来就不该滚，所以这里直接封死，任何中间态溢出都只是被裁掉、不产生滚动条。 */
.app-view { display: flex; height: 100vh; overflow: hidden; }
/* ⚠️ 侧栏宽度下限 188px＝品牌名「安诚ERP 管理系统」单行所需（实测 187.9px，见 tests/render-check-sidebar-width.html）。
   最长菜单项只需 169px，故品牌名是唯一的宽度约束；再想收窄必须同步缩短品牌文案。 */
.sidebar {
  width: 200px; background: #0f172a; color: #cbd5e1; display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh; flex-shrink: 0;
}
.sidebar-brand {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 15px; font-size: 14px; font-weight: 600; color: #f1f5f9;
  letter-spacing: .01em; border-bottom: 1px solid rgba(255,255,255,.06);
}
/* 品牌名兜底：万一被更窄的宽度挤到，宁可出省略号也不要折成两行（折行会顶高品牌行、看着像坏了） */
.brand-text { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brand-mark {
  width: 26px; height: 26px; border-radius: 7px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #3b82f6, #2563eb);
  color: #fff; font-size: 14px; font-weight: 700; line-height: 1;
}
.sidebar-nav { flex: 1; padding: 10px 10px 16px; overflow-y: auto; }
.sidebar-nav::-webkit-scrollbar { width: 6px; }
.sidebar-nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.1); border-radius: 3px; }

/* ——— 一级菜单项（顶层 / 分组内的页面） ——— */
.nav-item {
  position: relative; display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; margin-bottom: 2px; border-radius: 7px;
  cursor: pointer; color: #94a3b8; font-size: 13.5px; line-height: 20px;
  transition: background .15s, color .15s;
}
.nav-item:hover { color: #e2e8f0; background: rgba(255,255,255,.05); }
.nav-item.active { color: #f8fafc; background: rgba(59,130,246,.16); font-weight: 500; }
.nav-item.active::before {
  content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 2px; height: 16px; border-radius: 0 2px 2px 0; background: #3b82f6;
}
.nav-item.active .nav-icon { color: #60a5fa; }
.nav-icon { display: flex; align-items: center; justify-content: center; width: 18px; height: 18px; flex-shrink: 0; }
.nav-icon svg { width: 17px; height: 17px; }
.nav-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-badge { margin-left: auto; background: var(--danger, #e5484d); color: #fff; font-size: 11px; font-weight: 600; min-width: 18px; height: 18px; line-height: 18px; border-radius: 9px; text-align: center; padding: 0 5px; }

/* ============ 导航分组折叠（二期地基） ============
   分组头只当「标签」使：小号 + 字距 + 更暗的色阶，不配图标，避免与菜单项抢视觉重量 */
.nav-group { margin-top: 14px; }
.nav-group-head {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 10px 5px 6px; border-radius: 6px;
  cursor: pointer; user-select: none;
  color: #64748b; font-size: 11px; font-weight: 600; letter-spacing: .08em;
  transition: color .15s, background .15s;
}
.nav-group-head:hover { color: #94a3b8; background: rgba(255,255,255,.03); }
.nav-group.has-current .nav-group-label { color: #cbd5e1; }
.nav-group-caret { display: flex; width: 13px; height: 13px; flex-shrink: 0; opacity: .85; transition: transform .18s; }
.nav-group-caret svg { width: 100%; height: 100%; }
.nav-group.is-collapsed .nav-group-caret { transform: rotate(-90deg); }
.nav-group-label { flex: 1; }
.nav-group-count { font-size: 10.5px; font-weight: 500; color: #475569; letter-spacing: 0; }

/* 子项：整体缩进一档 + 左侧导引线，和分组头拉开层级 */
.nav-group-body {
  position: relative; display: flex; flex-direction: column; gap: 1px;
  margin: 3px 0 0 12px; padding-left: 11px;
}
.nav-group-body::before {
  content: ''; position: absolute; left: 0; top: 5px; bottom: 5px; width: 1px;
  background: rgba(255, 255, 255, .11);
}
.nav-group-body .nav-item { padding: 8px 10px; margin-bottom: 0; font-size: 13px; }
/* 子项选中时把左侧导引线这一段点亮，而不是再堆一块背景 */
.nav-group-body .nav-item.active::before { left: -11px; background: #3b82f6; }
.nav-group.is-collapsed .nav-group-body { display: none; }

/* 审批中心 */
.ap-form-hint { background: #fffbeb; border: 1px solid #fcd34d; color: #92400e; border-radius: 10px; padding: 10px 14px; font-size: 13px; margin-bottom: 14px; }
.ap-diff-row { display: flex; align-items: baseline; gap: 10px; padding: 8px 0; border-bottom: 1px dashed var(--border, #e5e7eb); font-size: 13px; }
.ap-diff-label { min-width: 130px; color: var(--text-sub, #6b7280); flex-shrink: 0; }
.ap-diff-old { color: #b91c1c; background: #fef2f2; border-radius: 6px; padding: 2px 8px; text-decoration: line-through; }
.ap-diff-arrow { color: var(--text-sub, #6b7280); }
.ap-diff-new { color: #166534; background: #f0fdf4; border-radius: 6px; padding: 2px 8px; font-weight: 500; }

/* ============ 审批详情（变更摘要 / 分类正文 / 调价明细） ============ */
.ap-summary {
  background: var(--primary-light); border: 1px solid #c7d9ff; color: #1e3a8a;
  border-radius: 10px; padding: 12px 15px; font-size: 14px; font-weight: 600; line-height: 1.6;
}
.ap-sec { margin-top: 20px; }
.ap-sec-title {
  font-size: 13px; font-weight: 600; color: var(--text-2); line-height: 1.3;
  margin-bottom: 6px; padding-left: 9px; border-left: 3px solid var(--primary);
}
.ap-kv { display: flex; align-items: baseline; gap: 10px; padding: 7px 0; border-bottom: 1px dashed var(--border); font-size: 13px; }
.ap-kv > b { min-width: 132px; flex-shrink: 0; font-weight: 400; color: var(--text-2); }
.ap-kv > span { color: var(--text); word-break: break-word; }
.ap-sec .empty-state { padding: 16px 12px; font-size: 13px; }
.ap-form-hint.danger { background: var(--danger-light); border-color: #fca5a5; color: #991b1b; }
.ap-chg { width: 100%; border-collapse: collapse; font-size: 13px; }
.ap-chg th, .ap-chg td { padding: 6px 10px; border-bottom: 1px solid var(--border); text-align: left; white-space: nowrap; }
.ap-chg th { color: var(--text-2); font-weight: 500; background: var(--gray-bg); }
.ap-chg tbody tr:hover { background: #f8fafc; }
.ap-chg .num { text-align: right; font-variant-numeric: tabular-nums; }
.ap-up { color: #b91c1c; font-weight: 600; }     /* 涨价：红（成本上浮，需要盯） */
.ap-down { color: #15803d; font-weight: 600; }   /* 降价：绿 */
.ap-add { color: #1d4ed8; font-weight: 600; }
.ap-drop { color: #94a3b8; text-decoration: line-through; }
/* 凭证展示（报销明细 / 审批详情）：一排 3 张「大图」，不点开就能基本看清票面。
   contain 不裁剪 + 白底：发票照片整张可见；高度固定 320px 保证三张行高一致。 */
.ap-photos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.ap-photos a {
  width: 100%; height: 320px; border-radius: 8px; border: 1px solid var(--border);
  overflow: hidden; background: #fff;
  display: flex; align-items: center; justify-content: center;
}
.ap-photos img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* 凭证文件被清理掉时不显示裂图，给一句人话。
   ⚠️ 用 ::before 而不是 ::after：有「补传这张」按钮时，::after 会排在按钮**下面**，
      读起来就是「先给按钮、再说文件丢了」。::before 保证文案在上、按钮在下。 */
.ap-photos a.ap-photo-missing::before {
  content: "凭证文件已丢失"; font-size: 11px; color: var(--text-3);
  text-align: center; line-height: 1.4; padding: 0 8px;
}
/* 2026-10-20：丢失的凭证给一个「原位置补传」出口（默认隐藏，只在 .ap-photo-missing 时露出来）。
   竖向排：「凭证文件已丢失」在上、按钮在下，不挤在一行。 */
.ap-photos a.ap-photo-missing { flex-direction: column; gap: 10px; cursor: default; }
.ap-photos .ap-repair { display: none; font-size: 12px; padding: 4px 12px; border-radius: 6px;
  border: 1px solid #2563eb; color: #2563eb; background: #fff; cursor: pointer; white-space: nowrap; }
.ap-photos a.ap-photo-missing .ap-repair { display: inline-block; }
.ap-photos .ap-repair:hover { background: #eff6ff; }
/* 审批列表：列多且内容长，横向滚动而不是把列挤到换行 */
.ap-table { min-width: 1200px; }
.ap-table th, .ap-table td { white-space: nowrap; padding: 10px 11px; }
/* 除摘要外的长文本列都限宽折行，把宽度让给「申请内容」和「操作」 */
.ap-table th:nth-child(2), .ap-table td:nth-child(2),
.ap-table th:nth-child(3), .ap-table td:nth-child(3),
.ap-table th:nth-child(5), .ap-table td:nth-child(5),
.ap-table th:nth-child(6), .ap-table td:nth-child(6) { white-space: normal; }
.ap-table td:nth-child(2) { min-width: 110px; max-width: 152px; }
.ap-table td:nth-child(3) { min-width: 180px; max-width: 205px; }
.ap-table td:nth-child(5) { min-width: 128px; max-width: 172px; }
.ap-table td:nth-child(6) { min-width: 128px; max-width: 180px; }
/* 「申请内容」列：摘要最多两行，完整内容鼠标悬停可见 */
.ap-sum-col { min-width: 300px; max-width: 330px; }
.ap-table th:nth-child(7) { min-width: 280px; }
.ap-table td.ap-sum { white-space: normal; max-width: 400px; }
/* 摘要在单元格内做两行截断（不把 td 改成 -webkit-box，避免破坏表格布局） */
.ap-clamp {
  line-height: 1.5; color: var(--text-2);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.btn-detail { border-color: #93b4f8; color: var(--primary); background: var(--primary-light); }
.btn-detail:hover { background: var(--primary); color: #fff; border-color: var(--primary); }
/* 侧栏底部「同事访问」提示已于 2026-10-20 上云后移除（系统改为统一公网地址访问，
   本机局域网地址对使用者已无意义）。原来的 .sidebar-footer / .lan-tip 一并删除，
   侧栏底部一区现在就是「系统设置 + 使用说明书」，直接贴着侧栏底边。 */
.user-chip { font-size: 12px; color: #94a3b8; margin-bottom: 10px; line-height: 1.6; }
.user-chip b { color: #e2e8f0; }
.main { flex: 1; padding: 24px 28px; min-width: 0; }

/* ============ 全局顶栏（跑马灯 + 消息中心，2026-10-03） ============ */
/* min-height:0（2026-10-20）：不加的话子项（.pages-wrap）的 min-height 默认按内容算，
   内容一高就把主列顶高 —— 竖排 flex 里必须显式允许收缩。 */
.app-main-col { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.topbar {
  height: 50px; flex: none; background: var(--card-bg); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px; padding: 0 18px; position: relative; z-index: 20;
}
/* 跑马灯：内容不足一屏时复制一份实现无缝衔接；悬停暂停方便阅读 */
.marquee {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; height: 30px;
  background: var(--primary-light); border: 1px solid #dbeafe; border-radius: 20px; padding: 0 12px; overflow: hidden;
}
.marquee-label { flex: none; font-size: 11.5px; font-weight: 600; color: var(--primary); }
.marquee-track { flex: 1; min-width: 0; overflow: hidden; height: 30px; display: flex; align-items: center; }
.marquee-items { display: flex; gap: 44px; white-space: nowrap; animation: mqScroll 28s linear infinite; padding-left: 100%; }
.marquee:hover .marquee-items { animation-play-state: paused; }
@keyframes mqScroll { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.marquee-item { font-size: 12.5px; color: var(--text-2); }
.marquee-item b { color: var(--text); font-weight: 600; }
.marquee-empty { font-size: 12.5px; color: var(--text-3); }
.topbar-right { flex: none; display: flex; align-items: center; gap: 12px; }
.bell {
  position: relative; width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center;
  background: #f8fafc; border: 1px solid var(--border); cursor: pointer;
}
.bell:hover { background: var(--primary-light); border-color: #bfdbfe; }
.bell-count {
  position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; line-height: 16px; padding: 0 5px;
  background: var(--danger); color: #fff; font-size: 10.5px; font-weight: 700; border-radius: 9px;
  text-align: center; border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
}
/* 右上角用户按钮 + 下拉菜单（侧栏底部的用户信息与退出按钮已移到这里，2026-10-03） */
.topbar-user {
  display: flex; align-items: center; gap: 8px; padding: 4px 8px 4px 4px; border-radius: 20px;
  cursor: pointer; border: 1px solid transparent; flex: none;
}
.topbar-user:hover { background: #f8fafc; border-color: var(--border); }
.topbar-user.on { background: #f8fafc; border-color: var(--border); }
.avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: none; color: #fff;
  background: linear-gradient(135deg, #2563eb, #38bdf8);
  display: grid; place-items: center; font-size: 12.5px; font-weight: 600;
}
.tu-text { line-height: 1.25; }
.tu-text b { display: block; font-size: 12.5px; color: var(--text); font-weight: 600; }
.tu-text span { font-size: 11px; color: var(--text-3); }
.tu-caret { color: var(--text-3); transition: transform .15s; flex: none; }
.topbar-user.on .tu-caret { transform: rotate(180deg); }
.user-menu {
  position: absolute; top: 56px; right: 16px; width: 232px; background: #fff;
  border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow-lg); z-index: 70; overflow: hidden;
}
.um-head { padding: 13px 14px; border-bottom: 1px solid var(--border); display: flex; gap: 10px; align-items: center; background: #f8fafc; }
.um-info { min-width: 0; }
.um-info b { display: block; font-size: 13.5px; }
.um-info span { font-size: 11.5px; color: var(--text-3); }
.um-item { display: flex; align-items: center; gap: 9px; padding: 9px 14px; font-size: 12.5px; color: var(--text-2); cursor: pointer; }
.um-item:hover { background: #f8fbff; color: var(--text); }
.um-item svg { width: 15px; height: 15px; flex: none; opacity: .8; }
.um-item.danger { color: var(--danger); }
.um-item.danger:hover { background: var(--danger-light); }
.um-sep { height: 1px; background: var(--border); }
/* 修改密码弹窗：强度条 + 错误提示
   注意：.form-field 是 flex 布局，强度条/提示必须包在 .pwd-wrap 里独占一行，
   否则会被当成并列的 flex item 挤到输入框右侧。 */
.pwd-wrap { width: calc(100% - 114px); margin: -6px 0 10px 114px; }
/* 必填校验失败时的输入框红框反馈 */
.input.is-error { border-color: var(--danger) !important; box-shadow: 0 0 0 3px rgba(220, 38, 38, .1); }
.pwd-err {
  background: var(--danger-light); border: 1px solid #fecaca; color: #b91c1c;
  border-radius: 8px; padding: 8px 11px; font-size: 12px; margin-bottom: 12px;
}
.pwd-strength { display: flex; gap: 5px; margin-top: 7px; }
.pwd-strength i { height: 4px; flex: 1; border-radius: 2px; background: var(--border); transition: background .2s; }
.pwd-strength.s1 i:nth-child(1) { background: var(--danger); }
.pwd-strength.s2 i:nth-child(-n+2) { background: var(--warn); }
.pwd-strength.s3 i:nth-child(-n+3) { background: #0d9488; }
.pwd-strength.s4 i { background: var(--success); }
.pwd-hint { font-size: 11.5px; color: var(--text-3); margin-top: 4px; }
/* 消息中心下拉 */
.msg-pop {
  position: absolute; top: 56px; right: 16px; width: 420px; max-width: calc(100vw - 40px);
  background: #fff; border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow-lg);
  z-index: 60; overflow: hidden;
}
.msg-pop-head { padding: 12px 14px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 8px; }
.msg-pop-head b { font-size: 13.5px; }
.msg-pop-mark { margin-left: auto; font-size: 12px; color: var(--primary); cursor: pointer; }
.msg-tabs { display: flex; gap: 6px; padding: 10px 14px; border-bottom: 1px solid var(--border); background: #f8fafc; }
.msg-tab { font-size: 12px; padding: 4px 10px; border-radius: 14px; background: #fff; border: 1px solid var(--border); color: var(--text-2); cursor: pointer; }
.msg-tab.on { background: var(--primary); border-color: var(--primary); color: #fff; }
.msg-list { max-height: 340px; overflow: auto; }
.msg-sec { padding: 7px 14px; background: #f8fafc; font-size: 11.5px; color: var(--text-3); border-bottom: 1px solid #f1f5f9; }
.msg-row { display: flex; gap: 10px; padding: 11px 14px; border-bottom: 1px solid #f1f5f9; cursor: pointer; align-items: flex-start; }
.msg-row:hover { background: #f8fbff; }
.msg-row.unread { background: #fcfdff; }
.msg-ico { width: 30px; height: 30px; border-radius: 8px; display: grid; place-items: center; font-size: 14px; flex: none; }
.msg-main { flex: 1; min-width: 0; }
.msg-title { font-size: 12.5px; color: var(--text); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.msg-row.unread .msg-title { font-weight: 600; }
.msg-newdot { width: 6px; height: 6px; border-radius: 50%; background: var(--danger); flex: none; }
.msg-body { font-size: 12px; color: var(--text-2); margin-top: 2px; line-height: 1.5; }
.msg-meta { font-size: 11px; color: var(--text-3); margin-top: 3px; }
.msg-go { font-size: 11.5px; color: var(--primary); flex: none; align-self: center; }
.msg-pop-foot { padding: 9px 14px; text-align: center; background: #f8fafc; font-size: 12px; color: var(--text-3); }
.msg-lv { font-size: 10.5px; padding: 1px 6px; border-radius: 4px; font-weight: 600; }
.msg-lv.info { background: var(--primary-light); color: var(--primary); }
.msg-lv.warn { background: var(--warn-light); color: var(--warn); }
.msg-lv.urgent { background: var(--danger); color: #fff; }
/* 公告查看弹窗 */
.notice-view { line-height: 1.85; }
.notice-view h4 { margin: 0 0 8px; font-size: 15px; }
.notice-view .nv-meta { font-size: 12px; color: var(--text-3); margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--border); }
.notice-view .nv-body { font-size: 13.5px; color: var(--text-2); white-space: pre-wrap; }

/* ============ 页面头部 ============ */
.page-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; flex-wrap: wrap; gap: 12px; }
.page-title { font-size: 20px; font-weight: 700; }
.page-title small { display: block; font-size: 12px; color: var(--text-3); font-weight: 400; margin-top: 4px; }
/* 页头动作按钮：grid + 1fr 让同排按钮**等宽**（基准=最宽那个），不再随文字长短参差；
   收缩适应容器下 1fr 会按最大内容均分（Chrome 按规范实现）。锁定高度，emoji 行盒不再影响。
   ⚠️ grid 不换行：按钮极多或窗口极窄时可能溢出，目前各页 ≤4 个、总和 <600px，够用。 */
.page-actions { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 10px; }
.page-actions .btn { height: 32px; padding: 0 12px; }

/* ============ 卡片 ============ */
.card { background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px 20px; margin-bottom: 18px; }
.card-title { font-size: 14px; font-weight: 600; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }

/* ============ 搜索 / 筛选区 ============ */
.filter-bar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
/* 筛选条里的按钮与控件同高（36px），否则「查询/重置」比旁边的下拉/日期矮一截 */
.filter-bar .btn { height: 36px; padding-top: 0; padding-bottom: 0; }
.search-input {
  position: relative; flex: 0 1 220px; min-width: 170px; max-width: 260px;
}
.search-input input {
  width: 100%; height: 36px; padding: 0 12px 0 32px; border: 1px solid var(--border); border-radius: 8px;
  font-size: 13px; outline: none; transition: border .15s; background: var(--card-bg);
}
.search-input::before {
  content: '🔍'; position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  font-size: 12px; opacity: .55; pointer-events: none;
}
.search-input input:focus { border-color: var(--primary); }
/* 筛选条内文本筛选（片区/楼层等）：弹性伸缩自适应，保证提示文案完整可见 */
.filter-bar > .filter-item.filter-text { flex: 1 1 215px; min-width: 215px; max-width: 300px; }

/* 资质照片上传（证书 / 保险类字段） */
.cert-thumbs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; align-items: center; }
.cert-thumb { position: relative; width: 54px; height: 54px; border-radius: 6px; overflow: hidden; border: 1px solid var(--border); flex: 0 0 auto; }
.cert-thumb img { width: 100%; height: 100%; object-fit: cover; cursor: zoom-in; display: block; }
.cert-del { position: absolute; top: 0; right: 0; width: 17px; height: 17px; line-height: 15px; text-align: center; background: rgba(15,23,42,.6); color: #fff; border: none; border-radius: 0 0 0 6px; cursor: pointer; font-size: 12px; padding: 0; }
.cert-del:hover { background: var(--danger); }
.cert-add { display: inline-flex; align-items: center; justify-content: center; width: 54px; height: 54px; border: 1px dashed var(--border); border-radius: 6px; cursor: pointer; font-size: 12px; color: var(--text-2); text-align: center; user-select: none; }
.cert-add:hover { border-color: var(--primary); color: var(--primary); }
/* 报销「发票 / 凭证」上传区（2026-10-03 二次调整）：与详情展示同尺寸 —— 一排 3 张大图，最多 5 张 */
.cert-thumbs.ex-inv {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
  align-items: start; margin-top: 8px;
}
.cert-thumbs.ex-inv .cert-thumb { width: 100%; height: 320px; border-radius: 8px; background: #fff; }
.cert-thumbs.ex-inv .cert-thumb img { cursor: zoom-in; object-fit: contain; }
.cert-thumbs.ex-inv .cert-del { width: 24px; height: 24px; line-height: 22px; font-size: 15px; border-radius: 0 0 0 8px; }
.cert-thumbs.ex-inv .cert-add {
  width: 100%; height: 320px; border-radius: 8px; font-size: 15px;
  flex-direction: column; gap: 4px; line-height: 1.5; padding: 8px;
}
.cert-thumbs.ex-inv .cert-add em { font-style: normal; font-size: 12px; color: var(--text-3); }
.cert-thumbs.ex-inv .cert-add em { font-style: normal; font-size: 11px; color: var(--text-3); }
.cert-thumbs.ex-inv .cert-add.is-full { border-style: solid; color: var(--text-3); cursor: default; }
.cert-thumbs.ex-inv .cert-add.is-full:hover { border-color: var(--border); color: var(--text-3); }
.ex-inv-count { margin-left: 8px; color: var(--text-3); font-variant-numeric: tabular-nums; }
/* 报销发票 / 凭证：理赔式「点选 + 拖拽 + 粘贴」上传区（与 .ins-upbox 同一套语汇） */
.ex-inv-drop { margin: 10px 0 0; padding: 14px 10px; text-align: center; font-size: 12.5px; color: var(--text-3);
  border: 1px dashed var(--border); border-radius: 8px; background: var(--bg-2, #f7f8fa); user-select: none; }
.ex-inv-drop b { color: var(--text-2); }
.ex-inv-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.ex-inv-bar .btn { white-space: nowrap; }
#exInvSec.drop-on .ex-inv-drop { border-color: var(--primary); border-style: solid; color: var(--primary); }
#exInvSec.drop-on .ex-inv-drop::after { content: '（松手即上传）'; color: var(--primary); }
.detail-certs { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-left: 8px; vertical-align: middle; }
.detail-cert { width: 64px; height: 64px; object-fit: cover; border-radius: 6px; border: 1px solid var(--border); cursor: zoom-in; display: block; }
.filter-toggle { color: var(--text-2); }
.filter-toggle .arrow { display: inline-block; transition: transform .2s; }
.filter-toggle.open .arrow { transform: rotate(180deg); }

.more-filters {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 12px 16px; padding: 14px 4px 4px; border-top: 1px dashed var(--border);
  overflow: hidden;
}
.more-filters .filter-item label { display: block; font-size: 12px; color: var(--text-2); margin-bottom: 4px; }
.anim-collapse { transition: grid-template-rows .25s ease, opacity .2s ease; display: grid; }
.anim-collapse.closed { grid-template-rows: 0fr; opacity: 0; pointer-events: none; }
.anim-collapse > * { overflow: hidden; min-height: 0; }

/* ============ 统一表单控件（输入框/下拉/日期） ============ */
.ctrl {
  width: 100%; padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px;
  font-size: 13px; color: var(--text); background: var(--card-bg); outline: none;
  transition: border .15s, box-shadow .15s; font-family: inherit; line-height: 1.5;
}
.ctrl:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37,99,235,.1); }
.ctrl.invalid { border-color: var(--danger); box-shadow: 0 0 0 3px rgba(220,38,38,.08); }
select.ctrl { appearance: none; background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%2394a3b8' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 30px; }
textarea.ctrl { resize: vertical; min-height: 70px; }
/* 单行控件统一高度（2026-10-13）：Chrome 里 select 内容盒比 input 矮 ~4px、date 的日历件又比 input 偏高，
   同一排筛选控件高矮不一 —— text / select / date 显式锁同一高度（36px），内容由浏览器垂直居中 */
select.ctrl, input.ctrl { height: 36px; padding-top: 0; padding-bottom: 0; }

/* ============ 折叠分组面板（两个窗体完全一致） ============ */
.form-panel { background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 16px; overflow: hidden; border: 1px solid transparent; }
.form-panel-head {
  display: flex; align-items: center; gap: 10px; padding: 14px 20px; cursor: pointer;
  user-select: none; transition: background .15s;
}
.form-panel-head:hover { background: #f8fafc; }
.form-panel-head .p-icon {
  width: 26px; height: 26px; border-radius: 7px; background: var(--primary-light);
  color: var(--primary); display: inline-flex; align-items: center; justify-content: center; font-size: 13px;
}
.form-panel-head .p-title { font-size: 14px; font-weight: 600; flex: 1; }
.form-panel-head .p-chev { color: var(--text-3); transition: transform .25s; font-size: 12px; }
.form-panel.open .p-chev { transform: rotate(180deg); }
.form-panel-body-wrap { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .28s ease; }
.form-panel:not(.open) .form-panel-body-wrap { grid-template-rows: 0fr; }
.form-panel-body { overflow: hidden; min-height: 0; }
.form-panel-inner { padding: 4px 20px 20px; }

/* ============ 表单字段网格 ============ */
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px 32px; }
.form-field { display: flex; align-items: flex-start; padding: 7px 0; min-height: 46px; }
.form-field > label {
  width: 128px; flex-shrink: 0; font-size: 13px; color: var(--text-2); line-height: 32px; text-align: right;
  padding-right: 14px;
}
.form-field > label .req { color: var(--danger); margin-left: 2px; }
.form-field .field-ctrl { flex: 1; min-width: 0; }
.form-field .field-ctrl .ctrl { line-height: 1.5; }
.form-field.full { grid-column: 1 / -1; }
.form-field .field-err { color: var(--danger); font-size: 12px; margin-top: 4px; display: none; }
.form-field.has-err .field-err { display: block; }
.field-hint { font-size: 12px; color: var(--text-3); margin-top: 4px; }

/* 多选 chips */
.chips { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 4px; }
.chip {
  border: 1px solid var(--border); border-radius: 16px; padding: 4px 14px; font-size: 13px;
  cursor: pointer; user-select: none; transition: all .15s; background: var(--card-bg); color: var(--text-2);
}
.chip:hover { border-color: var(--primary); color: var(--primary); }
.chip.on { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 500; }
.chip.on::before { content: '✓ '; }
.chip.on:hover { background: var(--primary-dark); border-color: var(--primary-dark); color: #fff; }

/* 联动显隐动画（两个窗体一致） */
.linked-field { display: grid; grid-template-rows: 1fr; opacity: 1; transition: grid-template-rows .25s ease, opacity .2s ease; }
.linked-field.hidden-link { grid-template-rows: 0fr; opacity: 0; pointer-events: none; height: 0; overflow: hidden; }
.linked-field > .lf-inner { overflow: hidden; min-height: 0; }

/* 表单底部 */
.form-footer {
  display: flex; justify-content: flex-end; gap: 12px; padding: 16px 20px;
  background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow);
  position: sticky; bottom: 12px; border: 1px solid var(--border);
}

/* ============ 数据表格 ============ */
/* 财务表格容器：宽屏不滚动，列多时可横向滚动（配合操作列右侧固定） */
.table-wrap { background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow); overflow-x: auto; overflow-y: hidden; }
table.data-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.data-table th {
  text-align: left; padding: 11px 14px; background: #f8fafc; color: var(--text-2);
  font-weight: 600; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.data-table td { padding: 11px 14px; border-bottom: 1px solid #f1f5f9; vertical-align: middle; }
.data-table tbody tr { transition: background .12s; }
.data-table tbody tr:hover { background: #f8fbff; }
.data-table .cell-id { color: var(--text-3); font-size: 12px; }
/* 同理：操作列禁止换行（否则窄窗口/浏览器缩放时会折行） */
.data-table .cell-actions { white-space: nowrap; display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
.data-table .empty-row td { text-align: center; color: var(--text-3); padding: 40px 0; }
/* 列表内品类标签：紧凑换行，便于一行内看全师傅可安装能力 */
.data-table .cell-cats-col { min-width: 240px; }
/* 特殊标签列：比品类列窄一些（通常 1~3 个标签），同样紧凑换行 */
.data-table .cell-tags-col { min-width: 150px; }
.data-table .cell-tags-col .cell-cats { max-width: 260px; }
.data-table .cell-cats { display: flex; flex-wrap: wrap; gap: 3px; max-width: 320px; }
.data-table .cell-cats .tag { font-size: 11px; padding: 1px 8px; border-radius: 10px; }
.data-table .cell-cats .tag + .tag { margin-left: 0; }
.data-table .cell-none { color: var(--text-3); }

/* 长文本列（面试备注，2026-10-10）：限宽 + 最多 3 行截断 + 悬停浮层看全文 —— 与报销列表「说明」列同款。
   ⚠️ 表格铁律：td/th 不能改 display（所以不用 -webkit-line-clamp，它要 display:-webkit-box），
   限高只能落在内层 div 上；td 保持 table-cell，列宽仍由浏览器自适应。
   ⚠️ 选择器必须带 `.data-table td` 前缀 —— `.data-table td{padding:11px 14px;vertical-align:middle}`
   是 (0,1,1)，裸类名 (0,1,0) 压不过它（与数字列 / 操作列同一个坑）。 */
.data-table td.cell-desc { width: 240px; min-width: 200px; max-width: 320px; white-space: normal; vertical-align: top; }
.data-table th.cell-desc-h { min-width: 200px; }
.data-table td.cell-desc > .cell-desc-in {
  font-size: 12.5px; color: var(--text-2); line-height: 1.55;
  max-height: 58px;            /* 约 3 行（12.5 × 1.55 ≈ 19.4px） */
  overflow: hidden; word-break: break-word; overflow-wrap: anywhere;
  cursor: default;
}
/* 只有被截断的单元格才加 is-hoverable（JS 判定），悬停给一点反馈 */
.data-table td.cell-desc.is-hoverable > .cell-desc-in:hover { color: var(--text); text-decoration: underline dotted; }
/* 时间列（创建日期 / 修改日期）：日期时间不能折行 */
.data-table .cell-time { white-space: nowrap; color: var(--text-2); font-size: 12.5px; }
/* 备注悬停浮层：显示全文；由 JS 定位到单元格上方，鼠标移出即消失。
   这是 appendChild 到 body 的独立浮层元素（不落在 tr/td/th 上），所以用裸类名，与 .fin-desc-pop 保持一致。 */
.cell-desc-pop {
  position: fixed; z-index: 340; max-width: 420px; min-width: 180px;
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 10px 30px rgba(15, 23, 42, .18); padding: 11px 13px;
  font-size: 12.5px; line-height: 1.7; color: var(--text); white-space: normal;
  word-break: break-word; pointer-events: none;   /* 鼠标移出单元格即隐藏，不阻塞 */
}
.cell-desc-pop b { display: block; font-size: 12px; color: var(--text-2); font-weight: 600; margin-bottom: 4px; }

/* ============ 列表横向滚动 + 冻结前三列（ID / 姓名 / 手机号） ============ */
.table-scroll { overflow-x: auto; }
/* --fc3 = 手机号列宽。显示层按 3-4-4 分段（177 5349 6183），座机更宽：
   "0531-88888888" 实测约 102px + 左右内边距 28px ≈ 130px，128px 会折行 → 取 140px（余量 10px）。
   11 位手机号分段后约 91px，同样放得下。仅影响冻结列宽，不动表格结构。 */
.data-table.frozen-cols { min-width: 1180px; --fc1: 76px; --fc2: 100px; --fc3: 140px; }
.data-table.frozen-cols th:nth-child(1),
.data-table.frozen-cols td:nth-child(1) { position: sticky; left: 0; width: var(--fc1); min-width: var(--fc1); }
.data-table.frozen-cols th:nth-child(2),
.data-table.frozen-cols td:nth-child(2) { position: sticky; left: var(--fc1); width: var(--fc2); min-width: var(--fc2); }
.data-table.frozen-cols th:nth-child(3),
.data-table.frozen-cols td:nth-child(3) { position: sticky; left: calc(var(--fc1) + var(--fc2)); width: var(--fc3); min-width: var(--fc3); }
.data-table.frozen-cols th:nth-child(-n+3) { z-index: 3; background: #f8fafc; }
.data-table.frozen-cols td:nth-child(-n+3) { z-index: 2; background: var(--card-bg); }
.data-table.frozen-cols tbody tr:hover td:nth-child(-n+3) { background: #f8fbff; }
/* 冻结区右缘阴影，滚动时区分固定列与滚动内容 */
.data-table.frozen-cols th:nth-child(3),
.data-table.frozen-cols td:nth-child(3) { box-shadow: 8px 0 10px -10px rgba(15, 23, 42, .45); }
/* 奖励台账第 1 列是「事迹日期」（nowrap，实际 99px），比通用的 ID 列 76px 宽。
   不单独声明，第 2/3 列的吸顶偏移会各少 23px，横向滚动时三列互相压叠。 */
.data-table.frozen-cols.rw-ledger { --fc1: 99px; }
.tag { display: inline-block; padding: 2px 10px; border-radius: 12px; font-size: 12px; line-height: 1.6; white-space: nowrap; }
.tag + .tag { margin-left: 4px; }
.tag-gray  { background: #f1f5f9; color: #64748b; }
.tag-blue  { background: var(--primary-light); color: var(--primary); }
.tag-green { background: var(--success-light); color: var(--success); }
.tag-amber { background: var(--warn-light); color: var(--warn); }
.tag-red   { background: var(--danger-light); color: var(--danger); }
.tag-purple{ background: #f5f3ff; color: #7c3aed; }
/* 特殊标签：金色系，与状态标签（蓝/绿/琥珀/红/紫）区分开，一眼可辨「特殊达标」 */
.tag-star  { background: #fef3c7; color: #a16207; }

/* 分页 */
.pager { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; flex-wrap: wrap; gap: 10px; }
/* 左侧计数：**永不折行**（「共 7 条记录 · 第 1 / 1 页」折成两行比控件换行更丑），
   容器真挤不下时省略号收尾，右侧控件保持原样 */
.pager .pager-info { color: var(--text-3); font-size: 12px; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pager .pager-btns { display: flex; gap: 6px; align-items: center; flex: 0 0 auto; }
.pager-btn {
  min-width: 30px; height: 30px; padding: 0 8px; border: 1px solid var(--border); background: var(--card-bg);
  border-radius: 7px; cursor: pointer; font-size: 13px; color: var(--text-2); transition: all .15s;
}
.pager-btn:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
.pager-btn.on { background: var(--primary); border-color: var(--primary); color: #fff; }
.pager-btn:disabled { opacity: .4; cursor: not-allowed; }
/* 每页条数：与翻页键**同高同圆角**（30px / 8px）——
   别在分页条里突然出现一个 36px 的筛选级大控件，那是「两行」的另一个诱因 */
.pager select.ctrl { width: auto; min-width: 92px; height: 30px; padding: 0 26px 0 10px;
  font-size: 12px; border-radius: 8px; color: var(--text-2); }

/* ============ 弹窗 ============ */
.modal-mask {
  position: fixed; inset: 0; background: rgba(15,23,42,.45); z-index: 100;
  display: flex; align-items: center; justify-content: center; padding: 24px;
  animation: fadeIn .18s ease;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
/* ---------- 报销明细弹窗：深蓝标题栏 + 状态胶囊（2026-10-04） ----------
   替代原先顶部那条黄色提示条（内容已上移到标题栏第二行）。
   胶囊颜色跟随单据状态：待审批=琥珀 / 待付款·已通过=绿 / 已驳回=红。 */
.ex-detail-head {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 22px; background: linear-gradient(135deg, #0b2a4d 0%, #154a80 100%);
  border-bottom: none; flex-shrink: 0;
}
.ex-detail-head .mh-l { min-width: 0; }
.ex-detail-head .mh-title { font-size: 17px; font-weight: 700; color: #fff; letter-spacing: .2px; }
.ex-detail-head .mh-sub {
  margin-top: 3px; font-size: 12.5px; color: #c7dbf0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ex-detail-head .mh-r { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
.mh-status {
  font-size: 13px; font-weight: 600; color: #7ff0c0; background: rgba(22, 163, 74, .16);
  border: 1.5px solid #34d399; border-radius: 20px; padding: 4px 16px; white-space: nowrap;
}
.mh-status.is-amber { color: #fcd34d; background: rgba(245, 158, 11, .16); border-color: #fbbf24; }
.mh-status.is-red   { color: #fca5a5; background: rgba(220, 38, 38, .16); border-color: #f87171; }
.ex-detail-head .modal-close {
  border: none; background: rgba(255, 255, 255, .1); font-size: 18px; cursor: pointer;
  color: #c7dbf0; padding: 3px 9px; border-radius: 6px; line-height: 1;
}
.ex-detail-head .modal-close:hover { background: rgba(255, 255, 255, .2); color: #fff; }

/* ---------- 报销明细弹窗：单据信息表（2026-10-04） ----------
   把提交时填写的表头字段全部列出来（原来只有顶部黄条一句话，等于看不见）。
   用 colgroup 固定四列（88 / 292 / 88 / 其余）：标签与它的值之间只隔 292px，
   视线不用横跨整行；第 1 列值再长也压不到第 2 列标签，每行字段名竖成一列。 */
.ap-info { width: 100%; border-collapse: collapse; font-size: 13px; margin: 0 0 4px; table-layout: fixed; }
.ap-info col.c1, .ap-info col.c3 { width: 88px; }
.ap-info col.c2 { width: 292px; }
.ap-info th, .ap-info td {
  padding: 7px 10px; border-bottom: 1px solid var(--border);
  text-align: left; vertical-align: top; word-break: break-word;
}
.ap-info th { color: var(--text-2); font-weight: 500; background: var(--gray-bg); white-space: nowrap; }
.ap-info td { color: var(--text); }
.ap-info tr:hover td, .ap-info tr:hover th { background: #f8fafc; }
/* 「说明」整行浅黄底：审批的主要依据，单独占一行不挤在单元格里 */
.ap-info th.key-note-lb { background: #fef3c7; color: #92400e; }
.ap-info td.key-note { background: #fffbeb; color: var(--text); line-height: 1.65; }

.modal {
  background: var(--card-bg); border-radius: 14px; box-shadow: var(--shadow-lg);
  max-width: 880px; width: 100%; max-height: 88vh; display: flex; flex-direction: column;
  animation: popIn .2s ease;
  /* ★ 必须有 overflow:hidden —— 否则深色标题栏/深色页脚这类"满宽"子元素
     会顶穿 border-radius，表现为「顶部是直角、底部是圆角」不对称。
     圆角要靠 overflow 裁切子元素才能生效（背景色本身不会被裁）。 */
  overflow: hidden;
}
.modal.wide { max-width: 1180px; }
/* tall：内容多的表单（新增报销）。表单字段一多，88vh 就开始逼用户拉滚动条 ——
   这里把窗体顶到接近全屏高度，同时 mask 内边距收窄（否则 max-height 再大也用不满）。 */
.modal.tall { max-height: calc(100vh - 20px); }
.modal-mask.tight { padding: 10px; }
/* tall 表单的头/尾/合计条再收一点 —— 差十几像素就够把「要拉滚动条」变成「一屏看完」 */
.modal.tall .modal-head { padding: 12px 22px; }
.modal.tall .modal-foot { padding: 11px 22px; }
.modal.tall .ex-total { margin-top: 10px; padding: 8px 12px; }
@keyframes popIn { from { transform: translateY(14px) scale(.98); opacity: 0; } to { transform: none; opacity: 1; } }
.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 16px 22px; border-bottom: 1px solid var(--border); }
.modal-head h3 { font-size: 16px; }
.modal-close { border: none; background: transparent; font-size: 18px; cursor: pointer; color: var(--text-3); padding: 4px 8px; border-radius: 6px; }
.modal-close:hover { background: var(--gray-bg); color: var(--text); }
.modal-body { padding: 20px 22px; overflow-y: auto; flex: 1; min-height: 0; }
/* 内容超出时滚动条保持可见，避免「看不出还能往下滚」 */
.modal-body::-webkit-scrollbar { width: 10px; }
.modal-body::-webkit-scrollbar-track { background: #f1f5f9; border-radius: 6px; }
.modal-body::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 6px; border: 2px solid #f1f5f9; }
.modal-body::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
.modal-foot { padding: 14px 22px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 10px; }

/* 详情查看（分组折叠，与录入窗体一致风格） */
.detail-group { border: 1px solid var(--border); border-radius: 10px; margin-bottom: 12px; overflow: hidden; }
.detail-group-head {
  display: flex; align-items: center; gap: 8px; padding: 10px 16px; background: #f8fafc;
  cursor: pointer; font-size: 13px; font-weight: 600; user-select: none;
}
.detail-group-head .d-chev { margin-left: auto; color: var(--text-3); transition: transform .2s; font-size: 12px; }
.detail-group.open .d-chev { transform: rotate(180deg); }
.detail-group-body-wrap { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .25s ease; }
.detail-group:not(.open) .detail-group-body-wrap { grid-template-rows: 0fr; }
.detail-group-body { overflow: hidden; min-height: 0; }
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 24px; padding: 10px 16px 14px; }
.detail-item { display: flex; padding: 6px 0; border-bottom: 1px dashed #f1f5f9; font-size: 13px; }
.detail-item .d-label { width: 130px; flex-shrink: 0; color: var(--text-3); }
.detail-item .d-value { flex: 1; color: var(--text); word-break: break-all; }
/* 详情页派生信息（年龄）：灰字小号说明，跟在主值后面不抢视线 */
.detail-item .d-hint { margin-left: 6px; font-size: 12px; color: var(--text-3); }
.detail-item .d-none { color: var(--text-3); }
.detail-item.full { grid-column: 1 / -1; }

/* 导入报告 */
.import-report { max-height: 320px; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; }
.import-row { display: flex; gap: 10px; padding: 8px 14px; font-size: 13px; border-bottom: 1px solid #f1f5f9; align-items: flex-start; }
.import-row:last-child { border-bottom: none; }
.import-row .r-no { color: var(--text-3); width: 44px; flex-shrink: 0; }
.import-row.ok .r-msg { color: var(--success); }
.import-row.fail .r-msg { color: var(--danger); }

/* Toast */
.toast-box { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 950; display: flex; flex-direction: column; gap: 10px; align-items: center; }
.toast {
  background: #0f172a; color: #fff; padding: 10px 20px; border-radius: 10px; font-size: 13px;
  box-shadow: var(--shadow-lg); animation: toastIn .25s ease; max-width: 480px;
}
.toast.success { background: #14532d; }
.toast.error { background: #7f1d1d; }
.toast.warn { background: #78350f; }
@keyframes toastIn { from { transform: translateY(-14px); opacity: 0; } to { transform: none; opacity: 1; } }

/* 空状态 */
.empty-state { text-align: center; padding: 50px 20px; color: var(--text-3); }
.empty-state .icon { font-size: 40px; margin-bottom: 10px; }

/* ============ 主页大屏 ============ */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 14px; margin-bottom: 18px; }
.stat-card {
  background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 18px 20px; position: relative; overflow: hidden;
}
.stat-card::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--primary); }
.stat-card.green::before { background: var(--success); }
.stat-card.amber::before { background: var(--warn); }
.stat-card.purple::before { background: #7c3aed; }
.stat-card.teal::before { background: #0d9488; }
.stat-card.cyan::before { background: #0891b2; }
.stat-card .s-num { font-size: 30px; font-weight: 700; line-height: 1.2; }
.stat-card.blue .s-num { color: var(--primary); }
.stat-card.green .s-num { color: var(--success); }
.stat-card.amber .s-num { color: var(--warn); }
.stat-card.purple .s-num { color: #7c3aed; }
.stat-card.teal .s-num { color: #0d9488; }
.stat-card.cyan .s-num { color: #0891b2; }
.stat-card .s-label { font-size: 12px; color: var(--text-3); margin-top: 5px; }

.dash-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-bottom: 18px; }
@media (max-width: 1100px) { .dash-grid { grid-template-columns: 1fr; } }
.bar-row { display: flex; align-items: center; gap: 10px; margin-bottom: 11px; }
.bar-row:last-child { margin-bottom: 0; }
.bar-label { width: 118px; flex-shrink: 0; font-size: 12px; color: var(--text-2); text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-track { flex: 1; height: 16px; background: var(--gray-bg); border-radius: 8px; overflow: hidden; }
.bar-fill { height: 100%; background: linear-gradient(90deg, #60a5fa, #2563eb); border-radius: 8px; min-width: 3px; transition: width .5s ease; }
.bar-fill.fill-green { background: linear-gradient(90deg, #4ade80, #16a34a); }
.bar-fill.fill-purple { background: linear-gradient(90deg, #a78bfa, #7c3aed); }
.bar-fill.fill-amber { background: linear-gradient(90deg, #fbbf24, #d97706); }
.bar-num { width: 28px; flex-shrink: 0; font-size: 12px; color: var(--text-2); font-weight: 600; }
.empty-hint { color: var(--text-3); font-size: 13px; text-align: center; padding: 16px 0; }

/* ---------- 顶部：人才供给链路（招聘需求 → 意向人员 → 在职人员） ---------- */
.flow { display: flex; align-items: stretch; }
.flow-stage {
  flex: 1; min-width: 0; border-radius: 10px; padding: 14px 18px;
  border: 1px solid var(--border); position: relative;
}
.flow-stage.s1 { background: #f5f3ff; border-color: #ddd6fe; }
.flow-stage.s2 { background: #eff6ff; border-color: #bfdbfe; }
.flow-stage.s3 { background: #f0fdf4; border-color: #bbf7d0; }
.flow-stage .fs-head { font-size: 13px; font-weight: 700; color: var(--text-2); }
.flow-stage .fs-num { font-size: 32px; font-weight: 700; line-height: 1.15; margin-top: 4px; }
.flow-stage .fs-num small { font-size: 13px; font-weight: 500; color: var(--text-3); margin-left: 3px; }
.flow-stage.s1 .fs-num { color: #7c3aed; }
.flow-stage.s2 .fs-num { color: #2563eb; }
.flow-stage.s3 .fs-num { color: #16a34a; }
.flow-stage .fs-sub { font-size: 12px; color: var(--text-3); margin-top: 4px; }
.flow-arrow {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 0 16px; color: var(--text-3); flex-shrink: 0;
}
.flow-arrow span { font-size: 11px; margin-bottom: 2px; }
.flow-arrow b { font-size: 18px; line-height: 1; }
@media (max-width: 900px) {
  .flow { flex-direction: column; gap: 10px; }
  .flow-arrow { padding: 4px 0; }
  .flow-arrow b { transform: rotate(90deg); }
}

/* ---------- 三大业务模块 ---------- */
.dash-module {
  --mc: var(--primary); --mc-soft: #eff6ff;
  background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 18px 20px; margin-bottom: 18px;
}
.dash-module.m1 { --mc: #7c3aed; --mc-soft: #f5f3ff; }
.dash-module.m2 { --mc: #2563eb; --mc-soft: #eff6ff; }
.dash-module.m3 { --mc: #16a34a; --mc-soft: #f0fdf4; }
.mod-head { display: flex; align-items: center; gap: 12px; padding-bottom: 14px; border-bottom: 1px solid var(--border); }
.mod-index {
  width: 28px; height: 28px; flex-shrink: 0; border-radius: 50%;
  background: var(--mc); color: #fff; font-size: 14px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.mod-head-text { min-width: 0; }
.mod-title { font-size: 15px; font-weight: 700; }
.mod-desc { font-size: 12px; color: var(--text-3); margin-top: 3px; }
.mod-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(116px, 1fr)); gap: 10px; margin: 14px 0; }
.mod-stat { background: var(--mc-soft); border-left: 3px solid var(--mc); border-radius: 8px; padding: 10px 12px; }
.mod-stat .ms-num { font-size: 22px; font-weight: 700; color: var(--mc); line-height: 1.2; }
.mod-stat .ms-label { font-size: 12px; color: var(--text-2); margin-top: 2px; }
.mod-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); gap: 14px; }
.mini-card {
  align-self: start; display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; background: #fff;
}
.mini-title { font-size: 13px; font-weight: 600; margin-bottom: 10px; display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.mini-sub { font-size: 11px; color: var(--text-3); font-weight: 400; }
.mini-body { flex: 1; display: flex; flex-direction: column; justify-content: center; }
.mini-card .bar-label { width: 86px; }
.mod-list { margin-top: 16px; }
.mod-list-title { font-size: 13px; font-weight: 600; margin-bottom: 8px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* ---------- 请假计划（待生效）与请假记录 ---------- */
.leave-list { display: flex; flex-direction: column; }
.leave-row { display: flex; align-items: center; gap: 12px; padding: 9px 6px; border-bottom: 1px dashed #f1f5f9; font-size: 13px; cursor: pointer; }
.leave-row:last-child { border-bottom: none; }
.leave-row:hover { background: #f8fbff; }
.leave-row .lv-name { min-width: 104px; font-weight: 600; display: flex; flex-direction: column; line-height: 1.25; }
.leave-row .lv-name small { font-size: 11px; font-weight: 400; color: var(--text-3); }
.leave-row .lv-area { min-width: 92px; color: var(--text-2); }
.leave-row .lv-cats { display: flex; flex-wrap: wrap; gap: 3px; flex: 1; min-width: 126px; }
.leave-row .lv-reason { min-width: 72px; }
.leave-row .lv-range { min-width: 176px; font-size: 12px; color: var(--text-3); }
.leave-row .lv-state { min-width: 132px; text-align: right; }
@media (max-width: 900px) { .leave-row { flex-wrap: wrap; } .leave-row .lv-state { text-align: left; } }

.leave-history { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 10px; }
.lh-title { font-size: 12px; font-weight: 600; color: var(--text-2); margin-bottom: 8px; }
.lh-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 7px 4px; border-bottom: 1px dashed #f1f5f9; font-size: 13px; }
.lh-row:last-child { border-bottom: none; }
.lh-range { font-weight: 600; min-width: 168px; }
.lh-by { font-size: 11px; color: var(--text-3); margin-left: auto; }
/* 请假记录行上的操作按钮（提前销假 / 撤销）：有按钮时按钮靠右，提交人信息让位 */
.lh-ops { display: inline-flex; gap: 6px; margin-left: auto; }
.lh-row:has(.lh-ops) .lh-by { margin-left: 0; }

/* 可搜索人员选择（请假弹窗等）：输入模糊过滤 + 姓名/区域/身份证脱敏引导 */
.searchable { position: relative; }
.searchable .ctrl { width: 100%; }
.searchable-list { display: none; position: absolute; z-index: 40; left: 0; right: 0; top: calc(100% + 4px); max-height: 248px; overflow-y: auto; background: var(--card-bg, #fff); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(15, 23, 42, .14); }
.searchable-list.open { display: block; }
.searchable-item { padding: 8px 12px; cursor: pointer; }
.searchable-item:hover { background: #f8fbff; }
.searchable-item.on { background: var(--primary-light); }
.si-name { font-size: 13px; font-weight: 600; color: var(--text); }
.si-sub { font-size: 12px; color: var(--text-3); margin-top: 2px; font-variant-numeric: tabular-nums; }
.searchable-empty { padding: 12px; font-size: 13px; color: var(--text-2); text-align: center; }
.ring-wrap { position: relative; width: 168px; height: 168px; margin: 6px auto 10px; }
.ring { width: 168px; height: 168px; transform: rotate(-90deg); }
.ring-bg { fill: none; stroke: var(--gray-bg); stroke-width: 9; }
.ring-fg { fill: none; stroke-width: 9; stroke-linecap: round; transition: stroke-dashoffset .6s ease; }
.ring-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.ring-center b { font-size: 34px; font-weight: 700; line-height: 1.1; }
.ring-center small { font-size: 13px; color: var(--text-3); margin-top: 4px; }

.expiring-item { display: flex; align-items: center; gap: 12px; padding: 9px 6px; border-bottom: 1px dashed #f1f5f9; font-size: 13px; }
.expiring-item:last-child { border-bottom: none; }
.expiring-item:hover { background: #f8fbff; }
.exp-name { font-weight: 600; min-width: 70px; }
.exp-item { color: var(--text-2); flex: 1; }
.exp-date { color: var(--text-3); font-size: 12px; }
.card-title-sub { font-size: 12px; color: var(--text-3); font-weight: 400; margin-left: 4px; }

.ctrl-row { display: flex; gap: 6px; align-items: flex-start; }
.ctrl-row .ctrl { flex: 1; min-width: 0; }
.ctrl-row .chips { flex: 1; padding-top: 0; }
.ctrl-row .add-dict { flex-shrink: 0; }

/* ============ 数据字典 ============ */
.dict-add-row { display: flex; gap: 8px; margin-bottom: 14px; }
.dict-add-row .ctrl { max-width: 280px; }
.dict-list { border-top: 1px solid var(--border); }
/* 允许换行：字典卡片内容是「名称 + 使用计数 + 承担徽标 + 操作按钮」，
   卡片宽度由 .dict-group-body 的 grid（minmax(430px,1fr)）决定，视口一变就变窄。
   附加费类型那行多一个徽标 + 多一个「承担设置」按钮 → 卡在 430~570px 时被撑破卡片
   （2026-10-07 实测：1280 宽下每行溢出 168px、1440 宽下溢出 88px，"字段外溢"）。
   flex-wrap 之后：放得下仍是一行（操作列靠右，与改动前完全一致），放不下就让操作列
   整体落到第二行并右对齐 —— 任何宽度都不再横向挤出卡片。 */
.dict-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 9px 4px; border-bottom: 1px dashed #f1f5f9; }
.dict-row:last-child { border-bottom: none; }
.dict-row:hover { background: #f8fbff; }
.dict-name { font-weight: 500; min-width: 150px; }
.dict-usage { font-size: 12px; color: var(--text-3); flex: 1 1 auto; min-width: 0; }
.dict-usage b { color: var(--warn); }
/* margin-left:auto 只在「操作列被挤到第二行」时才起作用（同一行时 usage 已经把右侧占满）——
   保证换行后操作列依然贴右，不会孤零零缩在左边 */
.dict-ops { display: flex; gap: 6px; margin-left: auto; }
/* 增 / 改 / 删后定位到的字典卡片高亮一次，帮助视觉定位 */
.dict-flash { animation: dictFlash 1.2s ease-out; }
@keyframes dictFlash {
  0%   { box-shadow: 0 0 0 3px rgba(37, 99, 235, .35); }
  100% { box-shadow: var(--shadow); }
}

/* ============ 字典分组折叠（二期地基） ============ */
.dict-group { margin-bottom: 20px; }
.dict-group-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; background: #f1f5f9;
  border: 1px solid var(--border); border-radius: 10px;
  cursor: pointer; user-select: none; transition: background .15s;
}
.dict-group-head:hover { background: #e9eff8; }
.dict-group-caret { font-size: 12px; color: var(--text-3); transition: transform .18s; display: inline-block; }
.dict-group.is-collapsed .dict-group-caret { transform: rotate(-90deg); }
.dict-group-icon { font-size: 16px; }
.dict-group-label { font-weight: 600; font-size: 14px; }
.dict-group-count {
  font-size: 12px; color: var(--primary);
  background: rgba(37, 99, 235, .09); border-radius: 20px; padding: 2px 9px;
}
.dict-group-desc { font-size: 12px; color: var(--text-3); margin-left: auto; }
.dict-group-body {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(430px, 1fr));
  gap: 14px; margin-top: 14px; align-items: start;
}
.dict-group.is-collapsed .dict-group-body { display: none; }
.dict-group-body .card { margin-bottom: 0; }
@media (max-width: 1000px) {
  .dict-group-body { grid-template-columns: 1fr; }
  .dict-group-desc { display: none; }
}

/* ============ 版本管理（二期地基） ============ */
.ver-current {
  display: flex; gap: 14px; align-items: flex-start;
  background: linear-gradient(180deg, #eff6ff, #fff); border: 1px solid #bfdbfe;
}
.ver-current-icon { font-size: 22px; line-height: 1.2; }
.ver-current-title { font-size: 15px; font-weight: 600; margin-bottom: 5px; }
.ver-current-name { font-size: 13px; font-weight: 400; color: var(--text-3); margin-left: 8px; }
.ver-current-sub { font-size: 12.5px; color: var(--text-2); line-height: 1.7; }
.ver-count { font-size: 13px; color: var(--text-3); margin: 18px 4px 10px; }
.ver-card-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; }
.ver-badge { font-size: 15px; }
.ver-title { font-weight: 600; font-size: 14px; word-break: break-all; }
.ver-meta { font-size: 12px; color: var(--text-3); margin-bottom: 5px; }
.ver-note { font-size: 13px; color: var(--text-2); margin-bottom: 13px; }
.ver-ops { display: flex; gap: 8px; flex-wrap: wrap; }
.ver-steps { padding-left: 20px; margin: 8px 0; }
.ver-steps li { margin-bottom: 2px; }
.ver-form-row { margin-bottom: 14px; }
.ver-form-row label { display: block; font-size: 13px; font-weight: 500; margin-bottom: 6px; }
.ver-form-row .ctrl { width: 100%; }
.ver-form-hint { font-size: 12.5px; color: var(--text-3); line-height: 1.7; margin-top: 4px; }

/* ============ 招聘需求：缺口与关联人员 ============ */
.linked-stat { display: flex; gap: 18px; flex-wrap: wrap; font-size: 13px; color: var(--text-2); margin-bottom: 8px; }
.linked-stat .ls-item b { font-size: 15px; }
.ls-ok { color: var(--success); }
.ls-warn { color: var(--danger); }
.linked-chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.linked-chip {
  display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border);
  border-radius: 16px; padding: 3px 8px 3px 4px; font-size: 13px; background: var(--card-bg);
}
.linked-chip .lc-type { font-size: 11px; padding: 1px 6px; border-radius: 8px; background: var(--gray-bg); color: var(--text-2); }
.linked-chip .lc-type.formal { background: var(--success-light); color: var(--success); }
.linked-chip .lc-type.intention { background: var(--primary-light); color: var(--primary); }
.lc-del { border: none; background: transparent; color: var(--text-3); cursor: pointer; font-size: 14px; line-height: 1; padding: 0 2px; }
.lc-del:hover { color: var(--danger); }

/* 关联人员选择弹窗 */
.picker-bar { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
.picker-bar .ctrl { flex: 0 1 260px; }
.picker-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.picker-list { max-height: 42vh; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; }
.picker-item { display: flex; align-items: center; gap: 10px; padding: 8px 12px; font-size: 13px; border-bottom: 1px solid #f1f5f9; cursor: pointer; }
.picker-item:last-child { border-bottom: none; }
.picker-item:hover { background: #f8fbff; }
.picker-item.on { background: var(--primary-light); }
.picker-item input { flex: 0 0 auto; }
.pi-type { font-size: 11px; padding: 1px 7px; border-radius: 8px; background: var(--gray-bg); color: var(--text-2); flex: 0 0 auto; }
.pi-type.formal { background: var(--success-light); color: var(--success); }
.pi-type.intention { background: var(--primary-light); color: var(--primary); }
.pi-name { font-weight: 600; min-width: 70px; }
.pi-meta { color: var(--text-2); min-width: 96px; }
.pi-area { flex: 1; min-width: 120px; color: var(--text-3); }
.pi-status { color: var(--text-3); font-size: 12px; }
.picker-tip { margin-top: 12px; font-size: 13px; color: var(--text-2); }

/* 列表：需求缺口进度单元格 */
.gap-cell { display: flex; align-items: center; gap: 8px; min-width: 170px; }
.gap-bar { flex: 1; height: 8px; background: var(--gray-bg); border-radius: 5px; overflow: hidden; min-width: 50px; }
.gap-bar-fill { height: 100%; background: linear-gradient(90deg, #4ade80, #16a34a); border-radius: 5px; transition: width .4s ease; }
.gap-pct { font-size: 12px; color: var(--text-2); font-weight: 600; }

/* 大屏：招聘需求到岗进度 */
.recruit-list { display: flex; flex-direction: column; }
.recruit-row { display: flex; align-items: center; gap: 12px; padding: 9px 6px; border-bottom: 1px dashed #f1f5f9; font-size: 13px; cursor: pointer; }
.recruit-row:last-child { border-bottom: none; }
.recruit-row:hover { background: #f8fbff; }
.recruit-row .rc-area { min-width: 118px; font-weight: 600; }
.recruit-row .rc-cats { display: flex; flex-wrap: wrap; gap: 3px; min-width: 120px; }
.recruit-row .rc-track { flex: 1; height: 14px; background: var(--gray-bg); border-radius: 7px; overflow: hidden; min-width: 70px; }
.recruit-row .rc-fill { height: 100%; background: linear-gradient(90deg, #60a5fa, #2563eb); border-radius: 7px; transition: width .4s ease; }
.recruit-row .rc-num { font-size: 12px; font-weight: 600; color: var(--text-2); min-width: 46px; text-align: right; }
.recruit-row .rc-gap { min-width: 76px; }
.recruit-row .rc-date { font-size: 12px; color: var(--text-3); min-width: 108px; text-align: right; }
.recruit-row .rc-date.rc-overdue { color: var(--danger); font-weight: 600; }

/* ============ 暂停接单（大屏时间轴 + 登记弹窗） ============ */
.pause-list { display: flex; flex-direction: column; }
.pause-row { display: flex; align-items: center; gap: 12px; padding: 9px 6px; border-bottom: 1px dashed #f1f5f9; font-size: 13px; cursor: pointer; }
.pause-row:last-child { border-bottom: none; }
.pause-row:hover { background: #f8fbff; }
.pause-row .ps-name { min-width: 104px; font-weight: 600; display: flex; flex-direction: column; line-height: 1.25; }
.pause-row .ps-name small { font-size: 11px; font-weight: 400; color: var(--text-3); }
.pause-row .ps-area { min-width: 92px; color: var(--text-2); }
.pause-row .ps-cats { display: flex; flex-wrap: wrap; gap: 3px; flex: 1; min-width: 126px; }
.pause-row .ps-reason { min-width: 72px; }
.pause-row .ps-range { min-width: 166px; font-size: 12px; color: var(--text-3); }
.pause-row .ps-track { flex: none; width: 190px; height: 14px; background: var(--gray-bg); border-radius: 7px; overflow: hidden; }
.pause-row .ps-fill { height: 100%; border-radius: 7px; background: linear-gradient(90deg, #fcd34d, #f59e0b); transition: width .4s ease; }
.pause-row.upcoming .ps-fill { background: linear-gradient(90deg, #93c5fd, #3b82f6); }
.pause-row.open .ps-fill { background: linear-gradient(90deg, #fcd34d, #f97316); }
.pause-row.ended .ps-fill { background: linear-gradient(90deg, #fca5a5, #ef4444); }
.pause-row .ps-state { min-width: 188px; text-align: right; }
.pause-row.upcoming { background: #f5f9ff; }
.pause-row.ended { opacity: .8; }
.pause-row.unknown { background: #fff7ed; }
.pause-form { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 12px; }
.pause-form label { display: block; font-size: 13px; font-weight: 600; color: var(--text-2); margin-bottom: 6px; }
.pf-err { display: none; margin-top: 12px; color: var(--danger); font-size: 13px; font-weight: 600; }

/* 响应式 */
@media (max-width: 900px) {
  .form-grid { grid-template-columns: 1fr; }
  .detail-grid { grid-template-columns: 1fr; }
  .pause-form { grid-template-columns: 1fr; }
  .pause-row { flex-wrap: wrap; }
  .pause-row .ps-state { text-align: left; }
  .pause-row .ps-track { flex: 1 1 160px; width: auto; }
  .sidebar { width: 64px; }
  .sidebar-brand { padding: 18px 0; justify-content: center; }
  .sidebar-brand .brand-text { display: none; }
  /* 窄屏只剩图标条：文字、分组头、角标一律收起，子项强制展开 */
  .nav-label, .nav-badge, .nav-group-head { display: none; }
  .nav-item, .nav-group-body .nav-item { justify-content: center; padding: 10px 0; }
  .nav-group { margin-top: 8px; }
  .nav-group-body { display: flex !important; margin: 0; padding: 0; }
  .nav-group-body::before, .nav-group-body .nav-item.active::before { display: none; }
  .user-chip { display: none; }
  .main { padding: 16px; }
}

/* ============================================================
 * 师傅贡献奖励台账
 * ============================================================ */
/* 发放弹窗表单 */
.rw-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 14px; }
.rw-form .pf-item.full { grid-column: 1 / -1; }
.rw-form label { display: block; font-size: 13px; font-weight: 600; color: var(--text-2); margin-bottom: 6px; }
.rw-form label small { font-weight: 400; color: var(--text-3); margin-left: 6px; }
.rw-form .ctrl-row { display: flex; gap: 8px; align-items: center; }
.rw-form .ctrl-row .ctrl { flex: 1; }
.rw-form textarea.ctrl { resize: vertical; line-height: 1.6; font-family: inherit; }
.rw-form .pf-item.req-on label { color: var(--danger); }
.rw-points-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.rw-points-row .ctrl { width: 96px; flex: none; }
.rw-quick { display: flex; gap: 6px; flex-wrap: wrap; }

/* 台账统计卡（auto-fit：有「待审批」第 6 张卡时自动重排，不会挤成两行参差） */
.rw-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 12px; margin: 14px 0; }
.rw-stat { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; }
.rw-stat-label { font-size: 12px; color: var(--text-3); }
.rw-stat-value { font-size: 24px; font-weight: 700; color: var(--text); margin: 4px 0 2px; letter-spacing: -.5px; }
.rw-stat-note { font-size: 11px; color: var(--text-3); }
/* 待审批：琥珀色提醒（这些记录尚未计入积分） */
.rw-stat-warn { border-color: var(--warn); background: var(--warn-light); }
.rw-stat-warn .rw-stat-value { color: var(--warn); }

/* 视图切换 */
.rw-viewtabs { display: flex; gap: 8px; margin: 0 0 12px; }
.rw-tab { border: 1px solid var(--border); background: var(--card-bg); color: var(--text-2); border-radius: 18px; padding: 6px 16px; font-size: 13px; cursor: pointer; transition: all .15s; }
.rw-tab:hover { border-color: var(--primary); color: var(--primary); }
.rw-tab.on { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 500; }

/* 筛选：日期区间 */
.rw-daterange { display: flex; align-items: center; gap: 6px; }
.rw-daterange .ctrl { width: 150px; }
.rw-dash { color: var(--text-3); }

/* 台账表格列 */
.cell-date { white-space: nowrap; font-size: 12px; color: var(--text-2); }
.cell-person { min-width: 96px; }
.cell-sub { font-size: 11px; color: var(--text-3); margin-top: 2px; }
/* 数字列（积分 / 金额）表头与内容统一右对齐。
   必须带 `.data-table` 前缀：全局的 `.data-table th { text-align: left }` 特异性 (0,1,1)
   高于单个类名 (0,1,0)，不加前缀会让表头被强制左对齐、而内容仍右对齐 → 视觉上"错位"。 */
.data-table .cell-points { text-align: right; white-space: nowrap; }
.data-table .cell-money { text-align: right; white-space: nowrap; }
.cell-reward { min-width: 130px; }
.cell-title { min-width: 220px; max-width: 340px; }
.cell-no { white-space: nowrap; }
.cell-last { min-width: 190px; }
.rw-person { color: var(--primary); cursor: pointer; font-weight: 500; }
.rw-person:hover { text-decoration: underline; }
.rw-points { color: #7c3aed; font-weight: 700; }
.rw-money { color: var(--warn); font-weight: 600; }
.rw-title { font-size: 13px; color: var(--text); }
.rw-note { font-size: 12px; color: var(--text-3); margin-top: 3px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.rw-no { display: inline-flex; align-items: center; gap: 4px; }
.rw-no-txt { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--text-2); }
.rw-copy { border: none; background: transparent; color: var(--text-3); font-size: 11px; cursor: pointer; padding: 0 2px; }
.rw-copy:hover { color: var(--primary); text-decoration: underline; }
.rw-credit-cell { display: inline-flex; align-items: baseline; gap: 2px; color: #b45309; font-weight: 600; }
.rw-credit-cell b { font-size: 15px; }
.rw-credit-cell small { font-size: 11px; color: var(--text-3); font-weight: 400; }
.rw-credit-times { margin-left: 4px; }
.rw-revoked { opacity: .55; }
.rw-revoked-tip { color: var(--danger); font-size: 11px; }

/* 档案上的贡献汇总徽章 */
.credit-badge {
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  background: #fffbeb; border: 1px solid #fde68a; border-radius: var(--radius);
  padding: 12px 16px; margin-bottom: 14px;
}
.cb-main { display: flex; align-items: baseline; gap: 8px; }
.cb-star { font-size: 18px; }
.cb-score { font-size: 30px; font-weight: 700; color: #b45309; letter-spacing: -1px; }
.cb-unit { font-size: 13px; color: var(--text-2); }
.cb-meta { display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--text-2); }
.cb-meta b { color: var(--text); }

/* 详情里的「奖励积分卡」 */
.rw-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.rw-card-head .credit-badge { margin-bottom: 0; flex: 1 1 auto; }
.rw-card-none { font-size: 13px; color: var(--text-3); }
.rw-type-sum { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.rw-list { display: flex; flex-direction: column; gap: 10px; }
.rw-card-row { border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; }
.rw-card-line1 { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rw-date { font-size: 12px; color: var(--text-2); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; white-space: nowrap; }
.rw-card-title { font-weight: 600; font-size: 13px; }
.rw-card-op { margin-left: auto; }
.rw-card-note { font-size: 12px; color: var(--text-2); margin-top: 6px; line-height: 1.6; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.rw-card-meta { display: flex; gap: 14px; flex-wrap: wrap; font-size: 11px; color: var(--text-3); margin-top: 6px; }
.rw-meta-item { display: inline-flex; align-items: center; gap: 4px; }

/* 服务单号关联提示 */
.rw-related { margin-top: 12px; }
.rw-rel-ok { font-size: 12px; color: var(--text-3); }
.rw-rel { border: 1px solid #fde68a; background: #fffbeb; border-radius: 8px; padding: 10px 12px; }
.rw-rel-title { font-size: 13px; font-weight: 600; color: #b45309; margin-bottom: 6px; }
.rw-rel-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12px; padding: 3px 0; }
.rw-rel-name { font-weight: 600; }
.rw-rel-pt { color: #7c3aed; font-weight: 600; }
.rw-rel-warn { margin-top: 6px; font-size: 12px; color: var(--danger); font-weight: 600; }
.rw-rel-tip { margin-top: 6px; font-size: 11px; color: var(--text-3); }

/* 排行榜 */
.rw-board-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.rw-board-title { font-size: 15px; font-weight: 600; }
.rw-board-title small { display: block; font-weight: 400; font-size: 12px; color: var(--text-3); margin-top: 3px; }
.rw-win { display: flex; gap: 8px; }
.rw-rank { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; background: var(--gray-bg); color: var(--text-2); font-size: 12px; font-weight: 600; flex: none; }
.rw-rank.top1 { background: #fef3c7; color: #b45309; }
.rw-rank.top2 { background: #e2e8f0; color: #475569; }
.rw-rank.top3 { background: #fde8d7; color: #c2410c; }

/* 按服务单号反查 */
.rw-lookup-bar { display: flex; gap: 8px; margin: 12px 0; }
.rw-lookup-bar .ctrl { flex: 1; }
.rw-lookup-sum { font-size: 13px; color: var(--text-2); margin-bottom: 10px; }
.rw-lookup-list { display: flex; flex-direction: column; gap: 8px; }
.rw-lookup-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; font-size: 13px; }
.rw-lk-title { font-weight: 600; }

/* 大屏：贡献积分榜 */
.reward-list { display: flex; flex-direction: column; gap: 6px; }
.reward-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 8px 10px; border-radius: 8px; cursor: pointer; }
.reward-row:hover { background: #f8fafc; }
.rw-board-pt { font-weight: 700; color: #b45309; font-size: 16px; margin-left: auto; white-space: nowrap; }
.rw-board-pt small { font-size: 11px; font-weight: 400; margin-left: 2px; }
.rw-board-cnt { font-size: 12px; color: var(--text-2); white-space: nowrap; }
.rw-board-last { font-size: 12px; color: var(--text-3); flex: 1 1 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 1100px) {
  .rw-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .rw-form { grid-template-columns: 1fr; }
  .rw-stats { grid-template-columns: 1fr; }
  .rw-daterange .ctrl { width: 130px; }
}

/* ============================================================
 * 账号角色多选（2026-10-09 重做）：一个人可兼多岗
 *
 *   原来是「一个角色占一整行」的纵向列表 —— 角色加到第 5 个就把弹窗撑满，
 *   再加角色只会更长。改成**自适应网格卡片**：按最小卡宽自动换行、每行 1~N 张，
 *   以后新增角色只改 ROLE_TIPS 文案，**样式一行都不用动**。
 *
 *   ⚠️ 布局规则一律带 `.role-cards` 作用域前缀 —— 卡片类名长在 <label> 上，
 *      裸类名规则会外溢（同 2026-10-08 合计行 `display:flex` 事故的教训）。
 *   ⚠️ 每张卡是 <label>，必须用 </label> 闭合。写成 </span> 会让浏览器把
 *      label 逐层嵌套 → 每张卡变成 flex 行把下一张吞进去（详见 app.js 注释）。
 * ============================================================ */
.role-cards {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
}
.role-cards .role-card {
  display: flex; align-items: flex-start; gap: 9px;
  border: 1px solid var(--border); border-radius: 8px;
  padding: 9px 12px; cursor: pointer;
  transition: border-color .15s, background .15s, box-shadow .15s;
}
.role-cards .role-card:hover { border-color: var(--primary, #2563eb); background: #f8fafc; }
/* 选中态：以 JS 打的 .is-on 为准；:has() 只作兜底（不支持也不影响勾选功能） */
.role-cards .role-card.is-on,
.role-cards .role-card:has(input:checked) {
  border-color: var(--primary, #2563eb); background: #eff6ff;
  box-shadow: inset 0 0 0 1px var(--primary, #2563eb);
}
.role-cards .role-card.is-disabled { opacity: .6; cursor: not-allowed; }
.role-cards .role-card.is-disabled:hover { border-color: var(--border); background: transparent; }
.role-cards .role-card.is-disabled.is-on:hover { background: #eff6ff; }
.role-cards .role-card input {
  flex: none; margin-top: 2px; width: 15px; height: 15px;
  accent-color: var(--primary, #2563eb);
}
/* min-width:0 必须加：否则文字在 flex 子项里不收缩、直接把卡片撑破（老结构就是这么挤成竖排的） */
.role-cards .role-card-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.role-cards .role-card-name { font-size: 13px; font-weight: 600; color: var(--text-1); line-height: 1.35; }
.role-cards .role-card-tip { font-size: 12px; color: var(--text-2); line-height: 1.5; overflow-wrap: break-word; }

/* ============================================================
 * 二期 · 结算财务模块（2.1 工单与价格 / 2.2 应付）
 *   .input 是 .ctrl 的别名（财务页面用 .input 命名，样式与全站控件一致）
 * ============================================================ */
.page-head h2 { font-size: 20px; font-weight: 700; }
.page-sub { flex-basis: 100%; font-size: 12px; color: var(--text-3); line-height: 1.6; margin-top: -6px; }
.page-sub b { color: var(--primary); }

.input {
  width: 100%; border: 1px solid var(--border); border-radius: 8px;
  padding: 7px 11px; font-size: 13px; background: #fff; color: var(--text);
  font-family: inherit; line-height: 1.4; outline: none; transition: border-color .15s, box-shadow .15s;
}
.input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .1); }
.input:disabled { background: #f8fafc; color: var(--text-3); cursor: not-allowed; }
select.input { appearance: none; padding-right: 28px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%2394a3b8' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; }
textarea.input { resize: vertical; min-height: 70px; font-family: inherit; }

.fin-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow); padding: 10px 14px; }
.fin-toolbar .input { width: auto; min-width: 120px; max-width: 240px; }
.fin-toolbar #ordSearch { min-width: 220px; }
.fin-grow { flex: 1; }
.fin-dash { color: var(--text-3); }
.fin-sums { font-size: 12px; color: var(--text-2); }
.fin-sums b { color: var(--text); }
.fin-sums .warn, .fin-hint.warn { color: var(--warn); }
.fin-sums .danger, .fin-hint.danger { color: var(--danger); }
.chk { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-2); cursor: pointer; user-select: none; }
.chk input { width: 15px; height: 15px; accent-color: var(--primary); cursor: pointer; }
.empty { text-align: center; padding: 46px 20px; color: var(--text-3); font-size: 13px; }

.fin-table { min-width: 100%; }
.fin-table th, .fin-table td { white-space: nowrap; }
.fin-table.fin-item-table { min-width: 1080px; }
.fin-table.fin-item-table td { padding: 6px 8px; }
.fin-table.fin-item-table .input { min-width: 92px; padding: 5px 8px; font-size: 12.5px; }
.fin-col-idx { width: 42px; color: var(--text-3); font-size: 12px; }
/* 数字列：表头与数值必须同一条规则右对齐。
   坑：全局 `.data-table th { text-align: left }` 特异性 (0,1,1) 高于 `.fin-num` (0,1,0)，
   只写 `.fin-num` 会造成「表头贴左、数字贴右」整列错位（看账务极易看错列）。
   等宽数字（tabular-nums）让 ¥1,000.00 与 ¥179.00 的小数点成一条线，方便对账。 */
.data-table th.fin-num, .data-table td.fin-num { text-align: right; font-variant-numeric: tabular-nums; min-width: 92px; }
/* 同理收口 .num（明细/审批类表格的数字列），避免新表又只标 td 不标 th */
.data-table th.num, .data-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.fin-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
/* 操作列。★ 三条铁律（都是踩过的坑）：
   1) 禁止给 td.fin-ops 设 display:flex —— 会覆盖 table-cell，该列脱离表格布局、宽度按内容算，
      而表头仍是 table-cell，两套排版机制导致右缘差 14~18px，看着就是"没对齐"。
      表头与数据统一用 text-align 对齐（同一机制）即可。
   2) 操作项必须 nowrap：窗口窄或浏览器缩放（110%/125%）时若能折行，会折成上下两行。
   3) 操作项做成等高小标签（inline-flex + vertical-align:middle），文字垂直居中，
      不依赖字形墨迹，视觉上永远成一条线。 */
.fin-ops {
  white-space: nowrap; text-align: right; min-height: 22px;
  position: sticky; right: 0; z-index: 2; background: var(--card-bg);
  box-shadow: -6px 0 8px -6px rgba(15, 23, 42, .12);
}
/* 表头必须带 .data-table th 前缀提高特异性（(0,2,1) 才能压过 .data-table th 的 (0,1,1)），
   否则表头仍左对齐、内容右对齐，差半个列宽 —— 这就是"总览正常、下钻歪"这类现象的根因。 */
.data-table th.fin-ops { z-index: 3; background: #f8fafc; text-align: right; }
.fin-ops a, .fin-ops button {
  display: inline-flex; align-items: center; justify-content: center; vertical-align: middle;
  height: 22px; margin-left: 8px; padding: 0 9px; border: 1px solid var(--border); border-radius: 6px;
  background: #fff; color: var(--primary); text-decoration: none;
  font-size: 12.5px; line-height: 1; cursor: pointer;
}
.fin-ops a:hover { background: #eff6ff; border-color: var(--primary); text-decoration: none; }
.fin-ops a.danger { color: var(--danger); border-color: #fbd5d5; background: #fff7f7; }
.data-table tbody tr:hover .fin-ops { background: #f8fbff; }
.fin-hint { font-size: 12px; color: var(--text-3); line-height: 1.55; }
.fin-inline { display: inline-flex; gap: 6px; width: 100%; }
/* 费用科目维护：停用的科目整行压暗（仍可见，便于重新启用）；刚改过的行高亮一下 */
.subj-off td { opacity: .5; }
.subj-focus td { background: var(--primary-light); }
.fin-sub { font-size: 13px; font-weight: 600; margin: 18px 0 10px; padding-left: 9px; border-left: 3px solid var(--primary); }
.fin-tabs { display: flex; gap: 6px; margin-bottom: 14px; }
.fin-tab { border: 1px solid var(--border); background: var(--card-bg); color: var(--text-2); border-radius: 8px; padding: 7px 18px; font-size: 13px; cursor: pointer; }
.fin-tab.active { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 600; }

/* ---------- 报销明细 / 外援上浮台账（外援单不入工单池，报销明细是它唯一的记录） ---------- */
.fin-field-inline { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); }
.fin-field-inline .input { width: auto; }
.fin-up { color: var(--danger); }
.fin-down { color: var(--success); }
.ex-sec-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; }
.ex-sec-head b { font-size: 13px; font-weight: 600; }
.ex-sec-head span { font-size: 11px; color: var(--text-3); }
.ex-table { width: 100%; border-collapse: collapse; font-size: 12px; table-layout: fixed; }
.ex-table th { background: var(--gray-bg); color: var(--text-2); font-weight: 400; padding: 6px; text-align: left; white-space: nowrap; }
.ex-table td { padding: 5px 6px; border-top: 1px solid var(--border); vertical-align: top; }
.ex-table td.num, .ex-table th.num { text-align: right; }
.ex-table .input { padding: 5px 7px; font-size: 12px; width: 100%; min-width: 0; }
.ex-table select.input { padding-right: 2px; }
/* ⚠️ 表格单元格不能设 display:flex（会覆盖 table-cell 破坏列宽，见 MEMORY 铁律）。
   分类下拉个数按价格本层级渲染后可能只有 1~2 个，用 inline-flex 容器包一层来均分宽度。 */
.ex-cats > .ex-cats-in { display: inline-flex; gap: 4px; width: 100%; }
.ex-cats-in > .input { flex: 1 1 0; min-width: 0; }
.ex-src { display: block; font-size: 10px; color: var(--text-3); margin-top: 2px; }
.ex-src.auto { color: var(--success); }
.ex-src.warn { color: var(--warn); }
.ex-table .pick { font-size: 10px; color: var(--primary); text-decoration: none; margin-left: 4px; }
.ex-table .pick:hover { text-decoration: underline; }
.ex-del { border: none; background: none; color: var(--text-3); cursor: pointer; font-size: 15px; line-height: 1; padding: 6px 4px; }
.ex-del:hover { color: var(--danger); }
.ex-empty { padding: 12px; text-align: center; color: var(--text-3); font-size: 12px; }
.ex-total { background: var(--primary-light); border: 1px solid #bfdbfe; border-radius: var(--radius); padding: 10px 12px; font-size: 12.5px; color: #1e3a8a; margin-top: 14px; }
/* 报销列表「说明」列（2026-10-04）：限宽 200px 自动换行，超出 3 行截断。
   ⚠️ 表格铁律：td 不能改 display，所以不用 -webkit-line-clamp（要 display:-webkit-box），
   改用「内层 div 限高 + overflow:hidden」；td 保持 table-cell，表格仍是浏览器自适应列宽。
   ⚠️ 选择器必须带 `.fin-table td` 前缀 —— 上一行 `.fin-table th,.fin-table td{white-space:nowrap}`
   特异性 (0,2,1) 会压过裸类名 (0,1,0)，导致不换行（与数字列/操作列同一个坑）。 */
.fin-table td.fin-desc { width: 200px; min-width: 168px; max-width: 240px; white-space: normal; vertical-align: top; }
.fin-table th.fin-desc-h { min-width: 168px; }
.fin-table td.fin-desc > .fin-desc-in {
  font-size: 12.5px; color: var(--text-2); line-height: 1.55;
  max-height: 58px;            /* 约 3 行（12.5 × 1.55 ≈ 19.4px） */
  overflow: hidden; word-break: break-word; overflow-wrap: anywhere;
  position: relative; cursor: default;
}
/* 有内容才可悬停看全文（用 data-desc 判定，JS 会给可悬停的加 is-hoverable） */
.fin-table td.fin-desc.is-hoverable > .fin-desc-in:hover { color: var(--text); text-decoration: underline dotted; }
/* 悬停浮层：显示完整说明；由 JS 定位到单元格上方，鼠标移出即消失 */
.fin-desc-pop {
  position: fixed; z-index: 340; max-width: 420px; min-width: 180px;
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 10px 30px rgba(15, 23, 42, .18); padding: 11px 13px;
  font-size: 12.5px; line-height: 1.7; color: var(--text); white-space: normal;
  word-break: break-word; pointer-events: none;   /* 鼠标移出单元格即隐藏，不阻塞 */
}
.fin-desc-pop b { display: block; font-size: 12px; color: var(--text-2); font-weight: 600; margin-bottom: 4px; }
/* 明细表底部汇总行（2026-10-04）：浅灰底 + 上边线，与数据行区分但不用另起一段 */
.ex-table .ex-sum-row td { background: #f8fafc; border-top: 1px solid var(--border); border-bottom: none; font-weight: 600; }
.ex-table .ex-sum-row:hover td { background: #f1f5f9; }
.ex-total b { font-size: 17px; font-weight: 600; color: var(--primary-dark); }
.ex-hint-num { font-size: 11px; color: var(--text-2); }

/* —— 审批流程时间线（报销明细弹窗内，替代"去审批中心查"） —— */
.ex-flow { list-style: none; margin: 2px 0 0; padding: 4px 0 0; }
.ex-flow-step { position: relative; display: flex; gap: 14px; padding: 0 0 16px; }
.ex-flow-step:last-child { padding-bottom: 0; }
.ex-flow-step::before {           /* 竖线：最后一段不画 */
  content: ""; position: absolute; left: 6px; top: 16px; bottom: 0; width: 2px; background: var(--border);
}
.ex-flow-step:last-child::before { display: none; }
.ex-flow-dot {
  position: relative; z-index: 1; flex: 0 0 auto; width: 14px; height: 14px; margin-top: 3px;
  border-radius: 50%; background: var(--gray-bg); border: 3px solid var(--gray-bg);
  box-shadow: 0 0 0 1px var(--border);
}
.ex-flow-step.is-done .ex-flow-dot { background: #16a34a; box-shadow: 0 0 0 1px #16a34a; }
.ex-flow-step.is-reject .ex-flow-dot { background: #dc2626; box-shadow: 0 0 0 1px #dc2626; }
.ex-flow-step.is-wait .ex-flow-dot { background: #f59e0b; box-shadow: 0 0 0 1px #f59e0b; }
.ex-flow-main { flex: 1 1 auto; min-width: 0; }
.ex-flow-t { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13.5px; color: var(--text); }
.ex-flow-t em { font-style: normal; font-size: 12px; color: var(--text-2); }
.ex-flow-tag { font-size: 11px; font-weight: 600; padding: 1px 7px; border-radius: 10px; line-height: 1.6; }
.ex-flow-tag.is-ok { background: #dcfce7; color: #15803d; }
.ex-flow-tag.is-wait { background: #fef3c7; color: #b45309; }
.ex-flow-tag.is-no { background: #fee2e2; color: #b91c1c; }
.ex-flow-who { font-size: 12.5px; color: var(--text-2); margin-top: 3px; }
.ex-flow-note {
  margin-top: 5px; font-size: 12.5px; color: var(--text); background: var(--gray-bg);
  border-left: 2px solid var(--border); border-radius: 0 var(--radius) var(--radius) 0; padding: 5px 10px;
}
.ex-flow-empty { font-size: 12.5px; color: var(--text-2); padding: 6px 0 2px; }
.ex-jpg { margin-right: auto; }

/* —— 新增报销表单：字段多，默认 2 列会占掉 5 行、把下面的明细表挤出视野 ——
   弹窗已是 wide（1180），窗口 ≥920px 就排 3 列（省两行 ≈ 90px）；逐级回落。 */
.ex-grid { grid-template-columns: 1fr; }
.ex-grid .form-field { min-height: 38px; padding: 4px 0; }
.ex-grid .form-field > label { width: 104px; font-size: 12.5px; }
.ex-grid .form-field.span2 { grid-column: span 2; }
.ex-grid .form-field.span3 { grid-column: 1 / -1; }
@media (min-width: 560px) { .ex-grid { grid-template-columns: repeat(2, 1fr); } .ex-grid .form-field.span3 { grid-column: 1 / -1; } }
@media (min-width: 920px) { .ex-grid { grid-template-columns: repeat(3, 1fr); } .ex-grid .form-field.span3 { grid-column: 1 / -1; } }
@media (max-width: 559px) { .ex-grid .form-field.span2 { grid-column: auto; } }

/* 附加费用没添加时不给表头和空行，只留一条窄提示 —— 空表格看着占地方，其实永远没人用 */
.ex-fee-empty {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  border: 1px dashed var(--border); border-radius: var(--radius);
  padding: 7px 12px; font-size: 12.5px; color: var(--text-3); background: var(--gray-bg);
}

/* 可折叠段（其他附加费用）：默认收起 —— 十有八九没有，有的话一眼能看到条数 */
.ex-fold { border: 1px solid var(--border); border-radius: var(--radius); background: var(--card-bg); }
.ex-fold > summary {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; cursor: pointer;
  padding: 9px 12px; font-size: 13px; list-style: none; user-select: none;
}
.ex-fold > summary::-webkit-details-marker { display: none; }
.ex-fold > summary::before { content: "▸"; color: var(--text-3); font-size: 12px; transition: transform .15s; }
.ex-fold[open] > summary::before { transform: rotate(90deg); }
.ex-fold > summary b { font-size: 13.5px; }
.ex-fold > summary span { font-size: 12px; color: var(--text-3); }
.ex-fold > summary:hover { background: var(--gray-bg); }
.ex-fold-n {
  margin-left: auto; font-style: normal; font-size: 11px; min-width: 18px; text-align: center;
  padding: 1px 6px; border-radius: 9px; background: var(--gray-bg); color: var(--text-3);
}
.ex-fold.has-rows > summary { background: #f0f7ff; }
.ex-fold.has-rows .ex-fold-n { background: var(--primary); color: #fff; }
.ex-fold > :not(summary) { margin: 0 12px 12px; }
.tk-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin-bottom: 12px; }
.tk-card { background: var(--gray-bg); border-radius: var(--radius); padding: 10px 12px; }
.tk-card i { display: block; font-style: normal; font-size: 11px; color: var(--text-2); }
.tk-card b { display: block; font-size: 20px; font-weight: 600; margin-top: 3px; }
@media (max-width: 900px) { .tk-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* 算价依据（逐层留痕）：出账能解释「为什么是这个价」 */
.fin-basis { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-top: 6px; }
.layer-chip { display: inline-block; background: #f1f5f9; color: var(--text-2); border-radius: 6px; padding: 2px 8px; font-size: 12px; }
.layer-chip b { color: var(--text); }
.layer-chip.add { background: var(--warn-light); color: var(--warn); }
.layer-chip.sub { background: var(--danger-light); color: var(--danger); }
.layer-chip.total { background: var(--primary); color: #fff; font-weight: 600; }
.layer-chip.total b, .layer-chip.add b, .layer-chip.sub b { color: inherit; }
.layer-arrow { color: var(--text-3); font-size: 12px; padding: 0 3px; }
.fin-line { border-bottom: 1px dashed #f1f5f9; padding: 9px 0; }
.fin-line:last-child { border-bottom: none; }
.fin-line-head { font-size: 13px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.fin-line-amt { margin-left: auto; font-weight: 700; color: var(--primary); }

/* 计算进度条 */
.calc-bar { display: flex; align-items: center; gap: 12px; background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow); padding: 12px 16px; margin-bottom: 12px; font-size: 13px; }
.calc-bar.done { color: var(--success); }
.calc-bar-track { flex: 1; height: 8px; background: #e2e8f0; border-radius: 6px; overflow: hidden; }
.calc-bar-track i { display: block; height: 100%; background: var(--primary); transition: width .3s; }
.calc-bar-text { white-space: nowrap; color: var(--text-2); }

/* 财务大屏卡片与条形图 */
.stat-card .stat-icon { font-size: 20px; float: right; opacity: .5; }
.stat-card .stat-label { font-size: 12px; color: var(--text-3); }
.stat-card .stat-value { font-size: 22px; font-weight: 700; margin: 4px 0 2px; line-height: 1.25; }
.stat-card .stat-sub { font-size: 11.5px; color: var(--text-3); }
.stat-card.warn::before { background: var(--warn); }
.stat-card.danger::before { background: var(--danger); }
.stat-card.danger .stat-value { color: var(--danger); }
.stat-card.warn .stat-value { color: var(--warn); }
.fin-charts { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.fin-charts .chart-card { background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px 18px; }
.fin-charts .chart-card h3 { font-size: 13.5px; margin-bottom: 12px; color: var(--text-2); }
.fin-bar-row { display: flex; align-items: center; gap: 10px; padding: 5px 0; font-size: 12.5px; }
.fin-bar-name { width: 110px; flex: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-2); }
.fin-bar-track { flex: 1; height: 14px; background: #f1f5f9; border-radius: 8px; overflow: hidden; }
.fin-bar-track i { display: block; height: 100%; background: linear-gradient(90deg, #60a5fa, #2563eb); border-radius: 8px; }
.fin-bar-val { width: 96px; flex: none; text-align: right; font-variant-numeric: tabular-nums; }

/* 导入预检报告 */
.imp-report { margin-top: 14px; }
.imp-sum { font-size: 13px; padding: 10px 12px; background: #f8fafc; border-radius: 8px; margin-bottom: 10px; }
.imp-sec { border-radius: 8px; padding: 10px 12px; margin-bottom: 8px; font-size: 12.5px; }
.imp-sec b { display: block; margin-bottom: 6px; }
.imp-sec ul { margin-left: 18px; line-height: 1.7; max-height: 180px; overflow-y: auto; }
.imp-sec.err { background: var(--danger-light); color: #991b1b; }
.imp-sec.warn { background: var(--warn-light); color: #92400e; }
.imp-sec.dup { background: #f1f5f9; color: var(--text-2); }

/* 价格表编辑器 */
.fin-dims { display: flex; gap: 20px; padding: 10px 12px; background: #f8fafc; border-radius: 8px; margin-bottom: 6px; flex-wrap: wrap; }
.fin-rule-head td { background: #f8fafc; font-weight: 600; font-size: 12px; color: var(--text-2); }
.pd-table { width: 100%; font-size: 12.5px; }

/* 规划中占位页 */
.fin-placeholder { background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow); padding: 26px 30px; }
.fin-ph-badge { display: inline-block; background: var(--primary-light); color: var(--primary); border-radius: 20px; padding: 4px 14px; font-size: 12px; margin-bottom: 14px; }
.fin-placeholder ul { margin-left: 20px; line-height: 2; font-size: 13px; color: var(--text-2); }
.fin-placeholder li b { color: var(--text); }

@media (max-width: 1100px) {
  .fin-charts { grid-template-columns: 1fr; }
}

/* 财务模块弹窗表单：.form-field 直接作为 label 时的排布（左侧标签定宽 + 右侧控件自适应） */
.form-field > span:first-child { width: 132px; flex: none; font-size: 13px; color: var(--text-2); line-height: 1.65; padding-top: 5px; }
.form-field > .input, .form-field > .fin-inline { flex: 1; min-width: 0; }
.form-field.form-span2 { grid-column: 1 / -1; }
.form-field .input { width: 100%; }

/* ============ 财务页「怎么用」：操作顺序指引条 ============ */
.fin-flow {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--card-bg); border-left: 3px solid var(--primary);
  border-radius: 8px; box-shadow: var(--shadow);
  padding: 9px 14px; margin-bottom: 12px; font-size: 12.5px;
}
.fin-flow-step { display: inline-flex; align-items: center; gap: 6px; color: var(--text-2); }
.fin-flow-step i {
  display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; border-radius: 50%; flex: none;
  background: var(--primary); color: #fff; font-style: normal; font-size: 11px;
}
.fin-flow-arrow { color: var(--text-3); font-size: 12px; }
.fin-flow-hint { color: var(--text-3); }
.fin-flow-help { margin-left: auto; color: var(--primary); cursor: pointer; font-size: 12.5px; white-space: nowrap; }
.fin-flow-help:hover { text-decoration: underline; }

/* ============ 财务术语速查 ============ */
.fin-gloss { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 22px; margin-top: 14px; }
.fin-gloss-item { border-bottom: 1px dashed var(--border); padding-bottom: 8px; }
.fin-gloss-item b { display: block; font-size: 13px; color: var(--primary); margin-bottom: 3px; }
.fin-gloss-item span { font-size: 12.5px; color: var(--text-2); line-height: 1.6; }
@media (max-width: 900px) { .fin-gloss { grid-template-columns: 1fr; } }

/* 行内术语提示小图标 */
.fin-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 50%; margin-left: 4px;
  background: var(--border); color: var(--text-3);
  font-size: 10px; cursor: help; vertical-align: middle;
}
.fin-tip:hover { background: var(--primary); color: #fff; }

/* 前端更新提醒条（右下角 · 版本巡检发现前端资源变了才出现） */
.ver-bar{position:fixed;right:18px;bottom:18px;z-index:300;display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:10px;background:#15427a;color:#fff;box-shadow:0 6px 20px rgba(8,24,44,.28);font-size:13px}
.ver-bar button{border:0;border-radius:8px;padding:5px 12px;background:#fff;color:#15427a;font-weight:600;cursor:pointer}
/* 维护提示条（2026-10-07）：管理员施工/更新期间顶部常驻，提醒同事先别操作；
   放标记即出现、撤标记即消失，都不需要重启。z-index 高于弹窗(320)，别被弹窗盖住。 */
.mt-bar{position:fixed;top:0;left:0;right:0;z-index:400;display:flex;align-items:center;gap:10px;padding:9px 16px;background:#8a4b00;color:#fff;font-size:13px;box-shadow:0 2px 10px rgba(0,0,0,.18)}
.mt-bar .mt-ico{font-size:15px;line-height:1}
.mt-bar .mt-msg{font-weight:600}
.mt-bar .mt-sub{opacity:.85;font-size:12px}
body.mt-on{padding-top:38px}
/* 空跑单（2026-10-07）：整单没有主品安装时勾它 —— 明细表收起、只填附加费用。
   虚线框 + 浅底，跟普通明细表拉开视觉差别，一眼能看出这单「没有主品」。 */
.ex-blank-sw{display:flex;align-items:center;gap:8px;margin:10px 0 2px;padding:9px 12px;border:1px dashed var(--border);border-radius:var(--radius);background:var(--gray-bg);font-size:13px;cursor:pointer;user-select:none}
.ex-blank-sw input{width:16px;height:16px;cursor:pointer;flex:0 0 auto}
.ex-blank-sw b{font-weight:600;color:var(--text)}
.ex-blank-sw span{color:var(--text-3);font-size:12px}
.ex-blank-tip{margin:8px 0;padding:12px 14px;border-radius:var(--radius);background:var(--warn-light);border:1px solid #fcd9a1;color:#8a5200;font-size:13px;line-height:1.6}
/* 「费用摘要」（2026-10-08）：日常费用报销＝一个金额 + 用途说明，没有明细行。
   以前这类单在列表里点不开（入口判据只认有明细的单）；点开后也不该套一张空的模板明细表，
   所以用这张卡把「金额 / 用途 / 凭证」摆出来 —— 弹窗里就是这三件事，别的都是重复。
   ⚠️ 金额用 tabular-nums 等宽数字，多张单切换时数字不跳位（与全站金额口径一致）。 */
.ex-sum-card{margin:8px 0;padding:14px 16px;border:1px solid var(--border);border-radius:var(--radius);background:var(--gray-bg)}
.ex-sum-amt{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding-bottom:10px;margin-bottom:10px;border-bottom:1px dashed var(--border)}
.ex-sum-amt>span{font-size:12px;color:var(--text-3)}
.ex-sum-amt>b{font-size:22px;line-height:1.2;color:var(--primary-dark);font-variant-numeric:tabular-nums}
/* ⚠️ 下面三条必须带 .ex-sum-card 前缀限定作用域（2026-10-08 事故）：
   明细表的底部合计行也是 <tr class="ex-sum-row">，裸类名选择器会把这里的 display:flex
   一并糊到表格行上 —— tr 一旦成为 flex 容器，它的 <td> 就不再是表格单元格、脱离表格网格，
   整个合计行挤到左边并与表头错列（实测左缘错 547.8px / 右缘错 673.1px，行高也被 1.7 撑高）。
   表格那条同名规则在 .ex-table .ex-sum-row td（见上方「明细表底部汇总行」），两者不要混。 */
.ex-sum-card .ex-sum-row{display:flex;gap:10px;margin-top:8px;font-size:13px;line-height:1.7}
.ex-sum-card .ex-sum-lb{flex:0 0 60px;color:var(--text-3);font-size:12px;padding-top:2px}
.ex-sum-card .ex-sum-tx{flex:1 1 auto;min-width:0;color:var(--text-2);white-space:pre-wrap;word-break:break-word}
/* 「上游结算标准」的渠道细分（2026-10-07）：渠道可能有十来个，排两列网格；
   窄屏降单列。渠道名单列固定 84px 并省略号，保证输入框左缘对齐。 */
.fb-capby-list{display:grid;grid-template-columns:1fr 1fr;gap:6px 12px;margin-top:6px}
.fb-capby-row{display:flex;align-items:center;gap:8px;min-width:0}
.fb-capby-ch{flex:0 0 84px;font-size:12px;color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fb-capby-row .input{flex:1 1 auto;min-width:0}
@media (max-width:640px){.fb-capby-list{grid-template-columns:1fr}}

/* 二级浮层（弹窗里再弹一层，如价格表编辑器 → 从 Excel 导入）。主弹窗 z-index 100，浮层要盖在它之上 */
.float-mask { z-index: 320; }

/* 报销弹窗「单据信息」改单列一项目一行（2026-10-03 用户定版）：
   原来是三列栅格，短字段跨列换行后对不齐；现在标签统一左对齐、输入区统一右对齐 */
/* 新增报销：恢复「上次未提交的草稿」时的顶部提示条（2026-10-07） */
.ex-draft-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 2px 0 10px; padding: 8px 12px; max-width: 720px; line-height: 1.5;
  background: var(--primary-light); border: 1px solid rgba(37,99,235,.22); border-radius: 8px;
  font-size: 12.5px; color: var(--primary-dark);
}
.ex-draft-bar b { color: var(--primary); }
.ex-draft-bar .ex-draft-ic { flex: none; color: var(--primary); }
.ex-draft-bar > span:nth-child(2) { flex: 1; min-width: 0; }
.ex-draft-bar .btn { flex: none; }
.ex-sec-title { font-size: 12px; color: var(--text-3); margin: 2px 0 4px; letter-spacing: .04em; }
.ex-form { display: flex; flex-direction: column; max-width: 720px; }
.ex-form .form-field { align-items: center; min-height: 40px; padding: 5px 0; gap: 10px; }
.ex-form .form-field > .ff-lb { width: 104px; flex: none; font-size: 13px; color: var(--text-2); line-height: 1.5; }
.ex-form .form-field > .ff-lb i { color: var(--danger); font-style: normal; margin-left: 2px; }
.ex-form .form-field > .input,
.ex-form .form-field > .searchable,
.ex-form .form-field > .fin-inline { flex: 1; min-width: 0; }
.ex-form .fin-inline { display: flex; gap: 8px; }
.ex-form .fin-inline .input { flex: 1; min-width: 0; }
.ex-form .ff-tip { flex: none; font-size: 12px; color: var(--text-3); }
/* 服务单号防重提示（2026-10-17）：命中已提报的非作废案件 → 红字。只改颜色不碰布局 */
.ex-form .ff-tip.ff-tip-err { color: var(--danger); }

/* ============================================================
 * 三期 · 保险理赔（案件台账 / 报案向导 / 时间轴）
 * ============================================================ */
/* 统计条：一排数字卡片，窗口窄时自动换行（不给固定宽度，免得挤成一坨） */
.ins-stats { display: flex; flex-wrap: wrap; gap: 8px 18px; margin: 10px 0 12px;
  font-size: 12.5px; color: var(--text-2); }
.ins-stats b { color: var(--text); font-size: 14px; margin-left: 4px; }
.ins-stats .warn { color: var(--warn); }
.ins-stats .danger { color: var(--danger); }
.ins-stats .ok { color: var(--success); }

/* 案件详情信息表：左列表头定宽，值列自适应；与列表 data-table 同一套配色 */
.data-table.info-table th { width: 92px; background: var(--bg-2); color: var(--text-2);
  font-weight: 500; text-align: right; white-space: nowrap; }
.data-table.info-table td { color: var(--text); word-break: break-all; }

/* 案件号 / 报案编号不折行（LP-20261004-0001 折成三行太难看） */
#insList td:first-child, #insList td:nth-child(11) { white-space: nowrap; }

/* 时间轴 */
.ins-timeline { padding: 6px 0 2px 4px; }
.ins-tl-item { position: relative; padding: 0 0 12px 16px; border-left: 1px solid var(--border); font-size: 12.5px; }
.ins-tl-item:last-child { border-left-color: transparent; padding-bottom: 0; }
.ins-tl-dot { position: absolute; left: -4px; top: 3px; width: 7px; height: 7px; border-radius: 50%;
  background: var(--primary); }
.ins-tl-time { color: var(--text-3); margin-right: 8px; }
.ins-tl-act { color: var(--text); font-weight: 500; }
.ins-tl-note { color: var(--text-3); margin-left: 6px; }

/* P2 索赔材料 checklist：18 槽一行一张卡，已传绿边、缺项红边（纯 div 布局，不碰 table） */
.ins-docbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 6px 0 10px; }
.ins-docbar .btn { white-space: nowrap; }
.ins-docs { display: flex; flex-direction: column; gap: 6px; }
.ins-doc-row { display: flex; align-items: flex-start; gap: 10px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--card-bg, #fff); }
.ins-doc-row.done { border-color: #b7e2c4; background: #f6fbf8; }
.ins-doc-row.miss { border-color: #f0c9c9; }
.ins-doc-no { width: 26px; height: 26px; flex: none; border-radius: 50%; display: flex;
  align-items: center; justify-content: center; font-size: 12px; font-weight: 600;
  background: var(--bg-2); color: var(--text-2); }
.ins-doc-row.done .ins-doc-no { background: var(--success); color: #fff; }
.ins-doc-body { flex: 1; min-width: 0; }
.ins-doc-name { font-size: 13px; font-weight: 500; color: var(--text); }
.ins-doc-name i { color: var(--danger); font-style: normal; margin-left: 2px; }
.ins-doc-tag { margin-left: 6px; padding: 0 4px; font-size: 11px; font-weight: 400;
  color: var(--text-3); border: 1px solid var(--border); border-radius: 4px; }
.ins-doc-sub { margin-top: 2px; font-size: 12px; color: var(--text-3); word-break: break-all; }
.ins-doc-thumbs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.ins-doc-thumb-wrap { position: relative; display: inline-block; }
.ins-doc-thumb { display: block; width: 64px; height: 64px; object-fit: cover;
  border: 1px solid var(--border); border-radius: 6px; background: #fff; }
a.ins-doc-thumb { display: flex; align-items: center; justify-content: center;
  font-size: 20px; color: var(--primary); text-decoration: none; }
.ins-doc-del { position: absolute; right: -6px; top: -6px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--danger); color: #fff; font-size: 12px; font-weight: 400;
  line-height: 18px; text-align: center; cursor: pointer; }
.ins-doc-act { flex: none; display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.ins-doc-act .btn { white-space: nowrap; }

/* 节点引导（2026-10-05）：列表状态标签下的「下一步」+ 详情顶部整条引导
   —— 用户反馈：只显示当前状态，不知道下一个系统节点是什么 */
.ins-next-mini { margin-top: 3px; font-size: 11.5px; color: var(--primary); white-space: nowrap; }
.ins-next-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 9px 12px; margin: 0 0 12px;
  border: 1px solid #cfe2f7; background: var(--primary-light); border-radius: 8px; font-size: 13px; }
.ins-next-bar.done { border-color: #b7e2c4; background: var(--success-light); }
.ins-next-cur { color: var(--text-3); }
.ins-next-cur b { color: var(--text); }
.ins-next-arrow { color: var(--primary); }
.ins-next-txt { color: var(--primary); font-weight: 500; }
.ins-next-bar.done .ins-next-arrow, .ins-next-bar.done .ins-next-txt { color: var(--success); }

/* 拖拽上传：拖到哪一行，哪一行高亮（2026-10-05 用户要求支持拖拽上传） */
.ins-drop-hint { margin: 4px 0 8px; }
/* 材料锁定态提示（2026-10-05 用户：提交给财务后必须锁死）：琥珀色左条 + 不抢眼，
   与「可上传」的蓝色引导条区分开，一眼看出这单是只读的 */
.ins-drop-hint.lock { padding: 6px 10px; border-left: 3px solid var(--warn, #d97706);
  background: var(--warn-light, rgba(217, 119, 6, .08)); border-radius: 0 6px 6px 0; line-height: 1.7; }
.fin-hint.lock, .ins-doc-act .fin-hint.lock { color: var(--warn, #d97706); }
/* 锁定态缩略图外层链接（点开原图新标签页）：inline-block + line-height:0，
   不能影响 .ins-doc-thumb-wrap 的排布与悬停大图定位 */
.ins-doc-thumb-link { display: inline-block; line-height: 0; }
/* 打包命名预览：文件名可能很长，必须能换行不撑破弹窗（2026-10-05 用户要求按邮件主题命名） */
.ins-name-hint { margin: 0 0 8px; padding: 6px 10px; border-left: 3px solid var(--primary);
  background: var(--primary-light); border-radius: 0 6px 6px 0; word-break: break-all; line-height: 1.7; }
.ins-doc-row.drop-on { border-color: var(--primary); border-style: dashed; background: var(--primary-light);
  box-shadow: 0 0 0 2px rgba(37, 99, 235, .14); }
.ins-doc-row.drop-on .ins-doc-sub::after { content: '（松手即上传到这行）'; color: var(--primary); }

/* 理赔申请（2026-10-05 用户定稿的两段式流程）：提交按钮条 + 环节二进度条 + 驳回记录 + 操作区 */
.ins-submit-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 10px 0 4px;
  padding: 10px 12px; border: 1px solid var(--primary); border-left-width: 4px; border-radius: 8px;
  background: var(--primary-light); }
.ins-submit-bar .btn { white-space: nowrap; }
.ins-apply-head { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; margin: 4px 0 10px; }
.ins-step { display: flex; align-items: center; gap: 6px; padding: 4px 10px; border: 1px solid var(--border);
  border-radius: 999px; background: var(--card-bg, #fff); color: var(--text-3); font-size: 13px; }
.ins-step-dot { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px;
  border-radius: 50%; background: var(--border); color: #fff; font-size: 12px; line-height: 1; }
.ins-step.done { border-color: #b7e2c4; background: #f6fbf8; color: var(--text); }
.ins-step.done .ins-step-dot { background: #2f9e5f; }
.ins-step.cur { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(37, 99, 235, .12); }
.ins-step.cur .ins-step-dot { background: var(--primary); }
.ins-step-line { width: 18px; height: 1px; background: var(--border); }
.ins-apply-info { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 8px 0; padding: 8px 10px;
  border-radius: 8px; background: var(--bg-2, #f7f8fa); color: var(--text-2); font-size: 13px; }
.ins-apply-warn { margin: 8px 0; padding: 8px 10px; border-left: 3px solid var(--danger);
  background: #fdf2f2; border-radius: 0 6px 6px 0; color: #8c2b2b; line-height: 1.8; }
.ins-apply-ok { margin: 8px 0; padding: 8px 10px; border-left: 3px solid #2f9e5f;
  background: #f4fbf7; border-radius: 0 6px 6px 0; color: #1f6b43; }
.ins-return-log { margin: 8px 0; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.ins-return-log-t { padding: 6px 10px; background: var(--bg-2, #f7f8fa); color: var(--text-2); font-size: 13px; }
.ins-return-item { display: flex; gap: 10px; align-items: baseline; padding: 6px 10px; font-size: 13px;
  border-top: 1px solid var(--border); }
.ins-return-at { color: var(--text-3); white-space: nowrap; }
.ins-return-rs { flex: 1; color: var(--text); }
.ins-apply-acts { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 10px 0 2px; }
.ins-apply-acts .btn { white-space: nowrap; }
/* 「撤回 / 作废」对照（用户 2026-10-05）：两个按钮挨在一起容易点错，
   点任意一个都先在确认弹窗里把「这两件事差在哪」摆出来 */
.ins-choose { margin: 4px 0 2px; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.ins-choose-row { display: flex; gap: 10px; align-items: baseline; padding: 7px 10px; font-size: 13px;
  border-top: 1px solid var(--border); }
.ins-choose-row:first-child { border-top: 0; }
.ins-choose-row.on { background: var(--primary-light); box-shadow: inset 3px 0 0 var(--primary); }
.ins-choose-k { flex: 0 0 auto; white-space: nowrap; color: var(--text-2); }
.ins-choose-row.on .ins-choose-k { color: var(--primary); font-weight: 600; }
.ins-choose-d { flex: 1; color: var(--text); line-height: 1.7; }

/* 粘贴上传（2026-10-05 用户要求：拖拽之外还要能直接 Ctrl/⌘+V 贴截图）
   材料行可点选为「粘贴目标」；用 inset 阴影画左侧竖条，不改 border 宽度 → 不会引起行高跳动 */
.ins-doc-row:not([data-company]) { cursor: pointer; }
.ins-paste-hint { margin: 0 0 8px; }
.ins-paste-hint.on { padding: 6px 10px; border-left: 3px solid var(--primary); background: var(--primary-light);
  border-radius: 0 6px 6px 0; color: var(--primary); }
.ins-doc-row.paste-on { border-color: var(--primary); background: var(--primary-light);
  box-shadow: inset 4px 0 0 var(--primary), 0 0 0 2px rgba(37, 99, 235, .18); }
.ins-doc-row.paste-on .ins-doc-sub::after { content: ' · ⌨ 按 Ctrl / ⌘ + V 粘到这一行'; color: var(--primary); font-weight: 500; }

/* 收款凭证上传区（2026-10-05 用户：财务登记赔款到账要能传银行回单 / 到账截图，「同报案逻辑一样的方式 + 展示」）
   观感与材料行一致：虚线拖拽框 + 缩略图。缩略图复用 .ins-doc-thumb* 两个类，
   所以「悬停看大图」「右上角 × 删除」的样式与行为直接跟着材料区走，不另起一套。 */
.ins-payset { margin: 10px 0 2px; }
.ins-payset-t { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 6px;
  font-size: 13px; font-weight: 500; color: var(--text); }
.ins-payset-t .fin-hint { font-weight: 400; }
.ins-upbox { border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; background: #fff; }
.ins-upbox-thumbs { display: flex; flex-wrap: wrap; gap: 8px; }
.ins-upbox-empty { font-size: 12px; color: var(--text-3); }
.ins-upbox-drop { margin: 8px 0 6px; padding: 10px; text-align: center; font-size: 12.5px; color: var(--text-3);
  border: 1px dashed var(--border); border-radius: 8px; background: var(--bg-2, #f7f8fa); cursor: pointer; }
.ins-upbox-drop b { color: var(--text-2); }
.ins-upbox-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ins-upbox-bar .btn { white-space: nowrap; }
/* 拖拽落点高亮 / 粘贴目标高亮（与材料行的 .drop-on / .paste-on 同一套语汇） */
.ins-upbox.drop-on { border-color: var(--primary); background: var(--primary-light); }
.ins-upbox.drop-on .ins-upbox-drop { border-color: var(--primary); border-style: solid; color: var(--primary); }
.ins-upbox.drop-on .ins-upbox-drop::after { content: '（松手即上传）'; }
.ins-upbox.paste-on { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(37, 99, 235, .18); }
.ins-upbox.paste-on .ins-upbox-drop::after { content: ' · ⌨ 按 Ctrl / ⌘ + V 粘到这里'; color: var(--primary); font-weight: 500; }

/* 缩略图悬停大图预览（2026-10-05 用户：传上去的图没法检查对不对）
   只有一个浮层节点，鼠标离开缩略图即收回；pointer-events:none 防止鼠标进出浮层自己导致抖动，
   z-index 高于弹窗(<=340)，白底 + 阴影，尺寸由 JS 按原图等比算好后写死在 img 上。 */
.ins-preview { position: fixed; z-index: 420; padding: 6px; background: #fff;
  border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 12px 32px rgba(15, 23, 42, .22);
  pointer-events: none; }
.ins-preview img { display: block; border-radius: 6px; background: #fff; }

/* ============================================================
 * 使用说明书排版（2026-10-07）
 * 内容＝项目根 md 转出来的 HTML，类前缀统一 md-，避免与业务表格样式打架
 * ============================================================ */
.manual-card { padding: 22px 26px 30px; }
.manual-head { padding-bottom: 14px; margin-bottom: 18px; border-bottom: 1px solid var(--border); }
.manual-title { font-size: 17px; font-weight: 700; color: var(--text); }
.manual-upd { margin-top: 4px; font-size: 12px; color: var(--text-3); }

.md-h { margin: 26px 0 12px; color: var(--text); font-weight: 700; line-height: 1.4; scroll-margin-top: 70px; }
.md-h:first-child { margin-top: 0; }
.md-h1 { font-size: 22px; padding-bottom: 10px; border-bottom: 2px solid var(--primary); }
.md-h2 { font-size: 18px; padding-left: 10px; border-left: 4px solid var(--primary); }
.md-h3 { font-size: 15.5px; }
.md-h4 { font-size: 14px; color: var(--text-2); }
.md-h5, .md-h6 { font-size: 13px; color: var(--text-3); }

.md-p { margin: 10px 0; font-size: 13.5px; line-height: 1.85; color: var(--text-2); }
.md-list { margin: 10px 0 10px 22px; font-size: 13.5px; line-height: 1.85; color: var(--text-2); }
.md-list li { margin: 3px 0; }
.md-list ul, .md-list ol { margin: 4px 0 4px 20px; }
.md-quote { margin: 12px 0; padding: 10px 14px; background: var(--primary-light);
  border-left: 4px solid var(--primary); border-radius: 0 6px 6px 0;
  font-size: 13px; line-height: 1.8; color: var(--text-2); }
.md-hr { margin: 26px 0; border: 0; border-top: 1px dashed var(--border); }
.md-code { padding: 1px 5px; background: var(--gray-bg); border: 1px solid var(--border);
  border-radius: 4px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; color: var(--primary-dark); word-break: break-all; }
.md-pre { margin: 12px 0; padding: 14px 16px; background: #0f172a; border-radius: 8px; overflow-x: auto; }
.md-pre code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; line-height: 1.7; color: #e2e8f0; background: none; border: 0; padding: 0; }

/* 说明书里的表格：横向可滚，表头浅底 + 左对齐，与业务表区分开 */
.md-table-wrap { margin: 14px 0; overflow-x: auto; border: 1px solid var(--border); border-radius: 8px; }
.md-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.md-table th, .md-table td { padding: 9px 12px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; line-height: 1.7; }
.md-table th { background: var(--gray-bg); font-weight: 600; color: var(--text); white-space: nowrap; }
.md-table td { color: var(--text-2); }
.md-table tbody tr:last-child td { border-bottom: 0; }
.md-table tbody tr:hover td { background: var(--primary-light); }
.md-table code { padding: 0 4px; }

/* ============ 运营看板（2026-10-09）独立单文件，走 iframe 隔离 ============
   看板自带全局样式（body / * / :root），只能整篇隔离 —— 不能拼进 SPA。
   容器撑满内容区并给一个最小高度，内部自行滚动（看板页面会滚动）。
   注意：规则一律带 .dash-frame-wrap 作用域前缀，避免又出现裸类名外溢。 */
.dash-frame-wrap {
  height: calc(100vh - 148px);
  min-height: 520px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.dash-frame-wrap .dash-frame {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  background: #fff;
}

/* ============ 意向人员「新增」草稿提示条（2026-10-10） ============
   面试官填到一半被打断（误关页面 / 切菜单），下次进来提醒「上次填了一半，可以接着填」。
   配色沿用 .ap-form-hint 的暖黄 —— 是提示不是报错，不该用红色吓人。
   按钮固定不伸缩、文字占剩余宽度；窄屏换行时按钮整块下移，不会把文字压成竖排。
   ⚠️ 类名唯一且不进表格，不会触发「裸类名四处糊」那类事故。 */
.draft-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 14px; margin-bottom: 14px;
  background: #fffbeb; border: 1px solid #fcd34d; border-radius: 10px;
  font-size: 13px; color: #92400e; line-height: 1.6;
}
.draft-bar .draft-ico { font-size: 15px; flex: none; }
.draft-bar .draft-text { flex: 1 1 auto; min-width: 220px; }
.draft-bar .draft-text b { color: #78350f; }
.draft-bar .btn { flex: none; }

/* ============================================================
 * 客服排班（2026-10-11）
 * ⚠️ 作用域纪律：凡类名会落在 tr / td / th 上的，布局规则一律带 `.sh-table` 前缀
 *    —— 裸类名不认爹会到处糊（2026-10-08「.ex-sum-row 撞车」把整行挤到左边的事故）。
 *    其余 .sh-cell / .sh-tag / .sh-opt 只落在 div / label 上，可以直写。
 * ⚠️ 表格五铁律：不给 td/th 设 display；对齐只用 text-align；行里格数（含 colspan）= 表头列数。
 * ============================================================ */
.sh-card { padding: 16px 18px; }
.sh-card-title { font-size: 15px; font-weight: 700; margin-bottom: 12px; color: var(--text); }
.sh-card-title small { display: block; font-size: 12px; font-weight: 400; color: var(--text-3); margin-top: 5px; line-height: 1.7; }
.sh-card-title small b { color: var(--text-2); }

.sh-toolbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.sh-toolbar-right { display: flex; gap: 8px; align-items: center; }
.sh-toolbar-foot { margin: 14px 0 0; }
.sh-weeknav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sh-week { font-weight: 600; font-size: 14px; white-space: nowrap; }
.sh-week i { font-style: normal; font-size: 12px; font-weight: 400; color: var(--primary); background: var(--primary-light); border-radius: 10px; padding: 1px 8px; margin-left: 6px; }
/* 周 / 月视图切换（2026-10-11 新增）：分段控件，挂在周导航左侧 */
.sh-mode { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.sh-mode-btn { padding: 3px 12px; font-size: 13px; color: var(--text-2); background: #fff; cursor: pointer; user-select: none; line-height: 1.6; }
.sh-mode-btn + .sh-mode-btn { border-left: 1px solid var(--border); }
.sh-mode-btn.active { background: var(--primary); color: #fff; font-weight: 600; }
/* 只读 / 月度只读提示（调度员看排班、管理员看月视图时显示） */
.sh-ro { font-size: 12px; color: var(--text-3); }
/* 翻周/翻月时**保留旧表格**、只压暗一档表示加载中（不清空 → 版面不塌 → 滚动不跳回页顶） */
#shPane.is-loading .sh-card, #shMinePane.is-loading .sh-card { opacity: .55; transition: opacity .12s; }

.sh-sumline { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.sh-tag { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; border-radius: 20px; font-size: 12px; background: var(--gray-bg); color: var(--text-2); }
.sh-tag b { color: var(--text); font-variant-numeric: tabular-nums; }
.sh-tag-white { background: #eff6ff; color: #1e40af; }
.sh-tag-night { background: #f5f3ff; color: #4c1d95; }
.sh-tag-mid { background: #fff7ed; color: #c2410c; }
.sh-tag-rest { background: #f1f5f9; color: #475569; }
.sh-tag-leave { background: #fef3c7; color: #92400e; }
.sh-tag-warn { background: var(--danger-light); color: var(--danger); }
.sh-tag-ok { background: var(--success-light); color: var(--success); }
.sh-pub { font-size: 12px; color: var(--text-3); }
.sh-pub.is-on { color: var(--success); font-weight: 600; }

/* ── 排班表 ── */
.sh-table th.sh-th-name { width: 132px; text-align: left; }
.sh-table th.sh-th-day { width: 106px; text-align: center; }
.sh-table th.sh-th-day span { display: block; font-size: 11px; font-weight: 400; color: var(--text-3); margin-top: 2px; }
.sh-table th.sh-th-day.is-today { background: var(--primary-light); color: var(--primary); }
.sh-table th.sh-th-sum { width: 112px; text-align: center; }
.sh-table th.sh-th-ops { white-space: nowrap; text-align: right; }
.sh-table th.sh-th-mine { width: 92px; text-align: left; }

.sh-table td.sh-td { padding: 5px 4px; vertical-align: top; text-align: center; }
.sh-table td.sh-td.is-today { background: #f8fbff; }
.sh-table td.sh-td-name { text-align: left; }
.sh-table td.sh-td-sum { text-align: center; }
.sh-table td.sh-td-num { text-align: center; font-variant-numeric: tabular-nums; white-space: nowrap; }
.sh-table td.sh-td-note { text-align: left; color: var(--text-2); font-size: 12px; line-height: 1.7; }
.sh-table td.sh-td-ops { white-space: nowrap; text-align: right; }
.sh-table td.sh-td-preview { width: 156px; }
.sh-table td.sh-td-stat { text-align: left; font-size: 12px; color: var(--text-2); white-space: nowrap; }
.sh-table td.sh-td-stat-n { text-align: center; font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.sh-table .sh-stat-row td { background: #f8fafc; }
.sh-table-mine th, .sh-table-mine td { text-align: left; vertical-align: middle; }

/* ── 月度视图（2026-10-11 新增）：一屏铺满整月，**不横向滚动** ──
   ⚠️ 用户反馈（2026-10-11）：「月视图太大了，看不全；具体班次时段可以不用写，再压缩」——
      所以这里用 `table-layout: fixed` **锁死列宽**（靠表格分配，不靠内容撑），
      并且月视图的格子**不渲染时段文字**（`.sh-cell-t` 是 nowrap，会把窄列硬撑开；
      时段与午间值守改走整格 title + 右上角橙点，见 public/shifts.js 的 shCellHtml(…, compact)）。
   ⚠️ 必须同时把 `.sh-cell` 的 min-width:96px 收掉，否则 31 列 × 96px ≈ 3000px 滚也滚不完。
   ⚠️ 全部带 `.sh-table` 前缀 —— 这些类名会落在 th/td 上，裸类名会到处糊（铁律⑤）。 */
.sh-table.is-month { table-layout: fixed; width: 100%; }
.sh-table.is-month th.sh-th-name { width: 92px; }
.sh-table.is-month th.sh-th-day { width: auto; padding: 0 1px; }
.sh-table.is-month th.sh-th-day span { font-size: 10px; margin-top: 0; }
/* ⚠️ 汇总列必须**足够宽**：表头「出勤 / 本月休」实测需 90px、单元格「26本月休 0 / 4 ⚠」需 82px。
   原来给 76px，`table-layout: fixed` 下格子不会撑宽，**溢出的文字仍会进入祖先滚动容器** →
   整张月表横向滚出 14px（＝用户说的「月视图太大了，看不全」的残留）。
   td 侧原来已有 overflow:hidden（把内容裁掉、不参与祖先滚动），但 **th 侧没有** → 就漏在表头上。
   这里一次给足宽度；再给 th 兜一个 overflow:hidden，防止以后出现更长的文案又把整表顶出去。 */
.sh-table.is-month th.sh-th-sum { width: 96px; overflow: hidden; }
.sh-table.is-month td.sh-td { padding: 4px 1px; }
.sh-table.is-month td.sh-td-name, .sh-table.is-month td.sh-td-sum { overflow: hidden; }
.sh-table.is-month td.sh-td-name .sh-sub, .sh-table.is-month td.sh-td-sum .sh-sub { font-size: 10px; }
.sh-table.is-month .sh-cell { min-width: 0; padding: 3px 1px; border-radius: 5px; }
.sh-table.is-month .sh-cell-n { font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.sh-table.is-month .sh-cell-empty { font-size: 10px; border-radius: 5px; }
.sh-table.is-month td.sh-td-stat { font-size: 11px; }
.sh-table.is-month td.sh-td-stat-n { font-size: 11px; }
/* 月视图里单班次格也是「只写班次名」的紧凑块 —— 需要相对定位来挂右上角橙点 */
.sh-cells.is-compact { position: relative; }

.sh-sub { display: block; font-size: 11px; font-weight: 400; color: var(--text-3); margin-top: 2px; white-space: nowrap; }
.sh-sub.is-warn { color: var(--warn); }
.sh-warn-t { color: var(--danger); font-weight: 600; }

.sh-cell { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  min-width: 96px; min-height: 46px; padding: 6px 8px; border-radius: 8px; color: #fff; line-height: 1.25; }
.sh-cell-n { font-size: 13px; font-weight: 700; }
.sh-cell-t { font-size: 11px; opacity: .92; white-space: nowrap; }
.sh-cell-white { background: #2563eb; }
.sh-cell-night { background: #4c1d95; }
.sh-cell-leave { background: repeating-linear-gradient(45deg, #fde68a, #fde68a 6px, #fcd34d 6px, #fcd34d 12px); color: #7c2d12; }
/* 休息格（未排班）：浅灰底 + 灰字，按设计稿「休息用浅灰（该退到后面）」；
   虚线框保留「可点击排班」的暗示，hover 加深并转实线 */
.sh-cell-empty { background: #f1f5f9; border: 1px dashed var(--border); color: #64748b; font-weight: 400; font-size: 12px; }
.sh-cell-empty:hover { background: #e2e8f0; color: #475569; border-style: solid; }
/* ⚠️ 午间值守条：必须 width:max-content + margin auto —— 用块级 flex 会撑满整格，
   相邻两格的条会贴成一整条（2026-10-11 界面稿踩过，见 MEMORY 排班章节踩坑 A） */
.sh-mini { display: block; width: max-content; max-width: 100%; margin: 3px auto 0; background: #ea580c; color: #fff;
  font-size: 11px; padding: 1px 6px; border-radius: 4px; white-space: nowrap; }

.sh-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 12px; font-size: 12px; color: var(--text-2); }
.sh-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }
.sh-dot-white { background: #2563eb; }
.sh-dot-night { background: #4c1d95; }
.sh-dot-mid { background: #ea580c; }
.sh-dot-leave { background: repeating-linear-gradient(45deg, #fde68a, #fde68a 3px, #fcd34d 3px, #fcd34d 6px); }
.sh-dot-rest { background: #f1f5f9; border: 1px dashed var(--border); box-sizing: border-box; }
.sh-tip { color: var(--text-3); }

.sh-pill { display: inline-block; padding: 2px 10px; border-radius: 20px; color: #fff; font-size: 12px; font-weight: 600; white-space: nowrap; }
.sh-pill-white { background: #2563eb; }
.sh-pill-night { background: #4c1d95; }
.sh-pill-leave { background: #d97706; }
.sh-pill-rest { background: #e2e8f0; color: #64748b; }

/* ── 格子弹窗 / 批量弹窗 ── */
.sh-opts { display: grid; grid-template-columns: repeat(auto-fill, minmax(176px, 1fr)); gap: 8px; margin-bottom: 12px; }
.sh-opt { display: flex; align-items: center; gap: 8px; padding: 9px 11px; border: 1px solid var(--border);
  border-radius: 8px; cursor: pointer; background: #fff; }
.sh-opt i { width: 12px; height: 12px; border-radius: 3px; background: #e2e8f0; flex: none; }
.sh-opt-n { font-size: 13px; font-weight: 600; }
.sh-opt-t { font-size: 12px; color: var(--text-3); margin-left: auto; white-space: nowrap; }
.sh-opt.is-on { border-color: var(--primary); background: var(--primary-light); }
.sh-opt-rest i { background: repeating-linear-gradient(45deg, #e2e8f0, #e2e8f0 3px, #cbd5e1 3px, #cbd5e1 6px); }
.sh-check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-2); margin: 4px 0 14px; }
.sh-note-hint { font-size: 12px; color: var(--text-3); line-height: 1.7; }
.sh-note-hint b { color: var(--text-2); }
.sh-note-warn { background: var(--warn-light); color: #92400e; border-radius: 8px; padding: 10px 12px; font-size: 13px; margin-bottom: 12px; line-height: 1.7; }
.sh-bulk-sec { margin-bottom: 14px; }
.sh-bulk-title { font-size: 13px; font-weight: 600; margin-bottom: 7px; color: var(--text-2); }

/* ── 配置页 ── */
.sh-formline { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sh-formline label { font-size: 13px; color: var(--text-2); }
.sh-dash { color: var(--text-3); }
.sh-unit { font-size: 13px; color: var(--text-2); }
input.sh-time { width: 96px; text-align: center; }
input.sh-num { width: 76px; text-align: center; }

/* ── 一人多班次（2026-10-11）：**总高恒等于单班次格**，颜色在块内横向分层 ──
   ⚠️ 用户反馈：「多个班次在一天，整体模块的颜色可以分对应的层，但是最终大小和全天保持一致，
      否则视觉看着太乱了，感觉都串行了」→ 旧版纵向堆叠（x2=50px / x3=77px）会把整行拉高。
   解法：单位格高只在这里定义一次（`--sh-cell-h`），**单班次与多班次共用同一个高度**；
        多班次改为「一格之内按班次数横向分层」，层内只写班次名，时段/午间值守走 title + 橙点。
   守门：`render-check-shifts.html` §G —— 多班次格高 **严格等于** 单班次格高（`?tall=1` 反红）。 */
.sh-cells { --sh-cell-h: 46px; display: flex; flex-direction: column; gap: 4px; }
/* 单班次块：与「休息格」同高（46px）→ 整张表所有格子等高，行高不再忽高忽低 */
.sh-cell-block { min-height: var(--sh-cell-h); padding: 4px 6px; gap: 0; }
.sh-cell-block .sh-cell-n { font-size: 12px; }
.sh-cell-block .sh-cell-t { font-size: 11px; }
.sh-cell-block .sh-mini { margin-top: 2px; font-size: 11px; padding: 0 5px; }

/* 多班次：**锁死高度**（不随层数增高），层高自动等分 */
.sh-cells.is-multi { position: relative; height: var(--sh-cell-h); gap: 2px; }
.sh-cells.is-multi .sh-cell-block { flex: 1 1 0; min-height: 0; padding: 0 4px; overflow: hidden;
  border-radius: 3px; justify-content: center; }
.sh-cells.is-multi .sh-cell-block:first-of-type { border-radius: 8px 8px 3px 3px; }
.sh-cells.is-multi .sh-cell-block:last-of-type { border-radius: 3px 3px 8px 8px; }
.sh-cells.is-multi .sh-cell-block .sh-cell-n { font-size: 11px; line-height: 1.1; white-space: nowrap; }
/* 多班次里的「午间值守」：层高只有 ~14px，塞不下橙条 → 降级为右上角橙点（不占高度） */
.sh-mid-dot { position: absolute; top: 2px; right: 2px; z-index: 2; width: 9px; height: 9px;
  border-radius: 50%; background: #ea580c; box-shadow: 0 0 0 2px rgba(255, 255, 255, .9); }

/* ── 配置页：卡片标题行 + 按月休息天数网格 + 颜色选择 ── */
.sh-card-title-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.sh-card-title-row > span { flex: 1 1 auto; min-width: 0; }
.sh-formline-top { margin-top: 10px; }
.sh-rest-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin-top: 10px; }
.sh-rest-cell { display: flex; align-items: center; gap: 8px; background: var(--gray-bg); border-radius: 8px; padding: 8px 10px; }
.sh-rest-cell > span { font-size: 13px; color: var(--text-2); white-space: nowrap; }
.sh-rest-cell.is-now { background: var(--primary-light); box-shadow: inset 0 0 0 1px var(--primary); }
.sh-color { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px;
  border-radius: 6px; cursor: pointer; border: 2px solid transparent; box-sizing: border-box; }
.sh-color i { width: 18px; height: 18px; border-radius: 4px; display: block; }
.sh-color.is-on { border-color: var(--primary); }

/* ── 多选弹窗（.sh-opt 里多了一个 checkbox） ── */
.sh-opts-multi .sh-opt input[type="checkbox"] { margin: 0; flex: none; }

/* ── 我的班表：一天多班次时 pill / 时间竖排 ── */
.sh-pills { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
.sh-times { display: flex; flex-direction: column; gap: 2px; }
.sh-time-line { display: block; white-space: nowrap; }

/* ============ 多轮面试记录（2026-10-13） ============
   一个人要面谈好几轮（初试 / 测试 / 复试 / 终面），每轮结论与要点都不同。
   录入窗体里是「卡片列表 + 新增」，列表格里是「轮次栈 + 最新备注」，悬停看多轮时间线。
   ⚠️ 类名统一 .iv- 前缀：本项目踩过「裸类名到处糊」的坑。
   ⚠️ 表格铁律：td/th 不能改 display；出现在 td 上的类名，样式必须带 `.data-table td` 前缀
      （裸类名 (0,1,0) 压不过 `.data-table td` 的 (0,1,1)）。 */

/* ---- 录入窗体：面试记录编辑区 ---- */
.iv-editor { width: 100%; }
.iv-editor-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 10px;
}
.iv-editor-head .iv-count { font-size: 12.5px; color: var(--text-3); }
.iv-editor-head .iv-count b { color: var(--text); }
.iv-empty {
  font-size: 12.5px; color: var(--text-3); line-height: 1.7;
  border: 1px dashed var(--border); border-radius: var(--radius); padding: 12px 14px; background: #fafbfc;
}
.iv-list { display: flex; flex-direction: column; gap: 8px; }
.iv-card {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 10px 12px; background: #fff;
}
.iv-card.on { border-color: #bfdbfe; background: var(--primary-light); }
.iv-card-top { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-bottom: 5px; }
.iv-card-note { font-size: 12.5px; line-height: 1.7; color: var(--text-2); word-break: break-word; }
.iv-card-ops { display: flex; gap: 6px; margin-top: 8px; }
.iv-none { color: var(--text-3); }
.iv-meta { font-size: 12px; color: var(--text-3); }
.iv-latest {
  font-size: 11px; color: var(--primary); border: 1px solid var(--primary);
  border-radius: 4px; padding: 0 5px; line-height: 1.6;
}
/* 轮次标签：四个常驻轮次各一个色，扫一眼就知道面到哪一步 */
.iv-round {
  display: inline-block; font-size: 12px; font-weight: 600; line-height: 1.7;
  padding: 0 8px; border-radius: 5px; background: #f1f5f9; color: #64748b; white-space: nowrap;
}
.iv-round.r1 { background: #f1f5f9; color: #64748b; }
.iv-round.r2 { background: var(--warn-light); color: var(--warn); }
.iv-round.r3 { background: #f5f3ff; color: #7c3aed; }
.iv-round.r4 { background: var(--primary-light); color: var(--primary); }
/* 结论：绿=待录用、橙=储备备选、红=不予录用 */
.iv-res {
  display: inline-block; font-size: 12px; line-height: 1.7; padding: 0 7px;
  border-radius: 9px; background: #f1f5f9; color: #64748b; white-space: nowrap;
}
.iv-res.ok   { background: var(--success-light); color: var(--success); }
.iv-res.wait { background: var(--warn-light); color: var(--warn); }
.iv-res.no   { background: var(--danger-light); color: var(--danger); }

/* ---- 列表页：面试记录列 ---- */
.data-table td.cell-iv { width: 250px; min-width: 210px; max-width: 330px; white-space: normal; vertical-align: top; }
.data-table th.cell-iv { min-width: 210px; }
.iv-stack { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin-bottom: 4px; }
.iv-chip {
  display: inline-flex; align-items: center; font-size: 11px; line-height: 1.7;
  padding: 0 7px; border-radius: 9px; background: #f1f5f9; color: #64748b; white-space: nowrap;
}
.iv-chip.r1 { background: #f1f5f9; color: #64748b; }
.iv-chip.r2 { background: var(--warn-light); color: var(--warn); }
.iv-chip.r3 { background: #f5f3ff; color: #7c3aed; }
.iv-chip.r4 { background: var(--primary-light); color: var(--primary); }
.iv-chip.on { font-weight: 600; box-shadow: inset 0 0 0 1px currentColor; }
.iv-chip.ok   { background: var(--success-light); color: var(--success); }
.iv-chip.wait { background: var(--warn-light); color: var(--warn); }
.iv-chip.no   { background: var(--danger-light); color: var(--danger); }
.iv-count { font-size: 11px; color: var(--text-3); }
.iv-count-none { font-size: 11px; color: var(--text-3); }
.data-table td.cell-iv .iv-cell-note {
  font-size: 12.5px; color: var(--text-2); line-height: 1.55;
  max-height: 38px;                 /* 约 2 行 */
  overflow: hidden; word-break: break-word; overflow-wrap: anywhere;
}
.data-table td.cell-iv.is-hoverable .iv-cell-note { color: var(--text); text-decoration: underline dotted; }

/* ---- 悬停浮层：多轮时间线 ---- */
.iv-pop {
  position: fixed; z-index: 341; width: 400px; max-width: 92vw; max-height: 340px; overflow-y: auto;
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 10px 30px rgba(15, 23, 42, .18); padding: 12px 14px;
  font-size: 12.5px; color: var(--text);
  /* ⚠️ 不能设 pointer-events:none：鼠标会穿透浮层，既移不进去也滚不动（2026-10-13） */
}
.iv-pop-hd {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 12px; color: var(--text-2); font-weight: 600; margin-bottom: 9px;
}
.iv-pop-hd .more { color: var(--text-3); font-weight: 400; }
.iv-tl { position: relative; padding-left: 15px; }
.iv-tl::before { content: ''; position: absolute; left: 4px; top: 5px; bottom: 5px; width: 1px; background: var(--border); }
.iv-tl-item { position: relative; padding-bottom: 10px; }
.iv-tl-item:last-child { padding-bottom: 0; }
.iv-tl-item::before {
  content: ''; position: absolute; left: -15px; top: 5px; width: 7px; height: 7px;
  border-radius: 50%; background: #cbd5e1; border: 2px solid #fff; box-shadow: 0 0 0 1px var(--border);
}
.iv-tl-item.on::before { background: var(--primary); box-shadow: 0 0 0 1px var(--primary); }
.iv-tl-top { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 3px; }
.iv-tl-meta { font-size: 11.5px; color: var(--text-3); }
.iv-tl-note { font-size: 12px; line-height: 1.65; color: var(--text-2); word-break: break-word; }

/* 日期型筛选：控件后面跟一个文字标签，避免用户不知道这个日期框是筛什么的 */
/* 日期型筛选：输入框与右侧提示文字**同排**（2026-10-13 修复）
   ⚠️ 之前 .ctrl 是 width:100%，提示 span 被挤到下一行 —— 整个筛选项变两行高，
   flex 居中后日期框被顶上去，与同行其它控件错开十几个像素（看着像"日期框更大"）。
   现在：项内横排不换行 + 日期框定宽，提示文字贴右边，与邻居一条基线。 */
.filter-bar .filter-item.filter-date { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
.filter-bar .filter-item.filter-date input.ctrl { width: 160px; flex: none; }
.filter-date-label { font-size: 12px; color: var(--text-3); margin-right: 4px; white-space: nowrap; }

/* ==================== 侧栏浅色化 + 一级菜单面板（2026-10-13） ====================
   1) 侧栏由深色改为浅色（比工作区深一档，三档层次：侧栏 > 工作区 > 卡片白）
   2) 侧栏只留一级菜单；二级菜单全部搬进点开的半屏面板（含保险理赔流程图）
   动效统一用 --ease 减速曲线，收尾不生硬。 */
:root { --ease: cubic-bezier(.16, 1, .3, 1); --side: #e9eef6; --side-hover: #dee5f0; --side-border: #dbe2ec; }

.app-main-col { position: relative; }

/* ---- 侧栏皮肤 ---- */
.sidebar { background: var(--side); color: #475569; }
.sidebar-brand { color: #0f172a; border-bottom: 1px solid var(--side-border); }
.sidebar-nav::-webkit-scrollbar-thumb { background: #cfd8e6; }
/* 侧栏底部锚定（2026-10-14，用户拍板；2026-10-20 随「同事访问」移除再收紧）：
   nav 由普通块级改成**纵向 flex**，配合 buildNav 里插在「业务分组」与「系统设置」之间的
   `.nav-spacer{flex:1}`，把「系统设置 + 使用说明书」这一区压到侧栏最底部。
   内容比侧栏高时占位自动塌成 min-height=8px，滚动条行为与改动前一致。 */
.sidebar-nav { display: flex; flex-direction: column; }
.nav-spacer { flex: 1 1 auto; min-height: 8px; }

/* ---- 一级菜单项 ---- */
.nav-item { color: #475569; transition: background .18s var(--ease), color .18s var(--ease), box-shadow .18s var(--ease); }
.nav-item:hover { color: #0f172a; background: var(--side-hover); }
.nav-item.active { color: #2563eb; background: #fff; font-weight: 600; box-shadow: 0 1px 3px rgba(15,23,42,.10); }
.nav-item.active::before { background: #2563eb; }
.nav-item.active .nav-icon { color: #2563eb; }
.nav-icon { color: #64748b; }

/* 分组项（一级）：箭头默认朝右，面板打开时朝下 */
.nav-group-item .nav-caret { margin-left: auto; display: flex; width: 13px; height: 13px; color: #94a3b8;
  transform: rotate(-90deg); transition: transform .28s var(--ease), color .18s var(--ease); }
.nav-group-item .nav-caret svg { width: 100%; height: 100%; }
.nav-group-item:hover .nav-caret { color: #64748b; }
.nav-group-item.is-open .nav-caret { transform: rotate(0deg); color: #2563eb; }

/* ---- 半屏菜单面板 ----
   2026-10-13 修复：原先 position:absolute 挂在 .app-main-col 里，但整页滚动发生在 body 上，
   页面一长面板就跟着滚走。改 position:fixed 锁定视口（left=侧栏宽 200px，top=顶栏高 50px）；
   面板内部拆「横幅固定 + .mp-body 自滚」——内容再多也只有内容区滚动，标题不动。 */
.menu-panel {
  position: fixed; left: 200px; top: 50px; bottom: 0; width: calc(50vw - 100px); min-width: 430px; z-index: 30;
  display: flex; flex-direction: column;
  background-image:
    linear-gradient(rgba(37,99,235,.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(37,99,235,.035) 1px, transparent 1px),
    linear-gradient(160deg, #f8fafd 0%, #eef4fb 46%, #f7f9fd 100%);
  background-size: 24px 24px, 24px 24px, auto;
  background-attachment: local, local, local;
  border-right: 1px solid var(--side-border); box-shadow: 14px 0 38px rgba(15,23,42,.18);
  overflow: hidden; padding: 18px 24px 0;
  transform: translateX(-6%) translateZ(0); opacity: 0; pointer-events: none;
  transition: transform .28s var(--ease), opacity .20s ease, box-shadow .28s var(--ease);
}
.menu-panel.show { transform: none; opacity: 1; pointer-events: auto; }
/* 横幅（标题区）：不参与滚动 */
.menu-panel .mp-banner { flex: none; }
/* 内容区：唯一滚动的地方 */
.mp-body { flex: 1; min-height: 0; overflow-y: auto; margin: 0 -24px; padding: 14px 24px 30px; }
.mp-body::-webkit-scrollbar { width: 6px; }
.mp-body::-webkit-scrollbar-thumb { background: #d5deeb; border-radius: 3px; }
.mp-body::-webkit-scrollbar-thumb:hover { background: #c2cede; }
.menu-scrim { position: fixed; left: 200px; right: 0; top: 50px; bottom: 0; background: rgba(15,23,42,.10);
  z-index: 25; opacity: 0; pointer-events: none; transition: opacity .24s var(--ease); }
.menu-scrim.show { opacity: 1; pointer-events: auto; }
@media (max-width: 900px) {
  .menu-panel { left: 64px; width: auto; min-width: 0; }
  .menu-scrim { left: 64px; }
}

/* ============================================================================
   侧栏可折叠 + 磁吸呼出（2026-10-19，用户拍板）
   ----------------------------------------------------------------------------
   口径：① 侧栏能收起，把宽度还给内容区；② 收起后鼠标贴左边缘自动呼出；
        ③ **呼出是浮层，不挤压已打开的页面**；④ 选完菜单自动缩回；⑤ 要有磁吸感。

   实现要点（改这里之前先读 public/navcollapse.js 顶部注释）：
     · 收起 = `.sidebar` 负 margin → flex 占位归零，内容区平滑变宽；
     · 呼出 = **只加 transform** → transform 不参与布局，视觉滑回来、占位仍是 0，
              所以右侧页面纹丝不动。
   ⚠️ 绝不要把「呼出」写成 margin-left 还原成 0 —— 那是真把页面推走，与需求相反。
   ⚠️ 宽度统一走 --nav-w：≤900px 的媒体查询会把侧栏压成 64px 图标条，两边必须同源，
      否则窄屏收起会「只挪走 64px 却留下 200px 黑洞」。
   ========================================================================== */
.sidebar {
  /* transform 用带过冲的曲线 → 滑到位时轻轻「吸住」，这就是磁吸的手感；
     margin 用标准减速曲线（它是布局变化，过冲会让内容区抖一下）。 */
  transition: margin-left .34s var(--ease),
              transform .40s cubic-bezier(.22, 1.28, .36, 1),
              box-shadow .34s var(--ease);
}
/* 侧栏宽度只在这里定义一次（--nav-w 挂 .app-view，后代与菜单面板一起继承）
   --hint-w 是左侧提示角标的宽度：**角标多宽就让出多宽**，两者必须同源，
   否则收起来以后角标会压住表格第一列（2026-10-19 用户要「预留」的正是这块地）。 */
.app-view { --nav-w: 200px; --hint-w: 26px; }
.app-view.nav-hidden .sidebar { margin-left: calc(-1 * var(--nav-w)); z-index: 60; }
.app-view.nav-hidden .sidebar.is-peek {
  transform: translateX(var(--nav-w));
  box-shadow: 10px 0 30px rgba(15, 23, 42, .18);
}

/* 收起态的磁吸热区：贴着视口左边缘的一条**全高**窄带。
   它只负责「摸得到」（鼠标贴边任意高度都能呼出），视觉交给下面的角标。 */
.nav-rail { position: fixed; left: 0; top: 0; width: 8px; height: 100vh; z-index: 59;
  display: none; cursor: pointer; }
.app-view.nav-hidden .nav-rail { display: block; }

/* 收起态的提示角标（2026-10-19 用户：「菜单隐藏起来在左侧预留一个提示的角标」）
   ----------------------------------------------------------------------------
   为什么不是一根蓝条：热区只有 8px、颜色又淡，等于「只有摸得到、看不到」。
   这里做成贴左边缘的**竖向书签**，竖排「菜单」两字 —— 一眼就知道那里能拉出菜单。

   形态与交互：
     · 26 × 74，只有**右侧**圆角（左侧贴边齐平）→ 像从屏幕边里抽出来的书签；
     · **实心品牌蓝 + 白色竖排「菜单」**：浅灰页面上白底标签几乎看不见（试过，截图基本隐形），
       必须是实色才担当得起「提示」；
     · 悬停 → 颜色压深一档 + 向右滑 3px（磁吸吸附感）；
     · 3.6s 一次「轻轻右探」的呼吸动画 —— 静止的角标容易被当成装饰忽略；
     · 侧栏浮出时**滑出视口 + 让出点击**：它正压在侧栏菜单中部，不收掉会挡事。
   ⚠️ z-index 必须低于侧栏（60），否则浮出后角标会盖在菜单项上；
      同时低于热区（59），最左 8px 仍归全高热区，保证贴边任意高度都能呼出。 */
.nav-hint {
  position: fixed; left: 0; top: 50%; z-index: 58;
  display: none; width: var(--hint-w); height: 74px; padding-top: 1px;
  flex-direction: column; align-items: center; justify-content: center;
  border-radius: 0 12px 12px 0;
  background: linear-gradient(180deg, #3b82f6, #2563eb);
  box-shadow: 2px 3px 14px rgba(37, 99, 235, .34);
  color: #fff; cursor: pointer;
  transform: translate(0, -50%);
  transition: transform .34s cubic-bezier(.22, 1.28, .36, 1),
              opacity .22s var(--ease), box-shadow .26s var(--ease), background .26s var(--ease);
  animation: navHintBreathe 3.6s ease-in-out 1.4s infinite;
}
.app-view.nav-hidden .nav-hint { display: flex; }
.nav-hint span {
  writing-mode: vertical-rl; text-orientation: upright;
  font-size: 12px; font-weight: 700; letter-spacing: 2px; line-height: 1;
  user-select: none;
}
/* is-hot 与 :hover 同一套样式：无头 Chrome 点不出真实 hover，出图/预览时挂这个类代替 */
.nav-hint:hover, .nav-hint.is-hot {
  transform: translate(3px, -50%); animation: none;
  background: linear-gradient(180deg, #2563eb, #1d4ed8);
  box-shadow: 5px 5px 20px rgba(37, 99, 235, .46);
}
/* 侧栏浮出：角标退出（滑出左边并彻底不接收事件） */
.app-view.nav-hidden.nav-peek .nav-hint {
  transform: translate(-100%, -50%); opacity: 0; pointer-events: none; animation: none;
}
@keyframes navHintBreathe {
  0%, 74%, 100% { transform: translate(0, -50%); }
  86% { transform: translate(3px, -50%); }
}

/* 收起后给角标让出宽度（用户原话里的「预留」）：内容左边界退到角标右侧，
   角标不再压住表格第一列。多留 4px 是给角标一个缝，不然像从卡片里长出来的。
   只在 nav-hidden 时生效，展开态一切照旧；过渡与侧栏同步（都是 .34s），切换时不会「跳一格」。 */
.pages-wrap { transition: padding-left .34s var(--ease); }
.app-view.nav-hidden .pages-wrap { padding-left: calc(var(--hint-w) + 4px); }

/* 品牌行右侧的收起按钮：常显但压低对比度，hover 才强调（不抢品牌名的视觉重量） */
.nav-collapse-btn {
  margin-left: auto; flex: none; width: 24px; height: 24px; padding: 0;
  border: 0; border-radius: 6px; background: transparent; color: #8fa0b8; cursor: pointer;
  display: flex; align-items: center; justify-content: center; opacity: .7;
  transition: background .16s var(--ease), color .16s var(--ease), opacity .16s var(--ease);
}
.sidebar-brand:hover .nav-collapse-btn { opacity: 1; }
.nav-collapse-btn:hover { background: #dde5f0; color: #2563eb; opacity: 1; }
.nav-collapse-btn svg { width: 15px; height: 15px;
  transition: transform .34s cubic-bezier(.22, 1.28, .36, 1); }
/* 收起态箭头翻向：此刻点它是「固定展开」，不再是「收起」 */
.app-view.nav-hidden .nav-collapse-btn svg { transform: rotate(180deg); }

/* 品牌行让出按钮位：200 − 15(左内距) − 10(右内距) − 26(标) − 10(间距) − 24(按钮) ≈ 115px，
   「安诚ERP 系统」约 98px，单行放得下；再长就按既有规则出省略号（不折行）。 */
.sidebar-brand { padding-right: 10px; }
.sidebar-brand .brand-text { flex: 1; }

/* 一级菜单面板与遮罩：基准跟着侧栏宽度走（原来写死 200px / 64px，两处容易漂） */
.menu-panel { left: var(--nav-w); transition: left .34s var(--ease), transform .28s var(--ease),
  opacity .20s ease, box-shadow .28s var(--ease); }
.menu-scrim { left: var(--nav-w); transition: left .34s var(--ease), opacity .24s var(--ease); }
/* 侧栏收起 → 面板铺到最左边；但**侧栏正浮出时**要让出它的宽度，
   否则浮层压住面板左侧 200px（2026-10-19 层次改造时加） */
.app-view.nav-hidden .menu-panel,
.app-view.nav-hidden .menu-scrim { left: 0; }
.app-view.nav-hidden.nav-peek .menu-panel,
.app-view.nav-hidden.nav-peek .menu-scrim { left: var(--nav-w); }

@media (max-width: 900px) {
  /* 窄屏侧栏本来就是 64px 图标条，收起时只需挪走 64px；
     折叠按钮一并隐藏（图标条没有品牌文字可让位） */
  .app-view { --nav-w: 64px; }
  .nav-collapse-btn { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar, .nav-rail::after, .nav-collapse-btn svg,
  .menu-panel, .menu-scrim, .nav-hint { transition-duration: .01ms !important; }
  .nav-hint { animation: none !important; }
}

/* ① 一级：横幅 */
.mp-banner { position: relative; overflow: hidden; border-radius: 12px; padding: 18px 22px;
  background: var(--banner); border: 1px solid var(--banner-bd); box-shadow: 0 2px 10px rgba(15,23,42,.05); }
.mp-deco { position: absolute; right: 26px; top: 50%; transform: translateY(-50%); display: flex; gap: 12px; }
.mp-deco i { display: block; border-radius: 10px; background: rgba(37,99,235,.13); }
.mp-deco i:nth-child(1) { width: 40px; height: 56px; }
.mp-deco i:nth-child(2) { width: 66px; height: 72px; background: rgba(37,99,235,.19); }
.mp-deco i:nth-child(3) { width: 40px; height: 46px; margin-top: 14px; }
.mp-brow { display: flex; align-items: center; gap: 12px; position: relative; }
.mp-bicon { width: 40px; height: 40px; border-radius: 11px; background: rgba(255,255,255,.78); color: var(--accent);
  display: flex; align-items: center; justify-content: center; flex: none; box-shadow: 0 2px 6px rgba(15,23,42,.06); }
.mp-bicon svg { width: 21px; height: 21px; }
.mp-crumb { font-size: 11.5px; color: #94a3b8; }
.mp-title { font-size: 21px; font-weight: 800; letter-spacing: .6px; color: #0f172a; margin-top: 1px; }
.mp-desc { font-size: 12.5px; color: #475569; margin-top: 5px; line-height: 1.65; max-width: 78%; position: relative; }
.mp-close { position: absolute; right: 14px; top: 12px; border: none; background: rgba(255,255,255,.75); color: #475569;
  width: 28px; height: 28px; border-radius: 8px; cursor: pointer; font-size: 15px; line-height: 1; z-index: 2;
  transition: background .18s var(--ease), transform .18s var(--ease); }
.mp-close:hover { background: #fff; transform: rotate(90deg); }

/* ② 二级：小节卡片（白底 + 左侧色条 + **右侧竖排「显影」书脊**）
   2026-10-14 用户拍板：分组名从「卡片上方的圆点 + 粗体标题」改为**卡片最右侧的竖排显影**，
   卡片里只剩条目 —— 标题不再被误认为可点选项，上方那两行介绍文案（如「排班 / 客服班表」）也一并去掉。
   敲定参数：竖排 21px / 900、显影浓度 18%、书脊左侧一条淡虚线；条目描述保留。 */
.mp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(238px, 1fr)); gap: 13px; margin-top: 14px; }
.mp-sec { position: relative; overflow: hidden; background: #fff; border: 1px solid #e8edf5; border-radius: 12px;
  padding: 12px 14px 13px; box-shadow: 0 1px 3px rgba(15,23,42,.06); min-height: 100px; }
.mp-sec::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--c); z-index: 3; }
.mp-sec-config { margin-top: 13px; }

/* 右侧「书脊」显影：竖排分组名。字号由渲染时按字数给（--spine-fs，见 app.js spineFs()），
   4 字以内 21px / 5 字 18px / 更长 15px —— 卡片高度有限，长标题也不会被裁成半截字。 */
.spine-card { padding: 12px 46px 13px 14px; }
.wm-spine { position: absolute; z-index: 0; right: 0; top: 0; bottom: 0; width: 44px;
  display: flex; align-items: center; justify-content: center;
  writing-mode: vertical-rl; text-orientation: upright;
  font-size: var(--spine-fs, 21px); font-weight: 900; letter-spacing: .34em; line-height: 1;
  color: #cbd5e1;                                                   /* 不支持 color-mix 时的兜底 */
  color: color-mix(in srgb, var(--c) 18%, transparent);
  border-left: 1px dashed #e6ebf2;
  border-left-color: color-mix(in srgb, var(--c) 16%, #eef2f7);
  pointer-events: none; user-select: none; }
.wm-spine h4 { margin: 0; font: inherit; letter-spacing: inherit; color: inherit; }
.mp-list { position: relative; z-index: 1; }

/* ③ 三级：条目 */
.mp-link { display: flex; align-items: flex-start; gap: 8px; padding: 7px 9px; margin-left: -9px; border-radius: 8px;
  cursor: pointer; transition: background .16s var(--ease), transform .16s var(--ease); }
.mp-link:hover { background: #f1f5f9; transform: translateX(2px); }
.mp-ico { display: flex; width: 15px; height: 15px; margin-top: 2px; color: var(--c); opacity: .9; flex: none; }
.mp-ico svg { width: 100%; height: 100%; }
.mp-n { font-size: 13.5px; color: #0f172a; }
.mp-d { font-size: 11.5px; color: #94a3b8; margin-top: 2px; line-height: 1.5; }
.mp-link.here { background: color-mix(in srgb, var(--c) 12%, #fff); }
.mp-link.here .mp-n { color: var(--c); font-weight: 600; }
.mp-cur { margin-left: auto; margin-top: 1px; font-size: 10.5px; color: var(--c); background: #fff;
  border: 1px solid color-mix(in srgb, var(--c) 30%, #fff); padding: 1px 7px; border-radius: 20px; white-space: nowrap; }

/* ---- 保险理赔：竖向流程图 ---- */
.mp-flow { display: flex; flex-direction: column; margin-top: 14px; }
.mp-step { display: flex; gap: 12px; background: #fff; border: 1px solid #e8edf5; border-radius: 12px;
  padding: 12px 14px; box-shadow: 0 1px 3px rgba(15,23,42,.06); cursor: pointer;
  transition: transform .16s var(--ease), box-shadow .16s var(--ease), background .16s var(--ease); }
.mp-step:hover { transform: translateX(2px); box-shadow: 0 3px 10px rgba(15,23,42,.10); }
.mp-step-no { width: 26px; height: 26px; border-radius: 50%; background: var(--c); color: #fff; font-size: 13px;
  font-weight: 700; display: flex; align-items: center; justify-content: center; flex: none; }
.mp-step-hd { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.mp-step-hd b { font-size: 14px; color: #0f172a; }
.mp-step-page { font-size: 12px; color: #64748b; background: #f1f5f9; border-radius: 20px; padding: 1px 8px; }
.mp-step.here { background: color-mix(in srgb, var(--c) 10%, #fff); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 30%, #fff); }
.mp-step.locked { background: #f8fafc; opacity: .7; cursor: not-allowed; }
.mp-step.locked .mp-step-no { background: #cbd5e1; }
.mp-lock { font-size: 11px; color: #94a3b8; border: 1px dashed #cbd5e1; border-radius: 20px; padding: 1px 7px; }
.mp-arrow { height: 24px; display: flex; align-items: center; margin-left: 18px; color: var(--c); opacity: .6; }
.mp-arrow svg { width: 16px; height: 16px; }

.mp-tip { margin-top: 16px; font-size: 12px; color: #94a3b8; border-top: 1px dashed var(--side-border);
  padding-top: 11px; line-height: 1.7; }

/* 面板内容错峰入场（换组重放） */
.menu-panel.show .mp-banner { animation: mpRise .30s var(--ease) both; }
.menu-panel.show .mp-sec { animation: mpRise .34s var(--ease) both; }
.menu-panel.show .mp-flow { animation: mpRise .30s var(--ease) both; }
.menu-panel.show .mp-sec:nth-child(1) { animation-delay: .03s }
.menu-panel.show .mp-sec:nth-child(2) { animation-delay: .07s }
.menu-panel.show .mp-sec:nth-child(3) { animation-delay: .11s }
.menu-panel.show .mp-sec:nth-child(4) { animation-delay: .15s }
@keyframes mpRise { from { opacity: 0; transform: translateY(8px) } to { opacity: 1; transform: none } }

/* 尊重系统「减少动态效果」 */
@media (prefers-reduced-motion: reduce) {
  .menu-panel, .menu-scrim, .nav-group-item .nav-caret { transition-duration: .01ms !important; }
  .menu-panel.show .mp-banner, .menu-panel.show .mp-sec, .menu-panel.show .mp-flow { animation: none !important; }
}

/* ==================== 面板跳页编排（2026-10-14） ====================
   点面板里的二级菜单时：旧页淡出 → 面板收起中换页 → 新页上浮淡入，
   三段首尾相接，读起来是「菜单收回去、新页面跟着落位」的一个动作。
   只在 .main 上临时挂类，播完即摘，不影响其它换页路径。 */
/* 2026-10-20：换页动画去掉位移，只留淡入淡出。
   原来 mpPageIn 带 translateY(10px)、mpPageOut 带 translateY(-6px)，在有列表的页面上读作
   「换页上浮」，但在**整屏只有一块内容**的页面上（首页插画、好太太工作台右栏）会被读成
   「这东西没停稳、弹了一下」—— 用户两次分别指着这两处报同一个现象。
   淡入同样有「换了一页」的反馈，且不会让任何元素在屏幕上移动，从根上消掉这类误读。 */
@keyframes mpPageOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes mpPageIn { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .main.is-leaving, .main.is-entering-swap { animation: none !important; }
}

/* ==================== 标签页（2026-10-14，用户拍板：激活并刷新 / 上限 6 / 一期基础版） ====================
   结构：#pagesWrap 下每个开着的页面一个 .page-tab（滚动容器，切走时 display:none 保留 DOM 与滚动位置）；
   容器内一个 .main，#mainArea 的 id 始终只挂在当前标签上 → 全部渲染函数零改动。
   切换 = 移交 #mainArea + 切 .on（带 320ms 上浮淡入）；只有 switchPage 才重渲染内容。 */
.tabbar { height: 34px; flex: none; display: flex; align-items: stretch; background: #eef1f6;
  border-bottom: 1px solid var(--border); overflow-x: auto; overflow-y: hidden; }
.tabbar::-webkit-scrollbar { height: 0; }
.tab { display: flex; align-items: center; gap: 7px; padding: 0 8px 0 12px; min-width: 112px; max-width: 180px;
  font-size: 12.5px; color: #475569; cursor: pointer; border-right: 1px solid var(--border);
  position: relative; user-select: none; flex: none; }
.tab:hover { background: #e6ebf3; }
.tab.active { background: #fff; color: #2563eb; font-weight: 600; }
.tab.active::before { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 2px; background: #2563eb; }
.tab .t-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; opacity: .5; flex: none; }
.tab .t-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tab .t-badge { background: #ef4444; color: #fff; font-size: 10px; font-weight: 600; border-radius: 9px;
  padding: 0 5px; height: 15px; line-height: 15px; flex: none; }
.tab .t-close { width: 16px; height: 16px; border-radius: 4px; display: flex; align-items: center;
  justify-content: center; font-size: 13px; color: #94a3b8; margin-left: 1px; flex: none; }
.tab .t-close:hover { background: #e2e8f0; color: #0f172a; }

.pages-wrap { flex: 1; display: flex; min-height: 0; min-width: 0; }
.page-tab { display: none; flex: 1; min-width: 0; overflow-y: auto; }
.page-tab.on { display: block; animation: mpPageIn .32s var(--ease) both; }
.page-tab.on.is-leaving { animation: mpPageOut .12s var(--ease) both; }
/* 首页连淡入也不要（2026-10-20）：换页动画已经去掉了位移（见 mpPageIn），但首页整屏只有
   一张静态插画，任何进场效果都只是在提醒「这里刚才重画过」。直接出现在最终位置最干净。
   实测（rAF 逐帧采样 .welcome-art）：去掉位移前 top 225.8 → 215.8（正好 10px，高度不变）
   → 位移唯一来源就是 mpPageIn 的 translateY，不是图片解码那一路。 */
.page-tab[data-page="welcome"].on { animation: none; }
/* 登录那一刻 .main 还有一条 mainRiseIn（translateY 12px），首屏会再「往上一顶」，一并关掉 */
.app-view.is-entering .page-tab[data-page="welcome"] > .main { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .page-tab.on, .page-tab.on.is-leaving { animation: none !important; }
}

/* ==================== 自定义菜单（2026-10-14） ====================
   三块：① 浮出面板里的外链条目（打开方式徽标）；② 系统设置里的配置页（树形编辑器）；
        ③ 嵌入打开的系统内弹窗。
   配色沿用面板主题变量 --c（renderCustomPanelBody 按分组色阶下发），与业务菜单同一视觉语言。 */

/* ① 面板里的外链条目 */
.mp-link .mp-txt { min-width: 0; flex: 1; }
.cm-op { flex: none; margin-top: 1px; font-size: 10.5px; line-height: 1.6; padding: 1px 7px; border-radius: 20px;
  white-space: nowrap; border: 1px solid #e2e8f0; color: #64748b; background: #f8fafc; }
.cm-op.embed { color: #4f46e5; border-color: #ddd6fe; background: #eef2ff; }
.cm-op.window { color: #0e7490; border-color: #cffafe; background: #ecfeff; }
.mp-empty { padding: 22px 16px; text-align: center; color: #94a3b8; font-size: 12.5px; background: #fff;
  border: 1px dashed #e2e8f0; border-radius: 12px; margin-top: 14px; line-height: 1.8; }

/* ② 配置页（系统设置 → 自定义菜单） */
.cm-card { padding: 16px 18px 20px; }
.cm-hint { font-size: 12.5px; line-height: 1.9; color: #475569; background: #f8fafc; border: 1px solid #eef2f7;
  border-radius: 10px; padding: 11px 14px; margin-bottom: 16px; }
.cm-hint b { color: #0f172a; }
.cm-tree { display: flex; flex-direction: column; gap: 14px; }
.cm-empty-sec { font-size: 12px; color: #94a3b8; padding: 8px 12px; background: #f8fafc; border-radius: 8px; }

.cm-l1 { border: 1px solid #e8edf5; border-radius: 12px; background: #fff; overflow: hidden;
  box-shadow: 0 1px 3px rgba(15,23,42,.05); }
.cm-l1-hd { display: flex; align-items: center; gap: 10px; padding: 11px 14px; background: #f7f9fc;
  border-bottom: 1px solid #eef2f7; flex-wrap: wrap; }
.cm-l1-hd .cm-name { font-size: 14px; color: #0f172a; }
.cm-ibox { width: 26px; height: 26px; border-radius: 8px; background: #eef2ff; color: #4f46e5;
  display: flex; align-items: center; justify-content: center; flex: none; }
.cm-ibox svg { width: 15px; height: 15px; }
.cm-ibox.sm { width: 20px; height: 20px; border-radius: 6px; }
.cm-ibox.sm svg { width: 12px; height: 12px; }
.cm-roles { font-size: 11px; color: #0e7490; background: #ecfeff; border: 1px solid #cffafe;
  border-radius: 20px; padding: 1px 8px; white-space: nowrap; }
.cm-roles.all { color: #64748b; background: #f1f5f9; border-color: #e2e8f0; }
.cm-count { font-size: 11.5px; color: #94a3b8; }
.cm-ops { margin-left: auto; display: flex; gap: 5px; flex-wrap: wrap; }
.cm-btn { height: 26px; padding: 0 9px; font-size: 12px; border-radius: 7px; border: 1px solid #e2e8f0;
  background: #fff; color: #475569; cursor: pointer; transition: background .15s, border-color .15s, color .15s; }
.cm-btn:hover { background: #f1f5f9; border-color: #cbd5e1; color: #0f172a; }
.cm-btn:disabled { opacity: .4; cursor: default; }
.cm-btn.danger { color: #dc2626; border-color: #fecaca; }
.cm-btn.danger:hover { background: #fef2f2; border-color: #fca5a5; }

.cm-secs { padding: 10px 14px 13px; display: flex; flex-direction: column; gap: 9px; }
.cm-l2 { border: 1px solid #eef2f7; border-radius: 10px; background: #fcfdfe; overflow: hidden; }
.cm-l2-hd { display: flex; align-items: center; gap: 8px; padding: 7px 10px; background: #f8fafc; flex-wrap: wrap; }
.cm-l2-hd .cm-name { font-size: 13px; color: #1e293b; }
.cm-tag { font-size: 10.5px; color: #94a3b8; border: 1px solid #e2e8f0; border-radius: 5px; padding: 0 5px; line-height: 1.6; }
.cm-items { padding: 6px 10px 9px; display: flex; flex-direction: column; gap: 5px; }
.cm-l3 { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 8px;
  background: #fff; border: 1px solid #f1f5f9; flex-wrap: wrap; }
.cm-l3 .cm-name { font-size: 13px; color: #0f172a; }
.cm-url { font-size: 11.5px; color: #94a3b8; max-width: 42%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 编辑器弹窗里的表单行 */
.form-row { margin-bottom: 15px; }
.form-row > label { display: block; font-size: 12.5px; color: #475569; margin-bottom: 6px; }
.form-row input[type="text"], .form-row input:not([type]) { width: 100%; box-sizing: border-box; height: 36px;
  padding: 0 11px; border: 1px solid var(--border); border-radius: 8px; font-size: 13px; color: var(--text); background: #fff; }
.form-row input[type="text"]:focus, .form-row input:not([type]):focus { border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37,99,235,.1); outline: none; }

/* 图标选择器 */
.cm-icon-grid { display: flex; flex-wrap: wrap; gap: 7px; }
.cm-icon-opt { width: 38px; height: 38px; border-radius: 9px; border: 1px solid #e2e8f0; background: #fff;
  color: #64748b; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0;
  transition: border-color .15s, background .15s, color .15s; }
.cm-icon-opt svg { width: 17px; height: 17px; }
.cm-icon-opt:hover { border-color: #c7d2fe; color: #4f46e5; }
.cm-icon-opt.on { border-color: #4f46e5; background: #eef2ff; color: #4f46e5; box-shadow: 0 0 0 2px rgba(79,70,229,.12); }

/* 可见范围 chips / 打开方式单选 */
.cm-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.cm-chip { font-size: 12.5px; padding: 5px 13px; border-radius: 20px; border: 1px solid #e2e8f0; background: #fff;
  color: #475569; cursor: pointer; user-select: none; transition: all .15s; }
.cm-chip:hover { border-color: #c7d2fe; }
.cm-chip.on { background: #4f46e5; border-color: #4f46e5; color: #fff; font-weight: 600; }
.cm-chips-tip { font-size: 11.5px; color: #94a3b8; margin-top: 7px; line-height: 1.7; }
.cm-radio { display: flex; flex-direction: column; gap: 7px; font-size: 13px; color: #334155; }
.cm-radio label { display: flex; align-items: center; gap: 7px; cursor: pointer; }

/* ③ 嵌入打开＝**右侧工作区整幅内嵌**（2026-10-14 用户口径：不是微窗，是页面级嵌套，形态同运营看板）。
   高度算式与 `.dash-frame-wrap` 一致：100vh 减去 顶栏 + 标签栏 + 页头。
   规则一律带 `.cm-embed-wrap` 作用域前缀，防裸类名外溢。 */
.cm-embed-wrap { position: relative; height: calc(100vh - 148px); min-height: 520px;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.cm-embed-wrap .cm-embed-frame { display: block; width: 100%; height: 100%; border: 0; background: #fff; }
.cm-embed-wrap .cm-embed-load { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; font-size: 13px; color: #94a3b8; background: #fff; }
.cm-embed-wrap .cm-embed-fallback { position: absolute; left: 0; right: 0; bottom: 0; padding: 10px 14px;
  background: #fffbeb; border-top: 1px solid #fde68a; font-size: 12.5px; color: #92400e;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* ④ 改完某条后把它滚进视野并闪一下（cmAfterChange 的 focusId 定位，2026-10-14）
   —— 配置页保存后会整页重画，滚动条会弹回顶部；定位到目标行 + 闪一下，
      用户不用再从头往下滑。作用域前缀 #cmTree 防裸类名外溢。 */
#cmTree .cm-flash { animation: cmFlash 1.2s var(--ease) both; border-radius: 10px; }
@keyframes cmFlash {
  0% { box-shadow: 0 0 0 3px rgba(79, 70, 229, .5); }
  100% { box-shadow: 0 0 0 3px rgba(79, 70, 229, 0); }
}

/* ============================================================
 * 好太太项目（2026-10-15 新增业务线：信息采集 / 外呼预约 / 订单派工）
 * ------------------------------------------------------------
 * 铁律（本项目踩过的坑，动这段之前先读）：
 *  ① 所有规则一律带 `.ht-` 前缀作用域，**不许出裸类名** —— 裸类名会落到
 *     每个标签页各一份的 DOM 上到处糊（2026-10-08 表格 CSS 相撞事故）。
 *  ② 表格 th 的样式必须写 `.ht-table th`，不能只写 `th`；
 *     td / th 永不设 display；操作列 nowrap（HTML 侧已挂 .ht-op）。
 *  ③ 配色走 :root 变量；「待核对」黄底 = --warn-light 系（amber），
 *     与报销模块的提示色一致，不另造色调。
 * ============================================================ */

/* ---------- 小号按钮（行内操作 / 队列操作用；基础 .btn 在文件头） ---------- */
.btn.btn-xs { height: 26px; padding: 0 10px; font-size: 12.5px; border-radius: 8px; }

/* ---------- 采集页：全宽录入工作台（2026-10-16 删掉左栏 OCR，表单占满整宽） ---------- */
.ht-form-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 16px 20px 0; }
.ht-form-head > b { font-size: 15px; }
.ht-form-note { font-size: 12px; color: var(--text-3); }
.ht-form-note i.ht-req { color: var(--danger); font-style: normal; }
.ht-form-tip { font-size: 12px; color: #065f46; background: #ecfdf5;
  border: 1px solid #a7f3d0; border-radius: 999px; padding: 3px 12px; }

/* 采集表单：两张「有边界」的卡（客户与地址 / 订单），一眼能定位信息区。
   卡头左侧一条彩色竖条做区分：客户与地址=绿、订单=琥珀 —— 扫视成本最低。
   ⚠️ 2026-10-16 二改：原「用户信息」卡只有 2 个字段，一排只用到 5/12、右侧空一大块
   （用户反馈「一行只有两个字段、空间浪费严重」）→ 与地址信息合并成一张卡，
   6 个字段「2+4+2+2+2」正好排满 12 格。别再拆回去。 */
.ht-form-pane form { padding: 10px 20px 20px; }
.ht-sec { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.ht-sec + .ht-sec { margin-top: 14px; }
.ht-sec-h { display: flex; align-items: baseline; gap: 10px; padding: 9px 16px;
  background: var(--gray-bg); border-bottom: 1px solid var(--border);
  font-size: 13px; font-weight: 700; color: var(--text); letter-spacing: .02em; }
.ht-sec-h::before { content: ''; align-self: center; width: 3px; height: 13px;
  border-radius: 2px; background: var(--primary); flex: none; }
.ht-sec-s { font-size: 11.5px; font-weight: 400; color: var(--text-3); letter-spacing: 0; }
.ht-sec-b { padding: 14px 16px 16px; }
/* 分区卡头左侧彩色竖条（2026-10-16 二改：客户与地址合并成一张卡 → 两色） */
.ht-sec-cust .ht-sec-h::before { background: #10b981; }
.ht-sec-order .ht-sec-h::before { background: #f59e0b; }

/* 字段网格：12 格制，**按内容长度分配宽度**（姓名/省市区短字段不占长框，
   详细地址才给宽位）。缺省一档 = 1/3 宽；窄屏逐级降列。 */
.ht-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 13px 14px; }
.ht-grid > .ht-field { grid-column: span 4; }
.ht-grid > .fg2 { grid-column: span 2; }
.ht-grid > .fg3 { grid-column: span 3; }
.ht-grid > .fg4 { grid-column: span 4; }
.ht-grid > .fg5 { grid-column: span 5; }
.ht-grid > .fg6 { grid-column: span 6; }
.ht-grid > .fg9 { grid-column: span 9; }
.ht-grid > .fg12 { grid-column: 1 / -1; }
/* 中屏：改 6 格制（短字段 3 格 ≈ 半行，长字段整行），避免小框被压成几十像素 */
@media (max-width: 1180px) {
  .ht-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  /* ⚠️ 6 格制下短字段一律 span 2（=1/3 行），**不能照搬 12 格制的 span 3**：
     span 3 是半行，一行只塞得下 2 个字段，且每行末尾还空出 1 列（约 234px）——
     2026-10-16 用户实测反馈「一行只有两个字段、空间浪费严重」就是这个映射错位造成的。
     现在的对应关系保证**每一行都正好排满 6 格**（每个分区逐行验算过）。 */
  .ht-grid > .ht-field, .ht-grid > .fg3, .ht-grid > .fg4, .ht-grid > .fg5 { grid-column: span 2; }
  .ht-grid > .fg2 { grid-column: span 2; }
  /* fgh：12 格制下是 1/4 左右，6 格制下要占半行，两个凑一行正好排满 */
  .ht-grid > .fgh { grid-column: span 3; }
  .ht-grid > .fg9 { grid-column: span 4; }
  .ht-grid > .fg6, .ht-grid > .fg12 { grid-column: 1 / -1; }
}
/* 窄屏：全部整行 */
@media (max-width: 760px) {
  .ht-grid { grid-template-columns: 1fr; }
  .ht-grid > .ht-field, .ht-grid > .fg2, .ht-grid > .fg3, .ht-grid > .fg4,
  .ht-grid > .fg5, .ht-grid > .fg6, .ht-grid > .fg9, .ht-grid > .fg12 { grid-column: 1 / -1; }
}
.ht-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ht-label { font-size: 12.5px; font-weight: 600; color: var(--text-2); }
.ht-req { color: var(--danger); font-style: normal; margin-left: 2px; }
.ht-ctrl-row { display: flex; align-items: center; gap: 8px; }
.ht-ctrl { flex: 1; min-width: 0; }
.ht-hint { font-size: 11.5px; color: var(--text-3); white-space: nowrap; }
.ht-remark { resize: vertical; min-height: 76px; }
.ht-form-foot { display: flex; align-items: center; gap: 10px; margin-top: 22px;
  padding-top: 16px; border-top: 1px solid var(--border); }
.ht-grow { flex: 1; }

/* ---------- 采集页：浏览器扩展接收条 ---------- */
/* ---------- 采集页：左队列(2) + 右表单(8)（2026-10-18 用户要求 2:8） ----------
   左边是扩展传过来的信息（一条一卡竖着排队），右边是填表区；
   ⚠️ 左栏**永远占位**：用 .ht-src-slot 常驻第一列，空态时显示提示而不是 display:none，
      否则 grid 里表单会自动补到第一列 → 比例塌成 10:0。 */
.ht-collect-wrap { display: grid; grid-template-columns: minmax(212px, 2fr) minmax(0, 8fr);
  gap: 14px; align-items: start; }
.ht-src-slot { min-width: 0; display: flex; flex-direction: column; gap: 10px;
  position: sticky; top: 8px; max-height: calc(100vh - 210px); overflow-y: auto; padding-right: 2px; }
.ht-src-slot::-webkit-scrollbar { width: 7px; }
.ht-src-slot::-webkit-scrollbar-thumb { background: #d3dbe8; border-radius: 4px; }
.ht-src-empty { border: 1px dashed #cbd5e1; border-radius: var(--radius); background: var(--card-bg);
  padding: 12px 13px; display: flex; flex-direction: column; gap: 5px; }
.ht-src-empty b { font-size: 13px; color: var(--text-2); }
.ht-src-empty span { font-size: 11.5px; color: var(--text-3); line-height: 1.6; }
.ht-src-empty[hidden] { display: none !important; }
.ht-form-pane { min-width: 0; }

.ht-draft-bar { border: 1px solid #a7f3d0; border-radius: var(--radius);
  background: #ecfdf5; padding: 9px 10px 10px; }
.ht-db-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.ht-db-ico { font-size: 15px; }
.ht-db-head b { font-size: 13.5px; color: #065f46; }
.ht-db-count { font-size: 12px; font-weight: 700; color: #047857; background: #d1fae5;
  border-radius: 999px; padding: 1px 9px; }
.ht-db-tip { font-size: 11.5px; color: var(--text-3); line-height: 1.55; margin-top: 5px; }
.ht-db-bulk { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.ht-db-selall { display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
  color: var(--text-2); cursor: pointer; white-space: nowrap; }
.ht-db-selall input { width: 14px; height: 14px; cursor: pointer; }
.ht-db-list { margin-top: 8px; display: flex; flex-direction: column; gap: 7px; }
/* 列式一条一卡：谁/单号 → 号码·地址 → 产品·类型 → 错误位 → 三个动作 */
.ht-db-item { display: flex; flex-direction: column; gap: 3px; padding: 7px 9px 8px;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px; }
.ht-db-item.is-bad { border-color: #fca5a5; background: #fef2f2; }
.ht-db-r1 { display: flex; align-items: center; gap: 7px; }
.ht-db-ck { display: inline-flex; align-items: center; cursor: pointer; }
.ht-db-ck input { width: 14px; height: 14px; cursor: pointer; }
.ht-db-no { font-size: 11.5px; font-weight: 700; color: #047857; flex: none; }
.ht-db-src { font-size: 11px; color: var(--text-3); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; max-width: 60%; }
.ht-db-r2, .ht-db-r3, .ht-db-r4 { font-size: 12px; line-height: 1.55; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.ht-db-r2 { font-weight: 600; color: var(--text); }
.ht-db-r3, .ht-db-r4 { color: var(--text-2); }
.ht-db-r5:empty, .ht-db-err[hidden] { display: none; }
.ht-db-err { display: block; font-size: 11px; color: var(--danger); line-height: 1.5; }
.ht-db-act { display: flex; align-items: center; gap: 6px; margin-top: 5px; flex-wrap: wrap; }
.ht-db-item .btn { flex: none; }
/* 窄屏（≤1180，与表单 6 格制同一断点）降为单列：2:8 在这个宽度会把左栏顶到最小宽、
   右表单被压到不足 6 成 —— 宁可上下堆，也不要一个填不进去的表单 */
@media (max-width: 1180px) {
  .ht-collect-wrap { grid-template-columns: minmax(0, 1fr); }
  .ht-src-slot { position: static; max-height: 300px; }
}

/* ---------- 列表页（外呼 / 派工共用） ---------- */
.ht-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px;
  background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow); padding: 10px 14px; }
.ht-search { width: 260px; }
.ht-date { width: 145px; }
.ht-sep { color: var(--text-3); font-size: 12.5px; }
.ht-tab-n { margin-left: 5px; font-size: 11.5px; color: var(--text-3); font-weight: 600; }
.role-tab.active .ht-tab-n { color: var(--primary); }
/* 表格：th 一律带 .ht-table 前缀（铁律②） */
.ht-table th { white-space: nowrap; font-size: 12.5px; }
.ht-table td { font-size: 13px; vertical-align: middle; }
/* 好太太列表（派工页 8 列）横向内边距比通用表格略收（14 → 12）。
   ⚠️ 2026-10-18：外呼页的 9 列表格已随「整页工作台」下线（操作列/勾选列/复制灰字
      那一套只服务它）—— 派工页仍用 .ht-table，这里的前缀规则保留。 */
.ht-table th, .ht-table td { padding-left: 12px; padding-right: 12px; }
.ht-table .ht-op { white-space: nowrap; text-align: right; }
.ht-table .ht-op .btn { margin-left: 4px; }
.ht-mono { font-variant-numeric: tabular-nums; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
.ht-addr { max-width: 230px; }
/* 地址两段式（2026-10-18 用户要求）：
   第一行「省 市 区县」（不够宽也不折行 —— 三级地址要一眼看全）；
   第二行「详细地址」另起一行，长地址自然换行（门牌/楼栋不能被截断）。 */
.ht-addr-r { font-size: 12px; color: var(--text-3); white-space: nowrap; }
.ht-addr-d { margin-top: 1px; color: var(--text); word-break: break-word; }
.ht-sub { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
/* 客户反馈问题（2026-10-18 用户要求：维修单必须能看到客户反馈）——
   列表行内联一条 .ht-fb-cell；详情/外呼弹窗走 .ht-fb-kv（全宽 KV 行）。
   ⚠️ 不截断：客服要读完整问题才能准备话术；max-width 防撑爆表格列。 */
.ht-fb-cell {
  margin-top: 4px; padding: 3px 7px; border-radius: 4px;
  background: var(--warn-light); border-left: 2px solid var(--warn);
  font-size: 12px; line-height: 1.5; color: #92400e;
  white-space: normal; word-break: break-word; max-width: 24em;
}
.ht-fb-kv > span { color: var(--warn); }
/* 工作台的「客户反馈」独立卡（2026-10-18）：客户原话整段展示，橙色左边条，不截断 */
.ht-sec-fb .ht-sec-h::before { background: var(--warn); }
/* ⚠️ 2026-10-18 第四稿（用户：「问题反馈基本没法显示，只能滚」）——四层卡片压成**一行条**：
   标签 + 原话，高度从 100px 降到 50 上下；用户当晚要求排到「关键信息条」下方。 */
.ht-sec-fb { display: flex; align-items: baseline; gap: 9px; padding: 8px 12px; border: none;
  border-left: 3px solid var(--warn); border-radius: 6px; background: var(--warn-light); overflow: visible; }
.ht-fb-k { flex: none; font-size: 11.5px; font-weight: 700; color: #b45309; }
.ht-fb-v { font-size: 13px; line-height: 1.65; color: #92400e; word-break: break-word; min-width: 0; }
.ht-fb-full { padding: 10px 13px; background: var(--warn-light); border-left: 3px solid var(--warn);
  border-radius: 6px; font-size: 13.5px; line-height: 1.8; color: #92400e; word-break: break-word; }
.ht-fb-kv > b {
  color: #92400e; background: var(--warn-light); border-left: 2px solid var(--warn);
  padding: 3px 9px; border-radius: 4px; font-weight: 500;
  display: inline-block; max-width: 100%; word-break: break-word;
}
/* 服务类型单元格里的「-保内 / -保外」（2026-10-16 用户要求：维修单要能看出是否在保）。
   2026-10-18 用户明确要求「维修-保外 这种在一行显示」→ 纯行内灰字紧跟服务类型，不加底色、不换行。 */
.ht-warranty { font-size: 11.5px; color: var(--text-3); }
.ht-nowrap { white-space: nowrap; }
/* 服务单号查重失败（服务端 409 + field=serviceNo）：把错误钉在出错的输入框上，
   而不是只弹一句 toast 让录入人自己找哪一栏 —— 2026-10-16 用户要求防重。 */
.ht-ctrl.is-bad { border-color: var(--danger); box-shadow: 0 0 0 3px var(--danger-light); }
/* 状态徽章（tag 基础类在文件头；这里只补好太太五态） */
.ht-st-wait { background: #fef3c7; color: #92400e; }
.ht-st-ok { background: #dbeafe; color: #1e40af; }
.ht-st-run { background: #d1fae5; color: #065f46; }
.ht-st-bad { background: var(--danger-light); color: var(--danger); }
.ht-st-part { background: #ede9fe; color: #5b21b6; }
.ht-st-done { background: #e2e8f0; color: #334155; }
.ht-st-off { background: var(--gray-bg); color: var(--text-3); }

/* ---------- 弹窗：外呼登记 ---------- */
.ht-call-sum { padding: 10px 12px; background: var(--gray-bg); border-radius: var(--radius);
  font-size: 13px; margin-bottom: 14px; }
.ht-cr-list { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }
.ht-cr { display: flex; align-items: flex-start; gap: 9px; padding: 9px 11px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius); transition: border-color .15s, background .15s; }
.ht-cr:hover { border-color: var(--primary); }
.ht-cr:has(input:checked) { border-color: var(--primary); background: var(--primary-light); }
.ht-cr input { margin-top: 3px; }
.ht-cr-b { display: flex; flex-direction: column; gap: 2px; }
.ht-cr-b b { font-size: 13px; }
.ht-cr-b i { font-size: 11.5px; color: var(--text-3); font-style: normal; }
.ht-cr-extra { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
.ht-tip { font-size: 12.5px; color: #92400e; background: var(--warn-light);
  border: 1px solid #fde68a; border-radius: 8px; padding: 8px 12px; margin-bottom: 12px; }

/* ---------- 详情：键值对 ----------
   ⚠️ 2026-10-19 「详情」全系统统一成右侧抽屉后，居中的「订单详情」弹窗（分组卡网格 +
   顶部动作条 + 备件虚线卡）已连根拔除 —— 对应的 .ht-det-top / .ht-det-grid /
   .ht-sec.ht-parts / .ht-parts-* 一并删掉，别让它们变成「没人用但还在改」的死样式。
   这里只保留 .ht-kv（分组卡与抽屉键值区都在用）。 */
.ht-kv { display: flex; gap: 8px; font-size: 13px; min-width: 0; }
.ht-kv span { color: var(--text-3); flex: none; }
.ht-kv b { font-weight: 600; word-break: break-all; }

/* ---------- 弹窗：派工（师傅卡片） ---------- */
.ht-workers { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; max-height: 380px; overflow-y: auto; }
.ht-worker { display: flex; align-items: flex-start; gap: 9px; padding: 10px 12px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius); transition: border-color .15s, background .15s; }
.ht-worker:hover { border-color: var(--primary); }
.ht-worker:has(input:checked) { border-color: var(--primary); background: var(--primary-light); }
.ht-worker.is-cur { border-color: #a7f3d0; }
.ht-worker input { margin-top: 4px; }
.ht-w-b { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.ht-w-b b { font-size: 13.5px; }
.ht-w-b i { font-size: 11.5px; color: var(--text-3); font-style: normal; }
.ht-w-b em { font-size: 11px; font-style: normal; color: var(--text-2); background: var(--gray-bg);
  border-radius: 5px; padding: 1px 7px; }
.ht-w-b em.is-busy { color: #92400e; background: #fef3c7; }
.ht-badge-ht { font-size: 10.5px; font-weight: 700; color: #065f46; background: #d1fae5;
  border: 1px solid #a7f3d0; border-radius: 5px; padding: 0 6px; line-height: 18px; }
.ht-check { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-2); cursor: pointer; }
.ht-mt { margin-top: 12px; }

/* ============================================================
 * 好太太 · 外呼工单池 + 认领制（2026-10-16）
 * ------------------------------------------------------------
 * 用户拍板（设计稿 _设计稿/好太太外呼工单池_设计方案_20261016.md）：
 *   归属是叠加在业务状态旁边的第二维 → 列表加「归属」列 + 作用域 tab + 批量操作，
 *   外呼登记从 560px 小弹窗改成 1120px 两栏工作台（字段按「打电话需要什么」排序）。
 * ⚠️ 表格铁律：td/th 永不设 display；th 的样式一律带 .ht-table 前缀；
 *    操作列 nowrap + sticky right（表格可横向滚动，按钮不能被滚走）。
 * ⚠️ 本段只加 .ht-* 类，不与既有类同名，避免触发表格 CSS 相撞（守门 verify-table-css-collision）。
 * ============================================================ */

/* ---------- 页头身份徽标 / 今日统计：2026-10-18 用户「这个区域的提示词按钮都不要，全给我删掉，
   太占用空间」→ 连同 .ht-today / .ht-who / .ht-head-r 一起连根删除（DOM 与 paint 函数已删）。
   身份在「指派弹窗的客服卡片」与权限行为里体现，不再占页头一行。 ---------- */

/* ---------- KPI 条（2026-10-18 整页工作台：类名从 .ht-nav 改为 .ht-wb-kpis） ----------
   ⚠️ 2026-10-18 第四稿（用户：「大屏卡片和筛选组件太占公共空间，客户信息尤其是问题反馈
      显示不全只能滚」）：7 张 70px 大卡 → **一行 30px 分段条**。
      卡片高度从 82px 砍到 38px（含间距），省出的 44px 全给右栏信息卡。
      大卡的五段信息不丢：副标题 u 仍在 DOM（守门用），只是不显示；
      最老等待时长 / 待接单里我的几单 已并入 title，悬停可查。
   卡片是 <button>：全部可点，点 = 切筛选；当前卡 .on 蓝框，有活的卡 .hot 橙计数。 */
.ht-wb-kpis { display: flex; gap: 6px; flex: none; margin-bottom: 8px; flex-wrap: nowrap; overflow: hidden; }
/* 基础皮（其它页面若复用 .ht-kpi 也有底）；工作台里再按分段条覆盖一次 */
.ht-kpi { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  position: relative; overflow: hidden; }
.ht-wb-kpis .ht-kpi { flex: 0 0 auto; min-width: 0; display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 11px; border-radius: 15px; box-shadow: none; cursor: pointer;
  font: inherit; text-align: left; appearance: none; -webkit-appearance: none; transition: border-color .14s, background .14s; }
.ht-wb-kpis .ht-kpi::before { display: none; }             /* 左侧彩条：条状形态里没必要 */
.ht-wb-kpis .ht-kpi span { font-size: 12.5px; color: var(--text-2); margin: 0; display: inline; }
.ht-wb-kpis .ht-kpi b { font-size: 13.5px; font-weight: 700; letter-spacing: 0; }
.ht-wb-kpis .ht-kpi u { display: none; }
.ht-wb-kpis .ht-kpi:hover { border-color: var(--primary); }
.ht-wb-kpis .ht-kpi:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.ht-wb-kpis .ht-kpi.hot b { color: var(--warn); }
.ht-wb-kpis .ht-kpi.on { border-color: var(--primary); background: var(--primary-light); }
.ht-wb-kpis .ht-kpi.on span { color: var(--primary-dark); font-weight: 600; }
.ht-wb-kpis .ht-kpi.on b { color: var(--primary); }

/* ---------- 作用域 / 状态混合 tab（role-tabs 上做少量增强） ---------- */
.ht-tabs { margin-bottom: 14px; }
.ht-tabs .role-tab { display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  white-space: nowrap; padding-left: 10px; padding-right: 10px; }
.ht-tabs .role-tab.hot b { background: var(--warn-light); color: var(--warn); }

/* ---------- 工具栏上的紫色动作（指派，仅主管可见；与主色区分开） ---------- */
.btn.ht-btn-purple { background: #7c3aed; border-color: #7c3aed; color: #fff; }
.btn.ht-btn-purple:hover { background: #6d28d9; border-color: #6d28d9; color: #fff; }
.btn.ht-btn-xs { height: 32px; padding: 0 14px; font-size: 12.5px; }

/* ---------- 表格：操作列 sticky（派工页仍用 .ht-table） ----------
   ⚠️ 2026-10-18：勾选列 / 选中行 / 复制灰字那一套只服务外呼页的 9 列表格，
      表格随整页工作台下线，规则一并删除（不留死样式）。 */
.ht-table .ht-op { position: sticky; right: 0; background: var(--card-bg); }
.data-table tbody tr:hover .ht-op { background: #f8fbff; }
.ht-own { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 600;
  border-radius: 999px; padding: 2px 9px; white-space: nowrap; }
.ht-own.pool { background: #f8fafc; border: 1px dashed #cbd5e1; color: var(--text-3); font-weight: 400; }
.ht-own.assigned { background: var(--warn-light); color: var(--warn); border: 1px solid #fde68a; }
.ht-own.mine { background: var(--primary-light); color: var(--primary); border: 1px solid #bfdbfe; }
.ht-own.other { background: #f8fafc; color: var(--text-2); border: 1px solid var(--border); font-weight: 400; }
.ht-face { width: 17px; height: 17px; border-radius: 50%; flex: none; display: inline-flex;
  align-items: center; justify-content: center; font-size: 10px; font-weight: 700;
  font-style: normal; background: var(--primary); color: #fff; }
.ht-own.assigned .ht-face { background: var(--warn); }
.ht-own.other .ht-face { background: #94a3b8; }

/* ---------- 勾选计数小条（2026-10-18 从「底部浮条」改行内） ----------
   ⚠️ 原 `.ht-footbar` 是 `position:fixed; bottom:24px`，会盖住右栏预约卡的提交区
   （截图里「已选 2 单 / 批量领取」正好压住过程备注和提交按钮）→ 改成工具条里的行内 chip，
   有勾选才出现，批量操作走同一行的「领取选中 / 指派给…」。 */
.ht-picked { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-2);
  background: var(--primary-light); border: 1px solid #bfdbfe; border-radius: 999px;
  padding: 5px 12px; white-space: nowrap; }
.ht-picked[hidden] { display: none !important; }
.ht-picked b { color: var(--primary-dark); font-weight: 600; font-variant-numeric: tabular-nums; }
.ht-picked a { color: var(--primary); text-decoration: none; }
.ht-picked a:hover { text-decoration: underline; }

/* ---------- 外呼登记工作台（1280px 两栏：左看右做） ----------
   2026-10-18：原 1120px 被 `.modal` 的 max-width:880 压成 880（信息拥挤），
   max-width 已在 openModal 同步抬升；这里同时把右栏 380→400、内边距与卡间距加大。 */
.modal-body.ht-wb-body { padding: 0; }
/* 顶部横幅（超期红 / 已派工黄）长在 padding:0 的 body 里，必须自己让出左右边距，
   否则贴着弹窗边框，与下面两栏的内容左边线错开一截。 */
.ht-wb-body > .ht-wb-alert { margin: 14px 22px 0; }
.ht-wb { display: grid; grid-template-columns: minmax(0, 1fr) 400px; }
.ht-wb-l { padding: 18px 22px; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.ht-wb-r { padding: 18px 22px; background: #fbfcfe; display: flex; flex-direction: column; gap: 16px;
  border-left: 1px solid var(--border); }
/* 左栏 gap 已给间距，卡与卡之间不再叠一个 margin-top（否则双层留白） */
.ht-wb-l > .ht-sec + .ht-sec { margin-top: 0; }
/* ---------- 工作台左栏（2026-10-18 重构：电话 → 姓名/地址 → 单类型·技师 → 反馈） ----------
   用户反馈「重点信息混乱」：原来顶部一条里塞了号码 + 姓名 + 省市区 +类型 + 已约，
   下面是五张带序号的卡，拨号前真正要看的东西（谁、去哪、什么单、谁去）散在各处。
   新版动线：① 大号号码（分段）→ ② 姓名 + 完整地址 → ③ 关键信息条 → ④ 客户反馈 → 参考卡。 */
.ht-big-phone { display: flex; flex-direction: column; gap: 7px;
  padding: 13px 16px; background: var(--primary-light); border: 1px solid #bfdbfe; border-radius: var(--radius); }
.ht-bp-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ht-bp-num { font-size: 26px; font-weight: 700; letter-spacing: .6px; font-variant-numeric: tabular-nums;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--primary-dark); line-height: 1.25; }
/* 虚拟号分机：跟在主号后面，字号小一号（主号仍然是第一眼看到的） */
.ht-bp-ext { font-style: normal; font-size: 17px; font-weight: 600; color: var(--primary-dark); opacity: .72; }
/* ⚠️ 2026-10-18 用户反馈「预约上门框太小、信息装不下」：
   四格等分时预约列只有 ~170px，「2026-10-19 上午 09:00-12:00」被折成两行。
   → 预约列 1.55fr（值再 nowrap），类型/技师 1fr，保内 0.85fr。 */
.ht-bp-nm { font-size: 15px; color: var(--text); line-height: 1.65; word-break: break-word; }
.ht-bp-nm b { font-size: 16.5px; color: var(--text); margin-right: 9px; }
.ht-bp-nm i { font-style: normal; color: var(--primary); margin-right: 9px; }
/* 编辑态要把「姓名 + 地址」这行收起（作者样式里有 display 的必须补 [hidden] 规则，铁律） */
.ht-bp-nm[hidden] { display: none !important; }
.ht-big-phone.ht-flash { animation: htFlash 1.2s ease-out; }
/* 就地编辑表单（原在「客户与地址」卡里，现在挂在电话条下方） */
.ht-hero-form { margin-top: 10px; border: 1px solid #bfdbfe; border-radius: var(--radius); background: #f8fbff; }

/* ---------- 关键信息条：拨号前必须知道的五件事（竖排标签 + 值，横排五格） ----------
   ⚠️ 2026-10-18 用户反馈「预约上门框太小、信息装不下」：
   预约列用 **auto**（按内容宽度走）而不是固定 fr —— 值是 nowrap 的，
   给固定比例时一旦不够就会溢出到相邻格（比折行更难看）。auto 保证永远装得下。
   ⚠️ 第 5 格「归属」摆的是 htOwnBadge（头像 + 姓名 + 状态 + 接单时限），
      比原来的「保内/保外」四个字宽得多 —— fr 从 .8 抬到 1.05，宁可让型号列紧一点。 */
.ht-keybar { display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.1fr) minmax(0, 1fr) auto minmax(0, 1.05fr);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--card-bg); overflow: hidden; }
.ht-kb { padding: 10px 14px; min-width: 0; }
.ht-kb + .ht-kb { border-left: 1px solid var(--border); }
.ht-kb > span { display: block; font-size: 11.5px; color: var(--text-3); margin-bottom: 5px; }
.ht-kb > b { display: block; font-size: 13.5px; font-weight: 600; word-break: break-word; }
/* 预约上门：日期 + 时段是一个整体，折成两行就读不连贯了 */
.ht-kb-when > b { white-space: nowrap; }
.ht-kb-none { font-style: normal; font-weight: 400; color: var(--text-3); }
/* 归属格：徽标自带样式，别继承外层的 600 字重把徽标压变形 */
.ht-kb-own > b { font-weight: 400; line-height: 1.6; }
/* 客户服务单类型：黄底 + 红字（2026-10-18 用户要求：维修 / 安装这类要一眼看出来）。
   ⚠️ 颜色写死不取 --warn-light（那个是 #fffbeb，贴在白卡上几乎看不出黄）。 */
.ht-type-tag { display: inline-block; padding: 1px 11px; border-radius: 6px;
  background: #fef3c7; border: 1px solid #fcd34d; color: #b91c1c;
  font-size: 14.5px; font-weight: 700; letter-spacing: .3px; }
.ht-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; border-radius: 6px;
  padding: 2px 8px; background: var(--gray-bg); color: var(--text-2); border: 1px solid var(--border); }
/* 分区卡头彩色竖条：客户=绿 / 服务产品=琥珀 / 保修=紫 / 来源=灰 / 跟进=天蓝 */
.ht-sec-prod .ht-sec-h::before { background: #f59e0b; }
.ht-sec-warr .ht-sec-h::before { background: #8b5cf6; }
.ht-sec-src .ht-sec-h::before { background: #64748b; }
/* （.ht-sec-log 随居中详情弹窗一并删除，2026-10-19；抽屉的「操作记录 / 跟进记录」自带样式） */
.ht-grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px 18px; }
.ht-grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px 18px; }
/* 在 .ht-grid2 / .ht-grid3 里占满整行（工作台「客户与地址」的省市区 / 详址两行）
   ⚠️ 故意不叫 ht-span2：那个名字属于采集页 12 格制时代的废弃类（语义是「占 2 格」），
      同名会让 verify-ht-ext-static 的「废弃类已清除」反向断言失效。 */
.ht-wide { grid-column: 1 / -1; }

/* ---------- 跟进历史 / 流转记录（工作台与详情共用） ---------- */
.ht-hist { display: flex; gap: 10px; padding: 9px 0; font-size: 12.5px; }
.ht-hist + .ht-hist { border-top: 1px dashed var(--border); }
.ht-hist-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; margin-top: 5px; background: var(--primary); }
.ht-hist-dot.miss { background: var(--text-3); }
.ht-hist-dot.bad { background: var(--danger); }
.ht-hist-dot.own { background: #7c3aed; }
.ht-hist-dot.edit { background: var(--warn); }
.ht-hist-dot.disp { background: var(--success); }
.ht-hist b { display: block; font-size: 12.5px; }
.ht-hist span { display: block; font-size: 11.5px; color: var(--text-3); margin-top: 1px; }

/* （2026-10-19 已删：.ht-det-top / .ht-det-grid / .ht-sec.ht-parts —— 详情统一走右侧抽屉，
   居中详情弹窗连根拔除。别再往这里加回去，否则两套详情 UI 必然口径分叉。） */

/* ---------- 指派 / 转派：客服选人卡片 + 负载条 ---------- */
.ht-pick { display: flex; flex-direction: column; gap: 8px; max-height: 320px; overflow-y: auto;
  padding: 2px; margin-top: 6px; }
.ht-pk { display: flex; align-items: center; gap: 11px; border: 1px solid var(--border);
  border-radius: 9px; padding: 10px 13px; cursor: pointer; background: var(--card-bg); transition: border-color .15s, background .15s; }
.ht-pk:hover { border-color: var(--primary); background: var(--primary-light); }
.ht-pk.on { border-color: var(--primary); background: var(--primary-light); box-shadow: 0 0 0 2px rgba(37, 99, 235, .12); }
.ht-pk input { accent-color: var(--primary); flex: none; }
.ht-av { width: 32px; height: 32px; border-radius: 50%; background: var(--primary-light); color: var(--primary);
  display: inline-flex; align-items: center; justify-content: center; font-weight: 600; font-size: 13px; flex: none; }
.ht-av.s2 { background: #f5f3ff; color: #7c3aed; }
.ht-av.s3 { background: var(--warn-light); color: var(--warn); }
.ht-av.s4 { background: var(--success-light); color: var(--success); }
.ht-pk-info { flex: 1; min-width: 0; }
.ht-pk-info b { font-size: 13px; display: block; }
.ht-pk-info i { font-style: normal; font-size: 11.5px; color: var(--text-3); }
.ht-pk-load { font-size: 11.5px; color: var(--text-2); white-space: nowrap; text-align: right; flex: none; }
.ht-pk-load b { display: block; font-size: 14px; color: var(--primary); font-variant-numeric: tabular-nums; }
.ht-pk-load em { font-style: normal; font-size: 11px; color: var(--text-3); }
.ht-bar { display: block; height: 5px; border-radius: 999px; background: var(--gray-bg); overflow: hidden; margin-top: 5px; }
.ht-bar i { display: block; height: 100%; background: var(--primary); border-radius: 999px; }
.ht-bar i.busy { background: var(--warn); }
.ht-ai-tip { display: flex; gap: 8px; align-items: flex-start; background: var(--warn-light);
  border: 1px solid #fde68a; border-radius: 9px; padding: 10px 12px; font-size: 12px;
  color: #92400e; line-height: 1.6; margin-top: 12px; }
.ht-ai-tip b { color: #78350f; }

/* ---------- 窄屏：工作台单栏、指标条降列 ---------- */
@media (max-width: 1180px) {
  .ht-wb { grid-template-columns: minmax(0, 1fr); }
  .ht-wb-r { border-left: 0; border-top: 1px solid var(--border); }
  /* 关键信息条：窄屏改成**两列**。
     ⚠️ 原先是「竖排五段」（老 1280 弹窗左栏 ~500px，五格横排会把「客户服务单类型」压成
        两个字一行）。2026-10-18 整页工作台右栏在 1100 下仍有 ~530px，全竖排会把表单推到
        看不见的地方，两列既不压字又不占高。 */
  .ht-keybar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ht-kb + .ht-kb { border-left: 1px solid var(--border); border-top: 0; }
  .ht-kb:nth-child(odd) { border-left: 0; }          /* 每行第一格不带左线 */
  .ht-kb:nth-child(n+3) { border-top: 1px solid var(--border); }  /* 第二行起加顶线 */
  /* 奇数格数（现 5 格）时最后一行只有半格，让它吃掉整行，别留一块空白 */
  .ht-kb:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 760px) {
  .ht-grid2, .ht-grid3 { grid-template-columns: minmax(0, 1fr); }
}

/* ================= 超期未履约 / 二次联系 / 就地改址（2026-10-16） =================
   三件事：① 工作台顶部要交代「这单为什么又要打」（红色超期 / 黄色已派工横幅）；
          ② 客户信息卡就地编辑（虚拟号、地址采集错是常态，不能让人绕去详情页）。
   ⚠️ ①的列表红底版（tr.ht-overdue）随 2026-10-18 整页工作台下线，改成卡片左红条
      （见 .ht-wb-card.od）——「超期要一眼看见」的口径没变，只是换了载体。
   ⚠️ 凡设 display 的容器必须补 [hidden] 规则，否则 el.hidden=true 会被作者样式盖掉。 */

/* ② 工作台顶部状态横幅（超期红 / 已派工已预约黄） */
.ht-wb-alert { border-radius: 9px; padding: 10px 13px; font-size: 12.5px; line-height: 1.7;
  margin-bottom: 12px; border: 1px solid; }
.ht-wb-alert b { font-weight: 600; }
.ht-wb-alert.bad { background: #fef2f2; border-color: #fecaca; color: #991b1b; }
.ht-wb-alert.bad b { color: #7f1d1d; }
.ht-wb-alert.warn { background: var(--warn-light); border-color: #fde68a; color: #92400e; }
.ht-wb-alert.warn b { color: #78350f; }

/* ════════════ 外呼三态（2026-10-18 按京东待预约界面重构） ════════════
   取代原来的「拨打结果四张单选卡 + 预约时段下拉」。
   ⚠️ 2026-10-18 第三稿（用户拿京东截图拍板「现在这种不方便看」）——**行式表单**：
        ① 预约结果   ○ 预约成功   ○ 预约失败   ● 未确定上门时间      ← 一行
        ② * 未确定上门时间原因 [请选择]  * 下次预约日期 [日期]  下次预约时间 [时间]   ← 一行
        ③ * 过程备注  [textarea ………………………………… 27/200]          ← 一行
      左列竖排胶囊块被否：信息密度太低，一屏装不全。行式＝标签在左、控件在右，京东原版形态。 */
/* ⚠️ flex-direction 必须显式写 row：备注行同时带 .ht-field（column），不写就被它按纵向排，
   子项在交叉轴上按 flex-start 收缩 → textarea 缩成默认 180px（2026-10-18 踩过） */
.ht-3lrow { display: flex; flex-direction: row; align-items: center; gap: 12px; min-width: 0; }
.ht-3lab { flex: none; font-size: 12.5px; font-weight: 600; color: var(--text-2); white-space: nowrap; }
.ht-3s { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; min-width: 0; }
/* 单选圆点（京东那个样式）：未选＝灰空心；选中＝蓝实心 + 外圈蓝框 */
.ht-3p { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font-family: inherit;
  border: 1px solid transparent; background: none; border-radius: 7px; padding: 3px 9px; min-width: 0;
  transition: border-color .14s, background .14s, box-shadow .14s; }
.ht-3p:hover { border-color: #d7dfeb; }
.ht-3dot { width: 14px; height: 14px; border-radius: 50%; border: 1.5px solid #c8d1de; background: #fff;
  flex: none; position: relative; box-sizing: border-box; }
.ht-3p b { font-size: 13px; font-weight: 500; color: var(--text); white-space: nowrap; }
.ht-3p.on { border-color: var(--primary); background: #fff; box-shadow: 0 0 0 2px rgba(37,99,235,.08); }
.ht-3p.on b { color: var(--primary-dark); font-weight: 600; }
.ht-3p.on .ht-3dot { border-color: var(--primary); }
.ht-3p.on .ht-3dot::after { content: ''; position: absolute; inset: 2.5px; border-radius: 50%; background: var(--primary); }
/* 字段行：每组 `标签 控件` 紧挨着，组间拉开距离（不强行等宽对齐，京东也不对齐） */
.ht-3f { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.ht-3f:empty { display: none; }
.ht-3row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 22px; min-width: 0; }
.ht-3c { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ht-3c .ht-ctrl { flex: none; }
.ht-3c select.ht-ctrl { width: 186px; }
.ht-3c input[type="date"].ht-ctrl { width: 148px; }
.ht-3c input[type="time"].ht-ctrl { width: 108px; }
/* 起止时间：两个 time 输入并排；「全天」是快捷方式，不是标签 */
.ht-tm { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.ht-tm .ht-ctrl { width: 108px; }
.ht-tm i { font-style: normal; color: var(--text-3); font-size: 12px; }
.ht-tm .ht-lnk, .ht-lnk { font-size: 11.5px; color: var(--primary); cursor: pointer; white-space: nowrap; }
.ht-tm .ht-lnk:hover { text-decoration: underline; }
.ht-reason.ht-wide, .ht-field .ht-ctrl.ht-wide { width: 100%; }
.ht-3hint { font-size: 11.5px; line-height: 1.6; color: var(--text-3); }
.ht-3hint:empty { display: none; }
.ht-3hint.warn { color: var(--warn); }
.ht-3hint.bad { color: var(--danger); }
/* 备注行：标签在左、textarea 占满右侧，计数压在 textarea 右下角（截图同款） */
.ht-3lrow-note { align-items: flex-start; }
.ht-3lrow-note .ht-3lab { line-height: 1.7; padding-top: 9px; }
.ht-opt { font-size: 10.5px; color: var(--text-3); margin-left: 6px; font-weight: 400; }
.ht-note-wrap { flex: 1 1 auto; min-width: 0; position: relative; }
.ht-note-wrap textarea { width: 100%; resize: vertical; line-height: 1.7; padding-bottom: 17px; }
.ht-note-cnt { position: absolute; right: 9px; bottom: 6px; font-size: 10.5px; color: var(--text-3);
  font-variant-numeric: tabular-nums; pointer-events: none; }
/* 右栏底部：把「其余信息去哪了」说清楚，别让人以为信息丢了 */
.ht-wb-more { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 13px;
  border: 1px dashed var(--border); border-radius: var(--radius); background: #fbfcfe;
  font-size: 11.5px; color: var(--text-3); }
.ht-wb-more span { flex: 1; min-width: 0; }

/* ════════ 外呼页整页工作台（2026-10-18，按批准原型 _design-ht-workbench.html 落地） ════════
   原型三区：页头（.wb-head）→ KPI 行 7 卡（.wb-kpis）→ 双栏（.wb：左 320px 卡片流 + 右单列处理区）。
   ⚠️ 本页**满高不滚**：.page-tab 关掉竖向滚动，左栏卡片流自己滚、右栏信息区自己滚、
      表单贴底 —— 绝不出现「整页滚 + 左栏滚」的双滚动条（原型 .wb 用 grid-template-rows
      封顶是同一目的：隐式行不封顶会把 900px 的格子撑破）。 */
/* ⚠️ 2026-10-18 用户截图：「右侧一大片空白、和下半部分衔接很怪」。
   真因有两层：① `.app-view` 是 `min-height:100vh`，内容一多整个 app 跟着长高 →
   `.page-tab` 拿到的是内容高度（实测 1054px，视口才 757）→ 工作台比屏幕高，表单被推出视口；
   ② 右栏 `.ht-wb-mid { flex:1 }` 再把中间撑满，于是「内容 → 大空白 → 看不见的表单」。
   这里先钉死高度：50 顶栏 + 34 标签栏 = 84（与 `.cm-embed-wrap` 的 148 同一套算法）。
   维护横幅 `body.mt-on` 会再加 38px 顶部内边距，要同步扣掉。 */
/* 2026-10-20：固定常数（84 / 122）换成 height:100% —— 见 .app-view 那条的说明。
   常数对不上时（维护横幅、顶栏跑马灯、窗口缩放中间态）tab 会比可用高度多出十几像素，
   溢到文档上 → 出一次竖向滚动条 → 整个工作区横向缩 15px 再弹回来，就是用户看到的
   「右侧拉伸」。改成跟着 .pages-wrap 的高度走，永远不会算错。 */
.page-tab[data-page="ht-appoint"] { overflow: hidden; height: 100%; min-height: 520px; }
.page-tab[data-page="ht-appoint"] > .main { height: 100%; box-sizing: border-box; padding-bottom: 16px; }
.ht-wb-page { height: 100%; min-height: 0; display: flex; flex-direction: column; }
/* 页头整块已删（2026-10-18 用户：页签栏已有「外呼客户预约」，标题行纯占空间）。
   KPI 行顶上留 2px 内边距，避免卡片投影贴住页签栏。 */
/* 2026-10-18 用户：「大屏卡片 + 筛选组件太占公共空间，客户信息尤其问题反馈显示不全只能滚」。
   → KPI 7 大卡压成分段条（30px），工具条压到 32px 控件 + 更薄内边距。
     两项合计从 ~128px 降到 ~78px，省出的高度全部给右栏信息卡（反馈是打电话前必看的）。 */
.ht-wb-page > .ht-wb-kpis { padding-top: 2px; }
.ht-wb-tools { margin-bottom: 8px; flex: none; padding: 8px 12px; gap: 6px; }
.ht-wb-tools .ctrl, .ht-wb-tools .btn { height: 32px; }
/* 搜索框 168 + 短占位文案：长文案（「搜索服务单号 / 联系人 / 电话 / 地址」）
   在 168 里会被切成「… / 电」半截；撑到 210 又会把导出按钮挤到第二行。
   所以**文案让位**，完整可搜字段挂 title（悬停可查，信息不丢）。 */
.ht-wb-tools .ht-search { width: 168px; }
.ht-wb-tools .ht-date { width: 122px; }
/* 服务技师 / 状态下拉（2026-10-19）：比搜索框窄一档，且**不许被 flex 压缩**
   （flex-shrink 会把 select 压到只剩箭头，选项文字全丢） */
.ht-wb-tools .ht-sel { width: 112px; flex: 0 0 auto; }
/* 服务技师组合框（2026-10-20）：容器定宽、input 撑满；候选面板允许比输入框宽 ——
   112px 里塞不下「田帅 / 张延军」加序号，面板按内容宽（最长 280）浮出，不做 etc 截断。 */
.ht-wb-tools .ht-tech { width: 136px; flex: 0 0 auto; }
.ht-wb-tools .ht-tech .ctrl { width: 100%; }
.ht-wb-tools .ht-tech .searchable-list { left: 0; right: auto; width: max-content; min-width: 176px; max-width: 280px; }
/* 窄屏（≤1180，内容区只剩 ~860）：8 个控件 + 右侧 3 个按钮放不进一行，
   把三档输入一起收窄，保住「筛选控件在同一行」——按钮组换行可以，筛选区散了就难用 */
@media (max-width: 1180px) {
  .ht-wb-tools .ht-search { width: 150px; }
  .ht-wb-tools .ht-date { width: 112px; }
  .ht-wb-tools .ht-sel { width: 104px; }
  .ht-wb-tools .ht-tech { width: 124px; }
}
/* 导出 Excel：挪进工具条、跟在「指派给…」右侧（2026-10-19 用户：不单独占一行；
   原先 .ht-wb-exportrow / .ht-wb-exporttip 那一行连提示小字一起删了）。
   ⚠️ [hidden] 会被作者样式里的 display 覆盖，必须显式补一条。 */
.ht-wb-tools #htWbExport { margin-left: 2px; }
.ht-wb-tools #htWbExport[hidden] { display: none !important; }
/* ── 右栏信息卡的「紧凑档」（2026-10-18 第四稿）────────────────────────
   用户在 1080p（900 高）上看到的是：信息卡内容 361px、可用仅 317px → 底部（关键条）
   被折叠线切掉，只能滚。这里把**只读展示件**逐个收紧 10~15px（不改字号层级）：
   单号头 / 电话条 / 反馈条 / 关键条 / 卡内间距，合计省 ~60px，正好一屏装下。
   ⚠️ 一律挂 .ht-wb-page 作用域：弹窗与详情抽屉里的同名组件保持原尺寸。 */
.ht-wb-page .ht-wb-mhead { padding: 7px 14px; }
.ht-wb-page .ht-wb-mid { padding: 9px 14px 10px; gap: 9px; }
.ht-wb-page .ht-big-phone { padding: 10px 14px; gap: 5px; }
.ht-wb-page .ht-bp-num { font-size: 24px; }
.ht-wb-page .ht-bp-nm { line-height: 1.55; }
.ht-wb-page .ht-sec-fb { padding: 4px 12px; }
.ht-wb-page .ht-kb { padding: 7px 12px; }
.ht-wb-page .ht-kb > span { margin-bottom: 3px; }
.ht-wb-page .ht-wb-alert { padding: 7px 12px; font-size: 12px; line-height: 1.6; margin-bottom: 0; }
/* ⚠️ 类名碰撞（2026-10-18 踩过）：弹窗工作台（.modal-body.ht-wb-body > .ht-wb，左 1fr 右 400px）
   与整页工作台（.ht-wb-page > .ht-wb，左 320px 右 1fr）**共用 .ht-wb 容器类**，
   谁写在后面谁赢 —— 整页规则原本会把弹窗的 400px 右栏挤成 1fr（实测 948px）。
   所以整页的两条 grid 规则必须收拢在 `.ht-wb-page >` 作用域下（ specificity 0,2,0 压住 0,1,0）。 */
.ht-wb-page > .ht-wb { flex: 1; min-height: 0; display: grid; gap: 12px;
  grid-template-columns: 320px minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }

/* 左：卡片流（滚动区自己滚；**不做翻页器**，滚到底自动续拉 + 末尾一行计数）
   overscroll-behavior: contain —— 滚到头不要把滚动「传」给整页（整页本来就 overflow:hidden，
   不 contain 的话触底滚动会被浏览器判成页面滚动尝试，回弹动画反而更迟钝）。 */
.ht-wb-list { min-height: 0; display: flex; flex-direction: column; gap: 9px; }
.ht-wb-cards { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding-right: 2px; }
.ht-wb-cards::-webkit-scrollbar { width: 6px; }
.ht-wb-cards::-webkit-scrollbar-thumb { background: #d3dbe8; border-radius: 3px; }
/* 内层＝弹性回弹的位移目标（不动滚动容器本身，滚动条才不会跟着飘） */
.ht-wb-cards-in { display: flex; flex-direction: column; gap: 9px; will-change: transform; }
.ht-wb-end { text-align: center; font-size: 11px; color: var(--text-3); padding: 8px 0 10px; }
.ht-wb-end[hidden] { display: none; }
.ht-wb-end.loading { color: var(--primary); }
.ht-wb-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: 10px;
  padding: 10px 12px 9px; cursor: pointer; transition: border-color .15s, box-shadow .15s, background .15s; }
.ht-wb-card:hover { border-color: #93c5fd; box-shadow: 0 2px 10px rgba(37,99,235,.07); }
.ht-wb-card.on { border-color: var(--primary); background: #f6faff; box-shadow: 0 2px 12px rgba(37,99,235,.13); }
.ht-wb-card.picked { background: #eff6ff; border-color: #93c5fd; }
/* 超期：左侧红条（inset 阴影）。⚠️ .on.od 必须两个阴影并列 —— 只写红条会把蓝色选中阴影冲掉
   （原型 .wb-card.on.od 同款双阴影，2026-10-18 踩过：单选高亮被红条吃掉的案例） */
.ht-wb-card.od { box-shadow: inset 3px 0 0 var(--danger); }
.ht-wb-card.on.od { box-shadow: inset 3px 0 0 var(--danger), 0 2px 12px rgba(37,99,235,.13); }
.ht-wb-c1 { display: flex; align-items: center; gap: 7px; }
.ht-wb-ck { flex: none; display: flex; margin-right: 1px; cursor: pointer; }
.ht-wb-ck input { width: 14px; height: 14px; cursor: pointer; accent-color: var(--primary); }
.ht-wb-tag { font-size: 11px; line-height: 1.5; padding: 0 6px; border-radius: 4px; border: 1px solid transparent; white-space: nowrap; }
.ht-wb-tag.warn { color: #b45309; background: #fef3c7; border-color: #fcd34d; }
.ht-wb-tag.bad { color: #b91c1c; background: #fee2e2; border-color: #fca5a5; }
.ht-wb-tag.gray { color: var(--text-2); background: #f1f5f9; border-color: #e2e8f0; }
.ht-wb-tag.blue { color: var(--primary-dark); background: var(--primary-light); border-color: #bfdbfe; }
.ht-wb-tag.run { color: #065f46; background: #d1fae5; border-color: #a7f3d0; }
.ht-wb-tag.part { color: #5b21b6; background: #ede9fe; border-color: #ddd6fe; }
.ht-wb-tm { margin-left: auto; font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ht-wb-card.od .ht-wb-tm { color: var(--danger); font-weight: 600; }
.ht-wb-c2 { font-size: 13.5px; font-weight: 600; margin-top: 6px; display: flex; align-items: center; gap: 5px; min-width: 0; }
.ht-wb-c2 .ht-wb-w { flex: none; font-size: 11.5px; font-weight: 600; color: #b91c1c; background: #fef3c7; border: 1px solid #fcd34d; border-radius: 3px; padding: 0 4px; }
.ht-wb-c2 i { font-style: normal; color: #cbd5e1; font-weight: 400; }
.ht-wb-c2 .ht-wb-model { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* c3：客户·电话 与「师傅」徽标同一行（2026-10-20 用户：「既然安排师傅了，这个页面下就要显示师傅名称」）。
   徽标靠右、名字可截断；没有派工时不渲染，行宽自然回到只有客户信息。 */
.ht-wb-c3 { font-size: 12.5px; color: var(--text-2); margin-top: 3px; display: flex; align-items: center; gap: 8px; }
.ht-wb-c3 b { color: var(--text); font-weight: 600; }
.ht-wb-c3 i { font-style: normal; color: #cbd5e1; margin: 0 5px; }
.ht-wb-cust { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ht-wb-tech { flex: none; margin-left: auto; display: inline-flex; align-items: center; gap: 3px; max-width: 48%;
  font-size: 11.5px; line-height: 1.5; padding: 0 5px; border-radius: 4px;
  color: #065f46; background: #ecfdf5; border: 1px solid #a7f3d0; }
.ht-wb-tech em { font-style: normal; font-size: 10.5px; color: #047857; opacity: .8; }
.ht-wb-tech b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #065f46; font-weight: 600; }
/* 未派工不占位：师傅徽标只在 hasDispatch 时存在，这里不加 min-width，避免空框 */
.ht-wb-c4 { font-size: 12px; color: var(--text-2); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ht-wb-c5 { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-top: 6px;
  padding-top: 6px; border-top: 1px dashed #eef2f8; font-size: 11px; color: var(--text-3); }
.ht-wb-c5 .ht-mono { letter-spacing: .2px; }

/* 右：**上下两张卡**（2026-10-18 照京东工作台改：滚动都在可视范围内，整窗不滚）
   ┌ 信息卡 .ht-wb-info（单号头钉顶 + 电话/关键条/反馈；自身滚）┐
   └ 预约卡 .ht-wb-foot（三态表单；自身滚，高度按内容、最多 58%）┘
   ⚠️ 旧方案「一列 flex + 中间 flex:1 + 表单贴底」会把内容短时的剩余高度全变成中间的白洞
      （用户截图：「右边一大片空白，和下半部分衔接很怪」）；拆成两张卡后，空白只可能落在
      有边框的卡片里，读起来是卡片内边距，不是页面断了。 */
.ht-wb-main { min-height: 0; display: flex; flex-direction: column; gap: 12px; overflow: hidden; }
/* ⚠️ 2026-10-18 第四稿（用户截图：「这么大区域都是空白，把预约框往上提一提」）——
   信息卡原来 flex:1 吃满剩余高度，内容短时下半张卡全是白洞，预约卡被顶到最底下。
   改为**按内容高度**（最多 60%，超了自己滚），预约卡紧贴其下并吃掉剩余高度：
   空出来的高度交给「过程备注」的文本框去长 —— 用户上一句正是「备注框太小、右侧闲着」。 */
.ht-wb-info { flex: 0 1 auto; min-height: 0; max-height: 70%; display: flex; flex-direction: column; overflow-y: auto;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); }
.ht-wb-info::-webkit-scrollbar { width: 7px; }
.ht-wb-info::-webkit-scrollbar-thumb { background: #d3dbe8; border-radius: 4px; }
.ht-wb-mhead { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 9px 14px;
  border-bottom: 1px solid #eef2f8; flex: none; position: sticky; top: 0; z-index: 3;
  background: var(--card-bg); border-radius: var(--radius) var(--radius) 0 0; }
.ht-wb-no { font-size: 12px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.ht-wb-no b { color: var(--text); font-weight: 600; }
.ht-wb-no i { font-style: normal; color: #cbd5e1; margin: 0 6px; }
.ht-wb-copy-n { font-size: 11px; color: var(--text-3); white-space: nowrap; }
.ht-wb-copy-n:empty { display: none; }
/* 「复制汇总」按钮 + 次数灰字绑成一个不可拆组（2026-10-18 窄屏踩过：
   mhead flex-wrap 把灰字挤到第二行、跟「单据详情」混在一起，跟它的按钮被拆开） */
.ht-wb-copy-grp { display: inline-flex; align-items: center; gap: 6px; flex: none; }
.ht-wb-mhead .btn .n { font-size: 10.5px; font-weight: 500; color: var(--primary-dark); background: #dbeafe;
  border-radius: 8px; padding: 0 5px; margin-left: 5px; }
/* 信息区（卡内）：按内容高度，滚动交给卡片本身（不再自己吃剩余高度） */
.ht-wb-mid { flex: 0 0 auto; min-height: 0; overflow: visible;
  padding: 12px 14px; display: flex; flex-direction: column; gap: 12px; }
/* 预约卡：自己一张卡（边框 + 圆角），**吃掉右栏剩余高度**（信息卡按内容、不再抢高度）
   ⚠️ 2026-10-18 第四稿：原来 max-height:58% + 内容贴底，短内容时下面一大截白；
     现在 flex:1 撑满，多出来的高度全部给「过程备注」的 textarea（它自己 flex:1 长高）。 */
.ht-wb-foot { flex: 1 1 auto; min-height: 0; overflow-y: auto;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 9px 14px; display: flex; flex-direction: column; gap: 7px; }
/* 表单里的备注行固定半高：用户 2026-10-18 要求「过程备注的框高度减半」。
   行高 70px（含标签与计数），textarea 自适应填满，保留 2 行左右的输入空间。 */
.ht-wb-foot > .ht-3lrow-note { flex: 0 0 auto; min-height: 70px; }
.ht-wb-foot > .ht-3lrow-note .ht-note-wrap { display: flex; flex-direction: column; align-self: stretch; height: 100%; }
.ht-wb-foot > .ht-3lrow-note .ht-note-wrap textarea { flex: 1 1 auto; height: auto; min-height: 46px; resize: none; }
.ht-wb-foot::-webkit-scrollbar { width: 7px; }
.ht-wb-foot::-webkit-scrollbar-thumb { background: #d3dbe8; border-radius: 4px; }
.ht-wb-foot::-webkit-scrollbar { width: 7px; }
.ht-wb-foot::-webkit-scrollbar-thumb { background: #d3dbe8; border-radius: 4px; }
/* 二次联系只有两态（.two）—— 竖排布局下不需要列数覆盖，规则已下线（2026-10-18） */
.ht-wb-subrow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; row-gap: 8px; flex: none; }
/* 不能登记时的那道门：在变高的卡里垂直居中，免得又塌在最上面留一大截白 */
.ht-wb-foot > .ht-wb-gate { margin: auto 0; }
.ht-wb-fbtns { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* 右栏的「门」（不能登记时的说明：接单 / 只读 / 终态）—— 为什么不能填，当面说清 */
.ht-wb-gate { padding: 14px 2px 6px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.ht-wb-gate b { font-size: 14px; }
.ht-wb-gate p { font-size: 12.5px; color: var(--text-2); line-height: 1.7; }
.ht-wb-gate.off b, .ht-wb-gate.off p { color: var(--text-3); }
.ht-wb-gate-btns { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.ht-wb-empty { margin: auto; padding: 30px 20px; text-align: center; color: var(--text-3); }
.ht-wb-empty b { display: block; font-size: 14px; color: var(--text-2); margin-bottom: 6px; }
.ht-wb-empty p { font-size: 12.5px; line-height: 1.7; }
/* 窄屏：左栏收窄 + KPI 允许两行（每张卡仍 ≥110px 才不把副标题裁掉）
   ⚠️ 同样要挂 .ht-wb-page > 作用域：否则会把上面弹窗的「窄屏单栏」规则压掉 */
@media (max-width: 1180px) {
  .ht-wb-page > .ht-wb { grid-template-columns: 280px minmax(0, 1fr); }
  /* 窄屏：分段条放不下就换行（不横滚、不拉长胶囊）；其余按行式表单的收窄规则走 */
  .ht-wb-kpis { flex-wrap: wrap; overflow: visible; }
  .ht-wb-kpis .ht-kpi { flex: 0 0 auto; }
  /* 窄屏右栏只剩 ~430px：起止时间输入收窄 */
  .ht-wb-page .ht-tm .ht-ctrl { width: 96px; }
  /* 窄屏主区只有 ~410px（KPI 折两行），塞不下「信息卡 + 整张表单」480px 的硬内容。
     ⚠️ 预约卡不再设 max-height（2026-10-18 第四稿：它现在 flex:1 吃剩余高度，
        设了 max-height 反而在窄屏下面留白）。 */
  .ht-wb-page .ht-wb-info { max-height: 64%; }
}

/* ════════════ 单据详情抽屉（2026-10-18：京东式右侧抽屉 + 书签页签） ════════════
   ⚠️ 壳子是 openFloat 生成的 .modal，这里把它改成右侧满高面板：
      定位 absolute + 去掉圆角与居中，宽度靠 vw 封顶（笔记本 1440 时 960 刚好不压住左栏联系信息）。 */
.float-mask .modal.ht-dr-wrap { position: absolute; top: 0; right: 0; bottom: 0; left: auto;
  width: min(960px, 92vw); max-width: min(960px, 92vw); max-height: none; margin: 0;
  border-radius: 0; transform: none; display: flex; flex-direction: column; overflow: hidden;
  box-shadow: -14px 0 46px rgba(15,23,42,.16); animation: htDrIn .26s cubic-bezier(.22,.75,.28,1) both; }
@keyframes htDrIn { from { transform: translateX(30px); opacity: .4; } to { transform: none; opacity: 1; } }
.ht-dr-h { display: flex; align-items: flex-start; gap: 10px; padding: 13px 16px 11px; flex: none; }
.ht-dr-h h3 { font-size: 15px; font-weight: 600; }
.ht-dr-h p { font-size: 11.5px; color: var(--text-3); margin-top: 2px; font-variant-numeric: tabular-nums; }
.ht-dr-x { border: none; background: none; width: 26px; height: 26px; border-radius: 6px; cursor: pointer;
  color: var(--text-3); font-size: 15px; line-height: 1; font-family: inherit; }
.ht-dr-x:hover { background: var(--gray-bg); color: var(--text); }
/* 书签式页签：行底色压深一档，选中页签白底 + 底部 2px 白条盖住分隔线 → 与内容区连成一体 */
.ht-dr-tabs { display: flex; align-items: flex-end; gap: 2px; padding: 0 14px; flex: none;
  background: #eef2f8; border-bottom: 1px solid #dde5f0; }
.ht-dr-tab { position: relative; font-size: 13px; color: #64748b; padding: 8px 17px 7px; cursor: pointer;
  border-radius: 9px 9px 0 0; transition: background .16s, color .16s; white-space: nowrap; }
.ht-dr-tab:hover { background: #e4ebf6; color: #334155; }
.ht-dr-tab.on { background: #fff; color: var(--text); font-weight: 600; }
.ht-dr-tab.on::after { content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: #fff; }
.ht-dr-tab .n { font-size: 10.5px; font-weight: 500; color: #64748b; background: #e2e8f0;
  border-radius: 8px; padding: 0 5px; margin-left: 4px; }
.ht-dr-tab.on .n { background: #dbeafe; color: var(--primary-dark); }
.ht-dr-b { flex: 1; min-height: 0; overflow-y: auto; padding: 0 6px 10px; }
.ht-dr-b::-webkit-scrollbar { width: 8px; }
.ht-dr-b::-webkit-scrollbar-thumb { background: #d3dbe8; border-radius: 4px; }
.ht-dr-b.ht-dr-in { animation: htDrPane .22s cubic-bezier(.22,.75,.28,1) both; }
@keyframes htDrPane { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
.ht-dr-g { font-size: 12px; font-weight: 600; color: var(--text-2); display: flex; align-items: center; gap: 6px;
  margin: 12px 10px 7px; }
.ht-dr-g::before { content: ''; width: 3px; height: 12px; border-radius: 2px; background: var(--primary); }
.ht-dr-g.mt { margin-top: 18px; }
.ht-dr-gs { font-weight: 400; color: var(--text-3); font-size: 11.5px; }
/* 抽屉的键值区：**每行两组「标签 + 值」**。
   ⚠️ 2026-10-18 修真 bug：老模板 `84px minmax(0,300px) 84px minmax(0,300px)` 是按
      「扁平的 span / b」写的，可实际子元素是**成对的 .ht-kv 容器**（每个自带 span+b）。
      4 列模板套到成对容器上 = 每格只分到 84px，值被 `word-break:break-all` 压成
      「山东省青岛市市南区钢城区」逐字竖排（用户截图实锤）。改成 2 列、标签定宽值自适应。 */
.ht-dr-kv { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 30px; padding: 0 10px; font-size: 13px; }
.ht-dr-kv .ht-kv { min-width: 0; align-items: baseline; }
.ht-dr-kv .ht-kv span { flex: none; width: 76px; }
/* ⚠️ 值必须能撑开且只在**装不下时**才断字：`word-break:break-all` 配窄列 = 逐字竖排 */
.ht-dr-kv .ht-kv b { flex: 1 1 auto; min-width: 0; word-break: normal; overflow-wrap: anywhere; }
/* 整行项（省市区 / 详细地址 / 客户反馈）：跨两列，别挤在半格里 */
.ht-dr-kv .ht-kv.ht-wide { grid-column: 1 / -1; }
.ht-dr-fb { margin: 0 10px; background: #fef2f2; border-left: 3px solid var(--danger);
  border-radius: 0 6px 6px 0; padding: 8px 11px; font-size: 12.5px; line-height: 1.65; color: #7f1d1d; max-width: 660px; }
.ht-dr-tl { padding: 0 10px 0 26px; position: relative; }
.ht-dr-tl::before { content: ''; position: absolute; left: 14px; top: 4px; bottom: 8px; width: 1px; background: #e6ecf5; }
.ht-dr-ev { position: relative; padding: 0 0 12px; font-size: 12.5px; }
.ht-dr-ev::before { content: ''; position: absolute; left: -14px; top: 5px; width: 8px; height: 8px; border-radius: 50%;
  background: #cbd5e1; border: 2px solid #fff; box-shadow: 0 0 0 1px #e2e8f0; }
.ht-dr-ev.ok::before { background: var(--success); box-shadow: 0 0 0 1px #bbf7d0; }
.ht-dr-ev.miss::before { background: #f59e0b; box-shadow: 0 0 0 1px #fde68a; }
.ht-dr-ev.bad::before { background: var(--danger); box-shadow: 0 0 0 1px #fecaca; }
.ht-dr-ev .h { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.ht-dr-ev .h b { font-weight: 600; }
.ht-dr-ev .h span { font-size: 11.5px; color: var(--text-3); }
.ht-dr-ev .x { font-size: 11.5px; color: var(--text-2); margin-top: 2px; }
/* 2026-10-19 用户：「跟进记录只保留 日期时间 · 操作人 · 过程备注 这样的格式」
   —— 备注不再做成独立灰块（一条记录占两三行），改成同一行里的第三段；
   原来 .ht-dr-ev .note 的块状样式已随格式一并删除。 */
.ht-dr-ev .h span.memo { font-size: 12px; color: var(--text-2); flex: 1 1 320px; min-width: 0;
  white-space: pre-wrap; }
/* 订单留言（2026-10-19）：跟进记录里与外呼混排，用**灰蓝圆点**区分 ——
   它不是一通电话，不能被误读成外呼三态里的任何一种。 */
.ht-dr-ev.nt::before { background: #64748b; box-shadow: 0 0 0 1px #cbd5e1; }
/* 跟进记录页**底部**的内联留言框（2026-10-19 用户：放记录列表下方）。
   阅读顺序是「从头往下看发生了什么 → 看完顺手补一句」，放顶部会把最新一条挤下去。 */
.ht-dr-note { margin: 14px 10px 6px; padding-top: 12px; border-top: 1px dashed #e2e8f0; }
.ht-dr-note textarea { width: 100%; box-sizing: border-box; min-height: 48px; resize: vertical;
  border: 1px solid var(--border); border-radius: 7px; padding: 7px 9px; font-size: 12.5px;
  line-height: 1.65; color: var(--text); background: #fff; font-family: inherit; }
.ht-dr-note textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .10); }
.ht-dr-note textarea::placeholder { color: var(--text-3); }
.ht-dr-note-a { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.ht-dr-note-h { font-size: 11.5px; color: var(--text-3); flex: 1 1 auto; min-width: 0; }
/* 操作列「留言」弹窗（与抽屉里那行输入框同一个业务，样式分开挂：弹窗不走 .ht-dr-note 作用域） */
.ht-note-ta { width: 100%; box-sizing: border-box; min-height: 96px; resize: vertical; line-height: 1.7; }
.ht-note-cnt { text-align: right; font-size: 11.5px; color: var(--text-3); margin-top: 4px; }
.ht-dr-empty { padding: 10px 12px; font-size: 12px; color: var(--text-3); }
/* 操作记录表：表格样式必须带作用域前缀（守门 verify-table-css-collision） */
.ht-dr-tb { padding: 4px 10px 0; }
.ht-dr-tb table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.ht-dr-tb thead th { text-align: left; font-weight: 600; font-size: 11.5px; color: var(--text-3);
  background: #f8fafc; padding: 6px 9px; border-bottom: 1px solid var(--border); }
.ht-dr-tb tbody td { padding: 7px 9px; border-bottom: 1px solid #f1f5f9; vertical-align: top; line-height: 1.6; }
.ht-dr-tb tbody td.tm { color: var(--text-3); font-variant-numeric: tabular-nums; white-space: nowrap; width: 150px; }
.ht-dr-tb tbody td.by { text-align: right; color: var(--text-2); white-space: nowrap; width: 88px; font-size: 11.5px; }
.ht-dr-tb thead th.by { text-align: right; }
.ht-dr-f { display: flex; align-items: center; gap: 10px; padding: 9px 16px; flex: none;
  border-top: 1px solid var(--border); font-size: 11.5px; color: var(--text-3); }
/* 去登记预约：抽屉的唯一出口，必须一眼看见（2026-10-18 用户「进入的按钮太不明显」）。
   原来只是 btn-sm primary，26px 高混在「关闭」旁边，等于没有。 */
.ht-dr-gow { font-size: 11.5px; color: var(--text-3); }
.ht-dr-go { height: 34px; padding: 0 18px; font-size: 13.5px; font-weight: 600;
  display: inline-flex; align-items: center; gap: 6px; box-shadow: 0 2px 8px rgba(37,99,235,.28); }
.ht-dr-go i { font-style: normal; font-size: 14px; line-height: 1; }
.ht-dr-go:hover { filter: brightness(1.06); }

/* ③ 客户与地址卡：就地编辑 */
/* ⚠️ 别重定义 .ht-sec-h（上面已有 baseline 版）—— 这里只补编辑按钮自身 */
.ht-sec-edit { margin-left: auto; align-self: center; border: 1px solid var(--border); background: var(--card-bg);
  color: var(--text-2); border-radius: 7px; padding: 3px 10px; font-size: 12px; cursor: pointer;
  font-family: inherit; line-height: 1.6; flex: none; }
.ht-sec-edit:hover { border-color: var(--primary); color: var(--primary); background: var(--primary-light); }
.ht-sec-edit[hidden] { display: none !important; }
/* 编辑态表单（2026-10-18 晚，用户截图）：**两行紧凑版**——
   ① 客户姓名 + 联系电话　② 省/市/区县（三枚窄输入）+ 详细地址。
   标签全部退成 placeholder，提示语整块删除 —— 不滚动就能看到「保存修改」。 */
.ht-cust-form { display: flex; flex-direction: column; gap: 8px; }
.ht-cust-form[hidden] { display: none !important; }
/* ⚠️ 只读态 body 是 .ht-sec-b.ht-grid2（display:grid），hidden 必须显式压掉 */
.ht-sec-b[hidden] { display: none !important; }
.ht-cust-r1, .ht-cust-r2 { display: flex; gap: 8px; min-width: 0; }
.ht-cust-r1 .ctrl { flex: 1 1 0; min-width: 0; }
.ht-cust-r1 .ctrl + .ctrl { flex: 1.15 1 0; }
.ht-cust-addr3 { display: flex; gap: 6px; flex: none; }
.ht-cust-addr3 .ctrl { width: 72px; padding: 0 8px; text-align: center; flex: none; }
.ht-cust-r2 > .ht-ctrl { flex: 1 1 90px; min-width: 80px; }
.ht-cust-act { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
/* ── 编辑聚焦遮罩：其它层置灰磨砂 + 不可点，编辑区保持清晰可交互（取消/保存才解除） ── */
.ht-edit-mask { position: fixed; inset: 0; z-index: 930;
  background: rgba(15, 23, 42, .32); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); }
.page-tab.ht-edit-top { position: relative; z-index: 931; }
.ht-edit-mask-local { position: absolute; inset: 0; z-index: 901;
  background: rgba(15, 23, 42, .38); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.ht-edit-focus { position: relative; z-index: 902; }
/* 保存成功后整卡闪一下（改了但看着没变，是这类就地编辑最容易被质疑的地方） */
@keyframes htFlash { 0% { background: #ecfdf5; } 100% { background: transparent; } }
.ht-sec.ht-flash { animation: htFlash 1.2s ease-out; }

/* ════════════ 外呼预约页 · 表格视图（2026-10-19 用户给的格式） ════════════
   只有「待外呼池」「我的工单」走卡片工作台；其余 tab（超期/已预约/已派工/预约失败/全部）
   一律表格，「全部」再加全量字段列。
   ⚠️ 表格 tab 要把右栏处理区收掉、两栏并成一栏（htApplyShellMode 加 .table-mode）。 */
/* ⚠️ 只给 grid-template-columns 不够：行高默认 auto 会被表格内容撑开 →
   容器跟着长高，永远不出滚动条。必须同时锁「行高 = 剩余空间」+ 容器 min-height:0。 */
.ht-wb.table-mode { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr);
  flex: 1 1 auto; min-height: 0; }
.ht-wb.table-mode > .ht-wb-main { display: none !important; }
/* 表格 tab 下左栏不再需要「卡片流」那一套内层滚动壳，直接占满 */
/* 🔥 表格 tab 的纵向滚动落在 **.table-wrap 自己身上**（不是左栏容器）。
   为什么：sticky 只能相对「最近的滚动容器」吸顶。上一版把滚动放在 .ht-wb-list 上，
   而 .table-wrap 带 overflow-y:hidden（hidden 也会建立滚动容器、但它自己不滚）
   → thead 的 top:0 只能钉在 wrap 顶边、wrap 又跟着页面一起滚走 = 表头吸不住。
   2026-10-19 用户两次反馈后的最终口径：**表头要冻结（吸顶常驻）**。
   于是把纵向滚动下沉到 wrap：表头钉在 wrap 顶边，wrap 本身不动 → 真吸顶。 */
.ht-wb.table-mode > .ht-wb-list { overflow: hidden; min-height: 0;
  height: 100%; padding-right: 4px; }
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--card-bg); flex: none; }
  /* ⚠️ flex:none 是默认值（其它页面的表格不参与收缩）——表格 tab 里由下面那条
     `.ht-wb.table-mode .table-wrap` 改成 flex:0 1 auto，让它按剩余高度收缩 + 内部滚动。 */
/* 表格 tab 里 wrap 自己当纵向滚动容器（表头才能相对它吸顶）：
   flex:0 1 auto → 内容矮时按内容高（不会拖出一条大空白边框），
   内容高时收缩到剩余高度并在内部滚动。min-height:0 是收缩的前提。 */
.ht-wb.table-mode .table-wrap { flex: 0 1 auto; min-height: 0; overflow: auto; }
.ht-table { min-width: 1080px; }
/* 「全部」= 全量字段列，天然更宽，靠横向滚动（不许把列压成竖排单字） */
.ht-table.ht-table-full { min-width: 2760px; }
  /* ⚠️ min-width 必须 ≥ 各列 min 之和（冻结 562 + 其余 ~2100），否则浏览器会压缩
     「状态 / 预约」这类窄列（2026-10-19 实测：状态被压成「待外」两字）。 */
.ht-table th { white-space: nowrap; }
.ht-table td { vertical-align: top; }
.ht-table .ht-t-ck { width: 40px; min-width: 40px; }
.ht-table .ht-t-no { min-width: 150px; }
.ht-table .ht-t-cust { min-width: 130px; }
.ht-table .ht-t-addr { min-width: 200px; }
.ht-table .ht-t-svc { min-width: 210px; max-width: 280px; }
  /* 全量字段档列多，首屏能多露一列是一列；行高也跟着降下来（26 行才 1300px 左右） */
  .ht-table.ht-table-full .ht-t-svc { min-width: 190px; max-width: 240px; }
  .ht-table.ht-table-full .ht-table td { line-height: 1.5; }
  .ht-table.ht-table-full .ht-t-fb { max-height: 40px; overflow: hidden; }
.ht-table .ht-t-own { min-width: 130px; }
.ht-table .ht-t-st { min-width: 110px; }
/* 服务技师列（2026-10-20）：标准档新增，约时间前先看这单派给谁 —— 名字可截断，不换行，不做来源副行 */
.ht-table .ht-t-tech { min-width: 104px; max-width: 132px; }
.ht-table .ht-t-ap { min-width: 130px; }
/* 操作列钉右侧：横向滚动时永远够得着（表格铁律：操作列 nowrap + sticky right:0） */
.ht-table .ht-t-act { position: sticky; right: 0; background: var(--card-bg); min-width: 190px;
  box-shadow: -6px 0 8px -6px rgba(15, 23, 42, .18); }
.ht-table tbody tr:hover .ht-t-act { background: #f8fbff; }
.ht-op-btns { display: flex; gap: 6px; flex-wrap: nowrap; justify-content: flex-start; }
.ht-op-copy { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
.ht-op-copy .ht-sub { white-space: nowrap; }
.ht-t-fb { margin-top: 4px; padding: 3px 8px; border-radius: 5px; font-size: 12px; line-height: 1.55;
  background: var(--warn-light); border-left: 2px solid var(--warn); color: #92400e; word-break: break-word; }
/* .ht-t-warr 已于 2026-10-20 删除：保修已由 htTypeCell 并进「维修-保外」，
   再挂一个徽章就是用户看到的「维修-保外 保外」重复。 */
.ht-cell-none { color: var(--text-3); }
.ht-t-rk { min-width: 220px; max-width: 320px; }
.ht-t-rk-in { max-height: 40px; overflow: hidden; word-break: break-word; }
.ht-t-x { min-width: 96px; }
.ht-table tr.ht-picked td { background: #eff6ff; }
.ht-table tr.ht-overdue td { background: #fff7ed; }
.ht-tbl-foot { display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 10px 14px; font-size: 12px;
  color: var(--text-3); flex: none; }
.ht-tbl-foot b { color: var(--text); }

/* ── 前 4 列冻结（勾选 / 服务单号 / 客户·号码 / 服务地址）──
   横向滚动时仍认得出「这是谁的单、装哪儿」。
   ⚠️ 冻结列必须**给定宽**（width+min+max 三写）：auto 布局下列宽会随内容伸缩，
      left 偏移就算对了也会错位 —— 偏移量 = 前几列宽度之和（40 / 150 / 132 / 200）。 */
.ht-table th.ht-t-ck, .ht-table td.ht-t-ck { width: 40px; min-width: 40px; max-width: 40px; }
.ht-table th.ht-t-no, .ht-table td.ht-t-no { width: 150px; min-width: 150px; max-width: 150px; }
.ht-table th.ht-t-cust, .ht-table td.ht-t-cust { width: 132px; min-width: 132px; max-width: 132px; }
.ht-table th.ht-t-addr, .ht-table td.ht-t-addr { width: 200px; min-width: 200px; max-width: 200px; word-break: break-word; }
.ht-table th.ht-t-ck, .ht-table td.ht-t-ck { position: sticky; left: 0; z-index: 2; background: var(--card-bg); }
.ht-table th.ht-t-no, .ht-table td.ht-t-no { position: sticky; left: 40px; z-index: 2; background: var(--card-bg); }
.ht-table th.ht-t-cust, .ht-table td.ht-t-cust { position: sticky; left: 190px; z-index: 2; background: var(--card-bg); }
.ht-table th.ht-t-addr, .ht-table td.ht-t-addr { position: sticky; left: 322px; z-index: 2; background: var(--card-bg);
  box-shadow: 6px 0 8px -6px rgba(15, 23, 42, .18); }
/* ⚠️ 2026-10-19 用户：「明细表行标题，还是会随着向下滚动消失啊，我要求冻结行标题」
   → 表头**吸顶冻结**（钉在 .table-wrap 的滚动视口顶边常驻），
     横向仍冻结前 4 列 + 最右操作列。
   top 不写在冻结列那几条里 —— 让本条的 top:0 统一生效（冻结列只覆盖 left/z-index）。 */
.ht-table thead th { position: sticky; top: 0; z-index: 3; background: var(--gray-bg);
  /* border-collapse:collapse 下 sticky 表头滚起来会丢底边框，用内阴影补回来 */
  box-shadow: inset 0 -1px 0 var(--border); }
.ht-table thead th.ht-t-ck, .ht-table thead th.ht-t-no,
.ht-table thead th.ht-t-cust, .ht-table thead th.ht-t-addr { z-index: 4; background: var(--gray-bg); }
/* 冻结区右缘那道竖向阴影在表头格上要保留（否则横向滚时表头少一条分界线） */
.ht-table thead th.ht-t-addr { box-shadow: inset 0 -1px 0 var(--border), 6px 0 8px -6px rgba(15, 23, 42, .18); }
.ht-table tbody tr:hover td.ht-t-ck, .ht-table tbody tr:hover td.ht-t-no,
.ht-table tbody tr:hover td.ht-t-cust, .ht-table tbody tr:hover td.ht-t-addr { background: #f8fbff; }
.ht-table tr.ht-picked td.ht-t-ck, .ht-table tr.ht-picked td.ht-t-no,
.ht-table tr.ht-picked td.ht-t-cust, .ht-table tr.ht-picked td.ht-t-addr { background: #eff6ff; }
.ht-table tr.ht-overdue td.ht-t-ck, .ht-table tr.ht-overdue td.ht-t-no,
.ht-table tr.ht-overdue td.ht-t-cust, .ht-table tr.ht-overdue td.ht-t-addr { background: #fff7ed; }
.ht-table .ht-t-act { z-index: 2; }
/* 操作列表头：既要吸顶（top:0 来自上面那条）又要钉右侧 —— z-index 高于普通表头，
   背景必须给灰底，否则吸顶后透出底下滚过的行 */
.ht-table thead th.ht-t-act { z-index: 3; background: var(--gray-bg);
  box-shadow: inset 0 -1px 0 var(--border), -6px 0 8px -6px rgba(15, 23, 42, .18); }

/* ============================================================
 * 首页（2026-10-19 新增；替代已删除的「待办中心」作为登录落地页）
 * ------------------------------------------------------------
 * 一张插画居中 + 一行引导，侧栏不高亮任何项。
 * .page-tab 由 flex 撑出确定高度，所以这里的 height:100% 有效，
 * 插画才能落在工作区的视觉中心（而不是贴着顶栏）。
 * ============================================================ */
.page-tab[data-page="welcome"] > .main {
  height: 100%;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
}
.welcome-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* 插画下方留一点呼吸，避免整块视觉重心偏下 */
  padding-bottom: 3vh;
}
.welcome-art {
  display: block;
  /* 宽度三档取最小：设计宽 / 视口比例 / 高度上限折算宽度。
     最后那档替代了原来「height:auto + max-height:58vh」的写法 —— 那种写法在矮窗口下
     会先把宽定成 560 再压高度，插画被纵向压扁（SVG 没 intrinsic 约束撑不住）；
     折成宽度上限后是等比缩小，永远不会变形。 */
  --w-max: min(560px, 54vw);
  width: min(var(--w-max), calc(58vh * 876 / 728));
  aspect-ratio: 876 / 728;
  height: auto;
  filter: drop-shadow(0 20px 40px rgba(37, 99, 235, .10));
  user-select: none;
  -webkit-user-drag: none;
}
.welcome-hint {
  margin-top: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  letter-spacing: .4px;
  color: #8b98ad;
}
.welcome-hint::before,
.welcome-hint::after {
  content: '';
  width: 28px;
  height: 1px;
}
.welcome-hint::before { background: linear-gradient(90deg, transparent, #cfd8e6); }
.welcome-hint::after  { background: linear-gradient(90deg, #cfd8e6, transparent); }

/* 窄屏：插画收一点，别把引导文字挤出视口 */
@media (max-width: 1240px) {
  .welcome-art { --w-max: min(460px, 62vw); }
}
@media (max-width: 760px) {
  .welcome-art { --w-max: 76vw; }
}
