/* ============================================================================
   驻场项目管理平台 — 设计系统与样式表
   ----------------------------------------------------------------------------
   设计方向：企业级「运维控制台」克制风（工业实用 + 制度感）。
     · 一个记忆点：左侧导航做成深蓝「领航轨」（Brand Rail）——
       在白色顶栏之下形成一条稳定的深色竖向锚线，一眼即知这是个正经的内部
       运维系统；其余区域一律克制，不喧哗、不圆角卡通、不做营销式动效。
     · 单一主色承诺：#1B4D8F 体系（institutional blue）占绝对主导，
       仅以一个天蓝信号色 --accent 用于「当前所在」的高亮指示。
   组织方式：① 设计令牌 → ② 重置 → ③ 工具类 → ④ 主框架 → ⑤ 通用构件
             → ⑥ 表单 → ⑦ 业务模块 → ⑧ 响应式 / 动效降级。
   ----------------------------------------------------------------------------
   硬性约束（本项目零构建、零第三方、仅 ES5 前端）：
     · 不引入任何外部字体 / 图标库 / CDN；字体只用系统字体栈。
     · 不新增 / 不删除 / 不重命名既有 class：js/*.js 生成的标记依赖这些钩子。
     · index.html 的 ?v= 内容指纹由 deploy/push.sh 刷新，本文件不涉及。
   ============================================================================ */

/* ============================================================================
   ① 设计令牌（Design Tokens）
   ----------------------------------------------------------------------------
   所有魔法值收敛到此处；下列「兼容别名」与历史变量同名，供既有 JS 内联
   style / 历史规则继续引用（--font 亦被 SVG 文本使用）。
   ============================================================================ */
:root {
  /* ---- 品牌色阶（institutional blue） ---- */
  /* 全亮通透：整条色阶比原来亮一档、并略微偏青，去掉原来的「藏蓝发灰」感。
     原 600 = #1B4D8F（很深且饱和度低），它是全站按钮/链接/激活态的底色，
     也是「压抑感」的第二大来源（仅次于左侧那块深色）。 */
  --brand-50:  #F1F7FE;
  --brand-100: #E3EEFC;
  --brand-200: #C5DEF9;
  --brand-300: #96C2F3;
  --brand-400: #5C9FEA;
  --brand-500: #2E80E0;
  --brand-600: #1A6BD6;   /* 主色：明亮蓝，替下 #1B4D8F */
  --brand-700: #1557AE;
  --brand-800: #113F82;
  --brand-900: #0D3163;

  /* 兼容别名（历史变量名，勿删） */
  --brand: var(--brand-600);
  --brand-hover: #1557AE;
  --brand-dark: #113F82;
  --brand-soft: var(--brand-100);

  /* ---- 中性色阶（cool slate） ---- */
  --ink-900: #0F172A;
  --ink-800: #1E293B;
  --ink-700: #334155;
  --ink-600: #475569;
  --ink-500: #64748B;
  --ink-400: #94A3B8;
  --ink-300: #CBD5E1;
  --ink-200: #E2E8F0;
  --ink-100: #F1F5F9;
  --ink-50:  #F8FAFC;

  /* ---- 表面 / 文本 / 描边 ---- */
  /* 原 #F2F5F9 偏冷灰、压暗感明显；换成更浅更通透的底色（带一点暖，压住冷蓝的硬感）。 */
  --page-bg: #F8F8F6;
  --card-bg: #FFFFFF;
  --border: #E3E9F0;
  --border-strong: #D2DBE6;
  --text: #1B2430;          /* 正文：对白底 ≈ 14.3:1，对页面底 ≈ 13:1（实测 14.31） */
  --text-sub: #5A6675;      /* 次要：对白底 ≈ 5.8:1，对页面底 ≈ 5.3:1（实测 5.35） */
  --text-mute: #6B7684;     /* 占位符 / 非正文装饰：对白底 ≈ 4.6:1（实测 4.62），仍明显弱于正文 */

  /* ---- 语义色：-solid 填充 / -ink 浅底上的文字 / -bg 浅底 ---- */
  --green-solid: #16A34A; --green-ink: #166534; --green-bg: #DCFCE7;
  --red-solid:   #DC2626; --red-ink:   #B91C1C; --red-bg:   #FEE2E2;
  --blue-solid:  #2563EB; --blue-ink:  #1E40AF; --blue-bg:  #DBEAFE;
  --amber-solid: #D97706; --amber-ink: #92400E; --amber-bg: #FEF3C7;
  --gray-solid:  #64748B; --gray-ink:  #475569; --gray-bg:  #F1F5F9;
  --teal-solid:  #0D9488; --teal-ink:  #0F766E; --teal-bg:  #CCFBF1;

  /* 兼容别名（历史变量名，勿删） */
  --green: var(--green-solid);
  --red: var(--red-solid);
  --blue: var(--blue-solid);
  --amber: var(--amber-solid);
  --gray: var(--gray-ink);

  /* ---- 信号色（仅用于「当前所在」指示，克制使用） ---- */
  /* 原 #5BA8FF 是「深底专用」的天蓝信号色，放到浅色侧栏上对比不足。
     换成更实的蓝：浅底上 4.5:1 以上，且在白色侧栏里仍显得「亮起来」。 */
  --accent: #1A6BD6;
  --accent-soft: rgba(26, 107, 214, .12);
  --accent-ink: #14549F;   /* 激活态文字：比 --accent 再深一点，保证可读 */

  /* ---- 字体：系统字体栈（零外链） ---- */
  --font: -apple-system, "Segoe UI", "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", sans-serif;
  --font-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, "Microsoft YaHei", monospace;

  /* ---- 字号阶 ---- */
  --fs-11: 11px; --fs-12: 12px; --fs-13: 13px; --fs-14: 14px; --fs-15: 15px;
  --fs-16: 16px; --fs-18: 18px; --fs-20: 20px; --fs-24: 24px; --fs-28: 28px;
  --fs-h1: clamp(19px, 0.6vw + 15px, 21px);   /* 页标题随视口微调，避免窄屏换行 */

  /* ---- 行高（中文排版：正文 1.6，长文 1.85） ---- */
  --lh-tight: 1.25; --lh-snug: 1.45; --lh-body: 1.6; --lh-prose: 1.85;

  /* ---- 间距（4px 基数） ---- */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px;
  --sp-6: 24px; --sp-7: 32px; --sp-8: 40px;

  /* ---- 圆角（克制：卡片 10 / 控件 8 / 小件 6） ---- */
  --r-xs: 4px; --r-sm: 6px; --r-md: 8px; --r-lg: 10px; --r-xl: 14px; --r-pill: 999px;
  /* 兼容别名（历史变量名，勿删） */
  --radius-card: var(--r-lg);
  --radius-btn: var(--r-md);
  --radius-tag: var(--r-sm);

  /* ---- 阴影（分层、偏冷，避免死黑） ---- */
  /* 阴影减重：原值在高不透明度下会让白色卡片「发闷」。整体降一档，靠细边框而不是
     重投影来分隔层级 —— 这是「通透」的关键（轻，但有边界）。 */
  /* 上一版减重过头，卡片「浮不起来」也是寡淡的一部分 → 回调到原值与现值之间。 */
  --sh-xs: 0 1px 2px rgba(16, 32, 56, .05);
  --sh-sm: 0 1px 2px rgba(16, 32, 56, .07), 0 1px 3px rgba(16, 32, 56, .05);
  --sh-md: 0 2px 10px rgba(16, 32, 56, .09), 0 1px 3px rgba(16, 32, 56, .05);
  --sh-lg: 0 10px 24px rgba(16, 32, 56, .11), 0 2px 8px rgba(16, 32, 56, .05);
  --sh-pop: 0 12px 32px rgba(11, 33, 64, .14), 0 3px 8px rgba(11, 33, 64, .06);
  /* 兼容别名（历史变量名，勿删） */
  --shadow-card: var(--sh-sm);
  --shadow-pop: var(--sh-lg);

  /* ---- 焦点环 ---- */
  --ring: 0 0 0 3px color-mix(in srgb, var(--brand-500) 24%, transparent);
  --ring-danger: 0 0 0 3px color-mix(in srgb, var(--red-solid) 22%, transparent);

  /* ---- 动效 ---- */
  --t-1: .12s; --t-2: .18s; --t-3: .26s;
  --ease: cubic-bezier(.2, .7, .3, 1);
  /* ---- 流体交互（Apple Fluid Interfaces）----
     CSS 没有真正的弹簧物理，这里用 linear() 缓动**逼近**苹果的弹簧曲线：
     数值 >1 的那一段即「过冲」，随后回稳 —— 这就是弹簧手感的来源。
     受限说明：真实弹簧可随速度实时改变参数（Web 不能），故此处为近似。
     --r-* 是「响应时长」：越常用的动作越短，保证即时响应。 */
  --r-fast: 140ms; --r-base: 260ms; --r-slow: 380ms;
  --spring-soft: linear(0, .32 10%, .68 22%, .92 35%, 1.02 50%, 1.01 65%, 1 82%, 1 100%);
  --spring-snappy: linear(0, .45 9%, .82 18%, 1.01 30%, 1.05 42%, 1.02 56%, 1 72%, 1 100%);
  --spring-bounce: linear(0, .5 8%, .95 16%, 1.12 26%, 1.08 38%, .98 52%, 1.01 66%, 1 100%);

  /* ---- 布局尺寸 ---- */
  --header-h: 56px;
  --side-w: 224px;

  /* ---- 领航轨（左侧深色导航）配色 ---- */
  /* 领航轨：由「深藏蓝渐变」改为「白到极浅灰蓝」，只留一条右边线做分界。
     原来的深色整块是全站压抑感的头号来源（1440 屏上占 15.5% 宽度、整屏高）。
     注意：--rail-ink* 原本是浅色文字（为深底而设），这里必须同步改成深色文字，
     否则会出现「浅底浅字」看不清。 */
  /* 加质感：不再用接近纯白的底（那会让侧栏与内容区糊成一片），
     改为极淡的品牌蓝 —— 有「这一块」的存在感，但仍然是亮的。 */
  --rail-bg-1: #FBFCFE;
  --rail-bg-2: #F1F5FC;
  --rail-ink: #3A4658;
  --rail-ink-strong: #0F172A;
  --rail-ink-dim: #6B7684;
  --rail-line: #DFE7F3;
  --rail-hover: #E9F0FA;
}

/* ============================================================================
   ② 重置与基础
   ============================================================================ */
* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  font-family: var(--font);
  font-size: var(--fs-14);
  line-height: var(--lh-body);
  color: var(--text);
  /* 平色底会让整页看起来像一张纸；加一段极淡的纵向渐变（顶部略偏蓝），
     形成很轻的「光从上面来」的错觉，页面上半部分不再死平。 */
  background: linear-gradient(180deg, #F4F7FC 0%, var(--page-bg) 340px);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

a { color: var(--brand-600); text-decoration: none; transition: color var(--t-1) var(--ease); }
a:hover { color: var(--brand-700); text-decoration: underline; }

button { font-family: inherit; cursor: pointer; }
input, select, textarea { font-family: inherit; font-size: var(--fs-14); color: var(--text); }

/* 选中态：品牌浅底 */
::selection { background: color-mix(in srgb, var(--brand-400) 32%, transparent); color: var(--brand-900); }

/* 全局可见焦点（键盘可达）：仅在键盘聚焦时出现，不干扰鼠标操作 */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--brand-500);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* 细滚动条（含横向表格容器）；Firefox 用 scrollbar-* 标准属性 */
:where(.table-scroll, .org-chart-wrap, .policy-tree, .drawer-body, .modal, .dt-body, .ov-matrix) {
  scrollbar-width: thin;
  scrollbar-color: var(--ink-300) transparent;
}
:where(.table-scroll, .org-chart-wrap, .policy-tree, .drawer-body, .modal, .dt-body, .ov-matrix)::-webkit-scrollbar {
  width: 10px; height: 10px;
}
:where(.table-scroll, .org-chart-wrap, .policy-tree, .drawer-body, .modal, .dt-body, .ov-matrix)::-webkit-scrollbar-thumb {
  background: var(--ink-300); border: 3px solid transparent; background-clip: content-box; border-radius: var(--r-pill);
}
:where(.table-scroll, .org-chart-wrap, .policy-tree, .drawer-body, .modal, .dt-body, .ov-matrix)::-webkit-scrollbar-thumb:hover {
  background: var(--ink-400); background-clip: content-box;
}
:where(.table-scroll, .org-chart-wrap, .policy-tree, .drawer-body, .modal, .dt-body, .ov-matrix)::-webkit-scrollbar-track { background: transparent; }

/* ============================================================================
   ③ 工具类（保持既有类名不变）
   ============================================================================ */
.hidden { display: none !important; }
.row { display: flex; align-items: center; }
.between { display: flex; align-items: center; justify-content: space-between; }
.gap8 { gap: 8px; } .gap12 { gap: 12px; } .gap16 { gap: 16px; } .gap24 { gap: 24px; }
.mt8 { margin-top: 8px; } .mt16 { margin-top: 16px; } .mt24 { margin-top: 24px; } .mt32 { margin-top: 32px; }
.mb8 { margin-bottom: 8px; } .mb16 { margin-bottom: 16px; } .mb24 { margin-bottom: 24px; }
.muted { color: var(--text-sub); }
.f12 { font-size: 12px; } .f14 { font-size: 14px; } .f16 { font-size: 16px; } .f20 { font-size: 20px; }
.bold { font-weight: 600; }
.center { text-align: center; }
.right { text-align: right; }
.nowrap { white-space: nowrap; }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ============================================================================
   ④-1 登录页 / 强制改密 / 连接错误
   ----------------------------------------------------------------------------
   左栏 = 封面图 + 深蓝遮罩；右栏 = 品牌标题行 + 表单。
   历史故障防护：封面图必须有（图片层在前、渐变层在后，缺图退化为纯渐变不破图）；
                 标题与 logo 方块必须有（.login-logo .mark 尺寸放大）；
                 标题与表单不得并排（右栏为 column 布局，表单在标题下方）。
   ============================================================================ */
.login-wrap { display: flex; min-height: 100vh; background: var(--brand-900); }

