/* ============================================================================
   中国广电长沙片区 · 长沙广电直销员分析系统
   全站设计系统（单一数据源，Design Tokens → Base → Layout → Components → Pages）

   维护约定（务必遵守，避免再次出现重复/硬编码）：
   1. 所有间距只用 --sp-* 刻度；所有圆角只用 --r-*；所有阴影只用 --sh-*；
      所有颜色只用 --c-* 语义变量。禁止在组件里写字面量色值与魔法数字。
   2. 排版组件样式一律写类选择器，不写行内 style（JS 里也不允许）。
   3. 断点只允许出现在文件末尾「响应式」一节，且顺序为 降序（宽→窄）。
   4. 改样式先改 :root 变量，再改组件规则。
   ========================================================================== */

/* ========================= 1. 设计令牌 ========================= */
:root{
  /* --- 色板：中性（背景/描边/文字） --- */
  --c-bg:#0b1220;
  --c-bg-2:#0f1a2e;          /* 输入框 / 表头底 / 次级底 */
  --c-panel:#16213e;         /* 卡片面 */
  --c-panel-2:#1c2b4d;       /* 悬浮/次级面 */
  --c-line:#26365c;          /* 描边 */
  --c-line-soft:rgba(255,255,255,.06);
  --c-line-soft-2:rgba(255,255,255,.10);

  /* --- 文字：三级层级 --- */
  --c-text:#e6edf7;          /* 主文本，对 --c-panel 对比度 ≈ 12:1 (AAA) */
  --c-text-2:#94a3c4;        /* 次要文本 ≈ 6.4:1 (AA) */
  --c-text-3:#8494b8;        /* 弱化文本 ≈ 4.8:1 (AA，正文可用) */

  /* --- 语义色：仅 4 个主色 + 3 个状态色，避免花哨 --- */
  --c-gold:#f5b942;          /* 金额 / 品牌 */
  --c-blue:#3b82f6;          /* 量 / 主操作 */
  --c-cyan:#22d3ee;          /* 次要数据 */
  --c-green:#34d399;         /* 正向 / 达成 */
  --c-red:#f87171;           /* 负向 / 危险 */
  --c-orange:#fb923c;        /* 关注 */
  --c-purple:#a78bfa;        /* 第三序列 */

  /* --- 语义背景（半透明，用于 pill / 提示条） --- */
  --bg-gold:rgba(245,185,66,.13);
  --bg-blue:rgba(59,130,246,.12);
  --bg-green:rgba(52,211,153,.14);
  --bg-red:rgba(248,113,113,.12);
  --bg-orange:rgba(251,146,60,.14);

  /* --- 间距刻度：4px 基数的 6 级 --- */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:22px; --sp-6:30px;

  /* --- 圆角 --- */
  --r-sm:8px; --r-md:12px; --r-lg:16px; --r-pill:999px;

  /* --- 阴影：两级 + 焦点环 --- */
  --sh-1:0 1px 2px rgba(0,0,0,.24);
  --sh-2:0 8px 28px rgba(0,0,0,.34);
  --focus-ring:0 0 0 2px rgba(245,185,66,.55);

  /* --- 字体：家族 + 字号阶梯（8 级，正文 14 起） --- */
  --ff:"Microsoft YaHei","PingFang SC","Hiragino Sans GB",system-ui,-apple-system,"Segoe UI",sans-serif;
  --ff-mono:ui-monospace,"SF Mono",Consolas,"Liberation Mono",monospace;
  --fs-11:11px; --fs-12:12px; --fs-13:13px; --fs-14:14px;
  --fs-15:15px; --fs-16:16px; --fs-18:18px; --fs-26:26px; --fs-28:28px;

  /* --- 布局常量 --- */
  --sidebar-w:212px;
  --sidebar-w-collapsed:64px;
  --topbar-h:54px;
  --control-h:34px;          /* 按钮/输入统一高度 */
}

/* ========================= 2. 基础重置 ========================= */
*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;height:100%}
body{
  font-family:var(--ff);
  font-size:var(--fs-14);
  line-height:1.5;
  color:var(--c-text);
  background:var(--c-bg);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
}
h1,h2,h3,h4{margin:0;font-weight:600;line-height:1.35}
p{margin:0}
a{color:var(--c-blue);text-decoration:none}
a:hover{text-decoration:underline}
button,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}
button{cursor:pointer}
img{max-width:100%;display:block}
[hidden]{display:none!important}
.hidden{display:none!important}

/* 键盘可达性：所有可交互元素统一焦点环（鼠标点击不显示） */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible,
.monthpills button:focus-visible,
.tabs button:focus-visible,
.seg button:focus-visible,
.nav a:focus-visible{
  outline:none;
  box-shadow:var(--focus-ring);
  border-radius:var(--r-sm);
}
/* 跳转到主内容（屏幕阅读器/键盘用户） */
.skip-link{
  position:absolute;left:-9999px;top:0;z-index:300;
  background:var(--c-gold);color:#1a1300;padding:var(--sp-2) var(--sp-4);
  border-radius:0 0 var(--r-sm) 0;font-weight:600;
}
.skip-link:focus{left:0}

/* 仅屏幕阅读器可见 */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* 尊重系统「减少动态效果」偏好 */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
}

