/* ============ JT/T 808 · JT/T 1078 车辆管理平台 - 样式 ============ */
:root {
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --primary-light: #dbeafe;
  --success: #16a34a;
  --success-light: #dcfce7;
  --warning: #d97706;
  --warning-light: #fef3c7;
  --danger: #dc2626;
  --danger-light: #fee2e2;
  --info: #0891b2;
  --info-light: #cffafe;
  --gray-50: #f8fafc;
  --gray-100: #f1f5f9;
  --gray-200: #e2e8f0;
  --gray-300: #cbd5e1;
  --gray-400: #94a3b8;
  --gray-500: #64748b;
  --gray-600: #475569;
  --gray-700: #334155;
  --gray-800: #1e293b;
  --gray-900: #0f172a;
  --sidebar-w: 220px;
  --radius: 10px;
  --shadow: 0 1px 3px rgba(15, 23, 42, .08), 0 1px 2px rgba(15, 23, 42, .04);
  --shadow-lg: 0 10px 25px rgba(15, 23, 42, .12);
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; }
/* 移动端「一滑屏就退出登录」防线 ①：关掉浏览器原生下拉刷新 / 过度滚动导航。
   本平台是固定布局的单页应用（.content 内部滚动），页面向下拖拽没有任何语义，
   只会触发浏览器把整页重载 —— 而重载在修复前等于退出登录（见 app.js bootRestore）。
   这里在根与滚动容器两处都收口：根挡住浏览器 UI 级下拉刷新，容器挡住滚动链上溢。

   ⚠ 2026-10-24 补 x 轴：上一条原先只写了 overscroll-behavior-y（纵向），
   横向仍是默认 auto ⇒ 移动端左右滑到内容边界即触发浏览器「横滑前进/后退」
   手势导航，页面被导航走并重载，复现同一句报障「H5 左右滑动都会退出登录」。
   故改为两轴一次收口：none = x/y 的过度滚动与滚动链全部断开。
   注意 overscroll-behavior 不继承，.content / #login-view .intro 等自有滚动
   容器各自已单独声明（见 .content 的 contain），不依赖本条。 */