.login-brand {
  flex: 0 0 56%;
  position: relative; overflow: hidden;
  background: url('/assets/login-cover.jpg') center center / cover no-repeat,
              linear-gradient(150deg, var(--brand-800) 0%, var(--brand-600) 58%, var(--brand-500) 100%);
}
/* 深蓝半透明遮罩：透明度偏轻，保证封面图清晰可见 */
.login-brand::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(150deg, rgba(11, 33, 64, .82) 0%, rgba(20, 60, 116, .52) 55%, rgba(44, 108, 182, .22) 100%);
}
/* 封面区叠一层极淡的网格纹理，制造「控制台」氛围（纯 CSS，无外链） */
.login-brand::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 44px 44px, 44px 44px;
  -webkit-mask-image: radial-gradient(120% 90% at 30% 20%, #000 30%, transparent 78%);
          mask-image: radial-gradient(120% 90% at 30% 20%, #000 30%, transparent 78%);
  opacity: .7;
}

.login-panel {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 48px; background: #fff;
}
.login-head { width: 100%; max-width: 448px; margin-bottom: 30px; }
.login-logo { display: flex; align-items: center; gap: 16px; }
.login-logo .mark {
  flex: 0 0 auto; width: 60px; height: 60px; border-radius: var(--r-xl);
  background: linear-gradient(150deg, var(--brand-600) 0%, var(--brand-800) 100%);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 24px color-mix(in srgb, var(--brand-800) 34%, transparent), inset 0 1px 0 rgba(255, 255, 255, .18);
}
.login-logo .mark svg { width: 34px; height: 34px; }
.login-brand-title {
  font-size: clamp(22px, 1vw + 14px, 26px); font-weight: 700; letter-spacing: .2px; line-height: 1.3; color: var(--brand-900);
}

.login-card { width: 100%; max-width: 448px; }
.login-card h3 { font-size: var(--fs-24); font-weight: 700; line-height: 1.35; margin-bottom: 6px; color: var(--ink-900); letter-spacing: .2px; }
.login-card .sub { color: var(--text-sub); font-size: var(--fs-15); line-height: var(--lh-body); margin-bottom: 20px; }

/* 防爆破策略信息条 */
.login-card .login-policy {
  display: flex; align-items: flex-start; gap: 8px;
  background: var(--brand-50); border: 1px solid var(--brand-100); border-radius: var(--r-md);
  padding: 11px 13px; font-size: var(--fs-13); line-height: var(--lh-body); color: var(--text-sub); margin-bottom: 24px;
}
.login-card .login-policy svg { flex: 0 0 auto; margin-top: 2px; }

/* —— 登录卡片局部尺寸（一律 .login-card 前缀，避免污染全站 .field/.input） —— */
.login-card .field { margin-bottom: 18px; }
.login-card .field label { font-size: var(--fs-14); margin-bottom: 8px; }
.login-card .input { height: 48px; padding: 0 14px; font-size: var(--fs-15); border-radius: var(--r-md); }
/* 验证码图片：尺寸/圆角/边框/光标集中在这个类上（JS 不再内联 style）。
   历史上这里靠一条带「强制优先」标记的规则去压 JS 内联的 38px —— 一个界面细节要靠
   强制覆盖才能生效，是典型的耦合坏味道。现把内联样式移出，此处用普通规则即可。 */
.captcha-img { height: 48px; border-radius: 6px; border: 1px solid #E2E8F0; cursor: pointer; display: block; }
.login-card #li-login-btn { height: 48px; font-size: var(--fs-16); letter-spacing: 3px; margin-top: 4px; }

/* 密码明文切换 */
.login-card .pwd-wrap { position: relative; }
.login-card .pwd-wrap .input { padding-right: 48px; }
.login-card .pwd-toggle {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 36px; height: 36px; padding: 0; border: 0; border-radius: var(--r-md);
  background: transparent; color: var(--ink-400);
  display: flex; align-items: center; justify-content: center;
  transition: color var(--t-1) var(--ease), background var(--t-1) var(--ease);
}
.login-card .pwd-toggle:hover { color: var(--brand-600); background: var(--brand-50); }
.login-card .pwd-toggle.on { color: var(--brand-600); }

/* 页脚合规提示 */
.login-card .login-foot {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  margin-top: 20px; font-size: var(--fs-12); line-height: var(--lh-body); color: var(--text-sub);
}
.login-card .login-foot svg { flex: 0 0 auto; }

@media (max-width: 960px) {
  .login-wrap { flex-direction: column; }
  .login-brand { flex: none; height: 208px; }
  .login-panel { padding: 36px 24px 48px; }
}
@media (max-width: 640px) {
  .login-brand { height: 172px; }
  .login-head { margin-bottom: 22px; }
  .login-logo .mark { width: 52px; height: 52px; border-radius: var(--r-lg); }
  .login-logo .mark svg { width: 28px; height: 28px; }
  .login-brand-title { font-size: 22px; }
  .login-panel { padding: 28px 20px 40px; }
  .login-card { max-width: none; }
  .login-card h3 { font-size: var(--fs-20); }
}

/* ============================================================================
   ④-2 表单基础件（全站共用）
   ============================================================================ */
.field { margin-bottom: 16px; }
.field label { display: block; font-size: var(--fs-13); color: var(--ink-700); margin-bottom: 6px; font-weight: 500; }
/* 聚焦时标签同步高亮（:has 由 chromium 实测支持，见报告特性清单） */
.field:has(.input:focus, .select:focus, .textarea:focus) > label { color: var(--brand-600); }

.input, .select, .textarea {
  width: 100%; padding: 9px 12px; border: 1px solid var(--border-strong);
  border-radius: var(--r-md); background: #fff; outline: none;
  transition: border-color var(--t-1) var(--ease), box-shadow var(--t-1) var(--ease), background var(--t-1) var(--ease);
}
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-300); }
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--brand-500); box-shadow: var(--ring);
}
.input::placeholder, .textarea::placeholder { color: var(--text-mute); }
.textarea { resize: vertical; min-height: 92px; line-height: var(--lh-body); }
.input[readonly], .input:disabled, .select:disabled { background: var(--ink-50); color: var(--text-sub); cursor: not-allowed; border-color: var(--border); }
/* 校验失败态：由 .err-msg 兄弟触发 */
.field:has(.err-msg) .input,
.field:has(.err-msg) .select,
.field:has(.err-msg) .textarea { border-color: var(--red-solid); }
.field:has(.err-msg) .input:focus { box-shadow: var(--ring-danger); }

/* 只读字段视图 */
.roview {
  display: flex; align-items: center; min-height: 41px; padding: 8px 12px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--ink-50); color: var(--text-sub); font-size: var(--fs-14); line-height: var(--lh-body);
}

.checkbox-row { display: flex; align-items: center; gap: 8px; font-size: var(--fs-13); color: var(--text-sub); cursor: pointer; }
.checkbox-row input { width: 16px; height: 16px; accent-color: var(--brand-600); cursor: pointer; }

/* 身份选择列表（登录多身份） */
.identity-list { margin-top: 4px; display: grid; gap: 8px; }
.identity-item {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  cursor: pointer; transition: all var(--t-1) var(--ease); background: #fff;
}
.identity-item:hover { border-color: var(--brand-400); background: var(--brand-50); }
/* ---------- 头像 .avat（单一真相源） ----------
   由 JS 的 avatar(name,size) 生成，JS 只注入两个变量：
     --avat-size = 边长（默认 32px）   --avat-bg = 按姓名哈希得到的稳定底色
   圆角、白字、字号随边长缩放、居中、禁止收缩都在这里定义。
   各处只需覆盖自己关心的项，例如 `.xxx .avat { width: var(--avat-size, 34px) }`。
   注：改动前 JS 把宽高等 11 个属性内联在元素上，内联优先级压倒样式表，
   使下面的各条 `.xxx .avat` 规则形同虚设；现在它们才真正生效。 */
.avat {
  width: var(--avat-size, 32px); height: var(--avat-size, 32px);
  border-radius: 50%; background: var(--avat-bg, var(--brand-600)); color: #fff;
  font-size: calc(var(--avat-size, 32px) * 0.38); font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.identity-item .avat {
  width: var(--avat-size, 34px); height: var(--avat-size, 34px); border-radius: 50%; color: #fff; font-size: var(--fs-13); font-weight: 600;
  display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.identity-item .meta { flex: 1; min-width: 0; }
.identity-item .meta .nm { font-weight: 600; font-size: var(--fs-14); }
.identity-item .meta .po { font-size: var(--fs-12); color: var(--text-sub); }
.identity-item .go { color: var(--text-sub); }

.divider-text { display: flex; align-items: center; gap: 12px; color: var(--text-sub); font-size: var(--fs-12); margin: 24px 0 12px; }
.divider-text::before, .divider-text::after { content: ""; height: 1px; background: var(--border); flex: 1; }

/* ============================================================================
   ④-3 主框架：顶栏 + 领航轨（左侧导航）+ 内容区
   ============================================================================ */
.app-header {
  height: var(--header-h);
  background: linear-gradient(180deg, rgba(255, 255, 255, .96) 0%, rgba(247, 251, 255, .94) 100%);
  -webkit-backdrop-filter: saturate(140%) blur(8px); backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--border-strong);
  display: flex; align-items: center; padding: 0 20px; position: fixed; inset: 0 0 auto 0; z-index: 100;
  box-shadow: 0 1px 2px rgba(16, 32, 56, .05);
}
.app-header .brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: var(--fs-15); color: var(--brand-900); letter-spacing: .2px; }
.app-header .brand .mark {
  width: 32px; height: 32px; border-radius: var(--r-md);
  background: linear-gradient(150deg, var(--brand-600) 0%, var(--brand-800) 100%);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 10px color-mix(in srgb, var(--brand-800) 26%, transparent), inset 0 1px 0 rgba(255, 255, 255, .18);
}
.app-header .spacer { flex: 1; }
.header-actions { display: flex; align-items: center; gap: 10px; }
.header-icon {
  position: relative; width: 36px; height: 36px; border-radius: var(--r-md); border: 1px solid transparent;
  display: flex; align-items: center; justify-content: center; color: var(--text-sub); cursor: pointer; background: transparent;
  transition: background var(--t-1) var(--ease), color var(--t-1) var(--ease);
}
.header-icon:hover { background: var(--ink-100); color: var(--brand-600); }
.header-icon .badge {
  position: absolute; top: 1px; right: 1px; min-width: 16px; height: 16px; padding: 0 4px;
  background: var(--red-solid); color: #fff; font-size: 10px; line-height: 16px; text-align: center;
  border-radius: var(--r-pill); font-weight: 700; box-shadow: 0 0 0 2px #fff;
}
.role-switch { display: flex; align-items: center; gap: 8px; }
.role-switch select {
  padding: 6px 10px; border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: #fff; font-size: var(--fs-13); outline: none; max-width: 210px;
}
.role-switch select:focus { border-color: var(--brand-500); box-shadow: var(--ring); }
.user-chip { display: flex; align-items: center; gap: 9px; padding-inline-start: 14px; border-inline-start: 1px solid var(--border); }
.user-chip .avat { width: var(--avat-size, 32px); height: var(--avat-size, 32px); border-radius: 50%; color: #fff; font-size: var(--fs-12); font-weight: 600; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 2px #fff, 0 0 0 3px var(--ink-200); }
.user-chip .nm { font-size: var(--fs-13); font-weight: 600; line-height: 1.25; }
.user-chip .po { font-size: var(--fs-11); color: var(--text-sub); line-height: 1.25; }

.app-body { display: flex; padding-top: var(--header-h); min-height: 100vh; }

/* —— 领航轨（本设计的记忆点） ——
   深蓝竖向锚线：稳定、专业、有「值班控制台」气质。
   当前项 = 半透明高亮 + 左侧信号色竖条；分组小标题在含激活项时提亮。 */
.app-side {
  width: var(--side-w); flex: 0 0 var(--side-w);
  background: linear-gradient(180deg, var(--rail-bg-1) 0%, var(--rail-bg-2) 100%);
  border-right: 1px solid var(--rail-line);
  position: fixed; top: var(--header-h); bottom: 0; left: 0;
  overflow-y: auto; padding: 14px 12px 24px;
  scrollbar-width: thin; scrollbar-color: rgba(15, 23, 42, .16) transparent;
}
.app-side::-webkit-scrollbar { width: 8px; }
.app-side::-webkit-scrollbar-thumb { background: rgba(15, 23, 42, .14); border-radius: var(--r-pill); }
.app-side .nav-group { margin-bottom: 6px; }
.app-side .nav-label { font-size: var(--fs-11); color: var(--rail-ink-dim); padding: 14px 12px 6px; letter-spacing: 1.4px; font-weight: 600; transition: color var(--t-2) var(--ease); }
/* 含激活项的分组标题提亮（:has 由 chromium 实测支持） */
.app-side .nav-group:has(.nav-item.active) > .nav-label { color: var(--rail-ink); }

.app-side .nav-sublabel {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--fs-12); font-weight: 600; color: var(--rail-ink-dim);
  padding: 12px 12px 6px; letter-spacing: .5px;
}
.app-side .nav-sublabel::before {
  content: ""; width: 3px; height: 11px; border-radius: 2px;
  background: var(--accent); opacity: .55;
}

.nav-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: var(--r-md);
  color: var(--rail-ink); font-size: var(--fs-14); margin-bottom: 2px; cursor: pointer; position: relative;
  transition: background var(--t-1) var(--ease), color var(--t-1) var(--ease);
}
.nav-item:hover { background: var(--rail-hover); color: var(--rail-ink-strong); text-decoration: none; }
/* 激活态：原先是「白色文字 + 半透明蓝叠加」（为深底而设），浅底上会看不见。
   改为「浅蓝底 + 深蓝字 + 细描边」，在白色侧栏里靠颜色而不是靠明暗对比来突出。 */
/* 激活项＝「局部高饱和」的落点。
   为什么改成实心渐变芯片：浅色侧栏上，浅蓝底+深蓝字的指示偏弱（就是「寡淡」的来源之一）。
   但注意 --accent 不能是「整块深色」那种压抑 —— 高饱和只占一个小方块，范围极小，
   所以既醒目又不压迫。 */
.nav-item.active {
  background: linear-gradient(135deg, var(--brand-600) 0%, var(--brand-500) 100%);
  color: #fff; font-weight: 600;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--brand-600) 34%, transparent);
}
.nav-item.active::before {
  content: ""; position: absolute; inset-inline-start: 0; top: 8px; bottom: 8px; width: 3px;
  border-radius: 0 3px 3px 0; background: #fff; opacity: .9; box-shadow: none;
}
.nav-item .nav-ico { color: var(--rail-ink-dim); display: flex; transition: color var(--t-1) var(--ease); }
.nav-item:hover .nav-ico { color: var(--rail-ink-strong); }
/* ⚠ 原来这里是 color: var(--accent) —— 底色换成同色渐变后，图标会直接消失。 */
.nav-item.active .nav-ico { color: #fff; }
.nav-item .badge {
  margin-inline-start: auto; min-width: 18px; height: 18px; padding: 0 5px; background: var(--red-solid);
  color: #fff; font-size: var(--fs-11); line-height: 18px; text-align: center; border-radius: var(--r-pill); font-weight: 700;
}

.app-main { flex: 1; margin-left: var(--side-w); padding: 28px; min-width: 0; }
.page { max-width: 1240px; }

/* 面包屑 & 页头 */
.crumb { font-size: var(--fs-12); color: var(--text-sub); margin-bottom: 12px; }
.crumb a { color: var(--text-sub); }
.crumb a:hover { color: var(--brand-600); }
.crumb .sep { margin: 0 6px; color: var(--ink-300); }
.page-head { display: flex; align-items: flex-end; justify-content: space-between; margin-bottom: 20px; gap: 16px; flex-wrap: wrap; }
.page-head h1 { font-size: var(--fs-h1); font-weight: 700; letter-spacing: -.2px; color: var(--ink-900); }
.page-head .desc { font-size: var(--fs-13); color: var(--text-sub); margin-top: 4px; }

/* ============================================================================
   ⑤ 通用构件
   ============================================================================ */

/* ---------- 卡片 ---------- */
.card {
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--sh-sm); padding: 22px 26px; margin-bottom: 18px;
}
.card.tight { padding: 16px 20px; }
/* 卡片头加一条极细分隔线：把「标题」与「内容」在结构上分开 —— 这是「寡淡」的另一个来源
   （原先标题和内容在同一浅平面上，读起来没有层次）。只加下边框不动布局宽高。 */
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-bottom: 12px; margin-bottom: 14px; border-bottom: 1px solid var(--border); }
/* 标题不参与收缩（避免中文标题被挤压成竖排），空间让给右侧 hint 折行 */
.card-head h3 { font-size: var(--fs-16); font-weight: 600; color: var(--ink-800); flex: 0 0 auto; }
.card-head .hint { font-size: var(--fs-12); color: var(--text-sub); text-align: right; }
.section-title { font-size: var(--fs-16); font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; color: var(--ink-800); }
.section-title::before { content: ""; width: 3px; height: 15px; background: var(--brand-600); border-radius: 2px; }

/* ---------- 按钮 ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 16px; border-radius: var(--r-md); border: 1px solid transparent;
  font-size: var(--fs-14); font-weight: 500; transition: background var(--t-1) var(--ease), border-color var(--t-1) var(--ease), color var(--t-1) var(--ease), box-shadow var(--t-1) var(--ease), transform var(--t-1) var(--ease);
  white-space: nowrap; line-height: 1.2;
}
.btn:active { transform: translateY(.5px); }
.btn-primary { background: linear-gradient(180deg, var(--brand-600) 0%, var(--brand-700) 100%); color: #fff; box-shadow: 0 1px 2px color-mix(in srgb, var(--brand-800) 34%, transparent), inset 0 1px 0 rgba(255, 255, 255, .14); }
.btn-primary:hover { background: linear-gradient(180deg, var(--brand-500) 0%, var(--brand-600) 100%); }
.btn-ghost { background: #fff; color: var(--ink-700); border-color: var(--border-strong); }
.btn-ghost:hover { border-color: var(--brand-400); color: var(--brand-600); background: var(--brand-50); }
.btn-success { background: linear-gradient(180deg, var(--green-solid) 0%, #12813C 100%); color: #fff; box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14); }
.btn-success:hover { filter: brightness(1.04); }
.btn-danger { background: #fff; color: var(--red-ink); border-color: color-mix(in srgb, var(--red-solid) 34%, #fff); }
.btn-danger:hover { background: var(--red-bg); border-color: var(--red-solid); }
.btn-sm { padding: 6px 12px; font-size: var(--fs-13); }
.btn-block { width: 100%; }
.btn:disabled { opacity: .55; cursor: not-allowed; transform: none; box-shadow: none; }
.btn-link { background: none; border: none; color: var(--brand-600); padding: 3px 6px; font-size: var(--fs-13); border-radius: var(--r-sm); transition: background var(--t-1) var(--ease), color var(--t-1) var(--ease); }
.btn-link:hover { text-decoration: none; background: var(--brand-50); color: var(--brand-700); }

/* ---------- 标签 / 徽章 ---------- */
.tag {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 10px; border-radius: var(--r-pill);
  font-size: var(--fs-12); font-weight: 600; line-height: 1.7; white-space: nowrap;
}
.tag-green { background: var(--green-bg); color: var(--green-ink); }
.tag-red { background: var(--red-bg); color: var(--red-ink); }
.tag-blue { background: var(--blue-bg); color: var(--blue-ink); }
.tag-amber { background: var(--amber-bg); color: var(--amber-ink); }
.tag-gray { background: var(--gray-bg); color: var(--gray-ink); }
.tag-brand { background: var(--brand-100); color: var(--brand-700); }
.tag-teal { background: var(--teal-bg); color: var(--teal-ink); }
.dot-ind { width: 6px; height: 6px; border-radius: 50%; background: currentColor; display: inline-block; }