/* 滚动条：与深色主题一致 */
*::-webkit-scrollbar{width:10px;height:10px}
*::-webkit-scrollbar-track{background:transparent}
*::-webkit-scrollbar-thumb{background:var(--c-line);border-radius:5px;border:2px solid transparent;background-clip:content-box}
*::-webkit-scrollbar-thumb:hover{background:var(--c-panel-2);background-clip:content-box}

/* ========================= 3. 布局骨架 ========================= */
.app{display:flex;height:100vh;overflow:hidden}

.sidebar{
  width:var(--sidebar-w);
  flex-shrink:0;
  display:flex;flex-direction:column;
  background:linear-gradient(180deg,#0d1526,#0a1120);
  border-right:1px solid var(--c-line-soft);
}
.sidebar .brand{padding:var(--sp-4);border-bottom:1px solid var(--c-line-soft);flex-shrink:0}
.sidebar .brand-logo{
  width:100%;max-width:158px;
  background:#fff;border-radius:var(--r-sm);
  padding:5px 8px;margin-bottom:10px;
}
.sidebar .brand b{display:block;color:var(--c-gold);font-size:var(--fs-14);line-height:1.35}
.sidebar .brand span{display:block;color:var(--c-text-3);font-size:var(--fs-11);margin-top:var(--sp-1)}

.nav{flex:1;overflow-y:auto;padding:var(--sp-2)}
.nav .group{
  color:var(--c-text-3);font-size:var(--fs-11);
  padding:var(--sp-3) var(--sp-3) var(--sp-1);
  letter-spacing:.6px;
}
.nav a{
  display:flex;align-items:center;gap:9px;
  padding:9px var(--sp-3);
  margin:2px 0;
  border-radius:var(--r-sm);
  color:var(--c-text-2);font-size:var(--fs-13);
  transition:background .16s ease,color .16s ease;
}
.nav a:hover{background:var(--c-panel);color:var(--c-text);text-decoration:none}
.nav a.active{
  background:linear-gradient(90deg,rgba(245,185,66,.18),transparent);
  color:var(--c-gold);
  box-shadow:inset 3px 0 0 var(--c-gold);
}
.nav a .dot{width:7px;height:7px;border-radius:50%;background:var(--c-text-3);flex-shrink:0}
.nav a.active .dot{background:var(--c-gold)}

.main{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}

.topbar{
  height:var(--topbar-h);flex-shrink:0;
  display:flex;align-items:center;
  gap:var(--sp-2);
  padding:0 var(--sp-5);
  background:rgba(13,21,38,.86);
  backdrop-filter:blur(10px);
  border-bottom:1px solid var(--c-line-soft);
}
.topbar h2{font-size:var(--fs-16);letter-spacing:.2px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.topbar .spacer{flex:1}
.topbar .badge{
  background:var(--c-panel-2);border:1px solid var(--c-line);
  padding:4px 10px;border-radius:var(--r-pill);
  font-size:var(--fs-12);color:var(--c-text-2);white-space:nowrap;
}
.topbar .badge.gold{color:var(--c-gold);border-color:rgba(245,185,66,.4)}

/* 内容区：自适应铺满，不设 max-width 上限 */
.view{
  flex:1;overflow-y:auto;overflow-x:hidden;
  width:100%;
  padding:var(--sp-5) var(--sp-6) var(--sp-6);
  scroll-behavior:smooth;
}

/* ========================= 4. 栅格 ========================= */
/* 用 --cols 驱动列数，媒体查询只改 --cols，规则唯一 */
.grid{display:grid;gap:var(--sp-4);grid-template-columns:repeat(var(--cols,4),minmax(0,1fr))}
.grid>*{min-width:0}          /* 防止长内容撑破栅格（多分辨率不变形） */
.cols-6{--cols:6}
.cols-4{--cols:4}
.cols-3{--cols:3}
.cols-2{--cols:2}
/* 跨列容器：让看板图表行以「2 个 KPI 列宽」为一块，
   从而与上方 KPI 卡的竖向分隔线严格对齐（全站模块网格统一）。 */
/* 跨列容器（.span2）：兼容写法，仅用于需要与 4 列 KPI 对齐的场景。
   看板下方大模块区推荐直接用 .dash-row（独立两列网格），不依赖 KPI 列数。 */
.span2{grid-column:span 2;min-width:0}
.span2>*{height:100%}

/* 看板下方大模块区：独立的可切换两列网格。
   与上方 KPI 栅格完全解耦——无论 KPI 是 4 列还是 5 列，
   本区恒定「每行 2 个模块、等宽、间距一致」，窄屏再退化为单列。 */
.dash-row{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--sp-4);
  margin-top:var(--sp-4);
  align-items:stretch;
}
.dash-row>*{min-width:0}
/* 仅在看板模块区内让卡片成为纵向弹性容器，使内部图表随同行卡片等高拉伸 */
.dash-row>.card{height:100%;display:flex;flex-direction:column}
/* 无卡片外壳的模块（自定义内容块）同样等高并纵向排列 */
.dash-row>.dash-cell{height:100%;display:flex;flex-direction:column;min-width:0}
/* 图表容器：flex 拉伸 + 响应式最小高度（随视口高度自适应，兼顾超宽屏与窄屏）。
   min-height 用 clamp 而非固定值，避免 ECharts 在 flex 量到 0 / 极小值；
   同时 JS 在初始化与每次 setOption 后强制 resize，彻底消除「高度过小」问题。 */
.dash-row>.dash-cell>.chart{flex:1 1 auto;height:auto;min-height:clamp(340px,34vh,440px)}
.dash-row>.card>.chart{
  flex:1 1 auto;
  height:auto;
  min-height:clamp(340px,34vh,440px);
}
/* 兼容未来可能引入的 .chartbox 包裹层 */
.dash-row>.card>.chartbox{flex:1 1 auto;min-height:clamp(340px,34vh,440px)}
.dash-row>.card>.chartbox>.chart{height:100%;min-height:clamp(340px,34vh,440px)}
/* 表格型模块随卡片等高填满（内部仍可独立滚动），消除两列高度不一致时的留白；
   上限与图表 clamp 一致，避免长表格（如单元 Top5）把整行撑爆、连带拉高同排图表 */
.dash-row>.card>.tablewrap{flex:1 1 auto;min-height:0;max-height:clamp(340px,34vh,440px)}

/* 趋势分析页：趋势变化独占第一行并横向拉伸占满整行宽度；
   各单元累计对比与分期明细在第二行并排展示，且与上方左边缘对齐。
   图表与表格高度同步提升，避免信息被截断/折叠。 */
.trend-row{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--sp-4);
  margin-top:var(--sp-4);
  align-items:stretch;
}
.trend-row>*{min-width:0}
/* 趋势变化模块：第一行横向拉伸占满整个版面宽度 */
.trend-row>:first-child{grid-column:1 / -1}
.trend-row>.card{height:100%;display:flex;flex-direction:column;padding:var(--sp-4)}
/* 趋势变化（第一行）更高，充分利用纵向空间，避免上下留白 */
.trend-row>:first-child>.chart{
  flex:1 1 auto;
  height:auto;
  min-height:clamp(460px,46vh,620px);
}
.trend-row>.card>.chart{
  flex:1 1 auto;
  height:auto;
  min-height:clamp(380px,38vh,500px);
}
.trend-row>.card>.tablewrap{
  flex:1 1 auto;
  min-height:0;
  max-height:clamp(380px,38vh,500px);
}

