/* ==============================================
   Comprehensive Data Analysis Management System — Modern Design System
   ============================================== */

:root {
  --bg: #f8fafc;
  --bg-card: #ffffff;
  --bg-sidebar: #0f172a;
  --bg-sidebar-hover: #1e293b;
  --bg-sidebar-active: #1e3a5f;
  --text: #1e293b;
  --text-muted: #64748b;
  --text-sidebar: #94a3b8;
  --text-sidebar-active: #ffffff;
  --border: #e2e8f0;
  --border-light: #f1f5f9;
  --bg-hover: #e2e8f0;
  --primary: #3b82f6;
  --primary-hover: #2563eb;
  --primary-light: #eff6ff;
  --success: #10b981;
  --success-light: #ecfdf5;
  --warning: #f59e0b;
  --warning-light: #fffbeb;
  --danger: #ef4444;
  --danger-light: #fef2f2;
  --purple: #8b5cf6;
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  --shadow-xs: 0 1px 2px rgba(0,0,0,.04);
  --shadow-sm: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
  --shadow: 0 4px 6px rgba(0,0,0,.04), 0 2px 4px rgba(0,0,0,.03);
  --shadow-md: 0 10px 15px rgba(0,0,0,.05), 0 4px 6px rgba(0,0,0,.04);
  --shadow-lg: 0 20px 25px rgba(0,0,0,.06), 0 10px 10px rgba(0,0,0,.03);
  --transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* ===== 全局深色主题 ===== */
html.theme-dark{
  --bg:#0f172a;
  --bg-card:#1e293b;
  --text:#f1f5f9;
  --text-muted:#94a3b8;
  --border:#334155;
  --border-light:#1e293b;
  --bg-hover:#334155;
  --primary-light:#1e3a5f;
  --success-light:#064e3b;
  --warning-light:#78350f;
  --danger-light:#7f1d1d;
  --shadow-xs:none;
  --shadow-sm:none;
  --shadow:none;
  --shadow-md:none;
  --shadow-lg:none;
}

/* 深色模式下表格统一深色（避免白底白字） */
html.theme-dark table{background:#1e293b !important;border-color:#334155 !important;color:#e5e7eb !important}
html.theme-dark th{background:#334155 !important;color:#f1f5f9 !important;border-color:#475569 !important}
html.theme-dark td{background:#1e293b !important;color:#e5e7eb !important;border-color:#334155 !important}
html.theme-dark tbody tr:nth-child(even) td{background:#1c2a3a !important}
html.theme-dark .record-row{background:#1e293b;border-color:#334155;color:#e5e7eb}
html.theme-dark .record-total{color:#e5e7eb}
html.theme-dark .empty-hint{color:#94a3b8}

/* ===== 原生表单控件的配色，跟随**页面主题**而不是系统 =====
 * 不声明 color-scheme 时，<select> 弹开的那个候选列表、<input type=month/date> 的
 * 原生选择器、以及滚动条，都跟随**操作系统/浏览器**的配色 ——
 * 系统是深色时，浅色页面点开筛选下拉，弹层就是黑的（用户 2026-09-20 报的问题：
 * 「配件记录多条件筛选下拉框在浅色模式下也是黑色的」；实测页面里控件的
 * 闭合状态本来就是白底深字，黑的只有系统画的那个弹层）。
 * 声明之后弹层跟着页面走：浅色主题给浅色弹层、深色主题给深色弹层。 */
html{color-scheme:light}
html.theme-dark{color-scheme:dark}

/* 深色模式下输入框统一深色（覆盖行内样式） */
html.theme-dark input,html.theme-dark select,html.theme-dark textarea{
  background:#1e293b !important;
  color:#e5e7eb !important;
  border-color:#334155 !important;
}
html.theme-dark input[type="month"]::-webkit-calendar-picker-indicator,
html.theme-dark input[type="date"]::-webkit-calendar-picker-indicator{
  filter:invert(1);
}
/* 深色模式下：下拉候选列表 / 当日汇总也适配深色 */
html.theme-dark .ac-list{background:#1e293b;border-color:#334155;box-shadow:0 4px 16px rgba(0,0,0,.5);color:#e5e7eb}
html.theme-dark .ac-item{color:#e5e7eb}
html.theme-dark .ac-item:hover{background:#2b3c57;color:#7dd3fc}
html.theme-dark .ac-item:not(:last-child){border-bottom-color:#334155}
html.theme-dark .ac-empty{color:#94a3b8}

/* ===== 顶部菜单栏 ===== */
.app-topbar{
  height:56px;
  flex-shrink:0;
  display:flex;align-items:center;justify-content:space-between;
  padding:0 20px;
  background:var(--bg-card);
  border-bottom:1px solid var(--border);
}
.topbar-title{font-size:1rem;font-weight:700;color:var(--text)}
.topbar-right{display:flex;align-items:center;gap:8px}
.topbar-btn{
  position:relative;width:38px;height:38px;border:none;border-radius:10px;
  background:transparent;color:var(--text);cursor:pointer;
  display:flex;align-items:center;justify-content:center;transition:background .2s;
}
.topbar-btn:hover{background:var(--bg-sidebar-hover)}
.topbar-badge{position:absolute;top:4px;right:4px;min-width:16px;height:16px;border-radius:8px;background:var(--danger);color:#fff;font-size:.62rem;display:none;align-items:center;justify-content:center;padding:0 4px;line-height:1}
.topbar-user{position:relative;display:flex;align-items:center;margin-left:8px}
.topbar-userbtn{display:flex;align-items:center;gap:8px;border:none;background:transparent;cursor:pointer;padding:4px 8px;border-radius:10px;color:var(--text);transition:background .2s}
.topbar-userbtn:hover{background:var(--bg-sidebar-hover)}
.topbar-caret{opacity:.6}
.topbar-dropdown{position:absolute;top:50px;right:0;min-width:140px;background:var(--bg-card);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-md);overflow:hidden;z-index:300}
.topbar-dd-item{display:block;width:100%;padding:10px 14px;border:none;background:transparent;color:var(--text);text-align:left;font-size:.85rem;cursor:pointer;transition:background .2s}
.topbar-dd-item:hover{background:var(--bg-sidebar-hover)}
.topbar-avatar{width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,#3b82f6,#8b5cf6);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:.85rem}
.topbar-name{font-size:.85rem;color:var(--text)}

/* ===== 顶部消息提醒下拉 ===== */
.topbar-notify{position:relative;display:flex;align-items:center}
.notify-dropdown{left:auto;right:0;width:360px;max-width:90vw;max-height:400px;display:flex;flex-direction:column}
.notify-head{padding:10px 14px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;font-size:.85rem;font-weight:600;color:var(--text)}
.notify-readall{background:transparent;border:none;color:var(--primary);font-size:.78rem;cursor:pointer;padding:2px 4px}
.notify-readall:hover{text-decoration:underline}
.notify-list{overflow-y:auto;max-height:350px}
.notify-empty{padding:22px;text-align:center;color:var(--text-muted);font-size:.82rem}
.notify-item{display:flex;align-items:flex-start;gap:8px;padding:10px 14px;border-bottom:1px solid var(--border)}
.notify-item:hover{background:var(--bg-sidebar-hover)}
.notify-item-text{flex:1;min-width:0;font-size:.8rem;color:var(--text)}
.notify-item-sub{display:block;font-size:.7rem;color:var(--text-muted);margin-top:2px}
.notify-btn{flex-shrink:0;padding:4px 11px;border:none;border-radius:6px;background:var(--primary);color:#fff;font-size:.72rem;cursor:pointer}
.notify-btn:hover{opacity:.9}

/* ===== 系统管理表单（统一风格） ===== */
.admin-label{font-size:.78rem;color:var(--text-muted);display:block;margin-bottom:4px}
.admin-input{width:220px;height:38px;padding:8px 12px;border:1px solid var(--border);border-radius:8px;font-size:.85rem;background:var(--bg-card);color:var(--text);outline:none;box-sizing:border-box}
.admin-input:focus{border-color:var(--primary)}
.admin-select{width:220px;height:38px;padding:8px 12px;border:1px solid var(--border);border-radius:8px;font-size:.85rem;background:var(--bg-card);color:var(--text);outline:none;box-sizing:border-box}
.admin-table{width:100%;border-collapse:collapse;font-size:.85rem}
.admin-table th{padding:9px 10px;border:1px solid var(--border);background:var(--border-light);color:var(--text);text-align:center;font-weight:600}
.admin-table td{padding:8px 10px;border:1px solid var(--border);color:var(--text)}

/* ===== 日志管理表格 =====
   问题：日志「详情」是自由文本，实际最长 462 字符（权限变更会逐项列出 30 个页面）。
        .admin-table 是自动布局，th 上的 width 百分比不生效，又没有换行约束，
        于是超长详情把表格撑得极宽 → 整页横向溢出（"被无限制放长、不换行"）。
   做法：
    · table-layout:fixed 让列宽按百分比真正生效，表格宽度锁定为容器宽度；
    · 详情列 overflow-wrap:anywhere + word-break:break-word 强制折行
      （anywhere 能处理「没有空格的长串」，例如权限变更里那一长串项目名）；
    · 详情列给 max-height + overflow-y，极长内容内部滚动，单行不会高得离谱；
    · 外面套一层 overflow-x:auto 兜底，窄屏（手机）可横向滑动而不撑破页面。 */
.admin-table-wrap{width:100%;overflow-x:auto}
.admin-log-table{table-layout:fixed;width:100%}
.admin-log-table th{vertical-align:middle}
.admin-log-table td{vertical-align:top}
.admin-log-table .col-time,
.admin-log-table .col-user,
.admin-log-table .col-act{overflow-wrap:anywhere;word-break:break-word}
.admin-log-table .col-detail{overflow-wrap:anywhere;word-break:break-word;white-space:normal}
/* 高度封顶必须放在内层块级元素上 —— max-height 对 <td> 无效 */
.admin-log-table .detail-box{max-height:8.5em;overflow-y:auto;line-height:1.55;overflow-wrap:anywhere;word-break:break-word}
.admin-perm-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 14px;border:1px solid var(--border);border-radius:8px;margin-bottom:8px;background:var(--bg-card)}
.admin-perm-row .mname{font-size:.85rem;color:var(--text);font-weight:600}
.admin-perm-row select{width:140px;padding:6px 10px;border:1px solid var(--border);border-radius:6px;font-size:.82rem;background:var(--bg-card);color:var(--text)}

/* 部门权限卡片（可折叠） */
.dept-card{border:1px solid var(--border);border-radius:10px;margin-bottom:12px;overflow:hidden;background:var(--bg-card)}
.dept-card-head{display:flex;align-items:center;gap:8px;padding:12px 14px;cursor:pointer;background:var(--border-light);transition:background .2s}
.dept-card-head:hover{background:var(--bg-hover)}
.dept-card-name{font-weight:600;font-size:.92rem;color:var(--text)}
.dept-card-count{font-size:.78rem;color:var(--text-muted);background:var(--border-light);border-radius:999px;padding:2px 8px;white-space:nowrap}
.dept-card-arrow{transition:transform .2s;opacity:.6;font-size:.75rem}
.dept-card.open .dept-card-arrow{transform:rotate(180deg)}
.dept-card-body{padding:8px 16px 14px}
.dept-mod-title{font-size:.82rem;font-weight:700;color:var(--text-muted);margin:12px 0 4px}

/* 权限管理：模块分组（可折叠） */
.perm-group{border:1px solid var(--border);border-radius:8px;margin-bottom:6px;overflow:hidden;background:var(--bg-card)}
.perm-group summary{cursor:pointer;padding:9px 12px;font-weight:600;font-size:.85rem;background:var(--border-light);color:var(--text);list-style:none;display:flex;align-items:center;justify-content:space-between}
.perm-group summary::-webkit-details-marker{display:none}
.perm-group summary::after{content:'▾';opacity:.6;transition:transform .2s}
.perm-group[open] summary::after{transform:rotate(180deg)}
.perm-group-body{padding:8px 12px}

/* 三层层级提示条（角色页 / 部门页各一条，说明"没设置的项会往哪一层回落"） */
.perm-layer-hint{
  margin:10px 12px 0;padding:8px 10px;border-radius:6px;
  font-size:.78rem;line-height:1.6;color:var(--text-muted);
  background:var(--border-light);border-left:3px solid var(--primary);
}
/* 「个人调整」标记：一眼看出哪些行是特例、哪些跟随角色 */
.perm-diff-tag{
  display:inline-block;font-size:.68rem;font-weight:600;line-height:1.5;
  padding:0 6px;border-radius:999px;
  background:rgba(245,158,11,.16);color:#b45309;border:1px solid rgba(245,158,11,.35);
}
html.theme-dark .perm-diff-tag{background:rgba(245,158,11,.2);color:#fbbf24;border-color:rgba(245,158,11,.4)}
.perm-row-diff>td{background:rgba(245,158,11,.06)}
/* 「生效值来自哪一层」的来源小标（个人权限页末列） */
.perm-src-tag{font-size:.68rem;color:var(--text-muted);white-space:nowrap}

/* ===== Reset & Base ===== */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{font-size:15px;background:var(--bg);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;height:100%;overflow:hidden}
body{
  font-family:'Inter',"Microsoft YaHei","PingFang SC",system-ui,sans-serif;
  background:var(--bg);
  color:var(--text);
  min-height:100vh;
  height:100vh;
  overflow:hidden;
  line-height:1.5;
}

/* ===== App Shell (Sidebar + Main) ===== */
.app-shell{display:flex;min-height:100vh;overflow:hidden}

/* ===== Sidebar ===== */
.sidebar{
  width:260px;
  background:var(--bg-sidebar);
  display:flex;
  flex-direction:column;
  position:fixed;
  top:0;left:0;bottom:0;
  z-index:100;
  overflow:hidden;
  border-right:1px solid rgba(255,255,255,.06);
  transition:transform .28s ease;
}
.sidebar-brand{
  flex-shrink:0;
  padding:24px 20px 20px;
  display:flex;
  align-items:center;
  gap:14px;
  border-bottom:1px solid rgba(255,255,255,.08);
}
.brand-icon{
  width:46px;height:46px;
  background:transparent;
  border-radius:var(--radius);
  overflow:hidden;
  display:flex;align-items:center;justify-content:center;
  flex-shrink:0;
  filter:drop-shadow(0 2px 8px rgba(56,189,248,.3));
}
.brand-icon svg{width:22px;height:22px}
.brand-text{display:flex;flex-direction:column;gap:1px}
.brand-title{font-size:1.1rem;font-weight:700;color:#fff;letter-spacing:-0.01em}
.brand-sub{font-size:0.65rem;font-weight:500;color:var(--text-sidebar);text-transform:uppercase;letter-spacing:0.08em}

.sidebar-nav{
  flex:1;
  min-height:0;
  overflow-y:auto;
  padding:12px 12px;
  display:flex;
  flex-direction:column;
  gap:2px;
}
.nav-item{
  display:flex;
  align-items:center;
  gap:12px;
  padding:11px 14px;
  border:none;
  border-radius:var(--radius);
  background:transparent;
  color:var(--text-sidebar);
  font-size:0.9rem;
  font-weight:500;
  cursor:pointer;
  transition:all var(--transition);
  text-align:left;
  font-family:inherit;
}
.nav-item svg{width:20px;height:20px;flex-shrink:0;opacity:0.7}
.nav-item:hover{background:var(--bg-sidebar-hover);color:#e2e8f0}
.nav-item:hover svg{opacity:1}
.nav-item.active{
  background:var(--bg-sidebar-active);
  color:var(--text-sidebar-active);
  font-weight:600;
}
/* ⚠️ 2026-09：图标已改为「蓝→青」渐变描边（见下方规则），这里的 color 不再影响图标；
   opacity 仍用于区分选中态（未选中 0.7 / 悬停与选中 1）。 */
.nav-item.active svg{opacity:1}

/* ===== 侧栏菜单图标：青→紫渐变描边 =====
   SVG 的描边没法直接用 CSS 的渐变，必须引用文档里定义好的 <linearGradient>
   （id = navIconGrad，定义在 index.html 的 <body> 之后；颜色 #22d3ee → #a855f7）。
   ⚠️ 那里**必须**写 gradientUnits="userSpaceOnUse"：用默认的 objectBoundingBox 时，
      图标里纯横线/纯竖线的包围盒宽或高为 0，退化包围盒会让 SVG 直接不渲染该元素
      （实测「工作台」显示器的支架线整条消失、只剩方框）。
   这一条同时管住「菜单项图标」和「分组标题前的小图标」——
   实测它们的子元素（rect/line/path…共 135 个）**都不自带 stroke**、全部继承父级，
   所以只需要改 <svg> 这一层，40 个图标一次生效、不必逐个改 HTML。
   注：右侧的折叠箭头（.group-arrow）是方向指示、不是菜单图标，**刻意不纳入**。 */
.sidebar-nav .nav-item svg,
.sidebar-nav .nav-group-toggle > svg:first-child{stroke:url(#navIconGrad)}
/* ===== 侧边栏分组菜单 ===== */
.nav-group{margin-top:2px}
.nav-group-toggle{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:11px 14px;border:none;border-radius:var(--radius);
  background:transparent;color:var(--text-sidebar);font-size:0.9rem;font-weight:600;
  cursor:pointer;transition:all var(--transition);text-align:left;font-family:inherit;
}
/* 一级（分组标题）图标 = 20px，与「工作台 / 图文排版」这两个一级单条一致。
 *
 * 为什么改：原来是 15px，而**二级子项是 16px**（见下面的 .nav-subitem svg）——
 * 一级比二级还小，层级是反的，看着分不出谁是谁的父级（实测：分组 14px、
 * 一级单条 19px、二级 15px）。改成 20px 之后：
 *     一级分组 20px ＞ 二级子项 16px
 * 一眼就能分层。
 * 透明度保持 .55 不动：那是"分组标题"和"可点子项"的区别，不是层级区别；
 * 用户这次只要求改大小。 */
.nav-group-toggle > svg:first-child{width:20px;height:20px;opacity:.55;flex-shrink:0}
.nav-group-toggle:hover{background:var(--bg-sidebar-hover);color:#e2e8f0}
.nav-group-toggle .group-arrow{width:16px;height:16px;margin-left:auto;opacity:.6;transition:transform .25s}
.nav-group-toggle.open .group-arrow{transform:rotate(180deg)}
.nav-submenu{display:none;flex-direction:column;gap:1px;padding:2px 0 2px 6px}
.nav-submenu.open{display:flex;animation:fadeSlideIn .25s ease}
.nav-subitem{padding:9px 14px 9px 26px;font-size:0.85rem;font-weight:400}
.nav-subitem svg{width:16px;height:16px;opacity:.55}
.nav-subitem.active{font-weight:600}
/* ===== 工作台 ===== */
@media (max-width:640px){
}

.sidebar-footer{
  flex-shrink:0;
  padding:16px 20px;
  border-top:1px solid rgba(255,255,255,.08);
  display:flex;
  flex-direction:column;
  gap:8px;
}
.footer-top{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}
/* 备案号 / 公安备案（内容来自 js/site-info.js）
   侧边栏底色较深，所以用弱化的灰蓝色、字号比正文更小，不抢视觉。
   留空时容器被 JS 设为 display:none，不会留下空白条。 */
.site-foot{font-size:.68rem;line-height:1.6;color:var(--text-muted,#94a3b8);word-break:break-all}
.site-foot a{color:inherit;text-decoration:none}
.site-foot a:hover{color:#cbd5e1;text-decoration:underline}
.site-foot .site-foot-sep{margin:0 5px;opacity:.55}
.month-badge{
  background:rgba(255,255,255,.08);
  color:#e2e8f0;
  padding:6px 12px;
  border-radius:20px;
  font-size:0.75rem;
  font-weight:600;
  letter-spacing:0.02em;
}

/* ===== Main Area ===== */
.main-area{
  flex:1;
  margin-left:260px;
  transition:margin-left .28s ease;
  padding:0;
  min-height:100vh;
}

/* ===== Stats Bar ===== */
.stats-bar{
  display:grid;
  grid-template-columns:repeat(6,1fr);
  gap:16px;
  margin-bottom:28px;
}
.stats-label{
  font-size:0.7rem;
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:0.06em;
  color:var(--text-muted);
  margin-bottom:10px;
}
.today-stats{
  grid-template-columns:repeat(6,1fr);
  margin-top:4px;
  padding-top:20px;
  border-top:1px solid var(--border);
}
.stat-card{
  background:var(--bg-card);
  border-radius:var(--radius);
  padding:20px;
  display:flex;
  align-items:center;
  gap:16px;
  box-shadow:var(--shadow-sm);
  border:1px solid var(--border-light);
  transition:all var(--transition);
}
.stat-card:hover{
  box-shadow:var(--shadow-md);
  transform:translateY(-1px);
}
.stat-icon{
  width:48px;height:48px;
  border-radius:var(--radius);
  display:flex;align-items:center;justify-content:center;
  flex-shrink:0;
}
.stat-icon svg{width:22px;height:22px}
.stat-info{display:flex;flex-direction:column;gap:2px}
.stat-value{font-size:1.5rem;font-weight:700;color:var(--text);letter-spacing:-0.02em}
.stat-label{font-size:0.78rem;color:var(--text-muted);font-weight:500}

/* ===== Buttons ===== */
.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:6px;
  padding:9px 18px;
  border:none;
  border-radius:var(--radius-sm);
  cursor:pointer;
  font-size:0.875rem;
  font-weight:600;
  font-family:inherit;
  transition:all var(--transition);
  white-space:nowrap;
  letter-spacing:0.01em;
}
.btn svg{width:17px;height:17px}
.btn-sm{padding:6px 13px;font-size:0.8rem}
.btn-xs{padding:4px 10px;font-size:0.75rem;border-radius:6px}
.btn-primary{background:var(--primary);color:#fff}
.btn-primary:hover{background:var(--primary-hover);box-shadow:0 4px 12px rgba(59,130,246,.35)}
.btn-warning{background:var(--warning);color:#fff}
.btn-danger{background:var(--danger);color:#fff}
.btn-ghost{background:transparent;color:var(--text-muted);border:1px solid var(--border)}
.btn-ghost:hover{background:var(--bg);color:var(--text)}
.btn-outline{background:transparent;color:var(--primary);border:1.5px solid var(--primary)}
.btn-outline:hover{background:var(--primary-light)}
.btn-full{width:100%}

/* ===== Tab Panels ===== */
.tab-panel{display:none}
.tab-panel.active{display:block;animation:fadeSlideIn .35s ease}
/* 基础数据标签页撑满内容区（视口自适应，列表内部滚动） */
#tab-basic.active{display:flex;flex-direction:column;flex:1;min-height:0}
#tab-basic.active .basic-grid{flex:1;min-height:0;align-items:stretch}
#tab-basic.active .basic-grid .basic-card{min-height:0}
/* 水电片区场所管理：卡片铺满内容区（非窗口底部），列表内部滚动 */
.main-area{display:flex;flex-direction:column;height:100vh;overflow:hidden}
.tab-content{display:flex;flex-direction:column;flex:1;min-height:0;overflow-y:auto;padding:24px 32px 40px}
.tab-content:not(:has(.tab-panel.active)){display:none}
#tab-we-manage.active{display:flex;flex-direction:column;flex:1;min-height:0}
#tab-we-manage.active .basic-grid{flex:1;min-height:0;align-items:stretch}
#tab-we-manage.active .basic-grid .basic-card{min-height:0}
@keyframes fadeSlideIn{
  from{opacity:0;transform:translateY(8px)}
  to{opacity:1;transform:translateY(0)}
}

/* ===== Panel Header ===== */
.panel-header{
  display:flex;
  justify-content:space-between;
  align-items:flex-start;
  flex-wrap:wrap;
  gap:16px;
  margin-bottom:24px;
}
.panel-header h2{font-size:1.35rem;font-weight:700;letter-spacing:-0.01em}
.panel-desc{font-size:0.8rem;color:var(--text-muted);margin-top:2px}
.panel-toolbar{
  display:flex;
  align-items:flex-end;
  gap:10px;
  flex-wrap:wrap;
}
.panel-toolbar input[type="date"],
.panel-toolbar input[type="month"]{
  height:40px;
}
.panel-toolbar .btn:not(.btn-sm):not(.btn-xs){
  height:40px;
}
.input-group{display:flex;flex-direction:column;gap:4px}
.input-group label{font-size:0.7rem;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.04em}

/* ===== Form Elements ===== */
input[type="date"],input[type="month"],input[type="text"],input[type="number"],select{
  padding:9px 14px;
  border:1.5px solid var(--border);
  border-radius:var(--radius-sm);
  font-size:0.875rem;
  font-family:inherit;
  background:var(--bg-card);
  color:var(--text);
  transition:all var(--transition);
  outline:none;
  cursor:pointer;
  min-height:40px;
}
input[type="date"]:hover,input[type="month"]:hover{
  border-color:#93c5fd;
  background:#f8faff;
}
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator{
  cursor:pointer;
  padding:4px;
  border-radius:4px;
  transition:all var(--transition);
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="month"]::-webkit-calendar-picker-indicator:hover{
  background:rgba(59,130,246,.1);
}
input:focus,select:focus{
  border-color:var(--primary);
  box-shadow:0 0 0 3px rgba(59,130,246,.12);
}

/* ===== Segmented Control ===== */
.segmented-control{
  display:flex;
  background:var(--bg);
  border-radius:var(--radius-sm);
  padding:3px;
  border:1px solid var(--border);
}
.seg-btn{
  padding:7px 14px;
  border:none;
  border-radius:6px;
  background:transparent;
  color:var(--text-muted);
  font-size:0.8rem;
  font-weight:500;
  cursor:pointer;
  transition:all var(--transition);
  font-family:inherit;
}
.seg-btn.active{background:var(--bg-card);color:var(--text);font-weight:600;box-shadow:var(--shadow-xs)}

/* ===== Day Records ===== */
.day-summary{
  margin-top:20px;
  padding:18px 20px;
  background:linear-gradient(135deg,#eff6ff,#f0f9ff);
  border-radius:var(--radius);
  border:1px solid #bfdbfe;
  font-size:0.9rem;
}
html.theme-dark .day-summary{
  background:linear-gradient(135deg,#16263f,#1c2a3a);
  border-color:#334155;
  color:#e5e7eb;
}
/* 生活垃圾录入页顶部工具栏：日期与筛选框高度一致 */
#tab-input .panel-toolbar input,
#tab-input .panel-toolbar input[type="date"]{
  height:36px !important;
  min-height:36px !important;
  max-height:36px !important;
  box-sizing:border-box !important;
  line-height:34px;
  vertical-align:middle;
  padding-top:0 !important;
  padding-bottom:0 !important;
}
#tab-input .panel-toolbar input[type="date"]::-webkit-calendar-picker-indicator{
  margin-top:0;margin-bottom:0;
}
#tab-input .panel-toolbar .input-group{gap:4px}
.record-row{
  display:flex;
  align-items:center;
  gap:10px;
  padding:14px 18px;
  background:var(--bg-card);
  border-radius:var(--radius);
  margin-bottom:8px;
  flex-wrap:wrap;
  border:1px solid var(--border-light);
  transition:all var(--transition);
}
.record-row:hover{border-color:#bfdbfe;box-shadow:var(--shadow-sm)}
.record-row select,.record-row input{
  padding:6px 10px;
  border:1.5px solid var(--border);
  border-radius:6px;
  font-size:0.82rem;
  font-family:inherit;
}
.record-row select{min-width:110px}
.record-row input[type="number"]{width:74px}
.record-tag{
  font-size:0.78rem;
  font-weight:600;
  padding:3px 10px;
  border-radius:20px;
  letter-spacing:0.01em;
}
.tag-vehicle{background:#eff6ff;color:#2563eb}
.tag-driver{background:#fef3c7;color:#d97706}
.tag-station{background:#ecfdf5;color:#059669}
.trip-inputs{display:flex;align-items:center;gap:5px;flex-wrap:wrap}
.trip-inputs input{width:70px!important;text-align:center}
.add-trip-btn{width:28px;height:28px;padding:0!important;border-radius:50%!important;font-size:1.1rem!important;line-height:1!important}
.trip-wrap{display:inline-flex;align-items:center;gap:1px}
.trip-del-btn{
  width:18px;height:18px;
  padding:0;
  border:none;
  border-radius:50%;
  background:#fee2e2;
  color:#ef4444;
  font-size:11px;
  font-weight:700;
  cursor:pointer;
  line-height:1;
  transition:all var(--transition);
  display:inline-flex;
  align-items:center;
  justify-content:center;
}
.trip-del-btn:hover{background:#fecaca;color:#dc2626}
.record-total{
  font-weight:700;
  color:var(--primary);
  white-space:nowrap;
  font-size:0.85rem;
  background:var(--primary-light);
  padding:4px 12px;
  border-radius:20px;
}
.empty-hint{
  text-align:center;
  padding:60px 20px;
  color:var(--text-muted);
  font-size:0.95rem;
}
.empty-hint::before{
  content:'';
  display:block;
  width:64px;height:64px;
  margin:0 auto 14px;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='22 12 16 12 14 15 10 15 8 12 2 12'/%3E%3Cpath d='M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='22 12 16 12 14 15 10 15 8 12 2 12'/%3E%3Cpath d='M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z'/%3E%3C/svg%3E") center/contain no-repeat;
  background-color:var(--text-muted);
  opacity:.75;
}

/* ===== Tables ===== */
.summary-table-wrap{
  overflow-x:auto;
  border-radius:var(--radius);
  border:1px solid var(--border);
}
.summary-table-wrap table{width:max-content;table-layout:auto;min-width:100%;border-collapse:collapse}
.summary-table-wrap th:first-child,.summary-table-wrap td:first-child{width:38px;min-width:38px}
.summary-table-wrap th:nth-child(2),.summary-table-wrap td:nth-child(2){min-width:110px;text-align:left}
.summary-table-wrap th,.summary-table-wrap td{min-width:52px;padding:5px 6px;white-space:nowrap;font-size:0.78rem}
.summary-table-wrap th:first-child,.summary-table-wrap td:first-child{position:sticky;left:0;background:#fff;z-index:2}
.summary-table-wrap th:nth-child(2),.summary-table-wrap td:nth-child(2){position:sticky;left:38px;background:#fff;z-index:2;box-shadow:3px 0 6px -3px rgba(100,116,139,.35)}
.summary-table-wrap .dash-dark th:first-child,.summary-table-wrap .dash-dark td:first-child,.summary-table-wrap .dash-dark th:nth-child(2),.summary-table-wrap .dash-dark td:nth-child(2){background:#0f172a}
.summary-table-wrap thead th{position:sticky;top:0;z-index:3;background:#f8fafc}
table{
  border-collapse:collapse;
  width:100%;
  font-size:0.82rem;
}
th,td{
  border:1px solid var(--border-light);
  padding:8px 12px;
  text-align:center;
  white-space:nowrap;
}
th{
  background:#f8fafc;
  font-weight:600;
  color:var(--text-muted);
  font-size:0.75rem;
  text-transform:uppercase;
  letter-spacing:0.03em;
}
td{color:var(--text)}
tr:hover td{background:#f8faff}
.total-row td{font-weight:700;background:#eff6ff!important;color:var(--primary)}
.weekday{font-size:0.65rem;color:var(--text-muted);font-weight:400;display:block;margin-top:1px}

/* ===== Dashboard ===== */
.dashboard-grid{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:20px;
  min-width:0;
}
.chart-card{
  min-width:0;
  background:var(--bg-card);
  border-radius:var(--radius-lg);
  padding:24px;
  border:1px solid var(--border-light);
  box-shadow:var(--shadow-sm);
  transition:all var(--transition);
}
.chart-card:hover{box-shadow:var(--shadow-md)}
.chart-card-header{
  display:flex;
  justify-content:space-between;
  align-items:center;
  margin-bottom:16px;
}
.chart-card-header h3{font-size:0.95rem;font-weight:600}
.chart-badge{
  font-size:0.7rem;
  font-weight:600;
  padding:3px 10px;
  border-radius:20px;
  background:var(--bg);
  color:var(--text-muted);
  letter-spacing:0.02em;
}
.chart-card canvas{min-height:200px;max-height:400px}

/* ===== IO Cards ===== */
.io-section{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:20px;
}
.io-card{
  background:var(--bg-card);
  border-radius:var(--radius-lg);
  padding:28px 24px;
  border:1px solid var(--border-light);
  box-shadow:var(--shadow-sm);
  display:flex;
  flex-direction:column;
  gap:14px;
  text-align:center;
  transition:all var(--transition);
}
.io-card:hover{box-shadow:var(--shadow-md);transform:translateY(-2px)}
/* 危险操作卡片（清空数据）：整体与其它卡片一致，仅图标/标题用红色警示；按钮已用红/橙色警示色 */
.io-card-danger{
  border:1px solid var(--border-light);
  background:var(--bg-card);
}
.io-card-danger .io-icon{background:var(--danger);color:#fff}
.io-card-danger h3{color:var(--danger)}
.io-icon{
  width:56px;height:56px;
  margin:0 auto;
  border-radius:var(--radius);
  background:var(--primary-light);
  color:var(--primary);
  display:flex;
  align-items:center;
  justify-content:center;
}
.io-icon svg{width:28px;height:28px}
.io-card h3{font-size:1rem;font-weight:600}
.io-card p{font-size:0.8rem;color:var(--text-muted);line-height:1.5}
.file-input-label{position:relative;cursor:pointer}
.file-input-label input[type="file"]{
  position:absolute;inset:0;opacity:0;cursor:pointer;
  width:100%;height:100%;
}
.file-input-btn{
  display:block;
  padding:10px 16px;
  border:2px dashed var(--border);
  border-radius:var(--radius-sm);
  font-size:0.82rem;
  font-weight:500;
  color:var(--text-muted);
  transition:all var(--transition);
}
.file-input-btn:hover{border-color:var(--primary);color:var(--primary);background:var(--primary-light)}
.file-input-name{display:block;margin-top:6px;font-size:0.75rem;color:var(--text-muted);min-height:1.1em;word-break:break-all}
.file-input-name.has-file{color:var(--success);font-weight:500}

/* ===== Basic Data ===== */
.basic-grid{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  gap:20px;
  align-items:stretch;
}
.basic-card{
  background:var(--bg-card);
  border-radius:var(--radius-lg);
  padding:20px;
  border:1px solid var(--border-light);
  box-shadow:var(--shadow-sm);
  display:flex;
  flex-direction:column;
}
.basic-card-header{
  display:flex;
  align-items:center;
  gap:10px;
  margin-bottom:12px;
  padding-bottom:12px;
  border-bottom:1px solid var(--border-light);
  flex-shrink:0;
}
.basic-card-header h3{font-size:0.95rem;font-weight:600;flex:1}
.basic-icon{width:24px;height:24px;display:flex;align-items:center}
.basic-icon svg{width:22px;height:22px}
.basic-count{
  font-size:0.75rem;
  font-weight:700;
  padding:3px 10px;
  border-radius:20px;
  background:var(--bg);
  color:var(--text-muted);
}
.basic-list{flex:1;overflow-y:auto;min-height:0;margin-bottom:10px}
.basic-list::-webkit-scrollbar{width:4px}
.basic-search{
  padding:7px 10px;
  border:1.5px solid var(--border);
  border-radius:6px;
  font-size:.78rem;
  font-family:inherit;
  outline:none;
  margin-bottom:8px;
  flex-shrink:0;
  transition:all .2s;
}
.basic-search:focus{border-color:var(--primary);box-shadow:0 0 0 3px rgba(59,130,246,.12)}
.basic-item{
  display:flex;
  justify-content:space-between;
  align-items:center;
  padding:8px 10px;
  border-radius:6px;
  font-size:0.85rem;
  transition:all var(--transition);
}
.basic-item:hover{background:var(--bg)}
/* 列表行的「删除 ×」按钮：**通用类**，不属于任何某一个列表容器。
   ⚠️ 2026-09 修复：原先写的是 `.basic-item .del-btn`（限定在磅单/水电的列表里），
   而费用页的列表容器叫 `.fe-list-item` —— 选择器命中不到，于是费用页的删除按钮
   退化成浏览器默认样式（实测 9×16、灰底 rgb(240,240,240)、`1px outset` 凸起边框、
   黑色 ×、圆角 0），在一排深色卡片里非常突兀。放开为通用类后任何列表都能直接用。 */
.del-btn{
  color:var(--danger);
  cursor:pointer;
  background:none;
  border:none;
  font-size:1.1rem;
  width:28px;height:28px;
  border-radius:6px;
  display:flex;align-items:center;justify-content:center;
  transition:all var(--transition);
  flex-shrink:0;
}
.del-btn:hover{background:var(--danger-light)}
.basic-add{display:flex;gap:6px;margin-bottom:8px;flex-shrink:0;align-items:center}
/* ⚠️ 2026-09 补齐：添加输入框原先**只有一个 flex:1、没有任何外观样式**，于是走浏览器
   默认外观 —— 方角（圆角 0）、零内边距、字号 13.3px；而紧挨在它上面的 .basic-search
   是圆角 6px / 内边距 7px 10px / 字号 11.7px。同一张卡片里两套观感，看着像"没做完"。
   现在整行（输入框 / 下拉框 / 按钮）统一到与搜索框相同的规格。
   ⚠️ 关于高度为什么写 32px：主站 body 上有 autoZoom()（public/js/app.js，按窗口大小
      自动算 CSS zoom）。zoom 缩的是**视觉**尺寸，而 CSS 里的 px 是**布局**尺寸、
      恒定不变；上方 .basic-search 的固有高度同样是布局值（实测约 32.1px）。
      两者在同一坐标系里，所以无论 autoZoom 算出多少，这排控件始终与搜索框齐平
      （实测视觉高度 30.1 vs 30.2，差 0.1px）。写"看起来的 30px"反而会矮 2px。 */
.basic-add input,
.basic-add select,
.basic-add .btn{height:32px;min-height:0}
/* ⚠️ 必须带 min-height:0：style.css 里有一条全局规则
   `input[type=date],input[type=month],input[type=text],input[type=number],select{min-height:40px}`，
   而 min-height **优先于** height（40 > 32）—— 只写 height 的话，
   "车辆→司机绑定"那行的两个下拉框会被撑到 40px，比同排的输入框/按钮高出一截。 */
.basic-add input{
  flex:1;
  min-width:0;
  padding:0 10px;
  border:1.5px solid var(--border);
  border-radius:6px;
  background:var(--bg-card);
  color:var(--text);
  font-size:.8rem;
  font-family:inherit;
  outline:none;
  transition:border-color .2s,box-shadow .2s;
}
.basic-add input:focus{border-color:var(--primary);box-shadow:0 0 0 3px rgba(59,130,246,.12)}
/* 添加/绑定按钮：这里只覆盖内边距与字号（高度由上面那条统一给 32px）。
   用于压过后面的全局 .btn-sm（padding:3px 10px / 字号 .72rem）——
   否则按钮实际只有 22px 高、字号 10.8px。 */
.basic-add .btn{padding:0 14px;font-size:.8rem;border-radius:6px;flex-shrink:0}

/* ===== 列表页通用：筛选区 / 计数 / 分页条（见 docs/UI-列表页布局规范.md）===== */
.list-filter{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
.list-filter input[type="text"],.list-filter input[type="month"],.list-filter input[type="date"],
.list-filter input[type="number"],.list-filter select{
  height:30px;padding:0 8px;border:1px solid var(--border);border-radius:6px;font-size:.8rem;
  background:var(--bg-card);color:var(--text);box-sizing:border-box;outline:none;
}
.list-filter input[type="text"]:focus,.list-filter select:focus{border-color:var(--primary)}
.list-filter .btn{height:30px;padding:0 12px;font-size:.8rem;display:inline-flex;align-items:center;justify-content:center}
.list-filter .list-filter-label{font-size:.78rem;color:var(--text-muted);white-space:nowrap}
.list-count{font-size:.75rem;color:var(--text-muted);font-weight:400;white-space:nowrap}
.list-pager{display:flex;align-items:center;gap:10px;margin-top:10px;flex-wrap:wrap;font-size:.78rem;color:var(--text-muted);padding-right:72px}
/* ↑ padding-right 为右下角 AI 悬浮球（#aiFab 76×76 @ right/bottom:20px）预留空间，
     否则「下一页」按钮约 81% 被悬浮球压住。悬浮球改小或移走后可把 72px 调回 0。 */

/* ===== 全部「可视化看板」卡片：统一立体感 + 悬停 45° 青光 =====
   覆盖：可视化看板 / 维修看板 / 资产看板 / 水电看板 / 费用看板 / 收缴看板 / 油耗看板
   ⚠️ 这是**写死的 id 白名单**：新增看板时必须把它的面板 id 加进下面每一个 :is(...)，
      否则新看板的卡片会"悬停没反应"（2026-09-20 维修看板就是这样漏掉的 —— 实测
      它的 .chart-card 悬停前后计算样式完全一样，而其他 6 个看板都会抬起 3px + 青色发光）。
   规则：
     · 平时 = 淡阴影 + 顶部 1px 内高光（深色主题下阴影 token 全是 none，故深色单独给真实投影）
     · 悬停 = 抬升 3px + 卡片底下那圈投影由「灰」换成「青」，位移 x=y 即 45°（光源在左上，影子打向右下）
   为什么用 !important：各模块的深色主题规则（.dash-dark / .we-dark / .op-dash-dark / .fe-dark）
   都写了 box-shadow:none，且选择器带模块类、优先级更高；这里必须压过它们，
   否则深色主题下看板卡片完全没有立体感。
   注意：只改投影颜色与位移，不动边框色。 */
:is(#tab-dashboard,#tab-maint-dashboard,#tab-asset-dashboard,#tab-we-dashboard,#tab-fee-dashboard,#tab-op-dashboard,#tab-fuel-dashboard)
  :is(.stat-card, .chart-card, .we-chart-card, .we-venue-card, .we-card, .fe-stat, .fe-chart-card, .op-stat, .op-card){
  --lift-shadow: var(--shadow-sm);
  --lift-glow: inset 0 1px 0 rgba(255,255,255,.9);
  border-radius: var(--radius);
  box-shadow: var(--lift-shadow), var(--lift-glow) !important;
  transition: transform .18s cubic-bezier(.4,0,.2,1),
              box-shadow .18s cubic-bezier(.4,0,.2,1),
              border-color .18s cubic-bezier(.4,0,.2,1);
}
:is(#tab-dashboard,#tab-maint-dashboard,#tab-asset-dashboard,#tab-we-dashboard,#tab-fee-dashboard,#tab-op-dashboard,#tab-fuel-dashboard)
  :is(.stat-card, .chart-card, .we-chart-card, .we-venue-card, .we-card, .fe-stat, .fe-chart-card, .op-stat, .op-card):hover{
  --lift-shadow: 7px 7px 20px rgba(8,145,178,.32), 2px 2px 8px rgba(8,145,178,.22);
  transform: translateY(-3px);
}
html.theme-dark
  :is(#tab-dashboard,#tab-maint-dashboard,#tab-asset-dashboard,#tab-we-dashboard,#tab-fee-dashboard,#tab-op-dashboard,#tab-fuel-dashboard)
  :is(.stat-card, .chart-card, .we-chart-card, .we-venue-card, .we-card, .fe-stat, .fe-chart-card, .op-stat, .op-card){
  --lift-shadow: 0 1px 2px rgba(0,0,0,.30), 0 1px 3px rgba(0,0,0,.22);
  --lift-glow: inset 0 1px 0 rgba(255,255,255,.07);
}
html.theme-dark
  :is(#tab-dashboard,#tab-maint-dashboard,#tab-asset-dashboard,#tab-we-dashboard,#tab-fee-dashboard,#tab-op-dashboard,#tab-fuel-dashboard)
  :is(.stat-card, .chart-card, .we-chart-card, .we-venue-card, .we-card, .fe-stat, .fe-chart-card, .op-stat, .op-card):hover{
  --lift-shadow: 8px 8px 26px rgba(34,211,238,.48), 3px 3px 10px rgba(34,211,238,.30);
}
@media (prefers-reduced-motion:reduce){
  :is(#tab-dashboard,#tab-maint-dashboard,#tab-asset-dashboard,#tab-we-dashboard,#tab-fee-dashboard,#tab-op-dashboard,#tab-fuel-dashboard)
    :is(.stat-card, .chart-card, .we-chart-card, .we-venue-card, .we-card, .fe-stat, .fe-chart-card, .op-stat, .op-card):hover{
    transform: none;
  }
}
.list-pager .btn{padding:3px 10px;font-size:.78rem}
.list-pager select{padding:2px 6px;border:1px solid var(--border);border-radius:6px;font-size:.78rem;background:var(--bg-card);color:var(--text)}

/* ===== 列表页统一高度策略 =====
   目标：所有列表页「表格/卡片底边到视口底部的距离」完全一致，
        恒等于 .tab-content 的下内边距（40px），与数据条数、页面无关。
   做法：面板撑满剩余高度 → 卡片作为弹性列容器撑满 → 表格区吃掉剩余空间内部滚动 → 分页条钉在卡片底部。
   已按此规则的页面：费用录入/水电录入（water-electric.css）、资产台账/到期未还/折旧明细（asset.css）。 */
#tab-asset-flow.active,#tab-summary.active,#tab-fuel-records.active,#tab-fuel-monthly.active,
#tab-fuel-vehicles.active,#tab-fuel-compare.active,#tab-event-locations.active,#tab-op-input.active{
  display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden;
}
/* 顶部（标题/工具栏/统计条/录入表单）不参与伸缩 */
#tab-asset-flow.active>.panel-header,#tab-summary.active>.panel-header,#tab-fuel-records.active>.panel-header,
#tab-fuel-monthly.active>.panel-header,#tab-fuel-vehicles.active>.panel-header,#tab-fuel-compare.active>.panel-header,
#tab-event-locations.active>.panel-header,#tab-op-input.active>.panel-header,
#tab-asset-flow.active>#assetFlowStats,#tab-fuel-records.active>#fuelInputCard,#tab-op-input.active>.op-input-card{flex:0 0 auto}
/* 卡片：撑满剩余高度并作为弹性列容器（去掉了各页原有的 max-height:calc(100vh - Npx) 写法） */
#tab-asset-flow.active>.fe-card,#tab-summary.active>.fe-card,#tab-fuel-records.active>.fe-card,
#tab-fuel-monthly.active>.fe-card,#tab-fuel-vehicles.active>.fe-card,#tab-fuel-compare.active>.fe-card,
#tab-event-locations.active>.fe-card,
#tab-op-input.active>.op-list-card{
  flex:1;display:flex;flex-direction:column;min-height:0;margin-bottom:0;
}
/* 收缴录入的「新增客户」表单卡片不参与伸缩，避免与列表卡片各占一半高度 */
#tab-op-input.active>.op-card:not(.op-list-card){flex:0 0 auto}
/* 卡片头不伸缩 */
#tab-asset-flow.active .fe-card-header,#tab-summary.active .fe-card-header,#tab-fuel-records.active .fe-card-header,
#tab-fuel-monthly.active .fe-card-header,#tab-fuel-vehicles.active .fe-card-header,#tab-fuel-compare.active .fe-card-header,
#tab-event-locations.active .fe-card-header,#tab-op-input.active .op-card-header{flex:0 0 auto}
/* 表格区：吃掉全部剩余高度，超出则内部滚动（max-height:none 用于解除收缴录入原有的 max-height:520px）
   注意：这里必须保留 overflow:auto，否则 sticky 表头会失去滚动容器、「内容穿上表头」（见 docs/UI-列表页布局规范.md 五之五） */
#tab-asset-flow.active .asset-flow-table-wrap,#tab-summary.active .summary-table-wrap,
#tab-fuel-records.active .fe-table-wrap,#tab-fuel-monthly.active .fe-table-wrap,
#tab-fuel-vehicles.active .fe-table-wrap,#tab-fuel-compare.active .fe-table-wrap,
#tab-event-locations.active .ev-loc-table-wrap,
#tab-op-input.active .op-table-wrap{flex:1;min-height:0;overflow:auto;max-height:none}
/* 事件地点：还原原先内联 style 上的边框与圆角 */
.ev-loc-table-wrap{border:1px solid var(--border);border-radius:10px}
/* 分页条：钉在卡片底部 */
#tab-asset-flow.active .list-pager,#tab-fuel-records.active .list-pager,#tab-fuel-monthly.active .list-pager,
#tab-fuel-vehicles.active .list-pager,#tab-event-locations.active .list-pager,
#tab-op-input.active .list-pager{flex:0 0 auto;margin-top:10px}
/* ===== 维修记录 / 维修汇总表：同一套规则（2026-09-20 用户要求"同样按列表页规范分页，和视口高度等"）
 *
 * 实测改前（视口 1600×900）：
 *   维修记录   卡片高 9006px、卡片底在视口下方 8373px、表格区不能内滚、卡片内无分页条、一次渲染 305 行
 *   维修汇总表 卡片高 3809px、同上
 *   参考页「加油记录」卡片底距视口底 38px、表格区内滚、分页条钉在卡片底（54px）→ 本次对齐这个标准
 *
 * ⚠️ 页面结构是「panel-header + 统计卡片(.fe-card) + 列表卡片(.fe-card#maintListView)」，
 *    所以只有**最后那张**卡片参与伸缩（:not(...) 把统计卡片排除掉），否则两张卡片各占一半高度。
 */
#tab-maint-records.active,#tab-maint-summary.active{
  display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden;
}
#tab-maint-records.active>.panel-header,#tab-maint-summary.active>.panel-header,
#tab-maint-records.active>.fe-card:not(#maintListView),
#tab-maint-summary.active>.fe-card:not(#maintSummaryCard){flex:0 0 auto}
#tab-maint-records.active>#maintListView,#tab-maint-summary.active>#maintSummaryCard{
  flex:1;display:flex;flex-direction:column;min-height:0;margin-bottom:0;
}
#tab-maint-records.active .fe-card-header,#tab-maint-summary.active .fe-card-header{flex:0 0 auto}
/* 表格区吃掉剩余高度并内部滚动。overflow 必须保留 auto，否则 sticky 表头会失去滚动容器（§七坑2） */
#tab-maint-records.active .summary-table-wrap,#tab-maint-summary.active .summary-table-wrap{
  flex:1;min-height:0;overflow:auto;max-height:none;
}
#tab-maint-records.active .list-pager,#tab-maint-summary.active .list-pager{flex:0 0 auto;margin-top:10px}
/* 配件记录（2026-09-20 模块审计后补）：这一页原先**没有**这套伸缩规则，
 * 于是 400 条数据时卡片高 10,861px、卡片底距视口底 -10,078px（规范 §八 要求 38px）。
 * 结构与维修记录页一样：panel-header + 统计卡片(fe-card) + 列表卡片(fe-card#mpListView)，
 * 所以同样只让**最后那张**卡片参与伸缩（:not(#mpListView) 排除统计卡片）。 */
#tab-maint-parts.active{display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden}
#tab-maint-parts.active>.panel-header,
#tab-maint-parts.active>.fe-card:not(#mpListView){flex:0 0 auto}
#tab-maint-parts.active>#mpListView{flex:1;display:flex;flex-direction:column;min-height:0;margin-bottom:0}
#tab-maint-parts.active .fe-card-header{flex:0 0 auto}
#tab-maint-parts.active .summary-table-wrap{flex:1;min-height:0;overflow:auto;max-height:none}
#tab-maint-parts.active .list-pager{flex:0 0 auto;margin-top:10px}
/* 费用波动告警：同规则（无分页条，表格底边距视口底 54px = 38px + 卡片内边距 16px） */
#tab-we-alert.active{display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden}
#tab-we-alert.active>.panel-header,#tab-we-alert.active>.we-alert-summary,#tab-we-alert.active>.we-alert-tabs{flex:0 0 auto}
#tab-we-alert.active>.we-card{flex:1;display:flex;flex-direction:column;min-height:0;margin-bottom:0}
#tab-we-alert.active .we-card-header{flex:0 0 auto}
#tab-we-alert.active .we-alert-table-wrap{flex:1;min-height:0;overflow:auto}
#tab-we-alert.active .we-table thead th{position:sticky;top:0;z-index:2;background:var(--primary-light);box-shadow:0 1px 0 var(--border)}

/* ===== Modal ===== */
.modal-overlay{
  display:none;
  position:fixed;
  inset:0;
  background:rgba(15,23,42,.5);
  backdrop-filter:blur(4px);
  z-index:1000;
  justify-content:center;
  align-items:center;
}
.modal-overlay.show{display:flex;animation:fadeIn .2s ease}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
.modal{
  background:var(--bg-card);
  border-radius:var(--radius-lg);
  padding:20px;
  max-width:680px;
  width:92%;
  max-height:85vh;
  overflow-y:auto;
  box-shadow:var(--shadow-lg);
  animation:scaleIn .25s ease;
}
@keyframes scaleIn{from{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}
.modal h3{font-size:1.1rem;font-weight:700;margin-bottom:16px}

/* ===== 公告阅读器 A4 纸张排版 ===== */
.ann-a4{
  background:#fff;
  color:#1f2937;
  width:100%;
  max-width:620px;
  flex-shrink:0;
  height:auto;
  margin:0 auto;
  padding:44px 48px 56px;
  border-radius:4px;
  box-shadow:0 2px 10px rgba(15,23,42,.18),0 0 0 1px rgba(148,163,184,.12);
  font-family:"Songti SC","SimSun","Noto Serif SC",serif;
  font-size:15px;
  line-height:1.9;
  box-sizing:border-box;
}
html.theme-dark .ann-a4{background:#fff;color:#1f2937}
.ann-a4-head{text-align:center;margin-bottom:20px}
.ann-a4-tag{display:inline-block;font-size:12px;padding:2px 12px;border-radius:999px;color:#fff;margin-bottom:12px}
.ann-a4-title{font-size:22px;font-weight:700;color:#111827;margin:0 0 8px;letter-spacing:.5px;line-height:1.4}
.ann-a4-meta{font-size:12px;color:#6b7280}
.ann-a4-line{width:56px;height:3px;background:#d1d5db;margin:18px auto 0;border-radius:2px}
.ann-a4-body{text-align:justify}
.ann-a4-body p{margin:0 0 12px;text-indent:2em}
.ann-a4-body .ann-a4-space{height:6px}
.ann-a4-list{margin:0 0 12px;padding-left:1.4em;list-style:disc}
.ann-a4-list li{margin-bottom:6px}
/* 公告内容 A4 编辑区：接近纸面的录入体验 */
.ann-edit-a4{
  display:block;
  width:100%;
  min-height:520px;
  padding:40px 44px;
  margin:0 auto;
  font-family:"Songti SC","SimSun","Noto Serif SC",serif;
  font-size:15px;
  line-height:1.9;
  color:#1f2937;
  resize:vertical;
  box-sizing:border-box;
  border:1px solid rgba(148,163,184,.35);
  border-radius:6px;
  background:#fff;
  box-shadow:inset 0 2px 6px rgba(13,23,42,.06),0 2px 8px rgba(15,23,42,.08);
}
html.theme-dark .ann-edit-a4{background:#fff;color:#1f2937;border-color:rgba(148,163,184,.3)}
.ann-edit-a4:focus{outline:none;border-color:rgba(56,189,248,.6);box-shadow:0 0 0 3px rgba(56,189,248,.12),inset 0 2px 6px rgba(13,23,42,.06)}

/* ===== Messages ===== */
.msg{font-size:0.85rem;padding:10px 14px;border-radius:var(--radius-sm);margin-top:8px}
.msg-success{background:var(--success-light);color:#065f46}
.msg-error{background:var(--danger-light);color:#991b1b}

/* ===== Scrollbar ===== */
::-webkit-scrollbar{width:6px;height:6px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:3px}
::-webkit-scrollbar-thumb:hover{background:#94a3b8}

/* ===== Responsive ===== */
@media(max-width:1200px){
  .dashboard-grid{grid-template-columns:1fr}
  .io-section{grid-template-columns:1fr}
  .stats-bar{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:768px){
  /* 手机端：侧栏改成【抽屉】—— 固定定位、默认滑出屏幕外（复用已有的
     .app-shell.sidebar-collapsed .sidebar{transform:translateX(-100%)}，见下方 sidebar-toggle 段）。
     原先这里把侧栏改成 width:100%;position:relative（全宽块），
     75 个导航项在 393px 里换行后堆到 1871px 高，把内容区整个顶到屏幕外 —— 所以改成抽屉。 */
  .sidebar{
    width:260px;
    position:fixed;
    height:100vh;
    overflow-y:auto;
    flex-direction:column;
    flex-wrap:nowrap;
    padding:16px 0;
  }
  .sidebar-brand,.sidebar-nav{flex-direction:column;flex-wrap:nowrap;gap:2px}
  .sidebar-nav .nav-item span{display:inline}          /* 抽屉里要显示文字，不能只留图标 */
  .sidebar-nav .nav-item{padding:10px 16px;border-radius:0}
  .app-shell{display:block}                            /* 不再纵向堆叠，内容区独立占满宽度 */
  .main-area{margin-left:0;padding:16px}
  .basic-grid{grid-template-columns:1fr}
  .panel-header{flex-direction:column}
  .panel-toolbar{width:100%;justify-content:flex-start}
}
/* 窄屏网格降列：原先只降到 3 列，而 393px 下每列≈100px，
   .stat-card 里图标48+间距16+内边距40=104px 固定开销 → 文字可用宽度归零、被挤成竖排。
   实测：3 列在 393px 上会产生 13 处文字竖排；2 列在 375/393/414 上竖排为 0。
   只有 ≤360px 的超小屏（iPhone SE 一代 320px）才降到 1 列。 */
@media(max-width:768px){
  .stats-bar,.today-stats{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:360px){
  .stats-bar,.today-stats{grid-template-columns:minmax(0,1fr)}
}

/* ===== Dropdown ===== */
.dropdown-item:hover{background:#f0f4ff!important;color:#1e40af}
.dropdown-menu{animation:fadeIn .15s ease}

/* ===== AutoComplete ===== */
.ac-wrap{position:relative;display:inline-block;vertical-align:middle}
.ac-input{width:100%;padding:7px 10px;border:1.5px solid var(--border);border-radius:8px;font-size:.85rem;font-family:inherit;outline:none;background:#fff;color:var(--text);transition:all .2s}
.ac-input:focus{border-color:var(--primary);box-shadow:0 0 0 3px rgba(59,130,246,.12)}
.ac-list{position:absolute;top:100%;left:0;right:0;background:#fff;border:1px solid var(--border);border-radius:8px;max-height:200px;overflow-y:auto;z-index:300;box-shadow:0 4px 16px rgba(0,0,0,.1);display:none;margin-top:2px}
.ac-item{padding:7px 12px;cursor:pointer;font-size:.82rem;color:var(--text);transition:background .1s}
.ac-item:hover{background:#f0f4ff;color:#1e40af}
.ac-item:not(:last-child){border-bottom:1px solid var(--border-light)}
.ac-empty{padding:10px;text-align:center;color:var(--text-muted);font-size:.78rem}

/* ===== 磅单可视化看板深色主题（纯黑） ===== */
#tab-dashboard.dash-dark{background:transparent;border-radius:0;padding:0}
/* tab-content 深色背景由 JS 控制（.tc-dark） */
#tab-dashboard.dash-dark .panel-header h2{color:#f8fafc}
#tab-dashboard.dash-dark .panel-desc{color:#94a3b8}
#tab-dashboard.dash-dark .stats-label{color:#cbd5e1}
#tab-dashboard.dash-dark .stat-card,
#tab-dashboard.dash-dark .chart-card{background:#111827;border-color:#1f2937;box-shadow:none}
#tab-dashboard.dash-dark .stat-value{color:#f8fafc}
#tab-dashboard.dash-dark .stat-label{color:#94a3b8}
#tab-dashboard.dash-dark .chart-card-header h3{color:#e5e7eb}
#tab-dashboard.dash-dark .chart-badge{background:#1e293b;color:#93c5fd}
#tab-dashboard.dash-dark .input-group label{color:#94a3b8}
#tab-dashboard.dash-dark input[type="month"]{background:#1f2937;color:#e5e7eb;border-color:#374151}
#tab-dashboard.dash-dark input[type="month"]:focus{border-color:#3b82f6;outline:none}
#tab-dashboard.dash-dark input[type="month"]::-webkit-calendar-picker-indicator{filter:invert(1)}
#tab-dashboard.dash-dark .dropdown-menu{background:#1f2937;border-color:#374151}
#tab-dashboard.dash-dark .dropdown-item{color:#e5e7eb !important}
.dash-theme-btn{display:inline-flex;align-items:center;gap:6px}
.dash-theme-btn svg{width:16px;height:16px}

/* ===== 中转站清运量滚动排行（对齐水电滚动图） ===== */
.dash-scroll-wrap{height:280px;overflow-y:auto;overflow-x:hidden;position:relative;scrollbar-width:none}
.dash-scroll-wrap::-webkit-scrollbar{display:none}
.dash-scroll-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#94a3b8;font-size:.85rem}
.dash-venue-row{display:flex;align-items:center;gap:8px;height:23px;padding:0 8px;font-size:.78rem;box-sizing:border-box;min-width:0}
.dash-venue-name{flex:0 1 110px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#94a3b8}
.dash-venue-track{flex:1 1 auto;min-width:24px;height:13px;border-radius:4px;background:rgba(148,163,184,.15);overflow:hidden}
.dash-venue-bar{display:block;height:100%;border-radius:4px}
.dash-venue-val{flex:0 1 auto;min-width:58px;text-align:right;color:#e5e7eb;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:visible}

.chart-wide{grid-column:1/-1}


/* ===== 磅单看板导出菜单深色适配 ===== */
#tab-dashboard.dash-dark .we-io-menu{background:#1f2937;border-color:#374151}
#tab-dashboard.dash-dark .we-io-item{color:#e5e7eb}
#tab-dashboard.dash-dark .we-io-item:hover{background:#0f172a;color:#60a5fa}

/* ===== 维修数据看板 · 深色面板 =====
   ⚠️ 这个面板本来就有 class="dash-dark"（而且「深浅色」按钮切的就是它），
      但**从来没有对应的 CSS** —— 于是那个按钮只改了图表线条颜色，页面本体一动不动，
      和其他看板（磅单/水电/费用/收缴都有各自的深色规则）完全不是一回事。
      这里按磅单看板（#tab-dashboard.dash-dark）的同一套写法补齐。
   注意：卡片背景/边框写在这里，但「立体感 + 悬停青光」由上面那条统一规则用
        !important 提供（和磅单看板一致），所以这里保留 box-shadow:none 不会盖掉悬停效果。 */
#tab-maint-dashboard.dash-dark{background:transparent;border-radius:0;padding:0}
#tab-maint-dashboard.dash-dark .panel-header h2{color:#f8fafc}
#tab-maint-dashboard.dash-dark .panel-desc{color:#94a3b8}
#tab-maint-dashboard.dash-dark .stat-card,
#tab-maint-dashboard.dash-dark .chart-card{background:#111827;border-color:#1f2937;box-shadow:none}
#tab-maint-dashboard.dash-dark .stat-value{color:#f8fafc}
#tab-maint-dashboard.dash-dark .stat-label{color:#94a3b8}
#tab-maint-dashboard.dash-dark .chart-card-header h3{color:#e5e7eb}
#tab-maint-dashboard.dash-dark .maint-stat-note{color:#cbd5e1}
#tab-maint-dashboard.dash-dark .input-group label{color:#94a3b8}
#tab-maint-dashboard.dash-dark input[type="month"]{background:#1f2937;color:#e5e7eb;border-color:#374151}
#tab-maint-dashboard.dash-dark input[type="month"]:focus{border-color:#3b82f6;outline:none}
/* 维修看板顶部 7 张卡片（比别的看板多一张「当月合计金额」）：
 *   用户 2026-09-20：「顶部卡片建议只排列成一行」→ 已把原来的两条（4 张 + 3 张）
 *   合并成**一条 7 张**，一行还是两行由列数决定：
 *     · 默认 4 列     → 4 + 3 两行，与合并前**像素级一致**
 *     · ≥1800px 7 列  → 一行 7 张（用户要的效果）
 *     · ≤1200px 2 列  → 与原来的响应式行为一致
 *   ⚠️ 门槛必须是 1800px，这是量出来的不是拍的：一张卡片有 **104px 固定开销**
 *      （内边距 40 + 图标 48 + 间距 16），而「98,353.17」在 22.5px 字号下要 **100px**
 *      → 每张至少 186px → 7 张一行要求网格宽 ≥ 7×186 + 6×16 = 1398px。
 *      实测「一行 7 列」各视口（文字区冲出卡片多少 —— 冲出去会压到右边那张）：
 *        1920px 正常 ｜ 1700px 冲出 13px ｜ 1600px 冲出 27px ｜ 1440px 冲出 50px
 *        ｜ 1280px 7 张全部冲出、标签被挤成竖排
 *      所以宁可 1800px 才一行，也不让金额被挤出去。
 *   本次不再写 margin-bottom:14px —— 合并后它是页面上唯一一条 .stats-bar，
 *   用默认的 28px，和磅单看板那条单条 stats-bar 完全一致。 */
#mdStatsBar{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (min-width:1800px){
  #mdStatsBar{grid-template-columns:repeat(7,minmax(0,1fr))}
}
@media (max-width:1200px){
  #mdStatsBar{grid-template-columns:repeat(2,minmax(0,1fr))}
}
#tab-maint-dashboard.dash-dark input[type="month"]::-webkit-calendar-picker-indicator{filter:invert(1)}

/* ===== 数据备份页 ===== */
.btn-sm{padding:3px 10px;font-size:.72rem;border-radius:6px;border:1px solid var(--border);background:var(--bg-card);color:var(--text);cursor:pointer}
.btn-sm:hover{background:var(--border-light)}
/* ⚠️ 2026-09 修复：上面那条 .btn-sm 是**全局生效**的（注释写着"数据备份页"，实际没有
   任何作用域限定），它把 .btn-primary 的蓝色背景和白字覆盖成了"卡片色 + 正文色"。
   两条规则同为单类选择器、特异性相同，它加载在后 → 后加载者胜。
   实测后果：全站 7 个 `class="btn btn-primary btn-sm"` 的按钮**都不蓝了**
   （磅单基础数据 4 个、水电片区场所管理 2 个、车务凭证上传 1 个），
   背景算出来是 rgb(30,41,59) 而不是主色 rgb(59,130,246)。
   下面用两个类把特异性提到 (0,2,0)，无论加载顺序都稳赢。 */
.btn-primary.btn-sm,.btn-primary.btn-xs{background:var(--primary);color:#fff;border:none}
.btn-primary.btn-sm:hover,.btn-primary.btn-xs:hover{background:var(--primary-hover);box-shadow:0 4px 12px rgba(59,130,246,.35)}
.op-period-modal{min-width:420px}
.op-per-row{display:flex;align-items:center;gap:8px;padding:8px;border:1px solid var(--border);border-radius:8px;margin-bottom:6px;background:var(--bg-card)}
.op-per-row input[type="month"]{flex:1;min-width:0;padding:5px 8px;border:1px solid var(--border);border-radius:6px;font-size:.8rem;background:var(--bg-card);color:var(--text)}
.op-per-to{color:var(--text-muted);font-size:.75rem}
.op-per-del{padding:4px 10px;border:none;border-radius:6px;background:#fee2e2;color:#dc2626;font-size:.72rem;cursor:pointer}
.op-per-del:hover{background:#fecaca}
.op-per-empty{padding:10px;text-align:center;color:#999;font-size:.8rem;border:1px dashed var(--border);border-radius:8px}
.op-a-line1{display:flex;align-items:center;justify-content:space-between;gap:8px}
/* ⚠️ 这两行原来是写死的浅色配色（#64748b / #b91c1b），
 *    深色主题下压在预警项的底上几乎看不清（用户反馈"很模糊"）。
 *    改成跟主题走：次要信息用 var(--text-muted)，欠费明细用红色但深浅两套。 */
.op-a-meta{font-size:11px;color:var(--text-muted);margin:3px 0;line-height:1.5}
.op-a-detail{font-size:11px;color:#b91c1b;font-weight:400;line-height:1.4}
html.theme-dark .op-a-detail{color:#fca5a5}
.switch{position:relative;display:inline-block;width:40px;height:22px;flex-shrink:0}
.switch input{opacity:0;width:0;height:0}
.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#cbd5e1;transition:.2s;border-radius:22px}
.slider:before{position:absolute;content:"";height:16px;width:16px;left:3px;bottom:3px;background:#fff;transition:.2s;border-radius:50%}
input:checked + .slider{background:#3b82f6}
input:checked + .slider:before{transform:translateX(18px)}

/* ===== 隐藏 number 输入框上下箭头（防误触） ===== */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}
/* 费用波动告警阈值输入框恢复上下箭头，便于微调 */
#weAlertPct::-webkit-inner-spin-button,
#weAlertPct::-webkit-outer-spin-button {
  -webkit-appearance: inner-spin-button;
  display: inline-block;
  opacity: 1;
}

/* ===== 侧边栏收起 ===== */
.sidebar-toggle{
  position:fixed;top:64px;left:272px;z-index:200;
  width:34px;height:34px;border-radius:8px;
  display:flex;align-items:center;justify-content:center;
  background:rgba(15,23,42,.85);color:#e2e8f0;border:1px solid rgba(255,255,255,.12);
  cursor:pointer;transition:left .28s ease,background .2s;
}
.sidebar-toggle:hover{background:#1e293b}
.sidebar-toggle svg{width:17px;height:17px}
.app-shell.sidebar-collapsed .sidebar{transform:translateX(-100%)}
.app-shell.sidebar-collapsed .main-area{margin-left:0}
.app-shell.sidebar-collapsed .sidebar-toggle{left:14px}
/* 原先这里是 @media (max-width:900px){.sidebar-toggle{display:none}}，
   但 ≤768px 的手机端【恰恰需要】这个开关来打开抽屉。
   改成只隐藏 769~900px 这一段 —— 这样 >900px 显示（同以前）、769~900px 隐藏（同以前）、
   ≤768px 才新显示。避免顺手给平板区间多出一个按钮。 */
@media (min-width:769px) and (max-width:900px){.sidebar-toggle{display:none}}
@media (max-width:768px){
  .sidebar-toggle{top:12px;left:12px;z-index:1200}
  /* 抽屉展开时禁止内容区滚动（否则会在抽屉后面滚动，手感很怪）。
     关闭方式由 JS 负责：点导航项、或点内容区。 */
  .app-shell:not(.sidebar-collapsed) .main-area{overflow:hidden}
}

/* ===== 工作台待办提醒 ===== */
.wb-alert{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:20px;margin-bottom:20px}
.wb-alert h3{font-size:1rem;font-weight:600;color:var(--text)}
/* 标题行：左侧标题 + 右侧待办项计数 */
.wb-alert-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px}
.wb-alert-count{font-size:.74rem;color:var(--text-muted);white-space:nowrap}
/* 待办提醒：强制单行；溢出后鼠标滚轮悬停其上即可横向滚动，但不显示滚动条与滑杆
   注意：这里故意不加 scroll-behavior:smooth —— 滚轮连续触发时平滑滚动会拖沓跟不上手 */
.wb-alert-grid{
  display:flex;flex-wrap:nowrap;gap:10px;
  overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;          /* Firefox：隐藏滚动条 */
  -ms-overflow-style:none;
  /* ⚠️ 上下必须留一点内边距，否则悬停时卡片的上边框会消失。
   *    原因：这个容器是横向滚动容器（overflow-y:hidden），**裁剪边界是 padding box**。
   *    卡片悬停要上移 2px，而卡片本来就正好填满容器高度 —— 一上移就跑到裁剪边界外，
   *    顶部那 ~2px 被裁掉，而 1px 的上边框正好在里面，于是"边框看起来没了"（实测踩到：
   *    悬停时卡片顶超出容器 1.88px）。留 3px 内边距给上移留出空间即可。
   *    注意只加上下内边距：横向滚动容器加左右内边距会让内容起点被吃掉。 */
  padding:3px 0;
}
.wb-alert-grid::-webkit-scrollbar{display:none;height:0}   /* Chrome/Edge：隐藏滚动条 */
/* 两侧渐隐：告诉用户"这一边还有被挡住的卡片"。
 * 为什么需要：卡片总宽 1560px 而容器只有 1256px（宽屏正好 6 张），第 7 张会被**从中间切开**；
 * 而滚动条是故意隐藏的 —— 看起来就像"卡片显示坏了"，而不是"右边还有内容"。
 * has-left / has-right 由 workbench.js 的 wbAlertSyncFade 维护：只在真的还有内容时才加，
 * 滑到尽头就撤掉，不会出现"到头了还在渐隐"的假提示。 */
.wb-alert-grid.has-right{-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 52px),transparent);mask-image:linear-gradient(90deg,#000 calc(100% - 52px),transparent)}
.wb-alert-grid.has-left{-webkit-mask-image:linear-gradient(90deg,transparent,#000 52px);mask-image:linear-gradient(90deg,transparent,#000 52px)}
.wb-alert-grid.has-left.has-right{-webkit-mask-image:linear-gradient(90deg,transparent,#000 52px,#000 calc(100% - 52px),transparent);mask-image:linear-gradient(90deg,transparent,#000 52px,#000 calc(100% - 52px),transparent)}
.wb-alert-item{display:flex;align-items:center;gap:8px;padding:12px 14px;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg);cursor:pointer;min-width:0;flex:0 0 max(176px, calc((100% - 50px) / 6));
  /* 只过渡会用到的属性。原来写的是 transition:all —— 会把布局属性也纳入过渡，
     悬停时更容易掉帧，而且以后加属性会意外产生动画。 */
  transition:transform .18s cubic-bezier(.4,0,.2,1), box-shadow .18s ease, border-color .18s ease, background-color .18s ease}
/* ↑ 宽度策略：宽屏正好显示 6 张，第 7 张起滑出可见区（被挡住的那侧会有渐隐提示）；窄屏保底 176px 不挤成一条 */
/* 悬停：抬 2px + 边框亮成这张卡的主题色 + 底色提一档 + 投影加深。
   为什么改：原来只有 translateY(-1px) 和 rgba(0,0,0,.08) 的阴影 ——
   深色主题下 8% 的黑影压在深色卡片上几乎看不见，等于悬停**没有任何反馈**（实测确认）。 */
.wb-alert-item:hover{transform:translateY(-2px);border-color:var(--ac);background:var(--bg-card);box-shadow:0 6px 16px rgba(15,23,42,.16)}
/* 深色主题要单独给一份：深底上用黑影是看不见的，得加深、再补一圈极淡的描边才"浮"得起来 */
html.theme-dark .wb-alert-item:hover{background:var(--bg-card);box-shadow:0 8px 20px rgba(0,0,0,.55),0 0 0 1px rgba(148,163,184,.14)}
/* 待办卡片：紧急态醒目（红描边 + 左红条 + 轻微呼吸动画），紧急项自动排在前面 */
.wb-alert-urgent{
  border-color:var(--danger) !important;
  border-left:4px solid var(--danger) !important;
  animation:wbAlertPulse 2.4s ease-in-out infinite;
}
.wb-alert-urgent .wb-alert-dot{animation:wbDotPulse 1.6s ease-in-out infinite}
.wb-alert-urgent .wb-alert-title{font-weight:700}
@keyframes wbAlertPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(239,68,68,0)}
  50%{box-shadow:0 0 0 4px rgba(239,68,68,.16)}
}
@keyframes wbDotPulse{
  0%,100%{transform:scale(1);opacity:1}
  50%{transform:scale(1.35);opacity:.75}
}
/* ⚠️ 紧急卡片的呼吸动画动的是 box-shadow，而 CSS 动画的优先级**高于** :hover 里的普通声明 ——
   不停掉动画的话，紧急卡片悬停时那圈投影完全不会出现（实测：阴影值一直是动画的那一帧）。
   悬停时把动画停掉，悬停反馈对它同样生效。 */
.wb-alert-urgent:hover{animation:none}
@media (prefers-reduced-motion:reduce){.wb-alert-urgent,.wb-alert-urgent .wb-alert-dot{animation:none}}
.wb-alert-dot{width:9px;height:9px;border-radius:50%;background:var(--ac);flex-shrink:0;box-shadow:0 0 0 3px var(--acbg)}
.wb-alert-text{min-width:0;flex:1}
.wb-alert-title{font-size:.82rem;font-weight:600;color:var(--ac);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wb-alert-desc{font-size:.7rem;color:var(--text-muted);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ⚠️ 这里原来有两条"响应式"规则（@media max-width:1200px/700px）设置
 *    grid-template-columns:repeat(3|2,1fr) —— 但 .wb-alert-grid 是 **display:flex**，
 *    grid-template-columns 对 flex 容器**完全无效**，那两条一直是死代码（看着像在管布局，
 *    实际什么都没做，容易误导后来的人）。布局本身已经能自适应：
 *    卡片宽度是 max(176px, (100% - 50px)/6)，窄屏自动少显示几张、靠横向滚动看其余的。
 *    所以直接删掉，不再留"看着有用其实没用"的规则。 */

/* ===== 工作台模块分组 ===== */

/* ===== 工作台深色模式 ===== */
.tab-panel.wb-dark{
  --bg-card:#1e293b;
  --border:#334155;
  --text:#f1f5f9;
  --text-muted:#94a3b8;
  --bg:#0f172a;
  --shadow-xs:none;
  background:#0f172a;
}
.wb-dark .panel-header h2{color:#f1f5f9}
.wb-dark .panel-header .panel-desc{color:#94a3b8}
.wb-dark .wb-alert{background:var(--bg-card);border-color:var(--border)}
.wb-dark .wb-alert-item{background:#0f172a;border-color:var(--border)}
.wb-dark .wb-alert-title{color:var(--ac)}
.wb-dark .wb-alert h3{color:var(--text)}
.main-area:has(.tab-panel.active.wb-dark),
.tab-content:has(.tab-panel.active.wb-dark){background:#0f172a}

/* ===== 工作台重点数据速览图表 ===== */
.wb-charts{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:20px;margin-bottom:20px}
.wb-charts h3{font-size:1rem;font-weight:600;margin-bottom:14px;color:var(--text)}
.wb-charts-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}
.wb-chart-card{border:1px solid var(--border);border-radius:var(--radius);padding:12px;background:var(--bg)}
.wb-chart-title{font-size:.78rem;color:var(--text-muted);margin-bottom:8px;font-weight:600}
.wb-chart-card canvas{height:150px !important;width:100% !important}
@media (max-width:900px){.wb-charts-grid{grid-template-columns:1fr}}

.wb-dark .wb-chart-card{background:#0f172a;border-color:#334155}
.wb-dark .wb-chart-title{color:#94a3b8}

/* ===== 工作台顶部：快捷入口 + 待办提醒 并排「一行两列」 =====
 * 为什么合并：两块原来各占一整条（实测 110px + 132px + 间距 20px = 262px），
 *   而它们都只有一行内容 —— 并排后约 132px，腾出的 ~130px 全给下面的图表。
 * align-items:start：让两张卡各自贴合内容高度（等高的那张会在窄的那张下面留一块空白）。
 * 窄屏退回上下堆叠，否则两列都挤不下。 */
/* ⚠️ 必须写 minmax(0,1fr) 而不是 1fr：
 *    `1fr` 等价于 `minmax(auto,1fr)`，而"auto 最小值"会取该列的 min-content。
 *    右列（待办）内部是一个 flex 横排 + overflow-x:auto，它的 min-content
 *    约等于 7 张卡基准宽之和（≈1240px）—— 于是右列把整行抢走，左列被挤成 176px，
 *    4 列入口卡片每张只剩 34px，字全糊在一起（实测踩到：列宽变成 176px 1239px）。
 *    把最小值显式设为 0，两列才会真正平分。 */
.wb-top{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:20px;margin-bottom:20px;
  /* 两列等高：左边是「标题 + 2 行入口」，右边是「标题 + 1 行待办」，
     内容天然差一行（实测 155px vs 132px），并排看就是一高一低。
     stretch（grid 默认值）让两张卡对齐到同一高度。 */
  align-items:stretch}
/* 并排时外边距交给 .wb-top 的 gap 统一管，避免出现"20 + 20"的双份间距 */
.wb-top .wb-quick,.wb-top .wb-alert{margin-bottom:0}
/* 右列：把待办那一行撑满剩余高度，免得卡片底部空出一块。
   .wb-alert-grid 是 flex 容器，撑高之后里面的卡片默认也会跟着拉伸（cross-axis:stretch），
   于是两张卡等高、且右列内容填满，不会出现"下面一片空"。 */
.wb-top .wb-alert{display:flex;flex-direction:column}
.wb-top .wb-alert-grid{flex:1}
@media (max-width:1000px){
  .wb-top{grid-template-columns:minmax(0,1fr)}          /* 堆叠：一行一列 */
  .wb-top .wb-alert-grid{flex:none}                     /* 堆叠时不需要撑高 */
}

/* 快捷入口 */
.wb-quick{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:20px;margin-bottom:20px}
.wb-quick h3{font-size:1rem;font-weight:600;margin-bottom:14px;color:var(--text)}
.wb-quick-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:10px}
/* 并排后每列只有半宽，8 列会把卡片压到 ~85px（"磅单数据分析"根本放不下）→ 改 4 列，
   8 个入口正好排成 2 行、全部可见、不需要滚动。 */
.wb-top .wb-quick-grid{grid-template-columns:repeat(4,1fr)}
.wb-quick-item{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--border);border-radius:10px;background:var(--bg);cursor:pointer;font-size:.8rem;font-weight:500;color:var(--text);white-space:nowrap;min-width:0;
  transition:transform .18s cubic-bezier(.4,0,.2,1), box-shadow .18s ease, border-color .18s ease, background-color .18s ease}
.wb-quick-item span:last-child{overflow:hidden;text-overflow:ellipsis}
/* 悬停与「待办提醒」卡片保持一致（原来这里是 translateY(-1px) + rgba(0,0,0,.08)，
   深色主题下几乎看不见，两块并排放在一起时差别会很明显） */
.wb-quick-item:hover{transform:translateY(-2px);box-shadow:0 6px 16px rgba(15,23,42,.16);border-color:var(--qc);background:var(--bg-card)}
html.theme-dark .wb-quick-item:hover{box-shadow:0 8px 20px rgba(0,0,0,.55),0 0 0 1px rgba(148,163,184,.14)}
.wb-quick-dot{width:9px;height:9px;border-radius:50%;background:var(--qc);flex-shrink:0;box-shadow:0 0 0 3px color-mix(in srgb,var(--qc) 18%,transparent)}
@media (max-width:700px){.wb-quick-grid,.wb-top .wb-quick-grid{grid-template-columns:repeat(2,1fr)}}

/* 生活垃圾组：6 卡固定一行 */
@media (max-width:1200px){.wb-group-live .wb-cards{grid-template-columns:repeat(3,1fr)}}
@media (max-width:700px){.wb-group-live .wb-cards{grid-template-columns:repeat(2,1fr)}}

/* ===== 水电片区/场所建议面板（可滚动） ===== */
.we-suggest-wrap{position:relative}
.we-suggest-panel{display:none;position:absolute;top:100%;left:0;right:0;z-index:120;max-height:200px;overflow-y:auto;background:var(--bg-card);border:1px solid var(--border);border-radius:8px;box-shadow:0 6px 20px rgba(0,0,0,.12);margin-top:2px}
.we-suggest-item{padding:7px 10px;font-size:.82rem;cursor:pointer;color:var(--text)}
.we-suggest-item:hover{background:var(--primary-light);color:var(--primary)}
.we-suggest-empty{padding:8px 10px;font-size:.8rem;color:var(--text-muted)}

/* 地图深色底图：瓦片反色，点位更清晰 */
#opMapContainer .leaflet-tile-pane {
  filter: invert(1) hue-rotate(180deg);
}
#opMapContainer .leaflet-marker-pane,
#opMapContainer .leaflet-popup-pane,
#opMapContainer .leaflet-control {
  filter: none;
}

/* 地图卡片筛选框压扁 */
#opMapCard select{height:22px !important;min-height:22px !important;padding:0 6px !important;font-size:.7rem !important;line-height:20px !important;box-sizing:border-box !important}

/* 地图缩放控件缩小 */
#opMapContainer .leaflet-control-zoom{box-shadow:none;border:1px solid rgba(56,130,246,.3);border-radius:6px;overflow:hidden}
#opMapContainer .leaflet-control-zoom a{width:24px !important;height:24px !important;line-height:24px !important;font-size:14px !important;background:#0d1b2e;color:#7dd3fc;border-bottom:1px solid rgba(56,130,246,.2)}
#opMapContainer .leaflet-control-zoom a:hover{background:#122a4a;color:#fff}



/* 导出长图时隐藏滚动条 */

/* 侧栏收起按钮避让：页面标题左移 */
.panel-header{padding-left:44px}

/* 磅单看板月份选择器：保留原生外观（可点击选择） */
#dashboardMonth{cursor:pointer}

/* 磅单看板浅色模式：中转站进度条文字加深 */
#tab-dashboard:not(.dash-dark) .dash-venue-val{color:#1e293b}
#tab-dashboard:not(.dash-dark) .dash-venue-name{color:#334155}

/* 只读页面：顶部提示条 + 整体禁用光标 */
.page-ro-banner{margin:0 0 12px;padding:9px 14px;border:1px solid #f59e0b;border-left:4px solid #f59e0b;background:rgba(245,158,11,.12);color:#b45309;border-radius:8px;font-size:.86rem;font-weight:600}
html.theme-dark .page-ro-banner{background:rgba(245,158,11,.16);color:#fbbf24}
.page-readonly{position:relative}
.page-readonly button:disabled{opacity:.55;cursor:not-allowed}
.page-readonly input[readonly],.page-readonly textarea[readonly]{cursor:not-allowed;background:var(--bg-sidebar-hover)}

/* 事件热力图：深色模式下把底图反色成深色，热点对比更醒目 */
html.theme-dark #evHeatMap .leaflet-tile{filter:invert(1) hue-rotate(180deg) brightness(.8) contrast(.9) saturate(1.1)}

/* 事件分布地点列表：表头固定（滚动时首行不随内容滚走；用 box-shadow 画底线下 + 强制独立绘制层，避免“漏光”） */
#tab-event-locations table thead th{position:sticky;top:0;background:var(--bg);z-index:3;box-shadow:0 1px 0 0 var(--border);will-change:transform}

/* 事件分布「导入 / 模板」下拉菜单项 hover */
.ev-io-item:hover{background:var(--bg)}

/* ===== 全局提示工具箱配套样式（见 public/js/ui-common.js）===== */
/* 按钮里的转圈：用 CSS 画，不依赖字体/图片 */
.btn-spin{
  display:inline-block;width:12px;height:12px;margin-right:6px;
  border:2px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;
  vertical-align:-2px;animation:btnSpin .7s linear infinite;
}
@keyframes btnSpin{to{transform:rotate(360deg)}}
/* "就是这一行"的闪烁高亮：只动背景色/投影，不改变布局。
 *
 * ⚠️ 这里踩过【两个】坑，都表现为"类名加上了、界面上一动不动"：
 *
 * 坑一（2026-09-18）：第一版只写了 `tr.row-flash>td{...}`，只匹配**表格行**。
 *    但磅单的记录行是 `<div class="record-row">`，不是 `<tr>` → 加了类没反应。
 *    当时的自动化测试只断言"class 存在"，所以没抓出来。现在分两条：div 版整块变色，
 *    表格版给单元格变色。
 *
 * 坑二（本次）：表格版原先用 background 做动画 —— 在深色主题下**永远不会生效**。
 *    因为 style.css 顶部有 `html.theme-dark td{background:#1e293b !important}`，
 *    而按 CSS 层叠顺序，**!important 的作者声明排在 CSS 动画之上**
 *    （normal 声明 < CSS 动画 < !important 声明），动画算出来的背景色被整段吃掉。
 *    实测证据：类名确实加在正确的 <tr> 上、连续采样 16 次全是最底层色 rgb(30,41,59)
 *    （正是 #1e293b），一点绿色中间态都没有。
 *    → 表格版改用 **inset box-shadow** 铺一层绿色：box-shadow 没有 !important 竞争者，
 *      同样不改变布局，且明暗主题都能看见。
 */
@keyframes rowFlashCard{
  0%{background:#10b981;box-shadow:0 0 0 3px rgba(16,185,129,.9)}
  45%{background:rgba(16,185,129,.5);box-shadow:0 0 0 5px rgba(16,185,129,.35)}
  100%{background:var(--bg-card);box-shadow:0 0 0 0 rgba(16,185,129,0)}
}
@keyframes rowFlashCell{
  0%{box-shadow:inset 0 0 0 9999px rgba(16,185,129,.55)}
  60%{box-shadow:inset 0 0 0 9999px rgba(16,185,129,.22)}
  100%{box-shadow:inset 0 0 0 9999px rgba(16,185,129,0)}
}
/* div 版列表（磅单记录行等）：整块变绿，结束时回到卡片底色（无缝，不会闪一下别的颜色） */
.row-flash:not(tr){animation:rowFlashCard 1.6s ease-out}
/* 表格版：给单元格铺投影（行/单元格的 background 被 theme-dark 的 !important 锁死，动不了） */
tr.row-flash>td{animation:rowFlashCell 1.6s ease-out}
/* 长操作期间禁止重复提交的鼠标样式 */
button[aria-busy="true"]{cursor:progress}

/* ===== 导入备份的进度条（系统管理 → 数据备份）=====
 * 配色跟主题走，不写死浅色值（本项目已经因此踩过好几次坑）。
 * 进度色用品牌蓝，**不用红色**：红色在这套界面里表示"欠费/告警"，
 * 拿它当进度色会让人以为出错了。 */
.adm-prog{margin:0 0 14px;padding:10px 14px;border:1px solid var(--border);border-radius:10px;background:var(--bg-card)}
/* 备份用量统计条：放在「数据备份」页顶部，显示已占多少 / 磁盘还剩多少。
   余量低于 10% 时加 is-warn（由 admin.js 的 admRenderBackupStats 切换），底色转警戒色。 */
.adm-bak-stats{margin:0 0 14px;padding:9px 14px;border:1px solid var(--border);border-radius:10px;background:var(--bg-card);font-size:.78rem;color:var(--text-muted);line-height:1.7}
.adm-bak-stats b{color:var(--text);font-variant-numeric:tabular-nums}
.adm-bak-stats.is-warn{border-color:var(--danger);background:rgba(239,68,68,.06)}
.adm-prog-head{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:.8rem;color:var(--text);margin-bottom:7px}
.adm-prog-head #admRestorePhase{font-weight:600}
.adm-prog-head #admRestorePct{font-variant-numeric:tabular-nums;font-weight:700;color:#2563eb}
html.theme-dark .adm-prog-head #admRestorePct{color:#60a5fa}
.adm-prog-track{height:10px;border-radius:6px;background:var(--border);overflow:hidden}
.adm-prog-bar{height:100%;width:0;border-radius:6px;background:linear-gradient(90deg,#3b82f6,#22d3ee);transition:width .25s ease-out}
/* 未填充部分加流动斜纹：某些阶段（解压、覆盖附件）百分比是跳变的，
 * 条纹能表明"确实在动"，不至于让人以为卡死了。 */
.adm-prog.running .adm-prog-track{background-image:linear-gradient(45deg,rgba(148,163,184,.35) 25%,transparent 25%,transparent 50%,rgba(148,163,184,.35) 50%,rgba(148,163,184,.35) 75%,transparent 75%);background-size:14px 14px;animation:admStripe .7s linear infinite}
@keyframes admStripe{from{background-position:0 0}to{background-position:14px 0}}
.adm-prog-msg{margin-top:7px;font-size:.72rem;color:var(--text-muted);word-break:break-all;line-height:1.5;min-height:1em}
/* 收尾状态：成功变绿、失败变红 ——
 * 失败时柱子可能也停在接近 100%，光看长度会误以为成功，所以必须换颜色。 */
.adm-prog.good .adm-prog-bar{background:linear-gradient(90deg,#16a34a,#4ade80)}
.adm-prog.bad .adm-prog-bar{background:linear-gradient(90deg,#dc2626,#f87171)}
html.theme-dark .adm-prog.bad .adm-prog-bar{background:linear-gradient(90deg,#ef4444,#fca5a5)}
.adm-prog.bad .adm-prog-msg{color:#b91c1c}
html.theme-dark .adm-prog.bad .adm-prog-msg{color:#fca5a5}

/* ===== 厨余垃圾月度明细：合计行 =====
 * 为什么用 box-shadow 而不是 background：
 *   深色主题有一条 `html.theme-dark td{background:#1e293b !important}`，
 *   优先级高于内联 style，实测把合计行的天蓝底吃成和普通数据行同色
 *   （都是 rgb(30,41,59)）——汇总行完全看不出来。
 *   inset box-shadow 铺色不受 background 的 !important 影响，两个主题都能正常显示。
 *
 * ⚠️ 这里必须再加一个 !important 去盖「冻结列」那条规则：
 *     .summary-table-wrap td:nth-child(2){… box-shadow:3px 0 6px -3px rgba(100,116,139,.35)}
 *     （见上文，它是给"日期/星期"这两列做横向滚动时冻结用的）
 *   它是「2 个类 + 1 个类型」的选择器，比单个 .kw-total-cell 重，
 *   会把合计行里"星期"那一格的底色阴影整个换掉 ——
 *   表现为合计行中间缺一块白（浅色深色都缺）。实测复现过，所以必须显式压过去。
 *   合计行"整行同色"是必须成立的视觉要求，冻结列的分隔阴影在这一行让位。 */
.summary-table-wrap td.kw-total-cell{box-shadow:inset 0 0 0 9999px #38bdf8 !important;color:#fff}
html.theme-dark .summary-table-wrap td.kw-total-cell{box-shadow:inset 0 0 0 9999px #0c4a6e !important;color:#e0f2fe}

/* ============================================================
   车辆维修分析 · 维修记录（2026-09-19 新增）
   只用 :root 变量色，深浅色主题自动跟随（项目约定：不写死颜色）
   ============================================================ */
.maint-stat{display:flex;flex-wrap:wrap;gap:18px;padding:12px 16px;font-size:13px;color:var(--text-muted)}
.maint-stat-item b{font-size:16px;color:var(--text);margin:0 2px}
.maint-table td,.maint-table th{white-space:nowrap}
.maint-table td.maint-note{white-space:normal;min-width:260px;max-width:420px;color:var(--text-muted);line-height:1.5}
.maint-subtable{margin:6px 0 10px;background:var(--bg)}
.maint-subtable th{font-size:12px;color:var(--text-muted)}
.maint-empty{padding:22px 16px;color:var(--text-muted);font-size:13px}
.maint-warn{color:var(--warning);cursor:help;border-bottom:1px dashed var(--warning)}
.maint-tag{display:inline-block;padding:1px 8px;border-radius:999px;font-size:12px;line-height:18px;background:var(--border);color:var(--text)}
.maint-tag-repair{background:var(--danger);color:#fff}
.maint-tag-maintain{background:var(--success);color:#fff}
.maint-hint{padding:6px 16px;font-size:13px}
/* 浅色（日间）下 #f59e0b 这种琥珀色落在白底上对比度只有 2.05，读起来很费劲。
   全局主题是浅色时换成更深的琥珀（对比度约 4.9），深色下仍用原色。 */
html:not(.theme-dark) .maint-warn{color:#b45309;border-bottom-color:#b45309}
.maint-hint-error{color:var(--danger)}
.maint-hint-info{color:var(--text-muted)}
.maint-sum-row{cursor:pointer}
.maint-sum-row:hover{background:var(--bg)}
.maint-caret{color:var(--text-muted);font-size:11px}
.maint-warnbox{margin:8px 0;padding:8px 10px;border-left:3px solid var(--warning);background:var(--bg);font-size:13px;line-height:1.6}
.maint-okbox{margin:8px 0;padding:8px 10px;border-left:3px solid var(--success);background:var(--bg);font-size:13px}
.maint-warnlist{max-height:180px;overflow:auto;color:var(--text-muted);margin-top:4px}
.maint-preview p{margin:6px 0;font-size:13px;line-height:1.7}
.maint-month-link{color:var(--primary);text-decoration:underline;cursor:pointer}
/* 维修看板的图表区：容器/整行/单位徽标**全部复用磅单可视化看板那套**
   （.dashboard-grid / .chart-wide / .chart-badge，都是全局已有的类）。
   ⚠️ 原来是自造的 .maint-charts + .maint-full-row，且多写了 padding:14px 16px ——
      实测那 16px 水平内边距让图表卡片左边从 274 变成 290，
      和它上面的统计卡片**没对齐**。现在交给全局的 .dashboard-grid（gap 20、无内边距）。 */
/* canvas 容器：给 Chart.js 一个确定高度，同时当「该月没有数据」提示的定位参照。
   400px 与磅单看板的 canvas 一致（其 .chart-card canvas 上限就是 400px）。 */
.maint-chart-box{height:400px;position:relative}
.maint-chart-box canvas{width:100%!important;height:100%!important}
/* 该月没有数据时，与其画一张空白图，不如直接说明（原先是排名表里的一行字） */
.maint-chart-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--text-muted);font-size:13px}
.maint-chart-empty[hidden]{display:none}
/* 看板顶部「未分类」说明行（不是卡片，但要一眼看到，所以用警示色）。
   注意左右内边距为 0：图表区已经不再自己加内边距，这里也要跟着对齐。 */
.maint-stat-note{padding:0 0 12px;font-size:13px;line-height:1.7}
/* 必填项没填时的标红（配合上传前的兜底弹窗：一眼看出要改哪个框） */
.input-invalid{border-color:#ef4444!important;box-shadow:0 0 0 2px rgba(239,68,68,0.18)!important}

/* ===== 维修记录 · 手工录入/编辑表单（弹窗内）===== */
.maint-form{display:grid;grid-template-columns:1fr 1fr;gap:10px 16px;max-height:52vh;overflow-y:auto;padding-right:4px}
.maint-form-row{display:flex;flex-direction:column;gap:4px;font-size:.8rem;color:var(--text-muted)}
.maint-form-row input,.maint-form-row select,.maint-form-row textarea{
  width:100%;box-sizing:border-box;padding:7px 9px;border:1px solid var(--border);border-radius:8px;
  background:var(--bg-card);color:var(--text);font-size:.85rem;font-family:inherit}
.maint-form-row input:focus,.maint-form-row select:focus,.maint-form-row textarea:focus{border-color:var(--primary);outline:none}
.maint-form-wide{grid-column:1/-1}
.maint-req{color:#ef4444;font-weight:700}
@media (max-width:560px){.maint-form{grid-template-columns:1fr}}
/* 明细表：整行可点即编辑，所以给手型光标 + 悬停提示 */
.maint-data-row{cursor:pointer}
.maint-data-row:hover td{background:var(--hover)}
/* 导入预览：「未能导入」的行必须一眼看到（用户要求「导入失败要提示第几行」）
 * ⚠️ 红色分深浅两套：#ef4444 在浅色底上只有 3.4:1（用户为浅色可读性报过 bug），
 *    所以浅色用更深的 #b91c1c（实测 5.9:1），深色用更亮的 #f87171（实测 5.2:1）。
 *    .maint-skipnote 取代原来的行内 style="color:#ef4444" —— 行内样式没法按主题覆盖。 */
.maint-failbox{border-left-color:#ef4444!important;background:rgba(239,68,68,.08)}
.maint-failbox>b,.maint-skipnote{color:#b91c1c}
html.theme-dark .maint-failbox>b,html.theme-dark .maint-skipnote{color:#f87171}
.maint-skipnote{font-weight:700}
/* 浅色下 .maint-warnlist 用的 --text-muted 只有 4.29:1；这一块里逐行列出的就是
 * "第几行"，是用户唯一能照着去 Excel 找的线索，所以单独加深（实测 9.3:1）。*/
html:not(.theme-dark) .maint-failbox .maint-warnlist{color:#334155}
.maint-warnline{padding:3px 0;line-height:1.6;border-bottom:1px dashed var(--border-light)}
.maint-warnline:last-child{border-bottom:none}