/* ---------- 表格 ---------- */
.table-scroll { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--r-lg); background: #fff; min-width: 0; }
table.grid { width: 100%; border-collapse: collapse; font-size: var(--fs-14); }
table.grid thead th {
  background: linear-gradient(180deg, var(--brand-50) 0%, #EEF4FB 100%); color: var(--ink-600); font-weight: 600; font-size: var(--fs-12);
  text-align: left; padding: 11px 16px; white-space: nowrap; border-bottom: 1px solid var(--border); letter-spacing: .2px;
}
table.grid thead th:first-child { border-top-left-radius: var(--r-lg); }
table.grid thead th:last-child { border-top-right-radius: var(--r-lg); }
table.grid tbody td { padding: 0 16px; height: 48px; border-bottom: 1px solid var(--ink-100); vertical-align: middle; line-height: var(--lh-body); }
table.grid tbody tr:last-child td { border-bottom: none; }
table.grid tbody tr { transition: background var(--t-1) var(--ease); }
table.grid tbody tr:hover { background: var(--brand-50); }
table.grid td.ops, table.grid th.ops { text-align: right; white-space: nowrap; }
table.grid .num { font-variant-numeric: tabular-nums; }
.link-code { color: var(--brand-600); font-weight: 600; cursor: pointer; }
.link-code:hover { text-decoration: underline; }

/* ---------- Tab ---------- */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
.tab {
  padding: 10px 16px; font-size: var(--fs-14); color: var(--text-sub); cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px; display: flex; align-items: center; gap: 6px;
  background: none; border-top: none; border-left: none; border-right: none;
  transition: color var(--t-1) var(--ease), border-color var(--t-1) var(--ease);
}
.tab:hover { color: var(--brand-600); }
.tab.active { color: var(--brand-600); font-weight: 600; border-bottom-color: var(--brand-600); }
.tab .badge { min-width: 18px; height: 18px; padding: 0 5px; background: var(--red-solid); color: #fff; font-size: var(--fs-11); line-height: 18px; border-radius: var(--r-pill); text-align: center; font-weight: 700; }

/* ---------- 筛选 Chip ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong); background: #fff; color: var(--ink-700); font-size: var(--fs-13); cursor: pointer;
  transition: all var(--t-1) var(--ease);
}
.chip:hover { border-color: var(--brand-400); color: var(--brand-600); background: var(--brand-50); }
.chip.on { background: var(--brand-600); border-color: var(--brand-600); color: #fff; font-weight: 600; box-shadow: 0 2px 8px color-mix(in srgb, var(--brand-600) 28%, transparent); }
.chip .n { background: rgba(0, 0, 0, .06); color: inherit; border-radius: var(--r-pill); padding: 0 7px; font-size: var(--fs-12); line-height: 16px; font-weight: 600; }
.chip.on .n { background: rgba(255, 255, 255, .28); }

/* ---------- 分页 ---------- */
.pager { display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin-top: 16px; font-size: var(--fs-13); color: var(--text-sub); }
.pager .pg { min-width: 32px; height: 32px; padding: 0 8px; border: 1px solid var(--border-strong); border-radius: var(--r-sm); background: #fff; color: var(--ink-700); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all var(--t-1) var(--ease); }
.pager .pg:hover { border-color: var(--brand-400); color: var(--brand-600); }
.pager .pg.on { background: var(--brand-600); border-color: var(--brand-600); color: #fff; font-weight: 600; }

/* ---------- 空状态 ---------- */
.empty { text-align: center; padding: 52px 16px; color: var(--text-sub); }
.empty .ic { color: var(--ink-300); margin-bottom: 12px; display: flex; justify-content: center; }

/* ---------- 数据卡片 / 统计 ---------- */
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 16px; }
.stat {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--sh-sm); padding: 18px 20px; cursor: pointer; position: relative; overflow: hidden;
  transition: border-color var(--t-2) var(--ease), box-shadow var(--t-2) var(--ease), transform var(--t-2) var(--ease);
}
/* 加质感的关键小招：这条 3px 色条本来就存在，但只在悬停时才出现（opacity:0），
   等于白写。改成常显后，一排统计卡立刻有了色彩节奏与左右结构。 */
.stat::before { content: ""; position: absolute; inset-inline-start: 0; top: 0; bottom: 0; width: 4px; background: var(--brand-600); opacity: .9; transition: opacity var(--t-2) var(--ease); }
.stat:hover { border-color: var(--brand-300); box-shadow: var(--sh-md); transform: translateY(-2px); }
.stat:hover::before { opacity: .9; }
.stat .lbl { font-size: var(--fs-13); color: var(--text-sub); display: flex; align-items: center; gap: 6px; }
.stat .val { font-size: var(--fs-28); font-weight: 700; margin-top: 8px; line-height: 1.2; font-variant-numeric: tabular-nums; color: var(--ink-900); letter-spacing: -.5px; }
.stat .val .unit { font-size: var(--fs-14); font-weight: 400; color: var(--text-sub); margin-inline-start: 4px; }
.stat .sub { font-size: var(--fs-12); color: var(--text-sub); margin-top: 6px; }
.stat .act { display: flex; }
.stat.accent-blue .val { color: var(--brand-600); }
.stat.accent-red .val { color: var(--red-ink); }
.stat.accent-green .val { color: var(--green-ink); }
/* 色条跟随语义：数字与色条同色，一眼能把「要处理的」和「正常的」分开 */
.stat.accent-blue::before { background: var(--brand-500); }
.stat.accent-red::before { background: var(--red-solid); }
.stat.accent-green::before { background: var(--green-solid); }

/* 三态余额卡 */
.balance-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 16px; }
.balance-card {
  background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--sh-sm); padding: 22px 24px; position: relative; overflow: hidden;
}
.balance-card .lbl { font-size: var(--fs-14); color: var(--text-sub); }
.balance-card .val { font-size: var(--fs-28); font-weight: 700; margin-top: 8px; font-variant-numeric: tabular-nums; letter-spacing: -.5px; }
.balance-card .val .unit { font-size: var(--fs-16); font-weight: 400; color: var(--text-sub); margin-inline-start: 6px; }
.balance-card .sub { font-size: var(--fs-12); color: var(--text-sub); margin-top: 8px; }
.balance-card.total { border-top: 3px solid var(--brand-600); }
.balance-card.frozen { border-top: 3px solid var(--amber-solid); }
.balance-card.avail { border-top: 3px solid var(--green-solid); }
.balance-card.total .val { color: var(--brand-800); }
.balance-card.frozen .val { color: var(--amber-ink); }
.balance-card.avail .val { color: var(--green-ink); }

/* ---------- 表单栅格 ---------- */
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 24px; }
.form-grid.col3 { grid-template-columns: repeat(3, 1fr); }
.form-grid .span2 { grid-column: span 2; }
.form-grid .span3 { grid-column: span 3; }
.field .req { color: var(--red-solid); margin-inline-start: 2px; }
.form-hint { font-size: var(--fs-12); color: var(--text-sub); margin-top: 6px; line-height: 1.55; }
.err-msg { font-size: var(--fs-12); color: var(--red-ink); margin-top: 6px; display: flex; align-items: center; gap: 4px; }