/* ========================= 5. 卡片 ========================= */
.card{
  min-width:0;
  background:var(--c-panel);
  border:1px solid var(--c-line-soft);
  border-radius:var(--r-lg);
  padding:var(--sp-5);
  box-shadow:var(--sh-1);
}
.card h3{
  display:flex;align-items:center;gap:var(--sp-2);
  font-size:var(--fs-13);font-weight:600;letter-spacing:.2px;
  padding-bottom:10px;margin-bottom:var(--sp-4);
  border-bottom:1px solid var(--c-line-soft);
}
.card h3 .tag{
  margin-left:auto;padding-left:10px;
  font-size:var(--fs-11);font-weight:400;color:var(--c-text-3);
}
.card h3 .fsbtn{
  margin-left:auto;
  background:none;border:1px solid var(--c-line);
  color:var(--c-text-2);border-radius:6px;
  padding:2px 9px;font-size:var(--fs-12);font-weight:400;
  transition:color .16s ease,border-color .16s ease;
}
.card h3 .fsbtn:hover{color:var(--c-gold);border-color:rgba(245,185,66,.45)}

/* ========================= 6. KPI ========================= */
.kpi{
  min-width:0;
  padding:var(--sp-4) var(--sp-5);
  border:1px solid var(--c-line-soft);
  border-radius:var(--r-lg);
  background:linear-gradient(165deg,rgba(255,255,255,.035),rgba(255,255,255,.012));
  box-shadow:var(--sh-1);
  transition:border-color .18s ease,transform .18s ease;
}
.kpi:hover{border-color:rgba(245,185,66,.28)}
.kpi .v{
  font-size:var(--fs-26);font-weight:600;letter-spacing:-.4px;
  font-variant-numeric:tabular-nums;line-height:1.15;
  color:var(--c-gold);
  overflow-wrap:anywhere;      /* 长金额不撑破卡片 */
}
.kpi .v.blue{color:var(--c-cyan)}
.kpi .l{font-size:var(--fs-12);color:var(--c-text-2);margin-top:6px}
.kpi .s{font-size:var(--fs-11);color:var(--c-text-3);margin-top:var(--sp-1);opacity:.9}

/* ========================= 7. 图表容器 ========================= */
.chart{width:100%;height:300px;min-width:0}
.chart.tall{height:340px}
.chart.sm{height:240px}
.chart.xl{height:calc(100vh - 200px);min-height:420px}

/* ========================= 8. 表格 ========================= */
.tablewrap{
  border:1px solid var(--c-line-soft);
  border-radius:var(--r-md);
  overflow:auto;
}
table.tbl{width:100%;border-collapse:collapse;font-size:var(--fs-13)}
table.tbl th{
  position:sticky;top:0;z-index:1;
  text-align:left;font-size:var(--fs-12);font-weight:500;
  letter-spacing:.3px;white-space:nowrap;
  padding:10px 12px;
  background:var(--c-bg-2);
  color:var(--c-text-2);
  border-bottom:1px solid var(--c-line-soft-2);
}
table.tbl td{
  padding:9px 12px;
  border-bottom:1px solid rgba(255,255,255,.04);
}
table.tbl tbody tr:nth-child(even) td{background:rgba(255,255,255,.012)}
table.tbl tbody tr:hover td{background:var(--bg-blue)}
table.tbl th.num,table.tbl td.num{text-align:right}
table.tbl th.sortable{cursor:pointer;user-select:none}
table.tbl th.sortable:hover{color:var(--c-gold)}
.num{font-variant-numeric:tabular-nums}

