/* ============================================
   PMO 项目管理系统 - 样式系统
   清爽简约风格
   ============================================ */

/* ---------- 基础变量 ---------- */
:root {
  --primary: #4f6bed;
  --primary-light: #6c83f2;
  --primary-dark: #3a56d4;
  --primary-bg: #eef2ff;
  --primary-bg-hover: #e0e7ff;

  --success: #10b981;
  --success-bg: #ecfdf5;
  --warning: #f59e0b;
  --warning-bg: #fffbeb;
  --danger: #ef4444;
  --danger-bg: #fef2f2;
  --info: #3b82f6;
  --info-bg: #eff6ff;

  --gray-50: #f9fafb;
  --gray-100: #f3f4f6;
  --gray-200: #e5e7eb;
  --gray-300: #d1d5db;
  --gray-400: #9ca3af;
  --gray-500: #6b7280;
  --gray-600: #4b5563;
  --gray-700: #374151;
  --gray-800: #1f2937;
  --gray-900: #111827;

  --bg: #f5f6f8;
  --card-bg: #ffffff;
  --text: #1f2937;
  --text-secondary: #6b7280;
  --text-tertiary: #9ca3af;
  --border: #e8eaed;
  --border-light: #f0f1f3;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;
  --radius-xl: 20px;

  --shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.06);
  --shadow-lg: 0 10px 30px rgba(0,0,0,0.08);
  --shadow-xl: 0 20px 50px rgba(0,0,0,0.12);

  --sidebar-w: 240px;
  --sidebar-collapsed-w: 64px;
  --topbar-h: 60px;

  --font: 'Segoe UI', system-ui, -apple-system, 'PingFang SC', 'Microsoft YaHei', sans-serif;
  --mono: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;

  /* ---------- v222 设计 token：字号 / 间距 / 动效 ----------
     全站美化统一引用，微交互（hover 抬升、tab 过渡）一律走这里的时长与曲线 */
  --font-xs: 11px;
  --font-sm: 12px;
  --font-md: 13px;
  --font-base: 14px;
  --font-lg: 16px;
  --font-xl: 20px;
  --font-num: 24px;   /* 统计卡数值 */

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;

  --dur-fast: 120ms;
  --dur: 200ms;
  --dur-slow: 320ms;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* 统计卡 / 列表卡 hover 抬升 */
  --shadow-hover: 0 8px 24px rgba(31, 41, 55, 0.10);
  --shadow-hover-md: 0 12px 32px rgba(31, 41, 55, 0.14);
  --lift: translateY(-2px);
  --lift-md: translateY(-3px);
}

/* ---------- v117: 深色主题变量 ----------
   html[data-theme='dark'] 时整体覆盖。
   设计原则：灰色阶梯反转让 bg/文本语义自动互换（低阶=表面色，高阶=文字色） */
html[data-theme='dark'] {
  --primary: #6c83f2;
  --primary-light: #8598f5;
  --primary-dark: #4f6bed;
  --primary-bg: #232c47;
  --primary-bg-hover: #2b3556;

  --success: #34d399;
  --success-bg: #12352a;
  --warning: #fbbf24;
  --warning-bg: #3a2e11;
  --danger: #f87171;
  --danger-bg: #3b1d1d;
  --info: #60a5fa;
  --info-bg: #17263f;

  --gray-50: #1c222e;
  --gray-100: #232a38;
  --gray-200: #2d3545;
  --gray-300: #3c4658;
  --gray-400: #5b6579;
  --gray-500: #828d9f;
  --gray-600: #9aa4b5;
  --gray-700: #b6bfc9;
  --gray-800: #d5dae2;
  --gray-900: #eceff4;

  --bg: #12161f;
  --card-bg: #1a1f2a;
  --text: #d5dae2;
  --text-secondary: #8b95a7;
  --text-tertiary: #626d80;
  --border: #2b3342;
  --border-light: #232a38;

  --shadow-xs: 0 1px 2px rgba(0,0,0,0.35);
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.4), 0 1px 2px rgba(0,0,0,0.3);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.4);
  --shadow-lg: 0 10px 30px rgba(0,0,0,0.5);
  --shadow-xl: 0 20px 50px rgba(0,0,0,0.6);
}

/* ---------- Reset ---------- */
* { margin: 0; padding: 0; box-sizing: border-box; }
*::before, *::after { box-sizing: border-box; }

/* v72: 多浏览器/移动端基础兼容 */
html { font-size: 15px; } /* v342: 14→15，整体字阶上推 */
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent; /* v72: 去除移动端点击蓝色高亮 */
  -webkit-text-size-adjust: 100%;           /* v72: 禁止 iOS 横屏自动放大文字 */
  text-size-adjust: 100%;
  overflow: hidden;
}

a { text-decoration: none; color: inherit; }
button { font-family: inherit; cursor: pointer; border: none; background: none; }
input, textarea, select { font-family: inherit; outline: none; }
ul, ol { list-style: none; }
img { max-width: 100%; display: block; }

/* ---------- 滚动条 ---------- */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--gray-300); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--gray-400); }

/* ============================================
   布局
   ============================================ */
/* v74: 满屏背景轮播 (海边/天空/草地) */
.login-bg-slideshow {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%;
  z-index: 0; /* 在 pane-left/right 之下 */
  overflow: hidden;
  background: #0f172a; /* fallback */
}
.login-bg-slide {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%;
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  /* 每张图轮流淡入 (默认全部隐藏，由 nth-child 控制不同时机显示) */
  opacity: 0;
  /* Ken Burns 缓慢推近 */
  transform: scale(1.0);
  transition: none;
  /* fade 时长 */
  -webkit-animation: loginBgFade 24s infinite ease-in-out;
          animation: loginBgFade 24s infinite ease-in-out;
  will-change: opacity, transform;
}
/* v177: 图片 URL 由 applyLoginBg() 统一注入（?t=mtime 精确缓存失效），
   CSS 不再写死 ?v= 引用——否则浏览器会把同一张图下载两遍（CSS 一次 + JS 一次） */
.login-bg-slide-1 {
  -webkit-animation-delay: 0s;
          animation-delay: 0s;
}
.login-bg-slide-2 {
  -webkit-animation-delay: 8s;
          animation-delay: 8s;
}
.login-bg-slide-3 {
  -webkit-animation-delay: 16s;
          animation-delay: 16s;
}
/* 关键帧：每张图 24s 周期里只显示 ~8s（占 1/3）+ 2s 淡入淡出交叉 */
@-webkit-keyframes loginBgFade {
  0%   { opacity: 0; transform: scale(1.0); }
  4%   { opacity: 1; }
  33%  { opacity: 1; transform: scale(1.08); }  /* Ken Burns 推近 */
  37%  { opacity: 0; }
  100% { opacity: 0; transform: scale(1.0); }
}
@keyframes loginBgFade {
  0%   { opacity: 0; transform: scale(1.0); }
  4%   { opacity: 1; }
  33%  { opacity: 1; transform: scale(1.08); }
  37%  { opacity: 0; }
  100% { opacity: 0; transform: scale(1.0); }
}
/* 全屏深色渐变遮罩：保证左侧品牌白字 + 右侧表单可读 */
.login-bg-overlay {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%;
  z-index: 1;
  background:
    linear-gradient(90deg, rgba(15,23,42,0.85) 0%, rgba(15,23,42,0.55) 38%, rgba(15,23,42,0.25) 65%, rgba(15,23,42,0.10) 100%);
  pointer-events: none;
}

/* v74: 左品牌/右表单 提到轮播层之上 */
.login-screen .login-pane-left,
.login-screen .login-pane-right {
  position: relative;
  z-index: 2;
}
.login-screen {
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
  /* fallback 旧浏览器不支持 dvh */
  height: 100vh; height: 100dvh;
  display: flex; flex-direction: row;
  background: #ffffff;
  z-index: 9999;
  overflow: hidden;
}
/* 左侧：品牌区（v77: 去掉实色背景，透出满屏轮播图，靠遮罩保证可读） */
.login-pane-left {
  flex: 0 0 42%; /* 桌面左 42% */
  background: transparent; /* v77: 原为 #0f172a 实色挡住背景 */
  color: #cbd5e1;
  display: flex; flex-direction: column; justify-content: space-between;
  padding: 56px 48px;
  position: relative;
}
.login-brand {
  display: flex; flex-direction: column;
  color: #ffffff;
}
.login-brand-mark {
  color: #ffffff; /* 内填色跟随 currentColor */
  margin-bottom: 32px;
}
/* v197: 后台上传的自定义登录页 LOGO（替换默认 SVG 图形位；限高等比缩放，透明底 PNG 最佳） */
.login-brand-logo {
  display: block;
  height: 64px; width: auto; max-width: 260px;
  object-fit: contain; object-position: left center;
  margin-bottom: 22px;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.25)); /* 深色背景上浅色 LOGO 可辨识 */
}
.login-brand-name {
  font-size: 42px; font-weight: 200; letter-spacing: 6px;
  line-height: 1; color: #ffffff;
  margin-bottom: 12px;
}
.login-brand-tagline {
  font-size: 13px; letter-spacing: 2px;
  color: #64748b; font-weight: 400;
  text-transform: uppercase;
}
.login-brand-quote {
  padding-left: 18px;
  border-left: 2px solid #334155;
  max-width: 360px;
}
.quote-line { display: none; } /* 兼容老节点 */
.login-brand-quote p {
  font-size: 15px; line-height: 1.75; color: #94a3b8;
  font-weight: 300; letter-spacing: 0.5px;
  margin: 0;
}
.login-copyright {
  font-size: 11px; color: rgba(255, 255, 255, 0.55); /* v77: 亮背景上灰色不可见 → 半透白 */
  letter-spacing: 1px;
}
/* v194: 登录页 ICP 备案信息（后台可编辑，未配置时整个不渲染）
   v195: 移至视口底部居中——fixed 于 loginScreen 内，登录后随视图整体隐藏 */
.login-icp {
  position: fixed; bottom: 14px; left: 0; right: 0;
  text-align: center; z-index: 10;
  font-size: 11px; color: rgba(255, 255, 255, 0.5);
  letter-spacing: 0.5px; line-height: 1.6;
}
.login-icp a {
  color: rgba(255, 255, 255, 0.6); text-decoration: none;
  border-bottom: 1px dotted rgba(255, 255, 255, 0.35);
}
.login-icp a:hover { color: rgba(255, 255, 255, 0.85); }
/* 右侧：背景图透出区 + 居中表单 */
.login-pane-right {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent;  /* v74: 透出背景轮播图 */
  padding: 40px 32px;
}
.login-card {
  width: 100%; max-width: 380px;
  text-align: left;
  /* v74: 毛玻璃卡片（兼容 fallback） */
  background: rgba(255, 255, 255, 0.72);  /* fallback */
  background: rgba(255, 255, 255, 0.55);  /* 实色（不支持 backdrop-filter 时用） */
  -webkit-backdrop-filter: blur(16px) saturate(140%);
          backdrop-filter: blur(16px) saturate(140%);
  box-shadow: 0 12px 40px rgba(15, 23, 42, 0.18);
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.5);
  padding: 36px 32px;
}
.login-title {
  font-size: 26px; font-weight: 600;
  color: #0f172a; /* 严谨主色 */
  letter-spacing: 0.5px;
  margin: 0 0 6px;
}
.login-subtitle {
  font-size: 13px; color: #64748b;
  margin: 0 0 36px;
}
.login-field { margin-bottom: 22px; }
.login-label {
  display: block; font-size: 12px; font-weight: 600;
  color: #475569; margin-bottom: 8px;
  letter-spacing: 0.5px;
}
.login-input {
  width: 100%; padding: 11px 14px;
  border: 1px solid #cbd5e1;
  background: #ffffff;
  border-radius: 4px;
  font-size: 14px; color: #0f172a;
  outline: none; transition: border-color .15s, box-shadow .15s;
  box-sizing: border-box;
  font-family: inherit;
}
.login-input:hover { border-color: #94a3b8; }
.login-input:focus {
  border-color: #0f172a;
  box-shadow: 0 0 0 3px rgba(15, 23, 42, 0.08);
}
.login-input::placeholder { color: #94a3b8; }
/* v382: 登录页密码框「按住查看」按钮——右侧 44×44 透明按钮，眼睛图标按下切换 text/松开还原 password
   wrap relative 输入框加右 padding 让位，按钮 absolute 右侧 4px，hover 浅蓝底 + active 浅蓝点 + 鼠标按下时 input 仍保持聚焦不丢 */
.login-pass-wrap { position: relative; }
.login-pass-input { padding-right: 44px; }  /* 给右侧眼睛按钮让位 */
.login-pass-toggle {
  position: absolute;
  top: 50%;
  right: 4px;
  width: 40px;
  height: 40px;
  margin-top: -20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  color: #94a3b8;
  outline: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .15s, color .15s;
}
.login-pass-toggle:hover { background: rgba(15, 23, 42, 0.05); color: #475569; }
.login-pass-toggle:active { background: rgba(15, 23, 42, 0.10); }
.login-pass-toggle .lpt-eye,
.login-pass-toggle .lpt-eye-off { display: block; pointer-events: none; }
/* 默认显示眼睛(图密码),按住时切为「斜线眼」提示密码可见 */
.login-pass-toggle .lpt-eye-off { display: none; }
.login-pass-toggle.is-showing .lpt-eye { display: none; }
.login-pass-toggle.is-showing .lpt-eye-off { display: block; }
.login-pass-toggle.is-showing { color: #0f172a; background: rgba(15, 23, 42, 0.08); }
/* v330: PC 端「记住密码」复选框——与品牌色一致，浮在按钮上方 */
.login-remember-wrap {
  display: flex;
  align-items: center;
  margin: -8px 0 12px;
  user-select: none;
}
.login-remember-label {
  display: flex;
  align-items: center;
  cursor: pointer;
  font-size: 13px;
  color: #475569;
  line-height: 1.4;
}
.login-remember-cb {
  margin-right: 6px;
  width: 14px;
  height: 14px;
  cursor: pointer;
  accent-color: #0f172a;
}
.login-remember-cb:focus { outline: 2px solid rgba(15, 23, 42, 0.2); outline-offset: 2px; }
.login-error {
  background: #fef2f2; color: #b91c1c; font-size: 13px;
  padding: 9px 12px; border-radius: 4px; margin-bottom: 18px;
  border-left: 3px solid #b91c1c;
}
.login-btn {
  width: 100%; padding: 12px 16px;
  border: 1px solid #0f172a;
  background: #0f172a; color: #ffffff;
  border-radius: 4px;
  font-size: 14px; font-weight: 600;
  letter-spacing: 2px;
  cursor: pointer;
  transition: background .15s, transform .08s;
  margin-top: 8px;
}
.login-btn:hover { background: #1e293b; }
.login-btn:active { transform: translateY(1px); }
.login-btn:disabled { background: #94a3b8; border-color: #94a3b8; cursor: not-allowed; }

.app-layout {
  display: flex;
  height: 100vh;
  height: 100dvh; /* v72: iOS Safari 动态视口，旧浏览器回退 100vh */
  overflow: hidden;
}

/* v72: 移动端侧边栏抽屉遮罩（≤768px 生效） */
.sidebar-backdrop {
  position: fixed;
  top: 0; left: 0;
  width: 100%; height: 100%;
  background: rgba(0,0,0,0.4);
  opacity: 0;
  visibility: hidden;
  transition: all 0.25s;
  z-index: 150; /* sidebar z-index 200 之下 */
}
.app-layout.sidebar-mobile-open .sidebar-backdrop { opacity: 1; visibility: visible; }

/* ---------- 侧边栏 ---------- */
.sidebar {
  width: var(--sidebar-w);
  background: var(--card-bg);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  transition: width 0.25s ease;
  z-index: 100;
}
.app-layout.sidebar-collapsed .sidebar { width: var(--sidebar-collapsed-w); }

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--topbar-h);
  padding: 0 16px;
  border-bottom: 1px solid var(--border-light);
  flex-shrink: 0;
}

.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  overflow: hidden;
}
.logo svg { flex-shrink: 0; }
.logo-text {
  font-size: 16px;
  font-weight: 700;
  color: var(--gray-800);
  white-space: nowrap;
  transition: opacity 0.2s;
}
.app-layout.sidebar-collapsed .logo-text { opacity: 0; width: 0; }

.sidebar-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  color: var(--gray-500);
  transition: all 0.15s;
  flex-shrink: 0;
}
.sidebar-toggle:hover { background: var(--gray-100); color: var(--gray-700); }
.app-layout.sidebar-collapsed .sidebar-toggle { transform: rotate(180deg); }

.sidebar-nav {
  flex: 1;
  overflow-y: auto;
  padding: 12px 10px;
}

.nav-group { margin-bottom: 20px; }
.nav-group-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0 12px 10px;
  white-space: nowrap;
  transition: opacity 0.2s;
}
.app-layout.sidebar-collapsed .nav-group-label { opacity: 0; height: 0; padding: 0; }

.nav-item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  color: var(--gray-600);
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s;
  white-space: nowrap;
  position: relative;
}
.nav-item svg { width: 19px; height: 19px; }
.nav-item span { letter-spacing: .2px; }
/* v185: 主导航 hover 再加深——实色主色填充 + 白字 + 右移（v183 淡底仍不够明显；与 active（淡底+左主色条+600字重）拉开差异） */
.nav-item:not(.active):hover { background: var(--primary); color: #fff; transform: translateX(3px); box-shadow: 0 4px 12px rgba(79,107,237,.35); }
.nav-item:not(.active):hover svg { color: #fff; }
.nav-item.active {
  background: var(--primary-bg);
  color: var(--primary);
  font-weight: 600;
}
.nav-item.active::before {
  content: '';
  position: absolute;
  left: -10px;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 20px;
  background: var(--primary);
  border-radius: 2px;
}
.nav-item svg { flex-shrink: 0; }
.app-layout.sidebar-collapsed .nav-item { justify-content: center; padding: 10px; }
.app-layout.sidebar-collapsed .nav-item span { opacity: 0; width: 0; overflow: hidden; }
.app-layout.sidebar-collapsed .nav-item.active::before { display: none; }

/* v289: 「合作伙伴」待同步数据全局角标——红橙渐变数字醒目提示（app.js updatePartnerSyncBadge 刷新）
   JS 内联 display:none 控制显隐；此块只管定位与外观。放到 nav-item 文本之后 margin-left:auto 靠右。 */
.nav-item .nav-badge {
  margin-left: auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background-image: linear-gradient(135deg, #ff6a3d, #f43f5e);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  box-sizing: border-box;
  flex-shrink: 0;
  box-shadow: 0 2px 6px rgba(244, 63, 94, .35);
}
/* v289: 侧栏折叠态——文本隐藏但角标缩为右上角小圆点，保证任意状态可见提醒 */
.app-layout.sidebar-collapsed .nav-item .nav-badge {
  position: absolute;
  right: 5px;
  top: 5px;
  min-width: 8px;
  width: 8px;
  height: 8px;
  padding: 0;
  border-radius: 50%;
  font-size: 0;
  line-height: 8px;
  opacity: 1;
  overflow: visible;
  box-shadow: none;
}

.sidebar-footer {
  padding: 12px;
  border-top: 1px solid var(--border-light);
  flex-shrink: 0;
}
.app-layout.sidebar-collapsed .sidebar-footer { padding: 12px 8px; }

.user-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  border-radius: var(--radius-sm);
  transition: background 0.15s;
  cursor: pointer;
}
.user-card:hover { background: var(--gray-100); }

.user-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
}
.user-avatar.sm { width: 28px; height: 28px; font-size: 11px; }
.user-avatar.xs { width: 24px; height: 24px; font-size: 10px; }
.user-avatar.green { background: var(--success); }
.user-avatar.orange { background: var(--warning); }
.user-avatar.purple { background: #8b5cf6; }
.user-avatar.cyan { background: #06b6d4; }
.user-avatar.pink { background: #ec4899; }

.user-info { overflow: hidden; }
.user-name { font-size: 13px; font-weight: 600; color: var(--gray-800); white-space: nowrap; }
.user-role { font-size: 11px; color: var(--text-tertiary); white-space: nowrap; }
.app-layout.sidebar-collapsed .user-info { display: none; }
.app-layout.sidebar-collapsed .btn-exit { display: none; }

/* v452: 退出按钮升级——更明显 + 动态美观（hover 渐变实底/上浮/箭头微移，按压回弹，焦点环，减弱动效降级） */
.btn-exit {
  margin-left: auto;
  border: 1.5px solid rgba(220,38,38,.35);
  background: var(--danger-bg);
  color: var(--danger);
  cursor: pointer;
  padding: 7px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-shadow: 0 1px 3px rgba(220,38,38,.14);
  transition: transform .18s ease, box-shadow .18s ease, background .18s ease, color .18s ease, border-color .18s ease;
}
.btn-exit svg { transition: transform .18s ease; }
.btn-exit:hover {
  background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
  color: #fff;
  border-color: transparent;
  transform: translateY(-1px);
  box-shadow: 0 6px 14px rgba(220,38,38,.38);
}
.btn-exit:hover svg { transform: translateX(2px); }
.btn-exit:active {
  transform: translateY(0) scale(.94);
  box-shadow: 0 2px 6px rgba(220,38,38,.28);
}
.btn-exit:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(220,38,38,.35);
}
@media (prefers-reduced-motion: reduce) {
  .btn-exit, .btn-exit svg { transition: none; }
  .btn-exit:hover, .btn-exit:hover svg { transform: none; }
}

/* ---------- 主区域 ---------- */
.main-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

/* ---------- 顶栏 ---------- */
.topbar {
  height: var(--topbar-h);
  background: var(--card-bg);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  flex-shrink: 0;
}

.topbar-left { display: flex; align-items: center; gap: 12px; }
.page-title { font-size: 18px; font-weight: 700; color: var(--gray-800); }

/* v72: 移动端汉堡按钮（仅 ≤768px 显示，打开侧边栏抽屉） */
.mobile-menu-btn {
  display: none; /* 桌面隐藏 */
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  margin-left: -6px;
  border-radius: var(--radius-sm);
  color: var(--gray-600);
  cursor: pointer;
}
.mobile-menu-btn:active { background: var(--gray-100); }

.topbar-right { display: flex; align-items: center; gap: 12px; }

.search-box {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  width: 240px;
  height: 36px;
  background: var(--gray-50);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: all 0.15s;
}
.search-box:focus-within { border-color: var(--primary); background: var(--card-bg); box-shadow: 0 0 0 3px var(--primary-bg); }
.search-box svg { color: var(--gray-400); flex-shrink: 0; }
.search-box input { border: none; background: none; font-size: 13px; flex: 1; min-width: 0; }

.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  color: var(--gray-500);
  transition: all 0.15s;
  position: relative;
}
.icon-btn:hover { background: var(--gray-100); color: var(--gray-700); }

.badge-dot {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 7px;
  height: 7px;
  background: var(--danger);
  border-radius: 50%;
  border: 1.5px solid var(--card-bg);
}

.topbar-divider { width: 1px; height: 24px; background: var(--border); }

/* v112: 在线指示呼吸绿点（心跳驱动的实时在线状态） */
.online-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: #10b981; flex: 0 0 auto;
  animation: onlinePulse 2s ease-out infinite;
}
@keyframes onlinePulse {
  0%   { box-shadow: 0 0 0 0 rgba(16, 185, 129, .45); }
  70%  { box-shadow: 0 0 0 5px rgba(16, 185, 129, 0); }
  100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}

.topbar-user { display: flex; align-items: center; gap: 8px; cursor: pointer; padding: 5px 10px; border-radius: var(--radius-sm); transition: background 0.15s; }
.topbar-user:hover { background: var(--gray-100); }
.topbar-username { font-size: 13px; font-weight: 500; color: var(--gray-700); }

/* v102: 个人设置弹窗 - 头像颜色选择圆点 */
.pf-colors { display: flex; gap: 10px; padding: 4px 0; }
.pf-color {
  width: 26px; height: 26px; border-radius: 50%;
  display: inline-block; cursor: pointer;
  border: 2px solid transparent; box-shadow: inset 0 0 0 2px var(--card-bg);
  transition: transform 0.15s, border-color 0.15s;
}
.pf-color:hover { transform: scale(1.15); }
.pf-color.sel { border-color: var(--gray-800); transform: scale(1.15); }
.pf-color[data-v="primary"] { background: var(--primary); }
.pf-color[data-v="green"] { background: var(--success); }
.pf-color[data-v="orange"] { background: var(--warning); }
.pf-color[data-v="purple"] { background: #8b5cf6; }
.pf-color[data-v="cyan"] { background: #06b6d4; }
.pf-color[data-v="pink"] { background: #ec4899; }

/* ---------- 内容区 ---------- */
.content {
  flex: 1;
  overflow-y: auto;
  padding: 24px;
}

.page-enter { animation: pageEnter 0.25s ease; }
@keyframes pageEnter {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ============================================
   通用组件
   ============================================ */

/* ---------- 按钮 ---------- */
/* v379: 按钮基线升级 —— 大气庄重：统一高度 34px / 圆角 8px / 字间距 0.3px / 阴影 + hover translateY */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 34px;
  padding: 0 16px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.3px;
  border-radius: 8px;
  transition: all 0.18s ease;
  white-space: nowrap;
  border: 1px solid transparent;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.btn:active { transform: translateY(0) !important; box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06) !important; }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(79, 107, 237, 0.18), 0 1px 2px rgba(15, 23, 42, 0.04); }
.btn svg { width: 14px; height: 14px; flex-shrink: 0; }

/* v379: 主按钮 —— 蓝渐变 + 字重 600 + 厚重阴影 */
.btn-primary {
  background: linear-gradient(135deg, #4f6bed 0%, #5b7bef 100%);
  color: #fff;
  font-weight: 600;
  border-color: transparent;
  box-shadow: 0 2px 8px rgba(79, 107, 237, 0.30), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}
.btn-primary:hover {
  background: linear-gradient(135deg, #3e5cdb 0%, #4a6adb 100%);
  box-shadow: 0 6px 16px rgba(79, 107, 237, 0.38), inset 0 1px 0 rgba(255, 255, 255, 0.18);
  transform: translateY(-1px);
}

/* v379: 次按钮（白底蓝边）—— 庄重质感：浅蓝边 + hover 浅蓝底 + 阴影加深 */
.btn-secondary {
  background: #fff;
  border-color: #d6deff;
  color: var(--gray-700);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.btn-secondary:hover {
  background: #f0f4ff;
  border-color: #4f6bed;
  color: #3e5cdb;
  box-shadow: 0 3px 8px rgba(79, 107, 237, 0.16);
  transform: translateY(-1px);
}

/* v379: 成功按钮 —— 绿渐变 + 阴影 */
.btn-success {
  background: linear-gradient(135deg, #16a34a 0%, #22c55e 100%);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(22, 163, 74, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}
.btn-success:hover {
  background: linear-gradient(135deg, #15803d 0%, #16a34a 100%);
  box-shadow: 0 6px 16px rgba(22, 163, 74, 0.36);
  transform: translateY(-1px);
}

/* v379: 危险按钮 —— 红渐变 + 阴影 */
.btn-danger {
  background: linear-gradient(135deg, #dc2626 0%, #ef4444 100%);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(220, 38, 38, 0.30), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}
.btn-danger:hover {
  background: linear-gradient(135deg, #b91c1c 0%, #dc2626 100%);
  box-shadow: 0 6px 16px rgba(220, 38, 38, 0.38);
  transform: translateY(-1px);
}

/* v379: 警告按钮（新增） —— 橙渐变 + 阴影 —— 注销申请等用 */
.btn-warning {
  background: linear-gradient(135deg, #d97706 0%, #f59e0b 100%);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(217, 119, 6, 0.30), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}
.btn-warning:hover {
  background: linear-gradient(135deg, #b45309 0%, #d97706 100%);
  box-shadow: 0 6px 16px rgba(217, 119, 6, 0.38);
  transform: translateY(-1px);
}

/* v379: 普通按钮（ghost）—— 透明背景 + 灰文字 + hover 浅灰底 + 蓝文字 */
.btn-ghost {
  height: 34px;
  padding: 0 12px;
  background: transparent;
  border-color: transparent;
  color: var(--gray-600);
  box-shadow: none;
}
.btn-ghost:hover {
  background: var(--gray-100);
  color: var(--primary);
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.06);
}
.btn-ghost.btn-danger-ghost { color: var(--gray-600); }
.btn-ghost.btn-danger-ghost:hover { background: rgba(220, 38, 38, 0.08); color: var(--danger); }

/* v379: 小尺寸 —— 高度 28px / 字号 12px（卡头次要操作、表行操作） */
.btn-sm {
  height: 28px;
  padding: 0 12px;
  font-size: 12px;
  border-radius: 6px;
}

/* v110: "+ 新建XX" 主操作按钮 — 整站一致的圆润蓝胶囊（v379 同步升级：高度 36px / 圆角 10px / 字重 600） */
.btn-new {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 36px;
  padding: 0 20px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.3px;
  border-radius: 10px;
  background: linear-gradient(135deg, #4f6bed 0%, #5b7bef 100%);
  color: #fff;
  border: 1px solid transparent;
  transition: all 0.18s ease;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 3px 10px rgba(79, 107, 237, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}
.btn-new:hover {
  background: linear-gradient(135deg, #3e5cdb 0%, #4a6adb 100%);
  transform: translateY(-1px);
  box-shadow: 0 8px 20px rgba(79, 107, 237, 0.40), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.btn-new:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(79, 107, 237, 0.32);
}
.btn-new:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(79, 107, 237, 0.22), 0 3px 10px rgba(79, 107, 237, 0.32);
}
.btn-new svg { width: 14px; height: 14px; }

/* v379: 大尺寸 —— 高度 40px / 字号 14px / 字重 600（页面级主操作） */
.btn-lg {
  height: 40px;
  padding: 0 22px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 10px;
}

.btn-icon { padding: 0; width: 34px; height: 34px; }
.btn-icon.btn-sm { width: 28px; height: 28px; }
.btn-block { width: 100%; }

/* ---------- 卡片 ---------- */
.card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border-light);
}
.card-title { font-size: 14px; font-weight: 600; color: var(--gray-800); }
.card-body { padding: 20px; }
.card-body.flush {
  padding: 0;
  overflow-x: auto;                    /* v72: 宽表格手机横向滚动 */
  -webkit-overflow-scrolling: touch;   /* v72: 旧 iOS 惯性滚动 */
}

/* ---------- 徽章 ---------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 20px;
  white-space: nowrap;
}
.badge-primary { background: var(--primary-bg); color: var(--primary); }
.badge-success { background: var(--success-bg); color: var(--success); }
.badge-warning { background: var(--warning-bg); color: #d97706; }
.badge-danger { background: var(--danger-bg); color: var(--danger); }
.badge-info { background: var(--info-bg); color: var(--info); }
.badge-gray { background: var(--gray-100); color: var(--gray-500); }
.badge-purple { background: #f3e8ff; color: #7c3aed; }
/* v443: 「项目专属成员」独立权限档位徽标色（青） */
.badge-cyan { background: #cffafe; color: #0e7490; }
.badge-dot-status { padding-left: 18px; position: relative; }
.badge-dot-status::before {
  content: '';
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

/* ---------- 进度条 ---------- */
.progress {
  height: 6px;
  background: var(--gray-100);
  border-radius: 3px;
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  background: var(--primary);
  border-radius: 3px;
  transition: width 0.4s ease;
}
.progress-bar.success { background: var(--success); }
.progress-bar.warning { background: var(--warning); }
.progress-bar.danger { background: var(--danger); }

/* ---------- 表格 ---------- */
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.table th {
  text-align: left;
  padding: 12px 16px;
  font-weight: 600;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
  background: var(--gray-50);
  white-space: nowrap;
}
.table td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-light);
  color: var(--gray-700);
  vertical-align: middle;
}
.table tr:last-child td { border-bottom: none; }

/* v78: 宽表格操作列 sticky（表格加 .ops 类，横滚时操作按钮不被滚走） */
.table.ops th:last-child,
.table.ops td:last-child {
  white-space: nowrap;
}
@media (max-width: 768px) {
  .table.ops th:last-child,
  .table.ops td:last-child {
    position: -webkit-sticky;
    position: sticky;
    right: 0;
    background: var(--card-bg);         /* 遮住底下滚过的内容 */
    box-shadow: -6px 0 8px -6px rgba(15, 23, 42, 0.18);  /* 左缘阴影提示可滚 */
    border-left: 1px solid var(--border-light);
  }
  .table.ops th:last-child { background: var(--gray-50); }
  /* 斑马纹/悬停行 sticky 单元格背景跟随 */
  .table.ops tbody tr:hover td:last-child { background: var(--gray-100); }
  .data-table.ops tbody tr:hover td:last-child { background: var(--primary-bg, #eef2ff); }
}
.table tbody tr { transition: background 0.1s; }
.table tbody tr:hover { background: var(--gray-50); }

/* ---------- 表单 ---------- */
.form-group { margin-bottom: 18px; }  /* v383: 16→18, 大气庄重 */
.form-label {
  display: block;
  font-size: 13px;
  font-weight: 600;  /* v383: 500→600 与 v381 庄重基线一致 */
  color: var(--gray-700);
  margin-bottom: 8px;  /* v383: 6→8, 与 v381 表单 token 对齐 */
  letter-spacing: 0.2px;
}
.form-label .required { color: var(--danger); font-weight: 700; margin-left: 2px; }
/* v468: 必填校验失败时的字段红边闪烁（配合 reqFlash） */
@keyframes pmReqFlash { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.55); } 100% { box-shadow: 0 0 0 6px rgba(239,68,68,0); } }
.input-req-err, .input-req-err:focus { border-color: var(--danger) !important; animation: pmReqFlash 0.8s ease-out 2; }

/* v469: 「关联甘特活动」被锁定（本任务已是别条任务关联的甘特活动）——视觉置灰 + 禁止误改 */
.form-group.field-locked .form-select:disabled {
  background: var(--gray-50, #f7f8fa);
  color: var(--gray-500, #6b7280);
  cursor: not-allowed;
  opacity: 1;
  border-color: var(--border);
}
.form-group.field-locked .form-label { color: var(--gray-500, #6b7280); }
.form-input, .form-select, .form-textarea {
  width: 100%;
  padding: 10px 12px;  /* v383: 9→10 */
  font-size: 14px;  /* v383: 13→14, 与 .btn 一致 */
  border: 1px solid #cbd5e1;  /* v383: 更明显 */
  border-radius: 6px;  /* v383: var(--radius-sm) 偏小,6px 与 .btn 圆角一致 */
  background: var(--card-bg);
  color: var(--text);
  transition: all 0.15s;
}
.form-input:hover, .form-select:hover, .form-textarea:hover { border-color: #94a3b8; }
.form-input:focus, .form-select:focus, .form-textarea:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(79, 107, 237, 0.10);
}
.form-textarea { resize: vertical; min-height: 80px; }
.form-row { display: flex; gap: 14px; }
.form-row .form-group { flex: 1; }
.form-hint { font-size: 11px; color: var(--text-tertiary); }

/* ---------- v472 新建/编辑项目表单：直观便捷 ----------
   一行说明取代两行长文；分组标题给出层次；编码自动生成可一键换；
   日期默认今天 + 工期实时反馈；必填提示贴在提交按钮旁 */
/* 顶部说明条：中性风格、单行、低干扰（原为浅红长文，观感像警告且占首屏） */
.pf-tip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 6px 10px; margin-bottom: 12px;
  border: 1px solid var(--border-light); border-radius: 8px;
  background: var(--gray-50);
  font-size: 11.5px; line-height: 1.45; color: var(--text-secondary);
}
.pf-tip a { color: var(--primary); font-weight: 600; text-decoration: none; }
.pf-tip a:hover { text-decoration: underline; }
.pf-tip-sep { color: var(--gray-300, #cbd5e1); }
/* 分组标题：小字 + 右侧填充细线，给出层次但不增加重感 */
.pf-sec {
  display: flex; align-items: center; gap: 8px;
  margin: 4px 0 12px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.4px;
  color: var(--text-secondary);
}
.pf-sec::after { content: ''; flex: 1; height: 1px; background: var(--border-light); }
/* 编码输入框：右侧内嵌「↻ 重新生成」 */
.pf-code-wrap { position: relative; display: flex; align-items: center; }
.pf-code-wrap .form-input { padding-right: 34px; }
.pf-regen {
  position: absolute; right: 5px;
  width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 6px; background: transparent;
  color: var(--text-tertiary); font-size: 14px; line-height: 1; cursor: pointer; transition: all 0.15s;
}
.pf-regen:hover { background: var(--gray-100); color: var(--primary); }
.pf-regen:active { transform: rotate(-180deg); }
/* 「自动生成」小徽标：用户手改后自动隐藏（oninput 处理） */
.pf-auto-tag {
  display: inline-block; margin-left: 6px; padding: 1px 6px;
  border-radius: 4px; background: rgba(79, 107, 237, 0.10);
  color: var(--primary); font-size: 10px; font-weight: 600; letter-spacing: 0;
  vertical-align: 1px;
}
/* 编码重新生成后的高亮反馈 */
@keyframes pfCodeFlash { 0% { background: rgba(79, 107, 237, 0.16); } 100% { background: var(--card-bg); } }
.pf-code-flash { animation: pfCodeFlash 0.7s ease-out 1; }
/* 工期提示行（结束日期下方）：正常灰色小字，倒挂为红色 */
.pf-dur { margin-top: 5px; font-size: 11px; line-height: 1.5; color: var(--text-tertiary); min-height: 17px; }
.pf-dur a { color: var(--primary); font-weight: 600; text-decoration: none; }
.pf-dur a:hover { text-decoration: underline; }
.pf-dur-err { color: var(--danger); font-weight: 600; }
/* 底部必填提示：靠左，与右侧按钮分离 */
.pf-req-hint { margin-right: auto; font-size: 12px; color: var(--text-tertiary); }
.pf-req-hint .required { color: var(--danger); font-weight: 700; margin: 0 1px; }
.pf-req-hint b { color: var(--danger); font-weight: 700; margin: 0 2px; }
.pf-req-hint.pf-req-ok { color: var(--success, #16a34a); }
/* 项目描述框单独降高（不动全局 .form-textarea）——压缩弹窗总高，减少滚动 */
.pf-desc { min-height: 66px; }

/* ---------- v426 财务经办人：固定为登录账号本人（只读展示条） ----------
   替代原选人输入框：整站 6 个财务单据表单统一「姓名 + 本人徽标」只读样式 */
.fin-handler-lock {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 8px 12px;
  background: var(--gray-50);
  border: 1px dashed #cbd5e1;
  border-radius: var(--radius-sm);
  cursor: default;
}
.fin-handler-lock .fin-handler-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-700);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fin-handler-lock .fin-handler-badge {
  margin-left: auto;
  flex: none;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 600;
  color: var(--primary-dark);
  background: var(--primary-bg);
  border: 1px solid #d7dfff;
  border-radius: 10px;
}
.fin-handler-lock .fin-handler-badge.is-other {
  color: #92400e;
  background: var(--warning-bg);
  border-color: #fde68a;
}
.fin-handler-lock .user-avatar.xs { flex: none; }
.fin-handler-lock + .form-hint { margin-top: 4px; }

/* ---------- v97 采购管理：表单分段 + 详情网格 ---------- */
.form-section { padding: 16px 18px; background: var(--card-bg); border-radius: 8px; border: 1px solid #d0d5db; box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04); }  /* v383: radius-sm→8 + 边框加深 + 轻阴影 */
.form-section + .form-section { margin-top: 14px; }
.form-section-title { font-size: 13px; font-weight: 700; color: var(--gray-800); margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid #e2e5ea; letter-spacing: 0.3px; }
.detail-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
.detail-cell { padding: 8px 0; }
.detail-label { font-size: 11px; color: var(--text-tertiary); margin-bottom: 2px; text-transform: uppercase; letter-spacing: 0.3px; }
.detail-value { font-size: 13px; color: var(--gray-800); font-weight: 500; }
@media (max-width: 768px) {
  .detail-grid { grid-template-columns: 1fr 1fr; gap: 8px; }
}

/* ---------- 模态框 ---------- */
.modal-overlay {
  position: fixed;
  top: 0; left: 0;
  width: 100%; height: 100%;
  background: rgba(0,0,0,0.3);
  opacity: 0;
  visibility: hidden;
  /* ★ v500: 收起态必须显式断开指针命中。
     缺陷：`visibility` 有 transition，从 visible→hidden 的 200ms 过渡期间
     浏览器仍把该层当作可命中的最高层 → 吃掉页面上的点击（user 首次点击
     下拉/按钮「没反应」，需第二下才生效）。
     JS 侧 closeReminderModal() 摘掉 .show → 250ms 后才 removeChild，
     这段窗口正是被吞点击的时段。显式 pointer-events 是唯一可靠断点。 */
  pointer-events: none;
  transition: opacity 0.2s, visibility 0.2s;
  z-index: 999;
}
.modal-overlay.show { opacity: 1; visibility: visible; pointer-events: auto; }

.modal {
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) scale(0.96);
  background: var(--card-bg);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  width: 90%;
  max-width: 560px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  opacity: 0;
  visibility: hidden;
  transition: all 0.2s;
  z-index: 1000;
}
.modal.show { opacity: 1; visibility: visible; transform: translate(-50%, -50%) scale(1); }

/* v78: 合同附件预览弹窗（桌面 860px，移动端走 .modal 媒体查询 94vw） */
.modal.fp-modal { max-width: 860px; max-height: 90vh; }
.modal.wide { max-width: 760px; }
.modal.full { max-width: 96vw; width: 96vw; max-height: 92vh; }
/* v314: 甘特图弹窗全屏——.modal 带 top/left/transform 居中，全屏时必须复位
   （UA :fullscreen 规则不含 transform，不复位会偏移半个弹窗尺寸） */
.modal.full:fullscreen,
.modal.full:-webkit-full-screen {
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100vw;
  height: 100vh;
  max-width: none;
  max-height: none;
  transform: none;
  border-radius: 0;
  margin: 0;
}
.modal.full:fullscreen .modal-body,
.modal.full:-webkit-full-screen .modal-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
}
/* 全屏按钮激活态（data-on=1）：主色描边提示当前处于全屏 */
#ganttFsBtn[data-on="1"] {
  border-color: var(--primary, #2563eb);
  color: var(--primary, #2563eb);
}
/* v316 主题按钮激活态（data-on=1 表示当前为深色）：主色描边 */
#ganttThemeBtn[data-on="1"] {
  border-color: var(--primary, #2563eb);
  color: var(--primary, #2563eb);
}

/* ---------- Gantt ---------- */
.gantt-header-info { padding: 14px 18px; border-bottom: 1px solid var(--gray-200); background: var(--gray-50); }
.gantt-table { border-collapse: collapse; width: 100%; font-size: 12px; }
.gantt-table th, .gantt-table td { border: 1px solid var(--gray-200); padding: 4px 6px; text-align: center; vertical-align: middle; }
.gantt-table thead th { background: var(--gray-100); font-weight: 500; color: var(--gray-700); }
.gantt-table tbody tr { height: 40px; }
.gantt-table tbody tr:nth-child(even) td { background: var(--gray-50); }
.gantt-table .gantt-info-name { text-align: left; font-weight: 500; color: var(--gray-800); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 240px; }
.gantt-table tr.gantt-row { cursor: pointer; }
.gantt-table tr.gantt-row-sel td { outline: 2px solid #2563eb; outline-offset: -2px; }
.gantt-table tr.gantt-row-sel td:first-child { font-weight: 700; color: #2563eb; }
.gantt-cell { position: relative; padding: 0 !important; background: var(--card-bg); }
.gantt-bar { position: absolute; top: 8px; height: 22px; border-radius: 3px; display: flex; align-items: center; font-size: 11px; color: #fff; font-weight: 500; padding: 0 8px; box-shadow: 0 1px 2px rgba(0,0,0,0.08); z-index: 2; overflow: hidden; white-space: nowrap; }
.gantt-bar.gantt-bar-done { background: #1e3a8a; }
.gantt-bar.gantt-bar-remain { background: #60a5fa; box-shadow: none; }
.gantt-bar.gantt-bar-todo { background: #93c5fd; color: #1e3a8a; }
.gantt-today-line { position: absolute; top: 0; bottom: 0; width: 2px; background: #ef4444; z-index: 5; pointer-events: none; }
.gantt-today-line::before { content: '今天'; position: absolute; top: 2px; left: 4px; background: #ef4444; color: #fff; font-size: 10px; padding: 1px 5px; border-radius: 3px; white-space: nowrap; }
.gantt-legend { display: flex; gap: 16px; font-size: 11px; color: var(--text-tertiary); padding: 10px 18px; border-top: 1px solid var(--gray-200); background: var(--gray-50); }

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 24px;
  border-bottom: 1px solid var(--border-light);
  flex-shrink: 0;
  /* v179: 标题栏可拖拽——移动光标 + 禁选中文本 + 禁触屏滚动 */
  cursor: move;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}
.modal-header h3 { font-size: 16px; font-weight: 700; color: var(--gray-800); pointer-events: none; }
/* v179: 拖动中关 transition（避免平滑跟手）+ 关 close button 选中态冒泡视觉干扰 */
.modal.dragging,
.modal.dragging * {
  cursor: move !important;
  user-select: none !important;
}
.modal.dragging { transition: none; }
.modal-body {
  padding: 24px;
  overflow-y: auto;
  flex: 1;
}
.modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 16px 24px;
  border-top: 1px solid var(--border-light);
  flex-shrink: 0;
}
.modal-close {
  width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm);
  color: var(--gray-400);
  transition: all 0.15s;
}
.modal-close:hover { background: var(--gray-100); color: var(--gray-600); }

/* ---------- v317: 弹窗窗口三按钮（最小化 / 最大化 / 关闭） ---------- */
.modal-win-controls {
  display: flex;
  align-items: center;
  gap: 0;
}
.modal-win-btn {
  width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm);
  color: var(--gray-400);
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  transition: all 0.15s;
}
.modal-win-btn:hover { background: var(--gray-100); color: var(--gray-600); }
.modal-win-btn:active { background: var(--gray-200); }
/* 关闭按钮（CSS 已有 .modal-close），与 win-btn 视觉对齐无视觉断层 */
/* v317: 最大化（窗口级 100vw×100vh）——与 v314 OS 全屏共存，由 .modal.full:fullscreen 处理 */
.modal.maximized {
  top: 0 !important;
  left: 0 !important;
  right: auto !important;
  transform: none !important;
  width: 100vw !important;
  height: 100vh !important;
  max-width: none !important;
  max-height: none !important;
  border-radius: 0 !important;
  margin: 0 !important;
}
.modal.maximized .modal-body { flex: 1; min-height: 0; overflow: auto; }
/* v317: 最小化——容器隐藏，仅任务栏项可见 */
.modal.minimized { display: none !important; }
/* v317: 最大化按钮激活态（与 #ganttFsBtn 范式一致：data-on=1 主色描边） */
#modalMaxBtn[data-on="1"] {
  border-color: var(--primary, #2563eb);
  color: var(--primary, #2563eb);
}

/* ---------- v317: 底部弹窗任务栏（多弹窗堆叠） ---------- */
.modal-taskbar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  display: flex;
  align-items: flex-end;
  gap: 6px;
  padding: 8px 12px;
  z-index: 1500;
  pointer-events: none;
}
.taskbar-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--card-bg);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  box-shadow: var(--shadow-md);
  font-size: 12px;
  color: var(--gray-700);
  max-width: 220px;
  cursor: pointer;
  pointer-events: auto;
  transition: all 0.15s;
}
.taskbar-item:hover { background: var(--gray-50); color: var(--gray-900); }
.taskbar-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--primary);
  flex-shrink: 0;
}
.taskbar-title {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.taskbar-close {
  width: 18px; height: 18px;
  display: flex; align-items: center; justify-content: center;
  border: none;
  background: transparent;
  color: var(--gray-400);
  font-size: 16px;
  line-height: 1;
  border-radius: var(--radius-sm);
  cursor: pointer;
  padding: 0;
}
.taskbar-close:hover { background: var(--gray-200); color: var(--gray-700); }

/* ---------- v448: 确认弹窗统一美化（退出/删除等二次确认） ---------- */
.modal-confirm {
  max-width: 420px;
  text-align: center;
}
.modal-confirm .modal-header {
  justify-content: center;
  position: relative;
  padding: 24px 24px 10px;
  border-bottom: none;
  cursor: default;
}
/* 验证性弹窗无需拖动/最小化/最大化 */
.modal-confirm .modal-header h3 {
  font-size: 18px;
  font-weight: 700;
  color: var(--gray-900);
}
.modal-confirm .modal-win-controls {
  position: absolute;
  right: 12px;
  top: 16px;
}
.modal-confirm .modal-win-controls .modal-win-btn { display: none; }
.modal-confirm .modal-close { color: var(--gray-400); }
.modal-confirm .modal-body {
  padding: 4px 32px 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1 1 auto;
  overflow: visible;
}
.modal-confirm .mc-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 16px;
  color: var(--primary);
  background: rgba(79, 107, 237, 0.10);
}
.modal-confirm .mc-icon.mc-danger {
  color: var(--danger);
  background: rgba(220, 38, 38, 0.10);
}
.modal-confirm .mc-icon svg { width: 28px; height: 28px; stroke-width: 1.8; }
.modal-confirm .mc-msg {
  color: var(--gray-600);
  font-size: 14px;
  line-height: 1.7;
  max-width: 320px;
  margin: 0;
}
.modal-confirm .modal-footer {
  justify-content: center;
  padding: 0 24px 24px;
  border-top: none;
  gap: 12px;
}
.modal-confirm .modal-footer .btn {
  min-width: 96px;
  height: 38px;
  padding: 0 20px;
  font-size: 14px;
}

/* v317: 移动端 <768px 隐藏三按钮（移动端 modal 用全屏 sheet 体验更佳） */
@media (max-width: 768px) {
  .modal-win-controls { display: none !important; }
}

/* ---------- Toast ---------- */
.toast-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  border-left: 3px solid var(--primary);
  font-size: 13px;
  color: var(--gray-700);
  animation: toastIn 0.25s ease;
  min-width: 280px;
}
.toast.success { border-left-color: var(--success); }
.toast.error { border-left-color: var(--danger); }
.toast.warning { border-left-color: var(--warning); }
.toast .toast-icon { flex-shrink: 0; }
.toast .toast-msg { flex: 1; }
.toast.removing { animation: toastOut 0.25s ease forwards; }
@keyframes toastIn {
  from { opacity: 0; transform: translateX(20px); }
  to { opacity: 1; transform: translateX(0); }
}
@keyframes toastOut {
  from { opacity: 1; transform: translateX(0); }
  to { opacity: 0; transform: translateX(20px); }
}

/* ---------- 通知面板 ---------- */
.notif-panel {
  position: fixed;
  top: 60px;
  right: 24px;
  width: 340px;
  max-height: 400px;
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  border: 1px solid var(--border);
  z-index: 500;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: all 0.2s;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.notif-panel.show { opacity: 1; visibility: visible; transform: translateY(0); }
.notif-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-light);
}
.notif-panel-header h4 { font-size: 14px; font-weight: 600; color: var(--gray-800); }
.notif-panel-body { overflow-y: auto; flex: 1; }
.notif-item {
  display: flex;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border-light);
  cursor: pointer;
  transition: background 0.1s;
}
.notif-item:hover { background: var(--gray-50); }
.notif-item:last-child { border-bottom: none; }
.notif-item .notif-icon { flex-shrink: 0; }
.notif-item .notif-content { flex: 1; min-width: 0; }
.notif-item .notif-title { font-size: 13px; font-weight: 500; color: var(--gray-700); }
.notif-item .notif-desc { font-size: 12px; color: var(--text-tertiary); margin-top: 2px; }
.notif-item .notif-time { font-size: 11px; color: var(--text-tertiary); margin-top: 4px; }

/* ============================================
   页面专用样式
   ============================================ */

/* ---------- 仪表盘 ---------- */
/* v190: 全站统计卡收窄+美化（紧凑+彩色边条+趋势点） */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
  gap: 14px;
  margin-bottom: 20px;
}
.stat-card {
  position: relative;
  overflow: hidden;
  background: linear-gradient(180deg, var(--card-bg) 0%, rgba(255,255,255,0) 100%);
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 16px 16px 16px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* v222: 微交互统一走动效 token */
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.stat-card:hover {
  border-color: var(--border);
  box-shadow: var(--shadow-hover);
  transform: var(--lift-md);
}
.stat-card .stat-info { flex: 1; min-width: 0; }
.stat-card .stat-label {
  font-size: 11.5px;
  color: var(--text-tertiary);
  margin-bottom: 4px;
  letter-spacing: 0.2px;
}
.stat-card .stat-value {
  font-size: clamp(17px, 1.8vw, 22px);
  font-weight: 700;
  color: var(--gray-800);
  line-height: 1.2;
  word-break: normal;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
}
.stat-card .stat-value-main { font-variant-numeric: tabular-nums; }
.stat-card .stat-value-dec { font-size: 0.72em; opacity: 0.85; margin-left: 1px; font-weight: 600; }
.stat-card .stat-trend {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  margin-top: 4px;
  color: var(--text-tertiary);
}
.stat-card .stat-trend::before {
  content: '';
  display: inline-block;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
  background: currentColor;
  opacity: 0.75;
  flex-shrink: 0;
}
.stat-card .stat-trend.up { color: var(--success); }
.stat-card .stat-trend.down { color: var(--danger); }
.stat-card .stat-icon {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  /* v222: 卡片 hover 时图标轻微放大（spring 曲线带回弹） */
  transition: transform var(--dur-slow) var(--ease-spring);
}
.stat-card:hover .stat-icon { transform: scale(1.08); }
.stat-card .stat-icon svg { width: 18px; height: 18px; }
.stat-icon.primary { background: var(--primary-bg); color: var(--primary); }
.stat-icon.success { background: var(--success-bg); color: var(--success); }
.stat-icon.warning { background: var(--warning-bg); color: var(--warning); }
.stat-icon.info { background: var(--info-bg); color: var(--info); }
.stat-icon.danger { background: var(--danger-bg); color: var(--danger); }

/* v100: 统计卡彩色左边条；v222 加粗到 4px + 上下渐隐 */
.stat-card::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  background-image: linear-gradient(180deg, var(--primary) 0%, var(--primary) 55%, transparent 100%);
}
.stat-card.accent-success::before { background-image: linear-gradient(180deg, var(--success) 0%, var(--success) 55%, transparent 100%); }
.stat-card.accent-warning::before { background-image: linear-gradient(180deg, var(--warning) 0%, var(--warning) 55%, transparent 100%); }
.stat-card.accent-danger::before  { background-image: linear-gradient(180deg, var(--danger)  0%, var(--danger)  55%, transparent 100%); }
.stat-card.accent-info::before    { background-image: linear-gradient(180deg, var(--info)    0%, var(--info)    55%, transparent 100%); }
.stat-card.accent-primary::before { background-image: linear-gradient(180deg, var(--primary) 0%, var(--primary) 55%, transparent 100%); }

/* v189: 兼容旧 class（已并入 .stat-grid） */
.stat-grid.stat-grid-compact { /* no-op, kept for backward compat */ }

.stat-mini {
  height: 4px;
  border-radius: 2px;
  background: var(--gray-100);
  margin-top: 12px;
  overflow: hidden;
}
.stat-mini-fill {
  height: 100%;
  border-radius: 2px;
  transition: width 0.5s ease;
}
.stat-mini-fill.primary { background: var(--primary); }
.stat-mini-fill.success { background: var(--success); }
.stat-mini-fill.warning { background: var(--warning); }
.stat-mini-fill.info { background: var(--info); }
.stat-mini-fill.danger { background: var(--danger); }

/* v101: 欢迎横幅改单行细条（一屏省空间） */
.dash-hero {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  background: linear-gradient(135deg, #4f6bed 0%, #3a56d4 55%, #7c3aed 100%);
  border-radius: var(--radius);
  padding: 12px 20px;
  margin-bottom: 14px;
  color: #fff;
  box-shadow: 0 3px 10px rgba(79, 107, 237, 0.22);
}
.dash-hero-hi { font-size: 16px; font-weight: 700; letter-spacing: 0.3px; display: flex; align-items: center; flex-wrap: wrap; gap: 10px; min-width: 0; }
.dash-hero-sep { display: inline-block; width: 1px; height: 14px; background: rgba(255, 255, 255, 0.35); margin: 0 2px; }
.dash-hero-sub { font-size: 12.5px; color: rgba(255, 255, 255, 0.85); font-weight: 400; display: inline-flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.dash-hero-sub b { color: #fff; font-weight: 700; }
.dash-hero-dot { display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: rgba(255, 255, 255, 0.5); margin: 0 2px; font-style: normal; }
/* v215: 欢迎横幅实时时钟（时分秒 pill，等宽数字防跳动） */
.dash-hero-clock {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 8px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.16);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.5px;
}
.dash-hero-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.dash-hero-btn {
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
  font-size: 12.5px;
  font-weight: 500;
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background 0.15s;
  white-space: nowrap;
}
.dash-hero-btn:hover { background: rgba(255, 255, 255, 0.28); }
@media (max-width: 640px) {
  .dash-hero { padding: 12px 14px; }
  .dash-hero-hi { font-size: 15px; }
  .dash-hero-sub { font-size: 12px; }
  .dash-hero-sep { display: none; }
}

/* v101: 一屏三列网格（左：项目进度纵跨2行；右：迷你卡 2×2） */
.dash-main {
  display: grid;
  grid-template-columns: 1.55fr 1fr 1fr;
  grid-auto-rows: min-content;
  gap: 14px;
  margin-top: 14px;
  align-items: start;
}
.dash-main .dash-proj { grid-row: 1 / span 2; }
.dash-main .mini-card.mini-span2 { grid-column: span 2; }
@media (max-width: 1280px) {
  .dash-main { grid-template-columns: 1fr 1fr; }
  .dash-main .dash-proj { grid-row: auto; grid-column: 1 / -1; }
  .dash-main .mini-card.mini-span2 { grid-column: span 1; }
}
@media (max-width: 900px) {
  .dash-main { grid-template-columns: 1fr; }
}

/* v101: 统计卡紧凑化（仅仪表盘） */
.dash-slim .stat-card { padding: 12px 16px; }
.dash-slim .stat-value { font-size: 24px; }
.dash-slim .stat-trend { margin-top: 5px; }
.dash-slim .stat-mini { margin-top: 8px; }
.dash-slim .stat-icon { width: 38px; height: 38px; }

/* v101: 迷你卡行内 KPI 条 */
.mini-kpis {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 14px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--border-light);
  background: var(--gray-50);
}
.mk { display: inline-flex; align-items: baseline; gap: 4px; white-space: nowrap; }
.mk b { font-size: 14px; font-weight: 700; color: var(--gray-800); font-variant-numeric: tabular-nums; }
.mk b.c-success { color: var(--success); }
.mk b.c-warning { color: #d97706; }
.mk b.c-danger { color: var(--danger); }
.mk b.c-primary { color: var(--primary); }
.mk i { font-style: normal; font-size: 11px; color: var(--text-tertiary); }

/* v101: 精简行（迷你卡 + 项目卡） */
.ov-row.ov-sm { padding: 7px 14px; gap: 8px; }
.ov-row.ov-sm .ov-row-name { font-size: 12.5px; }
.ov-row.ov-sm .ov-row-sub { font-size: 10.5px; }
.ov-row.ov-sm .ov-row-num { font-size: 13px; }
.ov-row.ov-sm .ov-row-date { font-size: 11.5px; }

/* v101: 自适应裁行 */
.ov-row.ov-hide { display: none; }
.ov-more {
  font-size: 11px;
  color: var(--text-tertiary);
  margin-left: 8px;
  white-space: nowrap;
  font-weight: 400;
}

/* v101: fitDashboard 紧凑模式（视口不够高时自动启用） */
.dash-compact .dash-hero { padding: 9px 16px; margin-bottom: 10px; box-shadow: none; }
.dash-compact .dash-hero-hi { font-size: 14px; }
.dash-compact .dash-slim .stat-card { padding: 9px 14px; }
.dash-compact .dash-slim .stat-card .stat-trend { display: none; }
.dash-compact .dash-slim .stat-card .stat-mini { display: none; }
.dash-compact .dash-main { margin-top: 10px; gap: 12px; }
.dash-compact .dash-main .card-header { padding: 11px 16px; }
.dash-compact .mini-kpis { padding: 7px 12px; }

/* ============================================
   v124: 仪表盘可视化图表区（纯 SVG，配色走 CSS 变量，深色主题自动适配）
   ============================================ */
.dash-charts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-top: 14px;
  align-items: stretch;
}
.dash-charts.charts-2 { grid-template-columns: repeat(2, 1fr); }

.chart-card .card-body { display: block; padding: 14px 20px 16px; }  /* v134: 20px 与 .card-header padding-left 对齐，圆点/状态名顶到「卡标题」左 */
.chart-card .chart-goto { font-size: 12px; color: var(--primary); font-weight: 500; text-decoration: none; margin-left: 8px; }
.chart-card .chart-goto:hover { text-decoration: underline; }

/* --- v126 横向柱状图（任务/预付款/合同/采购状态）--- */
/*   v127 对齐修复：flex + align-items:center 看似居中，但 <span> 文本 baseline 漂移
     + bar-name/bar-val 内容差异导致各行 min-content 高度不同，圆点/胶囊/数字纵向
     参差。改为 CSS Grid 锁 5 列固定列宽 + 锁定行高 + 所有子项强制 justify-self/align-self:center
     —— 跨行 100% 对齐。
     v134: 修复 .bar-chart class 与底部 mini bar chart (.bar-chart { align-items: flex-end; height: 180px })
     命名冲突 —— 用 .dash-charts .bar-chart 提升特异性，把 v126 的 column + stretch 行为恢复，
     让 bar-row 顶到 bar-chart 左边（与卡标题对齐）。 */
.dash-charts .bar-chart {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
  height: auto;
  padding: 0;
}
.bar-row {
  display: grid;
  grid-template-columns: 14px 72px minmax(60px, 1fr) 34px 48px;
  align-items: center;
  column-gap: 10px;
  font-size: 13px;
  min-width: 0;
  min-height: 30px;
  line-height: 1.4;
}
.bar-dot {
  width: 10px; height: 10px; border-radius: 50%;
  justify-self: start; align-self: center;  /* v134: start 让圆点顶到 cell 左边与「合同」标题对齐 */
  flex-shrink: 0; cursor: default;
}
.bar-name {
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text); font-weight: 500;
  display: inline-block; line-height: 1.4;
  align-self: center;
}
.bar-track {
  height: 14px;
  background: var(--gray-100); border-radius: 7px; overflow: hidden;
  align-self: center;
}
.bar-fill {
  height: 100%; border-radius: 7px;
  animation: v126barGrow 0.7s cubic-bezier(0.22, 0.8, 0.32, 1) backwards;
  transform-origin: left center;
}
.bar-fill:hover { filter: brightness(1.08); }
@keyframes v126barGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.bar-val {
  width: 100%; justify-self: end; align-self: center;
  text-align: right; font-weight: 700; color: var(--text); font-size: 13px;
  line-height: 1.2; font-variant-numeric: tabular-nums;
}
.bar-pct {
  width: 100%; justify-self: end; align-self: center;
  text-align: right; color: var(--text-tertiary); font-style: normal; font-size: 12px;
  line-height: 1.2; font-variant-numeric: tabular-nums;
}
.bar-total {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px dashed var(--border);
  font-size: 12px; color: var(--text-tertiary);
}

/* --- 趋势柱状图 --- */
.chart-trend .card-body { display: block; padding: 12px 16px 10px; }
.trend-svg { width: 100%; height: auto; display: block; }
.trend-bar {
  animation: v124barGrow 0.7s cubic-bezier(0.22, 0.8, 0.32, 1) backwards;
  transform-box: fill-box;
  transform-origin: bottom;
  cursor: default;
}
.trend-bar:hover { opacity: 0.85; }
@keyframes v124barGrow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
.trend-legend { display: flex; gap: 16px; justify-content: center; margin-top: 8px; font-size: 12px; color: var(--text-secondary); }
.trend-legend .tl-dot { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }
.trend-masked, .trend-empty {
  text-align: center; color: var(--text-tertiary); font-size: 13px;
  padding: 56px 16px; background: var(--gray-50); border-radius: var(--radius);
}

/* --- fitDashboard 紧凑模式下收缩图表 --- */
.dash-compact .dash-charts { margin-top: 10px; gap: 10px; }
.dash-compact .chart-card .card-body { padding: 10px 14px 12px; }
.dash-compact .dash-charts .bar-chart { gap: 9px; }  /* v134: 提升 specificity，覆盖迷你 bar-chart 的 align-items:flex-end 让 v126 横向柱状图左对齐 */
.dash-compact .bar-row {
  grid-template-columns: 12px 68px minmax(50px, 1fr) 28px 42px;
  font-size: 12.5px;
  min-height: 24px;
  column-gap: 8px;
}
.dash-compact .bar-name { font-size: 12.5px; }
.dash-compact .bar-track { height: 12px; }
.dash-compact .bar-val { font-size: 12.5px; }
.dash-compact .bar-pct { font-size: 11.5px; }
.dash-compact .trend-masked, .dash-compact .trend-empty { padding: 36px 14px; }

/* --- 响应式 --- */
@media (max-width: 1200px) {
  .dash-charts { grid-template-columns: 1fr 1fr; }
  .dash-charts .chart-trend { grid-column: 1 / -1; }
}
@media (max-width: 900px) {
  .dash-charts, .dash-charts.charts-2 { grid-template-columns: 1fr; }
}

/* ============================================
   v126: 仪表盘全柱状图化（环形图全部改为横向柱状图）
   复用 v125 项目进度 .pg-* 风格，6 卡 3×2 一屏
   ============================================ */

/* --- 项目进度概览：横向条形图 --- */
/*   v127 对齐修复：同 .bar-row 思路，CSS Grid 锁列 + 强制 center，行高度对齐 */
.chart-prog .card-body { display: block; padding: 6px 0; }
/* v138: 加 .ov-row 前缀提权，覆盖 line 1581 .ov-row{display:flex} 同名冲突 */
.ov-row.pg-row {
  display: grid;
  /* v138: 列宽调整——百分比列加宽到 58px 视觉靠右，bar 1fr 撑满中部 */
  grid-template-columns: 12px minmax(80px, 110px) minmax(80px, 1fr) 58px;
  align-items: center;
  column-gap: 12px;
  padding: 9px 20px;
  cursor: pointer;
  line-height: 1.4;
  min-height: 36px;
  border-bottom: 1px solid var(--border-light);
  transition: background 0.1s;
}
.ov-row.pg-row:hover { background: var(--gray-50); }
.ov-row.pg-row:last-child { border-bottom: none; }
.pg-row:hover { background: var(--gray-50); }
.pg-dot {
  width: 10px; height: 10px; border-radius: 3px;
  justify-self: center; align-self: center;
  box-shadow: 0 0 0 2px var(--card-bg);
}
.pg-name {
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13px; color: var(--text); font-weight: 500;
  align-self: center;
}
.pg-bar {
  height: 10px; background: var(--gray-100); border-radius: 6px; overflow: hidden;
  align-self: center; min-width: 0;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.04);
}
[data-theme='dark'] .pg-bar { background: var(--gray-800); }
.pg-fill {
  height: 100%; border-radius: 6px;
  animation: v125pgGrow 0.8s cubic-bezier(0.22, 0.8, 0.32, 1) backwards;
  transform-origin: left;
  box-shadow: 0 1px 2px rgba(0,0,0,0.08);
}
.pg-fill:hover { filter: brightness(1.08); }
@keyframes v125pgGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.pg-val {
  justify-self: end; align-self: center;
  text-align: right;
  font-size: 13px; font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.pg-more {
  padding: 5px 16px 8px; font-size: 11.5px; color: var(--text-tertiary);
}
.pg-more a { color: var(--primary); text-decoration: none; }
.pg-more a:hover { text-decoration: underline; }

/* --- v126 一屏：横向柱状图卡微缩（6 卡 3×2 布局下尽量收矮）--- */
.dash-charts .chart-card .card-header { padding: 12px 20px; }  /* v134: 20px 让 header padding-left 与 .chart-card .card-body 20px 对齐，圆点/状态名顶到「卡标题」左 */
.dash-compact .ov-row.pg-row {
  /* v138: 同步收紧——保持 4 列布局，val 列加宽到 40px 视觉靠右 */
  grid-template-columns: 10px minmax(64px, 96px) minmax(50px, 1fr) 40px;
  padding: 6px 14px;
  column-gap: 9px;
  min-height: 28px;
}
.dash-compact .pg-name { font-size: 12px; max-width: 96px; }
.dash-compact .pg-val { font-size: 12px; }
.dash-compact .pg-bar { height: 7px; border-radius: 5px; box-shadow: none; }
.dash-compact .pg-fill { border-radius: 5px; box-shadow: none; }
.dash-compact .pg-dot { width: 8px; height: 8px; box-shadow: 0 0 0 2px var(--card-bg); }
.dash-compact .chart-prog .card-body { padding: 4px 0; }

/* --- v125 响应式补充 --- */
@media (max-width: 1200px) {
  .pg-name { max-width: 140px; }
}

/* v100: 概览卡片双列网格（财务 / 采购）——v101 起由 .dash-main 取代，保留兼容 */
.dash-ov-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: stretch;
  margin-top: 16px;
}
@media (max-width: 1100px) {
  .dash-ov-grid { grid-template-columns: 1fr; }
}

/* v100: 剩余天数彩色标签 */
.ov-pill {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--gray-100);
  color: var(--text-secondary);
  white-space: nowrap;
  flex-shrink: 0;
  min-width: 48px;
  text-align: center;
}
.ov-pill.warning { background: var(--warning-bg); color: #b45309; }
.ov-pill.danger { background: var(--danger-bg); color: var(--danger); }
.ov-pill.success { background: var(--success-bg); color: var(--success); }

/* v100: 项目概览加宽进度条 */
.ov-bar-lg { width: 110px; }
.ov-bar-lg .ov-bar { height: 8px; border-radius: 4px; }
.ov-bar-lg .ov-bar-fill { border-radius: 4px; }
@media (max-width: 768px) {
  .ov-bar-lg { width: 70px; }
  .ov-pill { min-width: 40px; }
}

.dash-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 16px;
  margin-bottom: 24px;
}
@media (max-width: 1024px) {
  .dash-grid { grid-template-columns: 1fr; }
}

/* v128: 任务管理 KPI 条 — 美化为 5 张独立彩色块（左竖色条 + 圆角图标 + 大数字 + 微浮起） */
.ov-kpi-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
}
.ov-kpi {
  position: relative;
  padding: 14px 14px 12px 18px;
  background: var(--card-bg);
  border: 1px solid var(--border-light);
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  cursor: default;
  overflow: hidden;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
/* v543: 色条 3px→4px 并改「上下渐隐」——原 3px 整条在 1:1 下细到看不见（用户反馈「色条不显示」，
   实测 ::before 确有 3x111px 实色、只是太细）；渐隐同时让上圆角处不再硬切。
   语义色由 accent-* 单一真源给出，此处只换画法（与 .stat-card::before 同语言）。 */
.ov-kpi::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 0%, var(--gray-400) 22%, var(--gray-400) 78%, transparent 100%);
}
.ov-kpi.accent-success::before { background: linear-gradient(180deg, transparent 0%, var(--success) 22%, var(--success) 78%, transparent 100%); }
.ov-kpi.accent-warning::before { background: linear-gradient(180deg, transparent 0%, var(--warning) 22%, var(--warning) 78%, transparent 100%); }
.ov-kpi.accent-danger::before  { background: linear-gradient(180deg, transparent 0%, var(--danger)  22%, var(--danger)  78%, transparent 100%); }
.ov-kpi.accent-primary::before { background: linear-gradient(180deg, transparent 0%, var(--primary) 22%, var(--primary) 78%, transparent 100%); }
.ov-kpi.accent-info::before    { background: linear-gradient(180deg, transparent 0%, var(--info)    22%, var(--info)    78%, transparent 100%); }
/* v543: 「任务总数」为中性总量指标 —— 蓝色（accent-info）比原灰色更有存在感，且不与四张语义卡撞色 */
.ov-kpi.accent-info .ov-kpi-icon { background: var(--info-bg); color: var(--info); }
.ov-kpi:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px -8px rgba(0, 0, 0, .12);
  border-color: transparent;
}
/* v543: hover 时色条由 4px 微增至 5px —— 交互反馈落到色条本体上，强化「这张卡可点/在关注」感 */
.ov-kpi::before { transition: width .18s ease; }
.ov-kpi:hover::before { width: 5px; }
.ov-kpi-icon {
  width: 30px; height: 30px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--gray-100);
  color: var(--gray-500);
  margin-bottom: 2px;
}
.ov-kpi-icon svg { width: 16px; height: 16px; stroke-width: 2; }
.ov-kpi.accent-success .ov-kpi-icon { background: var(--success-bg); color: var(--success); }
.ov-kpi.accent-warning .ov-kpi-icon { background: var(--warning-bg); color: var(--warning); }
.ov-kpi.accent-danger  .ov-kpi-icon { background: var(--danger-bg);  color: var(--danger); }
.ov-kpi.accent-primary .ov-kpi-icon { background: var(--primary-bg); color: var(--primary); }
.ov-kpi-num {
  font-size: 26px;
  font-weight: 800;
  color: var(--gray-800);
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.ov-kpi-num.success { color: var(--success); }
.ov-kpi-num.warning { color: var(--warning); }
.ov-kpi-num.danger  { color: var(--danger); }
.ov-kpi-num.primary { color: var(--primary); }
.ov-kpi-label {
  font-size: 12px;
  color: var(--text-tertiary);
  font-weight: 500;
  white-space: nowrap;
}
/* v128: 完成率 — 用迷你环形进度替代纯数字 */
.ov-kpi-ring { display: flex; align-items: center; gap: 10px; }
.ov-kpi-ring-svg { width: 46px; height: 46px; flex-shrink: 0; transform: rotate(-90deg); }
.ov-kpi-ring-svg circle { fill: none; stroke-width: 5; stroke-linecap: round; }
.ov-kpi-ring-track { stroke: var(--gray-100); }
.ov-kpi-ring-fill  { transition: stroke-dashoffset .8s cubic-bezier(.2,.8,.3,1); }
.ov-kpi.accent-success .ov-kpi-ring-fill { stroke: var(--success); }
.ov-kpi.accent-warning .ov-kpi-ring-fill { stroke: var(--warning); }
.ov-kpi.accent-danger  .ov-kpi-ring-fill { stroke: var(--danger); }
.ov-kpi.accent-info    .ov-kpi-ring-fill { stroke: var(--info); }
.ov-kpi-ring-body { display: flex; flex-direction: column; line-height: 1; }
.ov-kpi-ring-pct {
  font-size: 22px; font-weight: 800;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.ov-kpi-ring-label { font-size: 11px; color: var(--text-tertiary); margin-top: 4px; font-weight: 500; }
@media (max-width: 1024px) {
  .ov-kpi-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 640px) {
  .ov-kpi-grid { grid-template-columns: repeat(2, 1fr); }
  .ov-kpi { padding: 12px; }
  .ov-kpi-num { font-size: 22px; }
}

/* v94: 仪表盘精简列表行 */
.ov-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border-light);
  cursor: pointer;
  transition: background 0.1s;
}
.ov-row:last-child { border-bottom: none; }
.ov-row:hover { background: var(--gray-50); }
.ov-row-name {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--gray-800);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ov-row-sub {
  font-size: 11px;
  color: var(--text-tertiary);
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ov-row-num {
  font-size: 14px;
  font-weight: 700;
  color: var(--gray-800);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ov-row-num.success { color: var(--success); }
.ov-row-num.warning { color: #d97706; }
.ov-row-num.danger { color: var(--danger); }
.ov-bar-wrap {
  width: 80px;
  flex-shrink: 0;
}
.ov-bar {
  height: 5px;
  background: var(--gray-100);
  border-radius: 3px;
  overflow: hidden;
}
.ov-bar-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.4s ease;
}
.ov-row-date {
  font-size: 11px;
  color: var(--text-tertiary);
  white-space: nowrap;
  flex-shrink: 0;
  min-width: 56px;
  text-align: right;
}
.ov-row-date.warning { color: #d97706; font-weight: 600; }
.ov-row-date.danger { color: var(--danger); font-weight: 600; }

@media (max-width: 768px) {
  .ov-bar-wrap { width: 60px; }
}

/* ---------- 迷你图表 (CSS bar chart) ---------- */
.bar-chart {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  height: 180px;
  padding: 10px 0;
}
.bar-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  height: 100%;
  justify-content: flex-end;
}
.bar-col .bar {
  width: 100%;
  max-width: 32px;
  background: var(--primary);
  border-radius: 4px 4px 0 0;
  transition: height 0.5s ease;
  position: relative;
  min-height: 2px;
}
.bar-col .bar:hover { opacity: 0.8; }
.bar-col .bar-label { font-size: 11px; color: var(--text-tertiary); }

/* ---------- 环形进度 ---------- */
.donut-chart {
  position: relative;
  width: 120px;
  height: 120px;
  margin: 0 auto;
}
.donut-chart svg { transform: rotate(-90deg); }
.donut-chart .donut-center {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
}
.donut-center .donut-value { font-size: 24px; font-weight: 700; color: var(--gray-800); }
.donut-center .donut-label { font-size: 11px; color: var(--text-tertiary); }

/* ---------- 项目卡片 ---------- */
.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 16px;
}
.project-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  transition: all 0.2s;
  cursor: pointer;
}
.project-card:hover { box-shadow: var(--shadow-md); border-color: var(--gray-300); transform: translateY(-2px); }
.project-card .pc-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 12px;
}
.project-card .pc-title { font-size: 15px; font-weight: 600; color: var(--gray-800); margin-bottom: 4px; }
.project-card .pc-code { font-size: 12px; color: var(--text-tertiary); font-family: var(--mono); }
.project-card .pc-desc { font-size: 12px; color: var(--text-secondary); margin-bottom: 14px; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.project-card .pc-progress-row { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
.project-card .pc-progress-label { font-size: 12px; color: var(--text-secondary); white-space: nowrap; }
.project-card .pc-progress-val { font-size: 12px; font-weight: 600; color: var(--gray-700); }
.project-card .pc-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 14px;
  border-top: 1px solid var(--border-light);
}
.project-card .pc-members { display: flex; }
.project-card .pc-members .user-avatar { margin-left: -6px; border: 2px solid var(--card-bg); }
.project-card .pc-members .user-avatar:first-child { margin-left: 0; }
.project-card .pc-deadline { font-size: 11px; color: var(--text-tertiary); display: flex; align-items: center; gap: 4px; }

/* ---------- 看板 ---------- */
.kanban-board {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding-bottom: 8px;
  min-height: 500px;
}
.kanban-column {
  flex: 1;
  min-width: 280px;
  background: var(--gray-50);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
}
.kanban-column-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.kanban-column-header .kc-title { font-size: 13px; font-weight: 600; color: var(--gray-700); display: flex; align-items: center; gap: 8px; }
.kanban-column-header .kc-count { font-size: 11px; color: var(--text-tertiary); background: var(--card-bg); padding: 1px 8px; border-radius: 10px; border: 1px solid var(--border); }
.kanban-column-body { padding: 10px; overflow-y: auto; flex: 1; }

/* v95: 看板列顶部色条 */
.kanban-col-accent {
  height: 3px;
  border-radius: var(--radius) var(--radius) 0 0;
  flex-shrink: 0;
}
.kanban-column-header .kc-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
}
.kanban-column-header .kc-count {
  font-size: 11px; font-weight: 700; padding: 1px 8px; border-radius: 10px;
  border: 1px solid; line-height: 1.4;
}
/* v95: 空列占位 */
.kanban-empty {
  text-align: center; padding: 20px 8px; font-size: 12px; color: var(--text-tertiary);
  border: 2px dashed var(--border); border-radius: var(--radius-sm); margin: 4px 0;
}

/* v95: 看板卡片重构 */
.kanban-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-left: 3px solid var(--gray-300);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: all 0.18s;
  position: relative;
}
.kanban-card:hover {
  box-shadow: var(--shadow-sm);
  border-color: var(--gray-300);
  transform: translateX(2px);
}
/* 优先级左边框色码 */
.kanban-card.p-critical { border-left-color: var(--danger); }
.kanban-card.p-high { border-left-color: var(--warning); }
.kanban-card.p-medium { border-left-color: var(--info); }
.kanban-card.p-low { border-left-color: var(--gray-300); }

.kanban-card .kc-title {
  font-size: 13.5px; font-weight: 600; color: var(--gray-800);
  margin-bottom: 6px; line-height: 1.4;
  word-break: break-word;
}
/* v95: 项目标签 chip */
.kanban-card .kc-project {
  display: inline-block;
  font-size: 11px; color: var(--gray-600);
  background: var(--gray-50);
  border: 1px solid var(--border-light);
  padding: 1px 7px; border-radius: 4px;
  margin-bottom: 10px; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kanban-card .kc-footer {
  display: flex; align-items: center; justify-content: space-between;
  gap: 6px; margin-top: 8px;
}
.kanban-card .kc-assignee {
  display: flex; align-items: center; gap: 4px; flex-shrink: 0;
}
.kanban-card .kc-assignee-name {
  font-size: 11px; color: var(--gray-600);
  max-width: 60px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kanban-card .kc-unassigned {
  font-size: 11px; color: var(--text-tertiary); font-style: italic;
}

/* v95: 日期标签色码体系 */
.kc-date {
  font-size: 11px; font-weight: 500;
  display: inline-flex; align-items: center; gap: 3px;
  white-space: nowrap;
}
.kc-date svg { opacity: 0.8; flex-shrink: 0; }
.task-date-overdue { color: var(--danger); }
.task-date-today { color: var(--danger); font-weight: 700; }
.task-date-soon { color: #d97706; }
.task-date-normal { color: var(--text-tertiary); }
.task-date-done { color: var(--success); }
.task-date-none { color: var(--text-tertiary); }

/* v95: 列表视图增强 */
.task-title-cell {
  display: flex; align-items: center; gap: 8px;
}
.task-pdot {
  width: 8px; height: 8px; border-radius: 50%;
  flex-shrink: 0; margin-top: 1px;
}
.task-project-chip {
  display: inline-block;
  font-size: 11px; color: var(--gray-600);
  background: var(--gray-50);
  border: 1px solid var(--border-light);
  padding: 2px 8px; border-radius: 4px;
  max-width: 140px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.task-assignee-cell {
  display: flex; align-items: center; gap: 6px;
}

/* ---------- 空状态 ---------- */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  text-align: center;
}
.empty-state .es-icon { color: var(--gray-300); margin-bottom: 12px; }
.empty-state .es-title { font-size: 14px; font-weight: 500; color: var(--gray-500); margin-bottom: 4px; }
.empty-state .es-desc { font-size: 12px; color: var(--text-tertiary); }

/* ---------- 页面工具栏 ---------- */
.page-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
  flex-wrap: wrap;
  gap: 12px;
}
.toolbar-left { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.toolbar-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* v440: 工具栏「一行显示」——状态筛选胶囊 + 右侧操作区同排。
   实测 1440 视口内容宽 1152px：五胶囊 601 + view-toggle 146 + 三按钮 301 + 间距 ≈ 1092，
   原本渲染成 2 行（.toolbar-flex-wrap=wrap 且总宽逼近临界）。
   收紧策略：① 组间距 12→10、组内间距 8→6（每组省 4~6px）；② 胶囊/按钮高度统一 32px
   （原胶囊 34 / btn 34 / btn-new 36 三档不齐，对齐后竖向更整齐，横向无影响）；
   ③ .page-toolbar 加 min-width:0 的两个子项防 flex 溢出（子项默认 min-width:auto）。
   ⚠️ 窄屏仍允许换行 —— 只保证 ≥1200px 内容宽下不换行，不做强制 nowrap（会横向溢出）。 */
.page-toolbar { gap: 10px; }
.page-toolbar .toolbar-left,
.page-toolbar .toolbar-right { min-width: 0; }
.toolbar-left { gap: 6px; }
.toolbar-right { gap: 6px; }
.page-toolbar .filter-chip { height: 32px; }
.page-toolbar .btn,
.page-toolbar .btn-new { height: 32px; }
.page-toolbar .btn-new { padding: 0 16px; border-radius: 9px; }
.page-toolbar .view-toggle { height: 32px; align-items: stretch; }
.page-toolbar .view-toggle button { display: inline-flex; align-items: center; padding: 0 11px; }

/* v196: 用户管理页 · 计数徽章 + 搜索框美化 */
.user-count-badge {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(79, 107, 237, 0.10), rgba(79, 107, 237, 0.04));
  border: 1px solid rgba(79, 107, 237, 0.18);
}
.user-count-num {
  font-size: 17px;
  font-weight: 700;
  color: var(--primary);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.user-count-label {
  font-size: 12px;
  color: var(--gray-500);
  letter-spacing: 0.5px;
}

.user-search-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.user-search-icon {
  position: absolute;
  left: 10px;
  width: 14px;
  height: 14px;
  color: var(--gray-400);
  pointer-events: none;
  transition: color 0.15s;
}
.admin-user-search {
  padding: 7px 12px 7px 32px;
  font-size: 13px;
  min-width: 240px;
  max-width: 320px;
  border: 1px solid var(--gray-200);
  border-radius: 8px;
  background: var(--card-bg);
  color: var(--gray-800);
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.admin-user-search::placeholder { color: var(--gray-400); }
.admin-user-search:hover { border-color: var(--gray-300); }
.admin-user-search:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(79, 107, 237, 0.12);
}
.admin-user-search:focus + * { color: var(--primary); }  /* fallback when sibling absent */
.user-search-wrap:focus-within .user-search-icon { color: var(--primary); }

/* v380.1: 大气庄重严谨 + 更显眼——字号 13→14 / 高度 32→34(与 .btn 一致) / 字色 gray-700 / 字重 600 / 边框 gray-300 / 圆点 8px / 静态阴影 0 2px 4px .06
   圆点/计数小徽标保留,圆角 999 胶囊,形成「硬主+软徽」对比,克制中显分量 */
.filter-chip {
  --fc-hover: var(--gray-50);
  --fc-color: var(--gray-700);
  --fc-border: #d0d5db;
  --fc-dot: var(--gray-500);
  /* v494: 计数气泡随状态着色（默认值 = 原 gray-100 / gray-700，全站外观不变） */
  --fc-count-bg: var(--gray-100);
  --fc-count-color: var(--gray-700);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 16px 0 14px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.3px;
  border-radius: 10px;
  border: 1px solid var(--fc-border);
  color: var(--fc-color);
  background: var(--card-bg);
  cursor: pointer;
  /* v379 token: 动效统一走 --dur-fast / --ease;transform 独立通道配合 active 弹入 */
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
  white-space: nowrap;
  position: relative;
  line-height: 1;
  /* v380.1: 静态阴影加深 — 0 1px 2px .04 → 0 2px 4px .06,默认态更「实」 */
  box-shadow: 0 2px 4px rgba(15, 23, 42, 0.06);
}
/* v440: 项目页胶囊去掉圆点后的横向收紧。
   ⚠️ 选择器必须锚在「状态筛选」独有的 `[data-status]` 上 —— 交付/财务/采购等页的 chip
   同样位于 `.page-toolbar` 内，若用 `.page-toolbar .filter-chip .fc-dot` 会**跨页误伤**
   （实测交付页 10 个 chip 的圆点被一起隐藏 = 回归）。项目页是唯一用 `data-status` 的状态筛选。 */
.page-toolbar .filter-chip[data-status] { gap: 6px; padding: 0 12px; }
.page-toolbar .filter-chip[data-status] .fc-dot { display: none; }
.filter-chip .fc-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--fc-dot);
  box-shadow: 0 0 0 2px var(--card-bg);
  flex: 0 0 auto;
  transition: background-color 0.18s, box-shadow 0.18s;
}
.filter-chip .fc-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; padding: 0 7px; height: 20px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.2px;
  background: var(--fc-count-bg);
  color: var(--fc-count-color);
  border-radius: 999px;
  margin-left: 2px;
  transition: background-color 0.18s, color 0.18s;
}
.filter-chip:hover {
  background: var(--fc-hover);
  border-color: var(--fc-border);
  color: var(--fc-color);
  /* v380.1: hover 阴影加深 — 0 4px 10px .08 → 0 6px 14px .12 */
  box-shadow: 0 6px 14px rgba(15, 23, 42, 0.12);
  transform: translateY(-1px);
}
/* v379 token: 按下瞬间回位 + 浅阴影,反馈感 */
.filter-chip:active { transform: translateY(0); box-shadow: 0 2px 4px rgba(15, 23, 42, 0.08); }
.filter-chip:hover .fc-count {
  background: rgba(15, 23, 42, 0.08);
  color: var(--fc-color);
}
.filter-chip.active {
  background: var(--fc-dot);
  border-color: var(--fc-dot);
  color: #fff;
  font-weight: 700;
  /* v380.1: active 厚重阴影 — 0 6px 16px .18 → 0 10px 24px .24 */
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.24);
  /* v222: 激活时 spring 弹入(class 添加触发, 播放一次) */
  animation: fc-pop var(--dur-slow) var(--ease-spring);
}
@keyframes fc-pop {
  0%   { transform: scale(0.94); }
  60%  { transform: scale(1.04); }
  100% { transform: scale(1); }
}
.filter-chip.active .fc-dot {
  background: #fff;
  box-shadow: 0 0 0 2px var(--fc-dot);
}
.filter-chip.active .fc-count {
  background: rgba(255, 255, 255, 0.3);
  color: #fff;
}

/* 5 个状态色板：all/in_progress/planning/completed/delayed */
.filter-chip[data-status="all"]         { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-status="in_progress"] { --fc-hover: var(--primary-bg); --fc-color: #4338ca; --fc-border: #c7d2fe; --fc-dot: #6366f1; }
.filter-chip[data-status="planning"]    { --fc-hover: #faf5ff; --fc-color: #6d28d9; --fc-border: #e9d5ff; --fc-dot: #a855f7; }
.filter-chip[data-status="completed"]   { --fc-hover: var(--success-bg); --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; }
.filter-chip[data-status="delayed"]     { --fc-hover: var(--danger-bg); --fc-color: #b91c1c; --fc-border: #fecaca; --fc-dot: #ef4444; }

/* v110: 整站统一 color palette — 合作伙伴状态 (4) */
.filter-chip[data-pstatus="all"]          { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-pstatus="cooperating"]  { --fc-hover: var(--primary-bg); --fc-color: #4338ca; --fc-border: #c7d2fe; --fc-dot: #6366f1; }
.filter-chip[data-pstatus="pending"]      { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; }
.filter-chip[data-pstatus="expired"]      { --fc-hover: var(--danger-bg); --fc-color: #b91c1c; --fc-border: #fecaca; --fc-dot: #ef4444; }

/* v110: 采购 6 状态 */
.filter-chip[data-pustatus="all"]      { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-pustatus="pending"]  { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; }
.filter-chip[data-pustatus="approved"] { --fc-hover: var(--primary-bg); --fc-color: #4338ca; --fc-border: #c7d2fe; --fc-dot: #6366f1; }
.filter-chip[data-pustatus="ordered"]  { --fc-hover: #faf5ff; --fc-color: #6d28d9; --fc-border: #e9d5ff; --fc-dot: #a855f7; }
.filter-chip[data-pustatus="received"] { --fc-hover: var(--success-bg); --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; }
.filter-chip[data-pustatus="rejected"] { --fc-hover: var(--danger-bg); --fc-color: #b91c1c; --fc-border: #fecaca; --fc-dot: #ef4444; }

/* v222: 财务中心 4 子视图色板（蓝=收支 / 橙=预付款 / 紫=合同 / 青=发票；records 对齐全站主蓝） */
.filter-chip[data-fview="records"]   { --fc-hover: var(--primary-bg); --fc-color: #4338ca; --fc-border: #c7d2fe; --fc-dot: #4f6bed; }
.filter-chip[data-fview="advance"]   { --fc-hover: var(--warning-bg); --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; }
.filter-chip[data-fview="contracts"] { --fc-hover: #faf5ff; --fc-color: #6d28d9; --fc-border: #e9d5ff; --fc-dot: #a855f7; }
.filter-chip[data-fview="tickets"]   { --fc-hover: #f0fdfa; --fc-color: #0f766e; --fc-border: #99f6e4; --fc-dot: #14b8a6; }

/* v110: 财务-收支类型 (3) */
.filter-chip[data-type="all"]     { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-type="expense"] { --fc-hover: var(--danger-bg); --fc-color: #b91c1c; --fc-border: #fecaca; --fc-dot: #ef4444; }
.filter-chip[data-type="income"]  { --fc-hover: var(--success-bg); --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; }

/* v110: 财务-预付款状态 (4) */
.filter-chip[data-adv-status="all"]     { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-adv-status="pending"] { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; }
.filter-chip[data-adv-status="partial"] { --fc-hover: var(--primary-bg); --fc-color: #4338ca; --fc-border: #c7d2fe; --fc-dot: #6366f1; }
.filter-chip[data-adv-status="paid"]    { --fc-hover: var(--success-bg); --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; }

/* v110: 财务-合同状态 (5) */
.filter-chip[data-ct-status="all"]        { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-ct-status="draft"]      { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-ct-status="active"]     { --fc-hover: var(--success-bg); --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; }
.filter-chip[data-ct-status="expired"]    { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; }
.filter-chip[data-ct-status="terminated"] { --fc-hover: var(--danger-bg); --fc-color: #b91c1c; --fc-border: #fecaca; --fc-dot: #ef4444; }

/* v110: 财务-发票类型 (3) */
.filter-chip[data-inv-kind="all"]     { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-inv-kind="special"] { --fc-hover: var(--danger-bg); --fc-color: #b91c1c; --fc-border: #fecaca; --fc-dot: #ef4444; }
.filter-chip[data-inv-kind="general"] { --fc-hover: var(--primary-bg); --fc-color: #4338ca; --fc-border: #c7d2fe; --fc-dot: #6366f1; }

/* ============================================================
   v495: 售后管理状态 chips 语义色板（aftersale.js STATUS_MAP 五态）
   为什么加：data-asstatus 此前无色板，5 个 chip 全同一套灰 + 同色圆点，
   待受理 / 处理中 / 已解决 / 已关闭 只能靠读文字区分。
   色相与 aftersale.js STATUS_MAP 的徽章语义严格一一对应
   （琥珀 = badge-warning 待受理；蓝 = badge-info 处理中；
     绿 = badge-success 已解决；中性灰 = badge-gray 已关闭），
   所以「工单状态列徽章」与「筛选 chip」同色，一眼能对上。
   默认态即带色（彩边 + 彩字 + 彩点 + 同色计数气泡），
   选中态沿用既有 .active 实色底白字。 */
.filter-chip[data-asstatus="all"]        { --fc-hover: #f5f7fa; --fc-color: #334155; --fc-border: #cbd5e1; --fc-dot: #475569; --fc-count-bg: #e2e8f0; --fc-count-color: #334155; }
.filter-chip[data-asstatus="pending"]    { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; --fc-count-bg: #fef3c7; --fc-count-color: #92400e; }
.filter-chip[data-asstatus="processing"] { --fc-hover: #eff6ff; --fc-color: #1d4ed8; --fc-border: #bfdbfe; --fc-dot: #3b82f6; --fc-count-bg: #dbeafe; --fc-count-color: #1d4ed8; }
.filter-chip[data-asstatus="resolved"]   { --fc-hover: #ecfdf5; --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; --fc-count-bg: #d1fae5; --fc-count-color: #047857; }
.filter-chip[data-asstatus="closed"]     { --fc-hover: #f8fafc; --fc-color: #475569; --fc-border: #cbd5e1; --fc-dot: #64748b; --fc-count-bg: #e2e8f0; --fc-count-color: #475569; }
/* 售后页 hover / 选中时保持气泡本色（否则被通用规则压成灰半透明） */
.filter-chip[data-asstatus]:hover .fc-count { background: var(--fc-count-bg); color: var(--fc-count-color); }
.filter-chip[data-asstatus].active .fc-count { background: rgba(255, 255, 255, 0.3); color: #fff; }

/* ============================================================
   v494: 交付管理状态 chips 语义色板
   为什么加：data-dlstatus（交付流程）与 data-docstatus（交付材料 / 文档状态）此前
   没有色板，10 个 chip 全是同一套灰 —— 状态之间只能靠读文字区分。
   色相与 delivery.js / docs.js 的 STATUS_MAP 徽章语义严格一一对应
   （琥珀 = badge-warning 待交付 / 评审中；蓝 = badge-info 已交付 / 已归档；
     绿 = badge-success 已验收 / 已通过；红 = badge-danger 已驳回），
   所以「状态列徽章」与「筛选 chip」同色，一眼能对上。
   默认态即带色（彩边 + 彩字 + 彩点 + 同色计数气泡），选中态沿用既有 .active 实色底白字。
   ============================================================ */

/* 交付流程 5 态（delivery.js） */
.filter-chip[data-dlstatus="all"]       { --fc-hover: #f5f7fa; --fc-color: #334155; --fc-border: #cbd5e1; --fc-dot: #475569; --fc-count-bg: #e2e8f0; --fc-count-color: #334155; }
.filter-chip[data-dlstatus="planned"]   { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; --fc-count-bg: #fef3c7; --fc-count-color: #92400e; }
.filter-chip[data-dlstatus="delivered"] { --fc-hover: #eff6ff; --fc-color: #1d4ed8; --fc-border: #bfdbfe; --fc-dot: #3b82f6; --fc-count-bg: #dbeafe; --fc-count-color: #1d4ed8; }
.filter-chip[data-dlstatus="accepted"]  { --fc-hover: #ecfdf5; --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; --fc-count-bg: #d1fae5; --fc-count-color: #047857; }
.filter-chip[data-dlstatus="rejected"]  { --fc-hover: #fef2f2; --fc-color: #b91c1c; --fc-border: #fecaca; --fc-dot: #ef4444; --fc-count-bg: #fee2e2; --fc-count-color: #b91c1c; }
/* 交付页 hover 时保持气泡彩色（否则会被通用 hover 规则压成灰半透明） */
.filter-chip[data-dlstatus]:hover .fc-count { background: var(--fc-count-bg); color: var(--fc-count-color); }

/* 文档 / 交付材料 4 态（docs.js STATUS_MAP） */
.filter-chip[data-docstatus="all"]       { --fc-hover: #f5f7fa; --fc-color: #334155; --fc-border: #cbd5e1; --fc-dot: #475569; }
.filter-chip[data-docstatus="draft"]     { --fc-hover: #f5f7fa; --fc-color: #475569; --fc-border: #cbd5e1; --fc-dot: #64748b; }
.filter-chip[data-docstatus="reviewing"] { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; }
.filter-chip[data-docstatus="approved"]  { --fc-hover: #ecfdf5; --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; }
.filter-chip[data-docstatus="archived"]  { --fc-hover: #eff6ff; --fc-color: #1d4ed8; --fc-border: #bfdbfe; --fc-dot: #3b82f6; }

/* 文档类型 5 态（docs.js TYPE_MAP 业务域色） */
.filter-chip[data-doctype="all"]      { --fc-hover: #f5f7fa; --fc-color: #334155; --fc-border: #cbd5e1; --fc-dot: #475569; }
.filter-chip[data-doctype="proposal"] { --fc-hover: #faf5ff; --fc-color: #6d28d9; --fc-border: #ddd6fe; --fc-dot: #7c3aed; }
.filter-chip[data-doctype="contract"] { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; }
.filter-chip[data-doctype="delivery"] { --fc-hover: #f0fdfa; --fc-color: #0f766e; --fc-border: #99f6e4; --fc-dot: #14b8a6; }
.filter-chip[data-doctype="other"]    { --fc-hover: #f5f7fa; --fc-color: #475569; --fc-border: #cbd5e1; --fc-dot: #64748b; }

/* v110: 团队-部门（JS 端用 fc-color-N 类轮询 5 色调，给部门身份感色彩差） */
.filter-chip.fc-color-1 { --fc-hover: var(--primary-bg); --fc-color: #4338ca; --fc-border: #c7d2fe; --fc-dot: #6366f1; }
.filter-chip.fc-color-2 { --fc-hover: #fffbeb; --fc-color: #92400e; --fc-border: #fde68a; --fc-dot: #f59e0b; }
.filter-chip.fc-color-3 { --fc-hover: #faf5ff; --fc-color: #6d28d9; --fc-border: #e9d5ff; --fc-dot: #a855f7; }
.filter-chip.fc-color-4 { --fc-hover: var(--success-bg); --fc-color: #047857; --fc-border: #a7f3d0; --fc-dot: #10b981; }
.filter-chip.fc-color-5 { --fc-hover: #ecfeff; --fc-color: #155e75; --fc-border: #a5f3fc; --fc-dot: #06b6d4; }
.filter-chip[data-dept="all"] { --fc-hover: #f5f7fa; --fc-color: #374151; --fc-border: #cbd5e1; --fc-dot: #64748b; }

.view-toggle {
  display: flex;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.view-toggle button {
  padding: 6px 12px;
  font-size: 12px;
  color: var(--gray-500);
  transition: all 0.15s;
}
.view-toggle button.active { background: var(--primary-bg); color: var(--primary); font-weight: 600; }

/* ---------- 团队成员卡片 ----------
   v467: 紧凑化重构——网格 minmax 240→168（一行 4 张 → 6~7 张）、头像 56→42、
   间距全面收紧、操作行 margin-top:auto 贴底（等高卡片），
   联系方式由竖排两行改横排一行，空值（'-'）整项不渲染（见 team.js） */
.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 12px;
}
.member-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 10px 12px;
  text-align: center;
  transition: all 0.2s;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
}
.member-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); border-color: rgba(79, 107, 237, 0.35); }
.member-card .mc-avatar { width: 42px; height: 42px; margin: 0 auto 8px; font-size: 13px; position: relative; flex: 0 0 auto; }
/* v459: 成员卡实时在线点（复用 .online-dot 脉冲动画） */
.mc-online-dot {
  position: absolute; right: 1px; bottom: 1px;
  width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid var(--card-bg); box-sizing: border-box;
  background: var(--gray-300);
}
.mc-online-dot.on { background: #10b981; animation: onlinePulse 2s ease-out infinite; }
.mc-online-dot.sm { width: 9px; height: 9px; right: -1px; bottom: -1px; border-width: 1.5px; }
.member-card .mc-name { font-size: 13px; font-weight: 600; color: var(--gray-800); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.member-card .mc-role { font-size: 11px; color: var(--text-secondary); margin-bottom: 6px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.member-card .mc-stats { display: flex; justify-content: space-around; padding-top: 8px; border-top: 1px solid var(--border-light); width: 100%; box-sizing: border-box; }
.member-card .mc-stat { text-align: center; min-width: 0; }
.member-card .mc-stat-val { font-size: 15px; font-weight: 700; color: var(--gray-800); }
.member-card .mc-stat-label { font-size: 10px; color: var(--text-tertiary); }
/* v467: 联系方式横排一行（电话 | 邮箱），各项单行省略；整块为空时由 team.js 不渲染 */
.member-card .mc-contact { display: flex; flex-direction: row; justify-content: center; flex-wrap: wrap; gap: 4px 10px; margin-bottom: 8px; font-size: 11px; color: var(--gray-600); max-width: 100%; }
.member-card .mc-phone { color: var(--primary); text-decoration: none; cursor: pointer; display: inline-flex; align-items: center; }
.member-card .mc-phone:hover { text-decoration: underline; }
.member-card .mc-phone-masked { color: var(--text-tertiary); display: inline-flex; align-items: center; }
.member-card .mc-email { color: var(--gray-500); display: inline-flex; align-items: center; min-width: 0; }
.member-card .mc-email svg, .member-card .mc-phone svg { flex: 0 0 auto; }
.member-card .mc-email, .member-card .mc-phone { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* v467: 操作行贴底——等高卡片下所有卡片的按钮基线对齐 */
.member-card .mc-actions { display: flex; gap: 6px; margin-top: auto; padding-top: 10px; width: 100%; }
.member-card .mc-actions .btn { flex: 1; min-width: 0; padding-left: 6px; padding-right: 6px; }
/* v467: 角色徽标行收紧 */
.member-card .mc-badges { margin-bottom: 6px; display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; }
.member-card .mc-badges .badge { font-size: 10px; padding: 1px 7px; }
/* v467: 未读消息联系人卡（置顶层）同步紧凑 */
.pm-msg-peer-card .pm-msg-peer-hint { font-size: 10px; }

/* ---------- 微信式聊天窗口 ---------- */
.mc-name-link { color: var(--gray-800); cursor: pointer; }
.mc-name-link:hover { color: var(--primary); }

/* v470: 头像也是对话入口——悬停放大 + 主色柔环，明确「可点」暗示（自己的头像不挂此类，无任何可点反馈） */
.member-card .mc-avatar.mc-avatar-link,
td .user-avatar.mc-avatar-link { cursor: pointer; transition: transform .16s ease, box-shadow .16s ease; }
.member-card .mc-avatar.mc-avatar-link:hover,
td .user-avatar.mc-avatar-link:hover { transform: scale(1.08); box-shadow: 0 0 0 3px rgba(79, 107, 237, 0.18); }

/* v470: 自己的成员卡——姓名旁「我」标记，解释为何不可点（替代聊天气泡） */
.mc-self-tag { display: inline-block; margin-left: 4px; padding: 0 5px; font-size: 10px; font-weight: 700; line-height: 15px; color: var(--primary); background: rgba(79, 107, 237, 0.12); border-radius: 999px; vertical-align: 1px; }

/* 聊天 modal：窄高布局 */
.modal.chat-modal { max-width: 480px; width: 92vw; }
.modal.chat-modal .modal-body { padding: 0; overflow: hidden; }

.chat-window { display: flex; flex-direction: column; height: 100%; }

.chat-header {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border-light);
  background: var(--gray-50, #f8f9fb);
  flex-shrink: 0;
}

.chat-body {
  height: 380px;
  overflow-y: auto;
  padding: 16px;
  background: var(--bg);
  display: flex; flex-direction: column; gap: 14px;
}

.chat-empty {
  margin: auto; font-size: 12px; color: var(--text-tertiary);
  text-align: center; padding: 30px 0;
}

.chat-msg { display: flex; gap: 8px; align-items: flex-start; }
.chat-msg .user-avatar.xs { flex-shrink: 0; margin-top: 2px; }
.chat-msg .chat-bubble-wrap { max-width: 72%; min-width: 0; }

.chat-bubble {
  padding: 8px 12px;
  border-radius: 2px 12px 12px 12px;
  background: var(--card-bg);
  border: 1px solid var(--border-light);
  font-size: 13px; color: var(--gray-800);
  line-height: 1.6;
  word-break: break-word;
  white-space: pre-wrap;
}

.chat-msg.mine { flex-direction: row-reverse; }
.chat-msg.mine .chat-bubble-wrap { display: flex; flex-direction: column; align-items: flex-end; }
.chat-msg.mine .chat-bubble {
  background: var(--primary, #4f6bed);
  border-color: var(--primary, #4f6bed);
  color: #fff;
  border-radius: 12px 2px 12px 12px;
}

.chat-time { font-size: 10px; color: var(--text-tertiary); margin-top: 4px; padding: 0 4px; }

.chat-input {
  display: flex; gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--border-light);
  background: var(--card-bg);
  flex-shrink: 0;
}
.chat-input .form-input { height: 38px; }

/* ---------- 数据表格 ---------- */
.data-table { border-collapse: collapse; font-size: 13px; }
.data-table thead th { padding: 10px 12px; text-align: left; font-size: 12px; font-weight: 600; color: var(--text-tertiary); border-bottom: 2px solid var(--border); white-space: nowrap; background: var(--gray-50, #f8f9fb); }
.data-table tbody td { padding: 10px 12px; border-bottom: 1px solid var(--border-light); vertical-align: middle; }
.data-table tbody tr:hover { background: var(--primary-bg, #eef2ff); }
.data-table a[href^="tel:"]:hover { text-decoration: underline; }

/* ---------- 报表 ---------- */
.report-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
  gap: 16px;
}
.legend-list { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.legend-item { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--gray-600); }
.legend-dot { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }

/* ---------- v129 后台管理重排 ---------- */
.admin-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 20px;
  padding: 5px;
  background: var(--gray-100);
  border: 1px solid var(--border-light);
  border-radius: 12px;
  border-bottom: none;
  width: fit-content;
  max-width: 100%;
}
/* v380.1: 圆角 8→10 + 字号 13→14 + height 32→34 与 filter-chip 统一;字间距 0.3px + 字重 500→600;active 加边框 + 厚重阴影 */
.admin-tab {
  height: 34px;
  padding: 0 14px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: var(--gray-700);
  border: 1px solid transparent;
  background: transparent;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  transition: all var(--dur-fast) var(--ease);
  margin-bottom: 0;
  white-space: nowrap;
}
.admin-tab svg { width: 15px; height: 15px; flex-shrink: 0; opacity: 0.65; transition: opacity 0.15s; }
.admin-tab:hover {
  color: var(--gray-800);
  background: rgba(255,255,255,0.6);
  transform: translateY(-1px);
}
.admin-tab:hover svg { opacity: 0.9; }
.admin-tab.active {
  color: var(--primary);
  background: var(--card-bg);
  font-weight: 700;
  border-color: var(--border);
  box-shadow: 0 6px 14px rgba(79, 107, 237, 0.16);
}
.admin-tab.active svg { opacity: 1; }
[data-theme='dark'] .admin-tab:hover { background: rgba(255,255,255,0.06); }
[data-theme='dark'] .admin-tab.active { box-shadow: 0 1px 2px rgba(0,0,0,0.3), 0 0 0 1px rgba(79,107,237,0.35); }

/* v129 hero 卡头 */
.admin-hero {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 20px;
  margin-bottom: 16px;
  background: linear-gradient(135deg, var(--card-bg) 0%, var(--gray-50) 100%);
  border: 1px solid var(--border-light);
  border-radius: 12px;
}
[data-theme='dark'] .admin-hero { background: linear-gradient(135deg, var(--card-bg) 0%, var(--gray-800) 100%); }
.admin-hero-icon {
  width: 40px; height: 40px;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--primary) 0%, #7c93f5 100%);
  color: white;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  box-shadow: 0 2px 6px rgba(79,107,237,0.25);
}
.admin-hero-icon svg { width: 20px; height: 20px; }
.admin-hero-text { flex: 1; min-width: 0; }
.admin-hero-text h3 { margin: 0 0 3px; font-size: 15px; font-weight: 600; color: var(--gray-900); }
.admin-hero-text p { margin: 0; font-size: 12px; color: var(--text-tertiary); }
.admin-hero-actions { display: flex; gap: 8px; flex-shrink: 0; align-items: center; }

/* v130 后台设置分类区块 */
.admin-cats { display: flex; flex-direction: column; gap: 28px; }
.admin-cat { display: flex; flex-direction: column; gap: 14px; }
.admin-cat-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 0 12px;
  border-bottom: 1px solid var(--border-light);
}
.admin-cat-icon {
  width: 36px; height: 36px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center; justify-content: center;
  color: #fff;
  flex-shrink: 0;
  box-shadow: 0 2px 6px rgba(0,0,0,0.08);
}
.admin-cat-icon svg { width: 18px; height: 18px; }
.admin-cat-title { font-size: 16px; font-weight: 700; color: var(--gray-800); letter-spacing: -0.01em; }
.admin-cat-count {
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 11px;
  background: var(--gray-100);
  color: var(--text-tertiary);
}
[data-theme='dark'] .admin-cat-count { background: var(--gray-800); }
.admin-cat-desc { font-size: 12px; color: var(--text-tertiary); margin-left: auto; }

/* v137 满宽单卡：单卡 section 占满整行（避免右侧空白） */
.admin-cat-full { grid-template-columns: 1fr !important; }
.admin-cat-full > .card { display: flex; flex-direction: column; }
.admin-cat-full .card-body { flex: 1; }

/* v137 系统设置独立页 hero 头部 */
.settings-hero {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 22px 26px;
  margin-bottom: 28px;
  background: linear-gradient(135deg, #4f6bed 0%, #6366f1 50%, #8b5cf6 100%);
  border-radius: 14px;
  color: #fff;
  box-shadow: 0 8px 24px rgba(79, 107, 237, 0.22);
  position: relative;
  overflow: hidden;
}
.settings-hero::after {
  content: '';
  position: absolute;
  right: -40px; top: -40px;
  width: 180px; height: 180px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,0.18) 0%, transparent 70%);
  pointer-events: none;
}
.settings-hero-icon {
  width: 52px; height: 52px;
  border-radius: 12px;
  background: rgba(255,255,255,0.18);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,0.25);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.settings-hero-icon svg { width: 26px; height: 26px; stroke: #fff; }
.settings-hero-text { flex: 1; min-width: 0; position: relative; z-index: 1; }
.settings-hero-text h2 { margin: 0 0 4px; font-size: 20px; font-weight: 700; letter-spacing: -0.01em; }
.settings-hero-text p { margin: 0; font-size: 13px; opacity: 0.88; line-height: 1.5; }
.settings-hero-stats {
  display: flex; gap: 10px; flex-shrink: 0;
  position: relative; z-index: 1;
}
.settings-hero-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  background: rgba(255,255,255,0.18);
  border: 1px solid rgba(255,255,255,0.25);
  border-radius: 18px;
  font-size: 12px;
  font-weight: 500;
  backdrop-filter: blur(8px);
}
.settings-hero-chip svg { width: 14px; height: 14px; }
@media (max-width: 720px) {
  .settings-hero { flex-wrap: wrap; }
  .settings-hero-stats { width: 100%; }
}

/* v137 系统设置底部状态条 */
.settings-footer {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 20px;
  padding: 12px 18px;
  background: var(--card-bg);
  border: 1px solid var(--border-light);
  border-radius: 10px;
  font-size: 12px;
  color: var(--text-tertiary);
}
.settings-footer-left { display: inline-flex; align-items: center; gap: 8px; }
.settings-footer-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #10b981;
  box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.18);
  flex-shrink: 0;
}
.settings-footer-version { font-weight: 600; color: var(--text-secondary); }

/* v129 后台设置双列网格 */
.admin-settings-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
}
.admin-settings-grid > .card { margin-top: 0 !important; }
@media (max-width: 1100px) {
  .admin-settings-grid { grid-template-columns: 1fr; }
}

/* v129 系统信息/数据迁移 紧凑网格（v198: 3 列 → 2 列自适应，配更大信息瓦片）
   v198 修复：深色主题原覆盖 gray-800（反转为浅色）导致瓦片变浅底、info-value 同色不可见——
   现统一用自适应变量（gray-50 双主题均为表面色；value 用 --text 双主题均为正文色） */
.admin-info-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  font-size: 13px;
}
@media (max-width: 480px) {
  .admin-info-grid { grid-template-columns: 1fr; }
}
.admin-info-grid > div {
  padding: 10px 12px;
  background: var(--gray-50);
  border-radius: 8px;
  transition: background .15s ease;
}
.admin-info-grid > div:hover { background: var(--primary-bg); }
.admin-info-grid .info-label { font-size: 11px; color: var(--text-tertiary); margin-bottom: 4px; }
.admin-info-grid .info-value { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.admin-info-grid .info-value.ok { color: var(--success); } /* v198: 云端已连接等正向状态 */

/* v129 用户管理操作列精简 */
.admin-user-actions {
  display: inline-flex;
  gap: 2px;
  justify-content: flex-end;
  align-items: center;
}
.admin-icon-btn {
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent;
  background: transparent;
  border-radius: 6px;
  color: var(--gray-500);
  cursor: pointer;
  transition: all 0.12s;
}
.admin-icon-btn:hover { background: var(--gray-100); color: var(--gray-800); }
.admin-icon-btn.primary { color: var(--primary); }
.admin-icon-btn.primary:hover { background: rgba(79,107,237,0.10); }
.admin-icon-btn.danger:hover { background: rgba(239,68,68,0.10); color: var(--danger); }
.admin-icon-btn svg { width: 15px; height: 15px; }
[data-theme='dark'] .admin-icon-btn:hover { background: rgba(255,255,255,0.08); color: var(--gray-100); }

/* v129 卡片顶部带图标 */
.admin-card-icon {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 24px; height: 24px;
  border-radius: 6px;
  background: var(--primary-light, rgba(79,107,237,0.10));
  color: var(--primary);
  margin-right: 8px;
  vertical-align: middle;
}
.admin-card-icon svg { width: 14px; height: 14px; }

.permission-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 8px;
}
.permission-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--gray-600);
}

/* ---------- 工具类 ---------- */
.text-primary { color: var(--primary); }
.text-success { color: var(--success); }
.text-warning { color: var(--warning); }
.text-danger { color: var(--danger); }
.text-muted { color: var(--text-tertiary); }
.text-center { text-align: center; }
.text-right { text-align: right; }
.fw-600 { font-weight: 600; }
.fw-700 { font-weight: 700; }
.flex { display: flex; }
.flex-1 { flex: 1; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-8 { gap: 8px; }
.gap-12 { gap: 12px; }
.gap-16 { gap: 16px; }
.mt-8 { margin-top: 8px; }
.mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; }
.mt-24 { margin-top: 24px; }
.mb-8 { margin-bottom: 8px; }
.mb-12 { margin-bottom: 12px; }
.mb-16 { margin-bottom: 16px; }
.mb-24 { margin-bottom: 24px; }
.w-full { width: 100%; }
.cursor-pointer { cursor: pointer; }
.no-data { padding: 40px; text-align: center; color: var(--text-tertiary); font-size: 13px; }

/* ---------- 响应式 ---------- */
/* v72: 移动端完整适配（平板竖屏及以下） */
@media (max-width: 768px) {
  /* 侧边栏抽屉化 */
  .sidebar {
    position: fixed; left: 0; top: 0;
    height: 100%;
    width: var(--sidebar-w) !important;   /* 抽屉模式忽略折叠态宽度 */
    transform: translateX(-100%);
    transition: transform 0.25s;
    z-index: 200;
    box-shadow: var(--shadow-lg);
  }
  .app-layout.sidebar-mobile-open .sidebar { transform: translateX(0); }
  /* 抽屉模式忽略桌面折叠态（sidebar-collapsed）的隐藏文字效果 */
  .app-layout.sidebar-collapsed .sidebar .nav-item { justify-content: flex-start; padding: 12px; }
  .app-layout.sidebar-collapsed .sidebar .nav-item span { opacity: 1; width: auto; overflow: visible; }
  .app-layout.sidebar-collapsed .sidebar .logo-text { opacity: 1; width: auto; }
  .app-layout.sidebar-collapsed .sidebar .nav-group-label { opacity: 1; height: auto; padding: 0 10px 8px; }
  .app-layout.sidebar-collapsed .sidebar .user-info { display: block; }
  .app-layout.sidebar-collapsed .sidebar .btn-exit { display: flex; }
  .app-layout.sidebar-collapsed .sidebar .sidebar-footer { padding: 12px; }

  /* 顶栏：显示汉堡按钮 */
  .mobile-menu-btn { display: flex; }
  .search-box { display: none; }
  .topbar-username { display: none; }
  .topbar { padding: 0 12px; }
  .page-title { font-size: 16px; }
  .topbar-left { gap: 8px; min-width: 0; }

  /* 内容区紧凑化 */
  .content { padding: 12px; }
  .card-body { padding: 14px; }
  .card-header { padding: 12px 14px; flex-wrap: wrap; gap: 8px; }

  /* 统计卡：平板/大手机 2 列（超窄屏再降 1 列） */
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .stat-card { padding: 14px; }
  .stat-card .stat-icon { width: 36px; height: 36px; }
  .stat-card .stat-icon svg { width: 18px; height: 18px; }

  /* 表单：iOS 聚焦输入框字号 ≥16px 防自动缩放；行内表单改纵向 */
  .form-input, .form-select, .form-textarea { font-size: 16px; }
  .form-row { flex-direction: column; gap: 0; }
  .login-input { font-size: 16px; } /* v78: 登录输入框同样防 iOS 缩放 */
  .login-btn { min-height: 46px; }

  /* 弹窗：接近全宽，高度受限 */
  .modal { width: 94vw; max-width: 94vw; max-height: 88vh; max-height: 88dvh; }
  .modal.fp-modal { width: 94vw; max-width: 94vw; } /* v78: 覆盖桌面 860px */
  .modal.wide { max-width: 94vw; }
  .modal-header { padding: 14px 16px; }
  .modal-body { padding: 16px; }
  .modal-footer { padding: 12px 16px; }
  .modal-footer .btn { min-height: 40px; } /* v72: 触摸目标 ≥40px */

  /* 表格：紧凑行高，操作列不换行 */
  .table th, .table td { padding: 10px 12px; }
  .table { font-size: 12px; }

  /* 项目卡片 / 看板 */
  .project-grid { grid-template-columns: 1fr; }
  .kanban-column { min-width: 240px; }

  /* 触摸目标加大 */
  .nav-item { padding: 12px 12px; }
  /* v380.1: 触摸目标 ≥40px;基线 height:34 移动端 height:40 + padding 0 14px + 字号 14 触摸友好 */
  .filter-chip { height: 40px; padding: 0 14px 0 14px; font-size: 14px; }
  .btn { min-height: 38px; }
  .btn-sm { min-height: 34px; }

  /* v78: iOS 安全区（viewport-fit=cover 刘海/底部横条） */
  .topbar { padding-top: env(safe-area-inset-top, 0px); }
  .sidebar { padding-bottom: env(safe-area-inset-bottom, 0px); }
  .content { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  .modal-footer { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }

  /* v78: 惯性滚动（旧 iOS）+ 聊天弹窗全屏化 */
  .gantt-wrap, .modal-body, .kanban-board { -webkit-overflow-scrolling: touch; }
  .modal.chat-modal { width: 96vw; max-height: 92vh; max-height: 92dvh; height: 92vh; height: 92dvh; }
  .modal.chat-modal .modal-body { display: flex; flex-direction: column; }
  .modal.chat-modal .chat-body { flex: 1; height: auto; min-height: 0; }

  /* v73: 登录左右分栏在手机堆叠为单列（左上、下表单） */
  .login-screen { flex-direction: column; }
  .login-pane-left {
    flex: 0 0 auto;
    padding: 32px 24px 28px;
  }
  .login-brand-mark { margin-bottom: 18px; }
  /* v197: 移动端 LOGO 相应缩小 */
  .login-brand-logo { height: 44px; max-width: 200px; margin-bottom: 14px; }
  .login-brand-name { font-size: 32px; letter-spacing: 5px; }
  .login-brand-tagline { font-size: 11px; }
  .login-brand-quote { display: none; } /* 移动端精简 */
  .login-copyright { display: none; }
  /* v195: ICP 移动端保留展示（备案号合规要求全终端可见；fixed 底部居中不占布局空间） */
  .login-pane-right {
    flex: 1 1 auto; padding: 32px 24px;
  }
  .login-card { max-width: none; }
  .login-title { font-size: 22px; }
}
@media (max-width: 380px) {
  .login-pane-left { padding: 24px 20px 20px; }
  .login-pane-right { padding: 24px 20px; }
}

/* v72: 超窄手机（iPhone SE 等 ≤480px）：统计卡降为单列 */
@media (max-width: 480px) {
  .stat-grid { grid-template-columns: 1fr; }
  .page-title { font-size: 15px; }
  .content { padding: 10px; }
}

/* ---------- 角色拖拽排序 ---------- */
.role-item:hover { background: var(--gray-50); }
.role-item:active { cursor: grabbing; }

/* ---------- 角色权限 - 上下排列布局 ---------- */
/* 角色卡片 */
.role-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-radius: 8px;
  background: var(--gray-50);
  margin-bottom: 8px;
  border-left: 4px solid var(--gray-400);
  transition: box-shadow 0.15s, transform 0.1s;
}
.role-card:hover {
  box-shadow: var(--shadow-sm);
  transform: translateX(2px);
}
.role-card:last-child { margin-bottom: 0; }

.role-card-avatar {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: 700;
}
.role-card-body { flex: 1; min-width: 0; }
.role-card-title { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.role-card-desc { font-size: 12px; color: var(--text-tertiary); }
/* v108: 卡片与矩阵同源联动的动态摘要行 */
.role-card-live { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; margin: 3px 0 4px; }
.role-card-live-label { font-size: 11px; color: var(--gray-400); }
.role-card-mod {
  font-size: 11px;
  line-height: 1.5;
  padding: 1px 7px;
  border: 1px solid;
  border-radius: 10px;
  white-space: nowrap;
}
.role-card-dev {
  font-size: 11px;
  color: #d97706;
  background: rgba(245, 158, 11, 0.12);
  border: 1px solid rgba(245, 158, 11, 0.35);
  border-radius: 10px;
  padding: 1px 8px;
  white-space: nowrap;
}
.role-card-ok {
  font-size: 11px;
  color: #059669;
  background: rgba(16, 185, 129, 0.1);
  border: 1px solid rgba(16, 185, 129, 0.3);
  border-radius: 10px;
  padding: 1px 8px;
  white-space: nowrap;
}
/* v108: 「⌖ 定位」激活时的卡片高亮 */
.role-card.role-card-focus {
  box-shadow: 0 0 0 2px rgba(79, 107, 237, 0.35), 0 2px 10px rgba(79, 107, 237, 0.12);
}
.role-card-stats { font-size: 12px; color: var(--gray-500); display: flex; align-items: center; gap: 10px; }
.role-card-stats b { color: var(--gray-700); font-weight: 600; }
.role-card-sep { color: var(--border); }
.role-card-bar {
  margin-top: 6px;
  height: 4px;
  background: var(--gray-200);
  border-radius: 2px;
  overflow: hidden;
}
.role-card-bar-fill {
  height: 100%;
  border-radius: 2px;
  transition: width 0.3s ease;
}
.role-card-pct {
  flex-shrink: 0;
  font-size: 20px;
  font-weight: 700;
  min-width: 48px;
  text-align: right;
}

/* 权限矩阵 */
.perm-matrix {
  width: 100%;
  table-layout: fixed;
}
.perm-matrix > thead > tr > th:first-child {
  text-align: left;
  padding-left: 16px !important;
  font-size: 12px;
  color: var(--text-tertiary);
  font-weight: 600;
}

/* 权限矩阵表头 */
.perm-matrix th.perm-col-head {
  text-align: center;
  vertical-align: bottom;
  padding: 10px 4px !important;
  border-bottom: 2px solid var(--border) !important;
}
.perm-matrix .perm-col-toggle {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 4px 2px; border-radius: 6px;
  transition: background 0.15s;
}
.perm-matrix .perm-col-toggle:hover { background: var(--gray-50); }
.perm-col-avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
}
.perm-col-name { font-size: 11px; color: var(--gray-600); font-weight: 500; }

/* v69: 权限矩阵增强 —— 图例 / 说明 / 高危徽标 / 列头计数 / 模块计数 / 角色卡操作 */
.perm-legend {
  display: flex; align-items: center; gap: 18px;
  font-size: 12px; color: var(--gray-500); flex-wrap: wrap;
}
.perm-legend > span { display: inline-flex; align-items: center; gap: 4px; }
.perm-risk-badge {
  display: inline-block;
  font-size: 10px; font-weight: 600; color: #dc2626;
  background: #fee2e2; border: 1px solid #fecaca;
  border-radius: 3px; padding: 0 4px; line-height: 16px;
  vertical-align: 1px;
}
.perm-name-cell { min-width: 0; }
.perm-desc-text { font-size: 11px; color: var(--text-tertiary); margin-top: 2px; line-height: 1.3; }
.perm-col-text { display: flex; flex-direction: column; align-items: center; gap: 2px; min-width: 0; }
.perm-col-count { font-size: 10px; color: var(--text-tertiary); }
.perm-module-count { font-size: 11px; color: var(--text-tertiary); margin-left: 8px; }
.role-card-side { display: flex; align-items: center; gap: 10px; }
.role-card-actions { display: flex; flex-direction: column; gap: 4px; }
.role-card-actions .btn-ghost { font-size: 11px; padding: 2px 8px; white-space: nowrap; }

/* 权限矩阵模块分组行 */
.perm-module-row td {
  background: linear-gradient(to right, var(--gray-50), transparent) !important;
  padding: 8px 14px !important;
  border-top: 1px solid var(--border-light) !important;
  border-bottom: 1px solid var(--border-light) !important;
}
.perm-module-tag {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; color: var(--gray-700);
}
.perm-module-tag::before {
  content: ''; width: 4px; height: 12px; background: var(--primary);
  border-radius: 2px;
}

/* 权限矩阵单元格 */
.perm-matrix tbody tr:not(.perm-module-row) td {
  padding: 6px 12px !important;
}
.perm-matrix tbody tr:not(.perm-module-row):hover {
  background: rgba(0,0,0,0.015);
}
.perm-name-text { font-size: 13px; color: var(--gray-700); }
.perm-cell {
  text-align: center;
  cursor: pointer;
  padding: 10px 4px !important;
  transition: all 0.15s;
  position: relative;
}
.perm-cell > svg { display: inline-block; vertical-align: middle; transition: transform 0.15s; }
.perm-cell:hover > svg { transform: scale(1.15); }
.perm-cell:hover { filter: brightness(0.97); }

/* v106: 仅 tbody 表格行区域独立可滚，工具栏/图例/列头全部脱离滚动容器禁止滚动
   v107: max-height 仅为无 JS 兜底；admin.js fitPermScroller() 按实际顶部位置
   动态设 height + maxHeight:none，让表格区精确填满剩余一屏 */
.perm-table-scroller {
  max-height: calc(100vh - 280px);
  min-height: 360px;
  overflow-y: auto;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* 红色细边框明确视觉边界（用户原话「红色区域可上下滚动，红色区外禁止」） */
  border: 1.5px solid rgba(239, 68, 68, 0.22);
  border-radius: 8px;
  margin: 8px 16px 16px;
  background: var(--card-bg, #fff);
  box-shadow: inset 0 0 0 1px rgba(239, 68, 68, 0.04);
}
.perm-table-scroller .perm-matrix { margin: 0; }
/* v106: 表格 thead 角色列头在 scroller 容器内 sticky top:0
   注意：浏览器对 <thead> 自身 position:sticky 支持不一致，
   改给 thead 内的 <tr> 元素加 sticky（th 自动跟随） */
.perm-table-scroller .perm-matrix thead tr {
  position: sticky;
  top: 0;
  z-index: 8;
}
.perm-table-scroller .perm-matrix thead th {
  background: var(--card-bg, #fff);
  box-shadow: 0 1px 0 var(--border-light);
  /* 移除 th 自身 sticky，由 tr 撑起 */
}
/* 模块分组行跟随滚动，但加浅底色强化分组边界 */
.perm-table-scroller .perm-module-row td {
  background: linear-gradient(180deg, #fafbff 0%, #f6f8fc 100%);
}
/* 滚动条染色暗示「这是可滚动区」 */
.perm-table-scroller::-webkit-scrollbar { width: 10px; height: 10px; }
.perm-table-scroller::-webkit-scrollbar-track { background: rgba(239, 68, 68, 0.04); border-radius: 5px; }
.perm-table-scroller::-webkit-scrollbar-thumb { background: rgba(239, 68, 68, 0.32); border-radius: 5px; }
.perm-table-scroller::-webkit-scrollbar-thumb:hover { background: rgba(239, 68, 68, 0.5); }

@media (max-width: 768px) {
  .perm-table-scroller { max-height: none; min-height: 0; }
}


/* ---------- v104: 权限矩阵丰富 + 可视化 ---------- */
/* 概览瓦片条 */
.perm-stat-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 16px;
}
.perm-stat-tile {
  display: flex; align-items: center; gap: 12px;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border-light);
  border-radius: 10px;
  padding: 14px 16px;
  position: relative;
  overflow: hidden;
}
.perm-stat-tile::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--primary);
}
.perm-stat-tile.pst-ok::before { background: #10b981; }
.perm-stat-tile.pst-warn::before { background: #f59e0b; }
.pst-icon {
  width: 38px; height: 38px; border-radius: 9px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px;
}
.pst-value { font-size: 21px; font-weight: 700; color: var(--gray-800); line-height: 1.15; }
.pst-label { font-size: 11.5px; color: var(--text-tertiary); margin-top: 2px; }

/* 操作类型徽标 */
.perm-act-badge {
  display: inline-block;
  font-size: 10px; font-weight: 600;
  border-radius: 4px; padding: 0 5px; line-height: 16px;
  margin-right: 6px; vertical-align: 1px;
  border: 1px solid transparent;
}
.perm-act-badge.act-view    { color: #2563eb; background: #eff6ff; border-color: #bfdbfe; }
.perm-act-badge.act-edit    { color: #059669; background: #ecfdf5; border-color: #a7f3d0; }
.perm-act-badge.act-delete  { color: #dc2626; background: #fef2f2; border-color: #fecaca; }
.perm-act-badge.act-approve { color: #7c3aed; background: #f5f3ff; border-color: #ddd6fe; }
.perm-act-badge.act-admin   { color: #d97706; background: #fffbeb; border-color: #fde68a; }
.perm-act-badge.act-comm    { color: #0891b2; background: #ecfeff; border-color: #a5f3fc; }

/* 高危筛选 chip */
.perm-chip {
  font-size: 12px; font-weight: 600;
  color: #dc2626; background: #fff; border: 1px solid #fecaca;
  border-radius: 999px; padding: 3px 12px; cursor: pointer;
  transition: all 0.15s;
}
.perm-chip:hover { background: #fef2f2; }
.perm-chip.active { background: #dc2626; color: #fff; border-color: #dc2626; }

/* 列头覆盖率迷你条 */
.perm-col-bar {
  display: block; width: 44px; height: 4px;
  background: rgba(0,0,0,0.06); border-radius: 2px;
  overflow: hidden; margin-top: 2px;
}
.perm-col-bar i { display: block; height: 100%; border-radius: 2px; transition: width 0.3s; }
.perm-col-toggle.col-hl { background: rgba(0,0,0,0.04); }

/* 模块行：图标 + 覆盖率热力条 + 默认按钮 */
.perm-module-inner {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.perm-module-ico {
  width: 22px; height: 22px; border-radius: 6px; font-size: 12px;
  display: inline-flex; align-items: center; justify-content: center;
}
.perm-module-tag { font-weight: 700; }
.perm-mod-cov { display: inline-flex; gap: 3px; margin-left: 10px; align-items: center; }
.pmc-bar {
  display: inline-block; width: 16px; height: 5px;
  border-radius: 2.5px; overflow: hidden; cursor: default;
}
.pmc-bar i { display: block; height: 100%; transition: width 0.3s; }
.perm-mod-reset {
  margin-left: auto;
  font-size: 11px; font-weight: 600;
  color: var(--text-tertiary); background: transparent;
  border: 1px solid var(--border-light); border-radius: 6px;
  padding: 2px 9px; cursor: pointer; transition: all 0.15s;
}
.perm-mod-reset:hover { color: var(--primary); border-color: var(--primary); background: rgba(79,107,237,0.05); }

/* 已授权单元格胶囊 */
.perm-cell { padding: 7px 4px !important; }
.perm-pill {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 20px;
  border-radius: 6px; border: 1px solid;
  transition: transform 0.15s, box-shadow 0.15s;
}
.perm-cell:hover .perm-pill { transform: scale(1.12); box-shadow: 0 2px 6px rgba(0,0,0,0.12); }
.perm-cell.granted { background: rgba(0,0,0,0.012); }

/* v104: 悬停整列高亮（十字定位） */
.perm-cell.col-hl { background: rgba(79,107,237,0.07) !important; box-shadow: inset 0 0 0 1px rgba(79,107,237,0.18); }
/* v108: 「⌖ 定位」整列钉住高亮（独立于悬停 col-hl，悬停离开不会误清） */
.perm-cell.col-focus { background: rgba(79,107,237,0.12) !important; box-shadow: inset 0 0 0 1.5px rgba(79,107,237,0.3); }
.perm-col-toggle.col-focus { background: rgba(79,107,237,0.08); border-radius: 6px; }

/* v104: 移动端瓦片 2 列 */
@media (max-width: 768px) {
  .perm-stat-strip { grid-template-columns: repeat(2, 1fr); }
  .perm-mod-cov { display: none; }
}
.role-item.dragging { opacity: 0.4; }

/* ---------- 项目分类拖拽排序 ---------- */
.cat-item { cursor: grab; transition: background 0.15s; }
.cat-item:hover { background: var(--gray-50); }
.cat-item:active { cursor: grabbing; }
.cat-item.dragging { opacity: 0.4; }

/* ---------- 站内消息 ---------- */
.msg-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-light);
  cursor: pointer;
  transition: background 0.15s;
}
.msg-item:last-child { border-bottom: none; }
.msg-item:hover { background: var(--gray-50, #f8f9fb); }
.msg-item.unread { background: rgba(79, 107, 237, 0.04); }
.msg-item.unread:hover { background: rgba(79, 107, 237, 0.08); }
.msg-unread-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #4f6bed;
  flex-shrink: 0;
  margin-top: 8px;
}

/* ---------- 任务详情编辑弹窗 ---------- */
.task-form { display: flex; flex-direction: column; gap: 18px; }
.task-form-section {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px 18px;
  background: var(--card-bg);
}
.task-form-section-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--gray-800);
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border-light);
  display: flex;
  align-items: center;
  gap: 6px;
}

/* 负责人多选 chips */
.assignee-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.assignee-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px 5px 4px;
  border: 1px solid var(--border);
  border-radius: 24px;
  cursor: pointer;
  transition: all 0.15s;
  background: var(--card-bg);
  font-size: 13px;
  color: var(--gray-600);
}
.assignee-chip:hover { border-color: var(--gray-300); background: var(--gray-50); }
.assignee-chip.selected {
  border-color: var(--primary);
  background: var(--primary-bg);
  color: var(--primary);
  font-weight: 600;
}
.assignee-chip .assignee-check {
  color: var(--primary);
  font-weight: 700;
  font-size: 14px;
  margin-left: 2px;
}

/* 票务卡片 */
.ticket-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 6px;
  margin-bottom: 8px;
  transition: background 0.15s;
}
.ticket-card:hover { background: var(--gray-50); }
.ticket-card-info { flex: 1; min-width: 0; }
.ticket-card-title { font-size: 13px; font-weight: 500; color: var(--gray-700); }
.ticket-card-meta { font-size: 11px; color: var(--text-tertiary); margin-top: 2px; }
.ticket-card-amount {
  font-size: 15px;
  font-weight: 700;
  color: var(--gray-800);
  white-space: nowrap;
}
.ticket-add-form {
  border: 1px dashed var(--border);
  border-radius: 8px;
  padding: 14px;
  margin-top: 12px;
  background: var(--gray-50);
}

/* ===== v38 合同附件上传 + 自动识别填充 ===== */
.ct-upload-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  min-width: 0;
}
.ct-parse-status {
  font-size: 12px;
  color: var(--gray-500);
}
.ct-file-list {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.ct-file-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  background: var(--gray-50);
  border: 1px solid var(--border);
  border-radius: 8px;
  min-width: 0;
}
.ct-file-name {
  font-size: 13px;
  color: var(--gray-700);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
.ct-file-size {
  font-size: 11px;
  color: var(--gray-400);
  white-space: nowrap;
}
.ct-file-remove {
  border: none;
  background: none;
  color: var(--gray-400);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 4px;
}
.ct-file-remove:hover {
  color: var(--danger);
  background: var(--gray-100);
}
.ct-attach-badge {
  display: inline-block;
  font-size: 11px;
  color: var(--gray-500);
  background: var(--gray-100);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1px 6px;
  margin-left: 6px;
  vertical-align: middle;
  cursor: pointer;
}
.ct-attach-badge:hover {
  color: var(--primary);
  border-color: var(--primary);
  background: rgba(59, 130, 246, 0.08);
}
.form-input.auto-filled {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
  transition: box-shadow 0.3s;
}

/* ---- v39 附件在线预览 ---- */
.ct-file-preview-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
}
.ct-file-preview-btn:hover .ct-file-name {
  color: var(--primary);
}
.fp-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 18px 12px 18px;
  border-bottom: 1px solid var(--border);
  min-width: 0;
}
.fp-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--gray-800);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
.fp-size {
  font-size: 11px;
  color: var(--gray-400);
  white-space: nowrap;
}
.fp-close {
  border: none;
  background: none;
  color: var(--gray-400);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 8px;
  border-radius: 4px;
}
.fp-close:hover {
  color: var(--danger);
  background: var(--gray-100);
}
/* v396: 预览器头部「下载」按钮 —— 所有格式统一导出入口 */
.fp-dl-btn {
  white-space: nowrap;
  font-weight: 600;
}
.fp-dl-btn:hover {
  transform: translateY(-1px);
}
/* v396: 不可在线渲染格式的文件信息预览卡 */
.fp-filecard {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 320px;
  padding: 48px 24px;
  text-align: center;
}
.fp-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 14px 18px;
}
.fp-frame {
  width: 100%;
  height: 100%;
  min-height: 60vh;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--gray-50);
}
.fp-img {
  max-width: 100%;
  max-height: 70vh;
  display: block;
  margin: 0 auto;
  border-radius: 8px;
  border: 1px solid var(--border);
}
/* v219: 附件预览器小视频播放器 */
.fp-video {
  max-width: 100%;
  max-height: 70vh;
  display: block;
  margin: 0 auto 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: #000;
}
.fp-text {
  white-space: pre-wrap;
  word-break: break-all;
  font-family: inherit;
  font-size: 13px;
  line-height: 1.8;
  color: var(--gray-700);
  margin: 0;
}
.fp-msg {
  padding: 48px 24px;
  text-align: center;
  color: var(--gray-400);
  font-size: 13px;
  line-height: 1.8;
}
/* v392: Excel/WPS 表格在线预览（SheetJS sheet_to_html 渲染） */
.fp-xlsx-preview {
  overflow: auto;
  max-height: 68vh;
}
.fp-xlsx-sheet {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-700);
  margin: 12px 0 6px;
}
.fp-xlsx-preview table {
  border-collapse: collapse;
  margin-bottom: 8px;
}
.fp-xlsx-preview td {
  border: 1px solid var(--gray-200);
  padding: 3px 10px;
  font-size: 12px;
  color: var(--gray-700);
  white-space: nowrap;
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fp-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.fp-list-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--gray-50);
  min-width: 0;
}
.fp-list-name {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  color: var(--gray-700);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fp-list-size {
  font-size: 11px;
  color: var(--gray-400);
  white-space: nowrap;
}

/* ============================================================
   v88 付款凭证：上传缩略图 + 凭证画廊
   ============================================================ */

/* 上传弹窗中的缩略图网格 */
.pay-voucher-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 8px;
}
.pay-voucher-thumb {
  position: relative;
  width: 120px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--gray-50);
  overflow: hidden;
}
.pay-voucher-icon {
  width: 120px;
  height: 90px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  background: var(--gray-100);
  overflow: hidden;
  transition: background 0.15s;
}
.pay-voucher-icon:hover {
  background: var(--gray-200);
}
.pay-voucher-info {
  padding: 6px 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.pay-voucher-name {
  font-size: 11px;
  color: var(--gray-600);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pay-voucher-size {
  font-size: 10px;
  color: var(--gray-400);
}
.pay-voucher-remove {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: rgba(0,0,0,0.55);
  color: #fff;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background 0.15s;
}
.pay-voucher-remove:hover {
  background: rgba(220,53,69,0.9);
}

/* 凭证画廊弹窗 */
.pay-history-section {
  margin-bottom: 16px;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.pay-history-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 14px;
  background: var(--gray-50);
  border-bottom: 1px solid var(--border);
}
.pay-history-amount {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-700);
}
.pay-history-date {
  font-size: 12px;
  color: var(--gray-500);
}
.voucher-gallery {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 12px;
}
.voucher-gallery-item {
  width: 130px;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s;
  background: var(--gray-50);
}
.voucher-gallery-item:hover {
  border-color: var(--primary);
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.voucher-thumb-wrap {
  width: 130px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--gray-100);
  overflow: hidden;
}
.voucher-item-info {
  padding: 6px 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.voucher-item-name {
  font-size: 11px;
  color: var(--gray-600);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.voucher-item-size {
  font-size: 10px;
  color: var(--gray-400);
}

/* 移动端适配 */
@media (max-width: 768px) {
  .pay-voucher-thumb { width: 100px; }
  .pay-voucher-icon { width: 100px; height: 75px; }
  .voucher-gallery-item { width: 110px; }
  .voucher-thumb-wrap { width: 110px; height: 85px; }
}

/* ============================================================
   v90 后台附件管理
   ============================================================ */
.file-stat-card {
  transition: box-shadow 0.15s;
  cursor: default;
}
.file-stat-card:hover {
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}
#fileTable th:last-child,
#fileTable td:last-child {
  position: sticky;
  right: 0;
  background: inherit;
  z-index: 1;
}

/* ============================================================
   v117: 深色主题适配（html[data-theme='dark']）
   变量体系自动覆盖大部分场景；此处补齐少量硬编码浅色残留
   ============================================================ */
html[data-theme='dark'] {
  color-scheme: dark; /* 原生控件（滚动条/日期选择/输入框）跟随深色 */
}

/* 筛选 chip：中性边框换深色 */
html[data-theme='dark'] .filter-chip { --fc-border: var(--border); }

/* v494: 状态 / 类型色板的深色主题覆盖 —— 浅色硬编码文字在暗底上偏暗，
   改用与暗色语义变量同值的提亮色（#fbbf24 warning / #60a5fa info / #34d399 success / #f87171 danger） */
html[data-theme='dark'] .filter-chip[data-dlstatus],
html[data-theme='dark'] .filter-chip[data-docstatus],
html[data-theme='dark'] .filter-chip[data-doctype] { --fc-count-bg: rgba(255, 255, 255, 0.10); --fc-count-color: var(--gray-800); }
html[data-theme='dark'] .filter-chip[data-dlstatus="planned"],
html[data-theme='dark'] .filter-chip[data-docstatus="reviewing"],
html[data-theme='dark'] .filter-chip[data-doctype="contract"] { --fc-color: #fbbf24; }
html[data-theme='dark'] .filter-chip[data-dlstatus="delivered"],
html[data-theme='dark'] .filter-chip[data-docstatus="archived"] { --fc-color: #60a5fa; }
html[data-theme='dark'] .filter-chip[data-dlstatus="accepted"],
html[data-theme='dark'] .filter-chip[data-docstatus="approved"] { --fc-color: #34d399; }
html[data-theme='dark'] .filter-chip[data-dlstatus="rejected"] { --fc-color: #f87171; }
html[data-theme='dark'] .filter-chip[data-docstatus="draft"],
html[data-theme='dark'] .filter-chip[data-doctype="other"] { --fc-color: var(--gray-600); }
html[data-theme='dark'] .filter-chip[data-doctype="proposal"] { --fc-color: #b794f4; }
html[data-theme='dark'] .filter-chip[data-doctype="delivery"] { --fc-color: #5eead4; }
html[data-theme='dark'] .filter-chip[data-dlstatus="all"],
html[data-theme='dark'] .filter-chip[data-docstatus="all"],
html[data-theme='dark'] .filter-chip[data-doctype="all"] { --fc-color: var(--gray-700); }
/* v495: 售后状态色板暗色覆盖（浅色硬编码文字在暗底偏暗，改用提亮同色相） */
html[data-theme='dark'] .filter-chip[data-asstatus] { --fc-count-bg: rgba(255, 255, 255, 0.10); --fc-count-color: var(--gray-800); }
html[data-theme='dark'] .filter-chip[data-asstatus="all"]        { --fc-color: var(--gray-700); }
html[data-theme='dark'] .filter-chip[data-asstatus="pending"]    { --fc-color: #fbbf24; }
html[data-theme='dark'] .filter-chip[data-asstatus="processing"] { --fc-color: #60a5fa; }
html[data-theme='dark'] .filter-chip[data-asstatus="resolved"]   { --fc-color: #34d399; }
html[data-theme='dark'] .filter-chip[data-asstatus="closed"]     { --fc-color: var(--gray-600); }

/* 徽章/标签：浅色底→深色底，文字提亮 */
html[data-theme='dark'] .badge-purple { background: #2e2440; color: #b794f4; }
html[data-theme='dark'] .badge-cyan { background: #10333c; color: #67e8f9; }
html[data-theme='dark'] .badge-warning { color: #fbbf24; }
html[data-theme='dark'] .badge-success { color: #34d399; }
html[data-theme='dark'] .badge-danger  { color: #f87171; }
html[data-theme='dark'] .badge-info    { color: #60a5fa; }

/* 权限矩阵：操作徽章/风险标识/表格渐变 */
html[data-theme='dark'] .perm-act-badge.act-view    { color: #93c5fd; background: #17263f; border-color: #2c4266; }
html[data-theme='dark'] .perm-act-badge.act-edit    { color: #6ee7b7; background: #12352a; border-color: #1f5240; }
html[data-theme='dark'] .perm-act-badge.act-delete  { color: #fca5a5; background: #3b1d1d; border-color: #6b2b2b; }
html[data-theme='dark'] .perm-act-badge.act-approve { color: #c4b5fd; background: #2e2440; border-color: #4c3d6b; }
html[data-theme='dark'] .perm-act-badge.act-admin   { color: #fcd34d; background: #3a2e11; border-color: #66521a; }
html[data-theme='dark'] .perm-act-badge.act-comm    { color: #67e8f9; background: #12333b; border-color: #1f5560; }
html[data-theme='dark'] .perm-risk-badge { color: #fca5a5; background: #3b1d1d; border-color: #6b2b2b; }
html[data-theme='dark'] .perm-chip { color: #fca5a5; background: var(--card-bg); border: 1px solid #6b2b2b; }
html[data-theme='dark'] .perm-chip:hover { background: #3b1d1d; }
html[data-theme='dark'] .perm-table-scroller .perm-module-row td {
  background: linear-gradient(180deg, #1e2431 0%, #1a1f2a 100%);
}

/* 顶栏在线指示器（内联浅色样式，!important 覆盖） */
html[data-theme='dark'] #onlineIndicator {
  background: #17263f !important;
  color: #93c5fd !important;
  border-color: #2c4266 !important;
}

/* 甘特图：todo 浅蓝条在深色下加深，保持可读 */
html[data-theme='dark'] .gantt-bar.gantt-bar-todo { background: #2b4a75; color: #cfe3ff; }
html[data-theme='dark'] .gantt-bar.gantt-bar-remain { background: #3b5f9e; }

/* 登录页右栏表单区（登录页本身固定浅色设计，深色主题下同步变暗） */
html[data-theme='dark'] .login-screen { background: var(--bg); }
html[data-theme='dark'] .login-card {
  background: rgba(26, 31, 42, 0.72);
  border-color: rgba(255, 255, 255, 0.08);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}
html[data-theme='dark'] .login-title { color: var(--text); }
html[data-theme='dark'] .login-subtitle { color: var(--text-secondary); }
html[data-theme='dark'] .login-label { color: var(--text-secondary); }
html[data-theme='dark'] .login-input {
  background: var(--gray-100);
  border-color: var(--border);
  color: var(--text);
}
html[data-theme='dark'] .login-input::placeholder { color: var(--text-tertiary); }
html[data-theme='dark'] .login-input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-bg); }
html[data-theme='dark'] .login-error { background: var(--danger-bg); color: #fca5a5; border-left-color: var(--danger); }

/* v117: 主题切换按钮（顶栏） */
.theme-btn { position: relative; }
.theme-btn .theme-icon-moon,
.theme-btn .theme-icon-sun { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; transition: opacity 0.2s, transform 0.2s; }
html:not([data-theme='dark']) .theme-btn .theme-icon-sun  { opacity: 0; transform: rotate(90deg) scale(0.6); }
html:not([data-theme='dark']) .theme-btn .theme-icon-moon { opacity: 1; transform: none; }
html[data-theme='dark'] .theme-btn .theme-icon-sun  { opacity: 1; transform: none; }
html[data-theme='dark'] .theme-btn .theme-icon-moon { opacity: 0; transform: rotate(-90deg) scale(0.6); }

/* ============================================
   v159: 仪表盘成员动态——置顶卡 · 15 条滚动 · 行点击定位详情
   ============================================ */
.dash-act-scroll { height: 283px; overflow-y: auto; margin: 0 -4px; padding: 0 4px; position: relative; } /* v163: 6 行窗口（原 v162 为 5 行 236px） */
.dash-act-scroll::-webkit-scrollbar { width: 5px; }
.dash-act-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.dash-act-scroll::-webkit-scrollbar-track { background: transparent; }
.dash-act-row { cursor: pointer; border-radius: 8px; transition: background 0.15s; }
.dash-act-row:hover { background: var(--primary-bg, rgba(79, 107, 237, 0.06)); }
.dash-act-row:last-child { border-bottom: none !important; }

/* v204: 当日动态明显标识——卡头计数徽标 + 行内「今日」徽标（暖橙，深浅主题双适配）
   v207: 标识加强——卡头计数改实心渐变、行内徽标加呼吸光晕、整行左侧橙色竖条 + 更深底色 */
.dash-act-today-chip {
  display: inline-block; margin-left: 8px; padding: 1px 9px;
  font-size: 11px; font-weight: 600; line-height: 18px;
  color: #fff; background: linear-gradient(135deg, #f59e0b, #f97316);
  border: none; border-radius: 999px;
  vertical-align: 1px; white-space: nowrap;
}
html[data-theme='dark'] .dash-act-today-chip {
  color: #fff; background: linear-gradient(135deg, #f59e0b, #f97316);
  box-shadow: 0 0 0 1px rgba(252, 211, 77, 0.35);
}
.dash-act-today-badge {
  display: inline-block; margin: 0 1px; padding: 0 5px;
  font-size: 10px; font-weight: 600; line-height: 16px;
  color: #fff; background: linear-gradient(135deg, #f59e0b, #f97316);
  border-radius: 4px; vertical-align: 1px; white-space: nowrap;
  animation: dashTodayGlow 2.4s ease-in-out infinite; /* v207: 呼吸光晕 */
}
@keyframes dashTodayGlow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(249, 115, 22, 0.45); }
  50% { box-shadow: 0 0 0 4px rgba(249, 115, 22, 0); }
}
@media (prefers-reduced-motion: reduce) { .dash-act-today-badge { animation: none; } }

/* v351: 成员动态卡头视图控制按钮——「展开全部 / 收起」+「折叠 / 展开」
   激活态（已展开全部 / 已折叠）用主色实心，一眼看出当前视图模式 */
.dash-act-btns {
  display: inline-flex; gap: 6px; margin-left: auto; flex: none;
}
.dash-act-btn {
  height: 24px; padding: 0 10px;
  font-family: inherit; font-size: 12px; line-height: 22px;
  color: var(--text-secondary, var(--text-tertiary));
  background: var(--bg-secondary, var(--card-bg));
  border: 1px solid var(--border); border-radius: 6px;
  cursor: pointer; white-space: nowrap;
  transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
}
.dash-act-btn:hover {
  color: var(--primary);
  border-color: var(--primary);
}
.dash-act-btn:active { transform: translateY(1px); }
.dash-act-btn.dash-act-btn-on {
  color: #fff;
  background: var(--primary);
  border-color: var(--primary);
}
html[data-theme='dark'] .dash-act-btn {
  background: var(--bg-secondary, var(--card-bg));
}
@media (prefers-reduced-motion: reduce) { .dash-act-btn { transition: none; } }
/* v207: 当日行——左侧 4px 橙色竖条 + 底色加深至 14%，hover 保持暖橙不退色 */
.dash-act-row.dash-act-today { background: rgba(245, 158, 11, 0.14); box-shadow: inset 4px 0 0 #f59e0b; }
html[data-theme='dark'] .dash-act-row.dash-act-today { background: rgba(245, 158, 11, 0.16); box-shadow: inset 4px 0 0 #f59e0b; }
.dash-act-row.dash-act-today:hover { background: rgba(245, 158, 11, 0.2); }
html[data-theme='dark'] .dash-act-row.dash-act-today:hover { background: rgba(245, 158, 11, 0.22); }

/* v205: 成员动态行尾完整发生年月日 */
.dash-act-date {
  margin-top: 2px; font-size: 11px; line-height: 1.4;
  color: var(--text-tertiary); opacity: 0.85;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.dash-act-row.dash-act-today .dash-act-date { color: var(--warning); opacity: 0.95; }

/* v170: 智能提醒卡默认折叠，点击卡头展开/收起（箭头旋转指示） */
.rem-fold-arrow {
  display: inline-block; font-size: 11px; color: var(--text-tertiary);
  margin-left: 2px; vertical-align: 1px;
  transition: transform 0.22s ease;
}
.rem-fold-arrow.rem-open { transform: rotate(90deg); }
#dashReminder .card-header:hover .card-title { color: var(--primary); }
#dashReminder .card-header .card-title { transition: color 0.18s ease; }

/* v164: 侧栏快捷入口（新建表单一键直达） */
.nav-item.quick-entry { color: var(--primary); }
.nav-item.quick-entry:hover { background: var(--primary-bg); color: var(--primary); }
.nav-item.quick-entry svg { flex-shrink: 0; }

/* v175: 快捷入口浮层「简约化」——面板改为与侧栏导航一致的「图标+文字」行式菜单，
   去掉标题栏/渐变瓦片/级联动画，组标签回归普通分组标签样式（fixed 定位逃逸侧栏裁剪不变） */
.quick-toggle {
  cursor: pointer; user-select: none; display: flex; align-items: center;
  gap: 5px; margin: 2px 8px 8px; padding: 6px 12px;
  border-radius: 8px;
  font-size: 11px; font-weight: 700; letter-spacing: 1px;
  color: var(--text-tertiary);
  transition: color .18s ease, background .18s ease;
}
.quick-toggle:hover { color: var(--primary); background: var(--primary-bg); }
.quick-toggle .qe-bolt { color: var(--primary); }
.quick-toggle .qe-arrow {
  margin-left: auto; font-size: 11px; opacity: .7;
  transition: transform .25s ease; display: inline-block;
}
#quickEntryGroup.open .qe-arrow { transform: rotate(90deg); }

.quick-list {
  position: fixed;
  z-index: 320;
  display: flex;
  flex-direction: column;
  min-width: 152px;
  padding: 6px;
  margin: 0;
  border-radius: 10px;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border, rgba(127,127,127,.18));
  box-shadow: 0 4px 14px rgba(31, 41, 55, .08), 0 12px 32px rgba(31, 41, 55, .12);
  opacity: 0; visibility: hidden;
  transform: translateX(-6px);
  transform-origin: left center;
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
}
#quickEntryGroup.open .quick-list { opacity: 1; visibility: visible; transform: none; }
/* v175: 入口纵向列表容器 */
.quick-row { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }

/* 侧栏收起态（纯图标）：组标签缩为 ⚡ 圆钮，仍是 hover/点击目标，浮层面板照常弹出 */
.app-layout.sidebar-collapsed .quick-toggle {
  opacity: 1; height: auto; width: 34px; margin: 2px auto 8px;
  padding: 7px 0; justify-content: center; font-size: 0; overflow: visible;
}
.app-layout.sidebar-collapsed .quick-toggle .qe-bolt { font-size: 15px; margin-right: 0; }
.app-layout.sidebar-collapsed .quick-toggle .qe-arrow { display: none; }
/* 收起态默认会隐藏 nav-item 文字——浮层面板内入口必须保留图标+文字 */
.app-layout.sidebar-collapsed .quick-list .nav-item span { opacity: 1; width: auto; overflow: visible; }

/* v175: 入口为「图标+文字」行（与侧栏 nav-item 同风格）——去底色纯主题色图标，hover 主色淡底 */
.quick-list .quick-entry {
  display: flex; flex-direction: row; align-items: center; justify-content: flex-start;
  gap: 10px;
  width: 100%;
  margin: 0;
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 13px; font-weight: 500;
  line-height: 1.3;
  text-align: left;
  white-space: nowrap;
  color: var(--text) !important;
  background: transparent;
  position: relative;
  transition: background .16s ease, color .16s ease;
}
.quick-list .quick-entry:hover { background: var(--primary-bg); }
.quick-entry .qe-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  flex-shrink: 0;
  color: var(--primary);
  transition: color .16s ease;
}
.quick-entry .qe-ic svg { width: 16px; height: 16px; }
.qe-c-primary .qe-ic { color: var(--primary); }
.qe-c-info    .qe-ic { color: var(--info); }
.qe-c-warning .qe-ic { color: var(--warning); }
.qe-c-success .qe-ic { color: var(--success); }
.qe-c-danger  .qe-ic { color: var(--danger); }
.quick-entry:hover .qe-ic { color: var(--primary); }


/* v171→v175: 财务记账子入口——面板内「下方列表」展开，简约行式与面板一致 */
.qe-has-sub { position: relative; display: flex; flex-direction: column; align-items: stretch; }
.qe-has-sub .quick-entry { width: 100%; }
.qe-has-sub .qe-sub-arrow {
  margin-left: auto; font-size: 10px; opacity: .55;
  transition: transform .22s ease; display: inline-block;
}
.qe-has-sub.open .qe-sub-arrow { transform: rotate(90deg); opacity: 1; color: var(--primary); }
.qe-sub-list {
  position: absolute;
  top: 100%; left: 0;
  margin-top: 4px;
  width: 100%;
  min-width: 128px;
  padding: 5px;
  border-radius: 10px;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border, rgba(127,127,127,.18));
  box-shadow: 0 4px 14px rgba(31, 41, 55, .08), 0 12px 32px rgba(31, 41, 55, .12);
  z-index: 5;
  opacity: 0; visibility: hidden;
  transform: translateY(-4px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
}
.qe-has-sub.open .qe-sub-list { opacity: 1; visibility: visible; transform: none; }
.qe-sub-head {
  padding: 5px 12px 4px;
  margin: 0 0 3px;
  font-size: 10px; font-weight: 700; letter-spacing: 1px;
  color: var(--text-tertiary);
  border-bottom: 1px solid var(--border-light, var(--border));
}
.qe-sub-item {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 12px;
  margin: 2px 0;
  border-radius: 8px;
  font-size: 13px; font-weight: 500;
  color: var(--text-secondary);
  cursor: pointer;
  position: relative;
  white-space: nowrap;
  transition: background .16s ease, color .16s ease;
}
.qe-sub-item:hover { background: var(--primary-bg); color: var(--primary); }

/* ============================================
   v173: 主导航 hover 浮层——鼠标经过各板块导航（项目管理/任务管理/.../财务管理）
   在侧栏右侧弹出该板块快捷入口面板（动态构建 + 按权限过滤）
   复用 .quick-list 基础样式（fixed/圆角/阴影/瓦片），自身 .open 控制显隐
   ============================================ */
.nav-pop.open { opacity: 1; visibility: visible; transform: none; }
/* 主导航悬停提示：有浮层的导航项右侧淡入 ▸ */
#sidebarNav .nav-item.has-qpanel::after {
  content: '▸';
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 10px;
  opacity: 0;
  color: var(--text-tertiary);
  transition: opacity .18s ease, color .18s ease;
  pointer-events: none;
}
#sidebarNav .nav-item.has-qpanel:hover::after { opacity: .75; color: var(--primary); }
/* 侧栏收起态（纯图标）无文字空间，隐藏 ▸ 提示 */
.app-layout.sidebar-collapsed #sidebarNav .nav-item.has-qpanel::after { display: none; }
/* v174: 后台停用快捷入口时，主导航 ▸ 提示同步隐藏 */
#sidebarNav .nav-item.has-qpanel.qe-off::after { display: none; }

/* ============================================
   v198: 后台设置页排版升级
   1) 脱敏字段行 .ds-field-row——5 列网格对齐（勾选/字段/说明/程度参数/实时预览），
      替代旧 flex-wrap 行（各列上下严格对齐，不再随内容漂移）
   2) 提示框 .admin-hint-warn / .admin-hint-info——升级版提示（图标左置 + 主题联动）
   3) 系统信息卡 .admin-info-grid——2 列自适应（见原定义处改造）
   ============================================ */

/* -- 脱敏字段列头（与 .ds-field-row 同一列宽，形成表头） -- */
.ds-field-head {
  display: grid;
  grid-template-columns: 18px 64px 1fr minmax(176px, max-content) 180px;
  gap: 6px 10px;
  padding: 0 12px 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .5px;
  color: var(--text-tertiary);
}
.ds-field-head .ds-h-rules,
.ds-field-head .ds-h-preview { justify-self: end; }

/* -- 脱敏字段行：5 列网格（勾选 18px / 字段名 64px / 说明 1fr / 参数 max-content / 预览 180px） -- */
.ds-field-row {
  display: grid;
  grid-template-columns: 18px 64px 1fr minmax(176px, max-content) 180px;
  align-items: center;
  gap: 6px 10px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 6px;
  transition: border-color .15s ease;
}
.ds-field-row:hover { border-color: var(--primary); }
.ds-field-row input[type='checkbox'] { width: 15px; height: 15px; accent-color: var(--primary); cursor: pointer; }
.ds-field-name { font-weight: 600; font-size: 13px; color: var(--text); white-space: nowrap; }
.ds-field-desc {
  font-size: 12px; color: var(--text-tertiary);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* -- 程度参数区：3 列 max-content（标签/输入框/单位），两参字段自动折两行、右对齐 -- */
.ds-field-rules {
  display: grid;
  grid-template-columns: repeat(3, max-content);
  align-items: center;
  gap: 4px 8px;
  justify-content: end;
}
.ds-field-rule { font-size: 12px; color: var(--text-tertiary); white-space: nowrap; }
.ds-field-rules .form-input { width: 52px; padding: 4px 6px; text-align: center; font-size: 12px; }

/* -- 固定脱敏徽标（不可调字段，占参数+预览两列） -- */
.ds-field-fixed {
  grid-column: 4 / -1;
  justify-self: end;
  font-size: 12px;
  color: var(--text-tertiary);
  border: 1px dashed var(--border);
  border-radius: 6px;
  padding: 3px 10px;
  white-space: nowrap;
}
[data-theme='dark'] .ds-field-fixed { color: var(--text-secondary); }

/* -- 实时预览黄标：180px 等宽字体（容纳 24 字符样本；邮箱样本 38 字符会截断，
      但通过 title 属性悬停可见完整）；同列严格对齐保证预览 chip 视觉成行 -- */
.ds-field-preview {
  justify-self: end;
  width: 180px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: #b45309;
  background: var(--warning-bg);
  border: 1px solid #fde68a;
  border-radius: 6px;
  padding: 4px 8px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}
[data-theme='dark'] .ds-field-preview { color: #fcd34d; border-color: rgba(251, 191, 36, .3); }

/* -- 窄屏（手机）：说明折行，参数与预览整行铺开 -- */
@media (max-width: 720px) {
  .ds-field-head { display: none; }
  .ds-field-row { grid-template-columns: 18px 64px 1fr; }
  .ds-field-desc { white-space: normal; }
  .ds-field-rules { grid-column: 1 / -1; justify-content: start; }
  .ds-field-preview, .ds-field-fixed { grid-column: 1 / -1; justify-self: start; width: auto; max-width: 240px; }
}

/* -- v198: 升级版提示框（替代内联样式的说明条；图标左置，深浅主题联动） -- */
.admin-hint-warn,
.admin-hint-info {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 12px;
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 12.5px;
  line-height: 1.75;
}
.admin-hint-warn { color: #92400e; background: var(--warning-bg); border: 1px solid #fde68a; }
.admin-hint-info { color: #1e40af; background: var(--info-bg); border: 1px solid #bfdbfe; }
.admin-hint-warn .admin-hint-ic,
.admin-hint-info .admin-hint-ic { flex-shrink: 0; font-size: 14px; line-height: 1.55; }
.admin-hint-warn .admin-hint-body,
.admin-hint-info .admin-hint-body { min-width: 0; }
[data-theme='dark'] .admin-hint-warn { color: #fcd34d; border-color: rgba(251, 191, 36, .3); }
[data-theme='dark'] .admin-hint-info { color: #93c5fd; border-color: rgba(96, 165, 250, .3); }
@media (max-width: 720px) {
  .admin-hint-warn, .admin-hint-info { font-size: 12px; padding: 9px 12px; }
}

/* ===================== v199: 用户管理树状结构 ===================== */
/* 部门 → 用户 两级折叠树；列头与用户行共用同一 grid 模板保证上下严格对齐 */
.ut-wrap {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card-bg);
  overflow: auto;
  max-height: calc(100vh - 250px);
}
/* 列头与用户行必须共用同一网格盒（同模板 + 同左右 padding），否则树形缩进会顶歪列对齐；
   操作列固定 170px（max-content 会让列头[文字]与行[按钮]轨道宽度不一致） */
.ut-head,
.ut-row {
  display: grid;
  grid-template-columns: minmax(190px, 2fr) 108px 128px minmax(130px, 1fr) 112px 80px 82px 160px;
  gap: 10px;
  align-items: center;
  min-width: 1040px;
  padding-left: 42px;
  padding-right: 16px;
}
.ut-head {
  position: sticky;
  top: 0;
  z-index: 6;
  padding-top: 10px;
  padding-bottom: 10px;
  background: var(--gray-50);
  border-bottom: 1px solid var(--border);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .4px;
  color: var(--gray-500);
  white-space: nowrap;
}
.ut-head .ut-col-ops { justify-self: end; }
.ut-group { border-bottom: 1px solid var(--border); }
.ut-group:last-child { border-bottom: none; }

/* -- 部门行（可点击折叠/展开） -- */
.ut-dept {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  cursor: pointer;
  user-select: none;
  background: var(--gray-50);
  transition: background .15s;
}
.ut-dept:hover { background: var(--gray-100); }
.ut-caret {
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  color: var(--gray-400);
  transition: transform .18s ease;
}
.ut-group.collapsed .ut-caret { transform: rotate(-90deg); }
.ut-folder { flex-shrink: 0; width: 17px; height: 17px; }
.ut-dept-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-800);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ut-dept-count {
  flex-shrink: 0;
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 10px;
  background: var(--primary-bg);
  color: var(--primary);
  font-size: 11px;
  font-weight: 600;
  text-align: center;
  line-height: 1.6;
}
.ut-dept-stat {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 11px;
  color: var(--gray-400);
  white-space: nowrap;
}

/* -- 用户行（挂载部门下、缩进 + 树形参考线） -- */
.ut-users { position: relative; }
.ut-group.collapsed .ut-users { display: none; }
.ut-row {
  position: relative;
  padding-top: 8px;
  padding-bottom: 8px;
  border-top: 1px dashed var(--border);
  transition: background .15s;
}
.ut-users .ut-row:first-child { border-top: none; }
.ut-row::before {
  content: '';
  position: absolute;
  left: 28px;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
}
.ut-row:hover { background: var(--gray-50); }
.ut-name { font-weight: 600; font-size: 13px; color: var(--gray-800); }
.ut-joined { font-size: 11px; color: var(--text-tertiary); }
.ut-mini { font-size: 12px; }
.ut-col-user, .ut-col-role, .ut-col-jobtitle, .ut-col-email, .ut-col-phone, .ut-col-status, .ut-col-pwd {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ut-col-ops {
  position: sticky;
  right: 0;
  justify-self: end;
  padding: 6px 0 6px 12px;
  background: var(--card-bg);
  box-shadow: -8px 0 8px -8px rgba(0, 0, 0, .18);
}
.ut-row:hover .ut-col-ops { background: var(--gray-50); }
.ut-empty {
  padding: 12px 16px 12px 42px;
  font-size: 12px;
  color: var(--gray-400);
}
.ut-noresult {
  padding: 30px 16px;
  text-align: center;
  font-size: 13px;
  color: var(--gray-400);
}

/* -- 搜索态：命中分组强制展开；无命中分组隐藏 -- */
.ut-wrap.searching .ut-group.collapsed .ut-users { display: block; }
.ut-wrap.searching .ut-group.collapsed .ut-caret { transform: none; }
.ut-group.no-match { display: none; }

/* -- 窄屏：隐藏电话/密码列（grid 模板同步收缩为 5 列） -- */
@media (max-width: 900px) {
  .ut-head, .ut-row {
    grid-template-columns: minmax(150px, 2fr) 96px 116px minmax(110px, 1fr) 70px 160px;
    min-width: 760px;
  }
  .ut-col-phone, .ut-col-pwd { display: none; }
}

/* ============ v208: 站内聊天微信式窗口（左会话列表 + 右聊天区） ============ */
.chat-panel {
  position: fixed; top: 0; right: -760px; width: 720px; max-width: 100vw; height: 100vh;
  z-index: 1150; display: flex; flex-direction: row;
  background: var(--card-bg); border-left: 1px solid var(--gray-200);
  box-shadow: -8px 0 24px rgba(0,0,0,.08); transition: right .22s ease;
}
.chat-panel.open { right: 0; }

/* -- 左：会话列表 -- */
.chat-sidebar {
  width: 250px; flex: 0 0 250px; display: flex; flex-direction: column; min-height: 0;
  border-right: 1px solid var(--gray-200); background: var(--gray-100);
}
.chat-sidebar-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--gray-200); flex: 0 0 auto;
}
.chat-title { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; color: var(--gray-900); }
.chat-close { cursor: pointer; color: var(--gray-400); padding: 4px; border-radius: 6px; display: flex; }
.chat-close:hover { color: var(--gray-700); background: var(--gray-200); }
.chat-list { flex: 1; overflow-y: auto; min-height: 0; }

.chat-item {
  display: flex; align-items: center; gap: 10px; padding: 11px 12px;
  cursor: pointer; border-bottom: 1px solid var(--gray-200);
}
.chat-item:hover { background: rgba(0,0,0,.04); }
html[data-theme='dark'] .chat-item:hover { background: rgba(255,255,255,.05); }
.chat-item.active { background: var(--primary-bg); }
.chat-item.active:hover { background: var(--primary-bg); }

.chat-avatar {
  position: relative; width: 44px; height: 44px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 700; color: #fff; flex: 0 0 auto; user-select: none;
}
.chat-avatar .dot {
  position: absolute; right: -1px; bottom: -1px; width: 11px; height: 11px;
  border-radius: 50%; border: 2px solid var(--card-bg);
}
.chat-avatar .dot.on { background: #22c55e; }
.chat-avatar .dot.off { background: var(--gray-300); }

.chat-item-body { flex: 1; min-width: 0; }
.chat-item-top { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.chat-item-name {
  font-size: 13px; font-weight: 600; color: var(--gray-800);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-item-time { flex: 0 0 auto; font-size: 10px; color: var(--gray-400); }
.chat-item-sub { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-top: 2px; }
.chat-item-preview {
  font-size: 11px; color: var(--gray-400);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-item-unread {
  flex: 0 0 auto; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  background: #ef4444; color: #fff; font-size: 10px; font-weight: 700; line-height: 16px; text-align: center;
}

/* v459: 顶栏「站内聊天」未读角标——更大更醒目 + 脉冲呼吸 */
.chat-unread-badge {
  display: none; position: absolute; top: -5px; right: -7px; min-width: 18px; height: 18px;
  padding: 0 5px; border-radius: 9px; background: #ef4444; color: #fff; font-size: 11px;
  font-weight: 700; line-height: 18px; text-align: center; box-shadow: 0 0 0 2px var(--card-bg);
  animation: chatBadgePulse 1.8s ease-out infinite;
}

/* v471: 顶栏「消息提示」入口——有未读时图标高亮并轻脉冲（角标本身沿用 .chat-unread-badge） */
.chat-entry-btn.has-unread { color: var(--danger, #ef4444) !important; }
.chat-entry-btn.has-unread svg { animation: pmMsgPulse 2s ease-in-out infinite; }
@keyframes pmMsgPulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.14); }
}

/* v471: 团队会话留言来源提示条 + 一键进入对话框 */
.chat-cloud-tip {
  display: flex; align-items: center; gap: 8px; margin: 0 0 12px;
  padding: 7px 10px; border-radius: 8px; font-size: 11px;
  background: var(--gray-50, #f9fafb); border: 1px solid var(--gray-200, #e5e7eb);
  color: var(--text-tertiary, #6b7280);
}
.chat-cloud-open {
  margin-left: auto; flex: 0 0 auto; padding: 3px 10px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--primary, #4f6bed); background: transparent;
  color: var(--primary, #4f6bed); font-size: 11px; font-weight: 600;
}
.chat-cloud-open:hover { background: var(--primary, #4f6bed); color: #fff; }
@keyframes chatBadgePulse {
  0%   { box-shadow: 0 0 0 2px var(--card-bg), 0 0 0 0 rgba(239,68,68,.5); }
  70%  { box-shadow: 0 0 0 2px var(--card-bg), 0 0 0 6px rgba(239,68,68,0); }
  100% { box-shadow: 0 0 0 2px var(--card-bg), 0 0 0 0 rgba(239,68,68,0); }
}

/* -- 右：聊天区 -- */
.chat-main { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.chat-main-head {
  display: flex; align-items: center; gap: 8px; padding: 12px 16px;
  border-bottom: 1px solid var(--gray-200); flex: 0 0 auto;
}
.chat-main-name { font-size: 14px; font-weight: 700; color: var(--gray-900); }
.chat-main-status { font-size: 11px; font-weight: 400; margin-left: 2px; }
.chat-main-status.on { color: #22c55e; }
.chat-main-status.off { color: var(--gray-400); }
.chat-main-head .chat-close { margin-left: auto; }

.chat-thread-body {
  flex: 1; overflow-y: auto; padding: 12px 16px 14px;
  display: flex; flex-direction: column; gap: 2px; min-height: 0;
  background: var(--card-bg);
}
.chat-date-divider {
  align-self: center; margin: 8px 0 6px; padding: 2px 10px; border-radius: 999px;
  background: var(--gray-100); color: var(--gray-400); font-size: 10px; flex: 0 0 auto;
}

.chat-row { display: flex; align-items: flex-end; gap: 8px; margin-top: 6px; }
.chat-row.mine { justify-content: flex-end; }
.chat-bubble-avatar {
  width: 28px; height: 28px; border-radius: 50%; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; color: #fff; user-select: none;
}
.chat-bubble {
  max-width: 72%; padding: 8px 12px; border-radius: 12px;
  font-size: 13px; line-height: 1.5; word-break: break-word; white-space: pre-wrap;
}
.chat-bubble.them { background: var(--gray-100); color: var(--gray-800); border-bottom-left-radius: 4px; }
.chat-bubble.mine { background: var(--primary); color: #fff; border-bottom-right-radius: 4px; }
.chat-bubble-time { font-size: 10px; color: var(--gray-400); padding: 0 2px 2px; flex: 0 0 auto; }

.chat-empty { margin: auto; text-align: center; color: var(--gray-400); font-size: 12px; padding: 20px; }
.chat-empty-icon {
  width: 56px; height: 56px; border-radius: 50%; background: var(--gray-100);
  display: flex; align-items: center; justify-content: center;
  font-size: 24px; margin: 0 auto 12px;
}

.chat-inputbar {
  display: flex; gap: 8px; padding: 10px 12px;
  border-top: 1px solid var(--gray-200); align-items: flex-end; flex: 0 0 auto;
}
.chat-input {
  flex: 1; resize: none; border: 1px solid var(--gray-300); border-radius: 8px;
  padding: 8px 10px; font-size: 13px; font-family: inherit; max-height: 96px; outline: none;
  background: var(--card-bg); color: var(--gray-900);
}
.chat-input:focus { border-color: var(--primary); }
.chat-send {
  flex: 0 0 auto; border: none; background: var(--primary); color: #fff;
  border-radius: 8px; padding: 0 16px; font-size: 13px; font-weight: 600;
  cursor: pointer; height: 34px;
}
.chat-send:hover { opacity: .92; }
.chat-send:active { opacity: .82; }

/* -- 窄屏：会话列表压缩为窄条 -- */
@media (max-width: 640px) {
  .chat-sidebar { width: 108px; flex-basis: 108px; }
  .chat-sidebar-head .chat-title { font-size: 12px; }
  .chat-item { padding: 10px 8px; justify-content: center; }
  .chat-item-body { display: none; }
}

/* -- v212: 合作伙伴合作项目明细编辑器 -- */
.coop-row {
  display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap;
}
.coop-row .form-input, .coop-row .form-select { margin: 0; }
.coop-row .coop-del {
  width: 26px; height: 26px; padding: 0; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 6px; font-size: 15px;
}
.coop-row .coop-del:hover { background: rgba(239, 68, 68, .1); }
#coopsEditor {
  border: 1px dashed var(--gray-300); border-radius: 8px; padding: 10px 12px;
  background: var(--card-bg); max-height: 260px; overflow-y: auto;
}
@media (max-width: 640px) {
  .coop-row { flex-direction: column; align-items: stretch; }
  .coop-row .form-input, .coop-row .form-select { width: 100% !important; flex: none !important; }
  .coop-row .coop-del { align-self: flex-end; }
}

/* ==========================================
   v223: 采购明细 grid-table · table-layout:fixed + colgroup
   - 每列宽可拖拽（表头 .col-resize 拖动 colgroup<col> width）
   - cell 内 input/select 透明背景 → 看起来是表格而非表单
   - focus 时显边框 + 阴影，hover 行高亮
   ========================================== */
.grid-table-wrap {
  margin-top: 8px;
  border: 1px solid #d0d5db;  /* v383: var(--border)→#d0d5db 更显 */
  border-radius: 8px;  /* v383: var(--radius)→8 与 v381 一致 */
  background: var(--card-bg);
  overflow-x: auto;
  /* v383: 大气庄重——卡片化静态阴影 */
  box-shadow: 0 2px 4px rgba(15, 23, 42, 0.04);
}
.grid-table {
  width: 100%;
  min-width: 760px;
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
  font-size: 14px;  /* v383: 13→14 与 v381 表单 token 一致 */
  color: var(--gray-800);
}
.grid-table thead th {
  padding: 12px 12px;  /* v383: 10→12 加重 */
  text-align: left;
  font-size: 13px;  /* v383: 12→13 略增 */
  font-weight: 700;  /* v383: 600→700 庄重 */
  color: var(--gray-800);  /* v383: 700→800 更显 */
  background: #f1f5f9;  /* v383: var(--gray-50)→#f1f5f9 更深 */
  border-bottom: 2px solid #d0d5db;
  white-space: nowrap;
  position: sticky;
  top: 0;
  letter-spacing: 0.2px;
  user-select: none;
  z-index: 2;  /* v383: 1→2 */
}
.grid-table thead th .col-resize {
  position: absolute;
  right: -4px; top: 0; bottom: 0;
  width: 8px;
  cursor: col-resize;
  z-index: 3;
  /* v387: 拖把可视性——hover 时左侧露出 4px 半透明蓝条,提示"可拖" */
}
.grid-table thead th .col-resize::before {
  content: '';
  position: absolute;
  left: 3px; top: 20%; bottom: 20%;
  width: 2px;  /* v387: 1px→2px 默认可见分隔 */
  background: var(--border);
  transition: width 0.15s, background 0.15s;
}
.grid-table thead th .col-resize:hover::before,
.grid-table thead th .col-resize.dragging::before {
  background: var(--primary);
  width: 3px;  /* v387: hover/dragging 加粗到 3px */
}
.grid-table thead th.cell-num,
.grid-table thead th.cell-subtotal,
.grid-table thead th.cell-op {
  text-align: right;
}
.grid-table thead th.cell-op { text-align: center; padding-right: 0; }

.grid-table tbody td {
  padding: 0 4px;
  border-bottom: 1px solid #e8ebef;  /* v383: 更明显分隔线 */
  vertical-align: middle;
  background: var(--card-bg);
  transition: background-color 0.15s;
}
.grid-table tbody tr:last-child td { border-bottom: none; }
.grid-table tbody tr:hover td { background: #f5f7fa; }  /* v383: hover 反馈明显 */
.grid-table tbody tr.is-removed td { background: var(--danger-bg); }

.grid-table td.cell-idx {
  text-align: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--gray-500);
  padding: 0;
  font-variant-numeric: tabular-nums;
}
.grid-table td.cell-subtotal {
  text-align: right;
  padding: 8px 12px;
  font-weight: 600;
  color: var(--primary);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum';
}
.grid-table td.cell-op { text-align: center; padding: 0; }
.grid-table td.cell-op .grid-row-del {
  border: none; background: transparent;
  color: var(--gray-400);
  width: 32px; height: 32px;  /* v383: 28x36→32x32 圆形 */
  cursor: pointer;
  border-radius: 50%;  /* v383: 6px→50% 圆形按钮 */
  transition: background 0.15s, color 0.15s, transform 0.15s;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.grid-table td.cell-op .grid-row-del:hover {
  background: #fee2e2;  /* v383: var(--danger-bg)→更明显 */
  color: var(--danger);
  transform: scale(1.1);  /* v383: 微微放大反馈 */
}

/* v383: 序号徽标(日常收支明细/采购 line item)——浅蓝圆形数字 */
.grid-table td.cell-idx .fin-row-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #e0e7ff;
  color: #4338ca;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* v383: 金额列 ¥ 前缀视觉 */
.grid-table td.cell-price { padding: 0 4px 0 8px; }
.grid-table td.cell-price .cell-price-wrap {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 100%;
}
.grid-table td.cell-price .cell-price-prefix {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-500);
  flex: 0 0 auto;
}
.grid-table td.cell-price input {
  flex: 1;
  min-width: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum';
  font-weight: 600;
}

/* v383: 财务明细 tfoot 行视觉(浅灰底,sticky 在底部) */
.grid-table tfoot tr td {
  background: #f8fafc !important;
  border-top: 2px solid #d0d5db;
}
.grid-table tfoot tr:hover td { background: #f1f5f9 !important; }

/* v383: 修复 v294 污染——日常收支明细用 v383 浅色庄重基线覆盖 v294 深色甘特图样式
   v294 的 .grid-table-wrap { border-radius: 4px } + 深色表头污染了所有 grid-table 表格,
   v295 单独修了 #inv_itemsTable,但日常收支一直没用回原浅色。这里把财务收支明细覆盖回 v383 */
.fin-items-section > .grid-table-wrap { border-radius: 8px; border-color: #d0d5db; box-shadow: 0 2px 4px rgba(15, 23, 42, 0.04); }
.fin-items-section .grid-table thead th { background: #f1f5f9 !important; color: var(--gray-800) !important; font-weight: 700 !important; font-size: 13px !important; border-bottom: 2px solid #d0d5db !important; letter-spacing: 0.2px !important; border-right: 1px solid #e8ebef !important; }
.fin-items-section .grid-table thead th:last-child { border-right: none !important; }
.fin-items-section .grid-table tbody tr { height: 44px; }
.fin-items-section .grid-table tbody td { border-right: 1px solid #f0f2f5; }
.fin-items-section .grid-table tbody td:last-child { border-right: none; }
.fin-items-section .grid-table tfoot tr td { background: #f8fafc !important; border-top: 2px solid #d0d5db; border-right: 1px solid #f0f2f5; }

/* cell 内表单控件全部透明,hover/focus 才显边框 → "无法填写"错觉消失 */
.grid-table td.cell-name input,
.grid-table td.cell-unit input,
.grid-table td.cell-qty input,
.grid-table td.cell-price input,
.grid-table td.cell-note input,
.grid-table td.cell-contract select {
  width: 100%;
  border: 1px solid transparent;
  background: transparent;
  border-radius: 4px;  /* v383: var(--radius-sm)→4px 略小让单元格更紧凑 */
  padding: 8px 10px;  /* v383: 7x8→8x10 略增 */
  font-size: 14px;  /* v383: 13→14 与 v381 表单 token 一致 */
  color: var(--gray-800);
  line-height: 1.4;
  transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
}
.grid-table td.cell-qty input,
.grid-table td.cell-price input { text-align: right; }
.grid-table td.cell-name input::placeholder,
.grid-table td.cell-unit input::placeholder,
.grid-table td.cell-qty input::placeholder,
.grid-table td.cell-price input::placeholder,
.grid-table td.cell-note input::placeholder { color: var(--gray-400); }
.grid-table td.cell-name input:hover,
.grid-table td.cell-unit input:hover,
.grid-table td.cell-qty input:hover,
.grid-table td.cell-price input:hover,
.grid-table td.cell-note input:hover,
.grid-table td.cell-contract select:hover {
  background: var(--card-bg);
  border-color: #cbd5e1;  /* v383: var(--border)→#cbd5e1 更显 */
}
.grid-table td.cell-name input:focus,
.grid-table td.cell-unit input:focus,
.grid-table td.cell-qty input:focus,
.grid-table td.cell-price input:focus,
.grid-table td.cell-note input:focus,
.grid-table td.cell-contract select:focus {
  background: var(--card-bg);
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(79, 107, 237, .15);  /* v383: 2→3px 阴影更显 */
  outline: none;
}

/* 整体拖拽态 */
body.col-resizing { cursor: col-resize !important; user-select: none; }
body.col-resizing * { cursor: col-resize !important; user-select: none !important; }
body.col-resizing .grid-table-wrap { cursor: col-resize; }

/* 只读视图（详情页复用同套视觉） */
.grid-table.is-readonly td { padding: 10px 12px; }
.grid-table.is-readonly td.cell-subtotal { padding: 8px 12px; }
.grid-table.is-readonly tfoot td {
  padding: 12px;
  background: var(--gray-50, #f8f9fb);
  border-top: 2px solid var(--border);
}


/* ==========================================
   v224→v225: 采购明细 Excel 化（保留视觉）
   - v225 移除行高拖拽与行高列宽设置面板（用户要求去掉）
   - 保留：编辑态单元格控件铺满（td padding 0 + 控件 height:100%）
   - 保留：序号列 Excel 行号风格
   - 行高固定 40px（td padding 4px 上下 + 控件撑满）
   ========================================== */

/* 固定行高 */
.grid-table tbody tr { height: 44px; }  /* v383: 40→44 更舒展 */

/* 编辑态单元格铺满（覆盖 v223 的 padding；readonly 由 .is-readonly 更高特异性保持） */
.grid-table tbody td { padding: 0; }
.grid-table tbody td.cell-name input,
.grid-table tbody td.cell-unit input,
.grid-table tbody td.cell-qty input,
.grid-table tbody td.cell-price input,
.grid-table tbody td.cell-note input,
.grid-table tbody td.cell-contract select {
  height: 100%;
  padding: 0 8px;
  border-radius: 0;
}
.grid-table tbody td.cell-contract select { padding: 0 4px; }

/* 序号列更像 Excel 行号：灰底 + 右侧分隔线 */
.grid-table tbody td.cell-idx {
  background: #f5f7fa;  /* v383: var(--gray-50)→#f5f7fa 更明显 */
  border-right: 1px solid #e8ebef;
  font-size: 12px;  /* v383: 11→12 与表头协调 */
  color: var(--gray-500);
  font-weight: 600;
}

/* 工具栏（仅保留列宽提示） */
.pu-tbl-toolbar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.pu-tbl-hint { font-size: 12px; color: var(--gray-400); user-select: none; }

/* ==========================================
   v294: 采购明细表格「甘特图同款外观」（仅观感 · 填写交互不变）
   - 表头深灰 #404040 白字（对齐甘特图 wkHead 行）
   - 单元格四周细格线 → Excel 网格观感（编辑态与只读详情统一）
   - 序号列灰底加粗（更贴近甘特图左侧行号列）
   - 行高 40px→36px 微紧凑，输入控件仍铺满整格
   - 格线走 --border-light 变量，深浅主题自适应
   ========================================== */
.grid-table-wrap {
  border-color: var(--border, #d7dce3);
  border-radius: 4px;
}
.grid-table thead th {
  background: #404040;
  color: #fff;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: .02em;
  border-bottom: 1px solid #333;
  border-right: 1px solid rgba(255, 255, 255, .16);
}
.grid-table thead th:last-child { border-right: none; }
/* 深色表头下的拖拽把手指示线 */
.grid-table thead th .col-resize::before { background: rgba(255, 255, 255, .4); }
.grid-table thead th .col-resize:hover::before,
.grid-table thead th .col-resize.dragging::before { background: #fff; }
/* 全格细线（编辑态 + 只读态） */
.grid-table tbody td,
.grid-table tfoot td {
  border-right: 1px solid var(--border-light, #eef1f5);
  border-bottom: 1px solid var(--border-light, #eef1f5);
}
.grid-table tbody td:last-child,
.grid-table tfoot td:last-child { border-right: none; }
/* 行高微紧凑（控件仍由 v224 撑满） */
.grid-table tbody tr { height: 36px; }
/* 序号列：甘特图行号感 —— 灰底 + 加粗 */
.grid-table tbody td.cell-idx {
  background: var(--gray-100, #f3f4f6);
  color: var(--gray-600, #4b5563);
  font-size: 12px;
  font-weight: 700;
}
/* 只读 tfoot 合计行沿用细格线 */
.grid-table.is-readonly tfoot td {
  border-top: 2px solid var(--border, #d7dce3);
  background: var(--gray-50, #f8f9fb);
}

/* ==========================================
   v295: 发票明细「WPS/Excel 网格观感」（仅观感 · 填写交互不变）
   - 复用 v294 grid-table 外观（深灰表头白字 / 四周细格线 / 序号列灰底 / 行高 36px）
   - 发票的明细输入仍用 .inv-cell（带 .form-input 边框），此块把 #inv_itemsTable 内的
     .inv-cell 也透明化铺满整格（对齐采购明细编辑手感），hover/focus 才显边框
   - 数值列右对齐；placeholder 浅灰；删除按钮由 grid CSS 的 .cell-op/.grid-row-del 覆盖
   - 仅作用于 id=inv_itemsTable，不污染采购明细（grid-table 仍仅 procurement 使用）
   ========================================== */
#inv_itemsTable.grid-table thead th { background: #404040; color: #fff; font-weight: 600; font-size: 12px; }
#inv_itemsTable .grid-table-wrap { margin-top: 0; }
#inv_itemsTable tbody tr { height: 36px; }
#inv_itemsTable tbody td.cell-idx {
  background: var(--gray-100, #f3f4f6);
  color: var(--gray-600, #4b5563);
  font-size: 12px;
  font-weight: 700;
}
#inv_itemsTable tbody td { padding: 0; }
#inv_itemsTable td.cell-op { text-align: center; padding: 0; }
#inv_itemsTable .inv-cell {
  width: 100%;
  height: 100%;
  border: 1px solid transparent;
  background: transparent;
  border-radius: 0;
  padding: 0 8px;
  font-size: 13px;
  color: var(--gray-800, #1f2937);
  line-height: 1.4;
  box-shadow: none;
  transition: border-color 0.15s, background 0.15s;
}
#inv_itemsTable .inv-cell[type="number"] { text-align: right; }
#inv_itemsTable .inv-cell::placeholder { color: var(--gray-400, #9ca3af); }
#inv_itemsTable .inv-cell:hover {
  background: var(--card-bg, #fff);
  border-color: var(--border, #d7dce3);
}
#inv_itemsTable .inv-cell:focus {
  background: var(--card-bg, #fff);
  border-color: var(--primary, #4f6bed);
  box-shadow: 0 0 0 2px rgba(79, 107, 237, .12);
  outline: none;
}

/* ==========================================
   v227: 项目名 hover 合作伙伴浮卡
   - 纯 CSS 实现：.pc-name-tip:hover::after 显示 data-tip 内容
   - 白色卡片 + 边框 + 阴影 + 渐显，z-index 50 不被遮挡
   - 移动端长按/聚焦也能看到（无 JS 事件依赖）
   ========================================== */
.pc-name-tip { position: relative; cursor: help; }
.pc-name-tip::after {
  content: attr(data-tip);
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 50;
  min-width: 240px;
  max-width: 460px;
  padding: 10px 12px;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border, #e2e6ed);
  border-radius: 6px;
  box-shadow: 0 4px 16px rgba(15, 23, 42, .12);
  font-size: 12px;
  font-weight: 400;
  color: var(--gray-700, #475569);
  line-height: 1.6;
  text-align: left;
  white-space: normal;
  word-break: break-all;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s ease, visibility .15s ease;
}
.pc-name-tip:hover::after,
.pc-name-tip:focus::after {
  opacity: 1;
  visibility: visible;
}

/* ============================================================
   v262: 顶栏头像下拉菜单（个人设置/退出登录/版本更新摘要）
   ============================================================ */
.user-menu {
  position: fixed;
  z-index: 1600;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border, #e2e6ed);
  border-radius: 10px;
  box-shadow: 0 8px 28px rgba(15, 23, 42, .16);
  overflow: hidden;
  font-size: 13px;
}
.um-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-light, #f0f1f3);
}
.um-head-info { min-width: 0; }
.um-head-name {
  font-weight: 600;
  color: var(--gray-800, #1e293b);
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.um-head-sub {
  font-size: 12px;
  color: var(--text-tertiary, #94a3b8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.um-actions { padding: 6px; }
.um-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 6px;
  color: var(--gray-700, #475569);
  cursor: pointer;
  user-select: none;
}
.um-item:hover { background: var(--gray-50, #f8fafc); color: var(--primary); }
.um-item.um-danger:hover { color: var(--danger, #dc2626); }
.um-ver-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 14px 6px;
  border-top: 1px solid var(--border-light, #f0f1f3);
  font-size: 12px;
  font-weight: 600;
  color: var(--gray-500, #64748b);
}
.um-ver-cur-badge {
  font-weight: 500;
  font-size: 11px;
  color: var(--primary, #2563eb);
  background: var(--primary-bg, #eff6ff);
  border-radius: 10px;
  padding: 2px 8px;
}
.um-ver-list {
  max-height: 220px;
  overflow-y: auto;
  padding: 0 8px 8px;
}
.um-ver-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 6px;
  border-radius: 6px;
  line-height: 1.5;
  /* v299: 压缩为一行——版本号固定最左，摘要单行省略，不再折行撑高菜单 */
  white-space: nowrap;
  overflow: hidden;
}
.um-ver-row.cur {
  background: var(--primary-bg, #eff6ff);
  color: var(--gray-800, #1e293b);
}
.um-ver-num {
  flex: 0 0 auto;
  font-weight: 600;
  font-size: 12px;
  color: var(--gray-500, #64748b);
  font-variant-numeric: tabular-nums;
}
.um-ver-row.cur .um-ver-num { color: var(--primary, #2563eb); }
.um-ver-desc {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12px;
  color: var(--gray-600, #475569);
  /* v299: 摘要单行省略（容器不够宽自动 … 截断），不再 break-all 折行 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
}
.um-ver-row.cur .um-ver-desc { color: var(--gray-800, #1e293b); }
.um-cur-tag {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  color: #fff;
  background: var(--primary, #2563eb);
  border-radius: 8px;
  padding: 1px 6px;
}
.um-ver-empty {
  padding: 10px 6px;
  font-size: 12px;
  color: var(--text-tertiary, #94a3b8);
  text-align: center;
}

/* ============ v265 采购层级审批时间线 ============ */
.approval-timeline {
  border-left: 2px solid var(--border-color, #e5e7eb);
  padding-left: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.at-item { position: relative; }
.at-dot {
  position: absolute;
  left: -23px;
  top: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  font-size: 10px;
  line-height: 16px;
  text-align: center;
  color: #fff;
  font-weight: 600;
}
.at-dot.ok { background: var(--success, #16a34a); }
.at-dot.no { background: var(--danger, #dc2626); }
.at-body { font-size: 13px; }
.at-head { color: var(--gray-800, #1f2937); line-height: 1.5; }
.at-meta { font-size: 12px; color: var(--text-tertiary, #94a3b8); margin-top: 2px; }
.at-note { font-size: 12px; color: var(--gray-600, #4b5563); margin-top: 2px; }
/* ============================================
   v303 智慧屏大屏（PMO.Smart）—— 深色沉浸式项目作战大屏
   独立深色体系（不随主题切换）；数据范围由 getVisibleProjects() 控制
   v528 重新规划：彻底填满视口（消灭底部空白）+ KPI 环形仪表 + 任务状态分布 +
        焦点区三栏 + 甘特回归主板块 + 全屏字号基线 ≥12px
   ============================================ */
.smart-screen {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: calc(100vh - var(--topbar-h, 60px) - 44px);
  padding: 18px 20px 14px;
  border-radius: 18px;
  color: #e6edf7;
  font-family: var(--font);
  overflow: hidden;
  background-color: #0a1020;
  background-image:
    radial-gradient(1100px 560px at 6% -12%, rgba(56, 111, 248, 0.17), transparent 60%),
    radial-gradient(900px 480px at 104% 4%, rgba(56, 189, 248, 0.10), transparent 55%),
    radial-gradient(860px 560px at 50% 118%, rgba(52, 211, 153, 0.07), transparent 60%);
  border: 1px solid rgba(148, 163, 184, 0.14);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
.smart-screen * { box-sizing: border-box; }

/* ---------- 头部：标题 + 时钟 ---------- */
.smart-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 2px 4px 0;
}
.smart-title {
  font-size: clamp(21px, 2.1vw, 32px);
  font-weight: 800;
  letter-spacing: 1px;
  color: #f1f5fb;
  text-shadow: 0 0 24px rgba(96, 165, 250, 0.35);
  line-height: 1.2;
}
.smart-title::before {
  content: "";
  display: inline-block;
  width: 10px;
  height: 22px;
  margin-right: 10px;
  border-radius: 3px;
  vertical-align: -2px;
  background: linear-gradient(180deg, #38bdf8, #4f6bed);
  box-shadow: 0 0 12px rgba(56, 189, 248, 0.6);
}
.smart-sub {
  margin-top: 6px;
  font-size: 13px;
  color: #93a5bd;
  letter-spacing: 0.4px;
}
.smart-clock-box { text-align: right; }
.smart-clock {
  font-size: clamp(24px, 2.6vw, 40px);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 2px;
  color: #dbeafe;
  line-height: 1.05;
  text-shadow: 0 0 18px rgba(59, 130, 246, 0.45);
}
.smart-date { margin-top: 4px; font-size: 13px; color: #93a5bd; }

/* ---------- KPI 统计卡 ---------- */
.smart-kpis {
  display: grid;
  grid-template-columns: repeat(5, minmax(140px, 1fr));
  gap: 12px;
}
/* v528: KPI 卡从「居中一个数字 + 一行小字」改为「左文右环」的仪表盘布局 ——
   每张卡都带一个 0~100 的语义占比环，五个指标一眼可比。 */
.smart-kpi {
  position: relative;
  min-width: 0;
  min-height: 132px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px 18px;
  border-radius: 16px;
  background: rgba(148, 163, 184, 0.07);
  border: 1px solid rgba(148, 163, 184, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.sk-main { min-width: 0; flex: 1 1 auto; }
.sk-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 7px;
  border-radius: 50%;
  vertical-align: 1px;
}
.sk-label {
  font-size: 13px;
  font-weight: 600;
  color: #a9bbd3;
  letter-spacing: 0.6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sk-value {
  margin: 7px 0 5px;
  font-size: clamp(32px, 2.9vw, 50px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -1px;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 22px currentColor;
}
.sk-sub {
  font-size: 13px;
  color: #8095b0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* v528: KPI 环形进度（SVG 双圆，用 stroke-dasharray 画占比弧） */
.sk-ring { flex: none; display: block; }
.sk-ring-txt {
  font-family: var(--font);
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---------- 甘特面板 ---------- */
.smart-panel {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 300px;
  border-radius: 16px;
  overflow: hidden;
  background: rgba(10, 16, 32, 0.55);
  border: 1px solid rgba(148, 163, 184, 0.13);
}
.sg-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 18px;
  border-bottom: 1px solid rgba(148, 163, 184, 0.12);
}
.sg-legend { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.sg-lg { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: #c3d0e2; }
.sg-lg i { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.sg-hint { font-size: 12px; color: #7d8ea6; }

/* 滚动区 .sg-rows：thead sticky + 行同处一个滚动容器（同一内容宽度 → 刻度与条 % 坐标对齐）
   v308：加 overflow-x 支持滚轮缩放后的横向滚动（双向滚动，thead/左右列 sticky 均相对此容器） */
.sg-rows {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(148, 163, 184, 0.35) transparent;
}
.sg-rows::-webkit-scrollbar { width: 9px; }
.sg-rows::-webkit-scrollbar-thumb { background: rgba(148, 163, 184, 0.28); border-radius: 6px; }
.sg-rows::-webkit-scrollbar-track { background: transparent; }

.sg-thead {
  position: sticky;
  top: 0;
  z-index: 4;
  background: #0c1428;
  border-bottom: 1px solid rgba(148, 163, 184, 0.14);
}

/* 三列网格（标签 | 时间轨道 | 状态）—— thead 与行共用同一列宽 */
.sg-grid {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr) 120px;
  align-items: center;
}
.sg-row { cursor: pointer; transition: background 0.18s ease; }
.sg-row:hover { background: rgba(148, 163, 184, 0.09); }
.sg-row + .sg-row { border-top: 1px solid rgba(148, 163, 184, 0.07); }

/* ---------- v308: 滚轮缩放横向滚动 —— 左右列 sticky 固定不随横滚（实底遮盖滑过的条形） ---------- */
.sg-rows .sg-thead .sg-col-lbl,
.sg-rows .sg-thead .sg-col-state { background: #0c1428; }
.sg-rows .sg-col-lbl {
  position: sticky;
  left: 0;
  z-index: 2;
  background: #0c1424;
  box-shadow: 6px 0 8px -6px rgba(0, 0, 0, 0.55);
}
.sg-rows .sg-col-state {
  position: sticky;
  right: 0;
  z-index: 2;
  background: #0c1424;
  box-shadow: -6px 0 8px -6px rgba(0, 0, 0, 0.55);
}
.sg-row:hover .sg-col-lbl,
.sg-row:hover .sg-col-state { background: #141c2b; }
.sg-row.expanded .sg-col-lbl,
.sg-row.expanded .sg-col-state { background: #102539; }

/* 左列 */
/* v528: 原实现是单行 flex —— 项目名/锁标/编号负责人三段互相挤压，
   232px 列里项目名只剩约 60px（截图实测「酒吧…」）。改为上下两行独立展示。 */
.sg-col-lbl {
  min-width: 0;
  padding: 9px 12px 9px 16px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 3px;
}
.sg-lbl-top { display: flex; align-items: center; gap: 6px; min-width: 0; }
.sg-lbl-top .sg-pname { flex: 1 1 auto; }
.sg-pname {
  font-size: 15px;
  font-weight: 600;
  color: #dbe6f5;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.sg-lock { font-size: 12px; flex-shrink: 0; }
.sg-row-meta {
  font-size: 13px;
  color: #7d8ea6;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 中列：轨道（同坐标体系） */
.sg-track {
  position: relative;
  height: 54px;
  min-width: 0;
  overflow: hidden;
}
.sg-track-head { height: 40px; }
/* v306 日期刻度（MM/DD，密度自适应；沿用旧月份刻度样式值改名而来） */
.sg-tick {
  position: absolute;
  top: 11px;
  transform: translateX(-50%);
  font-size: 12px;
  color: #8b9cb5;
  white-space: nowrap;
  pointer-events: none;
}
.sg-tick::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 21px;
  width: 1px;
  height: 7px;
  background: rgba(148, 163, 184, 0.3);
}

/* v530：刻度标签自适应避让 —— 与已保留标签间距不足的刻度整体隐藏
   （只由 js/smart.js 的 PMO.Smart.fitTicks() 运行时可逆地加/去这个类） */
.sg-tick.is-hidden { display: none; }
/* 月份底色交替（列视觉） */
.sg-track-zone { position: absolute; top: 0; bottom: 0; pointer-events: none; }

.sg-bar {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: 24px;
  min-height: 24px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  white-space: nowrap;
  cursor: pointer;
  transition: filter 0.18s ease, height 0.18s ease;
}
.sg-bar-txt {
  padding: 0 12px;
  font-size: 13px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.95);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  white-space: nowrap;
}
.sg-row:hover .sg-bar { filter: brightness(1.2); height: 28px; }
.sg-today {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  border-radius: 1px;
  background: rgba(251, 191, 36, 0.65);
  box-shadow: 0 0 6px rgba(251, 191, 36, 0.5);
  pointer-events: none;
}
.sg-today::before {
  content: "";
  position: absolute;
  top: -1px;
  left: -3px;
  border: 4px solid transparent;
  border-top: 6px solid rgba(251, 191, 36, 0.9);
}

/* 右列：状态 */
.sg-col-state {
  padding: 0 16px 0 8px;
  text-align: right;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 3px;
  min-width: 0;
}
.sg-state { font-size: 13px; font-weight: 600; white-space: nowrap; }
/* v528: 进度百分比升为右列主视觉（13→18px 加粗），与左侧状态形成「状态 + 进度」两级 */
.sg-state-pct { font-size: 18px; font-weight: 800; color: #c3d0e2; font-variant-numeric: tabular-nums; line-height: 1; }

/* 空态 */
.sg-empty {
  padding: 54px 20px;
  text-align: center;
  color: #7d8ea6;
  font-size: 14px;
}
.sg-empty-icon { font-size: 44px; margin-bottom: 12px; }
.sg-empty-sub { margin-top: 8px; font-size: 13px; color: #7d8ea6; }

/* 底部提示条 */
.smart-foot {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  color: #7d8ea6;
  padding: 0 6px;
}

/* ---------- v312: 任务视角主板块（逾期预警 + 本周到期） ---------- */
/* v528: 2 栏 → 3 栏（任务状态分布 / 逾期预警 / 本周到期）；
   固定高 262px —— 改前焦点区实际只有 119px，列表只看得见 1 行。 */
.smart-focus {
  display: grid;
  grid-template-columns: minmax(0, 0.94fr) minmax(0, 1.03fr) minmax(0, 1.03fr);
  grid-template-rows: minmax(0, 1fr);
  gap: 12px;
  flex: none;
  height: 262px;
  min-width: 0;
}
.sf-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  border-radius: 16px;
  overflow: hidden;
  background: rgba(10, 16, 32, 0.55);
  border: 1px solid rgba(148, 163, 184, 0.13);
}
.sf-panel.sf-overdue { border-color: rgba(224, 36, 36, 0.22); }
.sf-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid rgba(148, 163, 184, 0.12);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.5px;
}
.sf-overdue .sf-head { color: #fca5a5; }
.sf-overdue .sf-head::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #e02424;
  box-shadow: 0 0 10px rgba(224, 36, 36, 0.85);
}
.sf-week .sf-head { color: #fcd34d; }
.sf-week .sf-head::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #f59e0b;
  box-shadow: 0 0 10px rgba(245, 158, 11, 0.8);
}
.sf-count {
  margin-left: auto;
  font-size: 13px;
  font-weight: 600;
  padding: 1px 10px;
  border-radius: 999px;
  background: rgba(148, 163, 184, 0.15);
  color: #c3d0e2;
  font-variant-numeric: tabular-nums;
}
.sf-count.hot { background: rgba(224, 36, 36, 0.22); color: #fca5a5; }
.sf-week .sf-count.hot { background: rgba(245, 158, 11, 0.18); color: #fcd34d; }
.sf-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(148, 163, 184, 0.35) transparent;
}
.sf-list::-webkit-scrollbar { width: 8px; }
.sf-list::-webkit-scrollbar-thumb { background: rgba(148, 163, 184, 0.28); border-radius: 6px; }
.sf-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 16px;
  cursor: pointer;
  transition: background 0.18s ease;
}
.sf-row:hover { background: rgba(148, 163, 184, 0.09); }
.sf-row + .sf-row { border-top: 1px solid rgba(148, 163, 184, 0.07); }
.sf-main { min-width: 0; flex: 1; }
.sf-name {
  font-size: 14px;
  color: #e6edf7;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sf-meta {
  margin-top: 3px;
  font-size: 12px;
  color: #7d8ea6;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sf-badge {
  flex: none;
  font-size: 12px;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.b-late { color: #fca5a5; background: rgba(224, 36, 36, 0.18); border: 1px solid rgba(224, 36, 36, 0.42); }
.b-today { color: #fda4af; background: rgba(244, 63, 94, 0.16); border: 1px solid rgba(244, 63, 94, 0.42); }
.b-tomorrow { color: #fcd34d; background: rgba(245, 158, 11, 0.14); border: 1px solid rgba(245, 158, 11, 0.42); }
.b-week { color: #93c5fd; background: rgba(59, 130, 246, 0.14); border: 1px solid rgba(59, 130, 246, 0.4); }
.sf-empty {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px 16px;
  text-align: center;
  color: #7d8ea6;
  font-size: 13px;
}
.sf-empty-ok {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-right: 6px;
  border-radius: 50%;
  background: rgba(52, 211, 153, 0.15);
  color: #34d399;
  font-size: 12px;
  vertical-align: -4px;
}
.sf-more {
  padding: 8px 16px;
  font-size: 12px;
  color: #7d8ea6;
  text-align: center;
  border-top: 1px solid rgba(148, 163, 184, 0.07);
}

/* ---------- v528: 任务状态分布面板（堆叠条 + 图例 + 完成率） ---------- */
.sm-panel { padding: 0; }
.sm-stack {
  display: flex;
  align-items: stretch;
  height: 30px;
  margin: 14px 16px 12px;
  border-radius: 8px;
  overflow: hidden;
  background: rgba(148, 163, 184, 0.12);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35);
}
.sm-seg { display: block; min-width: 3px; transition: filter 0.18s ease; }
.sm-seg + .sm-seg { box-shadow: -1px 0 0 rgba(6, 11, 24, 0.85); }
.sm-seg:hover { filter: brightness(1.18); }
.sm-legend {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 16px;
}
.sm-lg {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr) auto 52px;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  font-size: 13px;
}
.sm-lg + .sm-lg { border-top: 1px solid rgba(148, 163, 184, 0.08); }
.sm-lg i { width: 12px; height: 12px; border-radius: 4px; display: block; }
.sm-lg-t { color: #c3d0e2; }
.sm-lg-n { font-size: 17px; font-weight: 800; font-variant-numeric: tabular-nums; text-align: right; }
.sm-lg-p { font-size: 13px; color: #7d8ea6; font-variant-numeric: tabular-nums; text-align: right; }
.sm-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 11px 16px;
  border-top: 1px solid rgba(148, 163, 184, 0.12);
  font-size: 13px;
  color: #93a5bd;
}
.sm-foot b { font-size: 16px; font-weight: 800; font-variant-numeric: tabular-nums; }
.sm-rate b { color: #34d399; }
.sm-risk b { color: #94a3b8; }
.sm-risk[data-hot="1"] b { color: #fb7185; }

/* v528: 原 v312 的 .mini 限高已取消 —— 它正是大屏底部约 320px 空白的来源。
   甘特回归主板块：.smart-panel 用 flex:1 吸收全部剩余高度，行区内部纵向滚动。 */
.sg-title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: #e2ebf7;
}

/* ---------- 响应式 ---------- */
@media (max-width: 1280px) {
  .sg-grid { grid-template-columns: 248px minmax(0, 1fr) 108px; }
  .smart-kpis { grid-template-columns: repeat(5, minmax(118px, 1fr)); }
}
@media (max-width: 1024px) {
  .sg-grid { grid-template-columns: 208px minmax(0, 1fr) 96px; }
  /* v528: 窄屏改回纵向堆叠 —— 固定高会让三栏各被压成 ~87px */
  .smart-focus { grid-template-columns: 1fr; grid-template-rows: none; height: auto; }
  .sf-panel { max-height: 320px; }
  .smart-panel { min-height: 220px; }
}
@media (max-width: 860px) {
  .smart-screen { padding: 14px 14px 10px; min-height: 0; }
  .smart-kpis { grid-template-columns: repeat(3, 1fr); }
  .sg-grid { grid-template-columns: 176px minmax(0, 1fr); }
  .sg-col-state { display: none; }
  .smart-clock { font-size: 26px; }
}

/* ---------- v304: 大屏全屏投放 ---------- */
.smart-head-side { display: flex; align-items: center; gap: 14px; }
.smart-fs-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: 10px;
  flex-shrink: 0;
  font-size: 13px;
  font-weight: 600;
  font-family: var(--font);
  line-height: 1;
  color: #cfe0f5;
  cursor: pointer;
  background: rgba(148, 163, 184, 0.08);
  border: 1px solid rgba(148, 163, 184, 0.28);
  transition: all 0.18s ease;
}
.smart-fs-btn:hover {
  color: #fff;
  background: rgba(56, 189, 248, 0.16);
  border-color: rgba(56, 189, 248, 0.55);
  box-shadow: 0 0 12px rgba(56, 189, 248, 0.25);
}
.smart-fs-btn:active { transform: translateY(1px); }
.smart-fs-btn[data-on="1"] {
  background: rgba(224, 36, 36, 0.16);
  border-color: rgba(248, 113, 113, 0.55);
  color: #fecaca;
}
.smart-fs-btn[data-on="1"]:hover {
  background: rgba(224, 36, 36, 0.24);
  border-color: #f87171;
  color: #fff;
}
.smart-fs-btn svg { flex-shrink: 0; display: block; }

/* 全屏态：铺满视口 + 去圆角（浏览器 top layer 已隐藏侧栏/顶栏外壳） */
.smart-screen:fullscreen {
  width: 100%;
  height: 100%;
  border-radius: 0;
}
.smart-screen:-webkit-full-screen {
  width: 100%;
  height: 100%;
  border-radius: 0;
}

/* ---------- v305: 智慧屏行内展开（任务级迷你甘特 + 任务动态） ---------- */
/* 展开态行高亮：左侧蓝色光条 + 微蓝底 */
.sg-row.expanded {
  background: rgba(56, 189, 248, 0.1);
  box-shadow: inset 3px 0 0 #38bdf8;
}
.sg-row.expanded:hover { background: rgba(56, 189, 248, 0.14); }

/* 展开面板：作为 .sg-row 的兄弟节点插入 */
.sg-exp {
  background: rgba(6, 11, 24, 0.6);
  border-bottom: 1px solid rgba(148, 163, 184, 0.12);
  padding: 12px 16px 14px 28px;
  animation: sgExpIn 0.22s ease;
}
@keyframes sgExpIn {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}
.sg-exp-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.sg-exp-title {
  font-size: 12px;
  font-weight: 700;
  color: #9fd4ff;
  letter-spacing: 0.5px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sg-exp-sub { margin-left: 10px; font-size: 12px; font-weight: 400; color: #7d8ea6; }
.sg-exp-open {
  flex-shrink: 0;
  font-family: var(--font);
  font-size: 12px;
  font-weight: 600;
  color: #9fd4ff;
  background: rgba(56, 189, 248, 0.1);
  border: 1px solid rgba(56, 189, 248, 0.35);
  border-radius: 8px;
  padding: 5px 10px;
  cursor: pointer;
  transition: all 0.18s ease;
}
.sg-exp-open:hover {
  color: #fff;
  background: rgba(56, 189, 248, 0.22);
  border-color: #38bdf8;
  box-shadow: 0 0 10px rgba(56, 189, 248, 0.3);
}
.sg-exp-empty { padding: 18px 0 8px; text-align: center; font-size: 12px; color: #64748b; }

/* 任务迷你甘特行（复用项目级时间轴坐标，同轴对齐） */
.sg-tk-list { display: flex; flex-direction: column; }
.sg-tk-row {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  align-items: center;
  padding: 2px 0;
}
.sg-tk-row + .sg-tk-row { border-top: 1px dashed rgba(148, 163, 184, 0.07); }
/* v308: 任务标题列 sticky —— 面板随网格拉伸横向滚动时锁定左侧（实底近似 .sg-exp 叠深底色） */
.sg-tk-lbl {
  min-width: 0;
  padding: 4px 10px 4px 0;
  position: sticky;
  left: 0;
  background: #0a101d;
  box-shadow: 6px 0 8px -6px rgba(0, 0, 0, 0.5);
}
.sg-tk-name {
  font-size: 13px;
  font-weight: 600;
  color: #c9d6e8;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sg-tk-meta {
  margin-top: 2px;
  font-size: 12px;
  color: #7d8ea6;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sg-tk-row.sg-tk-delayed .sg-tk-name { color: #fda4af; }
.sg-tk-track { position: relative; height: 30px; min-width: 0; overflow: hidden; }
.sg-tk-bar {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: 12px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  overflow: hidden;
  box-shadow: 0 1px 8px rgba(0, 0, 0, 0.35);
}
.sg-tk-pct {
  padding: 0 5px;
  font-size: 11px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.95);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
.sg-tk-delayed .sg-tk-bar { box-shadow: 0 0 10px rgba(224, 36, 36, 0.4); }

/* 任务动态（动作分色 chip 内联样式注入） */
.sg-act { margin-top: 12px; border-top: 1px solid rgba(148, 163, 184, 0.1); padding-top: 10px; }
.sg-act-head {
  font-size: 11px;
  font-weight: 700;
  color: #8fa3c4;
  letter-spacing: 1px;
  margin-bottom: 8px;
}
.sg-act-list {
  display: flex;
  flex-direction: column;
  gap: 5px;
  max-height: 172px;
  overflow-y: auto;
}
.sg-act-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  min-width: 0;
}
.sg-act-chip {
  flex-shrink: 0;
  padding: 1px 7px;
  border-radius: 9px;
  border: 1px solid;
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
}
.sg-act-user { flex-shrink: 0; color: #c3d0e2; font-weight: 600; }
.sg-act-target {
  flex-shrink: 0;
  color: #9fb2cc;
  font-weight: 600;
  max-width: 180px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sg-act-detail {
  flex: 1;
  min-width: 0;
  color: #64748b;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sg-act-time { flex-shrink: 0; color: #52637c; font-variant-numeric: tabular-nums; }
.sg-act-empty { padding: 6px 0; font-size: 11px; color: #5c6f8a; }

@media (max-width: 1024px) {
  .sg-tk-row { grid-template-columns: 150px minmax(0, 1fr); }
  .sg-act-target { max-width: 120px; }
}


/* ============ v320: AI 智能办公——悬浮球 + 对话面板 ============ */
/* z-index 铁律：990/991 低于 modal-overlay(999)，弹窗打开时 AI 面板被自然覆盖 */

.ai-fab {
  position: fixed; right: 24px; bottom: 24px; z-index: 990;
  width: 48px; height: 48px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #fff; cursor: pointer;
  background: linear-gradient(135deg, #4f6bed, #8b5cf6);
  box-shadow: 0 6px 18px rgba(79, 107, 237, .35);
  transition: transform .15s ease, box-shadow .15s ease;
  user-select: none;
}
.ai-fab:hover { transform: translateY(-2px) scale(1.05); box-shadow: 0 10px 24px rgba(79, 107, 237, .45); }
.ai-fab.active { transform: scale(.92); }

.ai-panel {
  position: fixed; right: 24px; bottom: 84px; z-index: 991;
  width: 420px; max-width: calc(100vw - 32px);
  height: min(600px, calc(100vh - 120px));
  display: flex; flex-direction: column;
  background: var(--card-bg); border: 1px solid var(--gray-200); border-radius: 14px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, .18);
  opacity: 0; visibility: hidden; transform: translateY(12px) scale(.98);
  transition: all .18s ease; overflow: hidden;
}
.ai-panel.open { opacity: 1; visibility: visible; transform: none; }

.ai-head {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--gray-200);
  background: linear-gradient(135deg, rgba(79, 107, 237, .08), rgba(139, 92, 246, .08));
}
.ai-title { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; color: var(--gray-900); }
.ai-title svg { color: var(--primary, #4f6bed); }
.ai-mode {
  font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 10px;
  background: var(--gray-100); color: var(--gray-500); margin-left: 4px;
}
.ai-mode.on { background: rgba(34, 197, 94, .12); color: #16a34a; }
.ai-close { cursor: pointer; color: var(--gray-400); padding: 4px; border-radius: 6px; display: flex; }
.ai-close:hover { color: var(--gray-700); background: var(--gray-200); }

.ai-chips {
  flex: 0 0 auto; display: flex; gap: 6px; flex-wrap: wrap;
  padding: 10px 12px 4px;
}
.ai-chip {
  font-size: 12px; padding: 5px 10px; border-radius: 14px; cursor: pointer;
  background: var(--gray-100); color: var(--gray-600);
  border: 1px solid var(--gray-200); transition: all .12s ease;
}
.ai-chip:hover { background: var(--primary-bg, rgba(79, 107, 237, .08)); color: var(--primary, #4f6bed); border-color: var(--primary, #4f6bed); }

.ai-msgs { flex: 1; overflow-y: auto; min-height: 0; padding: 10px 14px; }
.ai-msg { display: flex; margin-bottom: 10px; }
.ai-msg.user { justify-content: flex-end; }
.ai-msg.bot { justify-content: flex-start; flex-direction: column; align-items: flex-start; }
.ai-bubble {
  max-width: 92%; padding: 9px 12px; border-radius: 12px;
  font-size: 13px; line-height: 1.7; word-break: break-word;
  white-space: normal;
}
.ai-msg.user .ai-bubble { background: var(--primary, #4f6bed); color: #fff; border-bottom-right-radius: 4px; }
.ai-msg.bot .ai-bubble {
  background: var(--gray-100); color: var(--text-secondary, var(--gray-700));
  border-bottom-left-radius: 4px;
}
.ai-bubble b, .ai-bubble strong { color: var(--gray-900); }
.ai-msg.user .ai-bubble b, .ai-msg.user .ai-bubble strong { color: #fff; }
.ai-md-h { font-weight: 700; color: var(--gray-900); margin-bottom: 2px; font-size: 14px; }
.ai-md-li { padding-left: 4px; }
.ai-copy {
  font-size: 11px; color: var(--gray-400); background: none; border: none;
  cursor: pointer; padding: 2px 6px; margin-top: -4px; border-radius: 4px;
}
.ai-copy:hover { color: var(--primary, #4f6bed); background: var(--gray-100); }

/* 生成中动画 */
.ai-typing-row .ai-bubble { display: flex; gap: 4px; align-items: center; }
.ai-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--gray-400);
  animation: aiBlink 1.2s infinite ease-in-out;
}
.ai-dot:nth-child(2) { animation-delay: .2s; }
.ai-dot:nth-child(3) { animation-delay: .4s; }
@keyframes aiBlink {
  0%, 80%, 100% { opacity: .25; transform: scale(.8); }
  40% { opacity: 1; transform: scale(1); }
}

.ai-inputbar {
  flex: 0 0 auto; display: flex; align-items: flex-end; gap: 8px;
  padding: 10px 12px; border-top: 1px solid var(--gray-200); background: var(--card-bg);
}
.ai-input {
  flex: 1; min-width: 0; resize: none; border: 1px solid var(--gray-200);
  border-radius: 10px; padding: 8px 10px; font-size: 13px; line-height: 1.5;
  background: var(--gray-50, var(--card-bg)); color: var(--gray-800);
  max-height: 96px; font-family: inherit;
}
.ai-input:focus { outline: none; border-color: var(--primary, #4f6bed); }
.ai-send {
  flex: 0 0 auto; width: 36px; height: 36px; border-radius: 10px; border: none;
  background: linear-gradient(135deg, #4f6bed, #8b5cf6); color: #fff; cursor: pointer;
  display: flex; align-items: center; justify-content: center; transition: opacity .12s;
}
.ai-send:hover { opacity: .88; }

/* 移动端：面板近全屏 */
@media (max-width: 768px) {
  .ai-fab { right: 16px; bottom: 16px; }
  .ai-panel {
    right: 8px; left: 8px; bottom: 74px; width: auto; max-width: none;
    height: min(560px, calc(100vh - 96px));
  }
}

/* ============================================================
   v332: 全局搜索命令面板（Ctrl+K / 顶栏搜索入口）
   独立于 v317/v318 弹窗栈体系——固定定位浮层，z-index 高于 modal-overlay(999)
   ============================================================ */
.search-palette { display: none; position: fixed; inset: 0; z-index: 1100; }
.search-palette.open { display: block; }
.sp-backdrop { position: absolute; inset: 0; background: rgba(15, 23, 42, .45); backdrop-filter: blur(1px); }
.sp-panel {
  position: relative; margin: 9vh auto 0; width: min(660px, calc(100vw - 32px));
  background: var(--card-bg, #fff); border: 1px solid var(--border, #e8eaed);
  border-radius: 14px; box-shadow: 0 24px 64px rgba(15, 23, 42, .28);
  display: flex; flex-direction: column; overflow: hidden;
  animation: spPop .14s ease-out;
}
@keyframes spPop { from { opacity: 0; transform: translateY(-8px) scale(.985); } to { opacity: 1; transform: none; } }
.sp-head {
  display: flex; align-items: center; gap: 10px; padding: 14px 16px;
  border-bottom: 1px solid var(--border, #e8eaed); color: var(--gray-400, #9aa3b2);
}
.sp-head svg { flex-shrink: 0; }
#spInput {
  flex: 1; min-width: 0; border: none; background: none; outline: none;
  font-size: 15px; color: var(--text, #1f2937); font-family: inherit;
}
#spInput::placeholder { color: var(--gray-400, #9aa3b2); }
.sp-kbd {
  flex-shrink: 0; font-size: 10px; font-weight: 600; line-height: 1;
  padding: 4px 6px; border-radius: 5px; color: var(--gray-500, #79808c);
  background: var(--gray-100, #f3f4f6); border: 1px solid var(--border, #e8eaed);
  letter-spacing: .4px;
}
.sp-kbd.sm { padding: 2px 5px; font-size: 9px; }
.sp-body { max-height: min(46vh, 420px); overflow-y: auto; padding: 6px 8px; }
.sp-group-title {
  font-size: 11px; font-weight: 600; color: var(--gray-500, #79808c);
  padding: 10px 10px 4px; letter-spacing: .5px;
}
.sp-item {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  border-radius: 9px; cursor: pointer;
}
.sp-item:hover, .sp-item.active { background: var(--primary-bg, #eef2ff); }
.sp-icon {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  color: var(--primary, #4f6bed); background: var(--primary-bg, #eef2ff);
}
.sp-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.sp-title {
  font-size: 13px; font-weight: 600; color: var(--text, #1f2937);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sp-hl { color: var(--primary, #4f6bed); background: none; }
.sp-sub {
  font-size: 11px; color: var(--text-tertiary, #8a93a3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sp-empty { padding: 34px 16px; text-align: center; font-size: 13px; color: var(--gray-400, #9aa3b2); }
.sp-foot {
  display: flex; gap: 16px; padding: 9px 16px; font-size: 11px; color: var(--gray-500, #79808c);
  border-top: 1px solid var(--border, #e8eaed); background: var(--gray-100, #f8f9fb);
}
.sp-foot span { display: flex; align-items: center; gap: 5px; }
@media (max-width: 768px) {
  .sp-panel { margin-top: 5vh; }
  .sp-body { max-height: 56vh; }
  .sp-foot { display: none; }
}
/* v332: 顶栏搜索框 Ctrl K 快捷键提示 */
.search-kbd {
  flex-shrink: 0; font-size: 10px; font-weight: 600; line-height: 1;
  color: var(--gray-400); background: var(--gray-100);
  border: 1px solid var(--border); border-radius: 4px; padding: 3px 5px;
  letter-spacing: .3px; cursor: pointer; user-select: none;
}
.search-kbd:hover { color: var(--primary); border-color: var(--primary); }

/* ============================================================
   v334: 全局搜索美化——面板精修 + 右上角关闭按钮 + 标题栏拖拽移动
   （同特异性追加段，覆盖 v332 基础样式）
   ============================================================ */
/* 顶栏搜索框：胶囊造型 + 微妙悬浮光晕 */
.search-box {
  width: 252px; height: 34px; padding: 0 10px 0 14px;
  border-radius: 17px; border-color: transparent;
  box-shadow: none; background: var(--gray-100);
}
.search-box:hover { background: var(--gray-200, #e8eaee); }
.search-box:focus-within {
  border-color: var(--primary); background: var(--card-bg);
  box-shadow: 0 0 0 3px var(--primary-bg); border-radius: 17px;
}
.search-box svg { transition: color .15s; }
.search-box:focus-within svg, .search-box:hover svg { color: var(--primary); }

/* 面板：更大圆角 + 分层阴影 + 顶部高光描边 */
.search-palette.open { animation: spFade .12s ease-out; }
@keyframes spFade { from { opacity: 0; } to { opacity: 1; } }
.sp-backdrop { background: rgba(15, 23, 42, .5); backdrop-filter: blur(3px); }
.sp-panel {
  border-radius: 16px; border-color: var(--border);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .35) inset,
              0 8px 24px rgba(15, 23, 42, .14),
              0 28px 72px rgba(15, 23, 42, .3);
}
/* 拖拽态：全屏禁选文本 + 面板阴影加深，动画停掉防抖动 */
.search-palette.dragging { user-select: none; cursor: grabbing; }
.search-palette.dragging .sp-panel { animation: none; box-shadow: 0 32px 80px rgba(15, 23, 42, .38); transition: none; }

/* 标题栏：抓手图标 + 渐变底 + 拖拽游标 */
.sp-head {
  padding: 13px 12px 13px 16px;
  background: linear-gradient(180deg, var(--primary-bg, #eef2ff), transparent 220%);
  cursor: grab;
}
.sp-head:active { cursor: grabbing; }
.sp-grip { color: var(--primary); flex-shrink: 0; cursor: grab; }
.sp-grip:active { cursor: grabbing; }
.sp-head #spInput { font-size: 15.5px; cursor: text; }

/* 右上角关闭按钮 */
.sp-close {
  flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin-left: 2px; padding: 0;
  border: none; border-radius: 8px; cursor: pointer;
  background: transparent; color: var(--gray-400);
  transition: background .12s, color .12s, transform .12s;
}
.sp-close:hover {
  background: var(--danger-bg, rgba(220, 38, 38, .1));
  color: var(--danger, #dc2626); transform: scale(1.06);
}
.sp-close:active { transform: scale(.96); }

/* 分组标题：左竖条 + 计数徽标 */
.sp-group-title {
  display: flex; align-items: center; gap: 8px;
  padding: 11px 10px 5px;
}
.sp-group-name {
  position: relative; padding-left: 9px;
}
.sp-group-name::before {
  content: ''; position: absolute; left: 0; top: 50%;
  width: 3px; height: 10px; margin-top: -5px; border-radius: 2px;
  background: var(--primary);
}
.sp-group-count {
  font-size: 10px; font-weight: 500; color: var(--gray-400);
  background: var(--gray-100); border: 1px solid var(--border-light);
  border-radius: 8px; padding: 1px 6px; line-height: 1.4;
}

/* 结果项：过渡 + 图标着色微调 */
.sp-item { transition: background .1s, transform .1s; }
.sp-item:hover, .sp-item.active { transform: translateX(1px); }
/* v546: 确保点击子元素（标题/副标题/高亮）也能命中 .sp-item */
.sp-item > * { pointer-events: none; }
.sp-icon { border-radius: 9px; }
.sp-title { letter-spacing: .1px; }

/* 空态：图标 + 弱化文案 */
.sp-empty { line-height: 1.8; }

/* 底栏：拖拽提示靠右 */
.sp-foot { justify-content: flex-start; }
.sp-foot-drag { margin-left: auto; opacity: .8; letter-spacing: .3px; }

@media (max-width: 768px) {
  .search-box { width: 190px; }
  .sp-foot-drag { display: none; }
}
/* v334: 深色主题——白色高光描边换为微光，避免刺眼 */
[data-theme='dark'] .sp-panel {
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .07) inset,
              0 8px 24px rgba(0, 0, 0, .35),
              0 28px 72px rgba(0, 0, 0, .5);
}

/* ============================================================
   v340: 项目组/项目组合改为「项目管理」下默认折叠子项
   - .nav-branch 包裹父项 + 子项；默认无 .open → 子项 max-height:0 不可见
   - 加 .open 后子项展开（max-height 过渡）
   - 父项尾部 .caret 折叠朝右、展开后旋转 90° 朝下
   - .nav-child 缩进字号继承 v339 视觉
   ============================================================ */
.nav-branch > .nav-sub {
  max-height: 0;
  overflow: hidden;
  transition: max-height .25s ease;
}
.nav-branch.open > .nav-sub {
  max-height: 200px; /* 两行子项足够；溢出可调 */
}
.nav-item.nav-parent {
  position: relative; /* 已继承 .nav-item，但保持显式 */
}
.nav-item.nav-parent .caret {
  margin-left: auto;
  opacity: .55;
  transition: transform .25s ease, opacity .15s ease;
  flex-shrink: 0;
}
.nav-branch.open > .nav-item.nav-parent .caret {
  transform: rotate(90deg);
  opacity: .85;
}
.nav-item.nav-parent:hover .caret { opacity: .95; }

.nav-item.nav-child {
  padding-left: 32px;
  font-size: 14px;
  gap: 9px;
  margin-top: 2px;
}
.nav-item.nav-child svg { width: 16px; height: 16px; opacity: .8; }
.nav-item.nav-child.active svg { opacity: 1; }
/* 悬停面板分组间的细分隔线（v338 残留，无 .nav-branch/open 时不显示，保留兼容） */
.quick-list .np-sep {
  height: 1px; margin: 5px 8px;
  background: var(--border-light, var(--border));
}

/* ============================================================
   v341: 任务管理「状态分色」——待办/进行中/已完成三态更直观
   - 看板列头按状态淡色氛围（header 背景 + 标题文字色）
   - 列表视图整行左侧 3px 状态色竖带（box-shadow inset 不挤压内容）
   ============================================================ */
/* v341 任务看板列头状态色氛围 */
.kanban-col-todo .kanban-column-header { background: var(--gray-100); }
.kanban-col-todo .kanban-column-header .kc-title { color: var(--gray-600); }
.kanban-col-inprogress .kanban-column-header { background: var(--primary-bg); }
.kanban-col-inprogress .kanban-column-header .kc-title { color: var(--primary); }
.kanban-col-done .kanban-column-header { background: var(--success-bg); }
.kanban-col-done .kanban-column-header .kc-title { color: var(--success); }
/* v344 合作伙伴看板列头（同 .kanban-col-* 框架，独立 class） */
.kanban-col-cooperating .kanban-column-header { background: var(--success-bg); }
.kanban-col-cooperating .kanban-column-header .kc-title { color: var(--success); }
.kanban-col-pending .kanban-column-header { background: var(--warning-bg); }
.kanban-col-pending .kanban-column-header .kc-title { color: #d97706; }
.kanban-col-expired .kanban-column-header { background: var(--gray-100); }
.kanban-col-expired .kanban-column-header .kc-title { color: var(--gray-600); }

/* ============================================================
   v344: 合作伙伴看板卡片（伙伴 card 复用 .kanban-board/.kanban-column 框架，自定义卡片样式避免与任务 kanban-card 混淆）
   ============================================================ */
.kanban-board {
  display: flex; gap: 14px;
  align-items: flex-start;
  overflow-x: auto;
  padding-bottom: 8px;
}
.kanban-column {
  flex: 1 1 0; min-width: 260px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0;
  display: flex; flex-direction: column;
}
.kanban-col-body {
  padding: 10px;
  display: flex; flex-direction: column; gap: 8px;
  max-height: 70vh; overflow-y: auto;
}
.partner-card {
  background: var(--gray-50);
  border: 1px solid var(--border-light);
  border-left: 3px solid var(--gray-300);
  border-radius: var(--radius-sm);
  padding: 11px 12px;
  display: flex; flex-direction: column; gap: 7px;
  transition: all 0.18s;
}
.partner-card:hover {
  background: var(--card-bg);
  border-color: var(--gray-300);
  box-shadow: var(--shadow-sm);
  transform: translateX(2px);
}
.kanban-col-cooperating .partner-card { border-left-color: var(--success); }
.kanban-col-pending .partner-card     { border-left-color: var(--warning); }
.kanban-col-expired .partner-card     { border-left-color: var(--gray-400); }

.partner-card .pc-head {
  display: flex; align-items: center; gap: 9px;
  min-width: 0;
}
.partner-card .pc-avatar {
  width: 32px; height: 32px;
  border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--primary-bg); color: var(--primary);
  font-weight: 700; font-size: 13px;
  flex-shrink: 0;
}
.kanban-col-pending .partner-card .pc-avatar { background: var(--warning-bg); color: #d97706; }
.kanban-col-cooperating .partner-card .pc-avatar { background: var(--success-bg); color: var(--success); }
.kanban-col-expired .partner-card .pc-avatar { background: var(--gray-100); color: var(--gray-500); }

.partner-card .pc-name-wrap { min-width: 0; flex: 1; }
.partner-card .pc-name {
  font-size: 14px; font-weight: 600; color: var(--gray-800);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  line-height: 1.3;
}
.partner-card .pc-type {
  font-size: 11px; color: var(--text-tertiary);
  margin-top: 2px;
}

.partner-card .pc-contact {
  display: flex; flex-direction: column; gap: 2px;
  font-size: 12px;
  min-width: 0;
}
.partner-card .pc-contact-name { color: var(--gray-700); font-weight: 500; }
.partner-card .pc-contact-phone { color: var(--text-tertiary); font-family: var(--mono); }

.partner-card .pc-projects {
  display: flex; flex-wrap: wrap; gap: 4px;
}
.partner-card .pc-projects .kc-project {
  display: inline-block;
  font-size: 11px; color: var(--gray-600);
  background: var(--card-bg);
  border: 1px solid var(--border-light);
  padding: 1px 7px; border-radius: 4px;
  max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.partner-card .pc-projects .kc-project[style*="background"] { /* +N chip */ }

.partner-card .pc-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-top: 2px;
  padding-top: 6px; border-top: 1px dashed var(--border-light);
}
.partner-card .pc-amount {
  font-size: 13px; font-weight: 600; color: var(--gray-800);
  font-variant-numeric: tabular-nums;
}

.partner-card .pc-actions {
  display: flex; justify-content: flex-end; gap: 4px;
  margin-top: 2px;
}
.partner-card .pc-actions .btn-ghost {
  padding: 3px 8px; font-size: 12px;
}

/* 列表视图行级状态色带（3px 竖条：待办灰 / 进行中蓝 / 已完成绿） */
.task-row-todo { box-shadow: inset 3px 0 0 var(--gray-400); }
.task-row-in_progress { box-shadow: inset 3px 0 0 var(--primary); }
.task-row-done { box-shadow: inset 3px 0 0 var(--success); }

/* ============================================================
   v342: 整站字体再放大
   html 基础字号 14→15 已写在上方；下面针对关键写死 px 的元素再升 1-2px
   不动 login-input iOS 16 防缩放约定、图表数值、tooltip 等极小标签
   ============================================================ */
.page-title { font-size: 20px; }                        /* 18→20 */
.logo-text { font-size: 17px; font-weight: 700; }       /* 16→17 */
.nav-item { font-size: 16px; }                          /* 15→16（v337 已加再升 1） */
.quick-list .quick-entry { font-size: 14px; }       /* v342: 14px→14px（与主菜单接近），原 13px 被 .quick-list 选择器特异性覆盖 */
.nav-group-label { font-size: 14px; padding-bottom: 10px; }  /* 13→14 */
.user-name { font-size: 14px; }                         /* 13→14 */
.user-role { font-size: 12px; }                         /* 11→12 */
.topbar-username { font-size: 14px; }                   /* 13→14 */
.search-box input { font-size: 14px; }                  /* 13→14 */
.card-title { font-size: 15px; }                        /* 14→15 */
.card { border-radius: 12px; }
.stat-card .stat-label { font-size: 12.5px; }           /* 11.5→12.5 */
.stat-card .stat-trend { font-size: 12px; }             /* 11→12 */
.form-label { font-size: 14px; }                        /* 13→14 */
.form-input, .form-select, .form-textarea { font-size: 14px; }   /* 13→14 */
.form-section-title { font-size: 14px; }                /* 13→14 */
.detail-value { font-size: 14px; }                      /* 13→14 */
.detail-label { font-size: 12px; }                      /* 11→12 */
.table { font-size: 14px; }                             /* 13→14 */
.data-table { font-size: 14px; }
.data-table thead th { font-size: 13px; }               /* 12→13 */
.btn { font-size: 14px; }                               /* 13→14 */
.btn-new { font-size: 15px; }                              /* v379: 14→15 配合 height:36px */
.btn-sm { font-size: 13px; }                            /* 12→13 */
.btn-lg { font-size: 16px; font-weight: 700; }          /* v379: 14→16 + 字重 700 配合 height:40px */
.badge { font-size: 13px; padding: 4px 12px; }     /* v343: 11→13 + padding 4px12px；v342 padding:3px10px 重置了 .badge-dot-status padding-left:18px 导致圆点·与字体重叠 */

  /* v343: .badge-dot-status 与圆点·保留足够 gap（圆点 left:9 w:6 → 9~15px 内留出 5px 间距给文字 20px 起步） */
.badge-dot-status { padding-left: 22px; }
.badge-dot-status::before { width: 7px; height: 7px; left: 9px; }
.ov-row-name { font-size: 14px; }                       /* 13→14 */
.ov-row-sub { font-size: 12px; }                        /* 11→12 */
.ov-row-num { font-size: 15px; }                        /* 14→15 */
.ov-row-date { font-size: 12px; }                       /* 11→12 */
.ov-pill { font-size: 12px; }                           /* 11→12 */
.pg-name { font-size: 14px; }                           /* 13→14 */
.pg-val { font-size: 14px; }                            /* 13→14 */
.kanban-column-header .kc-title { font-size: 14px; }    /* 13→14 */
.kanban-card .kc-title { font-size: 14px; }
.empty-state .es-title { font-size: 15px; }             /* 14→15 */
.empty-state .es-desc { font-size: 13px; }              /* 12→13 */
.modal-header h3 { font-size: 17px; }                   /* 16→17 */
.modal-body { font-size: 14px; }                        /* 继承 + 显式 */
.modal-footer { font-size: 14px; }
.notif-panel-header h4 { font-size: 15px; }             /* 14→15 */
.notif-item .notif-title { font-size: 14px; }           /* 13→14 */
.notif-item .notif-desc { font-size: 13px; }            /* 12→13 */
.notif-item .notif-time { font-size: 12px; }            /* 11→12 */
.toast { font-size: 14px; }                             /* 13→14 */
.toast .toast-msg { font-size: 14px; }
.login-subtitle { font-size: 14px; }                    /* 13→14 */
.login-label { font-size: 13px; }                       /* 12→13 */
.login-input { font-size: 15px; }                       /* 14→15（iOS 16 防缩放已在 v78 @media 保留） */
.login-btn { font-size: 15px; }                         /* 14→15 */
.login-error { font-size: 14px; }                       /* 13→14 */
.login-brand-tagline { font-size: 14px; }               /* 13→14 */
.login-brand-quote .login-quote-rotator,
.login-brand-quote p { font-size: 16px; }               /* 15→16（保留，但稍调） */
/* v78: 移动端 iOS 防缩放——login-input/form-input 必须 ≥16 */
@media (max-width: 768px) {
  .form-input, .form-select, .form-textarea { font-size: 16px; }
  .login-input { font-size: 16px; }
}
/* dash-compact / ov-sm 微缩档独立设值，需单独升级 */
.dash-compact .ov-row.pg-row { font-size: 13px; }
.dash-compact .ov-row.pg-row .pg-name { font-size: 13px; }   /* 12→13 */
.dash-compact .ov-row.pg-row .pg-val { font-size: 13px; }    /* 12→13 */
.dash-compact .dash-hero-hi { font-size: 15px; }
.dash-compact .dash-hero-sub { font-size: 13px; }

/* ============================================
   v346 品牌引言多引言轮播
   - 多条引言绝对定位堆叠，靠 opacity + translateY 淡入淡出切换
   - 底部小圆点指示当前/总数；hover 时暂停（前端 JS 控制）
   - 单条时不显示 dots（不需指示）；移动端 .login-brand-quote 整体隐藏 → 自动忽略
   ============================================ */
.login-quote-rotator {
  position: relative;
  min-height: 56px;          /* 至少 1 行高度避免布局跳动 */
  /* v356: 文字可选中复制——非活动引言层 pointer-events:none 让鼠标穿透，
     否则绝对定位堆叠的 opacity:0 引言会截获鼠标导致选到错位文本 */
  -webkit-user-select: text; user-select: text;
}
.login-quote-item {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 600ms cubic-bezier(0.4, 0, 0.2, 1),
              transform 600ms cubic-bezier(0.4, 0, 0.2, 1);
  margin: 0;
  line-height: 1.75;
  color: #94a3b8;
  font-weight: 300;
  letter-spacing: 0.5px;
  /* 防止长文本溢出旋转容器 */
  overflow-wrap: break-word;
  word-break: break-word;
  /* v356: 非活动引言层让鼠标穿透（pointer-events:none），
     并 user-select:none 防被选中——避免视觉上看 A 但鼠标拖到 B */
}
/* v356: 非活动引言层不接收事件、不参与选区——保证 hover/选中只命中活动引言 */
.login-quote-item:not(.lqr-active) {
  pointer-events: none;
  -webkit-user-select: none; user-select: none;
}
.login-quote-item.lqr-active {
  opacity: 1;
  transform: translateY(0);
}
.login-quote-item.lqr-leaving {
  opacity: 0;
  transform: translateY(-8px);
}
/* v348-v349: 6 种切换动画（后台可设）——fade 是默认（上面 base 即 fade 上浮淡入）；
   slide / zoom / blur / flip / bounce 用更高特异性覆盖 transform 实现不同切换效果 */
.login-quote-rotator.lqr-anim-slide .login-quote-item {
  transform: translateX(40px);
}
.login-quote-rotator.lqr-anim-slide .login-quote-item.lqr-active {
  opacity: 1;
  transform: translateX(0);
}
.login-quote-rotator.lqr-anim-slide .login-quote-item.lqr-leaving {
  opacity: 0;
  transform: translateX(-40px);
}
.login-quote-rotator.lqr-anim-zoom .login-quote-item {
  transform: scale(0.9);
}
.login-quote-rotator.lqr-anim-zoom .login-quote-item.lqr-active {
  opacity: 1;
  transform: scale(1);
}
.login-quote-rotator.lqr-anim-zoom .login-quote-item.lqr-leaving {
  opacity: 0;
  transform: scale(1.08);
}
/* v349: 模糊聚焦——文字从模糊到清晰，配轻微缩放 */
.login-quote-rotator.lqr-anim-blur .login-quote-item {
  filter: blur(6px);
  opacity: 0;
  transform: scale(0.96);
  transition: opacity 600ms cubic-bezier(0.4, 0, 0.2, 1),
              transform 600ms cubic-bezier(0.4, 0, 0.2, 1),
              filter 600ms cubic-bezier(0.4, 0, 0.2, 1);
}
.login-quote-rotator.lqr-anim-blur .login-quote-item.lqr-active {
  filter: blur(0);
  opacity: 1;
  transform: scale(1);
}
.login-quote-rotator.lqr-anim-blur .login-quote-item.lqr-leaving {
  filter: blur(6px);
  opacity: 0;
  transform: scale(1.04);
}
/* v349: 3D 翻转——文字绕底部轴向上翻入、向下翻出 */
.login-quote-rotator.lqr-anim-flip {
  perspective: 600px;
}
.login-quote-rotator.lqr-anim-flip .login-quote-item {
  transform: rotateX(88deg);
  opacity: 0;
  transform-origin: 50% 100%;
}
.login-quote-rotator.lqr-anim-flip .login-quote-item.lqr-active {
  transform: rotateX(0deg);
  opacity: 1;
}
.login-quote-rotator.lqr-anim-flip .login-quote-item.lqr-leaving {
  transform: rotateX(-88deg);
  opacity: 0;
}
/* v349: 弹跳进入——文字带回弹地从下方弹入、向上弹出 */
.login-quote-rotator.lqr-anim-bounce .login-quote-item {
  transform: translateY(26px) scale(0.92);
  opacity: 0;
  transition: opacity 320ms ease,
              transform 520ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.login-quote-rotator.lqr-anim-bounce .login-quote-item.lqr-active {
  transform: translateY(0) scale(1);
  opacity: 1;
}
.login-quote-rotator.lqr-anim-bounce .login-quote-item.lqr-leaving {
  transform: translateY(-22px) scale(0.96);
  opacity: 0;
  transition: opacity 280ms ease,
              transform 320ms ease;
}
/* v350: 打字机——文字从左到右逐字揭示，末尾光标闪烁 */
.login-quote-rotator.lqr-anim-typewriter .login-quote-item {
  opacity: 0;
  clip-path: inset(0 100% 0 0);
}
.login-quote-rotator.lqr-anim-typewriter .login-quote-item.lqr-active {
  opacity: 1;
  clip-path: inset(0 0 0 0);
  animation: lqr-typewriter 1100ms steps(16, end);
}
.login-quote-rotator.lqr-anim-typewriter .login-quote-item.lqr-active::after {
  content: '|';
  margin-left: 2px;
  animation: lqr-caret 1s step-end infinite;
}
.login-quote-rotator.lqr-anim-typewriter .login-quote-item.lqr-leaving {
  opacity: 0;
  clip-path: inset(0 0 0 0);
  transition: opacity 300ms ease;
}
@keyframes lqr-typewriter {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes lqr-caret {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}
/* v350: 百叶窗——文字切成横向条纹，叶片从细到粗逐条展开 */
.login-quote-rotator.lqr-anim-blinds .login-quote-item {
  opacity: 0;
  -webkit-mask-image: repeating-linear-gradient(0deg, #000 0 1px, transparent 1px 6px);
  mask-image: repeating-linear-gradient(0deg, #000 0 1px, transparent 1px 6px);
}
.login-quote-rotator.lqr-anim-blinds .login-quote-item.lqr-active {
  opacity: 1;
  -webkit-mask-image: repeating-linear-gradient(0deg, #000 0 6px, transparent 6px 6px);
  mask-image: repeating-linear-gradient(0deg, #000 0 6px, transparent 6px 6px);
  animation: lqr-blinds 800ms ease;
}
.login-quote-rotator.lqr-anim-blinds .login-quote-item.lqr-leaving {
  opacity: 0;
  -webkit-mask-image: repeating-linear-gradient(0deg, #000 0 6px, transparent 6px 6px);
  mask-image: repeating-linear-gradient(0deg, #000 0 6px, transparent 6px 6px);
  transition: opacity 300ms ease;
}
@keyframes lqr-blinds {
  from {
    -webkit-mask-image: repeating-linear-gradient(0deg, #000 0 1px, transparent 1px 6px);
    mask-image: repeating-linear-gradient(0deg, #000 0 1px, transparent 1px 6px);
  }
  to {
    -webkit-mask-image: repeating-linear-gradient(0deg, #000 0 6px, transparent 6px 6px);
    mask-image: repeating-linear-gradient(0deg, #000 0 6px, transparent 6px 6px);
  }
}
/* v347 隐藏底部小圆点指示器（多引言轮播只保留 fade 切换，不再露出 dots） */
.login-quote-dots { display: none; }
/* 0 条时不占空间 */
.login-quote-rotator.lqr-empty { display: none; }

/* v354: 品牌引言配置行——文本留空时整行淡化、开关 disabled 视觉 */
.quote-row.quote-row-empty { background: transparent !important; opacity: 0.65; }
.quote-row.quote-row-empty .quote-txt-input { font-style: italic; }
.quote-en-input:disabled + .quote-switch-track { opacity: 0.5; cursor: not-allowed; }
.quote-en-input:disabled ~ .quote-switch-dot { box-shadow: none; }
@media (prefers-reduced-motion: reduce) {
  .quote-switch-track, .quote-switch-dot { transition: none !important; }
}

/* v355: 项目预算清单表格——科目/金额/备注/删除 行布局；input 透明铺满（仿采购明细 v295 grid 观感） */
.budget-items-table tbody tr:hover { background: var(--gray-50); }
.budget-items-table tbody td { vertical-align: middle; }
.budget-items-table input.bi-name,
.budget-items-table input.bi-amount,
.budget-items-table input.bi-note {
  border-color: transparent;
  background: transparent;
  transition: border-color 0.15s, background 0.15s;
}
.budget-items-table input.bi-name:hover,
.budget-items-table input.bi-amount:hover,
.budget-items-table input.bi-note:hover { border-color: var(--border-light); background: var(--bg-primary, #fff); }
.budget-items-table input.bi-name:focus,
.budget-items-table input.bi-amount:focus,
.budget-items-table input.bi-note:focus { border-color: var(--primary); background: var(--bg-primary, #fff); outline: none; }
.budget-items-table tbody tr td:first-child { border-left: 3px solid transparent; transition: border-color 0.15s; }
.budget-items-table tbody tr:hover td:first-child { border-left-color: var(--primary); }
@media (max-width: 640px) {
  .budget-items-table { font-size: 12px; }
  .budget-items-table th, .budget-items-table td { padding: 6px 4px !important; }
}
/* v357: 预算清单工具栏——详情页「导出/导入 Excel」按钮组右对齐 */
.bi-toolbar {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-left: auto;
  flex-wrap: wrap;
}
.bi-toolbar .btn-ghost { padding: 4px 10px; font-size: 12px; }
.bi-toolbar .btn-ghost:hover { background: var(--gray-50); border-color: var(--border-light); }

/* v364: 「＋ 添加行」醒目样式族——主色+加大 padding+微阴影 hover 抬起，与 ghost 清空/重置布局形成强视觉对比 */
.btn-add-row {
  background: var(--primary) !important;
  color: #fff !important;
  border-color: var(--primary) !important;
  font-size: 13px !important;
  padding: 8px 18px !important;
  font-weight: 600 !important;
  border-radius: 6px !important;
  box-shadow: 0 2px 4px rgba(33, 150, 243, 0.25);
  transition: all 0.15s ease;
}
.btn-add-row:hover {
  background: var(--primary-dark) !important;
  border-color: var(--primary-dark) !important;
  box-shadow: 0 4px 10px rgba(33, 150, 243, 0.4);
  transform: translateY(-1px);
}
.btn-add-row:active {
  transform: translateY(0);
  box-shadow: 0 1px 2px rgba(33, 150, 243, 0.3);
}

/* v363: 项目预算明细表 WPS 风格编辑器——cell-click + 行列 4 类拖拽 */
/* 行容器：display:grid；列宽通过 inline style 注入（默认 v361 硬编码；拖拽后改 CSS 变量） */
.bt-row {
  position: relative;
  display: grid;
  grid-template-columns: 28px 60px 1fr 1fr 1fr 1.5fr 70px 60px 100px 120px 1.4fr 50px;
  gap: 0;
  border-bottom: 1px solid var(--border-light);
  background: #fff;
  min-height: 34px;
}
.bt-row.bt-row-hd {
  background: var(--gray-100);
  font-size: 11px;
  font-weight: 600;
  color: var(--gray-600);
  border-bottom: 2px solid var(--border);
  min-height: 32px;
}
/* 行序号列（拖拽 handle 单独占 28px） */
.bt-row-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gray-400);
  cursor: grab;
  font-size: 14px;
  user-select: none;
  border-right: 1px dashed var(--border-light);
  background: var(--gray-50);
}
.bt-row-handle:active { cursor: grabbing; }
.bt-row-handle:hover { color: var(--primary); background: var(--bg-secondary, #f7f9fc); }
/* 单个单元格：display 文本态 / 编辑 input 态 */
.bt-cell {
  position: relative;
  padding: 0;
  border-right: 1px solid var(--border-light);
  min-width: 0;
}
.bt-cell:last-child { border-right: none; }
.bt-cell-display {
  display: block;
  padding: 8px 10px;
  min-height: 34px;
  line-height: 1.4;
  font-size: 13px;
  cursor: text;
  color: var(--text-primary, #1f2937);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bt-cell-display:hover { background: var(--bg-secondary, #f7f9fc); }
.bt-cell-display.bt-cell-empty::before {
  content: attr(data-placeholder);
  color: var(--text-tertiary);
}
.bt-cell.is-editing { padding: 0; background: #fff; box-shadow: inset 0 0 0 2px var(--primary); }
.bt-cell-input {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 34px;
  padding: 8px 10px;
  border: none;
  outline: none;
  background: transparent;
  font-size: 13px;
  font-family: inherit;
  color: inherit;
  box-sizing: border-box;
}
.bt-cell-input.bt-cell-num { text-align: right; }
.bt-cell-input.bt-cell-center { text-align: center; }
.bt-cell-input.bt-cell-total { font-weight: 600; color: var(--primary); }
/* 表头单元格 */
.bt-hd-cell {
  padding: 8px 10px;
  font-weight: 600;
  font-size: 11px;
  color: var(--gray-600);
  border-right: 1px solid var(--border-light);
  position: relative;
  user-select: none;
}
.bt-hd-cell:last-child { border-right: none; }
.bt-hd-cell.bt-hd-right { text-align: right; padding-right: 14px; }
.bt-hd-cell.bt-hd-center { text-align: center; padding-right: 14px; }
/* 列宽拖拽条：绝对定位右缘 + cursor */
.col-resizer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 6px;
  margin-right: -3px;
  cursor: col-resize;
  z-index: 5;
  background: transparent;
}
.col-resizer:hover, .col-resizer.is-dragging { background: var(--primary); opacity: 0.35; }
.bt-hd-cell .col-resizer { top: 0; }
/* 行高拖拽条：行底部 6px 高 */
.row-resizer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -3px;
  height: 6px;
  cursor: row-resize;
  z-index: 5;
  background: transparent;
}
.row-resizer:hover, .row-resizer.is-dragging { background: var(--primary); opacity: 0.35; }
/* 行拖拽悬停红线 + 占位 */
.bt-row.bt-drop-before { box-shadow: inset 2px 0 0 var(--primary), inset 0 2px 0 var(--primary); }
.bt-row.bt-drop-after { box-shadow: inset 2px 0 0 var(--primary), inset 0 -2px 0 var(--primary); }
.bt-row.bt-row-dragging { opacity: 0.4; }
/* 列拖拽——th 浮动 */
.bt-hd-cell { cursor: default; }
.bt-hd-cell.bt-col-dragging { opacity: 0.4; }
.bt-hd-cell.bt-drop-col-before { box-shadow: inset 2px 0 0 var(--primary), inset 0 2px 0 var(--primary); }
.bt-hd-cell.bt-drop-col-after { box-shadow: inset 2px 0 0 var(--primary), inset 0 -2px 0 var(--primary); }
.bt-hd-cell .bt-col-drag-handle {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 6px;
  margin-left: -3px;
  cursor: grab;
  opacity: 0;
  background: var(--primary);
  transition: opacity 0.15s;
}
.bt-hd-cell .bt-col-drag-handle:active { cursor: grabbing; }
.bt-hd-cell:hover .bt-col-drag-handle { opacity: 0.35; }
/* 操作列单元格 */
.bt-cell-action {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
}
.bt-cell-action .bt-del {
  border: none;
  background: transparent;
  color: var(--danger);
  cursor: pointer;
  font-size: 14px;
  padding: 4px 8px;
  border-radius: 4px;
}
.bt-cell-action .bt-del:hover { background: var(--danger); color: #fff; }
/* 空态占位 */
.bt-empty-placeholder {
  padding: 30px;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 13px;
  border-bottom: 1px solid var(--border-light);
}

/* ============================================================
 * v369: 项目预算明细表 — 行级附件 cell + 整表附件 cell 样式
 * ============================================================ */
.bt-cell-voucher {
  cursor: pointer;
  position: relative;
  padding: 0 !important;
}
.bt-cell-voucher:hover {
  background-color: var(--primary-50, #e3f2fd) !important;
}
.bt-cell-voucher .bt-cell-display {
  height: 100%;
  width: 100%;
}
.bt-cell-voucher .bt-cell-display.bt-cell-empty {
  color: var(--gray-400, #bdbdbd);
}
.bt-cell-voucher .bt-cell-display:not(.bt-cell-empty) {
  color: var(--primary, #1976d2);
  font-weight: 500;
}
.bt-cell-voucher-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 0 6px;
  font-size: 12px;
  line-height: 1.2;
  width: 100%;
  height: 100%;
}
.bt-cell-voucher-cell.bt-cell-empty .bt-voucher-icon {
  opacity: 0.5;
}
.bt-voucher-icon {
  font-size: 14px;
  flex-shrink: 0;
}
.bt-voucher-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* v369 编辑器工具栏整表附件按钮：与方案附件入口风格一致 */
#bt_editor_table_voucher {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}
#bt_editor_table_voucher #bt_editor_table_voucher_count {
  color: var(--primary, #1976d2);
  font-weight: 600;
}
#bt_editor_table_voucher.has-vouchers {
  background: var(--primary-50, #e3f2fd);
  border-color: var(--primary, #1976d2);
  color: var(--primary, #1976d2);
}

/* ============================================================
 * v373: 编辑器「上传整表附件」紧凑按钮 — 整合到工具栏动作行（与清空/重置布局同 ghost 风格）
 *   v371 的整行大按钮 + 主色渐变横条（.bt-voucher-bar / .bt-voucher-btn/-btn-icon/-btn-label/-btn-count/-btn-arrow）已删除
 * ============================================================ */
.bt-editor-voucher-has {
  color: var(--primary, #1976d2);
  border-color: var(--primary, #1976d2);
  background: rgba(25, 118, 210, 0.06);
}
.bt-editor-voucher-has:hover {
  background: rgba(25, 118, 210, 0.12);
}

/* v371: 序号列只读样式 */
.bt-cell-no .bt-cell-no-readonly {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: var(--gray-50, #f8f9fa);
  color: var(--text-tertiary, #6c757d);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: not-allowed;
}

/* ============================================================
 * v376: 项目预算明细 / 项目方案 空态按钮组统一——主按钮 + 附件按钮风格/大小完全一致
 * 应用：明细表空态（v375 改的）+ 方案空态
 * 规格：高度 30px / padding 0 14px / font-size 13px / font-weight 500 / 圆角 5px / 阴影 + 渐变蓝
 * ============================================================ */
.empty-state-actions {
  margin-top: 14px;
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
  align-items: center;
}
/* v379: 空态按钮 —— 高度 36px / 圆角 8px / 字间距 0.3px / 厚重阴影（与 .btn 基线一致） */
button.empty-state-action,
.btn.empty-state-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 18px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  color: #fff;
  background: linear-gradient(135deg, #4f6bed 0%, #5b7bef 100%);
  border: none;
  border-radius: 8px;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(79, 107, 237, 0.30), inset 0 1px 0 rgba(255, 255, 255, 0.15);
  transition: all 0.18s ease;
  letter-spacing: 0.3px;
}
button.empty-state-action:hover,
.btn.empty-state-action:hover {
  background: linear-gradient(135deg, #3e5cdb 0%, #4a6adb 100%);
  box-shadow: 0 6px 16px rgba(79, 107, 237, 0.40), inset 0 1px 0 rgba(255, 255, 255, 0.18);
  transform: translateY(-1px);
}
button.empty-state-action:active,
.btn.empty-state-action:active {
  transform: translateY(0);
  box-shadow: 0 2px 4px rgba(79, 107, 237, 0.30);
}

/* v379: 空态主按钮增强 —— 与附件按钮区分主从（高度 38px / 字重 600 / 阴影更深 / 字间距 0.4px） */
button.empty-state-action-primary,
.btn.empty-state-action-primary {
  height: 38px;
  padding: 0 22px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.4px;
  box-shadow: 0 4px 12px rgba(79, 107, 237, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.18);
  border-radius: 8px;
}
button.empty-state-action-primary:hover,
.btn.empty-state-action-primary:hover {
  box-shadow: 0 8px 20px rgba(79, 107, 237, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.22);
}

/* v379: 方案卡卡头「＋ 新建方案」明显主色按钮 —— 高度 36px / 圆角 8px / 字重 600 / 厚重阴影 */
.scheme-card-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 18px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.3px;
  color: #fff;
  background: linear-gradient(135deg, #4f6bed 0%, #5b7bef 100%);
  border: none;
  border-radius: 8px;
  cursor: pointer;
  box-shadow: 0 3px 10px rgba(79, 107, 237, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.15);
  transition: all 0.18s ease;
}
.scheme-card-action:hover {
  background: linear-gradient(135deg, #3e5cdb 0%, #4a6adb 100%);
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(79, 107, 237, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
/* v379: 卡头附件预览按钮——主色描边版（弱一档，与主色按钮区分主从） */
.scheme-card-action.outline {
  background: #fff;
  color: #4f6bed;
  border: 1px solid #c9d5ff;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.scheme-card-action.outline:hover {
  background: #f0f4ff;
  color: #3e5cdb;
  border-color: #4f6bed;
  box-shadow: 0 3px 8px rgba(79, 107, 237, 0.20);
  transform: translateY(-1px);
}

/* v379: 详情页明细表卡片 — 📎 上传附件 小主色按钮（高度 30px / 圆角 6px） */
.bt-voucher-mini-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 30px;
  padding: 0 12px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: #fff;
  background: linear-gradient(135deg, #4f6bed 0%, #5b7bef 100%);
  border: none;
  border-radius: 6px;
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(79, 107, 237, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.15);
  transition: all 0.18s ease;
  margin-right: 4px;
}
.bt-voucher-mini-btn em {
  font-style: normal;
  font-weight: 700;
  padding: 0 2px;
}
.bt-voucher-mini-btn:hover {
  background: linear-gradient(135deg, #3e5cdb 0%, #4a6adb 100%);
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(79, 107, 237, 0.38);
}
.bt-voucher-mini-btn.has-vouchers {
  background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%);
  box-shadow: 0 2px 6px rgba(46, 125, 50, 0.30), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}
.bt-voucher-mini-btn.has-vouchers:hover {
  background: linear-gradient(135deg, #1b5e20 0%, #2e7d32 100%);
  box-shadow: 0 4px 10px rgba(46, 125, 50, 0.40);
}

/* ==========================================
   v388: 防截屏 / 防泄露 / 溯源水印
   —— 配套 js/anti-capture.js
   设计边界：浏览器拦不住系统级截屏（PrintScreen/微信截图/拍照），
   本套样式只做「提高门槛 + 泄密可溯源」，水印是唯一事后追责手段。
   ========================================== */

/* 1. 禁页面文本选中（整站） */
body.pmo-no-select,
body.pmo-no-select *:not(input):not(textarea):not(select) {
  -webkit-user-select: none !important;
  -moz-user-select: none !important;
  -ms-user-select: none !important;
  user-select: none !important;
  -webkit-touch-callout: none !important; /* iOS 长按菜单 */
}
/* 输入框必须反向保留可选可编辑，否则用户连自己填的内容都复制不了 */
body.pmo-no-select input,
body.pmo-no-select textarea,
body.pmo-no-select select,
body.pmo-no-select [contenteditable="true"] {
  -webkit-user-select: text !important;
  -moz-user-select: text !important;
  -ms-user-select: text !important;
  user-select: text !important;
  -webkit-touch-callout: default !important;
}

/* ============================================
   v436: 项目详情页——整体信息分栏（概况/成员/进度/财务/交付/验收）
   目标：一屏看全项目，鼠标滑动（滚轮/触控板横滑/左右键）即可换栏，
        不再依赖纵向长条滚动。
   说明：.pd-* 全部走 CSS 变量，浅色/暗色主题自动适配。
   ============================================ */

/* ---------- 顶部粘性分栏条（v437 毛玻璃胶囊 + 滑动指示条） ---------- */
.pd-tabbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 2px;
  margin-bottom: 16px;
  padding: 5px 6px 5px 6px;
  /* v437: 毛玻璃胶囊化——半透明底 + 背景模糊，滚动时内容从下方透出 */
  /* 老浏览器 fallback：color-mix 不支持时整条声明会被丢弃，先给纯色兜底 */
  background: var(--gray-100);
  background: color-mix(in srgb, var(--card-bg) 82%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border: 1px solid var(--gray-300);
  border: 1px solid color-mix(in srgb, var(--gray-300) 70%, transparent);
  border-radius: 999px;
  /* 窄屏横向可滚，不换行 */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  transition: box-shadow 0.22s var(--ease), background 0.22s var(--ease);
}
.pd-tabbar::-webkit-scrollbar { display: none; }
/* 粘顶时才浮起投影（未吸顶保持扁平，避免突兀） */
.pd-tabbar.is-stuck {
  box-shadow: 0 6px 20px -8px rgba(15, 23, 42, 0.28), 0 2px 6px -2px rgba(15, 23, 42, 0.12);
  background: var(--card-bg);
  background: color-mix(in srgb, var(--card-bg) 92%, transparent);
}

/* v437: 滑动指示条——跟随激活项平移，用 transform 走 GPU 合成层 */
.pd-tab-ind {
  position: absolute;
  top: 5px;
  left: 0;
  height: calc(100% - 10px);
  border-radius: 999px;
  background: var(--primary);
  box-shadow: 0 2px 8px -2px rgba(79, 107, 237, 0.55);
  pointer-events: none;
  z-index: 0;
  /* spring 感缓动：起步快、收尾带一点回弹 */
  transition: transform 0.36s cubic-bezier(0.34, 1.32, 0.52, 1), width 0.3s cubic-bezier(0.34, 1.32, 0.52, 1);
  will-change: transform, width;
}
/* 首次渲染未测量前先隐藏，避免从左侧滑入的突兀感 */
.pd-tab-ind.is-init { transition: none; }

.pd-tab {
  position: relative;
  z-index: 1;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 15px;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--gray-600);
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  letter-spacing: 0.3px;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.2s var(--ease), transform 0.18s var(--ease);
}
.pd-tab:hover { color: var(--gray-800); }
/* 激活项文字转白（底色由指示条承担，避免双重背景） */
.pd-tab.is-active { color: #fff; }
.pd-tab.is-active:hover { color: #fff; }
/* v437: 点击微回弹——按下时轻微缩小，松手回弹 */
.pd-tab:active { transform: scale(0.955); }
.pd-tab .pd-tab-ic { font-size: 13px; line-height: 1; }
/* 计数徽标（该分栏条目数，0 时不渲染） */
.pd-tab-count {
  min-width: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: rgba(127, 127, 127, 0.22);
  color: inherit;
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  transition: background 0.2s var(--ease);
}
.pd-tab.is-active .pd-tab-count { background: rgba(255, 255, 255, 0.28); }

/* 分栏条右侧提示 + 进度「第 N / M 栏」 */
.pd-tabhint {
  flex: none;
  margin-left: auto;
  padding-left: 12px;
  font-size: 11px;
  color: var(--text-tertiary);
  white-space: nowrap;
}
.pd-tab-pos {
  flex: none;
  margin-left: auto;
  padding-right: 10px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* 指示条存在时，hint 不再自己顶到右侧（交给 .pd-tab-pos） */
.pd-tabbar.has-ind .pd-tabhint { margin-left: 10px; }

/* ---------- 分栏内容区（v437 方向感知入场） ---------- */
/* 默认（无方向信息时）：淡入 + 轻微上移 */
.pd-pane { animation: pdPaneIn 0.24s var(--ease) both; }
@keyframes pdPaneIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
/* v437: 往右切栏（下一栏）——新栏从右侧滑入 */
.pd-pane.pd-in-right { animation: pdInRight 0.3s cubic-bezier(0.22, 0.9, 0.3, 1) both; }
@keyframes pdInRight {
  from { opacity: 0; transform: translateX(26px); }
  to   { opacity: 1; transform: none; }
}
/* v437: 往左切栏（上一栏）——新栏从左侧滑入 */
.pd-pane.pd-in-left { animation: pdInLeft 0.3s cubic-bezier(0.22, 0.9, 0.3, 1) both; }
@keyframes pdInLeft {
  from { opacity: 0; transform: translateX(-26px); }
  to   { opacity: 1; transform: none; }
}
/* v437: 越界微回弹——已在首/末栏时再往外切，内容轻推一下即回，给出「到头了」的触感 */
.pd-pane.pd-bump-right { animation: pdBumpRight 0.26s ease both; }
@keyframes pdBumpRight {
  0%   { transform: none; }
  45%  { transform: translateX(10px); }
  100% { transform: none; }
}
.pd-pane.pd-bump-left { animation: pdBumpLeft 0.26s ease both; }
@keyframes pdBumpLeft {
  0%   { transform: none; }
  45%  { transform: translateX(-10px); }
  100% { transform: none; }
}
/* 指示条溢出（越界）时同理轻推 */
.pd-tab-ind.pd-bump { animation: pdIndBump 0.26s ease both; }
@keyframes pdIndBump {
  0%   { transform: translateX(var(--ind-x, 0)) scaleX(1); }
  45%  { transform: translateX(var(--ind-x, 0)) scaleX(1.06); }
  100% { transform: translateX(var(--ind-x, 0)) scaleX(1); }
}
@media (prefers-reduced-motion: reduce) {
  .pd-pane,
  .pd-pane.pd-in-right,
  .pd-pane.pd-in-left,
  .pd-pane.pd-bump-right,
  .pd-pane.pd-bump-left,
  .pd-tab-ind.pd-bump { animation: none; }
  .pd-tab-ind { transition: none; }
}

/* 分栏内区块节奏：相邻卡片自动留距，首个卡片不留上边距
   （覆盖原先散落各处的 inline margin-top:16px / mb-16，避免分栏内出现双倍间距） */
.pd-pane > * + * { margin-top: 16px; }
.pd-pane > .stat-grid + * { margin-top: 20px; }
.pd-pane > .card:first-child,
.pd-pane > .card.mb-16:first-child { margin-top: 0 !important; }
.pd-pane > .card + .card { margin-top: 16px !important; }
.pd-pane > .card.mb-16 { margin-bottom: 0 !important; }

/* ---------- v437: 左右边缘渐隐箭头（分栏条溢出提示） ---------- */
/* v438: wrap 现在同时容纳「分栏条 shell」与「整栏内容 pane」——
   之所以要把 pane 放进来，是因为 sticky 的吸附范围等于父元素高度：
   wrap 只包分栏条时，一滚出视口分栏条就跟着滚走（v437 遗留缺陷）。
   ⚠️ margin-bottom 必须为 0，否则会在 shell 与内容之间留出固定空隙。 */
.pd-tabbar-wrap { position: relative; margin-bottom: 0; }
.pd-tabbar-wrap .pd-tabbar { margin-bottom: 0; }
/* shell 与内容之间留白（替代原 wrap 的 margin-bottom） */
.pd-tabbar-wrap > .pd-pane { margin-top: 16px; }

/* v438: 分栏条容器（左侧可滚分栏区 + 右侧常驻操作区，合成一条胶囊）
   原先「徽标 + 记一笔/预付款/合同/发票 + AI摘要/编辑/注销申请」是独立的
   一整行，与分栏条上下堆叠，纵向占两行；现合并为同一条横向条。 */
.pd-tabbar-shell {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px;
  background: var(--gray-100);
  background: color-mix(in srgb, var(--card-bg) 82%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border: 1px solid var(--gray-300);
  border: 1px solid color-mix(in srgb, var(--gray-300) 70%, transparent);
  border-radius: 999px;
  transition: box-shadow 0.22s var(--ease), background 0.22s var(--ease);
}
/* 粘顶浮起投影（由 JS 在 shell 上打 is-stuck） */
.pd-tabbar-shell.is-stuck {
  box-shadow: 0 6px 20px -8px rgba(15, 23, 42, 0.28), 0 2px 6px -2px rgba(15, 23, 42, 0.12);
  background: var(--card-bg);
  background: color-mix(in srgb, var(--card-bg) 92%, transparent);
}
/* shell 内的分栏条自身不再吸顶/不画边框（外层 shell 已承担）
   ⚠️ position 必须保持 relative：.pd-tab-ind 是 position:absolute，
      其包含块要靠 .pd-tabbar 自己提供；若改成 static，包含块会上溯到
      .pd-tabbar-shell（带 5px/6px padding），指示条 top/left 就整体偏移。 */
.pd-tabbar-shell .pd-tabbar {
  position: relative;
  top: auto;
  z-index: auto;
  flex: 1 1 auto;
  min-width: 0;              /* ★ flex 子项必须显式 min-width:0，否则内容溢出 */
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  margin-bottom: 0;
  box-shadow: none;
}
.pd-tabbar-shell .pd-tabbar.is-stuck { background: none; box-shadow: none; }

/* v438: 分栏条右侧操作区（常驻不随分栏区滚动） */
.pd-tab-actions {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding-left: 8px;
  /* 与左侧分栏区之间一道极细分隔线，避免视觉粘连 */
  border-left: 1px solid var(--gray-300);
  border-left: 1px solid color-mix(in srgb, var(--gray-300) 70%, transparent);
  margin-left: 2px;
}
/* 徽标组：与按钮同高对齐，徽标自带圆角/底色 */
.pd-actions-badges {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
}
.pd-tab-actions .badge { white-space: nowrap; }
/* 条内按钮统一紧凑尺寸（比常规 btn-sm 再小一档，配合 44px 条高） */
.pd-tab-actions .btn-sm {
  padding: 5px 11px;
  font-size: 12px;
  border-radius: 999px;
  height: 30px;
}
.pd-tab-actions .btn-sm > svg { width: 14px; height: 14px; }
/* v438: 图标按钮——只留图标，文字交给 title/aria-label（AI摘要/注销申请/删除） */
.pd-icon-btn {
  padding: 0 !important;
  width: 30px;
  min-width: 30px;
  justify-content: center;
}
.pd-icon-btn.is-ai { color: var(--primary); }
.pd-icon-btn.is-ai:hover { color: var(--primary); background: var(--primary-light, rgba(79, 107, 237, 0.1)); }
.pd-icon-btn.is-warn { color: var(--warning); border-color: var(--warning) !important; }
.pd-icon-btn.is-warn:hover { background: var(--warning-bg, rgba(245, 158, 11, 0.1)); }
.pd-icon-btn.is-danger { color: var(--danger); border-color: var(--danger) !important; }
.pd-icon-btn.is-danger:hover { background: rgba(220, 38, 38, 0.08); }

/* v438: 「＋ 新增」下拉按钮与面板 */
.pd-more { position: relative; flex: none; }
.pd-more-btn { gap: 4px; }
.pd-more-btn > svg { width: 13px; height: 13px; }
.pd-more-btn.is-open {
  background: var(--primary-light, rgba(79, 107, 237, 0.1));
  border-color: var(--primary) !important;
  color: var(--primary);
}
/* 面板：挂 body + position:fixed（避开 .pd-tabbar 的 overflow 裁剪） */
.pd-more-panel {
  position: fixed;
  z-index: 1700;
  padding: 6px;
  background: var(--card-bg);
  border: 1px solid var(--border, #e2e6ed);
  border-radius: 12px;
  box-shadow: 0 10px 32px rgba(15, 23, 42, 0.18);
  font-size: 13px;
  animation: pdMoreIn 0.16s var(--ease) both;
}
@keyframes pdMoreIn {
  from { opacity: 0; transform: translateY(-6px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
.pd-more-head {
  padding: 4px 10px 6px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-tertiary);
  letter-spacing: 0.4px;
}
.pd-more-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  color: var(--gray-700);
  user-select: none;
}
.pd-more-item:hover { background: var(--gray-50, #f8fafc); }
.pd-more-item:hover .pd-more-tx b { color: var(--primary); }
.pd-more-ic {
  flex: none;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 7px;
  background: var(--gray-100);
  font-size: 13px;
  color: var(--gray-600);
}
.pd-more-ic > svg { width: 14px; height: 14px; }
.pd-more-item:hover .pd-more-ic { background: var(--primary-light, rgba(79, 107, 237, 0.1)); color: var(--primary); }
.pd-more-tx { min-width: 0; display: flex; flex-direction: column; line-height: 1.35; }
.pd-more-tx > b { font-weight: 600; font-size: 13px; color: var(--gray-800); transition: color 0.15s; }
.pd-more-tx > i { font-style: normal; font-size: 11px; color: var(--text-tertiary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* v438: 箭头改挂在 .pd-tabbar-shell 内部（shell 本身 sticky），
   用 absolute 定位在 shell 的 padding-box 内左右两端：
   - 左箭头贴在分栏区左缘；
   - 右箭头用 --pd-act-w 让出操作区宽度，避免盖住按钮。
   因为 shell 会吸附，箭头随之一同吸附，不需要自己 sticky。 */
.pd-edge {
  position: absolute;
  top: 5px;                              /* 对齐 shell 的 padding-top，只覆盖首行 */
  height: var(--pd-row-h, 32px);         /* 只覆盖首行高度（窄屏第二行不受影响） */
  width: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  color: var(--gray-500);
  cursor: pointer;
  z-index: 31;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s var(--ease), color 0.15s;
  border: none;
  background: none;
  font-family: inherit;
  padding: 0;
}
/* v438: 箭头定位 —— 只在「第一行（分栏区）」范围内，不覆盖右侧操作区、也不跨到窄屏第二行
   ⚠️ 两个坑：
     ① 右侧箭头若用 right:0 会盖住「＋新增/编辑/注销」按钮 → 用 --pd-act-w（JS 量测）让位；
     ② top/bottom 若写 0 会贯穿整个 shell（窄屏两行时压住第二行操作区）→ 锁定首行高度。
   首行高度 = shell 的 padding-top(5) + 分栏条高(32) = 37px；用 --pd-row-h 由 JS 写入更稳，
   这里给出兜底值 38px。 */
.pd-edge-l {
  left: 6px;
  border-radius: 999px 0 0 999px;
  background: linear-gradient(90deg, var(--card-bg) 42%, transparent 100%);
  justify-content: flex-start;
  padding-left: 7px;
}
.pd-edge-r {
  right: calc(var(--pd-act-w, 0px) + 6px);
  border-radius: 0 999px 999px 0;
  background: linear-gradient(270deg, var(--card-bg) 42%, transparent 100%);
  justify-content: flex-end;
  padding-right: 7px;
}
.pd-edge.is-on { opacity: 1; pointer-events: auto; }
.pd-edge:hover { color: var(--primary); }
.pd-edge > span { display: block; line-height: 1; }

/* ============================================================
   v439: 七栏统一美化 —— 统一「工具栏 / 空状态 / 分组标题 / 卡头统计 / 卡片间距」
   目标：七个栏（概况·成员·进度·财务·交付·验收·履约）视觉一致、信息层级清晰。
   ============================================================ */

/* ---------- 统一工具栏（财务栏顶部等：分组 + 分隔 + 右对齐尾组） ---------- */
.pd-tools {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.pd-tools-group {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}
/* 组间竖直分隔线（第一个组不加） */
.pd-tools-group + .pd-tools-group {
  position: relative;
  padding-left: 14px;
}
.pd-tools-group + .pd-tools-group::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 18px;
  background: var(--border);
}
.pd-tools-label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-tertiary);
  letter-spacing: 0.3px;
  white-space: nowrap;
  margin-right: 2px;
}
.pd-tools-end { margin-left: auto; }
/* 工具栏内按钮统一：同高同圆角，图标与文字间距一致 */
.pd-tools .btn-sm {
  height: 30px;
  padding: 0 12px;
  font-size: 12.5px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.pd-tools .btn-sm > svg { width: 14px; height: 14px; flex: none; }

/* v439: 「新增单据」组内四快捷（记一笔 / 预付款 / 合同 / 发票）文案长度 2-3 字，
   默认宽度由内容撑开 → 3 字 84px、2 字 72px 不齐。统一固定等宽，视觉成组更整齐。
   （用户验收要求：统一次要样式、尺寸一致） */
.pd-tools .pd-tools-4up .btn-sm { min-width: 86px; justify-content: center; }


/* 财务栏顶部工具栏所在卡片：去掉多余下边距，让工具栏成为一条独立横条 */
.pd-fin-bar { position: relative; }
.pd-fin-bar > .card-body { padding: 12px 16px; }

/* ---------- 统一空状态（图标 + 标题 + 描述 + 操作） ---------- */
.pd-empty {
  padding: 40px 20px;
  text-align: center;
}
.pd-empty-ic {
  font-size: 30px;
  line-height: 1;
  margin-bottom: 12px;
  opacity: 0.55;
}
.pd-empty-t {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--gray-600);
  margin-bottom: 5px;
}
.pd-empty-d {
  font-size: 12px;
  color: var(--text-tertiary);
  line-height: 1.65;
  max-width: 560px;
  margin: 0 auto;
}
.pd-empty-a {
  margin-top: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
}
/* 紧凑变体（子区块内，如合同/发票为空时） */
.pd-empty-sm { padding: 22px 16px; }
.pd-empty-sm .pd-empty-t { font-size: 12.5px; }
.pd-empty-sm .pd-empty-d { font-size: 11.5px; }

/* ---------- 统一子分组标题（卡内分区，如「📄 合同 (3)」） ---------- */
.pd-sub-hd {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 10px;
}
.pd-sub-hd + * { margin-top: 0; }
.pd-sub-hd-t {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-700);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* ---------- 统一卡头统计文字（替代各栏 inline font-size:12px/color:tertiary） ---------- */
.pd-card-stat {
  font-size: 12px;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  margin-left: auto;
  padding-left: 12px;
}

/* ---------- 统一卡内表格头部（浅底 + 小字，弱化表头） ---------- */
.pd-pane .table.ops > thead > tr { background: var(--gray-50); }
.pd-pane .table.ops > thead th {
  font-size: 12px;
  font-weight: 600;
  color: var(--gray-500);
  white-space: nowrap;
}
.pd-pane .table.ops > tbody td { font-size: 13px; color: var(--gray-700); }
.pd-pane .table.ops > tbody tr:hover { background: var(--gray-50); }

/* ---------- 统一「明细表卡」（原 bt-card inline 样式收编） ---------- */
.pd-pane .bt-card {
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm);
  overflow: hidden;
  margin-bottom: 14px;
}
.pd-pane .bt-card:last-child { margin-bottom: 0; }
/* 明细表卡头（表名 + 行数/合计 + 操作按钮） */
.pd-pane .bt-hd {
  background: var(--gray-50);
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--border-light);
}
.pd-pane .bt-hd-t {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  flex: 1;
}
.pd-pane .bt-hd-n {
  font-weight: 600;
  color: var(--gray-800);
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pd-pane .bt-hd-m {
  font-size: 12px;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pd-pane .bt-hd-a {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
/* 明细表空行提示 */
.pd-pane .bt-blank {
  padding: 14px;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 12px;
}

/* ---------- 窄屏：工具栏改为纵向堆叠，分组分隔线转为顶部边框 ---------- */
@media (max-width: 768px) {
  .pd-tools { gap: 10px; }
  .pd-tools-group + .pd-tools-group {
    padding-left: 0;
    padding-top: 10px;
    width: 100%;
    border-top: 1px solid var(--border-light);
  }
  .pd-tools-group + .pd-tools-group::before { display: none; }
  .pd-tools-label { display: none; }
  .pd-tools-end { margin-left: 0; }
  .pd-empty { padding: 28px 14px; }
  .pd-empty-ic { font-size: 26px; margin-bottom: 10px; }
}

/* ---------- v437: 项目健康度体检卡 ---------- */
.pd-health { position: relative; overflow: hidden; }
.pd-health::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
}
.pd-health.is-good::before { background: var(--success); }
.pd-health.is-warn::before { background: var(--warning); }
.pd-health.is-bad::before  { background: var(--danger); }
.pd-health-score {
  font-size: 15px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.2px;
}
.pd-health-score > i { font-style: normal; font-size: 11px; font-weight: 600; opacity: 0.75; }
.pd-health-bar {
  height: 7px;
  border-radius: 4px;
  background: var(--gray-200);
  overflow: hidden;
  margin-bottom: 14px;
}
.pd-health-bar > i {
  display: block;
  height: 100%;
  border-radius: 4px;
  transition: width 0.5s var(--ease), background 0.3s;
}
.pd-health-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px 18px;
}
.pd-hk { font-size: 11.5px; color: var(--text-tertiary); margin-bottom: 3px; }
.pd-hv {
  font-size: 17px;
  font-weight: 700;
  color: var(--gray-800);
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
}
.pd-hv .pd-hs { font-size: 11px; font-weight: 500; color: var(--text-tertiary); }
.pd-health-note {
  margin-top: 14px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  background: var(--gray-50);
  border: 1px solid var(--border-light);
  font-size: 12px;
  color: var(--gray-600);
  line-height: 1.6;
}

/* ---------- v437: 项目组合卡（概况栏） ---------- */
.pd-pf-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 12px;
  padding: 14px 16px;
  background: var(--gray-50);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
}
.pd-pf-num {
  font-size: 19px;
  font-weight: 700;
  color: var(--primary);
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
.pd-pf-cap { font-size: 11.5px; color: var(--text-tertiary); margin-top: 2px; }

.pd-sib-list { display: flex; flex-direction: column; gap: 6px; }
.pd-sib {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-light);
  background: var(--card-bg);
  cursor: pointer;
  transition: border-color 0.16s, background 0.16s, transform 0.16s var(--ease);
}
.pd-sib:hover {
  border-color: var(--primary-light);
  background: var(--primary-50, rgba(79, 107, 237, 0.05));
  transform: translateX(2px);
}
.pd-sib-main { flex: 1; min-width: 0; }
.pd-sib-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-800);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pd-sib-sub {
  font-size: 11.5px;
  color: var(--text-tertiary);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pd-sib-right { flex: none; display: flex; align-items: center; gap: 8px; }
.pd-sib-bar {
  width: 74px;
  height: 6px;
  border-radius: 3px;
  background: var(--gray-200);
  overflow: hidden;
}
.pd-sib-bar > i {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--primary), var(--primary-light));
}
.pd-sib-pct {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--gray-600);
  font-variant-numeric: tabular-nums;
  min-width: 32px;
  text-align: right;
}

/* ---------- v437: 状态小结四格（进度栏 / 履约栏共用） ---------- */
.pd-tk-sum {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}
.pd-tk-cell {
  padding: 12px 14px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color 0.16s, box-shadow 0.16s;
}
.pd-tk-cell.is-over { border-color: rgba(239, 68, 68, 0.42); }
.pd-tk-cell:hover { box-shadow: var(--shadow-sm); }
.pd-tk-num {
  font-size: 21px;
  font-weight: 700;
  color: var(--gray-800);
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.pd-tk-cap { font-size: 11.5px; color: var(--text-tertiary); margin-top: 3px; }
.pd-tk-bar {
  height: 4px;
  border-radius: 2px;
  background: var(--gray-200);
  overflow: hidden;
  margin-top: 9px;
}
.pd-tk-bar > i {
  display: block;
  height: 100%;
  border-radius: 2px;
  transition: width 0.45s var(--ease);
}

/* ---------- v437: 文档列表（履约栏） ---------- */
.pd-doc-list { display: flex; flex-direction: column; }
.pd-doc-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 16px;
  border-bottom: 1px solid var(--border-light);
}
.pd-doc-row:last-child { border-bottom: none; }
.pd-doc-ic {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--gray-100);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
}
.pd-doc-main { flex: 1; min-width: 0; }
.pd-doc-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-800);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pd-doc-sub { font-size: 11.5px; color: var(--text-tertiary); margin-top: 2px; }

/* 分栏空态（该栏暂无数据时的统一弱提示） */
.pd-empty {
  padding: 40px 16px;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 13px;
}

/* 分栏内的小节标题（交付 / 验收里分隔「清单 / 材料 / 记录」用） */
.pd-subtitle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 16px 0 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-700);
}
.pd-subtitle:first-child { margin-top: 0; }

/* 交付物完成度进度条（交付栏顶部总览） */
.pd-dv-overview {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 14px 16px;
  margin-bottom: 14px;
  background: var(--gray-50);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
}
.pd-dv-overview .pd-dv-num {
  font-size: 22px;
  font-weight: 700;
  color: var(--primary);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.pd-dv-overview .pd-dv-cap { font-size: 11.5px; color: var(--text-tertiary); margin-top: 2px; }
.pd-dv-bar {
  flex: 1;
  min-width: 140px;
  height: 8px;
  background: var(--gray-200);
  border-radius: 4px;
  overflow: hidden;
}
.pd-dv-bar > i {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--primary), var(--primary-light));
  border-radius: 4px;
  transition: width 0.4s var(--ease);
}
/* 全部完成 → 进度条转绿 */
.pd-dv-bar.is-done > i { background: linear-gradient(90deg, var(--success), #34d399); }

/* 验收栏流程状态条（交付 → 验收 → 售后 → 闭环） */
.pd-flow {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 12px 16px;
  margin-bottom: 14px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow-x: auto;
  scrollbar-width: none;
}
.pd-flow::-webkit-scrollbar { display: none; }
.pd-flow-step {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
.pd-flow-dot {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  background: var(--gray-200);
  color: var(--gray-500);
}
.pd-flow-step.is-cur .pd-flow-dot { background: var(--primary); color: #fff; }
.pd-flow-step.is-done .pd-flow-dot { background: var(--success); color: #fff; }
.pd-flow-label { font-size: 12.5px; font-weight: 500; color: var(--gray-500); white-space: nowrap; }
.pd-flow-step.is-cur .pd-flow-label { color: var(--primary); font-weight: 700; }
.pd-flow-step.is-done .pd-flow-label { color: var(--success); }
.pd-flow-line {
  flex: 1;
  min-width: 16px;
  height: 2px;
  margin: 0 10px;
  border-radius: 1px;
  background: var(--gray-200);
}
.pd-flow-line.is-done { background: var(--success); }

/* 桌面端分栏内容自适应宽度；窄屏分栏条圆角收窄 */
@media (max-width: 768px) {
  .pd-tabbar { border-radius: 999px; padding: 4px; }
  .pd-tab { padding: 6px 12px; font-size: 12.5px; }
  .pd-tabhint { display: none; }
  .pd-tab-pos { padding-right: 8px; }
  .pd-dv-overview { gap: 10px; padding: 12px; }
  /* v437: 窄屏箭头收窄，避免挤占 tab */
  .pd-edge { width: 28px; }
  .pd-health-grid { grid-template-columns: repeat(2, 1fr); gap: 10px 12px; }
  .pd-hv { font-size: 15px; }
  .pd-sib-bar { width: 48px; }
  .pd-tk-sum { grid-template-columns: repeat(2, 1fr); }

  /* v438: 窄屏下三区合一会挤成一团 → shell 改为可换行两行：
     第一行保留完整分栏区（可横滑），第二行放操作区（徽标 + 按钮）。
     这样「合并」的收益（桌面单行）保留，窄屏也不会把页签压扁到看不见。 */
  .pd-tabbar-shell {
    flex-wrap: wrap;
    border-radius: 14px;
    row-gap: 4px;
  }
  .pd-tabbar-shell .pd-tabbar { flex-basis: 100%; order: 1; }
  .pd-tab-actions {
    order: 2;
    flex-basis: 100%;
    justify-content: flex-end;
    padding-left: 0;
    border-left: none;
    border-top: 1px solid var(--gray-300);
    border-top: 1px solid color-mix(in srgb, var(--gray-300) 70%, transparent);
    padding-top: 5px;
    margin-left: 0;
  }
  .pd-actions-badges { margin-right: auto; }
  .pd-icon-btn { width: 34px; min-width: 34px; height: 34px; }
  .pd-tab-actions .btn-sm { height: 34px; }
}

/* 2. 溯源水印层：全屏平铺、盖在最上层、不挡点击 */
.pmo-watermark {
  position: fixed;
  left: 0; top: 0; right: 0; bottom: 0;
  z-index: 2147483000;
  pointer-events: none;      /* 关键：不拦截任何点击 */
  background-repeat: repeat;
  background-position: 0 0;
  opacity: 1;
  mix-blend-mode: normal;
}

/* 3. 切后台 / 失焦遮罩：防 Alt+Tab 时截图工具捕获正文 */
.pmo-blur-shield {
  position: fixed;
  left: 0; top: 0; right: 0; bottom: 0;
  z-index: 2147483001;
  display: none;
  align-items: center;
  justify-content: center;
  background: #0f172a;
  pointer-events: none;
}
.pmo-blur-shield.is-on { display: flex; }
.pmo-blur-tip {
  color: #94a3b8;
  font-size: 15px;
  letter-spacing: 1px;
  font-weight: 600;
}

/* 4. 拦截打印：打印输出为空白提示页，正文不落纸
   ⚠️ 必须隐藏 body 所有直属子元素（modal 是动态插到 body 的，不在 #app 内），
   只留 body::after 的提示文字；否则弹窗内容会从打印/另存 PDF 漏出去。 */
@media print {
  body > * { display: none !important; }
  body::after {
    content: "本系统禁止打印 · 如需纸质件请联系管理员";
    display: block;
    padding: 40px;
    font-size: 16px;
    color: #333;
  }
}

/* ==========================================================================
 * v446 智能提示：未读条目闪烁 + 已读标注
 * --------------------------------------------------------------------------
 * ① .pm-unread —— 未读待办所在行整行 1.6s 呼吸脉冲 + 首列左侧红条，
 *    与侧栏角标 .pm-badge-live 同节奏，用户一眼能对上「哪一行对应那个数字」。
 *    用 inset box-shadow 而非 background-color：表格操作列是 position:sticky +
 *    background:inherit，改背景色会破坏其遮挡效果；inset 阴影叠加在其上无副作用。
 * ④ v458 修正：原选择器 tr.pm-unread > td 是逐单元格命中，于是每一列都长出
 *    一条 3px 红边，整行看上去像警报条纹（用户截图反馈）。红条只应出现在首列：
 *    表格单元格现在只呼吸底色，首列改用 ::before 画固定宽度红条、仅呼吸透明度。
 * ② .pm-read —— 已读（点开查看过）但流程未闭环，置灰 + 打「已读」小标，
 *    与未读拉开层次，处理完成后条目本身消失。
 * ③ 行装饰由 js/badges.js 的 decorate() 统一施加，业务模块无需改渲染代码。
 * ========================================================================== */

@keyframes pmPulse {
  0%, 100% {
    box-shadow: inset 0 0 0 999px rgba(244, 63, 94, .04),
                inset 3px 0 0 0 rgba(244, 63, 94, .50);
  }
  50% {
    box-shadow: inset 0 0 0 999px rgba(244, 63, 94, .16),
                inset 3px 0 0 0 rgba(244, 63, 94, 1);
  }
}

/* v458：表格单元格只呼吸底色，红条改由首列 ::before 承担 */
@keyframes pmPulseCell {
  0%, 100% { box-shadow: inset 0 0 0 999px rgba(244, 63, 94, .035); }
  50%      { box-shadow: inset 0 0 0 999px rgba(244, 63, 94, .11); }
}

/* 未读：整行呼吸（表格行作用在 td 上，tr 的 box-shadow 多数浏览器不绘制） */
.pm-unread {
  animation: pmPulse 1.6s ease-in-out infinite;
}
tr.pm-unread > td {
  animation: pmPulseCell 1.6s ease-in-out infinite;
}

/* v458：未读行首列红条（固定 3px 宽，只呼吸透明度，不再逐列出现） */
tr.pm-unread > td:first-child {
  position: relative;
}
tr.pm-unread > td:first-child::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  border-radius: 0 2px 2px 0;
  background: rgba(244, 63, 94, .95);
  animation: pmBarFade 1.6s ease-in-out infinite;
}
@keyframes pmBarFade {
  0%, 100% { opacity: .5; }
  50%      { opacity: 1; }
}

/* 已读：整行置灰（inset 阴影染色 + 文字降灰，均用 !important 压过单元格内联色） */
.pm-read,
tr.pm-read > td {
  box-shadow: inset 0 0 0 999px rgba(148, 163, 184, .10);
  color: #93a0ad !important;
}
/* 卡片式行（任务看板卡 / 列表卡）不是表格，整块降透明度更直观；
   直接子元素降，保留「已读」小标本身清晰可读 */
.pm-read:not(tr) > *:not(.pm-read-tag) {
  opacity: .55;
}
/* 徽标（已报备 / 待审批 等）整体降透明度，避免已读行里仍有一块高饱和色块 */
tr.pm-read > td .badge,
.pm-read .badge {
  opacity: .55;
}

/* 「已读」小标 */
.pm-read-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  height: 16px;
  line-height: 16px;
  border-radius: 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .5px;
  color: #64748b;
  background: rgba(148, 163, 184, .22);
  border: 1px solid rgba(148, 163, 184, .45);
  vertical-align: 1px;
  white-space: nowrap;
  cursor: help;
}

/* v492：看板卡的「已读」小标改到卡片右上角
   --------------------------------------------------------------------------
   问题：.kanban-card 在 v487 改成 display:flex + flex-direction:column 之后，
   decorate() 插到宿主首位的 <span class="pm-read-tag"> 变成 flex 子项，默认
   align-items:stretch 把它横向拉满 —— 卡片顶上多出一条整行灰条，「已读」被拉成
   一根横杠压在标题上方（用户截图反馈）。
   修法：① 小标脱离文档流，绝对定位到卡片右上角（.kanban-card 自带 position:relative，
         其 padding 为 8px 11px，故 top:9px / right:11px 与标题首行、内容右边界对齐）；
        ② 紧跟小标的原首个子元素（.kc-title）补 44px 右侧内边距让位，长标题自动提前
         折行、不再压到小标；未读时装饰被 clearDecor 摘掉，内边距同步消失，无残留。
   ⚠️ 只对「纵向 flex」的看板卡生效。横向 flex 的行（工作台 .dash-act-row、
      成员卡 [data-pm-row]）小标在行内居中/左端显示是正常的，不能一并改成绝对定位。
   -------------------------------------------------------------------------- */
.kanban-card.pm-read > .pm-read-tag {
  position: absolute;
  top: 9px;
  right: 11px;
  margin-left: 0;
  z-index: 1;
}
/* 紧跟小标的原首个子元素为角标让位（看板卡的标题 .kc-title） */
.kanban-card.pm-read > .pm-read-tag + .kc-title {
  padding-right: 44px;
}

/* 侧栏角标：有未读时呼吸脉冲（折叠态 8px 圆点同样生效） */
@keyframes pmBadgePulse {
  0%, 100% {
    transform: scale(1);
    box-shadow: 0 2px 6px rgba(244, 63, 94, .35);
  }
  50% {
    transform: scale(1.16);
    box-shadow: 0 3px 12px rgba(244, 63, 94, .65);
  }
}
.nav-item .nav-badge.pm-badge-live {
  animation: pmBadgePulse 1.6s ease-in-out infinite;
}
.app-layout.sidebar-collapsed .nav-item .nav-badge.pm-badge-live {
  animation: pmBadgePulse 1.6s ease-in-out infinite;
}

/* 无障碍：用户开启「减弱动态效果」时全部降级为静态（未读仍保留左侧红条 + 浅红底） */
@media (prefers-reduced-motion: reduce) {
  .pm-unread,
  tr.pm-unread > td,
  .nav-item .nav-badge.pm-badge-live,
  .app-layout.sidebar-collapsed .nav-item .nav-badge.pm-badge-live {
    animation: none !important;
  }
  .pm-unread,
  tr.pm-unread > td:first-child {
    box-shadow: inset 0 0 0 999px rgba(244, 63, 94, .09),
                inset 3px 0 0 0 rgba(244, 63, 94, .9);
  }
  tr.pm-unread > td {
    box-shadow: inset 0 0 0 999px rgba(244, 63, 94, .09);
  }
  tr.pm-unread > td:first-child::before {
    opacity: 1;
  }
}

/* ============================================================
   v453: 未读消息红角标（红区静态红 / 绿区心跳）
   红区 = 侧栏导航（v445 呼吸角标已有）+ 团队页部门筛选 chips（静态红数字）
   绿区 = 成员卡 / 列表行姓名（心跳双跳动画，点开聊天后递减，归零不渲染）
   ============================================================ */
.member-card { position: relative; }

/* 红区：chips 未读角标（静态红，不动画——动画只属绿区心跳） */
.filter-chip .fc-unread {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  background: linear-gradient(135deg, #ff6a3d, #f43f5e);
  box-shadow: 0 1px 4px rgba(244, 63, 94, .45);
}

/* 绿区：成员卡心跳角标（右上角；pointer-events:none 点击穿透——卡片姓名才是聊天入口） */
.member-card .mc-unread {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  background: linear-gradient(135deg, #ff6a3d, #f43f5e);
  border: 2px solid var(--card-bg);
  box-shadow: 0 2px 8px rgba(244, 63, 94, .55);
  pointer-events: none;
  animation: pmo-heartbeat 1.6s ease-in-out infinite;
}

/* 绿区：列表视图行内角标（姓名右侧） */
.mc-unread-row {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  min-width: 17px;
  height: 17px;
  margin-left: 6px;
  padding: 0 5px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  background: linear-gradient(135deg, #ff6a3d, #f43f5e);
  box-shadow: 0 1px 4px rgba(244, 63, 94, .45);
  vertical-align: middle;
  animation: pmo-heartbeat 1.6s ease-in-out infinite;
}

/* 心跳双跳：一强一弱双峰（lub-dub 节律），1.6s 循环 */
@keyframes pmo-heartbeat {
  0%   { transform: scale(1); }
  14%  { transform: scale(1.24); }
  28%  { transform: scale(1); }
  42%  { transform: scale(1.14); }
  70%  { transform: scale(1); }
  100% { transform: scale(1); }
}

/* 无障碍：减弱动态效果时心跳降级为静态红角标（数字保留） */
@media (prefers-reduced-motion: reduce) {
  .member-card .mc-unread,
  .mc-unread-row {
    animation: none !important;
  }
}

/* v454: 智能提醒「去处理」通用条目定位高亮脉冲（PMO.Dashboard.locateEntry 施加，~3.4s 后移除） */
.pm-locate-pulse { animation: pm-locate-pulse 1.1s ease-in-out 3; }
@keyframes pm-locate-pulse {
  0%, 100% { background-color: transparent; }
  50%      { background-color: rgba(230, 162, 60, .26); }
}
/* 无障碍：减弱动态效果时定位脉冲降级为静态高亮（v453 心跳同款降级策略） */
@media (prefers-reduced-motion: reduce) {
  .pm-locate-pulse { animation: none !important; background-color: rgba(230, 162, 60, .26); }
}
/* ============================================================
   v455: 未读消息联系人卡 + 角标可点击
   ①消息联系人卡：发件人不在当前页签成员列表时补位（PX 收窄 / admin 页签过滤场景），
     呼吸边框一眼可辨，点击整卡打开消息框
   ②成员卡 / 列表行未读角标由「点击穿透」改「可点击」（点击直接打开消息框）
   ============================================================ */
.pm-msg-peer-block { margin-bottom: 18px; }
.pm-msg-peer-title { font-size: 13px; font-weight: 600; color: var(--text); margin-bottom: 10px; }
.pm-msg-peer-card { cursor: pointer; animation: pm-msg-breathe 1.6s ease-in-out infinite; }
.pm-msg-peer-hint { margin-top: 10px; font-size: 12px; font-weight: 600; color: #f43f5e; }

/* 呼吸边框：与心跳角标同族节律（1.6s 循环） */
@keyframes pm-msg-breathe {
  0%, 100% { box-shadow: 0 0 0 1px rgba(244, 63, 94, .25), 0 2px 8px rgba(244, 63, 94, .10); }
  50%      { box-shadow: 0 0 0 2px rgba(244, 63, 94, .55), 0 4px 14px rgba(244, 63, 94, .22); }
}

/* 成员卡 / 列表行角标可点击（v453 为 pointer-events:none 穿透，v455 需求：点击打开消息框） */
.member-card .mc-unread { pointer-events: auto; cursor: pointer; }
.mc-unread-row { cursor: pointer; }

/* 无障碍：减弱动态效果时呼吸边框降级为静态描边（v453/v454 同款降级策略） */
@media (prefers-reduced-motion: reduce) {
  .pm-msg-peer-card { animation: none !important; box-shadow: 0 0 0 2px rgba(244, 63, 94, .45); }
}
/* ==========================================================================
 * v462 选项卡（chips）未读角标 —— 「新消息 / 新增条目」在选项卡上一并显示
 * --------------------------------------------------------------------------
 * 用户需求：新消息、新增条目的提示要在成排的选项卡上也能看到，且要「明显」。
 * 口径由 js/badges.js 单一真源提供（未读智能提醒条目数，点开即归零），
 * 模块只在 chip 上写一个 data-pm-grp 标签，角标与呼吸态由 badges.js 统一注入。
 *
 * ① .pm-chip-count —— 选项卡末尾的红底白字数字角标。
 *    与 v453 团队页的 .fc-unread 刻意拆成两个类名：团队页部门 chip 那枚走
 *    「未读消息」口径（team.js 自渲染），这里走「未读智能提醒」口径
 *    （badges.js 注入）——两枚角标可以同页共存而互不干扰。
 * ② .pm-chip-live —— 该选项卡有未读时的「明显提示」：红色描边 + 圆点红晕，
 *    描边按 1.6s 呼吸，与行装饰 pm-unread / 侧栏 pm-badge-live 同节奏，
 *    用户一眼能对上「哪个选项卡对应侧栏那个数字」。
 *    ⚠️ 只动 border-color，不碰 transform / 不覆盖 box-shadow：
 *      .filter-chip:hover 有 translateY(-1px) + 阴影加深，.filter-chip.active 有
 *      fc-pop 弹入动效。active 态需要一并呼吸时**不允许**直接覆盖 animation
 *      （会把 fc-pop 顶掉），必须像下面 .pm-chip-live.active 那样把两条动画
 *      **合并声明**——两条动的是不同属性，可并行。
 * ========================================================================== */
.filter-chip .pm-chip-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
  color: #fff;
  background: linear-gradient(135deg, #ff6a3d, #f43f5e);
  /* 白色描边把红角标从 chip 底色里托出来（尤其 active 态是实色底） */
  box-shadow: 0 1px 4px rgba(244, 63, 94, .45), 0 0 0 2px var(--card-bg);
}
.filter-chip.active .pm-chip-count {
  box-shadow: 0 1px 4px rgba(15, 23, 42, .30), 0 0 0 2px rgba(255, 255, 255, .92);
}

@keyframes pmChipBreathe {
  0%, 100% { border-color: rgba(244, 63, 94, .45); }
  50%      { border-color: rgba(244, 63, 94, .95); }
}
.filter-chip.pm-chip-live {
  border-color: rgba(244, 63, 94, .60);
  animation: pmChipBreathe 1.6s ease-in-out infinite;
}
/* v462b：active 态（实心胶囊）此前被 :not(.active) 排除 → 「当前打开的这一栏」
   反而不呼吸（E2E 1.10 抓到）。fc-pop 动的是 transform、pmChipBreathe 动的是
   border-color，两者属性不重叠，可以并行声明；这样既保住 v222 的 spring 弹入，
   也让 active 栏同样「明显」。同理不动 box-shadow，:hover 的 translateY 与阴影
   加深照旧。 */
.filter-chip.pm-chip-live.active {
  animation: fc-pop var(--dur-slow) var(--ease-spring),
             pmChipBreathe 1.6s ease-in-out infinite;
}
.filter-chip.pm-chip-live .fc-dot {
  box-shadow: 0 0 0 2px var(--card-bg), 0 0 0 4px rgba(244, 63, 94, .18);
}

/* 无障碍：减弱动态效果时降级为静态红描边（提示仍然在） */
@media (prefers-reduced-motion: reduce) {
  .filter-chip.pm-chip-live,
  .filter-chip.pm-chip-live.active {
    animation: none !important;
    border-color: rgba(244, 63, 94, .85);
  }
}

/* ==========================================================================
   v463: 团队成员在线标识明显化（user: 系统人员 / 项目人员要有明显的在线标识）
   --------------------------------------------------------------------------
   原 v459 只在头像右下角点了一个 8-14px 的小圆点，颜色淡、体量小，在密集的
   成员卡片里几乎看不见，且只能靠颜色判断在线与否。本次两侧同时加强：
     ① 在线点放大（卡片 16px / 列表 11px）+ 双环水波脉冲，静止帧也足够醒目；
     ② 每位成员补一枚「在线 / 离线」状态胶囊——文字直读，不依赖颜色辨识，
        在线为绿底绿字加呼吸描边，离线为灰底灰字静态。
   两处标识同源（同一份 presence 名单），由 team.js updateMemberOnlineDots()
   在同一批循环里同步，原地切 class 不重渲染，不打扰当前交互。
   注：「系统人员」与「项目人员」两个页签的成员卡 / 列表行共用同一套样式。
   ========================================================================== */

/* -- 在线点：双环水波（后置规则覆盖 v459 的 onlinePulse，保持静止帧可辨）
   v467: 头像 56→42，在线点 16→12 同步缩小（right/bottom 收进头像圆弧内） -- */
.mc-online-dot { width: 12px; height: 12px; right: 0; bottom: 0; border-width: 2px; }
.mc-online-dot.on {
  background: #10b981;
  animation: mcDotRing 2.2s ease-out infinite;
}
.mc-online-dot.sm { width: 9px; height: 9px; right: -1px; bottom: -1px; border-width: 1.5px; }
@keyframes mcDotRing {
  0%   { box-shadow: 0 0 0 0 rgba(16, 185, 129, .55); }
  70%  { box-shadow: 0 0 0 5px rgba(16, 185, 129, 0); }
  100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}

/* -- 在线状态胶囊（成员卡：姓名下方居中；成员卡为 text-align:center，inline-flex 即自动居中）
   v467: 胶囊同步收紧（字号 11→10、行高 16→14、下边距 8→6） -- */
.mc-online-state {
  display: inline-flex; align-items: center; gap: 4px;
  margin: 0 0 6px; padding: 1px 8px 1px 7px; border-radius: 999px;
  font-size: 10px; font-weight: 700; line-height: 14px; white-space: nowrap;
  border: 1px solid transparent; vertical-align: middle; letter-spacing: .2px;
}
.mc-online-state i.mc-os-dot {
  width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto; display: inline-block;
}
.mc-online-state.on {
  background: #ecfdf5; color: #047857; border-color: #a7f3d0;
  animation: mcStateBreathe 2.6s ease-in-out infinite;
}
.mc-online-state.on i.mc-os-dot { background: #10b981; box-shadow: 0 0 0 3px rgba(16, 185, 129, .18); }
.mc-online-state.off { background: var(--gray-100); color: var(--gray-500); border-color: var(--border-light); }
.mc-online-state.off i.mc-os-dot { background: var(--gray-400); }
@keyframes mcStateBreathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, .28); }
  50%      { box-shadow: 0 0 0 4px rgba(16, 185, 129, 0); }
}

/* -- 列表行内小号胶囊：跟在姓名与未读角标之后，不占独立一行 -- */
.mc-online-state.sm { margin: 0 0 0 6px; padding: 1px 7px 1px 6px; font-size: 10px; line-height: 15px; }
.mc-online-state.sm i.mc-os-dot { width: 6px; height: 6px; }

/* -- 深色主题：绿底绿字需整体压暗，否则亮底绿字在白卡片之外刺眼（与 perm-act-badge 同色系） -- */
html[data-theme='dark'] .mc-online-state.on { background: #12352a; color: #6ee7b7; border-color: #1f5240; }
html[data-theme='dark'] .mc-online-state.off { background: var(--gray-800); color: var(--gray-400); border-color: var(--border); }

/* -- 无障碍：系统开启「减弱动态效果」时脉冲全部降级为静态（颜色与文字照常保留） -- */
@media (prefers-reduced-motion: reduce) {
  .mc-online-dot.on { animation: none; }
  .mc-online-state.on { animation: none; }
}

/* ============================================================
   v480: 工具栏筛选下拉——全站统一「显现」反馈
   ------------------------------------------------------------
   范围：任务管理 / 验收管理 / 交付管理 / 售后服务 / 采购管理 / 财务管理
        共 6 页 13 处筛选下拉（.page-toolbar 内的 select.form-select）
   三层显现：① 悬停 = 可点（边框加深 + 浅底 + 微立体）
             ② 聚焦 = 激活（主色描边 + 柔光，复用 .form-select:focus）
             ③ 筛选生效（选中项非「全部」）= 持续显现
                （主色描边 + 浅主色底 + 左侧 3px 色条）
   尺寸对齐：高度 32px、圆角 9px，与同排 filter-chip / .btn / view-toggle 齐平
   约束：纯视觉，不动 DOM / 属性 / 事件绑定；全部走主题变量，暗色自动适配
   ============================================================ */
.page-toolbar select.form-select {
  height: 32px !important;
  /* 覆盖各页内联 padding：财务管理六处右内边距仅 10px，原生下拉箭头会压住文字 */
  padding: 0 30px 0 12px !important;
  border-radius: 9px;
  cursor: pointer;
  transition: border-color .16s ease, background-color .16s ease, color .16s ease, box-shadow .16s ease;
}

/* ① 悬停：显现可点 */
.page-toolbar select.form-select:hover {
  border-color: var(--gray-400);
  background-color: var(--gray-50);
  box-shadow: var(--shadow-xs);
}

/* ③ 筛选生效：持续显现，一眼看出「列表已被筛选」
      判据统一 —— 全站 13 处筛选下拉的首项恒为 <option value="all"> */
.page-toolbar select.form-select:not(:has(option[value="all"]:checked)) {
  border-color: var(--primary);
  background-color: var(--primary-bg);
  color: var(--primary);
  box-shadow: inset 3px 0 0 0 var(--primary);
}
.page-toolbar select.form-select:not(:has(option[value="all"]:checked)):hover {
  box-shadow: inset 3px 0 0 0 var(--primary), var(--shadow-xs);
}
.page-toolbar select.form-select:not(:has(option[value="all"]:checked)):focus {
  box-shadow: inset 3px 0 0 0 var(--primary), 0 0 0 3px rgba(79, 107, 237, 0.16);
}


/* ============================================================
   v481: 财务管理——支付流程条（合同 → 预付款 → 发票 → 付款）
   ------------------------------------------------------------
   四步固定顺序；每步：序号 + 名称 + 环节计数 + 状态（ok/warn/todo）
   点击步骤直达对应子视图；全部走主题变量，暗色自动适配
   ============================================================ */
.pay-flow {
  margin-top: 20px;
  padding: 14px 16px 16px;
  border: 1px solid var(--gray-200);
  border-radius: 14px;
  background: var(--gray-50);
}
.pay-flow-hd {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.pay-flow-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--gray-700);
}
.pay-flow-rule {
  font-size: 12px;
  color: var(--text-tertiary);
}
.pf-steps {
  display: flex;
  align-items: stretch;
  gap: 6px;
  overflow-x: auto;
}
.pfs {
  flex: 1 1 0;
  min-width: 148px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--gray-200);
  border-radius: 11px;
  background: var(--bg);
  cursor: pointer;
  text-align: left;
  transition: border-color .16s ease, background-color .16s ease, box-shadow .16s ease;
}
.pfs:hover {
  border-color: var(--gray-400);
  box-shadow: var(--shadow-xs);
}
.pfs.active {
  border-color: var(--primary);
  box-shadow: inset 3px 0 0 0 var(--primary);
}
.pfs-no {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: var(--gray-300);
}
.pfs.ok .pfs-no { background: var(--success); }
.pfs.warn .pfs-no { background: var(--warning); }
.pfs-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pfs-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-700);
}
.pfs-sub {
  font-size: 11px;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pfs-state {
  margin-left: auto;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  font-size: 11px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: var(--gray-300);
}
.pfs.ok .pfs-state { background: var(--success); }
.pfs.warn .pfs-state { background: var(--warning); }
.pfs-arrow {
  flex: 0 0 auto;
  align-self: center;
  color: var(--gray-300);
}

/* v496: 表单控件整体提亮（整站）—— 边框加深 + 焦点品牌色 3px 光晕；
   ::placeholder / disabled / readonly 一并明确。只动这三个基础类。 */
.form-input, .form-select, .form-textarea {
  border-color: var(--gray-400);
  border-radius: 8px;
  font-weight: 500;
}
.form-input::placeholder, .form-textarea::placeholder {
  color: var(--gray-400);
  font-weight: 400;
}
.form-input:hover, .form-select:hover, .form-textarea:hover {
  border-color: var(--gray-500);
}
.form-input:focus, .form-select:focus, .form-textarea:focus {
  border-color: var(--primary);
  background: var(--card-bg);
  box-shadow: 0 0 0 3px rgba(79, 107, 237, 0.16);
}
.form-input:disabled, .form-select:disabled, .form-textarea:disabled,
.form-input[readonly], .form-textarea[readonly] {
  background: var(--gray-50);
  border-color: var(--border);
  color: var(--gray-500);
  cursor: not-allowed;
}
html[data-theme='dark'] .form-input:focus,
html[data-theme='dark'] .form-select:focus,
html[data-theme='dark'] .form-textarea:focus {
  border-color: #6c83f2;
  box-shadow: 0 0 0 3px rgba(108, 131, 242, 0.24);
}
html[data-theme='dark'] .form-input:disabled,
html[data-theme='dark'] .form-select:disabled,
html[data-theme='dark'] .form-textarea:disabled,
html[data-theme='dark'] .form-input[readonly],
html[data-theme='dark'] .form-textarea[readonly] {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--border);
}

/* ============================================================
   v482: 工具栏筛选下拉——默认态「做明显」（整站）
   ------------------------------------------------------------
   范围：.page-toolbar 内的 select.form-select（6 页 13 处筛选下拉）
   痛点：默认态白底 + 浅灰细边（#cbd5e1），与工具栏底色几乎无差，
         原生箭头各浏览器形态不一 → 看不出是「可点的筛选控件」
   方案：① 默认态加深边框（--gray-400）+ 浅灰底（--gray-50）+ 字重 500
         ② 自定义下拉箭头（appearance:none + SVG chevron，全站统一形态）
         ③ 悬停再加深一档（--gray-500 边框 + --gray-100 底 + 深灰箭头）
         ④ 筛选生效态箭头随主色
   说明：SVG data-URI 内无法引用 CSS 变量，箭头颜色按明/暗主题各写一条；
         其余色值仍全部走主题变量，暗色自动适配。
   约束：纯视觉，不动 DOM / 属性 / 事件绑定
   ============================================================ */
.page-toolbar select.form-select {
  appearance: none;
  -webkit-appearance: none;
  border-color: var(--gray-400);
  background-color: var(--gray-50);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%234b5563' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 14px 14px;
  font-weight: 500;
}

/* 悬停：边框 / 底色 / 箭头再加深一档 */
.page-toolbar select.form-select:hover {
  border-color: var(--gray-500);
  background-color: var(--gray-100);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%231f2937' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}

/* 筛选生效：箭头随主色（底色 / 描边 / 文字仍由 v480 段负责） */
.page-toolbar select.form-select:not(:has(option[value="all"]:checked)) {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%234f6bed' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
.page-toolbar select.form-select:not(:has(option[value="all"]:checked)):hover {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%234f6bed' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}

/* 暗色主题：箭头换浅色系（仅 SVG 内颜色硬编码，其余仍走变量） */
html[data-theme='dark'] .page-toolbar select.form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239aa4b5' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
html[data-theme='dark'] .page-toolbar select.form-select:hover {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23d1d5db' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
html[data-theme='dark'] .page-toolbar select.form-select:not(:has(option[value="all"]:checked)) {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236c83f2' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
html[data-theme='dark'] .page-toolbar select.form-select:not(:has(option[value="all"]:checked)):hover {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236c83f2' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}

/* ============================================================
   v483: 支付流程提示条——删除四步大卡条，横幅「显眼·美观·明了」
   ------------------------------------------------------------
   单行横幅：主色描边 + 浅主色底 + 图标 + 流程顺序 + 两枚琥珀硬规则徽章
   旧四步卡（.pf-steps/.pfs*）不再由 JS 生成；残留一律隐藏兜底
   全部走主题变量，暗色自动适配
   ============================================================ */
.pay-flow {
  margin-top: 16px;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  border: 1px solid var(--primary);
  border-radius: 12px;
  background: var(--primary-bg);
  box-shadow: var(--shadow-xs);
}
.pay-flow-ico {
  display: inline-flex;
  color: var(--primary);
  flex: none;
}
.pay-flow-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--primary);
  letter-spacing: .5px;
}
.pay-flow-order {
  font-size: 12px;
  color: var(--text-secondary);
  white-space: nowrap;
}
.pay-flow-order i {
  font-style: normal;
  color: var(--gray-400);
  margin: 0 5px;
}
.pay-flow-gates {
  display: inline-flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-left: auto;
}
.pay-flow-gate {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 600;
  color: var(--warning);
  background: var(--warning-bg);
  border: 1px solid var(--warning);
  border-radius: 999px;
  padding: 3px 10px;
  white-space: nowrap;
}
.pay-flow-gate::before {
  content: "\26A0";
  font-size: 11px;
}
/* v483 兜底：旧四步卡若因缓存残留一律隐藏 */
.pf-steps { display: none !important; }

/* ============================================================
   v484: 项目流程闭环步骤条——按「支付流程」横幅样式统一
   ------------------------------------------------------------
   范围：交付管理 / 项目验收 / 售后管理 三页顶部（app.js flowStepperHtml）
   横幅：主色描边 + 浅主色底 + 图标 + 标题 + 编号步骤（done ✓ / cur 主色 / todo 灰）
   类名化取代 v395 全内联；全部走主题变量，暗色自动适配
   ============================================================ */
.flow-stepper {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 16px;
  padding: 10px 14px;
  border: 1px solid var(--primary);
  border-radius: 12px;
  background: var(--primary-bg);
  box-shadow: var(--shadow-xs);
}
.flow-stepper-ico {
  display: inline-flex;
  color: var(--primary);
  flex: none;
}
.flow-stepper-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--primary);
  letter-spacing: .5px;
  flex: none;
}
.flow-stepper-steps {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.fls {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  border-radius: 8px;
  padding: 2px 4px;
  transition: background .15s ease;
}
.fls.clickable { cursor: pointer; }
.fls.clickable:hover { background: rgba(79, 107, 237, .12); }
.fls-no {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  font-size: 12px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.fls.cur .fls-no { background: var(--primary); color: #fff; }
.fls.done .fls-no { background: var(--success); color: #fff; }
.fls.todo .fls-no { background: var(--gray-200); color: var(--gray-500); }
.fls-label { font-size: 13px; font-weight: 500; color: var(--text-secondary); }
.fls.cur .fls-label { color: var(--primary); font-weight: 700; }
.fls.done .fls-label { color: var(--success); }
.fls-line {
  width: 26px;
  height: 2px;
  border-radius: 1px;
  background: var(--gray-200);
  flex: none;
}
.fls-line.done { background: var(--success); }

/* ============================================================
   v485: 支付流程提示条紧凑化——「变小作为提示」+ 消除与选项卡相贴
   ------------------------------------------------------------
   背景：v483 横幅 48px 整行宽、与下方子视图选项卡 0 间隙相贴（实测 bottom==chip_top）
   方案：整行横幅 → inline-flex 紧凑提示丸（自适应内容宽度）
         底部 margin 14px 与选项卡明确拉开；内部元素同步缩小一档
   纯覆盖段（同特异性后定义生效），DOM 零改动，色值全走主题变量
   ============================================================ */
.pay-flow {
  display: inline-flex;
  margin: 10px 0 14px;
  padding: 4px 12px;
  gap: 8px;
  border-radius: 999px;
  box-shadow: none;
}
.pay-flow-ico svg { width: 13px; height: 13px; }
.pay-flow-title { font-size: 12px; font-weight: 600; letter-spacing: .3px; }
.pay-flow-order { font-size: 11px; }
.pay-flow-order i { margin: 0 3px; }
.pay-flow-gates { gap: 6px; }
.pay-flow-gate { font-size: 11px; font-weight: 500; padding: 1px 8px; }

/* ============================================================
   v486: 支付流程条对齐「交付流程」步骤条
   ------------------------------------------------------------
   结构（finance.js renderPayFlow）与交付页 flowStepperHtml 同款：
     图标 + 标题 + 编号步骤（✓ 已完成 / 当前主色 / 未到灰）+ 连接线
   步骤样式零新增 —— 直接复用交付页 .fls / .fls-no / .fls-label / .fls-line；
   此处只补 .pay-flow 与 .flow-stepper 的三个差异点：
     ① 底部间距：与下方子视图选项卡拉开 14px（v485 教训：曾 0 间隙相贴）
     ② 徽章收窄：规则徽章字号降一档，避免整条过高
     ③ 步骤区换行对齐：空间不足时步骤条换行不挤压徽章
   纯覆盖段（同特异性后定义生效），色值全走主题变量，暗色自动适配
   ============================================================ */
.pay-flow {
  display: flex;
  margin: 10px 0 14px;
  padding: 10px 14px;
  gap: 10px;
  border-radius: 12px;
  box-shadow: var(--shadow-xs);
}
.pay-flow-ico svg { width: 16px; height: 16px; }
.pay-flow-title {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .5px;
  flex: none;
}
.pay-flow-gates {
  margin-left: 0;
  flex: none;
}
.pay-flow-gate {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 9px;
}

/* ============================================================
   v487: 看板卡紧凑化 + 美化（高度变窄）
   ------------------------------------------------------------
   实测旧形态：卡高 112~120px，其中约 24px 是纯空白
     padding 12/12 · .kc-title mb 6px · .kc-project mb 10px · .kc-footer mt 8px
   目标：压到 ~88px，三行信息一行不删（标题 / 项目 / 日期+指派）
   手法：① padding 与行距整体收一档 ② 改 flex column + gap 统一接管行距，
         避免各元素 margin 叠加后又被继承行高顶虚（.kc-footer 原继承 15px 字号）；
         ③ 项目 chip 收紧为紧凑内联；④ 卡间距 8→6
   纯覆盖段（同特异性后定义生效），DOM 零改动，色值全走主题变量，暗色自动适配
   ============================================================ */
.kanban-card {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 9px 12px;
  margin-bottom: 6px;
  border-radius: 8px;
}
/* ① 标题：字号微收 + 下边距压到 3px，行高锁 1.35 防止继承行高顶虚 */
.kanban-card .kc-title {
  font-size: 13px;
  line-height: 1.35;
  margin-bottom: 3px;
}
/* ② 项目 chip：下边距 10 → 5，横向内边距与圆角收紧 */
.kanban-card .kc-project {
  padding: 1px 6px;
  border-radius: 5px;
  margin-bottom: 5px;
  font-size: 11px;
  line-height: 1.5;
}
/* ③ 页脚：上边距 8 → 5，并显式锁字号与行高（原继承 15px 字号导致行高虚高） */
.kanban-card .kc-footer {
  margin-top: 5px;
  font-size: 11px;
  line-height: 1.5;
}
.kanban-card .kc-footer .kc-date,
.kanban-card .kc-footer .kc-assignee-name,
.kanban-card .kc-footer .kc-unassigned {
  font-size: 11px;
  line-height: 1.5;
}
/* ④ 悬停：位移收敛到 1px，避免「变窄后抖得明显」 */
.kanban-card:hover {
  transform: translateX(1px);
}

/* ============================================================
   v487b: 看板卡精修（承接 v487 首段的实测修正）
   ------------------------------------------------------------
   首段实测暴露三点（diag_v487.js 实锤）：
   ① 有指派人的卡比未指派的卡高 7px（95 vs 88）——元凶是 .kc-assignee 里的
      头像 .user-avatar.xs 为 24px，比 11px 文字高出整整一圈，把 footer 顶到 24px。
      该尺寸是全局值（聊天、表格都在用），不能在全局改 → 卡作用域内收到 16px。
   ② .kc-project 卡内被 flex 块化 → 从 inline-block 变成满宽（截图里一条长灰条）。
      改 align-self: flex-start，chip 缩到内容宽度，视觉立刻精致。
   ③ 附件行（无类名 DIV）是内容，不动。
   纯 CSS 覆盖段，DOM 零改动，色值走主题变量。
   ============================================================ */
.kanban-card {
  padding: 8px 11px;
  margin-bottom: 5px;
}
/* ① 头像收窄：只在看板卡作用域内生效，不影响聊天 / 表格的 24px */
.kanban-card .kc-assignee .user-avatar.xs {
  width: 16px;
  height: 16px;
  font-size: 9px;
  line-height: 16px;
}
/* ② 项目 chip 缩到内容宽，不再拉成满宽灰条 */
.kanban-card .kc-project {
  align-self: flex-start;
  max-width: 100%;
}
/* ③ 附件行（任务卡特有）行距统一，与项目 chip 视觉同族 */
.kanban-card > div:not([class]) {
  margin-top: 3px !important;
  font-size: 11px;
  line-height: 1.5;
}

/* ============================================================
   v488: chip 下拉（付款状态聚合）
   ------------------------------------------------------------
   预付款页原三个状态 chip（待付款/部分付款/已付清）合并为一个「付款」chip，
   悬停或点击展开三选项。触发 chip 计数随当前选择变化：
   未筛选时显示三态合计，选中某态时显示该态笔数。
   暗色自动适配（全走主题变量）。
   ============================================================ */
.chip-dropdown {
  position: relative;
  display: inline-flex;
}
/* 触发 chip 右侧小三角 */
.chip-dropdown .chip-dd-caret {
  margin-left: 2px;
  opacity: .62;
  transition: transform .18s;
  flex-shrink: 0;
}
.chip-dropdown.open .chip-dd-caret { transform: rotate(180deg); }
.chip-dropdown:hover .chip-dd-caret { opacity: 1; }
/* 选项面板：默认隐藏，悬停 / .open 时浮出 */
.chip-dropdown .chip-dd-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 60;
  margin-top: 6px;
  min-width: 148px;
  padding: 5px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 9px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.14);
  display: none;
  flex-direction: column;
  gap: 2px;
}
.chip-dropdown:hover .chip-dd-menu,
.chip-dropdown.open .chip-dd-menu {
  display: flex;
}
/* 悬停桥：面板与触发 chip 之间的 6px 空隙不能中断 hover */
.chip-dropdown::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 8px;
}
/* 单个选项 */
.chip-dropdown .chip-dd-item {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  padding: 6px 9px;
  background: transparent;
  border: 0;
  border-radius: 6px;
  font-size: 12px;
  font-family: inherit;
  color: var(--text-secondary);
  cursor: pointer;
  text-align: left;
  transition: background .14s, color .14s;
}
.chip-dropdown .chip-dd-item:hover {
  background: var(--gray-50);
  color: var(--text-primary);
}
/* 选中态：左侧色条 + 加粗（色条用 inset 阴影，避免改动布局宽度） */
.chip-dropdown .chip-dd-item.on {
  background: var(--primary-bg);
  color: var(--primary);
  font-weight: 600;
  box-shadow: inset 3px 0 0 0 var(--primary);
}
.chip-dropdown .chip-dd-item .fc-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--gray-400);
  flex-shrink: 0;
}
.chip-dropdown .chip-dd-item[data-adv-status="pending"] .fc-dot { background: #f59e0b; }
.chip-dropdown .chip-dd-item[data-adv-status="partial"] .fc-dot { background: #6366f1; }
.chip-dropdown .chip-dd-item[data-adv-status="paid"]    .fc-dot { background: #10b981; }
.chip-dropdown .chip-dd-item .fc-count {
  margin-left: auto;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-tertiary);
  background: var(--gray-100);
  border-radius: 999px;
  padding: 0 7px;
  line-height: 17px;
}
.chip-dropdown .chip-dd-item.on .fc-count {
  color: var(--primary);
  background: var(--card-bg);
}

/* ============================================================
   v488d: chips 压缩后间距微调
   ------------------------------------------------------------
   chip 文字压成两字后，内部「计数胶囊 fc-count」与「红色角标 pm-chip-count」
   挤在一起（视觉连成「104」）。原长文字时靠字宽天然有间隔，压缩后必须显式拉开。
   只加间隙，不动配色与尺寸。
   ============================================================ */
.filter-chip .pm-chip-count {
  margin-left: 5px;
}
.filter-chip .fc-count {
  margin-left: 1px;
}
/* 下拉触发 chip：计数胶囊与右侧三角之间留白 */
.chip-dropdown .chip-dd-trigger .chip-dd-caret {
  margin-left: 4px;
}


/* ============================================================
   v489: 成员累计在线时长（成员卡/列表胶囊 + 顶栏在线浮层）
   ------------------------------------------------------------
   一、胶囊内时长：v463 的在线状态胶囊 .mc-online-state 内部追加
       「│ 累计 12小时40分」。分隔符走 currentColor + 半透明，
       于是在线（绿字）随绿、离线（灰字）随灰，无需为两态各写一条色值。
       结构：.mc-os-dot / .mc-os-label / .mc-os-sep / .mc-os-time（均由 JS 原地改写）
   二、顶栏在线浮层：#onlinePopover 由 app.js 动态创建挂到 body（position:fixed），
       按 #onlineIndicator 的 getBoundingClientRect 定位。全走主题变量，暗色自动适配。
   纯追加覆盖段，DOM 结构性改动为零（浮层节点是新增，不动 index.html）。
   ============================================================ */
.mc-online-state .mc-os-sep {
  display: inline-block;
  width: 1px;
  height: 9px;
  margin: 0 1px;
  border-radius: 1px;
  background: currentColor;
  opacity: .3;
  flex: 0 0 auto;
}
.mc-online-state .mc-os-time {
  font-size: inherit;
  font-weight: 600;
  letter-spacing: 0;
  opacity: .9;
  white-space: nowrap;
  flex: 0 0 auto;
}
/* 小号胶囊（列表行内）时长再收半档，与姓名/角标同一视觉重量 */
.mc-online-state.sm .mc-os-time { opacity: .85; }

/* -- 顶栏触发器：指示器原本是纯展示，v489 起可点击 -- */
#onlineIndicator { cursor: pointer; }
#onlineIndicator:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* -- 在线成员浮层 -- */
#onlinePopover {
  position: fixed;
  z-index: 3000;
  width: 268px;
  max-height: 62vh;
  overflow-y: auto;
  box-sizing: border-box;
  padding: 6px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-lg);
  font-size: 12px;
  color: var(--gray-700);
  animation: onlinePopIn .14s ease-out;
}
@keyframes onlinePopIn {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
#onlinePopover .op-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 6px 7px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--border-light);
  font-size: 12px;
  font-weight: 700;
  color: var(--gray-800);
}
#onlinePopover .op-count { font-weight: 600; color: var(--text-tertiary); }
#onlinePopover .op-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px;
  border-radius: 7px;
  transition: background .15s;
}
#onlinePopover .op-row:hover { background: var(--gray-50); }
#onlinePopover .op-main { flex: 1 1 auto; min-width: 0; }
#onlinePopover .op-name {
  font-size: 12px;
  font-weight: 600;
  color: var(--gray-800);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#onlinePopover .op-sub {
  font-size: 11px;
  color: var(--text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#onlinePopover .op-now {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 700;
  color: #047857;
  white-space: nowrap;
}
#onlinePopover .op-empty {
  padding: 16px 8px;
  text-align: center;
  font-size: 12px;
  color: var(--text-tertiary);
}
#onlinePopover .op-tip {
  margin-top: 4px;
  padding: 6px 6px 2px;
  border-top: 1px solid var(--border-light);
  font-size: 10px;
  line-height: 1.5;
  color: var(--text-tertiary);
}
/* 暗色：本次时长绿字整体压暗（与 .mc-online-state.on 同色系） */
html[data-theme='dark'] #onlinePopover .op-now { color: #6ee7b7; }
/* ---------- v493: 预付款「付款」主操作按钮（明显大气体面 + 按付款状态自动失效） ----------
   设计意图：与同行「凭证 / 编辑 / 删除」等 28px 的 btn-sm 次要操作拉开层级 ——
   更高（34px）、更宽（≥100px）、有底色与投影、hover 抬升，一眼看出哪一个是主操作。
   三态：待付款（蓝渐变·主操作）/ 部分付款（橙渐变·需续付）/ 已付清（灰底·失效不可点）。 */
.btn-pay {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 100px;
  height: 34px;
  padding: 0 14px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.5px;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: 9px;
  color: #fff;
  background: linear-gradient(135deg, #4f6bed 0%, #5b7bef 100%);
  box-shadow: 0 3px 10px rgba(79, 107, 237, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.16);
  cursor: pointer;
  transition: all 0.18s ease;
}
.btn-pay svg { width: 14px; height: 14px; flex: none; }
.btn-pay:hover {
  background: linear-gradient(135deg, #3e5cdb 0%, #4a6adb 100%);
  box-shadow: 0 8px 20px rgba(79, 107, 237, 0.40), inset 0 1px 0 rgba(255, 255, 255, 0.20);
  transform: translateY(-1px);
}
.btn-pay:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(79, 107, 237, 0.34);
}
.btn-pay:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(79, 107, 237, 0.24), 0 3px 10px rgba(79, 107, 237, 0.34);
}

/* 部分付款：仍有待付余额 —— 橙渐变（与进度条/状态语义一致，提示「还要继续付」） */
.btn-pay.is-partial {
  background: linear-gradient(135deg, #d97706 0%, #f59e0b 100%);
  box-shadow: 0 3px 10px rgba(217, 119, 6, 0.30), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.btn-pay.is-partial:hover {
  background: linear-gradient(135deg, #b45309 0%, #d97706 100%);
  box-shadow: 0 8px 20px rgba(217, 119, 6, 0.40), inset 0 1px 0 rgba(255, 255, 255, 0.20);
}
.btn-pay.is-partial:focus-visible {
  box-shadow: 0 0 0 3px rgba(217, 119, 6, 0.24), 0 3px 10px rgba(217, 119, 6, 0.34);
}

/* 已付清：失效态 —— 灰底灰字、无阴影、无 hover 抬升，cursor 明示不可点 */
.btn-pay.is-done,
.btn-pay:disabled {
  background: var(--gray-100);
  border-color: var(--gray-200);
  color: var(--gray-500);
  font-weight: 500;
  box-shadow: none;
  cursor: not-allowed;
  transform: none;
}
.btn-pay.is-done:hover,
.btn-pay:disabled:hover,
.btn-pay.is-done:active {
  background: var(--gray-100);
  box-shadow: none;
  transform: none;
}

/* 操作列按钮行：让 34px 主操作与 28px 次要操作垂直居中对齐（inline-flex 基线对齐会错位） */
.ops-inline {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-wrap: nowrap;
}
/* 无障碍：减弱动态效果时取消浮层入场动画 */
@media (prefers-reduced-motion: reduce) {
  #onlinePopover { animation: none; }
}

/* ============================================================
   v496: 全站下拉「自绘面板」+ 表单控件整体提亮
   ------------------------------------------------------------
   为什么：原生 <select> 的展开弹出层由**操作系统渲染**，CSS 完全够不着 ——
   展开后选中项是浏览器默认的灰底（用户截图反馈），与整站精修视觉割裂。
   方案（见 js/select.js）：保留原生 select 与其文字（业务代码零改动），
   点击时 JS 阻止系统弹出，改弹 .pm-dd 面板，选中后写回 value 并派发原生 change。
   本段只负责「面板长什么样」+「原生壳收起态怎么显示」。

   醒目铁律（用户诉求「整站所有做醒目」）：
     · 选中项   = 品牌蓝渐变实底 + 白字 + 右侧对勾   ← 取代浏览器灰底
     · 悬停/键盘高亮 = 浅蓝底 + 品牌蓝字 + 左侧蓝色指示条
     · 面板     = 白底 + 14px 圆角 + 分层阴影 + 品牌色淡边
     · 收起态壳 = 品牌色描边 + 加粗 + 悬停浅蓝底，一眼看出可点
   暗色主题整套覆盖；SVG 内颜色按主题各写一条（data-URI 引用不到 CSS 变量）。
   ============================================================ */

/* ---------- ① 原生 select 收起态：加深「可点」提示 ---------- */
select[data-pm-dd="on"]:not([multiple]) {
  cursor: pointer;
  border-color: #a5b4fc;
  background-color: var(--card-bg);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(79, 107, 237, 0.07);
}
select[data-pm-dd="on"]:not([multiple]):hover {
  border-color: var(--primary);
  background-color: var(--primary-bg);
  box-shadow: 0 3px 10px rgba(79, 107, 237, 0.14);
}
select[data-pm-dd="on"]:not([multiple]):focus,
select[data-pm-dd="on"]:not([multiple]).pm-dd-open {
  border-color: var(--primary);
  background-color: var(--primary-bg);
  box-shadow: 0 0 0 3px rgba(79, 107, 237, 0.16);
  outline: none;
}
/* 筛选已生效（非 all）→ 描边更重（与 v482 的箭头变色配套） */
select[data-pm-dd="on"]:not([multiple]):not(:has(option[value="all"]:checked)):not(:focus):not(:hover) {
  border-color: var(--primary);
  background-color: var(--primary-bg);
}

/* ---------- ② 自绘面板 ---------- */
.pm-dd {
  position: fixed;
  z-index: 4000;                 /* 高于弹窗遮罩，低于 toast */
  min-width: 140px;
  padding: 6px;
  background: var(--card-bg);
  border: 1px solid rgba(79, 107, 237, 0.22);
  border-radius: 14px;
  box-shadow:
    0 4px 10px rgba(15, 23, 42, 0.08),
    0 16px 40px rgba(15, 23, 42, 0.16);
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  animation: pmDdIn 0.14s cubic-bezier(0.22, 1, 0.36, 1);
  transform-origin: top center;
}
.pm-dd.pm-dd-up { transform-origin: bottom center; }

@keyframes pmDdIn {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .pm-dd { animation: none; }
}

/* 分组标题（<optgroup>） */
.pm-dd-grp {
  padding: 7px 12px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  color: var(--text-tertiary);
}

/* 选项行 */
.pm-dd-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px 9px 10px;
  border-radius: 9px;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.35;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.pm-dd-item .pm-dd-txt {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pm-dd-item .pm-dd-tick {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: transparent;             /* 未选中：不可见但占位（防选中时横向抖动） */
}
.pm-dd-item .pm-dd-tick svg { display: block; }

/* ---------- ②.5 v501: 悬停「滑动切换」共用滑块 ----------
   用户诉求「鼠标经过滑动切换」：高亮底色不再逐项「就地亮起」，而由一块共用的
   浅蓝底板在项之间平滑滑移，形成连续动势（两项之间尤其明显）。
   三条设计约束：
     · z-index:0（低于 .pm-dd-item 的 1）→ 选中项的蓝实底天然盖住滑块，
       无需为「滑块滑到选中项」写特判；JS 另让它淡出，避免「块钻进蓝块后消失」。
     · 只有滑块**真的显示**时面板才挂 .has-slider，此刻项自身的 :hover 底色与
       指示条让位给滑块。二者同色（--primary-bg 不透明 #eef2ff），若不门控，
       目标项会先就地亮起再叠加滑块，滑动感被吃掉。
     · 未挂 .has-slider 时（如面板正好在静止光标下弹出、尚未产生 mousemove）
       完全退回 v500 的 :hover 表现 → 不存在「无底色」空窗。
   几何由 JS 读实测 offset* 后内联，CSS 不写死宽高。 */
.pm-dd-slider {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  width: 0;
  height: 0;
  border-radius: 9px;                 /* 与 .pm-dd-item 一致 */
  background: var(--primary-bg);
  opacity: 0;
  pointer-events: none;               /* 绝不参与命中，点击判定仍落在 .pm-dd-item */
  transition:
    transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
    height 0.18s cubic-bezier(0.22, 1, 0.36, 1),
    width 0.18s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.14s ease;
}
/* 左侧指示条随滑块一起滑移（项自身的 :hover::before 在 has-slider 下已让位） */
.pm-dd-slider::before {
  content: '';
  position: absolute;
  left: 0;
  top: 7px;
  bottom: 7px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--primary);
}
/* 文字层压在滑块之上（.pm-dd-item 本身已是 position: relative） */
.pm-dd-item { z-index: 1; }

.pm-dd.has-slider .pm-dd-item:hover:not(.is-sel):not(.is-dis) {
  background: transparent;
}
.pm-dd.has-slider .pm-dd-item:hover:not(.is-sel):not(.is-dis)::before {
  display: none;
}
html[data-theme='dark'] .pm-dd-slider { background: rgba(108, 131, 242, 0.18); }
html[data-theme='dark'] .pm-dd-slider::before { background: #93a6f7; }
@media (prefers-reduced-motion: reduce) {
  .pm-dd-slider { transition: none; }
}

/* ---- 悬停 / 键盘高亮：浅蓝底 + 蓝字 + 左侧指示条 ---- */
.pm-dd-item:hover,
.pm-dd-item.is-cursor {
  background: var(--primary-bg);
  color: var(--primary);
  font-weight: 600;
}
.pm-dd-item:hover::before,
.pm-dd-item.is-cursor::before {
  content: '';
  position: absolute;
  left: 0;
  top: 7px;
  bottom: 7px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--primary);
}
/* v500: 鼠标经过也要有「切换」动势 —— 指示条从左侧滑入 + 底色渐显。
   原 v496 只给 .is-cursor 写了指示条，纯鼠标悬停时退回的 only-底色变化
   不足以让人感知「正在切换目标项」（用户截图反馈）。 */
.pm-dd-item {
  transition: background-color 0.14s ease, color 0.14s ease, transform 0.14s ease;
}
.pm-dd-item:hover,
.pm-dd-item.is-cursor {
  transform: translateX(1px);
}
/* 选中项已满底色，再位移会让蓝块顶出面板圆角 → 排除 */
.pm-dd-item.is-sel:hover,
.pm-dd-item.is-sel.is-cursor { transform: none; }

/* ---- 选中项：品牌蓝渐变实底 + 白字 + 对勾（取代浏览器灰底） ---- */
.pm-dd-item.is-sel {
  background: linear-gradient(135deg, #5b76f0, var(--primary));
  color: #fff;
  font-weight: 700;
  box-shadow: 0 3px 10px rgba(79, 107, 237, 0.32);
}
.pm-dd-item.is-sel .pm-dd-tick { color: #fff; }
.pm-dd-item.is-sel:hover,
.pm-dd-item.is-sel.is-cursor {
  background: linear-gradient(135deg, #6b84f3, #4560e8);
  color: #fff;
}
/* ★ v500 回归修复：白条必须由 .is-sel 独立承载。
   原先只写在 `.is-sel.is-cursor::before` 上，而 v500 引入「鼠标模式不渲染
   is-cursor」后，选中项左侧白条会随之消失（S5b 负向对照抓到）。
   现在 :hover / :focus 等任何态下都保持白条。 */
.pm-dd-item.is-sel::before,
.pm-dd-item.is-sel:hover::before,
.pm-dd-item.is-sel.is-cursor::before { background: rgba(255, 255, 255, 0.9); }

/* 禁用项 */
.pm-dd-item.is-dis {
  color: var(--text-tertiary);
  cursor: not-allowed;
  opacity: 0.55;
}
.pm-dd-item.is-dis:hover {
  background: transparent;
  color: var(--text-tertiary);
  font-weight: 500;
}
.pm-dd-item.is-dis.is-cursor::before { display: none; }

/* 滚动条：细，不抢视觉 */
.pm-dd::-webkit-scrollbar { width: 8px; }
.pm-dd::-webkit-scrollbar-thumb {
  background: rgba(15, 23, 42, 0.16);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.pm-dd::-webkit-scrollbar-thumb:hover {
  background: rgba(15, 23, 42, 0.3);
  background-clip: padding-box;
}

/* ---------- ③ 暗色主题 ---------- */
html[data-theme='dark'] select[data-pm-dd="on"]:not([multiple]) {
  border-color: rgba(108, 131, 242, 0.5);
  background-color: var(--card-bg);
}
html[data-theme='dark'] select[data-pm-dd="on"]:not([multiple]):hover,
html[data-theme='dark'] select[data-pm-dd="on"]:not([multiple]):focus,
html[data-theme='dark'] select[data-pm-dd="on"]:not([multiple]).pm-dd-open {
  border-color: #6c83f2;
  background-color: rgba(79, 107, 237, 0.16);
}
html[data-theme='dark'] .pm-dd {
  background: var(--card-bg);
  border-color: rgba(108, 131, 242, 0.34);
  box-shadow:
    0 4px 10px rgba(0, 0, 0, 0.4),
    0 18px 44px rgba(0, 0, 0, 0.55);
}
html[data-theme='dark'] .pm-dd-item { color: var(--text); }
html[data-theme='dark'] .pm-dd-item:hover,
html[data-theme='dark'] .pm-dd-item.is-cursor {
  background: rgba(108, 131, 242, 0.18);
  color: #93a6f7;
}
html[data-theme='dark'] .pm-dd-item.is-sel {
  background: linear-gradient(135deg, #5b76f0, #3b52d4);
  color: #fff;
}


/* ==========================================================================
 * v499 看板三列状态可视化：待办 / 进行中 / 已完成 一眼分明
 * --------------------------------------------------------------------------
 * 问题（v498 实测基线）：
 *   ① 三列列头底色亮度 L 分别为 96 / 97 / 96 —— ΔL ≤ 1，只靠极淡色相差区分，
 *      肉眼几乎分不出「待办」和「进行中」（用户截图反馈「做明显区分」）。
 *   ② 卡片左侧 3px 竖条原本承载「优先级色」，而绝大多数卡片都是 p-medium
 *      → 三列卡片的竖条全部是同一个蓝 rgb(59,130,246)，状态信息被完全盖住。
 *   ③ v446 未读红条用 `inset 3px 0 0 0 rgba(244,63,94,..)`，与优先级竖条
 *      抢占同一个左侧 3px 位置，两者互相叠压。
 *
 * 方案：
 *   ① 列头改「实心深色块 + 白字」——三色同为深色家族（板岩 / 深蓝 / 墨绿），
 *      对比度 7.58 / 5.68 / 5.48，全部 ≥ WCAG AA 4.5，视觉「大气正式」。
 *   ② 竖条语义改为「状态色」，由列 class 驱动；优先级降级为标题前 6px 彩色
 *      小圆点（.kc-prio），信息不丢失但不再抢状态的位置。
 *   ③ 未读红条改「整卡外发光 + 呼吸」，离开左侧竖条位置，不与状态色打架。
 *   ④ 卡片右上角加状态胶囊（.kc-state），脱离列头独立看单卡也能自证状态。
 *
 * 兼容：全部新增/覆盖均为 .kanban-col-* 作用域内，不影响合作伙伴看板
 *       （v344 的 .partner-card 走独立 class）；未读呼吸节奏沿用 1.6s。
 * ========================================================================== */

/* ① 状态色 token（亮主题）：深色实心版，供列头/竖条/标签三处复用 */
:root {
  --kb-todo: #475569;        /* 待办：深板岩灰 —— 白字对比度 7.58 */
  --kb-todo-soft: #f1f5f9;
  --kb-todo-line: #64748b;   /* v499e: #94a3b8 在白卡上对比仅 ≈2.4:1（特写复查）→ 加深 */
  --kb-doing: #3d5bd9;       /* 进行中：品牌蓝加深 —— 白字对比度 5.68 */
  --kb-doing-soft: #eef2ff;
  --kb-doing-line: #3d5bd9;
  --kb-done: #047857;        /* 已完成：墨绿 —— 白字对比度 5.48 */
  --kb-done-soft: #ecfdf5;
  --kb-done-line: #047857;
}

/* 暗主题：深色块在白字下会过亮，改用「深色低饱和底 + 亮色字」，
   并把竖条换成亮色系，保证暗底上的可辨识度 */
html[data-theme='dark'] {
  --kb-todo: #334155;
  --kb-todo-soft: #232a38;
  --kb-todo-line: #94a3b8;   /* 暗主题保持：#94a3b8 在暗底上对比充分 */
  --kb-doing: #2a3d8f;
  --kb-doing-soft: #232c47;
  --kb-doing-line: #7b8ff5;
  --kb-done: #064e3b;
  --kb-done-soft: #12352a;
  --kb-done-line: #34d399;
}

/* ② 列头：实心深色块 + 白字 + 加粗顶部色条 */
.kanban-column .kanban-column-header {
  border-bottom: none;
  padding: 13px 16px;
}
.kanban-column .kanban-column-header .kc-title {
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .3px;
}
.kanban-column .kanban-column-header .kc-dot {
  width: 7px;
  height: 7px;
  background: rgba(255, 255, 255, .9) !important;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .22);
  border-radius: 50%;
}
/* 计数徽章：列头变深底后，改「半透明白底 + 白字」保证可读 */
.kanban-column .kanban-column-header .kc-count {
  background: rgba(255, 255, 255, .20) !important;
  color: #fff !important;
  border-color: rgba(255, 255, 255, .34) !important;
  font-weight: 700;
  padding: 1px 9px;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
/* 顶部色条：与列头同色，加粗到 4px 增强整体感 */
.kanban-column .kanban-col-accent {
  height: 4px;
  background: currentColor;
}

/* 三列各自的实心色块 */
.kanban-col-todo .kanban-column-header        { background: var(--kb-todo); }
.kanban-col-todo .kanban-col-accent           { color: var(--kb-todo); }
.kanban-col-inprogress .kanban-column-header  { background: var(--kb-doing); }
.kanban-col-inprogress .kanban-col-accent     { color: var(--kb-doing); }
.kanban-col-done .kanban-column-header        { background: var(--kb-done); }
.kanban-col-done .kanban-col-accent           { color: var(--kb-done); }

/* 列容器：加一圈同色浅描边，强化「这是一整列」的边界感 */
.kanban-column {
  overflow: hidden;
}
.kanban-col-todo       { border-color: var(--kb-todo-line); }
.kanban-col-inprogress { border-color: var(--kb-doing-line); }
.kanban-col-done       { border-color: var(--kb-done-line); }
.kanban-col-todo       .kanban-column-body { background: #fafbfc; }
.kanban-col-inprogress .kanban-column-body { background: #f8f9ff; }
.kanban-col-done       .kanban-column-body { background: #f8fdfb; }

/* ③ 卡片左侧竖条：优先级色 → 状态色（由列 class 驱动） */
.kanban-col-todo       .kanban-card { border-left-color: var(--kb-todo-line); border-left-width: 4px; }
.kanban-col-inprogress .kanban-card { border-left-color: var(--kb-doing-line); border-left-width: 4px; }
.kanban-col-done       .kanban-card { border-left-color: var(--kb-done-line); border-left-width: 4px; }
/* 已完成列整卡轻微降饱和，与在途任务拉开层次（不改文字对比度） */
.kanban-col-done .kanban-card .kc-title { color: var(--gray-600); }

/* ④ 优先级小圆点：替换原竖条的优先级语义，插在标题前
   v499c: 6px 在浅底上偏弱 → 加大到 7px 并套一圈同色 35% 描边环，
          配合 title 提示，浅底/暗底都能一眼看出优先级。 */
.kanban-card .kc-prio {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-right: 7px;
  vertical-align: 1px;
  flex-shrink: 0;
  box-sizing: border-box;
  position: relative;
  top: -1px;
}
.kanban-card .kc-prio.p-critical { background: var(--danger);  box-shadow: 0 0 0 2px rgba(239, 68, 68, .22); }
.kanban-card .kc-prio.p-high     { background: var(--warning); box-shadow: 0 0 0 2px rgba(245, 158, 11, .22); }
.kanban-card .kc-prio.p-medium   { background: var(--info);    box-shadow: 0 0 0 2px rgba(59, 130, 246, .22); }
.kanban-card .kc-prio.p-low      { background: var(--gray-400); box-shadow: 0 0 0 2px rgba(156, 163, 175, .22); }

/* ③v499c 未读小圆点：放在卡片右上角状态胶囊的**左侧**并排，
   明确表达「未读」。由 JS 注入，仅未读卡出现；已读卡不渲染
   → 天然形成正向/负向对照（无需 :has()，兼容性更稳）。 */
.kanban-card .kc-unread-dot {
  position: absolute;
  top: 13px;
  right: 70px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(244, 63, 94, .95);
  box-shadow: 0 0 0 3px rgba(244, 63, 94, .16);
  pointer-events: none;
  z-index: 2;
  animation: kbUnreadDotPulse 1.6s ease-in-out infinite;
}
/* v499e: 与整卡发光同节奏呼吸，强化「未读」关联 */
@keyframes kbUnreadDotPulse {
  0%, 100% { opacity: .55; transform: scale(.88); }
  50%      { opacity: 1;   transform: scale(1); }
}
/* 未读点存在时标题再让一点位，避免与点叠字 */
.kanban-card:has(.kc-unread-dot) .kc-title { padding-right: 62px; }

/* ⑤ 卡片右上角状态胶囊：脱离列头也能自证状态 */
.kanban-card .kc-state {
  position: absolute;
  top: 8px;
  right: 10px;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.5;
  padding: 0 7px;
  border-radius: 9px;
  letter-spacing: .2px;
  pointer-events: none;
  z-index: 1;
}
.kanban-col-todo       .kanban-card .kc-state { color: var(--kb-todo);  background: var(--kb-todo-soft);  box-shadow: inset 0 0 0 1px rgba(71, 85, 105, .28); }
.kanban-col-inprogress .kanban-card .kc-state { color: var(--kb-doing); background: var(--kb-doing-soft); box-shadow: inset 0 0 0 1px rgba(61, 91, 217, .28); }
.kanban-col-done       .kanban-card .kc-state { color: var(--kb-done);  background: var(--kb-done-soft);  box-shadow: inset 0 0 0 1px rgba(4, 120, 87, .28); }
/* 状态胶囊存在时，标题（及「已读」小标）向右让位，避免叠字 */
.kanban-card .kc-state ~ .kc-title,
.kanban-card .kc-title:first-child { padding-right: 46px; }
.kanban-card.pm-read > .pm-read-tag + .kc-title { padding-right: 46px; }

/* ⑥ v446 未读提示：整卡外发光 + 呼吸，离开左侧竖条位置
   v499c: 首轮峰值 2px/.90 过实（视觉像报错红框、且压住列头状态色），
          收敛为「细环 + 柔光」——环宽峰 1.5px、透明度峰 .62，
          再叠一层向外扩散的柔光，保持 1.6s 节奏与侧栏角标同步。 */
@keyframes kbUnreadGlow {
  0%, 100% {
    box-shadow: 0 0 0 1px rgba(244, 63, 94, .28),
                0 2px 8px rgba(244, 63, 94, .08);
  }
  50% {
    box-shadow: 0 0 0 1.5px rgba(244, 63, 94, .62),
                0 3px 12px rgba(244, 63, 94, .20);
  }
}
/* 看板卡覆写 v446 的 pmPulse（它画在左侧 3px，与状态竖条打架） */
.kanban-card.pm-unread {
  animation: kbUnreadGlow 1.6s ease-in-out infinite;
}
/* 未读时标题保持正常色（整卡已发光，不必再压暗） */
.kanban-col-todo .kanban-card.pm-unread .kc-title,
.kanban-col-inprogress .kanban-card.pm-unread .kc-title {
  color: var(--gray-800);
}

/* 暗主题下未读发光强度收敛（暗底上红晕更刺眼） */
html[data-theme='dark'] .kanban-card.pm-unread {
  animation: kbUnreadGlowDark 1.6s ease-in-out infinite;
}
@keyframes kbUnreadGlowDark {
  0%, 100% { box-shadow: 0 0 0 1px rgba(248, 113, 113, .35), 0 2px 8px rgba(248, 113, 113, .10); }
  50%      { box-shadow: 0 0 0 2px rgba(248, 113, 113, .70), 0 4px 14px rgba(248, 113, 113, .22); }
}

/* ⑦ 悬停：外发光动画与 hover 阴影会互相覆盖，用更高特异性给出 hover 态 */
.kanban-column .kanban-card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--gray-300);
  transform: translateX(1px);
}

/* ==========================================================================
 * v499e 特写复查后的终修
 * --------------------------------------------------------------------------
 * 复查手段：有头模式拍单卡特写（_v499_headful_after_card.png），而非只看整页。
 * 发现：① 待办列状态线 #94a3b8 在白卡上对比仅 ≈2.4:1 → 线语义传达失败；
 *       ② 未读红点孤立悬空、与状态胶囊间距过大，视觉像误触装饰；
 *       ③ 未读红环 + 优先级实心圆点两个红色/蓝色块相邻，画面偏乱。
 * ========================================================================== */

/* ③ 未读卡：优先级圆点改「空心描边环」，与红环拉开形态差（实心 vs 空心） */
.kanban-card.pm-unread .kc-prio {
  background: transparent !important;
  box-shadow: inset 0 0 0 2px currentColor !important;
}
.kanban-card.pm-unread .kc-prio.p-critical { color: var(--danger); }
.kanban-card.pm-unread .kc-prio.p-high     { color: var(--warning); }
.kanban-card.pm-unread .kc-prio.p-medium   { color: var(--info); }
.kanban-card.pm-unread .kc-prio.p-low      { color: var(--gray-400); }

/* ④ 已读卡：状态胶囊/优先级圆点降透明度，让「已读」的灰更统一，
      但保持胶囊文字可读（不降到无效对比度） */
.kanban-card.pm-read .kc-state { opacity: .72; }
.kanban-card.pm-read .kc-prio  { opacity: .55; }

/* ⑤ 待办列卡片在「已读」态下，状态线与列头呼应（避免整列发虚） */
.kanban-col-todo .kanban-card.pm-read { border-left-color: var(--kb-todo-line); }

/* v502: 财务「预付款列表」副行统一样式
   对齐「项目管理 → 项目列表」的字级体系（主文本 14px 继承 / 次要 12px / 副行 11px），
   消除原先 10/11/12/13px 四级混用。色值走主题变量，暗色自动适配。 */
.adv-sub {
  font-size: 11px;
  color: var(--text-tertiary);
  line-height: 1.5;
  margin-top: 2px;
}

/* v503: 表格文字层单一真源 —— 整站同类列表口径统一
   .txt-key 首列主标识（项目名 / 合同名 / 对手方 / 卡片标题）——对齐「项目管理 → 项目列表」范式：
            继承表格 14px，600 字重 + gray-800；不写显式字号，随容器自适应，暗色主题自动适配。
   .txt-num 数值列（金额 / 预算 / 净额）——对齐 v502「预付款列表」金额口径：
            13px + 600 + 右对齐，并启用等宽数字（tabular-nums）让多位金额按位对齐。
   ⚠ 二者只承载「文字层」语义，不设 padding/背景，避免影响 .table.ops 的 sticky 操作列。 */
.txt-key {
  font-weight: 600;
  color: var(--gray-800);
}
.txt-num {
  font-size: 13px;
  font-weight: 600;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   v505: 新建 / 编辑弹窗「一页展示全部」
   --------------------------------------------------------------------------
   问题（改前实测，视口 1440x900，.modal-body 可视高 676px）：
     22 个表单弹窗里 15 个超出一屏、必须滚动才能看全或看到底部按钮 ——
     projects 新建溢出 741px、aftersale 615px、acceptance 548px、预付款 514px、发票 387px。
   成因两条：
     ① 弹窗默认宽 560px（.modal 的 max-width），而多数表单有 10~18 个字段，
        每行只排得下 2 个 → 行数堆到 12~15 行；
     ② 垂直留白偏大：.form-group 下边距 18px、.modal-body 内边距 24px、
        控件 padding 10px（行高 90px），段头 / 说明条各行再吃掉 18~47px。
   对策两条：
     ① 表单弹窗加宽到 1040px，并把留白整体收紧（行高 90 → 72px 量级）；
     ② 由 js/app.js 的 _compactForm() 把「窄字段」摊平进 .form-flow，
        一行自动容纳 3~4 个 → 行数直接腰斩。
   安全性：纯展示层。元素是「移动」不是重建，id 与已绑定事件全部保留；
           .form-lg 只在表单弹窗上加，表格类 / 预览类弹窗不受影响。
   ========================================================================== */
.modal.form-lg { width: min(94vw, 1120px); max-width: 1120px; max-height: calc(100vh - 16px); }
.modal.form-lg .modal-header { padding: 11px 20px; }
.modal.form-lg .modal-header h3 { font-size: 15px; }
.modal.form-lg .modal-body { padding: 12px 18px; }
.modal.form-lg .modal-footer { padding: 9px 20px; }
.modal.form-lg .form-group { margin-bottom: 8px; }
.modal.form-lg .form-label { margin-bottom: 2px; font-size: 13px; }
.modal.form-lg .form-input,
.modal.form-lg .form-select { padding: 6px 10px; }
.modal.form-lg .form-textarea { min-height: 48px; }
.modal.form-lg .pf-sec { margin: 0 0 2px; }
.modal.form-lg .pf-tip { margin-bottom: 4px; padding: 3px 9px; }
.modal.form-lg .form-hint { font-size: 11px; }
@media (max-width: 900px) {
  .modal.form-lg { width: 96vw; max-width: 96vw; }
}
/* 窄字段流式行：一行按可用宽度自动容纳 4~5 个（每个基准 200px），末行自动铺满。
   .ff-half 给「多行文本」用——不挤 1/4 列，但两个可以并排，避免 3 条备注各占一整行。 */
.form-flow {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 12px;
  margin-bottom: 4px;
}
.form-flow > .form-group {
  flex: 1 1 200px;
  min-width: 0;
  margin-bottom: 0;
}
/* ==========================================================================
   v506: 表单弹窗排布 ——「半宽块」从窄字段流里摘出来，自成一组
   --------------------------------------------------------------------------
   动机（v505 实测 _diag506_struct.txt，弹窗宽 1120 / 可用 1084）：
     行3 名称 207 | 编码 207 | 分类 207 | 描述 428   ← 描述被挤到右上角一小块
     行6 负责人 205 | 项目总预算 428 | 进度 428      ← 同一行唯一的窄字段只剩 205
     行7 项目成员 205 | 采购审批 428 | 访问范围 428  ← 访问范围被顶到最右下角
   病因不是「行数」，而是 .ff-half 用的是 flex:0 1 40%（grow 0）—— 它不参与均分，
   于是同一行的窄字段被压回 200px 基准，整行宽度参差（205 / 428 / 428）。
   --------------------------------------------------------------------------
   v506 规则：半宽块不与窄字段混排，自成一组 —— 落单→整行、两个→各半、
   三个及以上→各 1/3。这样「描述/合作伙伴」自然落成整行，同类半宽字段（如
   负责人＋成员＋采购审批）自动等宽并排。
   注：窄字段仍跨 .form-row 归并（这条不改）。第一版预演实测「.form-row 整块保留」
   会让 7 个弹窗溢出（projects.new +273 / aftersale +223 / finance.advance +134 …），
   因为跨组归并一旦消失，每个 form-row 各占一行、整体变高。
   ========================================================================== */
.form-flow > .form-group.ff-half { flex: 1 1 calc(50% - 6px); }
.form-flow > .form-group.ff-third { flex: 1 1 calc(33.333% - 8px); }
.form-flow > .form-group.ff-full { flex: 1 1 100%; }
/* 段头（.pf-sec）也在流式行内，占满一行、不留额外边距（间距交给 .form-flow 的 row-gap） */
.form-flow > .pf-sec { flex: 1 1 100%; margin: 0; }

/* v506: 进度只读展示改为进度条（原先是一个灰底 readonly 数字输入框，
   在「团队与资源」段里既像可编辑字段又与其他只读展示不一致）。
   真值仍由隐藏域 #pf_progress 承载 —— saveProject 照常 parseInt 读取。 */
.pf-prog-row { display: flex; align-items: center; gap: 10px; margin-top: 2px; }
.pf-prog-bar { flex: 1; height: 8px; border-radius: 999px; background: var(--gray-100); overflow: hidden; }
.pf-prog-bar > i { display: block; height: 100%; border-radius: 999px; background: var(--primary); }
.pf-prog-num { min-width: 42px; text-align: right; font-size: 13px; font-weight: 600;
  color: var(--gray-800); font-family: var(--mono); font-variant-numeric: tabular-nums; }
/* 项目描述整行铺满后，min-height 收到 52px（约 2 行）—— 比半宽时代的 66px 更省高度 */
.modal.form-lg .form-textarea.pf-desc { min-height: 52px; }

/* v506: 修 v505 遗留的 specificity 冲突 —— .modal.form-lg .form-group{margin-bottom:8px}
   是 (0,3,0)，压过了 .form-flow > .form-group{margin-bottom:0} 的 (0,2,0)，
   于是流内每个字段都多带 8px 底边距（13 行 ≈ 96px 的隐性浪费）。
   这里按「流内 0 / 流外 8」的原始意图显式修正。 */
.modal.form-lg .form-flow > .form-group { margin-bottom: 0; }
/* 项目描述整行后：控制高度（原 padding:10px 12px + 2 行内容 ≈ 65px，min-height 压不下去） */
.modal.form-lg .form-textarea.pf-desc { padding: 6px 10px; height: 50px; min-height: 0; }

/* ==========================================================================
   v508: 弹窗头（表单头）整站统一美化
   --------------------------------------------------------------------------
   诉求（用户截图）：新建项目等表单弹窗头部是一条「纯白 + 一条浅灰细线」的裸头，
   与站内其它已美化区域（卡片头 / 工具栏 / 列表文字层）不在同一完成度上。

   做法（纯 CSS，零 JS 改动 —— #modalHeader 的 innerHTML 由 app.js 每次 open 重建，
   所以这里只管样式，不依赖任何新增节点）：
     ① 品牌淡渐变底 + 品牌色 3px 左竖条（inset box-shadow：不占布局、不撑高）
     ② 底部边线由 --border-light(#f0f1f3) 换为品牌淡色 #e4eafc
     ③ 头部顶角圆角与弹窗一致（.modal 为 --radius-lg=14px；★不补这行会「方角压圆角」）
     ④ 标题 --gray-800 → --gray-900 + 0.3px 字距
     ⑤ 关闭按钮 hover 由中性灰改危险色（Windows 惯例：右上角红底关闭）

   两处必须显式同步（否则出现「居中标题却带左竖条」/ 全屏方角错配）：
     · .modal-confirm —— 居中极简版式 → 去渐变底 / 去左竖条 / 去头部圆角
     · :fullscreen / .maximized —— 弹窗圆角已归零 → 头部圆角同步归零

   高度：只改背景 / 阴影 / 颜色 / 圆角，padding 与字号一律不动
        → 三类弹窗头部高度与改前逐项一致（_probe_v508_header.js 已逐项断言），
          v505 / v506「一屏展示全部」的口径不受影响。
   ========================================================================== */
.modal-header {
  background: linear-gradient(180deg, #f4f7ff 0%, #e8eefe 100%);
  border-bottom: 1px solid #d9e2fb;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: inset 3px 0 0 0 var(--primary);
}
.modal-header h3 { color: var(--gray-900); letter-spacing: 0.3px; }
.modal-close:hover { background: var(--danger-bg); color: var(--danger); }
/* 确认弹窗：居中版式不吃左竖条 / 渐变底 */
.modal-confirm .modal-header { background: none; box-shadow: none; border-radius: 0; }
/* 全屏 / 最大化：弹窗圆角已归零，头部圆角同步归零 */
.modal.full:fullscreen .modal-header,
.modal.full:-webkit-full-screen .modal-header,
.modal.maximized .modal-header { border-radius: 0; }
/* ==========================================================================
   v510: 全站附件上传区统一（样式单一真源）
   --------------------------------------------------------------------------
   诉求（用户截图）：整站附件区「样式格式统一 + 上传入口明显」。
   改前全站并存 4 种范式，同一个「上传附件」在 18 个弹窗里长得各不相同：
     ① btn-ghost btn-sm「📎 选择文件」幽灵小按钮（11 处）—— 截图即此类：
        透明底 + 灰字 + 无边框，和正文说明文字几乎同色，用户根本注意不到这是入口
     ② ct-upload-row + btn-secondary btn-sm「📎 上传 XX 文件」（2 处）
     ③ task-form-section 盒子 / 手写虚线框 + btn-secondary btn-sm「📎 添加附件」（4 处）
     ④ docs.js 的 btn-secondary（漏了 btn-sm）+ 提示文案写在按钮右侧
   提示文案的位置也四散：标题 span 里 / label span 里 / 按钮右侧 span / 按钮下方 div。

   统一后的单一真源（HTML 由 app.js PMO.App.utils.attBox() 生成，全站 18 处同源）：
     .att-box         虚线拖放框（悬停 / 拖入 → 边框转品牌色 + 品牌淡底 + 焦点环）
     .att-box-ico     左侧圆角图标块
     .att-box-txt/.t/.h  框内主文案 + 规格提示（提示一律收到框内，不再散落在 label）
     .att-btn         主色实心按钮「上传附件」—— 明显度：幽灵按钮 → 主色实心 + 阴影
     .att-list        附件列表容器（统一上间距；缩略图网格与行条列表共用）
     .att-count       「已上传 N / 20 个」计数行
     .att-empty       统一空态
   拖放：app.js utils.initAttachDrop() 事件委托，只有 .att-box 拦截 dragover，
   其余区域浏览器默认行为（打开文件）不变。
   ========================================================================== */
:root {
  --att-border: #c9d5f7;
  --att-bg: #f8faff;
  --att-bg-hover: #eef2ff;
  --att-ico: #4f6bed;
}
html[data-theme='dark'] {
  --att-border: #35406b;
  --att-bg: #1d2333;
  --att-bg-hover: #232c47;
  --att-ico: #8598f5;
}
.att-box {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 13px 16px;
  border: 1.5px dashed var(--att-border);
  border-radius: var(--radius);
  background: var(--att-bg);
  min-width: 0;
  transition: border-color .18s ease, background .18s ease, box-shadow .18s ease;
}
.att-box:hover { border-color: var(--primary); background: var(--att-bg-hover); }
.att-box.is-dragover {
  border-color: var(--primary);
  background: var(--primary-bg);
  box-shadow: 0 0 0 3px rgba(79, 107, 237, .16);
}
.att-box-ico {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 19px;
  line-height: 1;
  color: var(--att-ico);
  background: var(--card-bg);
  border: 1px solid var(--att-border);
}
.att-box-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.att-box-t { font-size: 13px; font-weight: 600; color: var(--gray-800); }
.att-box-h { font-size: 12px; line-height: 1.5; color: var(--gray-500); overflow-wrap: anywhere; }
.att-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 34px;
  padding: 0 18px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .3px;
  line-height: 1;
  border: 1px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
  color: #fff;
  background: linear-gradient(135deg, #4f6bed 0%, #5b7bef 100%);
  box-shadow: 0 2px 8px rgba(79, 107, 237, .30);
  transition: all .18s ease;
}
.att-btn:hover {
  background: linear-gradient(135deg, #3e5cdb 0%, #4a6adb 100%);
  box-shadow: 0 6px 16px rgba(79, 107, 237, .38);
  transform: translateY(-1px);
}
.att-btn:active { transform: translateY(0); }
.att-btn svg { width: 14px; height: 14px; flex: none; }
.att-list { margin-top: 10px; min-width: 0; }
.att-list > .pay-voucher-grid { margin-top: 0; }
.att-count { font-size: 12px; color: var(--gray-400); margin-top: 6px; }
.att-empty { font-size: 12px; color: var(--gray-400); padding: 4px 0; }
@media (max-width: 640px) {
  .att-box { flex-wrap: wrap; padding: 12px; gap: 10px; }
  .att-box-ico { width: 34px; height: 34px; font-size: 17px; }
  .att-box-txt { flex: 1 1 130px; }
  .att-btn { flex: 1 1 100%; }
}


/* ============================================================
   v521: 财务管理「支付流程」分页视图切换器美化
   ------------------------------------------------------------
   诉求：美化该行分页展示（合同 / 付款 / 发票 / 记录 / 收支 / 回款 / 借贷），大方直观明了。
   红线：.filter-chip 是全站基类（13 个页面、73 处渲染点），故本轮所有规则一律锚定
        .page-toolbar .fin-view-tabs（作用域类由 finance.js renderViewSwitcher 单点挂载），
        其余 72 处 filter-chip 外观零变化。
   结构零改动：data-fview / data-pm-grp（v453 角标）/ fc-dot / fc-count / pm-chip-count
        全部保留，仅追加一个分组分隔元素 .fin-tabs-sep。

   三段式：
   ① 槽 trough —— 浅灰内凹底 + 1px 描边 + 圆角 14 + 内边距 5px，把 7 枚胶囊收成
      「一个整体控件」，一眼看出是一组互斥视图；
   ② 胶囊 —— 未激活透明底、去边框去阴影（槽感）；hover 抬成白卡并转该视图主色；
      激活 = 视图主色实心 + 白字 + 同色光晕投影 + fc-pop 弹入；
   ③ 计数胶囊 —— 随视图着色（浅底同色深字），激活态反转为白底彩字，
      让「数字」始终是第一眼信息。
   ============================================================ */
.page-toolbar .fin-view-tabs {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--gray-50);
  box-shadow: inset 0 1px 2px rgba(15, 23, 42, 0.04);
}

/* ② 胶囊本体（覆盖基类：槽内不再各自带边框与阴影） */
.page-toolbar .fin-view-tabs .filter-chip {
  height: 40px;
  padding: 0 18px 0 16px;
  gap: 9px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  box-shadow: none;
  color: var(--text-secondary);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.3px;
}
.page-toolbar .fin-view-tabs .filter-chip:hover {
  background: var(--card-bg);
  border-color: var(--fc-border);
  color: var(--fc-color);
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.10);
  transform: none;
}
.page-toolbar .fin-view-tabs .filter-chip:active {
  transform: none;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.12);
}
.page-toolbar .fin-view-tabs .filter-chip.active {
  background: var(--fc-dot);
  border-color: var(--fc-dot);
  color: #fff;
  font-weight: 700;
  box-shadow: 0 4px 14px -2px var(--fc-dot), 0 1px 2px rgba(15, 23, 42, 0.10);
  animation: fc-pop var(--dur-slow) var(--ease-spring);
}
.page-toolbar .fin-view-tabs .filter-chip.active .fc-dot {
  background: #fff;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.45);
}

/* ③ 计数胶囊：未激活随视图着色，激活反转为白底彩字 */
.page-toolbar .fin-view-tabs .filter-chip .fc-count {
  min-width: 24px;
  height: 22px;
  padding: 0 8px;
  font-size: 12.5px;
  font-weight: 700;
  background: var(--fc-count-bg);
  color: var(--fc-count-color);
}
.page-toolbar .fin-view-tabs .filter-chip:hover .fc-count {
  background: var(--fc-count-bg);
  color: var(--fc-count-color);
}
.page-toolbar .fin-view-tabs .filter-chip.active .fc-count {
  background: #fff;
  color: var(--fc-dot);
}

/* ④ 分组细分隔：支付流程 4 步 ｜ 台账类视图 */
.page-toolbar .fin-view-tabs .fin-tabs-sep {
  flex: 0 0 auto;
  width: 1px;
  height: 24px;
  margin: 0 3px;
  background: var(--border);
}

/* ⑤ 七色识别：沿用 contracts 紫 / advance 琥珀 / tickets 青 / records 靛蓝，
   并为 payments / collections / loans 补上主色（原为灰色默认值） */
.page-toolbar .fin-view-tabs .filter-chip[data-fview="contracts"]   { --fc-dot: #a855f7; --fc-color: #6d28d9; --fc-border: #e9d5ff; --fc-count-bg: #f3e8ff; --fc-count-color: #6d28d9; }
.page-toolbar .fin-view-tabs .filter-chip[data-fview="advance"]     { --fc-dot: #f59e0b; --fc-color: #92400e; --fc-border: #fde68a; --fc-count-bg: #fef3c7; --fc-count-color: #92400e; }
.page-toolbar .fin-view-tabs .filter-chip[data-fview="tickets"]     { --fc-dot: #14b8a6; --fc-color: #0f766e; --fc-border: #99f6e4; --fc-count-bg: #ccfbf1; --fc-count-color: #0f766e; }
.page-toolbar .fin-view-tabs .filter-chip[data-fview="payments"]    { --fc-dot: #3b82f6; --fc-color: #1d4ed8; --fc-border: #bfdbfe; --fc-count-bg: #dbeafe; --fc-count-color: #1d4ed8; }
.page-toolbar .fin-view-tabs .filter-chip[data-fview="records"]     { --fc-dot: #4f6bed; --fc-color: #4338ca; --fc-border: #c7d2fe; --fc-count-bg: #e0e7ff; --fc-count-color: #4338ca; }
.page-toolbar .fin-view-tabs .filter-chip[data-fview="collections"] { --fc-dot: #10b981; --fc-color: #047857; --fc-border: #a7f3d0; --fc-count-bg: #d1fae5; --fc-count-color: #047857; }
.page-toolbar .fin-view-tabs .filter-chip[data-fview="loans"]       { --fc-dot: #f43f5e; --fc-color: #be123c; --fc-border: #fecdd3; --fc-count-bg: #ffe4e6; --fc-count-color: #be123c; }

/* ⑥ 暗色主题：槽改半透明；计数胶囊统一半透明白底（浅彩底在暗底上会过亮） */
html[data-theme='dark'] .page-toolbar .fin-view-tabs {
  background: rgba(255, 255, 255, 0.04);
  box-shadow: none;
}
html[data-theme='dark'] .page-toolbar .fin-view-tabs .filter-chip:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: transparent;
}
html[data-theme='dark'] .page-toolbar .fin-view-tabs .filter-chip[data-fview] {
  --fc-count-bg: rgba(255, 255, 255, 0.10);
  --fc-count-color: #e5e7eb;
}
html[data-theme='dark'] .page-toolbar .fin-view-tabs .filter-chip.active .fc-count {
  background: rgba(255, 255, 255, 0.92);
  color: #111827;
}

/* ⑦ 移动端：槽满宽、胶囊平分剩余宽度、分组分隔隐藏（换行后位置会错乱） */
@media (max-width: 768px) {
  .page-toolbar .fin-view-tabs {
    width: 100%;
    gap: 4px;
    padding: 4px;
    border-radius: 12px;
  }
  .page-toolbar .fin-view-tabs .filter-chip {
    flex: 1 1 auto;
    justify-content: center;
    height: 40px;
    padding: 0 12px;
    gap: 7px;
    font-size: 13px;
  }
  .page-toolbar .fin-view-tabs .fin-tabs-sep { display: none; }
}

/* ============================================================
   v522: 财务管理「列表卡片」统一美化
   覆盖 8 张表：合同 / 付款 / 发票 / 记录 / 收支 / 回款 / 借贷 / 分项目统计
   诉求：截图红框「合同列表」—— 简约、大气、直观。
   ★ 范围铁律：全部规则锚定新增作用域类 .fin-list（只挂在 finance.js 的 8 个列表卡片上），
     .card / .card-header / .card-title / .table / .badge / .btn-ghost 等全站基类零改动。
   ★ 不动既有语义：tr.pm-read（v446 已读置灰）/ tr.pm-unread（v446 未读呼吸 + 红左条）/
     .pm-read-tag / .ct-attach-badge / .table.ops 末列 sticky（仅 <=768px）全部保留。
   ============================================================ */

/* (1) 卡片：圆角 14px 与「支付流程」切换器槽呼应；一层极轻投影让它从页面上浮起来 */
.fin-list {
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 12px 32px -24px rgba(15, 23, 42, 0.30);
}

/* (2) 列表头：主色小竖条 + 加粗标题 —— 一眼看清这是哪张表，与上方切换器同色呼应 */
.fin-list > .card-header { padding: 14px 18px; }
.fin-list > .card-header .card-title {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 15px;
  font-weight: 700;
  color: var(--gray-800);
  letter-spacing: 0.2px;
}
.fin-list > .card-header .card-title::before {
  content: "";
  flex: none;
  width: 3px;
  height: 14px;
  border-radius: 2px;
  background: var(--primary);
}

/* (3) 表头：主动「退后一格」——更小 / 更重 / 更淡 / 字距拉开，数据行自然前进。
       表头 14px 与数据行同字号是原设计的层次问题：二者只靠颜色区分，远看糊成一片。 */
.fin-list .table thead th {
  padding: 11px 16px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.7px;
  color: var(--text-tertiary);
  background: var(--gray-50);
  border-bottom: 1px solid var(--border);
}

/* (4) 数据行：竖向内边距 14 -> 16px，给内容留出呼吸（大气） */
.fin-list .table tbody td { padding: 16px; }

/* (5) 主列（第一列 = 名称）：全表最重的一处，视线的第一落点 */
.fin-list .table tbody td:first-child .txt-key {
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: 0.1px;
  color: var(--gray-800);
}

/* (6) 金额列：与主列同口径加权（直观 —— 财务页的钱必须一眼看到） */
.fin-list .table td.txt-num { font-size: 14px; font-weight: 700; }

/* (7) 状态胶囊：8 张表统一 24px 定高，比原「13px 字 + 4px 内边距」更利落 */
.fin-list .table .badge {
  height: 24px;
  padding: 0 11px;
  font-size: 12.5px;
  font-weight: 600;
}

/* (8) 操作列：把「详情 / 编辑 / 删除」从隐形文字变成看得见、点得着的按钮（直观） */
.fin-list .table.ops td:last-child .btn-ghost {
  height: 28px;
  padding: 0 11px;
  font-size: 12.5px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card-bg);
  color: var(--text-secondary);
  box-shadow: none;
}
.fin-list .table.ops td:last-child .btn-ghost:hover {
  border-color: var(--primary);
  background: var(--primary-bg);
  color: var(--primary);
  transform: none;
  box-shadow: none;
}

/* (9) 悬停：已读行被 v446 用 inset 阴影涂抹整格底色（inset 阴影画在 background 之上），
       .table tbody tr:hover 的灰底对它无效 -> 单独提亮一档，保证每行悬停都看得见 */
.fin-list .table tbody tr.pm-read:hover > td {
  box-shadow: inset 0 0 0 999px rgba(148, 163, 184, 0.18);
}

/* (10) 暗色主题：表头 --gray-50(#1c222e) 与卡片 --card-bg(#1a1f2a) 几乎同色、
        区分不出来 -> 改用半透明白提亮；卡片投影在暗底上发脏 -> 去掉 */
html[data-theme='dark'] .fin-list {
  box-shadow: none;
}
html[data-theme='dark'] .fin-list .table thead th {
  background: rgba(255, 255, 255, 0.035);
  color: var(--text-secondary);
}
html[data-theme='dark'] .fin-list .table.ops td:last-child .btn-ghost {
  background: transparent;
}
html[data-theme='dark'] .fin-list .table tbody tr.pm-read:hover > td {
  box-shadow: inset 0 0 0 999px rgba(148, 163, 184, 0.14);
}

/* (11) 移动端（<=768px）：行高回落，避免列宽被行内边距吃光后过早横向滚动 */
@media (max-width: 768px) {
  .fin-list > .card-header { padding: 12px 14px; }
  .fin-list .table thead th { padding: 10px 12px; letter-spacing: 0.4px; }
  .fin-list .table tbody td { padding: 13px 12px; }
  .fin-list .table tbody td:first-child .txt-key { font-size: 14px; }
}

/* ============================================================
   v523: 智能提醒「待办条目区」美化 —— 直观明了大气
   作用域（均为本轮新增类，改前全站 0 命中）：
     .rem-modal                    智能提醒弹窗壳
     .rem-head/.rem-title/.rem-sub 弹窗头部三段
     .rem-body/.rem-foot/.rem-hint/.rem-ok  行区与底部
     .rem-todo                     待办条目行（含 .rem-ico/.rem-txt/.rem-go）
     .bd-meta                      文案括注（badges.js paren() 单一真源产出）
   全站基类 .dash-act-row / .modal / .btn-ghost / .card 零改动。
   ★ .rem-todo 只挂在 dashboard.js remRow()——弹窗与仪表盘「智能提醒」卡
     共用同一行渲染，两处一致受益；成员动态行（.dash-act-today）不受影响。
   ============================================================ */

/* ① 弹窗壳：品牌淡蓝渐变头部 + 主色竖条标题（与 v508 弹窗头 / v522 卡片标题同款语言） */
.rem-modal .rem-head {
  padding: 16px 20px 13px;
  background: linear-gradient(135deg, var(--primary-bg) 0%, transparent 72%);
  border-bottom: 1px solid var(--border);
}
.rem-modal .rem-title {
  display: flex; align-items: center; gap: 9px;
  font-size: 16px; font-weight: 700; color: var(--gray-800); letter-spacing: 0.2px;
}
.rem-modal .rem-title::before {
  content: ""; flex: none; width: 3px; height: 15px;
  border-radius: 2px; background: var(--primary);
}
.rem-modal .rem-sub { font-size: 12px; color: var(--text-tertiary); margin: 6px 0 0 12px; }
.rem-modal .rem-sub .rem-n { font-size: 13px; }
.rem-modal .rem-body { padding: 6px 16px 4px; max-height: 50vh; overflow-y: auto; }
.rem-modal .rem-foot {
  padding: 12px 20px 15px; display: flex; align-items: center;
  justify-content: flex-end; gap: 12px;
}
.rem-modal .rem-hint { font-size: 12px; color: var(--text-tertiary); }
.rem-modal .rem-ok {
  height: 30px; padding: 0 16px;
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--card-bg); color: var(--text-secondary); font-weight: 600;
}
.rem-modal .rem-ok:hover { border-color: var(--primary); background: var(--primary-bg); color: var(--primary); }

/* ② 条目行：图标立体化 + 关键量加权 + 动作按钮化 */
.rem-todo { border-radius: 10px; }
.rem-todo .rem-ico { box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.06); }
.rem-todo .rem-txt b { color: var(--primary); font-weight: 700; font-size: 1.06em; letter-spacing: 0.2px; }
.rem-todo .rem-go {
  flex: none; height: 28px; padding: 0 11px;
  display: inline-flex; align-items: center; white-space: nowrap;
  font-size: 12.5px; font-weight: 600; color: var(--primary);
  border: 1px solid var(--border); border-radius: 8px; background: var(--card-bg);
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.rem-todo:hover .rem-go { border-color: var(--primary); background: var(--primary); color: #fff; }

/* ③ 括注退后：次要信息让位正文（badges.js paren() 全站统一产出） */
.bd-meta { color: var(--text-tertiary); font-weight: 400; font-size: 0.95em; }

/* ★ 括注整块不拆行：行宽不足时「（我负责 · #P003）」整体另起一行，
   避免出现「（我负责 ·」/「#P9001）」跨行断裂（作用域限条目行内） */
.rem-todo .bd-meta { white-space: nowrap; }

/* ④ 暗色适配：头部渐变改主色半透明、图标描边提亮、悬停底加深、按钮与动作去白底 */
html[data-theme='dark'] .rem-modal .rem-head {
  background: linear-gradient(135deg, rgba(108, 131, 242, 0.14) 0%, transparent 72%);
}
html[data-theme='dark'] .rem-todo .rem-ico { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07); }
html[data-theme='dark'] .rem-todo:hover { background: rgba(108, 131, 242, 0.16); }
html[data-theme='dark'] .rem-modal .rem-ok { background: transparent; }
html[data-theme='dark'] .rem-todo .rem-go { background: transparent; }

/* ⑤ 窄屏：收敛内边距，动作列不挤正文 */
@media (max-width: 768px) {
  .rem-modal .rem-head { padding: 14px 16px 11px; }
  .rem-modal .rem-body { padding: 4px 12px 2px; }
  .rem-modal .rem-foot { padding: 10px 16px 13px; }
  .rem-todo .rem-go { padding: 0 9px; font-size: 12px; }
}

/* ============================================================
   v524：整站视觉升级 —— 边界感 · 可读性 · 呼吸感
   ------------------------------------------------------------
   用户诉求：美化整站，直观大气、视觉舒服（附统计卡截图）。
   全站 15 个页面共用同一套公共层，本段只升级公共层 —— 一处改、全站受益。
   ① 边界感：卡片由「零投影 + 1.21:1 淡边框」升级为「柔和双层投影 + 可辨边界」
   ② 可读性：辅助文字 --text-tertiary 由 2.54:1 提到 3.95:1；语义小字改用 4.5:1 以上色
   ③ 呼吸感：统计卡内距 16 → 18/22，数值字阶上限 22 → 26，标签与趋势行距放开
   ④ 细节：空状态分层、侧栏与顶栏辅助文字提清晰度、选区品牌化
   ★ 不改任何 DOM 结构、JS 逻辑与类名契约；暗色主题逐条同步。
   ============================================================ */

/* ---------- ① 设计令牌：文字可见度 / 边界清晰度 / 卡片投影 ---------- */
:root {
  --text-tertiary: #77818f;      /* v524: 原 #9ca3af 白底对比仅 2.54:1 → 3.95:1 */
  --border: #e3e6ec;             /* v524: 原 #e8eaed 白底对比仅 1.21:1 → 1.30:1（边界可辨） */
  --border-light: #eff1f4;
  --shadow-card: 0 1px 2px rgba(16, 24, 40, 0.04), 0 4px 14px -8px rgba(16, 24, 40, 0.10);
  --shadow-card-hover: 0 2px 6px rgba(16, 24, 40, 0.06), 0 14px 30px -12px rgba(16, 24, 40, 0.18);
}
html[data-theme='dark'] {
  --text-tertiary: #7e8a9e;      /* v524: 原 #626d80 暗底对比仅 3.16:1 → 4.73:1 */
  --border: #2f3846;
  --border-light: #262e3b;
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.30), 0 4px 14px -8px rgba(0, 0, 0, 0.45);
  --shadow-card-hover: 0 2px 6px rgba(0, 0, 0, 0.36), 0 14px 30px -12px rgba(0, 0, 0, 0.55);
}

/* ---------- ② 卡片：全站 .card 统一边界与柔和投影 ---------- */
.card {
  border-color: var(--border);
  box-shadow: var(--shadow-card);
}

/* ---------- ③ 统计卡（截图所指，8 个页面共用同一渲染点）----------
   去透明渐变底（真凶：linear-gradient 下半部转透明 → 透出页面灰底，卡片下沿发脏）
   → 纯卡底 + 1px 边界 + 投影；内距放宽留呼吸；标签/趋势提色提字阶。 */
.stat-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 18px 18px 18px 22px;
  gap: 14px;
  box-shadow: var(--shadow-card);
}
.stat-card:hover { box-shadow: var(--shadow-card-hover); }
.stat-card .stat-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  margin-bottom: 5px;
  letter-spacing: 0.3px;
}
.stat-card .stat-value {
  font-size: clamp(20px, 1.9vw, 26px);
  letter-spacing: -0.2px;
}
.stat-card .stat-trend {
  font-size: 12.5px;
  margin-top: 6px;
  color: var(--text-secondary);
}
/* 语义小字原用 --success 3.05:1 / --danger 3.76:1，小字号下不达标 → 换 4.5:1 以上同色系 */
.stat-card .stat-trend.up { color: #047857; }
.stat-card .stat-trend.down { color: #b91c1c; }
.stat-card .stat-icon { width: 42px; height: 42px; }
html[data-theme='dark'] .stat-card .stat-trend.up { color: #34d399; }
html[data-theme='dark'] .stat-card .stat-trend.down { color: #fca5a5; }

/* ---------- ④ 空状态：从「一片灰淡」到「有层次」 ---------- */
.empty-state .es-icon { color: var(--gray-400); }
.empty-state .es-title { font-weight: 600; color: var(--gray-600); }
.empty-state .es-desc { color: var(--text-secondary); }
.no-data { color: var(--text-secondary); }
html[data-theme='dark'] .empty-state .es-icon { color: var(--gray-500); }
html[data-theme='dark'] .empty-state .es-title { color: var(--gray-700); }

/* ---------- ⑤ 侧栏 / 顶栏：分组标题、角色、版本号、快捷键提示提清晰度 ---------- */
.nav-group-label { color: var(--text-secondary); }
.user-role { color: var(--text-secondary); }
.search-kbd { color: var(--text-secondary); }

/* ---------- ⑥ 页面标题：宽屏提到 22px（大气感的第一落点）
   ★ 必须限定 min-width，否则会盖掉 768px / 480px 两个窄屏断点 */
@media (min-width: 769px) {
  .page-title { font-size: 22px; letter-spacing: -0.2px; }
}

/* ---------- ⑦ 选区：品牌色化 ---------- */
::selection { background: rgba(79, 107, 237, 0.18); }
html[data-theme='dark'] ::selection { background: rgba(108, 131, 242, 0.32); }

/* ---------- v524 补：语义色小字可读性 ----------
   #f59e0b 在浅黄底（--warning-bg）上仅 2.07:1，作为 11~12px 文字不可读。
   文字场景统一改用项目既有的深琥珀 #92400e（6.83:1，与 .filter-chip 文字色口径一致）；
   暗色下深琥珀对比反而不足，改用亮琥珀。 */
.pay-flow-gate { color: #92400e; }
.dash-act-row.dash-act-today .dash-act-date { color: #92400e; }
html[data-theme='dark'] .pay-flow-gate { color: #fbbf24; }
html[data-theme='dark'] .dash-act-row.dash-act-today .dash-act-date { color: #fcd34d; }

/* ---------- v525: 全站统计数字「升序动画」配套（JS 见 js/app.js utils.initStatNumberAnim） ----------
   ① 数字容器统一等宽数字（tabular-nums）：从 0 滚动到终值的过程中逐位替换，
      等宽数字保证每一位占宽一致，卡片不会左右抖动。
      .stat-card .stat-value / .ov-kpi-num / .ov-kpi-ring-pct 原本各自已有 tabular-nums，
      这里补齐金额分体（.stat-value-main / .stat-value-dec）并做一次全局兜底，
      使「全站一致」不依赖各模块是否落在 .stat-card 里。
   ② 无障碍：prefers-reduced-motion: reduce 时由 JS 直接落终值（不播放动画），
      此处再固化「无过渡」语义，避免其它 transition 叠加造成视觉晃动。 */
.stat-value, .stat-value-main, .stat-value-dec,
.ov-kpi-num, .ov-kpi-ring-pct { font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) {
  .stat-value, .stat-value-main, .stat-value-dec,
  .ov-kpi-num, .ov-kpi-ring-pct { transition: none !important; }
}
/* ============================================================
   v532: 项目管理页顶部统计卡 —— 作用域类 .pm-stat-grid
   ------------------------------------------------------------
   ① 卡片本体完全复用全站 .stat-card / .stat-icon / .stat-trend（不新建第二套皮肤）
   ② 唯一差异：本页要放 5 张卡。全局 .stat-grid 是 minmax(196px)，
      1440 视口内容宽 1152 时 5 张需 1036 恰好可行，但 1280 视口内容宽 ≈1012
      时第 5 张会被挤到第二行（4+1 参差）。本页收窄到 minmax(158px)：
      5 张 = 158*5 + 14*4 = 846px，1280 及以上恒为一行。
   ③ 列宽收窄后同步收紧内距与图标，保证「项目总数」四字与「64 个」不折行；
      覆盖规则的选择器都带 .pm-stat-grid 前缀，特异性高于全局基类，零误伤他页。
   ④ 卡片可点即筛选 → cursor / active 两态，active 用 --primary 描边（深色主题自动跟随）；
      :focus-visible 只给键盘用户，鼠标点击不出方框。
   ============================================================ */
.pm-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: 14px;
  margin-bottom: 16px;
}
.pm-stat-grid .stat-card {
  padding: 14px 14px 14px 18px;
  gap: 12px;
  user-select: none;
  -webkit-user-select: none;
}
.pm-stat-grid .stat-card .stat-icon {
  width: 38px;
  height: 38px;
  flex: 0 0 38px;
}
.pm-stat-grid .stat-card .stat-value { font-size: clamp(19px, 1.7vw, 24px); }
.pm-stat-grid .stat-card .stat-trend { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pm-stat-grid .pm-stat-card { cursor: pointer; }
.pm-stat-grid .pm-stat-card:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.pm-stat-grid .pm-stat-card.active {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-bg);
}
/* 与全局 .stat-grid 的降列节奏保持一致（768 → 2 列 / 480 → 1 列） */
@media (max-width: 768px) {
  .pm-stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .pm-stat-grid .stat-card .stat-icon { width: 36px; height: 36px; flex: 0 0 36px; }
}
@media (max-width: 480px) {
  .pm-stat-grid { grid-template-columns: 1fr; }
}


/* ==========================================================================
   v535 · 仪表盘「待处理」卡空态美化（用户诉求：美化——醒目、突出）
   —— 新增作用域类 .rem-empty*；不改任何全站基类，也不改既有 .rem-* 规则。
   —— 追加在文件末尾，确保在层叠顺序上稳定压过任何更早的同名声明。
   ========================================================================== */
.rem-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 26px 20px 28px;
  border-radius: 14px;
  text-align: center;
  background:
    radial-gradient(118% 132% at 50% -8%, rgba(16, 185, 129, 0.16) 0%, rgba(16, 185, 129, 0.05) 44%, rgba(16, 185, 129, 0) 74%),
    linear-gradient(180deg, rgba(16, 185, 129, 0.07) 0%, rgba(16, 185, 129, 0.015) 100%);
  box-shadow: inset 0 0 0 1px rgba(16, 185, 129, 0.20);
}
.rem-empty-ico {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 23px;
  line-height: 1;
  background: radial-gradient(circle at 34% 26%, #ffffff 0%, rgba(16, 185, 129, 0.20) 100%);
  box-shadow: 0 6px 16px rgba(16, 185, 129, 0.22), inset 0 0 0 1px rgba(16, 185, 129, 0.24);
}
.rem-empty-main {
  font-size: 17px;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: 0.3px;
  color: var(--text);
}
.rem-empty-sub {
  font-size: 12.5px;
  line-height: 1.4;
  letter-spacing: 0.2px;
  color: var(--text-secondary);
}
html[data-theme='dark'] .rem-empty {
  background:
    radial-gradient(118% 132% at 50% -8%, rgba(52, 211, 153, 0.20) 0%, rgba(52, 211, 153, 0.06) 44%, rgba(52, 211, 153, 0) 74%),
    linear-gradient(180deg, rgba(52, 211, 153, 0.08) 0%, rgba(52, 211, 153, 0.02) 100%);
  box-shadow: inset 0 0 0 1px rgba(52, 211, 153, 0.22);
}
html[data-theme='dark'] .rem-empty-ico {
  background: radial-gradient(circle at 34% 26%, rgba(52, 211, 153, 0.30) 0%, rgba(52, 211, 153, 0.10) 100%);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.40), inset 0 0 0 1px rgba(52, 211, 153, 0.26);
}
@media (max-width: 480px) {
  .rem-empty { gap: 8px; padding: 20px 14px 22px; }
  .rem-empty-ico { width: 42px; height: 42px; font-size: 20px; }
  .rem-empty-main { font-size: 16px; }
}

/* ============================================================
   v536: 「待处理」提醒弹窗 —— 醒目 · 条理分明
   ------------------------------------------------------------
   用户诉求（verbatim）：美化，醒目条理分明。
   改前问题：① 头部品牌渐变淡到几乎不可见，标题 16px 无重量；
             ② 图标底色按「严重度」取色 —— 全 warning 时 8 条同色，
                卡片里是一整片同色块，类型不可辨、条理不清；
             ③ 「去处理」白底描边在白色卡片上几乎看不见（核心动作不醒目）。
   改后：① 头部改品牌渐变 banner（白字反向对比 + 数字胶囊 + 紧急徽标）；
         ② 图标底色改按「模块类型」—— 同模块同色成块，类型一眼可辨，
            类型变化处由 remRow 行内 margin 留 9px 组间距（弱分组）；
         ③ 紧急行整行极浅红底 + 左侧 3px 红条；动作按钮升主色淡底。
   ★ 亮色类型底必须写成 .rem-todo .rem-ico-<key>（0,2,0）——写成单类
     .rem-ico-<key>（0,1,0）会被同段兜底 .rem-todo .rem-ico（0,2,0）压过，
     11 类底色全部落回兜底灰（且类型类名照旧挂对、断言易假通过）。
   作用域（均为本轮新增类，改前全站 0 命中）：
     .rem-chip           头部紧急项徽标
     .rem-todo-danger   紧急条目行     .rem-sep 类型变化处首行
     .rem-ico-<key>     条目图标类型底（11 类：10 模块 + other）
   覆盖规则一律追加在文件末尾（v535 同款姿势）；全站基类
   .dash-act-row / .modal / .btn-ghost / .rem-todo 既有契约零改动。
   ★ .rem-todo 由弹窗与仪表盘「待处理」卡共用 → 两处一致受益。
   ============================================================ */

/* ① 头部：品牌渐变 banner —— 与浅色卡片形成强反差，一眼看到 */
.rem-modal .rem-head {
  padding: 18px 20px 15px;
  background: linear-gradient(135deg, #5b6cf0 0%, #7c5cf5 100%);
  border-bottom: none;
}
.rem-modal .rem-title {
  font-size: 18px; font-weight: 800; color: #ffffff;
  letter-spacing: 0.3px; gap: 10px;
}
.rem-modal .rem-title::before {
  width: 3.5px; height: 17px; background: rgba(255, 255, 255, 0.62);
}
.rem-modal .rem-chip {
  margin-left: 2px; padding: 2px 9px; border-radius: 20px;
  background: #ffffff; color: #d93b47;
  font-size: 11.5px; font-weight: 800; letter-spacing: 0.2px;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.14);
}
.rem-modal .rem-sub { font-size: 13px; color: rgba(255, 255, 255, 0.9); margin: 9px 0 0 13.5px; }
.rem-modal .rem-sub .rem-n {
  display: inline-block; min-width: 22px; padding: 1px 8px; margin: 0 2px;
  border-radius: 20px; background: rgba(255, 255, 255, 0.24);
  color: #ffffff; font-size: 14px; font-weight: 800;
  text-align: center; line-height: 1.35;
}

/* ② 条目行：类型色图标（同类同色成块）+ 紧急行高亮 */
.rem-todo { position: relative; }
.rem-todo .rem-ico { background: rgba(107, 114, 128, 0.17); }
.rem-todo .rem-ico-proposal {
  background: rgba(99, 102, 241, 0.19);
  box-shadow: inset 0 0 0 1px rgba(99, 102, 241, 0.30);
}
.rem-todo .rem-ico-projects {
  background: rgba(79, 107, 237, 0.19);
  box-shadow: inset 0 0 0 1px rgba(79, 107, 237, 0.30);
}
.rem-todo .rem-ico-tasks {
  background: rgba(139, 92, 246, 0.20);
  box-shadow: inset 0 0 0 1px rgba(139, 92, 246, 0.31);
}
.rem-todo .rem-ico-team {
  background: rgba(6, 182, 212, 0.19);
  box-shadow: inset 0 0 0 1px rgba(6, 182, 212, 0.30);
}
.rem-todo .rem-ico-delivery {
  background: rgba(249, 115, 22, 0.19);
  box-shadow: inset 0 0 0 1px rgba(249, 115, 22, 0.30);
}
.rem-todo .rem-ico-acceptance {
  background: rgba(16, 185, 129, 0.19);
  box-shadow: inset 0 0 0 1px rgba(16, 185, 129, 0.30);
}
.rem-todo .rem-ico-aftersale {
  background: rgba(244, 63, 94, 0.19);
  box-shadow: inset 0 0 0 1px rgba(244, 63, 94, 0.30);
}
.rem-todo .rem-ico-finance {
  background: rgba(245, 158, 11, 0.22);
  box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.33);
}
.rem-todo .rem-ico-procurement {
  background: rgba(234, 88, 12, 0.19);
  box-shadow: inset 0 0 0 1px rgba(234, 88, 12, 0.30);
}
.rem-todo .rem-ico-partners {
  background: rgba(100, 116, 139, 0.19);
  box-shadow: inset 0 0 0 1px rgba(100, 116, 139, 0.30);
}
.rem-todo .rem-ico-other {
  background: rgba(107, 114, 128, 0.17);
  box-shadow: inset 0 0 0 1px rgba(107, 114, 128, 0.26);
}

.rem-todo-danger { background: rgba(239, 68, 68, 0.06); }
.rem-todo-danger::before {
  content: ""; position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 3px; border-radius: 3px; background: var(--danger);
}
.rem-todo:hover { background: var(--primary-bg); }
.rem-todo-danger:hover { background: rgba(239, 68, 68, 0.09); }

/* ③ 动作按钮：由白底描边升为主色淡底（核心动作在白色卡片里可见），悬停实心 */
.rem-todo .rem-go {
  height: 30px; padding: 0 12px; font-size: 13px;
  background: var(--primary-bg); color: var(--primary);
  border-color: rgba(79, 107, 237, 0.24);
  box-shadow: 0 1px 2px rgba(79, 107, 237, 0.07);
}
.rem-todo:hover .rem-go {
  background: var(--primary); border-color: var(--primary); color: #ffffff;
}

/* ④ 底部：倒计时胶囊 + 主色「知道了」 */
.rem-modal .rem-hint {
  padding: 3px 10px; border-radius: 20px;
  background: var(--bg); color: var(--text-secondary);
  font-size: 12px; font-variant-numeric: tabular-nums;
}
.rem-modal .rem-ok { border-color: rgba(79, 107, 237, 0.3); color: var(--primary); font-weight: 700; }
.rem-modal .rem-ok:hover { background: var(--primary); border-color: var(--primary); color: #ffffff; }

/* ⑤ 行区滚动条（限弹窗作用域，不影响全站） */
.rem-modal .rem-body::-webkit-scrollbar { width: 8px; }
.rem-modal .rem-body::-webkit-scrollbar-track { background: transparent; }
.rem-modal .rem-body::-webkit-scrollbar-thumb {
  background: rgba(100, 116, 139, 0.28); border-radius: 8px;
}
.rem-modal .rem-body::-webkit-scrollbar-thumb:hover { background: rgba(100, 116, 139, 0.45); }

/* ⑥ 暗色：banner 降明度、类型底提 alpha、按钮与胶囊去白底 */
html[data-theme='dark'] .rem-modal .rem-head {
  background: linear-gradient(135deg, #39438f 0%, #4c3a8f 100%);
}
html[data-theme='dark'] .rem-modal .rem-chip { background: rgba(255, 255, 255, 0.92); color: #b0202c; }
html[data-theme='dark'] .rem-ico-proposal {
  background: rgba(129, 140, 248, 0.32);
  box-shadow: inset 0 0 0 1px rgba(129, 140, 248, 0.38);
}
html[data-theme='dark'] .rem-ico-projects {
  background: rgba(108, 131, 242, 0.34);
  box-shadow: inset 0 0 0 1px rgba(108, 131, 242, 0.40);
}
html[data-theme='dark'] .rem-ico-tasks {
  background: rgba(167, 139, 250, 0.32);
  box-shadow: inset 0 0 0 1px rgba(167, 139, 250, 0.38);
}
html[data-theme='dark'] .rem-ico-team {
  background: rgba(34, 211, 238, 0.30);
  box-shadow: inset 0 0 0 1px rgba(34, 211, 238, 0.36);
}
html[data-theme='dark'] .rem-ico-delivery {
  background: rgba(251, 146, 60, 0.30);
  box-shadow: inset 0 0 0 1px rgba(251, 146, 60, 0.36);
}
html[data-theme='dark'] .rem-ico-acceptance {
  background: rgba(52, 211, 153, 0.30);
  box-shadow: inset 0 0 0 1px rgba(52, 211, 153, 0.36);
}
html[data-theme='dark'] .rem-ico-aftersale {
  background: rgba(251, 113, 133, 0.30);
  box-shadow: inset 0 0 0 1px rgba(251, 113, 133, 0.36);
}
html[data-theme='dark'] .rem-ico-finance {
  background: rgba(251, 191, 36, 0.32);
  box-shadow: inset 0 0 0 1px rgba(251, 191, 36, 0.38);
}
html[data-theme='dark'] .rem-ico-procurement {
  background: rgba(251, 146, 60, 0.32);
  box-shadow: inset 0 0 0 1px rgba(251, 146, 60, 0.38);
}
html[data-theme='dark'] .rem-ico-partners {
  background: rgba(148, 163, 184, 0.28);
  box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.34);
}
html[data-theme='dark'] .rem-ico-other {
  background: rgba(148, 163, 184, 0.26);
  box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.32);
}
html[data-theme='dark'] .rem-todo-danger { background: rgba(248, 113, 113, 0.09); }
html[data-theme='dark'] .rem-todo:hover { background: rgba(108, 131, 242, 0.16); }
html[data-theme='dark'] .rem-todo-danger:hover { background: rgba(248, 113, 113, 0.14); }
html[data-theme='dark'] .rem-todo .rem-go {
  background: rgba(108, 131, 242, 0.16); border-color: rgba(108, 131, 242, 0.34);
}
html[data-theme='dark'] .rem-modal .rem-hint { background: rgba(255, 255, 255, 0.05); }

/* ⑦ 窄屏：标题与徽标收敛，动作列不挤正文 */
@media (max-width: 768px) {
  .rem-modal .rem-head { padding: 15px 16px 13px; }
  .rem-modal .rem-title { font-size: 17px; }
  .rem-modal .rem-sub { margin-left: 0; font-size: 12.5px; }
  .rem-modal .rem-chip { font-size: 11px; padding: 2px 7px; }
  .rem-todo .rem-go { height: 28px; padding: 0 9px; font-size: 12px; }
}

/* ═══ v538 数据列表表「整列对齐」单一真源 ═══ */
/* 背景：表头默认左对齐（css/style.css 早期 .table th{text-align:left}）；
   短内容列（状态胶囊/优先级/安全等级/进度/负责人/日期/类别）内容视觉重心偏列中央，
   而标题死贴左边 → 视觉错位。本段把数据列表表的标题与内容一起居中，
   长文本列用 .ta-left 回落左对齐，金额列用 .txt-num 回落右对齐。 */

/* ① 表头：数据列表表默认居中 */
.table.ops > thead > tr > th,
.data-table > thead > tr > th {
  text-align: center;
}

/* ② 单元格：默认居中（排除长文本列与金额列，避免压过它们自己的声明） */
.table.ops > tbody > tr > td:not(.ta-left):not(.txt-num),
.table.ops > tbody > tr > td.ta-c,
.data-table > tbody > tr > td:not(.ta-left):not(.txt-num),
.data-table > tbody > tr > td.ta-c {
  text-align: center;
}

/* ③ 长文本列：表头与单元格回落左对齐 */
.table.ops > thead > tr > th.ta-left,
.data-table > thead > tr > th.ta-left,
.table.ops > tbody > tr > td.ta-left,
.data-table > tbody > tr > td.ta-left {
  text-align: left;
}

/* ④ flex / inline-flex 单元格：text-align 管不到，补 justify-content 让其跟随列对齐。
   用「子元素 + flex 容器」通用兜底，不依赖具体类名（.flex / .ops-inline /
   .task-title-cell / .user-avatar 等任意自定义 flex 类都能命中）。
   注：对 block / inline / inline-block 子元素该属性无效，它们靠 td 的 text-align 生效。 */
.table.ops > tbody > tr > td:not(.ta-left) > *,
.data-table > tbody > tr > td:not(.ta-left) > * {
  justify-content: center;
}
.table.ops > tbody > tr > td.ta-left > *,
.data-table > tbody > tr > td.ta-left > * {
  justify-content: flex-start;
}

/* ⑤ 显式排除：输入网格 / 明细编辑表（.ta-keep）保持原有左对齐语义 */
.table.ops.ta-keep > thead > tr > th,
.table.ops.ta-keep > tbody > tr > td {
  text-align: left;
}
.table.ops.ta-keep > tbody > tr > td > * {
  justify-content: flex-start;
}

/* ⑥ 窄屏：保持居中即可，仅收敛内边距，避免列被挤压换行 */
@media (max-width: 768px) {
  .table.ops > thead > tr > th,
  .data-table > thead > tr > th { padding-left: 10px; padding-right: 10px; }
}


/* ── v538b 数据列表表 td 内头像与文本同排并列居中 ──
   根因（生产实测）：u.avatar() 返回 <div class="user-avatar …">…</div>，display:flex 属 block 级——
   block 元素不响应 text-align，且与紧随的 <span>姓名</span> 分处两行 → 内容盒中心偏移（tasks 实测 -9px）。
   方案：①头像在数据表 td 内改 inline-flex，与姓名同处一行，整行交回 td 的 text-align:center 居中；
        ②该 td 设 white-space:nowrap，避免窄列把姓名折行；
        ③td 自身保持 table-cell，不改 display（不破坏 colgroup / sticky 操作列 / colspan）。
   作用域：:has(> .user-avatar) 限定为「td 内确实含头像」，不触碰 .user-avatar 基类（全站 18 处用法）。 */
.table.ops > tbody > tr > td:has(> .user-avatar),
.data-table > tbody > tr > td:has(> .user-avatar) {
  white-space: nowrap;
}
.table.ops > tbody > tr > td:has(> .user-avatar) > .user-avatar,
.data-table > tbody > tr > td:has(> .user-avatar) > .user-avatar {
  display: inline-flex;
  vertical-align: middle;
}

/* ===== v550: 权限矩阵「鼠标经过坐标定位」强化 =====
   v104 起只有整列高亮（.col-hl，7% 蓝 + 1px 18% 描边），实测观感极淡、
   且缺「行轴」——看不出自己停在哪个权限上。本轮补成完整十字准星：
     上轴 .col-hl   = 角色整列 + 列头
     左轴 .row-hl   = 权限整行（含权限名列）
     交叉 .cross-hl = 鼠标所在单元格，拉到最亮
   并把「⌖ 定位」的 .col-focus 提到与悬停同强度，两种状态视觉统一。
   规则追加在文件末尾：不改动既有 .perm-cell / .col-hl 声明，
   靠 source order 稳胜，避免动全站基类。 */

/* --- 上轴：角色整列（含已授权单元格，用 !important 压过 .perm-cell.granted）--- */
.perm-matrix .perm-cell.col-hl {
  background: rgba(79, 107, 237, 0.18) !important;
  box-shadow: inset 0 0 0 1px rgba(79, 107, 237, 0.38) !important;
}
/* 列头同步加深，让「哪一列」一眼可辨 */
.perm-matrix .perm-col-toggle.col-hl {
  background: rgba(79, 107, 237, 0.14);
  box-shadow: inset 0 0 0 1px rgba(79, 107, 237, 0.3);
}

/* --- 左轴：权限整行（含权限名列、模块行不带 data-pi 故不受影响）--- */
.perm-matrix tr.perm-row td.row-hl {
  background: rgba(79, 107, 237, 0.13) !important;
}
.perm-matrix td.perm-name-col.row-hl {
  box-shadow: inset 4px 0 0 0 rgba(79, 107, 237, 1);
  background: rgba(79, 107, 237, 0.08) !important;
}
.perm-matrix td.perm-name-col.row-hl .perm-name-text {
  color: #3d55c7;
  font-weight: 600;
}

/* --- 交叉格：鼠标所在单元格，最亮 + 描边，明确「就是这一格」---
   ⚠ 特异性陷阱：行轴写的是 `tr.perm-row td.row-hl` = (0,3,2)，会压过
   `.perm-matrix .perm-cell.cross-hl` = (0,3,0)。交叉格必须比行轴更特异，
   故此处把作用域补成 `tr.perm-row td.perm-cell.cross-hl` = (0,4,2)，稳胜。 */
.perm-matrix tr.perm-row td.perm-cell.cross-hl {
  background: rgba(79, 107, 237, 0.38) !important;
  box-shadow: inset 0 0 0 2.5px rgba(79, 107, 237, 1) !important;
}

/* --- 「⌖ 定位」钉住高亮：与悬停同强度（原 12% / 1.5px 太淡）--- */
.perm-matrix .perm-cell.col-focus {
  background: rgba(79, 107, 237, 0.18) !important;
  box-shadow: inset 0 0 0 1px rgba(79, 107, 237, 0.55) !important;
}
.perm-matrix .perm-col-toggle.col-focus {
  background: rgba(79, 107, 237, 0.14);
  box-shadow: inset 0 0 0 1px rgba(79, 107, 237, 0.45);
  border-radius: 6px;
}


/* v551: 脱敏设置「金额」行——可见性已收归权限矩阵的「查看完整金额」，该行勾选改为只读展示 */
.ds-field-row.is-locked { background: rgba(79, 107, 237, 0.05); }
.ds-field-row.is-locked .ds-field-desc { color: var(--primary); }
.ds-field-row.is-locked input[type='checkbox'] { cursor: not-allowed; opacity: .7; }
html[data-theme='dark'] .ds-field-row.is-locked { background: rgba(79, 107, 237, 0.16); }

/* ==========================================================================
   v554: 整站鼠标经过（hover）统一增强
   — 语言：主色淡底 + 左侧 3px 主色定位条（沿用 .budget-items-table / .rem-todo-danger 既有范式）
   — 原则：一色一义。语义行（未读玫红 / 已读灰 / 已删除红）不被主色覆盖，只加强自身语义色。
   — 层级：底色写在 td 上（而非 tr），使 sticky 操作列与语义行的 td.box-shadow 底都能正确跟随。
   — 本段为纯追加，不修改既有任何规则；如需回退，删除本段即可。
   ========================================================================== */

:root {
  --hover-bg: rgba(79, 107, 237, 0.075);
  --hover-bg-strong: rgba(79, 107, 237, 0.13);
  --hover-bar: #4f6bed;
  --hover-ring: rgba(79, 107, 237, 0.38);
  --hover-shadow: 0 8px 20px -8px rgba(79, 107, 237, 0.45);
  --hover-ease: background-color .16s ease, box-shadow .16s ease, border-color .16s ease,
                transform .16s ease, color .16s ease;
}

html[data-theme='dark'] {
  --hover-bg: rgba(108, 131, 242, 0.17);
  --hover-bg-strong: rgba(108, 131, 242, 0.28);
  --hover-bar: #8598f5;
  --hover-ring: rgba(140, 160, 255, 0.50);
  --hover-shadow: 0 8px 20px -8px rgba(0, 0, 0, 0.65);
}

/* ---------- 1) 表格行：主色淡底 + 左侧定位条 ---------- */
.table tbody tr,
.data-table tbody tr,
.grid-table tbody tr,
.budget-items-table tbody tr,
.pd-pane .table.ops > tbody tr {
  transition: var(--hover-ease);
}

.table tbody tr:hover > td,
.data-table tbody tr:hover > td,
.grid-table tbody tr:hover > td,
.budget-items-table tbody tr:hover > td,
.pd-pane .table.ops > tbody tr:hover > td {
  background-color: var(--hover-bg);
}

.table tbody tr:hover > td:first-child,
.data-table tbody tr:hover > td:first-child,
.grid-table tbody tr:hover > td:first-child {
  box-shadow: inset 3px 0 0 0 var(--hover-bar);
}

/* ---------- 2) 语义行专属：不被主色覆盖，只加强自身语义色 ----------
   注意 1：tr.pm-unread > td 的底色由一个 1.6s 呼吸动画（pmPulseCell）接管了 box-shadow，
           animation 优先级高于普通声明 ⇒ hover 不能用 box-shadow 加强（会被动画相位吃掉）。
           故语义行的 hover 加强一律走 background-color 这一层（动画管不到此层）。
   注意 2：颜色必须沿用自身语义色，掺一点主色都会叠成偏紫，破坏「一色一义」。            */
.table tbody tr.pm-unread:hover > td,
.fin-list .table tbody tr.pm-unread:hover > td {
  background-color: rgba(244, 63, 94, 0.10);
}
.table tbody tr.pm-read:hover > td,
.fin-list .table tbody tr.pm-read:hover > td {
  background-color: rgba(148, 163, 184, 0.09);
}
/* 已删除行（预算/明细表）：红底是语义，不得被主色覆盖 */
.grid-table tbody tr.is-removed:hover > td {
  background-color: var(--danger-bg);
}
/* 语义行内的关键文本：随语义色走，不转主色 */
.table tbody tr.pm-unread:hover td:first-child .txt-key,
.fin-list .table tbody tr.pm-unread:hover td:first-child .txt-key {
  color: #be123c;
}

/* ---------- 3) 操作列：sticky 时自带背景会盖住行底，统一到同一 hover 色 ---------- */
table.table.ops tbody tr:hover > td:last-child,
table.data-table.ops tbody tr:hover > td:last-child {
  background-color: var(--hover-bg);
}
/* 语义行的操作列同样不得沾主色 */
table.table.ops tbody tr.pm-unread:hover > td:last-child {
  background-color: rgba(244, 63, 94, 0.10);
}
table.table.ops tbody tr.pm-read:hover > td:last-child {
  background-color: rgba(148, 163, 184, 0.09);
}

/* ---------- 4) 表格关键文本：hover 转主色（信息焦点） ---------- */
.table tbody tr:hover td .txt-key,
.data-table tbody tr:hover td .txt-key,
.grid-table tbody tr:hover td .txt-key {
  color: var(--hover-bar);
}
/* 财务列表首列有更高特异性的着色，须同写一份才不被压过 */
.fin-list .table tbody tr:hover td:first-child .txt-key {
  color: var(--hover-bar);
}

/* ---------- 5) 卡片：统一抬升 + 主色描边 + 主色阴影 ---------- */
.stat-card,
.project-card,
.kanban-card,
.member-card,
.ticket-card,
.file-stat-card,
.partner-card,
.role-card {
  transition: var(--hover-ease);
}
.stat-card:hover,
.project-card:hover,
.kanban-card:hover,
.member-card:hover,
.ticket-card:hover,
.file-stat-card:hover,
.partner-card:hover,
.role-card:hover {
  border-color: var(--hover-ring);
  box-shadow: var(--hover-shadow);
  transform: translateY(-3px);
}

/* ---------- 6) 列表行：统一底色（内部结构未知，不加左条以免破坏既有联动） ---------- */
.msg-item,
.notif-item,
.sg-row,
.sf-row,
.ov-row,
.ut-row,
.cat-item,
.admin-info-grid > div {
  transition: var(--hover-ease);
}
.msg-item:hover,
.notif-item:hover,
.sg-row:hover,
.sf-row:hover,
.ov-row:hover,
.ut-row:hover,
.cat-item:hover {
  background-color: var(--hover-bg);
}

/* ---------- 7) 仪表盘待办行：保留危险/警告语义色，仅加强 ---------- */
.dash-act-row {
  transition: var(--hover-ease);
}
.dash-act-row:hover {
  box-shadow: inset 3px 0 0 0 var(--hover-bar);
}
.dash-act-row.rem-todo-danger:hover {
  background-color: rgba(239, 68, 68, 0.15);
}
.dash-act-row.rem-todo-warn:hover {
  background-color: rgba(245, 158, 11, 0.20);
}

/* ---------- 8) 次级按钮 / 项目详情 tab：hover 反馈加强 ---------- */
.btn-ghost:hover {
  background-color: var(--primary-bg);
  color: var(--primary);
}
.pd-tab:hover {
  color: var(--hover-bar);
  background-color: var(--hover-bg);
}
/* v554 段结束 */