/* 提示横幅 */
.banner { display: flex; gap: 10px; padding: 12px 16px; border-radius: var(--r-md); font-size: var(--fs-13); line-height: var(--lh-body); margin-bottom: 16px; align-items: flex-start; border: 1px solid transparent; }
.banner .bi { flex: 0 0 auto; margin-top: 1px; }
.banner-amber { background: var(--amber-bg); color: var(--amber-ink); border-color: color-mix(in srgb, var(--amber-solid) 22%, #fff); }
.banner-red { background: var(--red-bg); color: var(--red-ink); border-color: color-mix(in srgb, var(--red-solid) 20%, #fff); }
.banner-blue { background: var(--blue-bg); color: var(--blue-ink); border-color: color-mix(in srgb, var(--blue-solid) 18%, #fff); }
.banner-green { background: var(--green-bg); color: var(--green-ink); border-color: color-mix(in srgb, var(--green-solid) 20%, #fff); }
.banner-gray { background: var(--gray-bg); color: var(--gray-ink); border-color: var(--border); }

/* 单选项卡片 */
.radio-cards { display: flex; gap: 12px; flex-wrap: wrap; }
.radio-card {
  display: flex; align-items: center; gap: 10px; padding: 12px 16px; border: 1px solid var(--border-strong);
  border-radius: var(--r-md); cursor: pointer; background: #fff; min-width: 160px; transition: all var(--t-1) var(--ease);
}
.radio-card:hover { border-color: var(--brand-400); }
.radio-card.on { border-color: var(--brand-600); background: var(--brand-50); box-shadow: inset 0 0 0 1px var(--brand-600); }
.radio-card .rd { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--border-strong); position: relative; flex: 0 0 auto; }
.radio-card.on .rd { border-color: var(--brand-600); }
.radio-card.on .rd::after { content: ""; position: absolute; inset: 2px; background: var(--brand-600); border-radius: 50%; }
.radio-card .tt { font-size: var(--fs-14); font-weight: 500; }
.radio-card .dd { font-size: var(--fs-12); color: var(--text-sub); }
.radio-card.locked { cursor: default; opacity: .92; }

/* 试算面板 */
.calc-panel { background: linear-gradient(180deg, #F8FAFC 0%, #F3F7FC 100%); border: 1px dashed var(--brand-300); border-radius: var(--r-md); padding: 16px; margin-top: 12px; }
.calc-panel .amt { font-size: var(--fs-24); font-weight: 700; color: var(--brand-700); font-variant-numeric: tabular-nums; }
.calc-formula { font-family: var(--font-mono); font-size: var(--fs-13); background: #fff; border: 1px solid var(--border); border-radius: var(--r-sm); padding: 8px 12px; margin-top: 8px; color: var(--ink-700); }

/* 路由判定面板 */
.route-panel { border: 1px solid var(--border); border-radius: var(--r-md); padding: 16px; background: var(--ink-50); }
.route-steps { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.route-step { display: flex; align-items: center; gap: 8px; padding: 6px 12px; border-radius: var(--r-pill); background: #fff; border: 1px solid var(--border); font-size: var(--fs-13); color: var(--text-sub); }
.route-step.hit { background: var(--brand-600); border-color: var(--brand-600); color: #fff; font-weight: 600; }
.route-step .n { width: 18px; height: 18px; border-radius: 50%; background: rgba(0, 0, 0, .06); display: flex; align-items: center; justify-content: center; font-size: var(--fs-11); }
.route-step.hit .n { background: rgba(255, 255, 255, .25); }
.route-arrow { color: var(--ink-300); }
.route-result { display: flex; align-items: center; gap: 12px; padding: 12px 16px; background: var(--brand-50); border-radius: var(--r-md); }
.route-result .avatar { width: 40px; height: 40px; border-radius: 50%; background: var(--brand-600); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 600; }
.route-result .nm { font-weight: 600; font-size: var(--fs-15); color: var(--brand-800); }
.route-result .lv { font-size: var(--fs-12); color: var(--brand-600); }

/* ---------- 审批布局 / 详情列表 / 附件 ---------- */
.approve-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 20px; align-items: start; }
.approve-grid > * { min-width: 0; }
.approve-aside { position: sticky; top: calc(var(--header-h) + 24px); }
.dl { display: grid; grid-template-columns: 128px 1fr; gap: 10px 16px; font-size: var(--fs-14); }
.dl dt { color: var(--text-sub); }
.dl dd { color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.dl.one-col { grid-template-columns: 1fr; }
.attach-item { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--r-md); background: #fff; transition: all var(--t-1) var(--ease); }
.attach-item:hover { border-color: var(--brand-300); background: var(--brand-50); }
.attach-thumb { width: 44px; height: 44px; border-radius: var(--r-md); background: var(--brand-100); display: flex; align-items: center; justify-content: center; color: var(--brand-600); flex: 0 0 auto; }
.attach-list { display: flex; flex-direction: column; gap: 8px; }
.attach-list .attach-item { margin: 0; }
.hide-file { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; clip: rect(0 0 0 0); }
label.btn { cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }

/* ---------- 时间线 ---------- */
.timeline { position: relative; padding-inline-start: 8px; }
.tl-item { position: relative; padding: 0 0 20px 28px; border-left: 2px solid var(--border); margin-inline-start: 6px; }
.tl-item:last-child { border-left-color: transparent; padding-bottom: 0; }
.tl-item .node { position: absolute; left: -9px; top: 2px; width: 16px; height: 16px; border-radius: 50%; background: #fff; border: 3px solid var(--border-strong); }
.tl-item.done .node { border-color: var(--green-solid); }
.tl-item.active .node { border-color: var(--blue-solid); }
.tl-item.rejected .node { border-color: var(--red-solid); }
.tl-item.pending .node { border-color: var(--border-strong); }
.tl-item .tt { font-weight: 600; font-size: var(--fs-14); }
.tl-item .meta { font-size: var(--fs-12); color: var(--text-sub); margin-top: 2px; }
.tl-item .cmt { font-size: var(--fs-13); background: var(--ink-50); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 8px 12px; margin-top: 8px; }

/* ---------- 制度手册 ---------- */
.policy-layout { display: grid; grid-template-columns: 240px 1fr; gap: 20px; align-items: start; }
.policy-layout > * { min-width: 0; }
.policy-tree {
  position: sticky; top: calc(var(--header-h) + 24px); background: #fff; border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sh-sm); padding: 12px;
  max-height: calc(100vh - var(--header-h) - 48px); overflow-y: auto;
}
.policy-doc-group { margin-bottom: 8px; }
.policy-doc-title { font-size: var(--fs-13); font-weight: 600; padding: 8px 10px; color: var(--brand-800); display: flex; align-items: center; gap: 6px; cursor: pointer; border-radius: var(--r-sm); transition: background var(--t-1) var(--ease); }
.policy-doc-title:hover { background: var(--brand-50); }
.policy-sec { display: block; font-size: var(--fs-13); color: var(--text-sub); padding: 6px 10px 6px 24px; border-radius: var(--r-sm); cursor: pointer; transition: all var(--t-1) var(--ease); }
.policy-sec:hover { background: var(--brand-50); color: var(--brand-600); text-decoration: none; }
.policy-sec.active { background: var(--brand-100); color: var(--brand-700); font-weight: 600; }
.policy-main { background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--sh-sm); padding: 32px 40px; max-width: 820px; }
.policy-main h2 { font-size: var(--fs-24); font-weight: 700; color: var(--brand-900); margin-bottom: 8px; letter-spacing: -.2px; }
.policy-main .doc-meta { font-size: var(--fs-12); color: var(--text-sub); padding-bottom: 16px; border-bottom: 1px solid var(--border); margin-bottom: 24px; }
.policy-content h4 { font-size: var(--fs-15); font-weight: 600; margin: 22px 0 10px; color: var(--ink-800); }
.policy-content p { margin-bottom: 12px; line-height: var(--lh-prose); }
.policy-content ul { margin: 0 0 14px 0; padding-inline-start: 22px; }
.policy-content li { margin-bottom: 8px; line-height: var(--lh-prose); }
.policy-content strong { color: var(--brand-800); }
.policy-content table { width: 100%; border-collapse: collapse; margin: 12px 0 18px; font-size: var(--fs-13); }
.policy-content th, .policy-content td { border: 1px solid var(--border); padding: 10px 12px; text-align: left; }
.policy-content th { background: var(--brand-50); font-weight: 600; }
.policy-content mark { background: #FDE68A; color: #92400E; padding: 0 2px; border-radius: 2px; font-weight: 600; }
.policy-nav { display: flex; justify-content: space-between; gap: 12px; margin-top: 32px; padding-top: 20px; border-top: 1px solid var(--border); }

.search-box { display: flex; align-items: center; gap: 8px; background: #fff; border: 1px solid var(--border-strong); border-radius: var(--r-md); padding: 8px 14px; transition: all var(--t-1) var(--ease); }
.search-box input { border: none; outline: none; flex: 1; font-size: var(--fs-14); background: transparent; }
.search-box:focus-within { border-color: var(--brand-500); box-shadow: var(--ring); }
.search-result-item { display: block; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--r-md); margin-bottom: 8px; cursor: pointer; background: #fff; transition: all var(--t-1) var(--ease); }
.search-result-item:hover { border-color: var(--brand-400); background: var(--brand-50); text-decoration: none; }
.search-result-item .rt { font-weight: 600; font-size: var(--fs-14); color: var(--ink-800); }
.search-result-item .rd { font-size: var(--fs-12); color: var(--text-sub); margin-top: 2px; }

.policy-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.policy-card { background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--sh-sm); padding: 20px; cursor: pointer; transition: all var(--t-2) var(--ease); display: flex; flex-direction: column; }
.policy-card:hover { border-color: var(--brand-300); box-shadow: var(--sh-md); transform: translateY(-3px); }
.policy-card .ico { width: 44px; height: 44px; border-radius: var(--r-lg); background: var(--brand-100); color: var(--brand-600); display: flex; align-items: center; justify-content: center; margin-bottom: 14px; }
.policy-card h4 { font-size: var(--fs-15); font-weight: 600; line-height: 1.5; margin-bottom: 8px; color: var(--ink-800); }
.policy-card .m { font-size: var(--fs-12); color: var(--text-sub); }
.policy-card .cs { font-size: var(--fs-12); color: var(--text-sub); margin-top: auto; padding-top: 12px; }
.policy-list { margin: 0; padding-inline-start: 22px; }
.policy-list li { margin-bottom: 8px; line-height: var(--lh-prose); }
.policy-list strong { color: var(--brand-800); }

/* ---------- 趋势图 ---------- */
.chart-box { width: 100%; overflow: hidden; }
.chart-legend { display: flex; gap: 16px; font-size: var(--fs-12); color: var(--text-sub); margin-top: 8px; flex-wrap: wrap; }
.chart-legend .lg { display: flex; align-items: center; gap: 6px; }
.chart-legend .sw { width: 12px; height: 3px; border-radius: 2px; }

/* ---------- 团队 / 消息 / 快捷 / 待办 ---------- */
.team-list-item { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: var(--r-md); cursor: pointer; border: 1px solid transparent; transition: all var(--t-1) var(--ease); }
.team-list-item:hover { background: var(--brand-50); }
.team-list-item.active { background: var(--brand-100); border-color: var(--brand-200); }
.team-list-item .tn { font-weight: 600; font-size: var(--fs-14); }
.team-list-item .tm { font-size: var(--fs-12); color: var(--text-sub); }

.msg-item { display: flex; align-items: flex-start; gap: 14px; padding: 16px; border-bottom: 1px solid var(--ink-100); }
.msg-item:last-child { border-bottom: none; }
.msg-item.unread { background: var(--brand-50); }
.msg-item .mi { width: 38px; height: 38px; border-radius: var(--r-lg); display: flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.msg-item .mt { font-weight: 600; font-size: var(--fs-14); }
.msg-item .md { font-size: var(--fs-13); color: var(--text-sub); margin-top: 2px; }
.msg-item .mr { margin-inline-start: auto; text-align: right; font-size: var(--fs-12); color: var(--text-sub); white-space: nowrap; }

.quick-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.quick {
  display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 18px 12px;
  border: 1px solid var(--border); border-radius: var(--r-lg); background: #fff; cursor: pointer; transition: all var(--t-2) var(--ease);
}
.quick:hover { border-color: var(--brand-300); background: var(--brand-50); transform: translateY(-2px); box-shadow: var(--sh-sm); }
.quick .qi { width: 40px; height: 40px; border-radius: var(--r-lg); background: var(--brand-100); color: var(--brand-600); display: flex; align-items: center; justify-content: center; transition: background var(--t-2) var(--ease), color var(--t-2) var(--ease); }
.quick:hover .qi { background: var(--brand-600); color: #fff; }
.quick .qt { font-size: var(--fs-13); font-weight: 500; }

.todo-item { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px dashed var(--border); }
.todo-item:last-child { border-bottom: none; }
.todo-item .ti { width: 34px; height: 34px; border-radius: var(--r-md); background: var(--brand-50); color: var(--brand-600); display: flex; align-items: center; justify-content: center; flex: 0 0 auto; }

/* ---------- 底部操作栏 ---------- */
.form-actions {
  display: flex; align-items: center; justify-content: flex-end; gap: 12px;
  padding: 16px 24px; background: #fff; border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sh-sm); margin-top: 8px;
}
.form-actions .left { margin-inline-end: auto; }

/* ---------- 成员单元格 / 头像 / 进度条 ---------- */
.avatar-sq { width: 36px; height: 36px; border-radius: 50%; color: #fff; font-weight: 600; font-size: var(--fs-13); display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.cell-member { display: flex; align-items: center; gap: 10px; }
.cell-member .cn { font-weight: 600; color: var(--ink-800); white-space: nowrap; }
.cell-member .ci { font-size: var(--fs-12); color: var(--text-sub); white-space: nowrap; }
/* 中文姓名/岗位列的可读下限：两字姓名与三字姓名同宽，杜绝挤压 */
.cell-member > div { min-width: 84px; }

.bar { height: 8px; border-radius: var(--r-pill); background: var(--ink-100); overflow: hidden; }
.bar > span { display: block; height: 100%; border-radius: var(--r-pill); background: var(--brand-600); }

/* ---------- 模态 / 抽屉 / Toast ---------- */
/* 遮罩＝Apple 的「材质」：半透明压暗 + 磨砂。模糊从 2px 提到 14px 并加 saturate，
   让背后内容「退到材质后面」而不是单纯变暗 —— 这是层次感的来源（不用缩放背景，
   因为 .modal-mask 渲染在 .app-main 内部，给祖先加 transform/filter 会让它成为
   position:fixed 的包含块，弹层定位会被搞坏）。
   入场用 transition 而非 animation：transition 可被中途打断/反向，animation 不行。 */
.modal-mask {
  position: fixed; inset: 0; background: rgba(11, 25, 45, .46);
  -webkit-backdrop-filter: blur(14px) saturate(120%); backdrop-filter: blur(14px) saturate(120%);
  display: flex; align-items: center; justify-content: center; z-index: 200; padding: 24px;
  opacity: 1;
  transition: opacity var(--r-base) var(--spring-soft);
}
@starting-style { .modal-mask { opacity: 0; } }

/* 模态：从下方 14px 处带轻微过冲升起（--spring-soft）。
   overscroll-behavior: contain —— 弹层内滚到底不应把滚动「传染」给背后页面。 */
.modal {
  background: #fff; border-radius: var(--r-xl); width: 100%; max-width: 520px; padding: 24px;
  max-height: 90vh; overflow-y: auto; overscroll-behavior: contain;
  box-shadow: 0 1px 2px rgba(11, 33, 64, .06), 0 8px 24px rgba(11, 33, 64, .10), 0 24px 48px rgba(11, 33, 64, .12);
  opacity: 1; transform: none;
  transition: opacity var(--r-base) var(--spring-soft), transform var(--r-base) var(--spring-soft);
}
@starting-style { .modal { opacity: 0; transform: translateY(14px) scale(.96); } }

.modal h3 { font-size: var(--fs-18); font-weight: 600; margin-bottom: 12px; color: var(--ink-900); }
.modal-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 24px; }

.toast-wrap { position: fixed; top: 72px; left: 50%; transform: translateX(-50%); z-index: 300; display: flex; flex-direction: column; gap: 8px; align-items: center; }
/* Toast 用 --spring-bounce（明显过冲）—— 它是「通知」，轻微弹一下更容易被注意到，
   且时长极短（--r-base 260ms），不阻塞任何操作。 */
.toast {
  background: var(--ink-800); color: #fff; padding: 10px 18px; border-radius: var(--r-md);
  font-size: var(--fs-13); display: flex; align-items: center; gap: 8px;
  box-shadow: 0 2px 6px rgba(11, 33, 64, .18), 0 14px 32px rgba(11, 33, 64, .22);
  opacity: 1; transform: none;
  transition: opacity var(--r-fast) var(--spring-soft), transform var(--r-base) var(--spring-bounce);
}
@starting-style { .toast { opacity: 0; transform: translateY(-14px) scale(.94); } }
.toast.ok { background: #14532D; }
.toast.warn { background: #92400E; }
.toast.err { background: #7F1D1D; }


/* ============================================================================
   ⑥ 业务模块
   ============================================================================ */

/* ---------- 加班时间段 ---------- */
.seg-list { display: flex; flex-direction: column; }
.seg-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
.seg-row .seg-dt { width: 220px; }
.seg-row .seg-arrow { color: var(--ink-400); flex: 0 0 auto; }
.seg-row .seg-h { min-width: 72px; font-size: var(--fs-13); font-weight: 600; color: var(--brand-600); font-variant-numeric: tabular-nums; }
.seg-row .seg-del { margin-inline-start: auto; color: var(--red-ink); }
.seg-total { font-size: var(--fs-14); color: var(--text-sub); }
.seg-total strong { font-size: var(--fs-18); color: var(--brand-800); font-variant-numeric: tabular-nums; }

/* ---------- 提交页审批人步骤条 ---------- */
.approval-route { display: flex; align-items: stretch; gap: 8px; flex-wrap: wrap; }
.approval-route .ar-node { border: 1px solid var(--border); border-radius: var(--r-md); padding: 10px 14px; background: var(--ink-50); min-width: 150px; }
.approval-route .ar-node.end { background: var(--green-bg); border-color: color-mix(in srgb, var(--green-solid) 30%, #fff); }
.approval-route .ar-who { display: flex; align-items: center; gap: 8px; }
.approval-route .ar-nm { font-weight: 600; font-size: var(--fs-13); }
.approval-route .ar-r { font-size: var(--fs-12); color: var(--text-sub); }
.approval-route .ar-cond { font-size: var(--fs-12); color: var(--amber-ink); margin-top: 6px; }

/* ---------- 审批链视图 ---------- */
.chain-view { display: flex; align-items: stretch; gap: 8px; flex-wrap: wrap; }
.chain-node { border: 1px solid var(--border); border-radius: var(--r-md); padding: 10px 14px; background: #fff; min-width: 160px; box-shadow: var(--sh-xs); }
.chain-node.cur { border-color: var(--blue-solid); background: var(--blue-bg); }
.chain-node.done { border-color: color-mix(in srgb, var(--green-solid) 30%, #fff); background: var(--green-bg); }
.chain-node .cn-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.chain-node .cn-name { font-weight: 600; font-size: var(--fs-13); }
.chain-node .cn-who { display: flex; align-items: center; gap: 6px; font-size: var(--fs-13); }
.chain-node .cn-role { font-size: var(--fs-12); color: var(--text-sub); margin-top: 4px; }
.chain-node .cn-cond { font-size: var(--fs-12); color: var(--amber-ink); margin-top: 4px; }
.chain-ops { margin-top: 16px; border-top: 1px dashed var(--border); padding-top: 16px; }
.chain-ops .co-line { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }

/* ---------- 绩效考核：等级徽章 ---------- */
.perf-grade { display: inline-flex; align-items: center; justify-content: center; width: 64px; height: 64px; border-radius: var(--r-xl); font-size: var(--fs-28); font-weight: 700; }
.grade-pill { display: inline-block; padding: 1px 10px; border-radius: var(--r-pill); font-size: var(--fs-12); font-weight: 700; text-align: center; }
.grade-S, .grade-A { background: var(--green-bg); color: var(--green-ink); }
.grade-B { background: var(--blue-bg); color: var(--blue-ink); }
.grade-C { background: var(--amber-bg); color: var(--amber-ink); }
.grade-D { background: var(--red-bg); color: var(--red-ink); }
.perf-grade.grade-S, .perf-grade.grade-A { background: var(--green-bg); color: var(--green-ink); }
.perf-grade.grade-B { background: var(--blue-bg); color: var(--blue-ink); }
.perf-grade.grade-C { background: var(--amber-bg); color: var(--amber-ink); }
.perf-grade.grade-D { background: var(--red-bg); color: var(--red-ink); }
/* 打分单元格：输入框与「得分 N」提示同行不换行 */
.score-cell { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }

/* ---------- 审批链可视化编辑器 ---------- */
.chain-canvas {
  display: flex; align-items: stretch; gap: 0; flex-wrap: wrap;
  padding: 24px 16px; border: 1px dashed var(--brand-300); border-radius: var(--r-md);
  background: linear-gradient(180deg, #FBFCFE 0%, #F2F5F9 100%); min-height: 180px;
}
.node-card {
  width: 190px; flex: 0 0 190px; background: #fff; border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 12px 14px; cursor: pointer; position: relative;
  box-shadow: var(--sh-sm); transition: all var(--t-2) var(--ease);
  /* 内容自适应（用户报「头像多了会溢出卡片」）：卡片不设固定高度（由内容撑开，
     行内各卡片经 .chain-canvas 的 align-items:stretch 等高对齐）；长文本/长名单
     允许任意位置断行，配合下方 .nc-actors 的换行，保证**内容绝不越出卡片**。 */
  min-width: 0; overflow-wrap: anywhere;
}
.node-card:hover { border-color: var(--brand-400); box-shadow: var(--sh-md); transform: translateY(-2px); }
.node-card.sel { border-color: var(--brand-600); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-500) 20%, transparent); }
.node-card.start { background: var(--ink-50); border-color: var(--border-strong); cursor: default; }
.node-card.cc { border-style: dashed; border-color: var(--ink-400); background: var(--ink-50); }
.node-card .nc-top { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; flex-wrap: wrap; }
.node-card .nc-seq { font-size: var(--fs-11); color: var(--text-sub); background: var(--ink-100); border-radius: var(--r-pill); padding: 0 8px; line-height: 18px; }
.node-card .nc-name { font-size: var(--fs-15); font-weight: 600; color: var(--brand-800); }
.node-card .nc-who { display: flex; align-items: center; gap: 8px; margin-top: 8px; font-size: var(--fs-13); }
.node-card .nc-role { font-size: var(--fs-12); color: var(--text-sub); margin-top: 4px; }
.node-card .nc-cond { display: flex; align-items: center; gap: 4px; font-size: var(--fs-12); color: var(--amber-ink); margin-top: 6px; }
.node-card .nc-ops { display: flex; align-items: center; gap: 2px; margin-top: 8px; border-top: 1px dashed var(--border); padding-top: 6px; }
.nc-link { display: flex; align-items: center; justify-content: center; width: 34px; flex: 0 0 34px; color: var(--ink-400); }
.chain-toolbar { display: flex; align-items: center; gap: 8px; justify-content: flex-end; margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); flex-wrap: wrap; }

/* 审批链节点多动作（会签 / 抄送）：头像组与名单**必须换行**，否则人一多就顶出卡片右边界。
   · .nc-actors 允许换行 ⇒ 头像组放不下时，名单整体落到下一行；
   · .nc-av 自身也可换行（头像极多时折行）；
   · .nc-act-txt 允许收缩 + 任意断行（min-width:0 是 flex 子项能真正收缩的前提）。 */
.nc-actors { display: flex; align-items: center; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
.nc-actors .nc-av { display: flex; flex-wrap: wrap; row-gap: 2px; max-width: 100%; }
.nc-actors .nc-av .avat { margin-inline-start: -6px; border: 2px solid #fff; }
.nc-actors .nc-av .avat:first-child { margin-inline-start: 0; }
.nc-actors .avat.more { margin-inline-start: -6px; border: 2px solid #fff; width: 22px; height: 22px; border-radius: 50%; background: var(--ink-200); color: var(--ink-700); font-size: 10px; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; }
.nc-actors .nc-act-txt { line-height: 1.35; min-width: 0; flex: 1 1 auto; overflow-wrap: anywhere; }
.actor-row { display: flex; align-items: center; gap: 8px; padding: 4px 0; border-bottom: 1px dashed var(--ink-200); font-size: var(--fs-13); }
.actor-row .btn-link { margin-inline-start: auto; }

/* ---------- 右侧节点编辑抽屉 ---------- */
/* 抽屉＝纸张从侧面「推入」：用 --spring-snappy（比 soft 更快收住，符合侧向滑动的手感）。
   同样用 transition + @starting-style，保证「刚滑出就点关闭」能立刻反向，不用等动画跑完。 */
.drawer {
  position: fixed; top: var(--header-h); right: 0; bottom: 0; width: 380px; max-width: 92vw;
  background: #fff; border-left: 1px solid var(--border);
  box-shadow: -1px 0 0 var(--border), -18px 0 48px rgba(11, 33, 64, .18);
  z-index: 150; display: flex; flex-direction: column;
  transform: translateX(0);
  transition: transform var(--r-base) var(--spring-snappy), opacity var(--r-fast) var(--spring-snappy);
}
@starting-style { .drawer { transform: translateX(24px); opacity: 0; } }
/* 重绘（非新开）时的弹层：把过渡关掉，直接渲染为终态。
   为什么不直接依赖 @starting-style：它每次元素插入都会生效，而本应用是整体替换
   innerHTML 的渲染模型 —— 不显式关掉的话，弹层里每点一次按钮整屏就会闪一下。
   注意 .no-enter 是**运行时**由 renderLayout 追加的，只对"重绘前已存在"的弹层生效。 */
.modal-mask.no-enter, .modal-mask.no-enter .modal, .drawer.no-enter { transition: none; }

.drawer-head { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; border-bottom: 1px solid var(--border); }
.drawer-head h3 { font-size: var(--fs-16); font-weight: 600; }
.drawer-body { flex: 1; overflow-y: auto; padding: 16px 20px; }
.drawer-foot { padding: 12px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 8px; }

/* ---------- 成员日程 ---------- */
.sched-member { border: 1px solid var(--border); border-radius: var(--r-md); padding: 10px 12px; margin-bottom: 10px; background: #fff; box-shadow: var(--sh-xs); }
.sched-member .sm-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.sched-member .sm-stat { margin-inline-start: auto; font-size: var(--fs-12); color: var(--text-sub); }
.sched-member .sm-stat b { color: var(--ink-900); }
.sched-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.sched-head7 { margin-bottom: 8px; }
.sched-cell { position: relative; border: 1px solid var(--border); border-radius: var(--r-sm); min-height: 46px; padding: 3px 4px; background: #fff; font-size: var(--fs-12); }
.sched-cell.empty { border: none; background: transparent; }
.sched-cell.weekend { background: var(--ink-50); }
.sched-cell.pending { background: repeating-linear-gradient(45deg, #F8FAFC, #F8FAFC 4px, var(--border) 4px, var(--border) 8px); cursor: pointer; }
.sched-cell.mark { cursor: pointer; }
.sched-cell.mark:hover { border-color: var(--brand-400); }
.sched-cell .sd { display: block; color: var(--ink-700); font-weight: 600; font-variant-numeric: tabular-nums; }
.sched-cell .sm { display: inline-block; margin-top: 2px; color: #fff; font-size: var(--fs-11); font-weight: 600; border-radius: var(--r-xs); padding: 0 5px; line-height: 16px; }
.sched-cell .sm.pend { background: var(--ink-400); }
.sched-cell.hd { min-height: 28px; text-align: center; color: var(--text-sub); font-weight: 600; background: var(--page-bg); border: none; }

/* ---------- 筛选条 / 角色分布 ---------- */
.filter-bar { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.filter-bar .fb-item { min-width: 180px; }
.filter-bar .fb-item .field { margin-bottom: 0; }
/* 筛选栏自适应（2026-10-12 需求③）：窄屏**换行**而非溢出；标签不折行；控件允许收缩进容器。
   修复现象：「关键字（姓名 / 工号 / 岗位）」标签被挤成两行、输入框超出容器右边界。 */
.filter-bar .fb-item, .filter-bar .fb-grow, .filter-bar .fb-btn { min-width: 0; }
.filter-bar .fb-item > .field > label { white-space: nowrap; }
.filter-bar .fb-grow { flex: 1 1 240px; }
.filter-bar .search-box { max-width: 100%; box-sizing: border-box; }
.filter-bar .search-box input { min-width: 0; width: 100%; }
.filter-bar .fb-grow { flex: 1; min-width: 260px; }
.filter-bar .fb-btn { min-width: auto; padding-bottom: 2px; }
.dist-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px 24px; }
.dist-item { display: flex; align-items: center; gap: 10px; font-size: var(--fs-13); }
.dist-item .dist-bar { flex: 1; height: 8px; background: var(--ink-100); border-radius: var(--r-xs); overflow: hidden; }
.dist-item .dist-bar i { display: block; height: 100%; background: linear-gradient(90deg, var(--brand-500), var(--brand-600)); border-radius: var(--r-xs); }
.dist-item b { font-variant-numeric: tabular-nums; min-width: 20px; text-align: right; }

/* ---------- PMO / 服务商 工作概览 ---------- */
.ov-section { margin-bottom: 20px; }
.ov-section > .ov-title { display: flex; align-items: center; gap: 8px; font-size: var(--fs-16); font-weight: 600; margin-bottom: 12px; color: var(--ink-800); }
.ov-section > .ov-title::before { content: ""; width: 3px; height: 15px; background: var(--brand-600); border-radius: 2px; }
.ov-section > .ov-title .hint { font-size: var(--fs-12); font-weight: 400; color: var(--text-sub); margin-inline-start: auto; }
.ov-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.ov-card { background: var(--ink-50); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 12px 14px; }
.ov-card .k { font-size: var(--fs-12); color: var(--text-sub); }
.ov-card .v { font-size: var(--fs-20); font-weight: 700; margin-top: 4px; line-height: 1.2; font-variant-numeric: tabular-nums; }
.ov-card .v small { font-size: var(--fs-12); font-weight: 400; color: var(--text-sub); margin-inline-start: 3px; }
.ov-card .s { font-size: var(--fs-11); color: var(--text-sub); margin-top: 4px; }
.ov-card.warn { background: var(--red-bg); border-color: color-mix(in srgb, var(--red-solid) 22%, #fff); }
.ov-card.warn .v { color: var(--red-ink); }
.ov-card.ok { background: var(--green-bg); border-color: color-mix(in srgb, var(--green-solid) 24%, #fff); }
.ov-card.ok .v { color: var(--green-ink); }
.grade-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: var(--fs-13); }
.grade-row .gl { width: 28px; font-weight: 600; }
.grade-row .gb { flex: 1; height: 10px; background: var(--ink-100); border-radius: var(--r-sm); overflow: hidden; }
.grade-row .gb i { display: block; height: 100%; border-radius: var(--r-sm); }
.grade-row .gn { width: 84px; text-align: right; color: var(--text-sub); font-variant-numeric: tabular-nums; }
.abnormal-item { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid color-mix(in srgb, var(--red-solid) 22%, #fff); background: var(--red-bg); border-radius: var(--r-md); margin-bottom: 8px; }
.abnormal-item .ai-ic { color: var(--red-ink); display: flex; flex: 0 0 auto; }
.abnormal-item .ai-tx { flex: 1; min-width: 0; font-size: var(--fs-13); line-height: 1.5; }
.abnormal-item .ai-tx b { color: var(--red-ink); }
.abnormal-item .ai-go { flex: 0 0 auto; }

/* ---------- 系统级加权评分项 / 一票否决项 ---------- */
.veto-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 8px 16px; }
.veto-item { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--r-md); background: #fff; font-size: var(--fs-13); line-height: 1.5; }
.veto-item .veto-box { flex: 0 0 auto; margin-top: 1px; }
.veto-item .veto-tx { flex: 1; min-width: 0; word-break: break-word; }
.veto-item.veto-on { background: var(--red-bg); border-color: color-mix(in srgb, var(--red-solid) 24%, #fff); color: var(--red-ink); }
.veto-item.veto-on .veto-tx b { color: var(--red-ink); }
.veto-num { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; background: var(--blue-bg); color: var(--blue-ink); font-size: var(--fs-11); font-weight: 700; margin-inline-end: 6px; }
.veto-item.veto-on .veto-num { background: color-mix(in srgb, var(--red-solid) 24%, #fff); color: var(--red-ink); }
.veto-banner { display: flex; align-items: flex-start; gap: 8px; padding: 10px 12px; border: 1px solid color-mix(in srgb, var(--red-solid) 22%, #fff); background: var(--red-bg); border-radius: var(--r-md); font-size: var(--fs-13); line-height: var(--lh-body); color: var(--red-ink); margin-top: 10px; }
.veto-banner .vb-ic { flex: 0 0 auto; display: flex; }
.sys-block { border: 1px solid var(--border); border-radius: var(--r-lg); margin-bottom: 16px; overflow: hidden; }
.sys-block > .sb-head { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: var(--ink-50); border-bottom: 1px solid var(--border); font-size: var(--fs-14); font-weight: 600; }
.sys-block > .sb-head .sb-tag { margin-inline-start: auto; font-size: var(--fs-11); font-weight: 400; color: var(--text-sub); border: 1px solid var(--border); border-radius: var(--r-pill); padding: 1px 8px; background: #fff; }
.sys-block > .sb-body { padding: 14px; }
.sys-tip { font-size: var(--fs-12); color: var(--text-sub); line-height: var(--lh-body); margin: 0 0 10px; }

/* ---------- 考评总览（月度矩阵） ---------- */
.ov-cell { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; cursor: pointer; padding: 4px 0; }
.ov-cell .ov-sc { font-size: var(--fs-11); color: var(--text-sub); font-variant-numeric: tabular-nums; }
.ov-cell.empty { color: var(--ink-300); cursor: default; }
.ov-cell:hover .ov-sc { color: var(--brand-600); }
.ov-matrix { overflow-x: auto; }
.ov-matrix table { min-width: 1080px; }
.ov-matrix th, .ov-matrix td { text-align: center; white-space: nowrap; }
.ov-matrix th:first-child, .ov-matrix td:first-child { text-align: left; }
.ov-matrix th:nth-child(2), .ov-matrix td:nth-child(2) { text-align: left; }
.ratio-warn { color: var(--red-ink); font-size: var(--fs-12); }
.ov-avgcell { display: flex; flex-direction: column; align-items: center; gap: 2px; }

/* ---------- 考核界面视觉增强（V6） ---------- */
.ap-hero {
  display: flex; align-items: center; gap: 24px; padding: 22px 24px;
  border-radius: var(--r-xl); border: 1px solid var(--brand-100);
  background: linear-gradient(120deg, #F7FAFD 0%, #E8F0FA 100%);
  box-shadow: var(--sh-sm); margin-bottom: 16px;
}
.ap-hero .ap-badge {
  width: 96px; height: 96px; border-radius: 28px; background: #fff; flex: 0 0 auto;
  box-shadow: 0 8px 22px rgba(11, 33, 64, .14);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.ap-hero .ap-badge .g { font-size: 40px; font-weight: 700; line-height: 1; }
.ap-hero .ap-badge .t { font-size: var(--fs-11); color: var(--text-sub); margin-top: 8px; letter-spacing: 2px; }
.ap-hero .ap-main { flex: 1; min-width: 0; }
.ap-hero .ap-k { font-size: var(--fs-12); color: var(--text-sub); letter-spacing: .5px; }
.ap-hero .ap-score { font-size: 36px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--brand-900); }
.ap-hero .ap-score small { font-size: var(--fs-14); font-weight: 400; color: var(--text-sub); margin-inline-start: 5px; }
.ap-hero .ap-tags { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.ap-hero .ap-divider { width: 1px; align-self: stretch; background: var(--brand-200); }
.ap-hero .ap-side { flex: 0 0 auto; min-width: 108px; text-align: center; }
.ap-hero .ap-side .k { font-size: var(--fs-12); color: var(--text-sub); }
.ap-hero .ap-side .v { font-size: var(--fs-20); font-weight: 700; margin-top: 4px; font-variant-numeric: tabular-nums; }
.ap-hero .ap-side .v small { font-size: var(--fs-12); font-weight: 400; color: var(--text-sub); margin-inline-start: 3px; }
.ap-hero .ap-side .s { font-size: var(--fs-11); color: var(--text-sub); margin-top: 2px; }

/* 三级评级流程条 */
.ap-flow { display: flex; align-items: flex-start; padding: 18px 8px 10px; }
.ap-flow .af-step { flex: 1; text-align: center; position: relative; }
.ap-flow .af-step .af-dot {
  width: 30px; height: 30px; border-radius: 50%; margin: 0 auto 8px;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-13); font-weight: 700; background: var(--ink-100); color: var(--ink-400); border: 2px solid var(--border);
  /* 修复「连接横线穿模」：连接线是后续步骤的定位伪元素（::before），默认层叠在非定位的
     .af-dot 之上且几何相交 ⇒ 横线穿过 ✓ 与数字圆圈。抬升 .af-dot 的层叠上下文即可。 */
  position: relative; z-index: 1;
}
.ap-flow .af-step.done .af-dot { background: var(--green-bg); color: var(--green-ink); border-color: color-mix(in srgb, var(--green-solid) 30%, #fff); }
.ap-flow .af-step.current .af-dot { background: var(--brand-600); color: #fff; border-color: var(--brand-600); box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand-500) 18%, transparent); }
.ap-flow .af-step .af-t { font-size: var(--fs-13); font-weight: 600; }
.ap-flow .af-step .af-s { font-size: var(--fs-12); color: var(--text-sub); margin-top: 2px; }
.ap-flow .af-step .af-g { margin-top: 6px; }
.ap-flow .af-step + .af-step::before { content: ""; position: absolute; left: 0; top: 15px; height: 2px; width: 50%; background: var(--border); transform: translateX(-100%); }
.ap-flow .af-step.done + .af-step::before { background: color-mix(in srgb, var(--green-solid) 30%, #fff); }

/* 考核得分条 */
.ap-bar { height: 8px; background: var(--ink-100); border-radius: var(--r-xs); overflow: hidden; }
.ap-bar i { display: block; height: 100%; border-radius: var(--r-xs); background: linear-gradient(90deg, var(--brand-600), var(--brand-400)); }
.ap-prog { height: 6px; background: var(--ink-100); border-radius: var(--r-xs); overflow: hidden; margin-top: 8px; }
.ap-prog i { display: block; height: 100%; background: var(--brand-600); border-radius: var(--r-xs); }

/* 成员账号设置 · 成员列表：固定列宽（table-layout:fixed + colgroup），列宽不再被浏览器
   自动布局挤压 —— 修复「所属团队被压成 2~4 行竖排字、行高参差」。列宽由 07-members-admin.js
   的 <colgroup> 逐列下发；窄视口（1280）放不下时由既有 .table-scroll 横向滚动兜底，
   任何列都不允许被压成竖排字。 */
table.acct-grid { table-layout: fixed; width: 100%; min-width: 1100px; }
/* 单元格水平内边距 12→8px（#acct-list-wrap 用 ID 选择器，须同级覆盖）：10 列合计省 80px，
   是「1440 零横向滚动 且 全列不截断」的关键空间来源；纵向 48px 行高不变，观感仍留白。 */
#acct-list-wrap table.acct-grid thead th,
#acct-list-wrap table.acct-grid tbody td { padding-left: 8px; padding-right: 8px; }
/* 禁止竖排断行：单行显示，超长省略号截断（完整内容随 title 悬停） */
table.acct-grid .nw { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; }
/* 操作列：最多 6 个按钮不折行；按钮水平内边距 6→1px（每枚省 10px）并收紧间距 */
table.acct-grid th.ops, table.acct-grid td.ops { white-space: nowrap; overflow: hidden; }
table.acct-grid td.ops .btn-link { padding-left: 1px; padding-right: 1px; margin-right: 2px; }
/* 标签（服务商/角色/状态/账号状态）水平内边距 10→7px（每枚省 6px） */
table.acct-grid .tag { padding-left: 7px; padding-right: 7px; }

/* 列表内方形等级徽章 */
.ap-grade-dot { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: var(--r-md); font-size: var(--fs-12); font-weight: 700; }

/* 工作台顶部概览卡 */
.ap-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 16px; }
.ap-summary .aps { background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--sh-sm); padding: 14px 16px; }
.ap-summary .aps .k { font-size: var(--fs-12); color: var(--text-sub); }
.ap-summary .aps .v { font-size: var(--fs-24); font-weight: 700; margin-top: 4px; line-height: 1.2; font-variant-numeric: tabular-nums; }
.ap-summary .aps .v small { font-size: var(--fs-12); font-weight: 400; color: var(--text-sub); margin-inline-start: 3px; }
.ap-summary .aps .s { font-size: var(--fs-11); color: var(--text-sub); margin-top: 4px; }
.ap-summary .aps.ok { background: var(--green-bg); border-color: color-mix(in srgb, var(--green-solid) 24%, #fff); }
.ap-summary .aps.ok .v { color: var(--green-ink); }
.ap-summary .aps.warn { background: var(--red-bg); border-color: color-mix(in srgb, var(--red-solid) 22%, #fff); }
.ap-summary .aps.warn .v { color: var(--red-ink); }

/* 考评总览：等级色块单元格 */
.ov-cell .ov-g { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: var(--r-md); font-size: var(--fs-13); font-weight: 700; transition: transform var(--t-1) var(--ease); }
.ov-cell:hover .ov-g { transform: scale(1.1); }

@media (max-width: 1080px) {
  .ap-hero { flex-wrap: wrap; gap: 14px; }
  .ap-hero .ap-divider { display: none; }
  .ap-hero .ap-side { min-width: 96px; }
}

/* ---------- 考评总览美化（V8） ---------- */
.ap-summary .aps { position: relative; overflow: hidden; padding-inline-start: 20px; }
.ap-summary .aps::before { content: ""; position: absolute; inset-inline-start: 0; top: 0; bottom: 0; width: 3px; background: var(--brand-600); opacity: .5; }
.ap-summary .aps.ok::before { background: var(--green-solid); opacity: .85; }
.ap-summary .aps.warn::before { background: var(--red-solid); opacity: .85; }
.ap-summary .aps .k { display: flex; align-items: center; gap: 6px; }

.ov-toolbar { padding: 12px 16px; }
.ov-toolbar .fb-item { min-width: 150px; }
.ov-toolbar .fb-sep { width: 1px; align-self: stretch; background: var(--border); min-width: 1px; margin: 2px 4px; }
.ov-toolbar .fb-dim { min-width: auto; }
.ov-toolbar .fb-dim .chip { padding: 8px 16px; font-size: var(--fs-13); }

.ov-matrix { max-height: calc(100vh - 320px); min-height: 220px; border: 1px solid var(--border); border-radius: var(--r-lg); overflow: auto; background: #fff; }
.ov-matrix table { border-collapse: separate; border-spacing: 0; width: 100%; min-width: 1080px; }
.ov-matrix thead th {
  position: sticky; top: 0; z-index: 2; background: #EDF3FA; color: var(--brand-800);
  font-size: var(--fs-12); font-weight: 600; padding: 10px 8px; border-bottom: 1px solid var(--border); white-space: nowrap; text-align: center;
}
.ov-matrix thead th.ov-stick { z-index: 3; text-align: left; }
.ov-matrix tbody td { padding: 5px 8px; border-bottom: 1px solid var(--ink-100); background: #fff; text-align: center; }
.ov-matrix tbody td.ov-stick { position: sticky; left: 0; z-index: 1; text-align: left; }
.ov-matrix tbody tr:hover td { background: #FAFCFF; }
.ov-matrix td.ov-avgcol { background: #F6F9FD; border-left: 1px solid var(--border); }
.ov-matrix tbody tr:hover td.ov-avgcol { background: #EDF4FC; }
.ov-matrix thead th.ov-cur, .ov-matrix tbody td.ov-cur { background: var(--brand-100); }
.ov-matrix tbody tr:hover td.ov-cur { background: #DCE9F8; }
.ov-matrix thead th.ov-cur { color: var(--brand-600); }

.ov-cell { min-height: 46px; border-radius: var(--r-md); transition: background var(--t-1) var(--ease), box-shadow var(--t-1) var(--ease); }
.ov-cell:not(.empty) { cursor: pointer; }
.ov-cell:not(.empty):hover { background: var(--brand-50); box-shadow: 0 0 0 1px color-mix(in srgb, var(--brand-500) 18%, transparent); }
.ov-cell.empty { background: #FCFDFE; }
.ov-cell .ov-g { width: 30px; height: 30px; border-radius: var(--r-md); font-size: var(--fs-14); box-shadow: var(--sh-xs); }
.ov-avgcell .ap-grade-dot { width: 30px; height: 30px; border-radius: var(--r-md); font-size: var(--fs-14); }

/* ---------- 考评总览 · 二级分表（2026-10-12 需求② 重构） ----------
   行 = 考核月份（纵向自然生长）、列 = 该二级组成员；整体不再横向滚动。 */
.ov-groups { display: flex; flex-direction: column; gap: 14px; }
.ov-group .card-head { margin-bottom: 10px; }
.ov-group .card-head h3 { font-size: var(--fs-15); }
/* 转置表：宽度随成员数自然增长（二级组内成员通常 ≤ 4），不再强制 1080px ⇒ 消灭横向滚动；
   真遇到成员很多的组时由容器内滚动兜底，th/td 仍 nowrap，任何单元格都不会被压成竖排字。 */
.ov-matrix.ov-transposed { max-height: none; min-height: 0; overflow: auto; }
.ov-matrix.ov-transposed table { min-width: 0; width: 100%; }
.ov-matrix.ov-transposed thead th:first-child,
.ov-matrix.ov-transposed tbody td:first-child { text-align: left; }
.ov-period { display: flex; align-items: center; gap: 8px; font-variant-numeric: tabular-nums; font-weight: 600; }
.ov-nowtag { font-size: var(--fs-11); font-weight: 600; color: var(--brand-600); background: var(--brand-100); border-radius: var(--r-xs); padding: 1px 6px; }
.ov-nowrow td { background: #FBFDFF; }
.ov-cell.ov-status { min-height: 40px; }
.ov-cell.ov-status .tag { white-space: nowrap; }

/* ---------- 考评总览 · 两行版（2026-10-12 布局改版：人物在左 + 月份每 6 个一组拆「表头行 + 数据行」） ----------
   渲染见 08-appraisal-flow.js · renderAppraisalOverview（结构：div.ov-matrix > table.grid.ov-2line）。
   .ov-matrix 仅本页使用，故直接在其上收敛容器行为；新结构
   （.ov-2line / .ov-mrow / .ov-drow / .ov-memcell / .ov-mh / .ov-chunkstart）样式补齐于此；
   容器与色板全部复用既有 token，不新增颜色。 */
.ov-matrix { max-height: none; min-height: 0; }
.ov-matrix table.ov-2line { min-width: 0; width: 100%; }
/* 左侧成员单元格：跨该成员整块（rowspan = chunks×2），弱底色 + 内容垂直居中 */
.ov-matrix .ov-memcell { vertical-align: middle; text-align: left; padding: 10px 12px; background: #FAFCFF; border-right: 1px solid var(--border); border-bottom: 1px solid var(--ink-100); }
.ov-matrix .ov-memcell .cell-member { align-items: flex-start; }
/* 月表头行：弱底色小字，恒居中；当月列沿用 ov-cur 高亮 */
.ov-matrix tr.ov-mrow > th.ov-mh { background: #F2F6FC; color: var(--brand-800); font-size: var(--fs-12); font-weight: 600; padding: 7px 8px; border-bottom: 1px solid var(--border); white-space: nowrap; text-align: center; }
.ov-matrix tr.ov-mrow > th.ov-mh.ov-cur { background: var(--brand-100); color: var(--brand-600); }
/* 数据行月份单元格恒居中：覆盖 .ov-matrix td:first-child / td:nth-child(2) 的靠左规则 */
.ov-matrix tbody tr.ov-drow > td { text-align: center; }
/* 第 2 组起：单元格顶部分隔线（上下半年视觉分隔） */
.ov-matrix tr.ov-chunkstart > th { border-top: 2px solid var(--brand-200); }

/* ---------- 组织架构图（纯 SVG 正交折线） ---------- */
.org-chart-card { margin-bottom: 16px; }
/* 允许横向滚动（仅在需要时出现滚动条）；SVG 随容器等比缩小，避免右侧被裁 */
.org-chart-wrap { overflow: auto; padding: 4px 10px 12px; background: #FCFDFE; border-radius: 0 0 var(--r-lg) var(--r-lg); min-width: 0; }
#orgChartInner { transform-origin: top left; transition: transform var(--t-1) var(--ease); }
.org-chart ul { display: flex; justify-content: center; padding: 14px 0 0; margin: 0; list-style: none; position: relative; }
.org-chart ul.ot-root { padding-top: 0; }
.org-chart li { display: flex; flex-direction: column; align-items: center; padding: 14px 5px 0; position: relative; }
.org-chart > ul > li { padding-top: 0; }
.org-chart li::before, .org-chart li::after { content: ""; position: absolute; top: 0; right: 50%; width: 50%; height: 14px; border-top: 2px solid var(--ink-300); }
.org-chart li::after { right: auto; left: 50%; border-left: 2px solid var(--ink-300); }
.org-chart li:only-child::before, .org-chart li:only-child::after { display: none; }
.org-chart li:only-child { padding-top: 0; }
.org-chart li:first-child::before, .org-chart li:last-child::after { border-top: 0 none; }
.org-chart li:last-child::before { border-right: 2px solid var(--ink-300); border-radius: 0 6px 0 0; }
.org-chart li:first-child::after { border-radius: 6px 0 0 0; }
.org-chart ul ul::before { content: ""; position: absolute; top: 0; left: 50%; width: 0; height: 14px; border-left: 2px solid var(--ink-300); }
.ot-box {
  display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: #fff; padding: 6px 9px; cursor: pointer; white-space: nowrap; flex: 0 0 auto;
  transition: border-color var(--t-1) var(--ease), box-shadow var(--t-1) var(--ease); box-shadow: var(--sh-xs);
}
.ot-box:hover { border-color: var(--brand-400); box-shadow: var(--sh-md); }
.ot-box.active { border-color: var(--brand-600); background: var(--brand-100); box-shadow: 0 4px 14px rgba(11, 33, 64, .14); }
.ot-box.lv1 { border-color: var(--brand-200); background: #F7FAFD; padding: 8px 12px; }
.ot-box.lv1.active { background: var(--brand-100); }
.ot-box .ot-ico { display: flex; }
.ot-box .ot-nm { font-size: var(--fs-12); font-weight: 600; color: var(--text); }
.ot-box.lv1 .ot-nm { font-size: var(--fs-13); }
.ot-box .ot-ct { font-size: 10px; color: var(--text-sub); background: var(--ink-100); border-radius: var(--r-pill); padding: 0 6px; line-height: 15px; font-variant-numeric: tabular-nums; }
.ot-box.active .ot-nm { color: var(--brand-700); }
.ot-box.active .ot-ct { background: color-mix(in srgb, var(--brand-600) 12%, transparent); color: var(--brand-700); }
.ot-tw { width: 16px; height: 16px; border: 1px solid var(--border-strong); border-radius: var(--r-xs); background: #fff; color: var(--ink-500); font-size: 9px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; }
.ot-tw:hover { border-color: var(--brand-600); color: var(--brand-600); }
.org-detail-grid { display: grid; grid-template-columns: 280px 1fr; gap: 20px; align-items: start; }
/* 关键：栅格子项允许收缩到 0，宽表交给 .table-scroll 横向滚动承载，不再把整页撑破 */
.org-detail-grid > * { min-width: 0; }
/* 列可读下限（仅本表）：table-layout:auto 下中文单元格的 min-content 只有 1 个汉字，
   列一被压缩就会「一字一行」竖排。给 72px 下限把最坏情况收成 2–3 行，
   上限取到「1440 视口下本表仍能贴合容器、不产生横向滚动」为止（已实测）。 */
.org-detail-grid table.grid tbody td { min-width: 72px; }
.org-detail-grid table.grid tbody td:nth-child(4) { min-width: 100px; } /* 「所属」= 组织路径，略宽 */

/* SVG 正交折线 */
.org-chart-wrap .ocs { display: block; width: auto; max-width: 100%; height: auto; margin: 0 auto; }
.ocs text { font-family: var(--font); }
/* 曲线连线比折线更细更淡即可（折线需要靠线宽撑住「结构感」，曲线不用）。 */
.ocs-line { fill: none; stroke: #C4D3E5; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.ocs-node { cursor: pointer; }
/* 层级差异化：一级=实心品牌色（只用在一级，面积小，所以醒目而不压抑）；
   二级=白底品牌描边；三级=浅灰底弱描边。三者一眼能分出父子关系。 */
.ocs-node rect { fill: #FFFFFF; stroke: #C6D5E8; stroke-width: 1.2; transition: stroke var(--t-1) var(--ease), fill var(--t-1) var(--ease); }
.ocs-node:hover rect { stroke: var(--brand-500); }
.ocs-node.lv1 rect { fill: var(--brand-600); stroke: var(--brand-600); }
.ocs-node.lv2 rect { fill: #FFFFFF; stroke: var(--brand-300); stroke-width: 1.4; }
.ocs-node.lv3 rect { fill: var(--ink-50); stroke: #DCE4EF; stroke-width: 1.2; }
.ocs-node.lv1 .ocs-nm { font-size: 13px; font-weight: 700; fill: #FFFFFF; }
.ocs-node.lv2 .ocs-nm { font-size: 12.5px; font-weight: 700; fill: var(--brand-800); }
.ocs-node.lv3 .ocs-nm { font-size: 12px; font-weight: 600; fill: #3A4658; }
.ocs-node .ocs-ct { font-size: 10.5px; fill: var(--ink-500); font-variant-numeric: tabular-nums; }
.ocs-node.lv1 .ocs-ct { fill: rgba(255, 255, 255, .84); }
/* 选中态只用「琥珀色描边」标记，不改填充 —— 一级节点是实心品牌色，
   若按旧写法改填充为浅蓝，白字会直接看不见。 */
.ocs-node.active rect { stroke: var(--amber-solid); stroke-width: 2.6; }
/* 0 人的组弱化：虚线框 + 灰字，把真实结构让出来 */
.ocs-node.is-empty rect { fill: #FBFCFE; stroke: #DCE4EF; stroke-dasharray: 4 3; }
.ocs-node.is-empty .ocs-nm { fill: #94A3B8; font-weight: 500; }
.ocs-node.is-empty .ocs-ct { fill: #B0BAC7; }
.ocs-node.is-empty.active rect { stroke: var(--amber-solid); }
/* 折叠按钮：收起态常显（胶囊里直接写隐藏的下级数），展开态鼠标进入组织图才浮现。
   为什么收起态必须常显：它是「这里还有东西」的唯一提示，藏起来会让用户以为组织就这么多。
   为什么展开态要隐藏：原来每个拐点都常驻一个小圆圈，是这棵树「像工程图」的最后一点。
   ⚠ 隐藏时必须同时关掉 pointer-events，否则会出现「看不见但点得到」的隐形按钮（可用性陷阱）。 */
.ocs-bt { cursor: pointer; }
.ocs-bt rect { fill: #FFFFFF; stroke: #C0CFE2; stroke-width: 1.2; transition: stroke var(--t-1) var(--ease), fill var(--t-1) var(--ease); }
.ocs-bt text { font-size: 10.5px; font-weight: 700; fill: var(--ink-500); transition: fill var(--t-1) var(--ease); }
.ocs-bt:hover rect { stroke: var(--brand-600); fill: var(--brand-50); }
.ocs-bt:hover text { fill: var(--brand-600); }
/* 收起态：常显，并用品牌色强调「下面还有内容」 */
.ocs-bt:not(.on) rect { stroke: var(--brand-300); fill: var(--brand-50); }
.ocs-bt:not(.on) text { fill: var(--brand-700); }
/* 展开态：默认透明且不接收指针事件 */
.ocs-bt.on { opacity: 0; pointer-events: none; }
/* 鼠标进入组织图 → 浮现；键盘聚焦时也必须可见（无障碍） */
.ocs:hover .ocs-bt.on { opacity: 1; pointer-events: auto; }
.ocs .ocs-bt.on:focus-visible { opacity: 1; pointer-events: auto; outline: 2px solid var(--brand-600); outline-offset: 1px; }

/* ============================================================================
   ⑦ 下拉框：收起态右侧观感 + 展开弹层（base-select）
   ----------------------------------------------------------------------------
   历史故障：① 收起态原生箭头被控件右缘挤掉；② 展开弹层缺右边与下边的框线。
   方案：① 去掉原生箭头改为内联 SVG；② appearance: base-select 让弹层可定制。
   不支持 base-select 的浏览器会忽略这两条规则、自动退回原生弹层（不会更差）。
   ============================================================================ */
.select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 36px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='8'%20viewBox='0%200%2012%208'%20fill='none'%3E%3Cpath%20d='M1%201.5L6%206.5L11%201.5'%20stroke='%2364748B'%20stroke-width='1.8'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 12px 8px;
}
.select:disabled {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='8'%20viewBox='0%200%2012%208'%20fill='none'%3E%3Cpath%20d='M1%201.5L6%206.5L11%201.5'%20stroke='%23B8C0CC'%20stroke-width='1.8'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E");
}
.select { appearance: base-select; }
/* base-select 自带 ::picker-icon 箭头；我们的箭头是 background-image，需隐藏它以免出现两个箭头 */
.select::picker-icon { display: none; }

/* 弹层本体：补齐四周完整边框（含用户反馈缺失的「右边和下边的框线」） */
.select::picker(select) {
  appearance: base-select;
  margin-top: 6px;
  padding: 6px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  background: #fff;
  box-shadow: var(--sh-lg);
  max-height: 320px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* 每个选项：内边距 + 选中 / 悬停态，避免「一行贴满、没有边界」 */
.select option { padding: 9px 12px; border-radius: var(--r-sm); font-size: var(--fs-14); line-height: 1.5; color: var(--text); background: #fff; }
.select option:hover,
.select option:focus { background: var(--brand-50); }
.select option:checked { background: var(--brand-600); color: #fff; font-weight: 600; }
/* 弹层内滚动条：细一些 */
.select::picker(select)::-webkit-scrollbar { width: 8px; }
.select::picker(select)::-webkit-scrollbar-thumb { background: var(--ink-300); border-radius: var(--r-xs); }
.select::picker(select)::-webkit-scrollbar-track { background: transparent; }

/* ============================================================================
   ⑧ 手动下发本期 · 按团队 + 成员选择弹窗
   ============================================================================ */
.dt-body { max-height: 48vh; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--r-lg); background: #FBFCFE; padding: 4px 12px 8px; }
.dt-body .empty { padding: 28px 0; }
.dt-team { display: flex; align-items: center; gap: 10px; padding: 10px 2px; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: #FBFCFE; z-index: 1; }
.dt-team input[type=checkbox] { width: 16px; height: 16px; accent-color: var(--brand-600); cursor: pointer; flex: 0 0 auto; }
.dt-team-name { font-weight: 600; font-size: var(--fs-13); color: var(--text); }
.dt-team .muted { margin-inline-start: auto; }
.dt-unfold { background: none; border: none; color: var(--brand-600); font-size: var(--fs-13); padding: 2px 6px; cursor: pointer; border-radius: var(--r-sm); }
.dt-unfold:hover { background: var(--brand-50); }
.dt-members { padding: 4px 0 10px 28px; display: flex; flex-direction: column; }
.dt-member { display: flex; align-items: center; gap: 8px; padding: 7px 8px; border-radius: var(--r-md); cursor: pointer; }
.dt-member:hover { background: #EEF3FA; }
.dt-member input[type=checkbox] { width: 16px; height: 16px; accent-color: var(--brand-600); cursor: pointer; flex: 0 0 auto; }
.dt-member-name { font-size: var(--fs-13); min-width: 76px; color: var(--text); }
.dt-member.dt-done { opacity: .55; background: var(--gray-bg); cursor: not-allowed; }
.dt-member.dt-done:hover { background: var(--gray-bg); }
.dt-member.dt-done .dt-member-name { text-decoration: line-through; }
.dt-member.dt-done input[type=checkbox] { cursor: not-allowed; }
.dt-member .tag { margin-inline-start: 2px; }

/* ============================================================================
   ⑨ 左侧导航子分组折叠（信息架构调整：绩效考核 / 组织与人员）
   ============================================================================ */
.app-side .nav-sublabel.tappable {
  cursor: pointer; border-radius: var(--r-md);
  user-select: none; -webkit-user-select: none;
  transition: background-color var(--t-1) var(--ease), color var(--t-1) var(--ease);
}
.app-side .nav-sublabel.tappable:hover { background: var(--rail-hover); color: var(--rail-ink-strong); }
.app-side .nav-sublabel.tappable:focus { outline: none; }
.app-side .nav-sublabel.tappable:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.app-side .nav-sublabel .nav-sub-txt { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-side .nav-sublabel .nav-sub-arrow { display: flex; align-items: center; color: inherit; transition: transform var(--t-2) var(--ease); }
.app-side .nav-sublabel.collapsed .nav-sub-arrow { transform: rotate(-90deg); }
.app-side .nav-sublabel.collapsed { color: #94A3B8; }

/* ============================================================================
   ⑩ 全局 UI 溢出 / 窄屏退化防护（保持既有行为不变）
   ----------------------------------------------------------------------------
   本质：宽表 table-layout:auto 的列没有下限，窄视口下列会被压到 min-content
   （中文一字一行）。正确做法是「给列可读下限 + 交给滚动容器承载」。
   ============================================================================ */
/* 表格内文本输入框可读下限（由 .table-scroll 横向滚动承载） */
table.grid .input[type="text"] { min-width: 180px; }
/* 成员账号表左右内边距收紧，抵消姓名/岗位单行带来的宽度增量 */
#acct-list-wrap table.grid thead th,
#acct-list-wrap table.grid tbody td { padding-left: 12px; padding-right: 12px; }
/* 考评总览矩阵表头首列补 left:0，修正横滚时与表体首列的错位 */
.ov-matrix thead th.ov-stick { left: 0; }

/* ============================================================================
   ⑪ 响应式
   ============================================================================ */
@media (max-width: 1080px) {
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
  .approve-grid { grid-template-columns: 1fr; }
  .policy-layout { grid-template-columns: 1fr; }
  .policy-tree { position: static; max-height: none; }
  .form-grid { grid-template-columns: 1fr; }
  .form-grid .span2, .form-grid .span3 { grid-column: span 1; }
  .policy-cards, .balance-grid { grid-template-columns: 1fr; }
  .org-detail-grid { grid-template-columns: 1fr; }
  .quick-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 860px) {
  :root { --side-w: 200px; }
  .app-main { padding: 16px; }
  .quick-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ============================================================================
   ⑫ 动效降级（尊重系统「减少动态效果」设置）
   ============================================================================ */
/* ---- 无障碍（Apple 要求：系统设置优先，动效不得成为负担）----
   1) 减弱动效：保留位移归零、只留极短淡入，避免眩晕；
   2) 降低透明度：毛玻璃在低视力/低性能设备上会降低可读性 → 退回不透明底色；
   3) 增强对比度：材质边框加重，保证仍能分辨层级。 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  /* 过冲类缓动在减弱动效下退化为线性，避免出现「晃一下」 */
  :root { --spring-soft: linear; --spring-snappy: linear; --spring-bounce: linear; }
  .btn:active:not(:disabled), .tappable:active, .nav-item:active { transform: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .modal-mask { background: rgba(11, 25, 45, .72); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  .modal, .drawer, .toast { border: 1px solid var(--ink-900); }
  .modal-mask { background: rgba(11, 25, 45, .66); }
}

/* ============================================================================
   ⑨ 交互升级 · 流体交互（Apple Fluid Interfaces）
   ----------------------------------------------------------------------------
   原则：即时响应 / 连续运动 / 可被打断 / 尊重系统偏好。
   本节只做「跨全站的交互反馈」，不动任何布局，因此不改变页面尺寸。
   ============================================================================ */

/* ---- 按压反馈：苹果要求「按下即响应」，故时长极短、位移极小（3%） ----
   为什么要 :active 而不是 :hover —— 悬停是「鼠标在哪」，按下才是「要执行了」。
   只缩 3% 是刻意的：超过 5% 在大表格里会让人误以为行在动。 */
.btn:active:not(:disabled),
.tappable:active,
.nav-item:active,
.nav-sublabel.tappable:active,
.page-link:active { transform: scale(.97); transition-duration: 90ms; }
.btn:disabled { transform: none; }

/* ---- 焦点可视化：键盘焦点给「双环」（内白外品牌），保证在深色领航轨上也看得见 ---- */
:focus-visible { outline: 2px solid var(--brand-600); outline-offset: 2px; }
.app-side :focus-visible { outline-color: var(--brand-600); }

/* ---- 数字对齐：表格数字用等宽数字，避免逐行宽度跳动（读数场景的硬需求） ---- */
table td, table th, .cell-num { font-variant-numeric: tabular-nums; }

/* ---- 光学排版：大字号收字距、小字号放字距（体积越大越要收，否则显得松散） ---- */
h1, .page-title { letter-spacing: -.012em; }
h2, h3, .modal h3 { letter-spacing: -.006em; }
.hint, .f12, small { letter-spacing: .004em; }

/* ---- 滚动边界：容器内滚到底不把滚动传染给背后页面（对应苹果的边界阻力） ---- */
.app-main, .drawer-body, .modal { overscroll-behavior: contain; }

/* ============================================================
   附件缩略图 + 图片放大灯箱（feat-attach-fe 追加）
   ------------------------------------------------------------
   为什么要这三条：
     1) .attach-thumb-btn/.attach-thumb-img —— 缩略图必须由 CSS 固定尺寸并 object-fit: cover，
        否则原图会按自身像素撑破卡片、把「审批意见/按钮」挤出视口（用户要求「不影响界面使用」）；
        loading="lazy" 由 HTML 侧加，确保一进页面不把全部原图拉下来。
     2) .attach-lightbox 复用既有 .modal-mask 遮罩（fixed 定位、材质模糊、入场 transition），
        只把它从「居中卡片」改成「居中大图舞台」，因此不需要任何第三方库 / CDN；
        遮罩仍渲染在 .app-main 内部 —— 绝不给祖先加 transform/filter（否则会改变 fixed 包含块、遮罩错位）。
     3) 灯箱由 state 驱动、随页面整体重绘，renderLayout 会给「重绘前已存在」的遮罩补 .no-enter，
        故切换上一张 / 下一张不会重放入场动画、不闪屏（与既有弹层同一套机制）。
   ============================================================ */
.attach-thumb-btn { width: 56px; height: 56px; padding: 0; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--brand-50); cursor: zoom-in; overflow: hidden; flex: 0 0 auto; display: block; }
.attach-thumb-btn:hover { border-color: var(--brand-400); }
.attach-thumb-img { width: 100%; height: 100%; object-fit: cover; display: block; }

.attach-lightbox { padding: 32px; }
.attach-lb-stage { position: relative; max-width: min(1100px, 92vw); max-height: 90vh;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; }
.attach-lb-img { max-width: 100%; max-height: calc(90vh - 56px); object-fit: contain;
  border-radius: var(--r-md); background: #fff; box-shadow: 0 10px 40px rgba(0, 0, 0, .45); }
.attach-lb-cap { color: #fff; font-size: var(--fs-13); text-align: center;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6); overflow-wrap: anywhere; }
.attach-lb-btn { position: absolute; display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border: none; border-radius: 50%; cursor: pointer;
  background: rgba(11, 25, 45, .55); color: #fff; transition: background var(--t-1) var(--ease); }
.attach-lb-btn:hover { background: rgba(11, 25, 45, .82); }
.attach-lb-close { top: -8px; right: -8px; }
.attach-lb-prev, .attach-lb-next { top: 50%; transform: translateY(-50%); }
.attach-lb-prev { left: -8px; }
.attach-lb-next { right: -8px; }
@media (max-width: 720px) {
  .attach-lb-prev { left: 4px; }
  .attach-lb-next { right: 4px; }
  .attach-lb-close { top: 4px; right: 4px; }
}

/* ============================================================================
   快捷模板条（加班 / 出差 / 调休 申请页「原因」输入框上方）
   ----------------------------------------------------------------------------
   · 复用既有 .chip 胶囊样式（含 .chip.on / .chip .n），此处只做「模板条」容器
     与两个附加胶囊（存为我的模板 / 删除 ×）的轻微样式补充；
   · 颜色一律取自设计令牌（--brand-* / --red-* / --ink-* / --border-*），不硬编新色值。
   ============================================================================ */
.tpl-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 8px; }
.tpl-bar .tpl-label { font-size: var(--fs-12); color: var(--text-sub); margin-right: 2px; }
.tpl-bar .chip { padding: 5px 12px; font-size: var(--fs-12); }
.tpl-bar .chip-add { border-style: dashed; border-color: var(--border-strong); background: #fff; color: var(--brand-600); }
.tpl-bar .chip-add:hover { border-color: var(--brand-400); background: var(--brand-50); }
.tpl-bar .chip-x { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; margin-left: 4px; border-radius: 50%; font-size: var(--fs-12); line-height: 1; color: var(--ink-400); }
.tpl-bar .chip-x:hover { color: var(--red-solid); background: var(--red-bg); }

/* === 头像（batch10） === */
/* 只作用于「有头像」的 .avat（不修改既有 .avat 规则本身）：img 绝对定位覆盖在姓名圆之上，
   素材缺失（404）时由 onerror 隐藏 img，下层姓名圆自然露出 —— 不出现碎图。 */
.avat.avat-has-img { position: relative; overflow: hidden; }
.avat .avat-img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
/* 成员编辑表单的「成员头像」区：左预览 + 右操作（上传 / 九宫格 / 清除） */
.av-editor { display: flex; align-items: flex-start; gap: 20px; flex-wrap: wrap; }
.av-editor .av-preview { flex: 0 0 auto; text-align: center; }
.av-editor .av-pv-box { margin: 0 auto 6px; line-height: 0; }
.av-editor .av-ctl { flex: 1 1 320px; min-width: 0; }
.av-editor .av-grid { display: grid; grid-template-columns: repeat(9, 44px); gap: 8px; }
.av-editor .av-pick { background: none; border: 2px solid transparent; border-radius: 50%; padding: 2px; line-height: 0; cursor: pointer; transition: border-color var(--t-1) var(--ease); }
.av-editor .av-pick:hover { border-color: var(--brand-300); }
.av-editor .av-pick.on { border-color: var(--brand-600); box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand-500) 22%, transparent); }
/* 窄屏兜底（batch20 追加修正）：9 列九宫格宽 = 9×44 + 8×8 = 460px；实测「成员表单」在
   761–960px 视口区间内 .av-ctl 可用宽 < 460px ⇒ 页面横向溢出（940px 起 1px，800px 达 93px）。
   原断点只覆盖 ≤760px，中间这一段（含用户环境常见的 900px）没被兜住。
   把它抬到 960px（仍为 5 列 = 5×44+4×8 = 252px，到 ~620px 视口都放得下），
   只改这一个断点值，不动本段其它任何规则。 */
@media (max-width: 960px) { .av-editor .av-grid { grid-template-columns: repeat(5, 44px); } }

/* ============================================================================
   [UI-REDESIGN batch12] 前端设计规范落地 · 「珍珠玻璃」观感与丝滑度（2026-10-12）
   ----------------------------------------------------------------------------
   落地策略（硬约束，见任务说明）：
     · 纯 CSS「令牌重映射 + 追加式样式层」，**只追加、不改也不删任何既有规则**；
     · 本段整体位于文件末尾「两行版 .ov-*」段与「头像（batch10）」段**之后**，
       不触碰上述两段任何一行；
     · 不新增 / 不重命名任何既有 class；不依赖任何第三方库 / CDN / 字体；
     · 过渡只动 transform / opacity / background-color / box-shadow；不做常驻帧动画。
   分段：A 令牌重映射　B 材质与组件　C 动效　D 响应式补充
   ============================================================================ */

/* ---------------------------------------------------------------------------
   A. 令牌重映射（:root 覆盖；同选择器后来者胜 → 既有 var() 引用自动生效）
   ---------------------------------------------------------------------------
   语义色（规范锚点）：
     · 蓝  #236de9 = 选择与主操作   · 青柠 #58a021 = 正常状态   · 红 #e0443b = 危险操作
   圆角：规范表给 8/12/16/20/24，但 §2.3 明确 m-surface 用 --r-lg(16px)；
        二者取其一 → 以 16 为锚，整体软化一档但控件不过度圆润（企业观感）。
   尺寸：新增 --row-h / --cell-px / --control-h / --control-h-sm（既有规则若更紧凑不强制）。
   动效：统一 --ease-out 与 --dur-fast/base/slow，全站新段引用变量。
   --------------------------------------------------------------------------- */
:root {
  /* —— 主操作蓝（#236de9 体系）—— */
  --brand-600: #236de9;
  --brand-500: #3f82ee;
  --brand-400: #6ea3f4;
  --brand-300: #a6c8f9;
  --brand-200: #cddffc;
  --brand-100: #e6f0fd;
  --brand-50:  #f2f8fe;
  --brand-700: #1a57c4;
  --brand-800: #17479e;
  --brand-900: #133a80;
  --brand: var(--brand-600);
  --brand-hover: #1a57c4;
  --brand-dark: #17479e;
  --brand-soft: var(--brand-100);
  /* 信号色与主色保持一致（原两者同值，改主色需同步，否则浅色侧栏出现两种蓝） */
  --accent: #236de9;
  --accent-soft: rgba(35, 109, 233, .12);
  --accent-ink: #1c56c0;

  /* —— 正常状态青柠（#58a021 体系）—— */
  --green-solid: #58a021;
  --green-ink: #3f7316;
  --green-bg: #eef6e0;
  --green: var(--green-solid);

  /* —— 危险红（#e0443b 体系）—— */
  --red-solid: #e0443b;
  --red-ink: #b23327;
  --red-bg: #fdecea;
  --red: var(--red-solid);

  /* —— 圆角软化（6/9/12/16/20）—— */
  --r-xs: 6px; --r-sm: 9px; --r-md: 12px; --r-lg: 16px; --r-xl: 20px;
  --radius-card: var(--r-lg);
  --radius-btn: var(--r-md);
  --radius-tag: var(--r-sm);

  /* —— 阴影三档：e1 阅读面 / e2 高亮块 / e3 浮层；统一「接触 + 环境」双层柔和 —— */
  --sh-xs: 0 1px 2px rgba(16, 32, 56, .05);
  --sh-sm: 0 1px 2px rgba(16, 32, 56, .06), 0 2px 6px rgba(16, 32, 56, .05);
  --sh-md: 0 2px 6px rgba(16, 32, 56, .06), 0 10px 24px rgba(16, 32, 56, .09);
  --sh-lg: 0 4px 12px rgba(16, 32, 56, .08), 0 18px 44px rgba(11, 33, 64, .12);
  --sh-pop: 0 6px 16px rgba(11, 33, 64, .14), 0 24px 56px rgba(11, 33, 64, .16);
  --shadow-card: var(--sh-sm);
  --shadow-pop: var(--sh-lg);

  /* —— 表格 / 控件尺寸 —— */
  --row-h: 48px;
  --cell-px: 16px;
  --control-h: 36px;
  --control-h-sm: 30px;

  /* —— 动效：统一缓动与时长 —— */
  --ease-out: cubic-bezier(.16, .84, .44, 1);
  --dur-fast: 120ms;
  --dur-base: 180ms;
  --dur-slow: 260ms;

  /* —— 浮层玻璃（带不支持时的实色回落）—— */
  --glass-solid: #FBFCFE;
}

/* ---------------------------------------------------------------------------
   B. 材质与组件观感（落到既有 class；必要时用更高特异性覆盖）
   --------------------------------------------------------------------------- */

/* B1 · 阅读面 m-surface：近乎实色 + 细 1px 边 + e1/e2 阴影 */
.card,
.stat,
.balance-card,
.policy-tree,
.policy-main,
.form-actions,
.dt-body { box-shadow: var(--sh-sm); }
.card { border-radius: var(--r-lg); }
.table-scroll { box-shadow: var(--sh-xs); }
/* 卡片头分隔线随新边色微调，读起来更轻 */
.card-head { border-bottom-color: var(--border); }

/* B2 · 浮层 m-float：更高层级 e3 阴影（玻璃只留给遮罩，绝不降低可读性） */
.modal { box-shadow: var(--sh-pop); }
.drawer { box-shadow: -1px 0 0 var(--border), -20px 0 56px rgba(11, 33, 64, .20); }
.modal-mask { backdrop-filter: blur(14px) saturate(120%); -webkit-backdrop-filter: blur(14px) saturate(120%); }
.select::picker(select) { box-shadow: var(--sh-pop); border-color: var(--border-strong); }

/* B3 · 按钮：悬停轻浮 + 按压回落（只动 transform / box-shadow） */
.btn { border-radius: var(--radius-btn); }
.btn:hover:not(:disabled) { transform: translateY(-1px); }
.btn-primary:hover:not(:disabled) { box-shadow: 0 2px 6px color-mix(in srgb, var(--brand-700) 30%, transparent), 0 6px 16px color-mix(in srgb, var(--brand-700) 22%, transparent), inset 0 1px 0 rgba(255, 255, 255, .16); }
.btn-primary:active:not(:disabled) { box-shadow: inset 0 2px 6px rgba(11, 33, 64, .22); }
.chip { transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out); }
.chip:hover { transform: translateY(-1px); }
.chip:active { transform: translateY(0) scale(.98); }
.pager .pg { transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out); }
.pager .pg:hover { transform: translateY(-1px); }

/* B4 · 输入与下拉：统一控件高 + 焦点环（--ring 随主色自动更新） */
/* 垂直居中（batch20 修）：原生 <select>（appearance: base-select → 实为 inline-flex）在
   去掉上下内距、只给固定 height 后，内容盒(34px) > 行盒(line-height 1.6→22.4px)，行盒被顶到
   内容盒顶部 → **文字整体偏上**（实测偏上 5.5–7px；input 因浏览器对单行文本自带垂直居中而不偏）。
   统一令 line-height 等于内容盒高（控件高 − 上下边框 2px）：行盒填满内容盒 → 文字垂直居中。
   注：`.textarea` 不在此列（多行文本必须保留 1.6 行高）。 */
.input,
.select { height: var(--control-h); padding-block: 0; line-height: calc(var(--control-h) - 2px); }
/* 登录卡片输入框为 48px（既有规则 .login-card .input），把内容高令牌就地提到 48 使行高同步居中 */
.login-card .input { --control-h: 48px; }
/* 保留 .select 既有 36px 右内距（箭头位），仅收敛上下内距 */
.select { padding-right: 36px; }
.btn-sm { min-height: var(--control-h-sm); }
/* 聚焦时标签同步高亮已由 .field:has(...) 提供，这里补一档更强的焦点外圈 */
.input:focus,
.select:focus,
.textarea:focus { box-shadow: var(--ring); }

/* B5 · 表格：表头弱化 + 整行悬停 + 操作列吸附右侧（横向滚动时始终可见） */
table.grid thead th { background: #F7F9FC; color: var(--ink-500); font-weight: 600; font-size: var(--fs-12); letter-spacing: .2px; }
table.grid tbody tr:hover { background: color-mix(in srgb, var(--brand-500) 7%, #fff); }
/* 操作列吸附：仅在横向滚动的容器内生效，避免非滚动表误吸到视口右侧 */
.table-scroll table.grid thead th.ops,
#acct-list-wrap table.grid thead th.ops { position: sticky; right: 0; z-index: 3; background: #F7F9FC; }
.table-scroll table.grid tbody td.ops,
#acct-list-wrap table.grid tbody td.ops { position: sticky; right: 0; z-index: 2; background: var(--card-bg); }
.table-scroll table.grid tbody tr:hover td.ops,
#acct-list-wrap table.grid tbody tr:hover td.ops { background: color-mix(in srgb, var(--brand-500) 7%, #fff); }
/* 吸附列左侧一条极细分隔线，滚动时与其余列形成明确分界 */
.table-scroll table.grid thead th.ops,
.table-scroll table.grid tbody td.ops,
#acct-list-wrap table.grid thead th.ops,
#acct-list-wrap table.grid tbody td.ops { box-shadow: inset 1px 0 0 var(--border); }

/* B6 · 标签 / 徽章：统一圆角内距，语义色成组（颜色随令牌自动更新） */
.tag { padding: 2px 10px; line-height: 1.6; }

/* B7 · 分页：弱化、靠右、当前页强调（既有基础已满足，这里统一圆角与悬停） */
.pager .pg { border-radius: var(--r-sm); }

/* B8 · 页头与面包屑的留白节奏（不动结构，只保证间隙不被压小） */
.page-head { gap: 16px; }
.card-head { gap: 12px; }

/* ---------------------------------------------------------------------------
   C. 动效（丝滑度的主体）
   ---------------------------------------------------------------------------
   四类能量语态（简化可实现版）：
     1) 按压反馈：.btn / .chip / .pg 的 :active（见 B3）
     2) 页面切换：内容区纯 opacity 淡入（180ms，无位移）（.page.page-enter，见下方 keyframes）
     3) 浮层进场：弹窗 / 抽屉 / toast（复用既有 @starting-style，toast 改从下方浮入）
     4) 行入场：列表首屏前 12 行纯 opacity 级联（.page.page-enter tbody tr）
   说明：① 纯 CSS 无法区分「真实换页」与「同页重绘」（本项目 innerHTML 整体替换），
         故 .page-enter 由 JS 在**路由变化时**挂类；类不存在时本段全部为惰性规则（无副作用）。
         ② 性能红线：只动 transform / opacity；级联限前 12 行；尊重 reduced-motion。
   --------------------------------------------------------------------------- */
@keyframes ui-page-rise { from { opacity: 0; } to { opacity: 1; } }
@keyframes ui-row-rise  { from { opacity: 0; } to { opacity: 1; } }

/* 页面切换：纯 opacity 淡入，180ms（不做位移 —— 避免动画期间改变元素位置而影响既有位置断言） */
.page.page-enter { animation: ui-page-rise var(--dur-base) var(--ease-out) both; }
/* 列表首屏级联：仅前 12 行，步进 45ms（避免长列表卡顿与观感拖沓） */
.page.page-enter tbody tr:nth-child(-n+12) { animation: ui-row-rise var(--dur-base) var(--ease-out) both; }
.page.page-enter tbody tr:nth-child(1)  { animation-delay: 0ms; }
.page.page-enter tbody tr:nth-child(2)  { animation-delay: 45ms; }
.page.page-enter tbody tr:nth-child(3)  { animation-delay: 90ms; }
.page.page-enter tbody tr:nth-child(4)  { animation-delay: 135ms; }
.page.page-enter tbody tr:nth-child(5)  { animation-delay: 180ms; }
.page.page-enter tbody tr:nth-child(6)  { animation-delay: 225ms; }
.page.page-enter tbody tr:nth-child(7)  { animation-delay: 270ms; }
.page.page-enter tbody tr:nth-child(8)  { animation-delay: 315ms; }
.page.page-enter tbody tr:nth-child(9)  { animation-delay: 360ms; }
.page.page-enter tbody tr:nth-child(10) { animation-delay: 405ms; }
.page.page-enter tbody tr:nth-child(11) { animation-delay: 450ms; }
.page.page-enter tbody tr:nth-child(12) { animation-delay: 495ms; }

/* 浮层进场增强：toast 改「从下方浮入」（原为从上）——覆盖既有 @starting-style 的终态起点 */
@starting-style { .toast { opacity: 0; transform: translateY(12px) scale(.96); } }

/* ---------------------------------------------------------------------------
   D. 响应式补充（窄屏：可换行、主操作可达、容器内横滚、页面不横溢）
   --------------------------------------------------------------------------- */
.page,
.app-main { max-width: 100%; }
img { max-width: 100%; }

@media (max-width: 900px) {
  .app-main { padding: 14px; }
  .page-head { flex-wrap: wrap; align-items: flex-start; }
  .page-head h1 { font-size: var(--fs-18); }
  .card { padding: 16px 16px; }
  .card.tight { padding: 14px 14px; }
  .form-actions { flex-wrap: wrap; }
  .pager { flex-wrap: wrap; row-gap: 8px; }
  .search-box { max-width: 100%; }
  /* 表格一律在自身容器内横向滚动，页面整体绝不横向溢出 */
  .table-scroll { max-width: 100%; }
}

/* ---------------------------------------------------------------------------
   E. 动效降级兜底（追加在既有 reduced-motion 段之后，补 hover transform 与吸附层）
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .btn:hover:not(:disabled),
  .chip:hover,
  .pager .pg:hover { transform: none; }
  .page.page-enter,
  .page.page-enter tbody tr { animation: none; }
}

/* === 考评总览（batch13） === */
/* 筛选栏：角色下拉限宽（选项短，原宽偏大；沿用 batch13） */
.ov-toolbar .fb-role { min-width: 0; }
.ov-toolbar .fb-role select { max-width: 148px; }
/* 空组（二线团队下的 服务器团队 / 网络团队 暂无成员）：空态区留白，弱化但不缺席 */
.card.ov-group-empty .ov-empty { padding: 4px 2px 8px; }
/* v4：空组用 compact emptyBox（emptyBox 默认 52px 大留白会让空组喧宾夺主）——
      只压内距与图标，不改 emptyBox 文案与语义（仍复用同一口径），空组只占一行高度。 */
.card.ov-group-empty .ov-empty .empty { padding: 14px 12px; }
.card.ov-group-empty .ov-empty .empty .ic { margin-bottom: 4px; }
.card.ov-group-empty .ov-empty .empty .ic svg { width: 20px; height: 20px; }

/* ---------------------------------------------------------------------------
   v4 · 成员时间轴 · 节点读数（2026-10-12 推倒重做；用户连否 v1/v2/v3 后的正解）
   ---------------------------------------------------------------------------
   设计：人 = 视觉主体；月份 = 一条刻度轴（有考核 = 节点，无考核 = 极淡点，**不再出现成片「—」**）。
   布局：每组 = 组标题 + 刻度轴表头 + 每成员一行；行与轴共用同一列模板
         （身份列 + N×1fr + 读数列）⇒ 严格对齐；不用 table（避开 rowspan 两行版的坑）。
   配色：一律复用既有令牌与 .grade-* 等级配色，不新增色值。
   --------------------------------------------------------------------------- */
.ov-timeline { --ov-idw: 168px; --ov-readw: 176px; display: flex; flex-direction: column; overflow-x: auto; }
.ov-axis, .ov-row { display: grid; align-items: center; min-width: 700px; }

/* b. 刻度轴表头（月份小字、弱色；当月高亮并标「当月」） */
.ov-axis { padding-bottom: 4px; border-bottom: 1px solid var(--border); margin-bottom: 2px; }
.ov-axis .ov-ax-role { font-size: var(--fs-11); color: var(--text-sub); padding-left: 4px; white-space: nowrap; }
.ov-axis .ov-ax-cell { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; padding: 2px 0 4px; min-width: 0; }
.ov-axis .ov-ax-lbl { font-size: var(--fs-12); color: var(--text-sub); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ov-axis .ov-ax-cell.ov-cur { background: var(--brand-50); border-radius: var(--r-xs); }
.ov-axis .ov-ax-cell.ov-cur .ov-ax-lbl { color: var(--brand-600); font-weight: 700; }
.ov-nowtag { font-size: var(--fs-11); line-height: 1; font-weight: 600; color: var(--brand-600); background: var(--brand-100); border-radius: var(--r-xs); padding: 1px 5px; white-space: nowrap; }

/* c. 成员行（身份列单行：头像 28px + 姓名 + 一行「岗位 · 班组」） */
.ov-row { min-height: 54px; border-bottom: 1px solid var(--ink-100); }
.ov-row:last-child { border-bottom: 0; }
.ov-row:hover { background: #FAFCFF; }
.ov-row .ov-id { padding: 6px 8px 6px 4px; min-width: 0; }
.ov-row .ov-id .cell-member { align-items: center; gap: 8px; }
.ov-row .ov-id .cell-member > div { min-width: 0; }
.ov-row .ov-id .cn { font-size: var(--fs-13); font-weight: 600; color: var(--ink-800); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ov-row .ov-id .ci { font-size: var(--fs-11); color: var(--text-sub); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ov-row .ov-cellnode { display: flex; align-items: center; justify-content: center; min-width: 0; }
.ov-row .ov-cellnode.ov-cur { background: var(--brand-50); }

/* 右侧读数（弱色小字，一行，与身份列基线对齐） */
.ov-row .ov-read { display: flex; align-items: center; justify-content: flex-end; gap: 5px; padding-right: 4px; font-size: var(--fs-11); color: var(--text-sub); white-space: nowrap; overflow: hidden; }
.ov-read .ov-read-k { color: var(--text-sub); }
.ov-read .ov-read-sep { color: var(--ink-300); }
.ov-read .ov-read-g { display: inline-flex; align-items: center; justify-content: center; min-width: 17px; height: 17px; border-radius: var(--r-xs); font-size: var(--fs-11); font-weight: 700; }
.ov-read .ov-read-none { font-size: var(--fs-11); color: var(--ink-300); }

/* d. 节点（形状 + 颜色双重区分；可点击的节点由 08 下发 onclick 进该期详情） */
.ov-node { display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px; border-radius: 50%; box-sizing: border-box; transition: transform var(--t-1) var(--ease); }
.ov-node[role="button"] { cursor: pointer; }
.ov-node[role="button"]:hover { transform: scale(1.22); }
/* 未下发 / 无任务：极淡小点（视觉静默；不输出「—」文本） */
.ov-node-none { width: 5px; height: 5px; background: var(--ink-200); }
/* 组长考评中：空心圆（2px 蓝描边 + 白底） */
.ov-node-lead { border: 2px solid var(--brand-600); background: #fff; }
/* 项目经理审核中：虚线描边圆（与上一档区分） */
.ov-node-pm { border: 2px dashed var(--brand-600); background: #fff; }
/* PMO审核中：实心圆（蓝） */
.ov-node-pmo { background: var(--brand-600); border: 2px solid var(--brand-600); }
/* 已退回：实心圆（红） */
.ov-node-back { background: var(--red); border: 2px solid var(--red); }
/* 考核完成：实心圆 + 等级色（底色由 08 用 gradeColorOf 内联下发 → 配色沿用既有口径） */
.ov-node-done { width: 22px; height: 22px; font-size: var(--fs-11); font-weight: 700; color: #fff; box-shadow: var(--sh-xs); }

/* e. 状态图例（页面级，复用节点样式；配色复用既有 grade-* / 令牌） */
.ov-legend { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 16px; margin: -2px 2px 12px; font-size: var(--fs-12); color: var(--text-sub); }
.ov-legend .ov-lg-t { font-weight: 600; color: var(--text); }
.ov-legend .ov-lg { display: inline-flex; align-items: center; gap: 5px; }
.ov-legend .ov-lg .ov-node { cursor: default; }

/* f. 极窄屏兜底：整块横向滚动（绝不把文字压成竖排） */
@media (max-width: 1180px) {
  .ov-timeline { --ov-idw: 146px; --ov-readw: 150px; }
  .ov-axis, .ov-row { min-width: 720px; }
}

/* === 我的账号（batch14） === */
/* 顶栏用户区＝「我的账号」入口：可点暗示（手型光标 + 悬停底纹 + 键盘焦点环）。
   只影响带 .is-link 的 user-chip（其它 .user-chip 用法不受影响），且不改变既有内边距
   （用 margin 抵消，避免顶栏高度抖动）。 */
.user-chip.is-link { cursor: pointer; border-radius: var(--r-md); margin-block: -4px; padding-block: 4px; transition: background var(--t-1) var(--ease); }
.user-chip.is-link:hover { background: var(--brand-50); }
.user-chip.is-link:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 2px; }
/* 只读字段（我的账号 / 只读信息）：弱化底色，与可编辑输入框形成对比，一眼可辨「能不能改」 */
.roview { background: var(--ink-50); }

/* === 考评总览 · 均分审核（batch17） === */
/* 读数区内容变为「项目周期平均分 A（165） · 均分审核」，比原先更长 ⇒ 仅加宽读数列；
   不改 v4 的刻度轴 / 节点 / 图例结构与样式，只覆盖一个宽度变量 + 新增本批两个元素的样式。 */
.ov-timeline { --ov-readw: 244px; }
.ov-read .ov-conf-btn { font-size: var(--fs-11); color: var(--brand-600); padding: 0 2px; line-height: 1.2; }
.ov-read .ov-conf-btn:hover { text-decoration: underline; }
/* PM 只读态：入口灰显但仍可悬停看提示（title="仅 PMO 可审核"） */
.ov-read .ov-conf-dis { font-size: var(--fs-11); color: var(--ink-300); cursor: not-allowed; }
.ov-read .ov-conf-ok { font-size: var(--fs-11); padding: 0 6px; line-height: 16px; }
/* 弹层内的提示与禁用按钮：复用既有 .form-hint / .btn[disabled]，此处只保证禁用观感一致 */
.modal .btn-primary[disabled] { opacity: .5; cursor: not-allowed; }


/* === 站点页脚 · ICP 备案号（batch19） === */
/* 克制弱化：小一档字号 + 弱色 + 居中；不抢视线、不遮挡内容。
   使用既有 token（--fs-11 / --text-sub / --brand-600），不新造颜色体系。
   两处使用：主界面内容区底部（.site-icp）与登录页卡片底部（.site-icp-login 缩小上边距）。 */
.site-icp { margin-top: 18px; text-align: center; font-size: var(--fs-11); line-height: var(--lh-body); color: var(--text-sub); }
.site-icp .site-icp-link { color: var(--text-sub); text-decoration: none; }
.site-icp .site-icp-link:hover { color: var(--brand-600); text-decoration: underline; }
.site-icp.site-icp-login { margin-top: 14px; }
/* 窄屏：允许换行、不产生横向溢出 */
@media (max-width: 640px) { .site-icp { font-size: var(--fs-11); padding: 0 8px; word-break: break-word; } }