/* 可点击行的统一态（配合 data-filters） */
tr[data-filters]{cursor:pointer}
tr[data-filters]:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus-ring)}

/* ========================= 9. 控件 ========================= */
.controls{display:flex;flex-wrap:wrap;gap:var(--sp-3);align-items:center;margin-bottom:var(--sp-4)}

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  height:var(--control-h);
  padding:0 14px;
  background:var(--c-panel-2);
  border:1px solid var(--c-line-soft-2);
  border-radius:var(--r-sm);
  color:var(--c-text);font-size:var(--fs-13);white-space:nowrap;
  transition:border-color .16s ease,background .16s ease,opacity .16s ease;
}
.btn:hover{border-color:rgba(245,185,66,.45);text-decoration:none}
.btn.primary{
  background:linear-gradient(90deg,var(--c-gold),#f59e0b);
  color:#1a1300;border-color:transparent;font-weight:600;
}
.btn.primary:hover{filter:brightness(1.06)}
.btn.ghost{background:none}
.btn.danger{color:var(--c-red);border-color:rgba(248,113,113,.4)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn.sm{height:28px;padding:0 10px;font-size:var(--fs-12)}

/* 表单控件统一：高度、底色、描边、占位符 */
input,select,textarea{
  height:var(--control-h);
  padding:0 11px;
  background:var(--c-bg-2);
  border:1px solid var(--c-line);
  border-radius:var(--r-sm);
  color:var(--c-text);font-size:var(--fs-13);
  transition:border-color .16s ease,box-shadow .16s ease;
}
textarea{height:auto;padding:9px 11px;resize:vertical;line-height:1.6}
input::placeholder,textarea::placeholder{color:var(--c-text-3)}
input:hover,select:hover,textarea:hover{border-color:var(--c-line-soft-2)}
input:focus,select:focus,textarea:focus{border-color:var(--c-gold);outline:none;box-shadow:var(--focus-ring)}
select{cursor:pointer}
input[type=file]{height:auto;padding:6px 8px;cursor:pointer}
input[type=checkbox],input[type=radio]{width:auto;height:auto;accent-color:var(--c-gold)}

.seg{display:inline-flex;background:var(--c-bg-2);border:1px solid var(--c-line);border-radius:var(--r-sm);overflow:hidden}
.seg button{
  height:calc(var(--control-h) - 2px);
  background:none;border:none;color:var(--c-text-2);
  padding:0 12px;font-size:var(--fs-13);
  transition:background .16s ease,color .16s ease;
}
.seg button:hover{color:var(--c-text)}
.seg button.on{background:var(--c-gold);color:#1a1300;font-weight:600}

.monthpills{display:flex;flex-wrap:wrap;gap:var(--sp-2)}
.monthpills button{
  padding:6px 13px;
  border:1px solid var(--c-line-soft-2);
  border-radius:var(--r-pill);
  background:var(--c-bg-2);color:var(--c-text-2);
  font-size:var(--fs-12);white-space:nowrap;
  transition:background .16s ease,border-color .16s ease,color .16s ease,opacity .12s ease;
}
.monthpills button:hover{color:var(--c-text);border-color:var(--c-line-soft-2)}
.monthpills button.on{background:var(--c-blue);border-color:var(--c-blue);color:#fff;box-shadow:0 2px 10px rgba(59,130,246,.28)}
.monthpills button.incomplete{color:var(--c-gold);border-color:rgba(245,185,66,.4)}
.monthpills button.def{box-shadow:inset 0 0 0 1px var(--c-gold)}
.monthpills button.def::after{content:' ★';color:var(--c-gold)}
.monthpills.switching{opacity:.75;transform:translateY(1px)}

.tabs{display:flex;gap:var(--sp-1);margin-bottom:var(--sp-4);border-bottom:1px solid var(--c-line);overflow-x:auto}
.tabs button{
  background:none;border:none;
  color:var(--c-text-2);font-size:var(--fs-13);white-space:nowrap;
  padding:9px 14px;
  border-bottom:2px solid transparent;
  transition:color .16s ease,border-color .16s ease;
}
.tabs button:hover{color:var(--c-text)}
.tabs button.on{color:var(--c-gold);border-bottom-color:var(--c-gold)}

/* ========================= 10. 徽标 / 标签 ========================= */
.pill{display:inline-block;padding:2px 9px;border-radius:var(--r-pill);font-size:var(--fs-11);border:1px solid var(--c-line)}
.pill.severe{background:var(--bg-red);color:var(--c-red);border-color:rgba(248,113,113,.4)}
.pill.focus{background:var(--bg-orange);color:var(--c-orange);border-color:rgba(251,146,60,.4)}
.pill.tip{background:rgba(34,211,238,.14);color:var(--c-cyan);border-color:rgba(34,211,238,.35)}
.pill.ok{background:var(--bg-green);color:var(--c-green);border-color:rgba(52,211,153,.35)}
.pill.warn{background:var(--bg-gold);color:var(--c-gold);border-color:rgba(245,185,66,.4)}

.tag{font-size:var(--fs-11);color:var(--c-text-3);font-weight:400}

/* ========================= 11. 元信息条 / 口径标签 ========================= */
.metabar{
  display:flex;align-items:center;flex-wrap:wrap;
  gap:6px var(--sp-4);
  margin-top:10px;padding:9px 14px;
  background:var(--bg-blue);
  border:1px solid rgba(59,130,246,.16);
  border-radius:var(--r-md);
  font-size:var(--fs-11);color:var(--c-text-2);
}
.metabar .meta-item{white-space:nowrap}
.metabar .meta-item b{color:var(--c-text);font-weight:600;font-variant-numeric:tabular-nums}
.metabar .meta-sep{width:1px;height:12px;background:var(--c-line-soft-2)}

.glossary{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-top:10px}
.glossary .g-item{
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 10px;border-radius:var(--r-pill);
  font-size:var(--fs-11);
  background:rgba(255,255,255,.04);
  border:1px solid var(--c-line-soft);
  color:var(--c-text-2);
}
.glossary .g-item b{color:var(--c-text)}
.glossary .g-item.g-direct{border-color:rgba(59,130,246,.35);background:var(--bg-blue)}
.glossary .g-item.g-ref{border-color:rgba(245,185,66,.32);background:var(--bg-gold)}

.defnote{
  display:inline-flex;align-items:center;gap:6px;
  background:var(--bg-gold);border:1px solid rgba(245,185,66,.45);
  color:var(--c-gold);border-radius:var(--r-sm);
  padding:5px 12px;font-size:var(--fs-12);font-weight:600;
}

/* ========================= 12. 下钻筛选 chips ========================= */
.chips{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center}
.chip{
  display:inline-flex;align-items:center;gap:6px;
  padding:4px 6px 4px 12px;
  background:var(--c-panel-2);border:1px solid var(--c-line);
  border-radius:var(--r-pill);
  font-size:var(--fs-12);color:var(--c-text);
}
.chip b{color:var(--c-gold);font-weight:600}
.chip .x{
  display:inline-flex;align-items:center;justify-content:center;
  width:16px;height:16px;
  border:1px solid var(--c-line);border-radius:50%;
  color:var(--c-text-2);font-size:10px;
  transition:color .16s ease,border-color .16s ease;
}
.chip .x:hover{color:var(--c-red);border-color:rgba(248,113,113,.5)}

/* ========================= 13. 反馈态：进度 / 错误 / 骨架 / 空态 ========================= */
.busy-bar{
  position:fixed;top:0;left:0;height:2px;width:100%;z-index:200;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--c-gold),var(--c-blue),transparent);
  background-size:40% 100%;background-repeat:no-repeat;
  opacity:0;transition:opacity .2s ease;
}
.busy-bar::after{
  content:'';display:block;height:100%;background:inherit;background-size:40% 100%;
  animation:busySlide 1.1s linear infinite;
}
@keyframes busySlide{from{background-position:-40% 0}to{background-position:140% 0}}

.errbar{
  display:flex;align-items:center;gap:var(--sp-3);
  margin:0 0 var(--sp-4);padding:11px 14px;
  border:1px solid rgba(248,113,113,.32);
  background:var(--bg-red);color:#fecaca;
  border-radius:var(--r-md);font-size:var(--fs-13);
}
.errbar span{flex:1}

.skel-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp-4)}
.skel{
  height:74px;border-radius:var(--r-md);
  background:linear-gradient(100deg,rgba(255,255,255,.04) 30%,rgba(255,255,255,.10) 50%,rgba(255,255,255,.04) 70%);
  background-size:220% 100%;
  animation:shimmer 1.25s ease-in-out infinite;
}
@keyframes shimmer{from{background-position:140% 0}to{background-position:-40% 0}}