html, body { overscroll-behavior: none; }
body {
  font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", system-ui, sans-serif;
  background: var(--gray-50);
  color: var(--gray-800);
  font-size: 14px;
  line-height: 1.5;
}
a { color: var(--primary); text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
input, select, textarea { font-family: inherit; font-size: 13px; }

/* ============ 登录页 ============ */
#login-view {
  display: none;
  position: fixed; inset: 0;
  background: linear-gradient(135deg, #1e3a8a 0%, #2563eb 50%, #3b82f6 100%);
  align-items: center; justify-content: center;
  z-index: 100;
}
#login-view.active { display: flex; }
.login-card {
  background: #fff; border-radius: 16px; padding: 40px 44px;
  width: 400px; box-shadow: 0 25px 60px rgba(0,0,0,.3);
}
.login-card .logo {
  display: flex; align-items: center; gap: 12px; margin-bottom: 8px;
}
.login-card .logo .logo-icon {
  width: 44px; height: 44px; border-radius: 12px;
  background: linear-gradient(135deg, #2563eb, #3b82f6);
  color: #fff; display: flex; align-items: center; justify-content: center;
  font-size: 22px;
}
.login-card h1 { font-size: 20px; color: var(--gray-900); }
.login-card .subtitle { color: var(--gray-500); font-size: 13px; margin-bottom: 28px; }
.form-group { margin-bottom: 16px; }
.form-group label { display: block; font-size: 13px; color: var(--gray-600); margin-bottom: 6px; font-weight: 500; }
.form-group input, .form-group select {
  width: 100%; padding: 10px 12px; border: 1px solid var(--gray-300);
  border-radius: 8px; outline: none; transition: border .15s, box-shadow .15s;
  background: #fff;
}
.form-group input:focus, .form-group select:focus {
  border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .12);
}
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 16px; border: 1px solid transparent; border-radius: 8px;
  font-size: 13px; font-weight: 500; transition: all .15s;
  background: var(--gray-100); color: var(--gray-700);
}
.btn:hover { filter: brightness(.97); }
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-dark); }
.btn-success { background: var(--success); color: #fff; }
.btn-danger { background: var(--danger); color: #fff; }
.btn-outline { background: #fff; border-color: var(--gray-300); color: var(--gray-600); }
.btn-outline:hover { border-color: var(--primary); color: var(--primary); }
.btn-sm { padding: 5px 10px; font-size: 12px; border-radius: 6px; }
.btn-block { width: 100%; }
.login-tip { margin-top: 16px; font-size: 12px; color: var(--gray-400); text-align: center; }

/* ============ 布局 ============ */
#app {
  display: none;
  height: 100vh; /* 旧浏览器回退 */
  height: 100dvh; /* 移动端动态视口：避开地址栏/工具栏遮挡，使底栏与内容不被裁切 */
  overflow: hidden;
}
#app.active { display: flex; }
.sidebar {
  width: var(--sidebar-w); min-width: var(--sidebar-w);
  background: var(--gray-900); color: #cbd5e1;
  display: flex; flex-direction: column;
}
.sidebar .brand {
  display: flex; align-items: center; gap: 10px;
  padding: 18px 16px; border-bottom: 1px solid rgba(255,255,255,.08);
}
.sidebar .brand .logo-icon {
  width: 36px; height: 36px; border-radius: 10px;
  background: linear-gradient(135deg, #3b82f6, #2563eb);
  color: #fff; display: flex; align-items: center; justify-content: center; font-size: 18px;
}
.sidebar .brand .title { color: #fff; font-weight: 600; font-size: 14px; line-height: 1.3; }
.sidebar .brand .title small { display: block; color: var(--gray-400); font-weight: 400; font-size: 11px; }
.nav { flex: 1; padding: 12px 8px; overflow-y: auto; }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; margin-bottom: 2px; border-radius: 8px;
  cursor: pointer; color: var(--gray-400); font-size: 13.5px;
  transition: background .15s, color .15s;
  user-select: none;
}
.nav-item:hover { background: rgba(255,255,255,.06); color: #e2e8f0; }
.nav-item.active { background: var(--primary); color: #fff; }
.nav-item .icon { font-size: 16px; width: 20px; text-align: center; }
.nav-item .badge {
  margin-left: auto; background: var(--danger); color: #fff;
  font-size: 11px; padding: 1px 7px; border-radius: 10px; font-weight: 600;
}
.sidebar .user-box {
  padding: 12px 16px; border-top: 1px solid rgba(255,255,255,.08);
  display: flex; align-items: center; gap: 10px;
}
.sidebar .user-box .avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--primary); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 14px;
}
.sidebar .user-box .uname { font-size: 13px; color: #e2e8f0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* K9414：退出按钮可见性。原色 --gray-500(#64748b) 落在侧栏 --gray-900(#0f172a) 底上
   实测只有 3.75:1，低于 WCAG AA 正文门槛 4.5:1；再叠上 H5 低亮度/室外，几乎糊进底色
   （2026-10-24 用户报障「账户名旁边的退出按钮颜色看不见」，真机截图复现）。
   改为与侧栏正文同档亮度 #cbd5e1（12.6:1），并补 hover/active 反馈与 8px 圆角命中区。
   图形改由 inline SVG 用 currentColor 描边 ⇒ 颜色随 color 生效，且不依赖系统字体缺字。 */
.sidebar .user-box .logout-btn {
  background: none; border: none; color: #cbd5e1; font-size: 16px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 8px; padding: 0;
  transition: color .15s ease, background-color .15s ease;
}
.sidebar .user-box .logout-btn svg { width: 17px; height: 17px; display: block; }
.sidebar .user-box .logout-btn:hover { color: #fff; background: rgba(255,255,255,.10); }
.sidebar .user-box .logout-btn:active { color: #f87171; background: rgba(248,113,113,.16); }

.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.topbar {
  height: 56px; min-height: 56px; background: #fff;
  border-bottom: 1px solid var(--gray-200);
  display: flex; align-items: center; padding: 0 24px; gap: 16px;
}
.topbar .page-title { font-size: 17px; font-weight: 600; color: var(--gray-900); }
.topbar .conn-status {
  margin-left: auto; display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--gray-500);
}
.conn-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--gray-400); }
.conn-dot.online { background: var(--success); box-shadow: 0 0 0 3px var(--success-light); }
.conn-dot.offline { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-light); }

/* overscroll-behavior 取 contain（非 none）：本容器自身仍可滚到边界，
   但不把滚动链上溢给 body ⇒ 横向滚到尽头也不会触发浏览器前进/后退导航。
   注意 overflow-y:auto 会让 overflow-x 计算为 auto（CSS 规范），即本容器横向
   本来就可滚（K9275 记录的窄屏横溢 101px 即由此），所以 x 轴必须一并 contain。 */
.content { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 20px 24px; }
.view { display: none; }
.view.active { display: block; }

/* ============ 卡片 ============ */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; margin-bottom: 20px; }
.stat-card {
  background: #fff; border-radius: var(--radius); padding: 18px 20px;
  box-shadow: var(--shadow); display: flex; align-items: center; gap: 14px;
}
.stat-card .stat-icon {
  width: 46px; height: 46px; border-radius: 12px;
  display: flex; align-items: center; justify-content: center; font-size: 22px;
}
.stat-card .stat-info .stat-num { font-size: 24px; font-weight: 700; color: var(--gray-900); line-height: 1.2; }
.stat-card .stat-info .stat-label { font-size: 12.5px; color: var(--gray-500); }
.stat-card .stat-info .stat-sub { font-size: 11.5px; color: var(--gray-400); }

.card {
  background: #fff; border-radius: var(--radius); box-shadow: var(--shadow);
  margin-bottom: 16px; overflow: hidden;
}
.card-header {
  padding: 14px 20px; border-bottom: 1px solid var(--gray-100);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.card-header h3 { font-size: 15px; color: var(--gray-800); font-weight: 600; }
.card-body { padding: 16px 20px; }
.card-body.no-pad { padding: 0; }

.panel-grid { display: grid; grid-template-columns: 1fr 320px; gap: 16px; align-items: start; }
.panel-grid.wide-left { grid-template-columns: 1.6fr 1fr; }
/* K9299：≤1200 单列档必须 minmax(0,1fr)——1fr 的轨道下限是 min-content，
   仪表盘「最新报警」摘要行（.alarm-brief：.a-brief nowrap + .a-time/.a-count nowrap，
   min-width:0 只允许布局期收缩、挡不住固有尺寸测算）会把轨道撑到 ≈425px ⇒ 窄屏 +47px 横溢。 */
@media (max-width: 1200px) { .panel-grid, .panel-grid.wide-left { grid-template-columns: minmax(0, 1fr); } }

/* ============ 表格 ============ */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead th {
  text-align: left; padding: 10px 14px; background: var(--gray-50);
  color: var(--gray-500); font-weight: 600; font-size: 12px;
  border-bottom: 1px solid var(--gray-200); white-space: nowrap;
}
tbody td { padding: 10px 14px; border-bottom: 1px solid var(--gray-100); white-space: nowrap; }
tbody tr:hover { background: var(--gray-50); }
tbody tr:last-child td { border-bottom: none; }

/* ============ 标签/徽章 ============ */
.tag { display: inline-block; padding: 2px 10px; border-radius: 20px; font-size: 12px; font-weight: 500; }
.tag-green { background: var(--success-light); color: var(--success); }
.tag-gray { background: var(--gray-100); color: var(--gray-500); }
.tag-red { background: var(--danger-light); color: var(--danger); }
.tag-orange { background: var(--warning-light); color: var(--warning); }
.tag-blue { background: var(--primary-light); color: var(--primary); }
.tag-cyan { background: var(--info-light); color: var(--info); }

/* ============ 地图 ============ */
.map-container { width: 100%; height: 100%; min-height: 420px; position: relative; isolation: isolate; background: #e8edf2; }
/* K9275：地图内部 pane 自带 z-index:1000（外部 SDK），若不隔离会逃出容器盖住固定底栏(.m-tabbar z=115)
   ⇒ 移动端仪表盘地图范围内底栏点击被地图吃掉（verify-mobile-tabs ④ 长期红）。isolation 把地图层圈回自身层叠上下文。 */
.map-container .map-fallback {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; color: var(--gray-500); font-size: 14px; gap: 8px;
  background: repeating-linear-gradient(45deg, #f1f5f9, #f1f5f9 12px, #e8edf2 12px, #e8edf2 24px);
  text-align: center; padding: 20px;
}
/* 地图「默认自动加载」过渡骨架（SDK 拉取期间显示，与降级态同风格，避免布局跳动） */
.map-loading-tip {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px;
  color: var(--gray-500); font-size: 14px; font-weight: 500;
  background: repeating-linear-gradient(45deg, #f1f5f9, #f1f5f9 12px, #e8edf2 12px, #e8edf2 24px);
  text-align: center; padding: 20px;
}

/* 车辆列表（监控页侧栏） */
.vehicle-list { max-height: 460px; overflow-y: auto; }
.vehicle-item {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-bottom: 1px solid var(--gray-100); cursor: pointer; transition: background .12s;
}
.vehicle-item:hover { background: var(--gray-50); }
.vehicle-item.active { background: var(--primary-light); }
.vehicle-item .v-status { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.v-online { background: var(--success); box-shadow: 0 0 0 3px var(--success-light); }
.v-offline { background: var(--gray-300); }
.v-alarm { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-light); }
.vehicle-item .v-info { flex: 1; min-width: 0; }
.vehicle-item .v-plate { font-weight: 600; font-size: 13.5px; color: var(--gray-800); }
.vehicle-item .v-meta { font-size: 11.5px; color: var(--gray-400); }
.vehicle-item .v-status.v-drive { background: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,.18); }
.vehicle-item .v-status.v-park { background: #f59e0b; box-shadow: 0 0 0 3px rgba(245,158,11,.18); }
.vehicle-item .v-status.v-off { background: #6b7280; }

/* 电量徽标 */
.bat { font-size: 11px; margin-left: 6px; padding: 1px 6px; border-radius: 9px; white-space: nowrap; vertical-align: middle; }
.bat-full { background: #dcfce7; color: #166534; }
.bat-high { background: #dbeafe; color: #1e40af; }
.bat-mid { background: #fef9c3; color: #854d0e; }
.bat-low { background: #fee2e2; color: #b91c1c; }

/* 车辆列表底部筛选栏 */
.vfilter-bar { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 12px; border-bottom: 1px solid var(--gray-100); background: var(--gray-50); }
.vfilter-bar .vf { border: 1px solid var(--gray-200); background: #fff; color: var(--gray-600); font-size: 12px; padding: 4px 10px; border-radius: 14px; cursor: pointer; transition: all .15s; }
.vfilter-bar .vf:hover { border-color: var(--primary); color: var(--primary); }
.vfilter-bar .vf.active { background: var(--primary); border-color: var(--primary); color: #fff; }

/* ============ P0-② 实时监控：右列只留车辆列表，与左列地图等高铺满 ============
   详情区已搬到地图悬浮卡（原「列表 + 详情」上下叠会把列表压扁、留白）。 */
.panel-grid.monitor-grid { align-items: stretch; }
.monitor-side { display: flex; flex-direction: column; }
.monitor-side .card-body { flex: 1 1 auto; min-height: 0; overflow: hidden; }
.monitor-side .vehicle-list { max-height: none; height: 100%; overflow-y: auto; }
@media (max-width: 1200px) {
  /* 单列档：不再强行等高，列表恢复限高滚动 */
  .monitor-side .vehicle-list { height: auto; max-height: 460px; }
}

/* ============ 模态框 ============ */
.modal-mask {
  position: fixed; inset: 0; background: rgba(15,23,42,.45);
  display: none; align-items: center; justify-content: center; z-index: 200;
  backdrop-filter: blur(2px);
}
.modal-mask.active { display: flex; }
.modal {
  background: #fff; border-radius: 14px; width: 520px; max-width: calc(100vw - 40px);
  max-height: 86vh; overflow-y: auto; box-shadow: var(--shadow-lg);
}
.modal-header { padding: 16px 20px; border-bottom: 1px solid var(--gray-100); display: flex; align-items: center; justify-content: space-between; }
.modal-header h3 { font-size: 16px; color: var(--gray-900); }
.modal-close { background: none; border: none; font-size: 18px; color: var(--gray-400); cursor: pointer; }
.modal-close:hover { color: var(--gray-700); }
.modal-body { padding: 20px; }
.modal-footer { padding: 14px 20px; border-top: 1px solid var(--gray-100); display: flex; justify-content: flex-end; gap: 10px; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }

/* ============ Toast ============ */
#toast-wrap { position: fixed; top: 20px; right: 20px; z-index: 300; display: flex; flex-direction: column; gap: 8px; }
.toast {
  background: var(--gray-900); color: #fff; padding: 11px 16px; border-radius: 10px;
  font-size: 13px; box-shadow: var(--shadow-lg); min-width: 220px; max-width: 380px;
  display: flex; align-items: center; gap: 8px;
  animation: slideIn .25s ease;
}
.toast.success { background: var(--success); }
.toast.error { background: var(--danger); }
.toast.warn { background: var(--warning); }
@keyframes slideIn { from { transform: translateX(30px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
.toast.fade-out { opacity: 0; transform: translateX(30px); transition: all .3s; }

/* ============ 报警流 ============ */
.alarm-stream { max-height: 380px; overflow-y: auto; }
/* 首页报警优化：首页报警卡默认折叠为一行摘要（点击展开完整列表，避免高频报警占满右列） */
.alarm-brief {
  display: flex; align-items: center; gap: 8px; padding: 11px 14px;
  cursor: pointer; font-size: 13px; border-bottom: 1px solid var(--gray-100);
  user-select: none;
}
.alarm-brief:hover { background: var(--gray-50); }
.alarm-brief .a-icon { font-size: 16px; }
.alarm-brief .a-brief {
  flex: 1; min-width: 0; font-weight: 500; color: var(--gray-800);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.alarm-brief .a-time { font-size: 11.5px; color: var(--gray-400); white-space: nowrap; }
.alarm-brief .a-count {
  font-size: 11px; color: var(--gray-500); background: var(--gray-100);
  padding: 1px 8px; border-radius: 999px; white-space: nowrap;
}
.alarm-brief .a-caret { font-size: 11px; color: var(--gray-400); transition: transform .2s; }
.alarm-brief.expanded { border-bottom: none; }
.alarm-brief.expanded .a-caret { transform: rotate(180deg); }
/* 首页「车队列表」（Jack 2026-10-14 拍板 B 方案：左列大地图 / 右列「最新报警 + 车队列表」） */
/* #dash-map 高度与右列（报警卡 + 车队列表卡）齐平；窄屏单独收窄，避免一屏放不下 */
#dash-map { height: 560px; }

/* ============ K9257 实时监控地图高度（2026-10-14，Jack 真机截图反馈） ============
   问题：`#monitor-map` 高度原为**内联** `calc(100vh - 200px);min-height:500px`（app.js renderMonitor），
   内联优先级高于任何 CSS 类 ⇒ 手机档拿不到收窄；实测 390×844 下地图 644px = 占视口 76.3%，
   车辆列表被推到首屏外（顶部 y=966 > 可用 790）⇒ 用户「操作不了其他界面」。
   方案：高度改由 CSS 承担 —— 桌面（≥768px）沿用原内联值（逐像素零回归），
        ≤767px 手机档收窄（与 K967/K1029 同断点），让「地图 + 车辆列表」同屏可见。
   `#monitor-map` 为 id 选择器，优先级高于 `.map-container`（class）的 min-height:420px。 */
#monitor-map { height: calc(100vh - 200px); min-height: 500px; }
@media (max-width: 767px) {
  #monitor-map { height: 40vh; min-height: 220px; }
}

.fleet-tabs { display: flex; gap: 4px; align-items: center; }
.fleet-tab {
  border: 0; background: none; font-family: inherit; font-size: 12.5px;
  color: var(--gray-500); padding: 4px 10px; border-radius: 6px; cursor: pointer;
}
.fleet-tab:hover { background: var(--gray-100); }
.fleet-tab.on { background: var(--primary-light); color: var(--primary); font-weight: 600; }
.fleet-list { max-height: 470px; overflow-y: auto; }
.fleet-group + .fleet-group { border-top: 1px solid var(--gray-100); }
/* K9256: 一级「企业」头行（实体、带客户/自营徽标 + N 台 · 在线 M） */
.fleet-ogn {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  border: 0; background: var(--gray-50); font-family: inherit; font-size: 13.5px;
  padding: 10px 16px; cursor: pointer; border-bottom: 1px solid var(--gray-100);
}
.fleet-ogn:hover { background: var(--gray-100); }
.fleet-ogn .og-arrow { flex: none; width: 12px; color: var(--gray-500); font-size: 11px; }
.fleet-ogn .og-name { font-weight: 700; color: var(--gray-900); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fleet-ogn .og-badge {
  flex: none; font-size: 10px; padding: 1px 6px; border-radius: 4px;
  background: var(--gray-200); color: var(--gray-600); font-weight: 500;
}
.fleet-ogn .og-badge.cust { background: var(--info-light); color: var(--info); }
.fleet-ogn .og-count { margin-left: auto; font-size: 11.5px; color: var(--gray-500); white-space: nowrap; }
.fleet-ogn .og-online { font-size: 11.5px; color: var(--success); white-space: nowrap; }
.fleet-ogn .og-online.zero { color: var(--gray-400); }
.fleet-gh {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  border: 0; background: none; font-family: inherit; font-size: 13px;
  padding: 9px 16px; cursor: pointer;
}
.fleet-gh:hover { background: var(--gray-50); }
.fleet-gh .fg-arrow { flex: none; width: 12px; color: var(--gray-400); font-size: 11px; }
.fleet-gh .fg-name { font-weight: 600; color: var(--gray-800); }
.fleet-gh .fg-count { font-size: 11.5px; color: var(--gray-400); }
.fleet-gh .fg-online { margin-left: auto; font-size: 11.5px; color: var(--success); }
.fleet-gh .fg-online.zero { color: var(--gray-400); }
/* 二级（车队）整体缩进；「未编车队」弱化，与真实车队区分 */
.og-body .fleet-gh { padding-left: 30px; font-size: 12.5px; }
.og-body .fleet-gh .fg-name { font-weight: 600; color: var(--gray-700); }
.og-body .fleet-gh .fg-name.fg-name-muted { font-weight: 500; color: var(--gray-500); }
.og-body .fleet-row { padding-left: 48px; }
/* 折叠：一级塌陷整家企业（隐藏 .og-body），二级只塌陷该车队行 */
.fleet-group.collapsed .og-body { display: none; }
.fleet-team.collapsed .fleet-rows { display: none; }
.fleet-row {
  display: flex; align-items: center; gap: 8px; font-size: 12.5px;
  padding: 7px 16px 7px 34px; border-top: 1px solid var(--gray-50);
}
.fleet-row:hover { background: var(--gray-50); }
.fleet-row .fr-plate { font-weight: 600; color: var(--primary); cursor: pointer; }
.fleet-row .fr-plate:hover { text-decoration: underline; }
.fleet-row .fr-term { color: var(--gray-400); font-size: 11.5px; }
.fleet-row .fr-time { margin-left: auto; color: var(--gray-400); font-size: 11.5px; white-space: nowrap; }
@media (max-width: 767px) {
  #dash-map { height: 360px; }
  .fleet-list { max-height: 340px; }
}
.alarm-item {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-bottom: 1px solid var(--gray-100); font-size: 13px;
}
.alarm-item .a-icon { font-size: 18px; }
.alarm-item .a-info { flex: 1; min-width: 0; }
.alarm-item .a-title { font-weight: 500; color: var(--gray-800); }
.alarm-item .a-time { font-size: 11.5px; color: var(--gray-400); }
.alarm-item .a-actions button { margin-left: 4px; }

/* ============ 视频页 ============ */
.video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
.video-cell {
  aspect-ratio: 16/9; background: #0f172a; border-radius: 10px; overflow: hidden;
  position: relative;
}
/* K979 V2.2：格子放大（CSS 覆盖层，不断流不改布局） */
.video-cell.cell-zoomed {
  position: fixed; inset: 4%; width: auto; height: auto; z-index: 9999;
  box-shadow: 0 24px 64px rgba(0,0,0,.55); border-radius: 12px;
}
.video-cell.cell-zoomed .v-cell-toolbar { z-index: 20; }
.video-cell > video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; background: #000; z-index: 1; display: block;
}
.video-cell .v-cell-label { position: absolute; top: 8px; left: 10px; color: rgba(255,255,255,.85); font-size: 12px; z-index: 5; text-shadow: 0 1px 2px rgba(0,0,0,.6); pointer-events: none; }
.video-cell .v-cell-stats { position: absolute; top: 30px; left: 10px; color: rgba(255,255,255,.6); font-size: 11px; z-index: 5; pointer-events: none; }
.video-cell .v-cell-status {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: calc(100% - 24px); color: rgba(255,255,255,.55); font-size: 12.5px;
  text-align: center; padding: 0; z-index: 2; pointer-events: none;
}
.video-cell .v-cell-status.on { color: #4ade80; }
/* K917: 失败/无流态要能点「重试」，故恢复指针事件（基类为 pointer-events:none） */
.video-cell .v-cell-status.err { color: #fca5a5; pointer-events: auto; }
.video-cell .v-cell-status a { pointer-events: auto; color: inherit; text-decoration: underline; cursor: pointer; }
.video-cell .v-cell-toolbar {
  position: absolute; left: 8px; right: 8px; bottom: 8px; z-index: 6;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  background: rgba(15, 23, 42, .55); padding: 6px; border-radius: 8px;
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
}
.video-cell .v-cell-toolbar select { max-width: 96px; }
.video-cell .v-cell-toolbar .vc-terminal { flex: 1 1 88px; min-width: 60px; max-width: 160px; }
.video-cell .v-cell-toolbar .btn { flex: 0 0 auto; padding: 5px 10px; font-size: 12px; line-height: 1.4; }

/* ============ 视频中心 tab ============ */
.video-tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.vtab {
  padding: 8px 16px; border: 1px solid var(--border, #e2e8f0); background: #fff; color: var(--gray-600, #475569);
  border-radius: 8px; cursor: pointer; font-size: 14px; transition: all .15s;
}
.vtab:hover { border-color: var(--primary, #2563eb); color: var(--primary, #2563eb); }
.vtab.active { background: var(--primary, #2563eb); border-color: var(--primary, #2563eb); color: #fff; }

/* P0-③ 实时监控右列双 Tab（云台 / 会话）：原「会话卡 + 云台卡」上下堆叠改单卡切换，释放垂直空间 */
.video-side-head { padding: 10px 14px; gap: 10px; }
.vs-tabs { display: flex; gap: 6px; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; }
.vs-tab {
  padding: 6px 12px; border: 1px solid var(--border, #e2e8f0); background: #fff; color: var(--gray-600, #475569);
  border-radius: 8px; cursor: pointer; font-size: 13px; line-height: 1.4; white-space: nowrap; transition: all .15s;
}
.vs-tab:hover { border-color: var(--primary, #2563eb); color: var(--primary, #2563eb); }
.vs-tab.active { background: var(--primary, #2563eb); border-color: var(--primary, #2563eb); color: #fff; }
.vs-pane.vs-hidden, .ptz-more.vs-hidden { display: none !important; }
.ptz-more-toggle {
  width: 100%; margin-top: 12px; display: flex; align-items: center; justify-content: center; gap: 6px;
}
.ptz-more-toggle .pm-caret { display: inline-block; transition: transform .2s ease; }
.ptz-more-toggle.open .pm-caret { transform: rotate(180deg); }
/* 车辆信号设置（P1-C） */
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px 18px; }
.input-unit { margin-left: 6px; color: var(--gray-500, #64748b); font-size: 13px; }
.hint { background: #fff7ed; border: 1px solid #fed7aa; color: #c2410c; padding: 8px 12px; border-radius: 8px; font-size: 13px; margin-bottom: 12px; }
.switch { position: relative; display: inline-block; width: 44px; height: 24px; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider { position: absolute; cursor: pointer; inset: 0; background: #cbd5e1; border-radius: 24px; transition: .2s; }
.switch .slider:before { content: ""; position: absolute; height: 18px; width: 18px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: .2s; }
.switch input:checked + .slider { background: var(--primary, #2563eb); }
.switch input:checked + .slider:before { transform: translateX(20px); }
.pb-transport { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.file-card {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: #f8fafc; border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  padding: 12px 14px; margin-bottom: 10px; cursor: pointer; transition: all .15s;
}
.file-card:hover { border-color: var(--primary, #2563eb); background: #eff6ff; }
.file-card .fc-head { display: flex; gap: 8px; align-items: center; }
.file-card .fc-ch { font-weight: 600; color: var(--gray-800, #1e293b); }
.file-card .fc-type { font-size: 12px; color: #fff; background: var(--info, #0ea5e9); padding: 1px 8px; border-radius: 6px; }
.file-card .fc-time { color: var(--gray-600, #475569); flex: 1; }
.file-card .fc-play { font-size: 13px; color: var(--primary, #2563eb); white-space: nowrap; }

/* ============ 轨迹 ============ */
.track-controls {
  display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; padding: 16px 20px;
  background: #fff; border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 16px;
}
.track-controls .form-group { margin-bottom: 0; min-width: 150px; }
.track-progress-wrap { display: flex; gap: 8px; align-items: center; flex: 1; min-width: 240px; }
.track-progress-wrap #trk-progress { flex: 1; min-width: 120px; accent-color: var(--primary, #2563eb); }
.track-progress-wrap .trk-speed { width: auto; }

/* ============ K9251：轨迹回放速度曲线（零依赖自绘 SVG） ============ */
.trk-chart-flex { display: flex; gap: 16px; align-items: stretch; }
.trk-chart-wrap { position: relative; flex: 1 1 auto; min-width: 0; }
.trk-chart-wrap .trk-empty { display: flex; align-items: center; justify-content: center; height: 170px; color: var(--gray-400, #94a3b8); font-size: 13px; }
#trk-speed-svg { display: block; width: 100%; height: 170px; touch-action: pan-y; }
.trk-grid { stroke: #e6e9ef; stroke-width: 1; }
.trk-ylab { fill: #94a3b8; font-size: 11px; }
.trk-area { fill: rgba(37, 99, 235, .10); stroke: none; }
.trk-line { fill: none; stroke: #2563eb; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.trk-over { fill: none; stroke: #dc2626; stroke-width: 3; stroke-linejoin: round; stroke-linecap: round; }
.trk-playhead { stroke: #0f9d58; stroke-width: 2; }
.trk-hover-line { stroke: #94a3b8; stroke-width: 1; stroke-dasharray: 3 3; }
.trk-hover-dot { fill: #2563eb; stroke: #fff; stroke-width: 1.5; }
.trk-tip {
  position: absolute; top: 0; left: 0; transform: translate(-50%, -4px);
  background: #1b2430; color: #fff; font-size: 12px; padding: 2px 8px; border-radius: 6px;
  white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity .12s;
}
.trk-tip.show { opacity: 1; }
.trk-stats { flex: 0 0 152px; display: grid; grid-template-columns: 1fr; gap: 6px; align-content: start; }
.trk-stat { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; border-bottom: 1px dashed #eef1f6; padding-bottom: 4px; }
.trk-stat .k { color: var(--gray-400, #8a94a6); }
.trk-stat .v { font-weight: 600; color: var(--gray-800, #1b2430); }
.trk-axis { position: relative; height: 18px; margin: 6px 14px 0 46px; }
.trk-tick { position: absolute; transform: translateX(-50%); font-size: 11px; color: #94a3b8; white-space: nowrap; }
.trk-table-head { cursor: pointer; user-select: none; }
.trk-table-head .trk-fold-hint { font-size: 12px; color: #94a3b8; margin-left: 8px; font-weight: 400; }
.trk-table-card.folded #trk-table-body-wrap { display: none; }
@media (max-width: 900px) {
  .trk-chart-flex { flex-direction: column; }
  .trk-stats { flex: none; grid-template-columns: repeat(2, 1fr); }
  .trk-axis { margin-left: 46px; margin-right: 14px; }
}
@media (max-width: 560px) {
  .trk-axis { margin-left: 0; }
}

/* ============ 指令中心 ============ */
.cmd-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
.cmd-card { background: #fff; border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px; }
.cmd-card h4 { font-size: 14px; color: var(--gray-800); margin-bottom: 4px; display: flex; align-items: center; gap: 8px; }
.cmd-card .cmd-desc { font-size: 12px; color: var(--gray-400); margin-bottom: 12px; }
.cmd-card .form-group { margin-bottom: 10px; }
.cmd-card .btn { width: 100%; }

/* ============ 其他 ============ */
.empty-tip { text-align: center; padding: 40px 20px; color: var(--gray-400); font-size: 13px; }
.loading-tip { text-align: center; padding: 24px; color: var(--gray-400); font-size: 13px; }
.mt-8 { margin-top: 8px; } .mt-16 { margin-top: 16px; } .mb-8 { margin-bottom: 8px; } .mb-16 { margin-bottom: 16px; }
.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; }
.text-muted { color: var(--gray-500); } .text-sm { font-size: 12.5px; }
.text-danger { color: var(--danger); } .text-success { color: var(--success); }
.font-bold { font-weight: 600; }
.nowrap { white-space: nowrap; }
.scrollbar::-webkit-scrollbar { width: 6px; height: 6px; }
.scrollbar::-webkit-scrollbar-thumb { background: var(--gray-300); border-radius: 3px; }
.scrollbar::-webkit-scrollbar-track { background: transparent; }

/* 终端状态表格 */
.terminal-status { display: inline-flex; align-items: center; gap: 6px; }
.pulse-dot { width: 8px; height: 8px; border-radius: 50%; }
.pulse-dot.online { background: var(--success); animation: pulse 2s infinite; }
.pulse-dot.offline { background: var(--gray-300); }
@keyframes pulse { 0%,100% { box-shadow: 0 0 0 0 rgba(22,163,74,.4); } 50% { box-shadow: 0 0 0 5px rgba(22,163,74,0); } }

.section-title { font-size: 15px; font-weight: 600; color: var(--gray-800); margin-bottom: 12px; display: flex; align-items: center; gap: 8px; }
.section-title .line { flex: 1; height: 1px; background: var(--gray-200); }

/* ===== 主动安全总览 ===== */
.as-filterbar { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; align-items: center; }
.as-filter-group { display: inline-flex; align-items: center; gap: 6px; }
.as-filter-label { font-size: 13px; color: var(--gray-500); }
.hbar-row { display: flex; align-items: center; gap: 10px; padding: 5px 0; }
.hbar-label { width: 92px; flex: 0 0 92px; font-size: 13px; color: var(--gray-700); text-align: right; }
.hbar { flex: 1; height: 14px; background: var(--gray-100); border-radius: 7px; overflow: hidden; }
.hbar-fill { height: 100%; border-radius: 7px; transition: width .4s ease; min-width: 2px; }
.hbar-num { width: 56px; flex: 0 0 56px; text-align: right; font-size: 13px; font-weight: 600; color: var(--gray-800); }
.as-filterbar .btn { min-width: 56px; }

/* ===== 证据中心（K005） ===== */
.ev-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 14px; }
.ev-card { overflow: hidden; transition: box-shadow .2s; }
.ev-card:hover { box-shadow: 0 4px 14px rgba(0,0,0,.08); }
.ev-thumb { width: 100%; height: 132px; object-fit: cover; background: var(--gray-100); cursor: zoom-in; display: flex; align-items: center; justify-content: center; font-size: 40px; }
.ev-thumb-icon { cursor: default; color: var(--gray-400); }

/* ============================================================
   K967 · 移动端响应式（P1）+ 宫格移动交互（P2）
   约束：布局类规则全部锁在 max-width:767px 内
        ⇒ 桌面（≥768px，含验收档 ≥1200px）零回归
   分支：feature/mobile-pwa
   ============================================================ */

/* 移动端专属元素：桌面一律隐藏（display:none 不占位，不影响桌面布局） */
.m-nav-toggle,
.m-nav-mask,
.v-cell-fullscreen,
.ptz-sheet-toggle,
.ptz-sheet-mask,
.video-cell .v-cell-swipe-hint { display: none; }

@media (max-width: 767px) {
  /* ---------- P1-1 顶部栏：汉堡按钮 + 状态条可横滑 ---------- */
  .m-nav-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex: 0 0 40px;
    border: 1px solid var(--gray-200); border-radius: 8px;
    background: #fff; color: var(--gray-700); font-size: 18px; line-height: 1;
  }
  .m-nav-toggle:active { background: var(--gray-100); }

  .topbar {
    height: auto; min-height: 52px; padding: 8px 12px; gap: 10px;
    padding-top: calc(8px + env(safe-area-inset-top));
    flex-wrap: nowrap;
  }
  .topbar .page-title { font-size: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .topbar .conn-status {
    font-size: 11px; gap: 6px; margin-left: auto;
    overflow-x: auto; -webkit-overflow-scrolling: touch; white-space: nowrap;
    padding-bottom: 2px;
  }
  .topbar #tv-open-btn { display: none; } /* 小屏顶部拥挤，大屏入口桌面保留 */

  /* ---------- P1-2 侧栏抽屉化 ---------- */
  .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 120;
    transform: translateX(-100%);
    transition: transform .25s ease;
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .sidebar.m-open { transform: translateX(0); box-shadow: 6px 0 24px rgba(15,23,42,.35); }
  .m-nav-mask.m-open {
    display: block; position: fixed; inset: 0; z-index: 110;
    background: rgba(15,23,42,.45);
  }
  .nav { padding: 8px; }

  /* ---------- P1-3 触控目标 ≥44px ---------- */
  .nav-item { padding: 12px; min-height: 44px; font-size: 14px; }
  .sidebar .user-box .logout-btn { width: 44px; height: 44px; font-size: 18px; }
  .sidebar .user-box .logout-btn svg { width: 20px; height: 20px; }
  .btn { min-height: 38px; }
  .btn-sm { min-height: 30px; }

  /* ---------- P1-4 内容区与栅格：全部单列，杜绝横向溢出 ---------- */
  .content { padding: 12px; padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
  /* K9299：单列档同样须 minmax(0,1fr)（与 ≤1200 档同理；1fr 的 min-content 下限会被
     .alarm-brief 等 nowrap 弹性行撑爆 ⇒ 仪表盘窄屏 +47px 横溢） */
  .panel-grid, .panel-grid.wide-left { grid-template-columns: minmax(0, 1fr); }
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .cmd-grid, .ev-grid, .form-grid { grid-template-columns: 1fr; }
  .form-row, .form-row-3 { grid-template-columns: 1fr; }
  .track-controls { padding: 12px; }
  .track-controls .form-group { min-width: 0; flex: 1 1 100%; }
  .as-filterbar { gap: 10px; }

  /* ---------- K9299：JS 模板行内统计行（repeat(4,1fr)/repeat(3,1fr)）窄屏防撑爆 ----------
     行内样式只能被 !important 覆盖（范式同下方 .video-grid）。1fr 轨道下限 = min-content：
     报警统计卡（图标 46 + padding 40 + 「已处置 1720/50394」不可断行）≈160px/卡，
     4 列 ≈676px ≫ 366px 可用 ⇒ 实测 +233px 横溢。改 2 列 minmax(0,1fr) 让轨道可收缩，
     卡片内容自行换行（与 .cards 移动端行为一致）。桌面 ≥768 不受影响（行内 repeat 原样）。 */
  #alarm-stat-row, #fa-stat-row, #bd-stat-row, #sv-stat-row, #vas-stat-row {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }

  /* ---------- P1-5 表格：容器横滑 + 首列粘滞 ---------- */
  .table-wrap { -webkit-overflow-scrolling: touch; }
  .table-wrap table { min-width: 560px; }
  table thead th:first-child { position: sticky; left: 0; z-index: 3; background: var(--gray-50); }
  table tbody td:first-child { position: sticky; left: 0; z-index: 2; background: #fff; }
  tbody tr:hover td:first-child { background: var(--gray-50); }

  /* ---------- P1-6 模态框/登录卡全宽化 ---------- */
  .modal { width: calc(100vw - 24px); max-width: calc(100vw - 24px); max-height: 88vh; }
  .modal-body { padding: 14px; }
  .login-card { width: calc(100vw - 32px); padding: 28px 22px; }

  /* ---------- P2-1 视频宫格：2x2（手机同屏清晰显示 4 画面） ---------- */
  .video-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 8px; }

  /* ---------- P2-2 单元格工具栏：移动端两行布局、触控友好 ---------- */
  .video-cell .v-cell-toolbar { left: 6px; right: 6px; bottom: 6px; gap: 6px; padding: 6px; flex-wrap: wrap; }
  .video-cell .v-cell-toolbar .vc-terminal { flex: 1 1 100%; max-width: none; }
  .video-cell .v-cell-toolbar select { max-width: none; flex: 1 1 40%; min-height: 34px; }
  .video-cell .v-cell-toolbar .btn { flex: 1 1 auto; min-height: 34px; padding: 6px 8px; }
  .v-cell-fullscreen { display: inline-flex !important; }

  /* ---------- P2-3 单格全屏 ---------- */
  .video-cell:fullscreen,
  .video-cell:-webkit-full-screen { border-radius: 0; aspect-ratio: auto; width: 100vw; height: 100vh; }
  .video-cell:fullscreen .v-cell-toolbar,
  .video-cell:-webkit-full-screen .v-cell-toolbar { left: 12px; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom)); }

  /* ---------- P2-4 云台底部遮罩（bottom sheet） ---------- */
  .ptz-sheet-toggle { display: inline-flex !important; }
  .ptz-card {
    position: fixed; left: 0; right: 0; bottom: var(--vv-bottom, 0px); z-index: 130;
    margin: 0; border-radius: 16px 16px 0 0;
    max-height: 72vh; overflow-y: auto;
    transform: translateY(102%); transition: transform .28s ease;
    padding-bottom: calc(12px + env(safe-area-inset-bottom));
    box-shadow: 0 -8px 28px rgba(15,23,42,.28);
  }
  .ptz-card.m-open { transform: translateY(0); }
  .ptz-sheet-mask.m-open { display: block; position: fixed; inset: 0; z-index: 125; background: rgba(15,23,42,.45); }

  /* ---------- P2-5 滑切通道提示 ---------- */
  .video-cell .v-cell-swipe-hint { display: block; position: absolute; right: 8px; top: 8px; z-index: 7; font-size: 11px; color: rgba(255,255,255,.7); background: rgba(15,23,42,.5); padding: 2px 8px; border-radius: 10px; pointer-events: none; }
}

/* K967 补充（用户硬要求）：768–1023 小屏（小平板/小笔记本）视频宫格也 2x2，
   保证 4 个画面同屏清晰；此档 panel-grid 已被 max-width:1200 收起，视频区拿满宽度。 */
@media (min-width: 768px) and (max-width: 1023px) {
  .video-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 10px; }
}

/* ============ K967 P1 追加：中间档窗口适配（2026-09-27 用户四档截图复盘） ============
   问题：768–1199px 窗口下顶栏被硬裁（大屏按钮/状态项截断）、侧栏 220px 吃宽、
   视频工具栏换行成三行孤行。以下均为纯追加规则，宽屏 ≥1200 零变化。 */
@media (min-width: 768px) and (max-width: 1199px) {
  /* ① 顶栏防截断：允许换行，状态项/大屏按钮不再被裁 */
  .topbar { height: auto; min-height: 56px; flex-wrap: wrap; row-gap: 4px; padding: 8px 16px; }
  .topbar .conn-status { gap: 6px; }
  .topbar .conn-status > span { margin-left: 0 !important; }
  .topbar .conn-status #tv-open-btn { margin-left: 4px !important; padding: 4px 10px !important; font-size: 12px !important; }
  /* ③ 工具栏收纳：按钮/下拉紧凑化，换行成整齐两行 */
  .video-layout-btns { gap: 6px; row-gap: 8px; }
  .video-layout-btns .btn { padding: 5px 9px; font-size: 12px; }
  .video-layout-btns select { padding: 5px 6px !important; }
  #video-vehicle-sel { max-width: 128px !important; }
  /* 单格控制条紧凑化：窄窗口下尽量回到一行 */
  .video-cell .v-cell-toolbar { gap: 4px; padding: 5px 6px; }
  .video-cell .v-cell-toolbar select { max-width: 78px; }
  .video-cell .v-cell-toolbar .vc-terminal { max-width: 110px; }
  .video-cell .v-cell-toolbar .btn { padding: 4px 7px; font-size: 11px; }
  .content { padding: 16px; }
}
/* ② 侧栏图标窄栏（768–1023）：60px 只留图标，给视频区腾 160px */
@media (min-width: 768px) and (max-width: 1023px) {
  :root { --sidebar-w: 60px; }
  .sidebar { width: 60px; min-width: 60px; }
  .sidebar .brand { padding: 14px 8px; justify-content: center; }
  .sidebar .brand .title { display: none; }
  .nav { padding: 12px 6px; }
  .nav-item { position: relative; justify-content: center; gap: 0; padding: 10px 4px; font-size: 0; }
  .nav-item .icon { font-size: 17px; width: auto; }
  .nav-item .badge { position: absolute; top: 2px; right: 2px; margin-left: 0; font-size: 9px; padding: 0 5px; }
  .sidebar .user-box { justify-content: center; gap: 4px; padding: 10px 6px; }
  .sidebar .user-box .uname { display: none; }
}

/* ============ K967 P1 追加2：真机手机档（≤767）画面可见性修复（2026-09-27 用户真机截图复盘） ============
   问题：格子 16:9 约 166x93px，但浮层控制条 flex-wrap 三四行(≥110px)把画面盖满；
   页面工具栏占五排把实时画面顶到很下面。核心思路：控制条移出画面、静态放到格子下方，永不遮挡画面。 */
@media (max-width: 767px) {
  /* ① 格子改为「视频 16:9 在上 + 控制条静态在下」，画面永远完整可见 */
  .video-cell { aspect-ratio: auto; display: flex; flex-direction: column; }
  .video-cell > video { position: static; inset: auto; width: 100%; height: auto; aspect-ratio: 16/9; }
  .video-cell .v-cell-toolbar { position: static; left: auto; right: auto; bottom: auto; flex-wrap: wrap; gap: 4px; padding: 5px; }
  .video-cell .v-cell-toolbar .vc-terminal { flex: 1 1 46%; min-width: 0; max-width: none; }
  .video-cell .v-cell-toolbar select { flex: 1 1 30%; max-width: none; min-height: 30px; font-size: 12px; padding: 2px 4px; }
  .video-cell .v-cell-toolbar .btn { flex: 0 0 auto; min-height: 30px; padding: 4px 8px; font-size: 12px; }
  .video-cell .v-cell-status { font-size: 12px; }
  /* ② 页面工具栏手机收纳：隐藏文字标签、画面数只留 1/2/4（6/8/12/16 手机无意义，桌面仍在） */
  .video-layout-btns label.text-sm,
  .video-layout-btns span.text-sm { display: none; }
  .video-layout-btns button[data-layout="6"],
  .video-layout-btns button[data-layout="8"],
  .video-layout-btns button[data-layout="12"],
  .video-layout-btns button[data-layout="16"] { display: none; }
  .video-layout-btns { gap: 6px; row-gap: 6px; }
  .video-layout-btns .btn { padding: 7px 11px; font-size: 12px; min-height: 34px; }
  .video-layout-btns select { min-height: 34px; }
}

/* ============ K967 P1 追加3：真机手机档 overlay 遮挡修复（2026-09-27 用户真机二次截图复盘） ============
   问题：152x85 小格上 v-cell-label(12px,top8) + v-cell-stats(11px,top30,长文案换2-3行) 两层
   绝对定位 overlay 遮挡画面近 60%。处理：手机档收成单行截断（label 10px / stats 9px），
   遮挡降到 <20%；桌面档不动。 */
@media (max-width: 767px) {
  .video-cell .v-cell-label { top: 4px; left: 6px; font-size: 10px; max-width: calc(100% - 12px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .video-cell .v-cell-stats { top: 17px; left: 6px; font-size: 9px; max-width: calc(100% - 12px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .video-cell .v-cell-status { font-size: 11px; width: calc(100% - 12px); }
}

/* ============================================================
   UI 整理与美化：分组导航 / SVG 线性图标 / 侧栏折叠 / 视觉提质
   约束：移动端 K967 规则全部锁在 max-width 内；本块桌面规则以
         min-width:1024px 收口，并对 768–1023 图标栏、≤767 抽屉
         做兼容，确保手机/小平板零回归。
   ============================================================ */

/* ---- SVG 线性图标：随文字颜色（currentColor）着色 ---- */
.ic { width: 18px; height: 18px; flex: 0 0 18px; display: block; }
.nav-item .icon { display: inline-flex; width: 20px; flex: 0 0 20px; justify-content: center; }
.nav-item .icon .ic { width: 18px; height: 18px; flex: 0 0 18px; }
.brand-mark { width: 30px; height: 30px; flex: 0 0 30px; display: block; border-radius: 8px; }
.login-card .brand-mark { width: 44px; height: 44px; flex: 0 0 44px; }

/* ---- 分组导航 ---- */
.nav-group { margin-bottom: 2px; }
.nav-group + .nav-group { border-top: 1px solid rgba(255,255,255,.06); padding-top: 2px; }
.nav-group-title {
  display: flex; align-items: center; gap: 6px;
  padding: 14px 12px 6px; cursor: pointer; user-select: none;
  font-size: 11px; font-weight: 600; letter-spacing: .06em; color: var(--gray-400);
}
.nav-group-title .ic { width: 14px; height: 14px; flex: 0 0 14px; opacity: .8; transition: transform .2s ease; }
.nav-group.collapsed .nav-group-title .ic { transform: rotate(-90deg); }
.nav-group-items { display: block; }
.nav-group.collapsed .nav-group-items { display: none; }

/* ---- 侧栏折叠按钮（桌面） ---- */
.sidebar-toggle {
  margin-left: auto; width: 28px; height: 28px; flex: 0 0 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: rgba(255,255,255,.06); color: var(--gray-400);
  border-radius: 7px; cursor: pointer; transition: all .15s;
}
.sidebar-toggle:hover { background: rgba(255,255,255,.12); color: #e2e8f0; }
.sidebar-toggle .ic { width: 16px; height: 16px; flex: 0 0 16px; transition: transform .2s ease; }

/* 桌面（≥1024px）手动折叠为图标栏 */
@media (min-width: 1024px) {
  #app.sidebar-collapsed .sidebar { width: 64px; min-width: 64px; }
  #app.sidebar-collapsed .sidebar .brand { justify-content: center; padding: 18px 8px; }
  #app.sidebar-collapsed .sidebar .brand .title { display: none; }
  #app.sidebar-collapsed .sidebar .brand-mark { flex: 0 0 30px; }
  #app.sidebar-collapsed .sidebar .nav-group-title { display: none; }
  #app.sidebar-collapsed .sidebar .nav-group + .nav-group { border-top: none; }
  #app.sidebar-collapsed .sidebar .nav-item { justify-content: center; gap: 0; padding: 11px 4px; font-size: 0; }
  #app.sidebar-collapsed .sidebar .nav-item .icon { width: 22px; flex: 0 0 22px; }
  #app.sidebar-collapsed .sidebar .nav-item .icon .ic { width: 20px; height: 20px; flex: 0 0 20px; }
  #app.sidebar-collapsed .sidebar .user-box { justify-content: center; }
  #app.sidebar-collapsed .sidebar .user-box .uname { display: none; }
  #app.sidebar-collapsed .sidebar-toggle { margin-left: 0; transform: rotate(180deg); }
}

/* 768–1023 图标栏档：隐藏分组标题与折叠按钮（该档已自动图标栏） */
@media (min-width: 768px) and (max-width: 1023px) {
  .nav-group-title { display: none; }
  .nav-group + .nav-group { border-top: none; padding-top: 0; }
  .nav-group { margin-bottom: 0; }
  .sidebar-toggle { display: none; }
}

/* 手机抽屉档（≤767）：分组标题保留，隐藏折叠按钮（用汉堡） */
@media (max-width: 767px) {
  .sidebar-toggle { display: none; }
  .nav-group-title { padding: 12px 12px 4px; }
}

/* ---- 视觉提质（桌面） ---- */
.sidebar { box-shadow: 2px 0 12px rgba(15,23,42,.18); border-right: 1px solid rgba(0,0,0,.25); }
.nav { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.15) transparent; }
.nav::-webkit-scrollbar { width: 6px; }
.nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.14); border-radius: 3px; }
.nav::-webkit-scrollbar-track { background: transparent; }
.nav-item.active { font-weight: 600; box-shadow: inset 3px 0 0 rgba(255,255,255,.85); }
.topbar { box-shadow: 0 1px 0 var(--gray-200), 0 2px 10px rgba(15,23,42,.04); }


/* ---- 一键清屏：只留纯净视频画面（实时监控 Tab / 监控墙，两套 DOM 通用） ---- */
#video-clean-exit { display: none; }
/* ⚠ !important 必需：工具条带行内 style="display:flex"，无 !important 会被行内样式压过
   A-1：隐藏规则从 #video-live-toolbar（仅实时监控）改为 .video-toolbar（实时监控 + 监控墙通用） */
/* A2：工具条带行内 style="display:flex"，无 !important 会被行内样式压过（保留） */
body.video-clean-mode .video-toolbar,
body.video-clean-mode #video-av-hint { display: none !important; }
/* A7：清屏隐藏改用类名 .v-clean-hide-side（侧栏），弃用脆弱的「按位置隐藏次子元素」选择器 */
body.video-clean-mode .v-clean-hide-side { display: none; }
body.video-clean-mode .panel-grid .card > .card-header { display: none; }
/* A-1：画面格里那一圈 card 的标题在监控墙也要收起（此前只覆盖 .panel-grid 内的实时监控） */
body.video-clean-mode .v-clean-hide-header > .card-header,
body.video-clean-mode .v-clean-hide-panel { display: none; }
body.video-clean-mode .video-cell .v-cell-toolbar,
body.video-clean-mode .video-cell .v-cell-swipe-hint { display: none; }
/* A4：清屏态保留码率/码流诊断条（移除原 display:none !important，不再「卡了干瞪眼」） */
body.video-clean-mode .video-cell .v-cell-stats { /* 不隐藏：跟随 JS 内容显隐 */ }
/* A1：连「未连接 / 按需播放」占位也一并隐藏，做到真正纯净；A6 例外保留 .err 错误态可见（黑屏时给出原因） */
body.video-clean-mode .video-cell .v-cell-status:not(.err) { display: none !important; }
body.video-clean-mode .video-cell .v-cell-label { opacity: 0; }
/* A2：iOS Safari 对非交互元素的 :active 常不触发，由 JS 在 touch/mousedown 时挂 .v-label-peek */
body.video-clean-mode .video-cell.v-label-peek .v-cell-label,
body.video-clean-mode .video-cell:active .v-cell-label { opacity: 1; }
body.video-clean-mode #video-clean-exit {
  display: flex; align-items: center; justify-content: center;
  position: fixed; top: calc(env(safe-area-inset-top, 0px) + 10px); right: 10px; z-index: 320;
  min-height: 36px; padding: 0 14px; border: 1px solid rgba(255,255,255,.35); border-radius: 999px;
  background: rgba(15,23,42,.55); color: #fff; font-size: 13px; cursor: pointer;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}

/* ---- A-1：清屏态的「画面数」浮层 ----
   工具条整条被隐藏后 1/4/9 按钮跟着消失，导致「清屏 + 非 4 格」在结构上做不到。
   这里常驻一份画面数按钮浮层，仅在清屏态显示，固定在底部居中（拇指可达，避开右上角 ✕ 胶囊）。 */
#video-layout-float { display: none; }
body.video-clean-mode #video-layout-float {
  display: flex; align-items: center; justify-content: center; gap: 6px; flex-wrap: wrap;
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(54px + env(safe-area-inset-bottom, 0px) + 12px + var(--vv-bottom, 0px)); z-index: 320;
  max-width: calc(100vw - 12px); padding: 4px 8px; border-radius: 999px;
  background: rgba(15, 23, 42, .5); border: 1px solid rgba(255, 255, 255, .28);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
#video-layout-float .text-muted { color: rgba(255, 255, 255, .82); }
#video-layout-float .btn {
  padding: 4px 8px; min-height: 30px; font-size: 12px; white-space: nowrap;
  border-color: rgba(255, 255, 255, .35); background: rgba(255, 255, 255, .12); color: #fff;
}
#video-layout-float .btn.active {
  background: #fff; color: #0f172a; border-color: #fff; font-weight: 600;
}

/* ---------- P1-7 手机端表格卡片化（车辆列表 / 报警中心，≤767px，左滑出操作） ---------- */
.m-cards, .m-vehicle-tools { display: none; }

@media (max-width: 767px) {
  .m-cards {
    display: block;
    margin-top: 10px;
  }
  /* 卡片视图下不渲染横滑表格（P1-5）与其空壳容器 */
  .m-cards .table-wrap { display: none; }
  .m-cards .empty-tip { display: none; }

  .m-card-swipe {
    position: relative; overflow: hidden;
    margin: 0 10px 10px; border-radius: 12px; background: #fff;
    border: 1px solid var(--gray-200, #e2e8f0);
    box-shadow: 0 1px 3px rgba(15, 23, 42, .06);
  }
  .m-card-actions {
    position: absolute; top: 0; right: 0; bottom: 0; width: 152px;
    display: flex; z-index: 1;
  }
  .m-card-actions button {
    flex: 1; border: 0; color: #fff; font-size: 13px; font-weight: 600;
    cursor: pointer; padding: 0 2px; min-height: 100%;
  }
  .m-act { background: var(--gray-500, #64748b); }
  .m-act-primary { background: var(--primary, #2563eb); }
  .m-act-ok { background: var(--success, #16a34a); }
  .m-act-warn { background: var(--warning, #f59e0b); }
  .m-act-purple { background: var(--purple, #7c3aed); }
  .m-act-danger { background: var(--danger, #dc2626); }

  .m-card-body {
    position: relative; z-index: 2; background: #fff;
    padding: 12px 14px; transition: transform .22s ease; touch-action: pan-y;
  }
  .m-card-swipe.open .m-card-body { transform: translateX(-152px); }

  .m-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
  .m-card-title { font-size: 16px; font-weight: 700; color: var(--text, #0f172a); }
  .m-card-sub { margin-top: 6px; font-size: 12px; color: #64748b; word-break: break-all; }
  .m-card-meta { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
  .m-card-check { width: 20px; height: 20px; flex: none; }
  .m-card-hint { font-size: 11px; color: #94a3b8; text-align: center; padding: 0 0 6px; }
  /* K1069 车辆管理：按车队分组折叠 + 搜索（仅移动端卡片视图） */
  .m-vehicle-tools { display: block; margin: 10px 0 0; }
  .m-vehicle-tools .form-input { width: 100%; box-sizing: border-box; }
  .m-group { margin-bottom: 12px; }
  .m-group-head { display: flex; align-items: center; gap: 6px; width: 100%; border: 0; background: var(--gray-100, #f1f5f9); border-radius: 8px; padding: 8px 12px; font-size: 13px; font-weight: 700; color: var(--text, #0f172a); cursor: pointer; -webkit-tap-highlight-color: transparent; }
  .m-group-arrow { flex: none; width: 14px; color: var(--gray-500, #64748b); font-size: 12px; }
  .m-group-name { flex: 1 1 auto; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .m-group-count { flex: none; background: #fff; border: 1px solid var(--gray-200, #e2e8f0); border-radius: 10px; padding: 0 8px; font-size: 11px; font-weight: 600; color: var(--gray-500, #64748b); }
  .m-group.m-closed .m-group-body { display: none; }
  /* K9256: 企业 → 车队 两级（一级 .m-group-org 企业组、二级 .m-group-sub 车队组；嵌套复用 .m-closed 折叠） */
  .m-group-org > .m-group-head { background: var(--gray-200, #e2e8f0); }
  .m-group-sub { margin-bottom: 8px; }
  .m-group-sub > .m-group-head { margin-left: 10px; background: var(--gray-50, #f8fafc); font-size: 12.5px; font-weight: 600; }
  .m-group-body .m-card-swipe { margin-top: 8px; }
  .m-group-empty { padding: 16px; text-align: center; color: #94a3b8; font-size: 13px; }
}

/* 表格 card 在手机端让位给卡片视图（m-cards 是其后续兄弟，需用独立类命中） */
@media (max-width: 767px) {
  .m-hide-on-mobile { display: none; }
}

/* ============ K1029 移动端底部 5-tab 常驻导航（P1，2026-09-28） ============
   与 K967 侧栏抽屉并存：桌面(≥768px) 隐藏；≤767px 固定底部，内容区留底白避免被遮。
   断点 767px 与 K967 保持一致；z-index(100) < 抽屉遮罩(110) < 侧栏(120)，开抽屉时遮罩盖住 tabbar。
   五个高频视图：仪表盘 / 实时监控 / 视频监控 / 车辆管理 / 报警中心。 */
.m-tabbar { display: none; }
@media (max-width: 767px) {
  .m-tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: var(--vv-bottom, 0px); z-index: 115;
    height: 54px; padding-bottom: env(safe-area-inset-bottom);
    background: #fff; border-top: 1px solid var(--gray-200, #e2e8f0);
    box-shadow: 0 -2px 12px rgba(15, 23, 42, .08);
  }
  .m-tabbar-item {
    flex: 1 1 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px; border: 0; background: none; cursor: pointer; padding: 4px 0;
    color: var(--gray-500, #64748b); font-size: 11px; line-height: 1.1;
    -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  }
  .m-tabbar-item .ic { width: 22px; height: 22px; flex: 0 0 22px; }
  .m-tabbar-item.active { color: var(--primary, #2563eb); font-weight: 600; }
  .m-tabbar-item.active .ic { color: var(--primary, #2563eb); }
  /* 内容区底部留白，避免被固定 tabbar 遮挡（叠加 --vv-bottom 以避开动态工具栏） */
  .content { padding-bottom: calc(72px + env(safe-area-inset-bottom) + var(--vv-bottom, 0px)); }
}

/* ============ UI 打磨 2026-10-01（logo 透明化配套 + 焦点可见 + 滚动条） ============ */
.sidebar .brand .brand-mark { filter: drop-shadow(0 1px 2px rgba(0,0,0,.3)); }
.btn:focus-visible, button:focus-visible, .nav-item:focus-visible {
  outline: 2px solid var(--primary); outline-offset: 2px;
}
.content::-webkit-scrollbar { width: 8px; height: 8px; }
.content::-webkit-scrollbar-thumb { background: var(--gray-300); border-radius: 4px; }
.content::-webkit-scrollbar-thumb:hover { background: var(--gray-400); }
.content::-webkit-scrollbar-track { background: transparent; }

/* ============ K9239：窄屏图标栏档补「展开入口」（2026-10-14） ============
   问题：768–1023 档侧栏被强制成 60px 纯图标栏（为视频区腾宽度），而唯一能展开的 .sidebar-toggle
   被本档 display:none 隐藏、汉堡 .m-nav-toggle 基础样式亦为 display:none（仅 ≤767 显示）
   ⇒ 该档「零展开入口」（用户真机截图反馈）。
   方案（用户 2026-10-14 拍板）：保留 60px 图标栏不动，显示折叠按钮，点击后侧栏展开为
   「完整宽度浮层 + 遮罩」（复用 K967 移动端抽屉的 .m-open 机制，两条媒体查询区间不相交）。
   ≥1024 档的 #app.sidebar-collapsed 折叠样式既有，仅由 app.js toggleSidebar 接上开关。 */
@media (min-width: 768px) and (max-width: 1023px) {
  /* ① 该档恢复显示折叠按钮（覆盖上文 768–1023 档的 .sidebar-toggle{display:none}） */
  .sidebar .sidebar-toggle { display: inline-flex; }

  /* ①b 品牌行纵向堆叠：60px 档内容宽仅 44px，logo(30px)+按钮(28px) 横排必溢出 ⇒ 改上下排 */
  .sidebar .brand { flex-direction: column; gap: 6px; padding: 12px 6px; }

  /* ② 展开态：脱离 60px 图标栏，恢复完整宽度与文字，浮层覆盖在内容之上 */
  .sidebar.m-open {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 120;
    width: 220px; min-width: 220px;
    box-shadow: 6px 0 24px rgba(15,23,42,.35);
  }
  .sidebar.m-open .brand { flex-direction: row; justify-content: flex-start; gap: 10px; padding: 18px 16px; }
  .sidebar.m-open .brand .title { display: block; }
  .sidebar.m-open .nav { padding: 12px 8px; }
  .sidebar.m-open .nav-group-title { display: flex; }
  .sidebar.m-open .nav-group { margin-bottom: 6px; }
  .sidebar.m-open .nav-group + .nav-group { border-top: 1px solid rgba(255,255,255,.06); padding-top: 8px; }
  .sidebar.m-open .nav-item { justify-content: flex-start; gap: 10px; padding: 10px 12px; font-size: 13.5px; }
  .sidebar.m-open .nav-item .badge { position: static; top: auto; right: auto; margin-left: auto; font-size: 11px; padding: 1px 7px; }
  .sidebar.m-open .user-box { justify-content: flex-start; gap: 10px; padding: 12px 16px; }
  .sidebar.m-open .user-box .uname { display: block; }

  /* ③ 该档遮罩（复用 .m-nav-mask，与 ≤767 抽屉共用同一 DOM 元素） */
  .m-nav-mask.m-open {
    display: block; position: fixed; inset: 0; z-index: 110;
    background: rgba(15,23,42,.45);
  }
}

/* ---------- K9275-⑤ 移动端行内工具条横溢收口（2026-10-17） ----------
   现象：390px 视口实测 #content scrollWidth 491 / clientWidth 390 ⇒ 横滚 101px，
   左右滑动后左侧文字被裁、右侧留白（真机截图 + 无头 Chromium 双重复现）。
   真因：各视图行内 `<div class="flex justify-between mb-16" style="display:flex;justify-content:space-between">`
   不换行，且内部 select 行内 min-width:120px + 两个按钮 ⇒ 该行 min-content 479px > 366 可用宽。
   行内 display:flex / min-width 只能用 !important 覆盖（范式同 K9299）。 */
@media (max-width: 767px) {
  #content > .flex.justify-between.mb-16 { flex-wrap: wrap; row-gap: 8px; }
  #content > .flex.justify-between.mb-16 > *:first-child { flex: 1 1 100%; min-width: 0; }
  #content > .flex.justify-between.mb-16 > *:last-child { flex: 1 1 100%; flex-wrap: wrap; }
  #content > .flex.justify-between.mb-16 select.form-input { min-width: 0 !important; flex: 1 1 40%; max-width: 100%; }
}

/* ---------- K9275-⑥ 实时监控页头窄屏标题被压成两行（2026-10-17） ----------
   现象：390px 视口下 h3「实时监控」被压成 ~2 字宽竖排（截图可见「实时监 / 控」）。
   真因：app.js:1443 用 .card-header（h3 + 控件 div），app.css:188 的
   `.card-header{display:flex;justify-content:space-between;gap:12px}` 无 flex-wrap，
   h3 默认 flex-shrink:1 且无 nowrap，中文可逐字断行 ⇒ 被挤成竖排。
   与 K9275-⑤ 不同源：那批是行内 display:flex 需 !important，这里 flex 来自类，普通规则即可。
   作用域限定 .monitor-grid > .card:first-child（地图卡）；右侧车辆列表 .card.monitor-side 不受影响
   ——首版选到 .monitor-grid > .card 时把「车辆列表」头部也换行了，已收窄到 :first-child。 */
@media (max-width: 767px) {
  #content .monitor-grid > .card:first-child > .card-header { flex-wrap: wrap; row-gap: 8px; }
  #content .monitor-grid > .card:first-child > .card-header > h3 { flex: 0 0 100%; white-space: nowrap; }
  #content .monitor-grid > .card:first-child > .card-header > div { flex: 1 1 100%; flex-wrap: wrap; row-gap: 6px; }
}

/* ---------- K9275-⑦ 卡头通用：窄屏允许换行、按钮不被压成竖排（2026-10-17） ----------
   现象：仪表盘「车队列表」卡头 h3（含 9 台·在线 3·3 家企业）与 .fleet-tabs 两个按钮同处一行，
   .card-header 无 flex-wrap 且按钮默认可收缩 ⇒ 「全部」「在线」被压成 45×46 的两行竖排文字。
   同类风险适用于所有 .card-header（13 处视图模板）。修法：容器允许换行、h3 可伸缩但不为 0、
   其余子项与按钮/标签不收缩且 nowrap。特化规则（如地图卡 h3 占整行）仍按选择器优先级生效。 */
@media (max-width: 767px) {
  #content .card-header { flex-wrap: wrap; row-gap: 8px; }
  #content .card-header > h3 { flex: 1 1 auto; min-width: 0; }
  #content .card-header > :not(h3) { flex: 0 0 auto; }
  #content .card-header button,
  #content .card-header .btn,
  #content .card-header .tag,
  #content .card-header .fleet-tabs { flex: 0 0 auto; white-space: nowrap; }
}

/* ---------- K9275-⑧ 仪表盘车队行窄屏竖排（2026-10-17） ----------
   现象：.fleet-row 是 nowrap flex（tag + 车牌 + 终端号 + 时间），390px 下可用宽约 302px
   而子项合计约 314px ⇒ 在线/离线标签被压成 32x40 竖排、车牌断成「粤 / AFB293」两行。
   修法：允许行内换行，标签/车牌/终端号不收缩且 nowrap，时间仍靠右（放不下时整块落到第二行）。 */
@media (max-width: 767px) {
  #content .fleet-row { flex-wrap: wrap; row-gap: 2px; }
  #content .fleet-row .tag,
  #content .fleet-row .fr-plate,
  #content .fleet-row .fr-term { flex: 0 0 auto; white-space: nowrap; }
  #content .fleet-row .fr-time { margin-left: auto; }
}

/* ============================================================================
   K9344 · 常用模块切换体验：骨架屏 + 切换淡入
   目的：把「切模块 = 闪一行『加载中...』再跳出来」改成「先看到与真实布局同构的灰块」，
        弱网/低端机上不再是白屏空洞；配合 app.js 的视图离屏保留，回切直接是完整内容。
   约束：骨架必须无真实数据、不触发任何请求；reduced-motion 下关闭所有动画。
   ============================================================================ */
.skel {
  position: relative;
  overflow: hidden;
  background: var(--gray-100);
  border-radius: 8px;
}
.skel::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .72), transparent);
  animation: skelShimmer 1.15s ease-in-out infinite;
}
@keyframes skelShimmer { 100% { transform: translateX(100%); } }

.skel-card {
  background: #fff;
  border: 1px solid var(--gray-200);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* 仪表盘：6 个统计卡 + 左地图 / 右列表 */
.skel-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}
.skel-stat { height: 84px; }
.skel-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 16px;
}
.skel-map { min-height: 420px; }
.skel-map-inner { flex: 1; min-height: 420px; border-radius: 8px; }
.skel-side { display: flex; flex-direction: column; gap: 12px; min-height: 420px; }
.skel-side-wide { min-height: 480px; }
.skel-line { height: 14px; flex: 0 0 auto; }
.skel-table { gap: 14px; }
.skel-head { height: 34px; background: var(--gray-200); }
.skel-video-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.skel-video { aspect-ratio: 16 / 9; }
.skel-alarm { gap: 10px; margin-bottom: 12px; }

/* 切换淡入：仅新渲染时加，命中离屏保留副本时不加 */
#content.view-fade { animation: viewFadeIn .16s ease-out; }
@keyframes viewFadeIn { from { opacity: .45; } to { opacity: 1; } }

@media (max-width: 1020px) {
  .skel-cols { grid-template-columns: minmax(0, 1fr); }
  .skel-map, .skel-map-inner { min-height: 300px; }
  .skel-side, .skel-side-wide { min-height: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .skel::after { animation: none; }
  #content.view-fade { animation: none; }
}