.empty-state{padding:38px 20px;text-align:center;color:var(--c-text-3)}
.empty-ico{font-size:26px;opacity:.45;margin-bottom:var(--sp-2)}
.empty-t{font-size:var(--fs-13);color:var(--c-text-2)}
.empty-s{font-size:var(--fs-12);margin-top:6px;color:var(--c-text-3);opacity:.85}
.card .empty-state{padding:26px 12px}
.empty{padding:40px;text-align:center;color:var(--c-text-3)}

.toast{
  position:fixed;bottom:var(--sp-6);left:50%;transform:translateX(-50%);
  z-index:80;
  background:var(--c-panel-2);border:1px solid var(--c-line);
  padding:11px 20px;border-radius:var(--r-md);
  box-shadow:var(--sh-2);font-size:var(--fs-13);
  max-width:min(90vw,520px);
}

/* ========================= 14. 登录页 ========================= */
.login-wrap{
  position:fixed;inset:0;
  display:flex;align-items:center;justify-content:center;
  padding:var(--sp-4);
  background:radial-gradient(1200px 600px at 50% -10%,#1b2c50,var(--c-bg));
  overflow:auto;
}
.login-card{
  width:360px;max-width:100%;
  background:var(--c-panel);border:1px solid var(--c-line);
  border-radius:var(--r-lg);padding:30px;box-shadow:var(--sh-2);
}
.login-card h1{font-size:var(--fs-18);margin:0 0 4px;color:var(--c-gold)}
.login-card .sub{color:var(--c-text-2);font-size:var(--fs-12);margin-bottom:var(--sp-5)}
.login-logo{width:230px;margin:0 auto 14px;background:#fff;border-radius:10px;padding:8px 12px}
.login-card label{display:block;font-size:var(--fs-12);color:var(--c-text-2);margin:var(--sp-3) 0 5px}
.login-card input{width:100%}
.login-card button{
  width:100%;margin-top:var(--sp-5);
  height:44px;
  background:linear-gradient(90deg,var(--c-gold),#f59e0b);
  border:none;border-radius:var(--r-sm);
  color:#1a1300;font-weight:700;font-size:var(--fs-15);
}
.login-card button:hover{filter:brightness(1.06)}
.login-err{color:var(--c-red);font-size:var(--fs-12);min-height:16px;margin-top:10px}

/* ========================= 15. 抽屉 / 模态 / 全屏面板 ========================= */
.drawer-mask{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:50}
.drawer{
  position:fixed;top:0;right:0;height:100%;
  width:560px;max-width:92vw;
  display:flex;flex-direction:column;
  background:var(--c-panel);border-left:1px solid var(--c-line);
  z-index:51;box-shadow:-8px 0 30px rgba(0,0,0,.4);
}
.drawer .dh{
  display:flex;align-items:center;
  padding:var(--sp-3) var(--sp-5);
  border-bottom:1px solid var(--c-line);flex-shrink:0;
}
.drawer .dh b{font-size:var(--fs-15)}
/* 关闭按钮用 <button> 实现（语义更佳、可键盘聚焦），需重置浏览器默认样式 */
.drawer .dh .x{
  margin-left:auto;cursor:pointer;color:var(--c-text-2);
  background:none;border:none;font-size:20px;line-height:1;
  padding:2px 8px;border-radius:var(--r-sm);
  transition:color .16s ease,background .16s ease;
}
.drawer .dh .x:hover{color:var(--c-text);background:rgba(255,255,255,.06)}
.drawer .db{padding:var(--sp-3) var(--sp-5);overflow-y:auto;flex:1}
.crumbs{font-size:var(--fs-12);color:var(--c-text-2);margin-bottom:10px}
.breadbtn{padding:3px 9px;border:1px solid var(--c-line);border-radius:6px;background:var(--c-bg-2);color:var(--c-text-2);font-size:var(--fs-12);margin-right:6px}

.modal-mask{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:60;display:flex;align-items:center;justify-content:center;padding:var(--sp-4)}
.modal{
  width:480px;max-width:100%;max-height:90vh;overflow-y:auto;
  background:var(--c-panel);border:1px solid var(--c-line);
  border-radius:var(--r-lg);padding:var(--sp-5);box-shadow:var(--sh-2);
}
.modal h3{margin:0 0 var(--sp-4);font-size:var(--fs-16);color:var(--c-gold)}
.modal.modal-wide{width:680px}
.modal.modal-mid{width:560px}
.modal label{display:block;font-size:var(--fs-12);color:var(--c-text-2);margin:10px 0 4px}
.modal input,.modal select,.modal textarea{width:100%}
.modal .row{display:flex;gap:10px}
.modal .row>*{flex:1;min-width:0}
.modal .acts{display:flex;justify-content:flex-end;gap:10px;margin-top:var(--sp-5)}

.panel-mask{position:fixed;inset:0;background:rgba(4,8,18,.74);z-index:70;display:flex;align-items:stretch;justify-content:center;padding:var(--sp-5)}
.panel-full{
  width:100%;max-width:1440px;
  display:flex;flex-direction:column;overflow:hidden;
  background:var(--c-panel);border:1px solid var(--c-line-soft-2);
  border-radius:var(--r-lg);box-shadow:var(--sh-2);
}
.panel-full .pf-head{
  display:flex;align-items:center;gap:10px;
  padding:var(--sp-3) var(--sp-5);
  border-bottom:1px solid var(--c-line);flex-shrink:0;
}
.panel-full .pf-head b{font-size:var(--fs-15);color:var(--c-gold)}
.panel-full .pf-head .tag{font-size:var(--fs-11);color:var(--c-text-3)}
.panel-full .pf-head .x{margin-left:auto;cursor:pointer;color:var(--c-text-2);font-size:22px;padding:0 6px;line-height:1}
.panel-full .pf-head .x:hover{color:var(--c-red)}
.panel-full .pf-body{padding:var(--sp-4) var(--sp-5);overflow:auto;flex:1}

/* ========================= 16. 工具类（替代行内样式） ========================= */
/* 间距 */
.mt1{margin-top:var(--sp-1)}.mt2{margin-top:var(--sp-2)}.mt3{margin-top:var(--sp-3)}
.mt4{margin-top:var(--sp-4)}.mt5{margin-top:var(--sp-5)}.mt12{margin-top:var(--sp-3)}.mt16{margin-top:var(--sp-4)}
.mb2{margin-bottom:var(--sp-2)}.mb3{margin-bottom:var(--sp-3)}.mb4{margin-bottom:var(--sp-4)}
.ml8{margin-left:var(--sp-2)}

/* 弹性 */
.flex{display:flex}.between{justify-content:space-between}.acenter{align-items:center}
.gap8{gap:var(--sp-2)}.gap12{gap:var(--sp-3)}.wrap{flex-wrap:wrap}
.flex1{flex:1;min-width:0}
.block{display:block}

/* 文本 */
.muted{color:var(--c-text-2)}
.muted2{color:var(--c-text-3)}
.f11{font-size:var(--fs-11)}.f12{font-size:var(--fs-12)}.f13{font-size:var(--fs-13)}.f15{font-size:var(--fs-15)}
.txt{color:var(--c-text)}
.gold{color:var(--c-gold)}
.blue{color:var(--c-blue)}
.ok-text{color:var(--c-green)}
.err-text{color:var(--c-red)}

/* 滚动区域高度：统一表格可视高度，避免各处硬编码不同数值 */
.tw-xs{max-height:180px}
.tw-sm{max-height:300px}
.tw-md{max-height:360px}
.tw-lg{max-height:460px}
.tw-xl{max-height:560px}
.tw-viewport{max-height:calc(100vh - 380px)}
.tw-vh60{max-height:60vh}
.tw-auto{max-height:520px}

/* 表单块（后台配置/导入页常用） */
.field{display:block;margin-bottom:var(--sp-3)}
.field > span{display:block;font-size:var(--fs-12);color:var(--c-text-2);margin-bottom:5px}
.field input,.field select,.field textarea{width:100%}

/* 行内说明条 */
.hint{font-size:var(--fs-12);color:var(--c-text-2);line-height:1.7}
.note{font-size:var(--fs-12);color:var(--c-text-3);line-height:1.6}
.note.ok{color:var(--c-green)}

/* 窄宽度输入（工具类，替代行内 width） */
.inp-w-80{width:80px}
.inp-w-150{width:150px}
.inp-w-190{width:190px}
.inp-w-280{width:280px}
.inp-full{width:100%}

/* 表单行：flex 换行 + 间距（替代行内 flex-wrap/gap） */
.form-row{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
.form-row.tight{gap:var(--sp-2)}

/* 弹窗内表单标签 */
.field-label{display:block;font-size:var(--fs-12);color:var(--c-text-2);margin:10px 0 4px}

/* 可点击指针 */
.ptr{cursor:pointer}
.maxw-520{max-width:520px}

/* 单元行可展开态（替代行内 background 切换） */
.unit-row{cursor:pointer}
.unit-row.expanded{background:var(--bg-blue)}

/* 分组小标题（替代行内 font-size/color/margin） */
.grp-label{display:block;font-size:var(--fs-13);color:var(--c-text-2);margin-bottom:6px}
.grp-title{display:flex;align-items:center;gap:10px;margin:14px 0 6px;flex-wrap:wrap}

.kv{display:flex;flex-wrap:wrap;gap:var(--sp-4);font-size:var(--fs-13)}
.kv b{color:var(--c-text);margin-left:4px}

.title-row{display:flex;align-items:center;gap:10px;margin-bottom:4px;flex-wrap:wrap}
.title-row .desc{font-size:var(--fs-12);color:var(--c-text-3)}

.sect-title{
  font-size:var(--fs-13);color:var(--c-text-2);
  margin-bottom:6px;
}

/* ========================= 17. 响应式（唯一断点区，宽→窄） ========================= */
/* 超宽屏（≥1900px）：KPI 5 列；图表行改为整行铺满，
   否则 2×span2（各占 2 列）只填 4 列会在右侧留下 1 列空隙。 */
@media(min-width:1900px){
  .view{padding:var(--sp-6)}
  .cols-4{--cols:5}
  .cols-2{--cols:3}
  .chart{height:300px}
  .chart.tall{height:330px}
  .chart.sm{height:260px}
  table.tbl{font-size:var(--fs-13)}
  .kpi .v{font-size:var(--fs-28)}
  /* 超宽屏：.dash-row 仍保持 2 列（每个模块更宽，充分利用横向空间）；.span2 铺满整行 */
  .dash-row{gap:var(--sp-5)}
  .span2{grid-column:span 5}
  /* 超宽屏：趋势分析三模块同步放大间距与高度 */
  .trend-row{gap:var(--sp-5)}
  .trend-row>:first-child>.chart{min-height:clamp(520px,52vh,720px);max-height:clamp(520px,52vh,720px)}
  .trend-row>.card>.chart,
  .trend-row>.card>.tablewrap{min-height:clamp(420px,42vh,560px);max-height:clamp(420px,42vh,560px)}
}

/* 大桌面（1600~1900px）：图表区升 3 列，KPI 保持 4 列但压缩间距避免拥挤 */
@media(min-width:1600px){
  .cols-2{--cols:3}
  .grid{gap:var(--sp-3)}
}

/* 常规桌面（1281~1600px）：4 列 KPI 偏挤，收窄留白与卡片内边距，保证呼吸感 */
@media(max-width:1600px){
  .view{padding:var(--sp-4) var(--sp-5) var(--sp-5)}
  .card{padding:var(--sp-4)}
  .grid{gap:var(--sp-3)}
  .kpi{padding:var(--sp-3) var(--sp-4)}
  .kpi .v{font-size:var(--fs-26)}
  /* 中等宽度：趋势变化仍占满整行，下方两模块并排、左对齐；
     同时进一步收紧趋势页边距与高度，把横向/纵向空间还给图表与表格 */
  .trend-row{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2)}
  .trend-row>.card{padding:var(--sp-3)}
  .trend-row>:first-child>.chart{min-height:clamp(420px,42vh,540px);max-height:clamp(420px,42vh,540px)}
  .trend-row>.card>.chart,
  .trend-row>.card>.tablewrap{min-height:clamp(360px,36vh,460px);max-height:clamp(360px,36vh,460px)}
}

/* 笔记本（≤1440px，常见 1366×768）：KPI 降为 3 列，避免每张卡过窄导致数字换行 */
@media(max-width:1440px){
  .cols-4{--cols:3}
}

/* 平板横屏（≤1280px）：KPI 3 列、图表 2 列 */
@media(max-width:1280px){
  .cols-4{--cols:3}
  .cols-6{--cols:3}
  /* 平板横屏：两模块并排会导致每个不足 600px、图表被挤压，故提前降为单列 */
  .dash-row{grid-template-columns:minmax(0,1fr);gap:var(--sp-3)}
  /* 趋势分析页同步降为单列，表格不再强制占满整行 */
  .trend-row{grid-template-columns:minmax(0,1fr);gap:var(--sp-3)}
  .trend-row>.trend-table{grid-column:auto}
}

/* 平板竖屏（≤1024px）：侧栏折叠为图标条，KPI 与三卡行降为 2 列、图表单列 */
@media(max-width:1024px){
  :root{--sidebar-w:var(--sidebar-w-collapsed)}
  .sidebar .brand b,
.sidebar .brand span,
  .nav .group{display:none}
  .sidebar .brand-logo{max-width:44px;margin:0 auto;padding:4px}
  .nav a{justify-content:center;padding:10px 0;gap:0}
  .nav a .dot{width:8px;height:8px}
  .cols-4,.cols-3{--cols:2}
  .cols-2{--cols:1}
  .skel-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  /* 平板竖屏：看板大模块区退化为单列纵向排列，避免两个模块过窄导致图表挤压 */
  .dash-row{grid-template-columns:minmax(0,1fr);gap:var(--sp-3)}
  /* 2 列时 .span2 会溢出画布，必须降为整行 */
  .span2{grid-column:span 1}
}

/* 手机：全部单列，侧栏移出画布，控件横向滚动防堆叠 */
@media(max-width:760px){
  .view{padding:var(--sp-3) var(--sp-3) var(--sp-5)}
  .cols-4,.cols-3,.cols-2{--cols:1}
  .kpi{padding:var(--sp-3) var(--sp-4)}
  .kpi .v{font-size:var(--fs-22)}
  .card{padding:var(--sp-4)}
  .topbar{padding:0 var(--sp-3);gap:var(--sp-2);height:auto;min-height:var(--topbar-h);flex-wrap:wrap;padding-top:6px;padding-bottom:6px}
  .topbar h2{font-size:var(--fs-14)}
  .chart{height:250px}
  .chart.tall{height:290px}
  .chart.sm{height:220px}
  /* 看板图表在窄屏收敛高度，避免占满整屏、阅读需频繁滚动 */
  .dash-row>.card>.chart,.dash-row>.dash-cell>.chart{min-height:300px}
  /* 趋势分析页窄屏同步收敛 */
  .trend-row>.card>.chart,
  .trend-row>.card>.tablewrap{min-height:300px;max-height:420px}
  .skel-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .metabar{gap:4px var(--sp-3);font-size:var(--fs-11);padding:8px 10px}
  .metabar .meta-sep{display:none}
  /* 月份条与筛选控件横向滚动，避免换行堆叠造成拥挤与溢出 */
  .controls{flex-wrap:nowrap;overflow-x:auto;padding-bottom:6px;-webkit-overflow-scrolling:touch}
  .monthpills{flex-wrap:nowrap}
  .controls .note{white-space:nowrap}
  .tablewrap{overflow-x:auto}
  table.tbl{min-width:640px}
  .panel-mask{padding:0}
  .panel-full{max-width:none;border-radius:0;height:100%}
  .chart.xl{height:calc(100vh - 150px)}
  .drawer{width:100%;max-width:100%}
  .modal{width:100%}
  .toast{bottom:var(--sp-4);left:var(--sp-3);right:var(--sp-3);transform:none;max-width:none}
  .tabs{padding-bottom:2px}
}

/* 超窄屏：极小间距 */
@media(max-width:420px){
  .view{padding:var(--sp-2) var(--sp-2) var(--sp-4)}
  .kpi .v{font-size:20px}
  .skel-grid{grid-template-columns:minmax(0,1fr)}
  .topbar .badge{font-size:var(--fs-11);padding:3px 8px}
}

/* 打印：隐藏交互元素，展开内容 */
@media print{
  .sidebar,.topbar,.busy-bar,.toast,.panel-mask,.drawer,.drawer-mask{display:none!important}
  body{background:#fff;color:#000}
  .view{overflow:visible;padding:0}
  .card{break-inside:avoid;border:1px solid #ccc}
}