/* ===== 织网工程·辅导员工作台 — 设计系统 ===== */
:root{
  --blue:#0071e3; --blue-2:#4aa3ff; --blue-600:#0062c4; --blue-soft:rgba(0,113,227,.10);
  --green:#23854c; --green-soft:rgba(35,133,76,.12);
  --amber:#f0a500; --amber-soft:rgba(240,165,0,.14);
  --red:#e0342b; --red-soft:rgba(224,52,43,.12);
  --purple:#7b5cff; --purple-soft:rgba(123,92,255,.12);
  --cyan:#0aa1b0; --cyan-soft:rgba(10,161,176,.12);
  --bg:#f2f2f5; --surface:#ffffff; --surface-2:#fafafc; --surface-3:#f0f0f4;
  --text:#16171a; --text-2:#4a4b50; --muted:#6b6c75;
  /* v1.9.31：--muted 由 #8a8b93 调深到 #6b6c75 —— 原先在 #f2f2f5 底上对比度仅 3.03、
     在白底 3.39，均低于 WCAG AA 正文 4.5 的要求，10–12px 的说明文字/日期/KPI 标签偏灰难读。
     新值对比度：白底 5.22、页面底 4.67，达标且仍明显弱于 --text-2(#4a4b50)，层级关系不变。 */
  --border:rgba(0,0,0,.07); --border-2:rgba(0,0,0,.12);
  --shadow-1:0 1px 2px rgba(0,0,0,.04),0 4px 14px rgba(0,0,0,.05);
  --shadow-2:0 6px 18px rgba(0,0,0,.08),0 22px 48px rgba(0,0,0,.10);
  --r-lg:20px; --r-md:14px; --r-sm:10px; --r-xs:8px;
  --sb:264px; --sb-mini:76px; --top:60px;
  /* 侧栏宽度：由 initSidebarResize() 写入 --sb-w（拖拽调整，服务端持久化）
     v1.9.31：默认 248 → 260px。248px 时 .nav-txt 只剩 94–107px，39 个菜单里 10 个
     长表名（「入党积极分子培养考察登记表」需 176px 等）被省略号截断；加宽后降到 3 个左右。 */
  --sb-w:260px;
  --ease:cubic-bezier(.32,.72,0,1);
  --font:-apple-system,BlinkMacSystemFont,"SF Pro SC","Segoe UI","PingFang SC","Microsoft YaHei",system-ui,sans-serif;
}
[data-theme="dark"]{
  --bg:#0c0c0f; --surface:#17171b; --surface-2:#1d1d22; --surface-3:#232329;
  --text:#f4f4f6; --text-2:#c5c6cc; --muted:#8b8c95;
  --border:rgba(255,255,255,.09); --border-2:rgba(255,255,255,.16);
  --shadow-1:0 1px 2px rgba(0,0,0,.4),0 6px 18px rgba(0,0,0,.35);
  --shadow-2:0 10px 30px rgba(0,0,0,.5),0 24px 60px rgba(0,0,0,.45);
  --blue:#0a84ff; --blue-2:#5ac8fa; --blue-soft:rgba(10,132,255,.16);
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0;height:100%}
body{
  font-family:var(--font); background:var(--bg); color:var(--text);
  font-size:14px; line-height:1.55; -webkit-font-smoothing:antialiased;
  overflow:hidden;
  /* v1.9.28 整页背景：卓越图等比例铺满整屏（cover 不变形、底部贴页底）+ 蓝渐变铺满；
     最上叠一层白蒙版把照片压成「很淡的底纹」。
     原因：满屏照片直接透传会穿过卡片/表格/按钮，把整个 UI 染蓝、对比度崩塌。
     v1.9.62：.84 → .72。原值把页面底压到约 250 亮度（几乎纯白），
     卡片叠上去只剩 5 级差 → 用户反馈「整个模块的背景色好像没了」。
     降到 .72 后底约 240，卡片（--g-1 = 86%）约 253，拉开约 13 级，模块的面才立得住；
     照片仍只有 ~28% 可见度，不会重新造成「UI 被染蓝」。 */
  /* v1.9.111：图片改走 /api/brand/<key>（后台「品牌外观」可替换；未上传自动回落内置默认图）。
     key：main-bg = 卓越底图，main-tile = 蓝渐层。
     张数一旦定死就不能再增删，否则 linear-gradient 的位置会串位 —— 换图靠 JS 追加 ?v=<ts> 覆盖。 */
  background-image:
    linear-gradient(rgba(255,255,255,.72), rgba(255,255,255,.72)),  /* 淡底纹蒙版 */
    url('/api/brand/main-bg'),                                      /* 卓越图，等比例铺满、底部贴页底 */
    url('/api/brand/main-tile');                                    /* 蓝渐变，铺满整页 */
  background-repeat: no-repeat, no-repeat, no-repeat;
  background-position: center center, center bottom, center center;
  background-size: 100% 100%, cover, 100% 100%;
  background-attachment: fixed;
}
/* 暗色主题：换成深色蒙版，避免白蒙版把暗色界面冲亮 */
/* v1.9.62：.90/.88 → .78/.76，与亮色侧同步（原值把底压到接近纯黑，卡片同样看不出面） */
[data-theme="dark"] body{
  background-image:
    linear-gradient(rgba(10,10,14,.78), rgba(10,10,14,.76)),
    url('/api/brand/main-bg'),
    url('/api/brand/main-tile');
  background-repeat: no-repeat, no-repeat, no-repeat;
  background-position: center center, center bottom, center center;
  background-size: 100% 100%, cover, 100% 100%;
  background-attachment: fixed;
}
button,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}
a{color:var(--blue);text-decoration:none}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-thumb{background:var(--border-2);border-radius:9px}
::-webkit-scrollbar-track{background:transparent}

/* ===== 布局 ===== */
#app{display:flex;height:100vh;width:100%}
.sidebar{
  width:var(--sb-w);flex:0 0 var(--sb-w);background:var(--surface);border-right:1px solid var(--border);
  display:flex;flex-direction:column;z-index:60;position:relative;
}
/* 拖拽调宽时不要 transition，否则跟手感差；松手后恢复（body.sb-resizing 移除） */
body:not(.sb-resizing) .sidebar{transition:width .28s var(--ease)}
body.sb-resizing{cursor:col-resize;user-select:none}
body.sb-resizing *{cursor:col-resize !important}
/* 侧栏宽度拖拽条 */
.sb-resizer{
  position:absolute;top:0;right:-3px;bottom:0;width:6px;z-index:70;cursor:col-resize;
  background:transparent;touch-action:none;
}
.sb-resizer::after{
  content:'';position:absolute;top:50%;right:2px;width:3px;height:34px;margin-top:-17px;
  border-radius:3px;background:var(--border-2);opacity:0;transition:opacity .18s var(--ease);
}
.sb-resizer:hover::after,.sb-resizer:active::after{opacity:.55;background:var(--blue)}
.sb-collapsed .sb-resizer{display:none}
.sb-brand{height:var(--top);display:flex;align-items:center;gap:10px;padding:0 16px;border-bottom:1px solid var(--border)}
.sb-logo{width:30px;height:30px;border-radius:9px;background:linear-gradient(135deg,var(--blue),var(--blue-2));display:grid;place-items:center;color:#fff;font-weight:700;font-size:15px;box-shadow:0 4px 12px var(--blue-soft);flex:0 0 auto}
.sb-title{font-weight:650;font-size:15px;letter-spacing:-.2px;white-space:nowrap;overflow:hidden}
.sb-sub{font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden}
.sb-scroll{flex:1;overflow-y:auto;padding:10px 10px 24px}
/* ---------- v1.9.44 左栏底部固定区 ----------
   「系统」分组与「已隐藏项」由 renderNav 搬到这里：不随菜单滚动，永远看得见。
   空的时候整块隐藏（普通账号看不到系统菜单，就完全不占位）。 */
/* ⚠️ v1.9.118：这里**不能**写 background:var(--surface)（不透明纯色）。
   真踩（2026-09-18 用户报障：「数据表，系统这块背景色没有跟着背景色走」）：
   .sidebar 走的是 rgba(255,255,255,.58) + backdrop-filter 的玻璃底（跟随皮肤/主题/底图），
   而 .sb-pins 用不透明的 --surface 把整块底部压成死白 → 与上方「业务分组区」
   出现 255 vs ~250 的硬台阶，换皮肤/换主题时两块颜色不同步，像贴了张白纸。
   .sb-pins 是普通 flex 子项（无 position:sticky、无 z-index），不靠不透明去遮滚动内容，
   所以直接留透明、让它透出 .sidebar 的玻璃底即可 —— 这也正是 .sb-scroll/.sb-foot 的做法。 */
.sb-pins{flex:0 0 auto;padding:8px 10px 10px;border-top:1px solid var(--border);background:transparent}
.sb-pins:empty{display:none;border-top:0;padding:0}
.sb-pins .sb-group{margin-top:2px}
/* v1.9.67：底部固定区（数据表 / 系统）的分组标题字号调小，跟说明书页的字号对齐
   （说明书导航是 12.5px）。它们属于「工具性分组」，比业务分组（我的驾驶舱 / 台账 / 插件）
   低一级，缩小后视觉层级更清楚；正文菜单项字号不动。 */
.sb-pins .sb-group{font-size:12.5px;font-weight:600;letter-spacing:.3px;padding:4px 8px}
.sb-pins .sb-group .sb-group-t{font-weight:600}
.sb-collapsed .sb-pins{padding:8px 6px 8px}
.sb-collapsed .sb-pins .sb-group-t{display:none}
.sb-collapsed .sb-pins .sb-group{justify-content:center}
/* 侧栏分组标题（可点击折叠，Apple 风格） */
.sb-group{
  display:flex;align-items:center;gap:7px;width:100%;
  margin:14px 0 5px;padding:5px 8px;border:0;border-radius:7px;
  background:transparent;cursor:pointer;text-align:left;
  font-size:14px;font-weight:700;letter-spacing:.6px;color:var(--text);
  transition:background .16s var(--ease),color .16s var(--ease);
}
.sb-group:hover{background:var(--surface-3);color:var(--blue)}
.sb-group:active{transform:scale(.99)}
/* v1.9.3：分类标题前不再显示折叠箭头图标（常规模式隐藏）；
   折叠状态用标题变灰提示；迷你侧栏下箭头是唯一标识，单独恢复 */
.sb-group.off .sb-group-t{color:var(--muted);font-weight:600}
.sb-group-arrow{
  width:13px;height:13px;flex:0 0 auto;display:none;place-items:center;
  transition:transform .22s var(--ease);opacity:.85;
}
.sb-group-arrow svg{width:13px;height:13px;stroke:currentColor;stroke-width:2.1;fill:none;stroke-linecap:round;stroke-linejoin:round}
.sb-group.off .sb-group-arrow{transform:rotate(-90deg)}
.sb-group-t{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;text-align:center}
.sb-group-body{display:contents}
/* 分组行右上角：重命名 / 删除（悬停或聚焦时出现）
   v1.9.5：改为绝对定位——原先 opacity:0 仍占布局空间，把居中标题挤偏约 20px */
.sb-group{position:relative}
.sb-gops{position:absolute;right:6px;top:50%;transform:translateY(-50%);display:inline-flex;gap:2px;flex:none;opacity:0;transition:opacity .16s var(--ease)}
.sb-group:hover .sb-gops,.sb-gops:focus-within{opacity:1}
.sb-collapsed .sb-gops{display:none}
.sb-gop{
  width:24px;height:24px;padding:0;border:0;border-radius:6px;background:transparent;
  color:var(--muted);cursor:pointer;display:grid;place-items:center;
  transition:background .15s var(--ease),color .15s var(--ease),transform .12s var(--ease);
}
.sb-gop:hover{background:var(--surface-3);color:var(--blue);transform:scale(1.12)}
.sb-gop.danger:hover{background:var(--red-soft);color:var(--red)}
.sb-gop svg{width:13px;height:13px}
.sb-collapsed .sb-gops{display:none}
/* v1.9.0：系统固定分类的锁定标记 */
.sb-gop-lock{width:24px;height:24px;display:grid;place-items:center;color:var(--muted);opacity:.55}
.sb-gop-lock svg{width:12px;height:12px}
/* v1.9.0：固定系统菜单项——视觉上与普通项区分，且不可拖动/隐藏 */
.nav-item.nav-fixed .nav-txt{font-weight:600}
.nav-item.nav-fixed::after{
  content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:2px;height:16px;border-radius:0 2px 2px 0;background:var(--blue);opacity:.55;
}
.nav-item.nav-fixed .nav-hide{display:none}

/* 单项：hover 显示的隐藏按钮 */
/* 24px 太占横向空间：这个按钮只在 hover 出现（触屏无 hover，永远看不到），
   把它撑大会白吃掉菜单名 4px 宽度，得不偿失，保持 20px。 */
.nav-hide{
  margin-left:auto;flex:0 0 auto;width:20px;height:20px;padding:0;
  border:0;border-radius:6px;background:transparent;color:var(--muted);
  display:grid;place-items:center;cursor:pointer;opacity:0;
  transition:opacity .16s var(--ease),background .16s var(--ease),color .16s var(--ease);
}
.nav-hide svg{width:14px;height:14px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round}
.nav-item:hover .nav-hide{opacity:.7}
.nav-hide:hover{opacity:1;background:var(--surface-3);color:var(--text)}
.nav-hide.restore{opacity:.85}
.nav-hide.restore:hover{background:var(--blue-soft);color:var(--blue)}

/* 已隐藏项管理入口 */
.sb-hidden-row{
  display:flex;align-items:center;gap:7px;width:100%;
  margin:6px 0 2px;padding:6px 9px;
  border:1px dashed var(--border-2);border-radius:8px;
  background:transparent;color:var(--muted);cursor:pointer;
  font-size:11.5px;font-weight:600;
  transition:border-color .16s var(--ease),color .16s var(--ease),background .16s var(--ease);
}
.sb-hidden-row:hover{border-color:var(--blue);color:var(--blue);background:var(--blue-soft)}
.sb-hidden-row.on{border-style:solid;border-color:var(--blue);color:var(--blue);background:var(--blue-soft)}
.sb-hidden-ic{width:14px;height:14px;flex:0 0 auto;display:grid;place-items:center}
.sb-hidden-ic svg{width:14px;height:14px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round}
.nav-item.ghost{opacity:.62}
.nav-item.ghost:hover{opacity:1}

/* 迷你栏（侧栏折叠）下隐藏单项入口，避免拥挤 */
.sb-collapsed .nav-hide,
.sb-collapsed .sb-hidden-row,
.sb-collapsed .sb-hidden-list,
.sb-collapsed .sb-group-t{display:none}
.sb-collapsed .sb-group{justify-content:center;padding:4px 0;margin:9px 0 3px}
.sb-collapsed .sb-group-arrow{display:grid;margin:0}
.nav-item{
  display:flex;align-items:center;gap:9px;padding:9px 9px;border-radius:var(--r-sm);
  cursor:pointer;color:var(--text-2);font-size:13.5px;font-weight:500;margin-bottom:2px;
  transition:background .18s,color .18s,transform .18s;position:relative;user-select:none;
}
.nav-item:hover{background:var(--surface-3);color:var(--text)}
.nav-item.active{background:var(--blue-soft);color:var(--blue);font-weight:600}
.nav-item.active::before{content:"";position:absolute;left:-10px;top:50%;transform:translateY(-50%);width:3px;height:18px;border-radius:0 3px 3px 0;background:var(--blue)}
.nav-ic{width:20px;height:20px;flex:0 0 20px;display:grid;place-items:center}
.nav-ic svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.nav-txt{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1}
.nav-badge{font-size:10.5px;background:var(--surface-3);color:var(--muted);border-radius:20px;padding:1px 6px;font-weight:600;letter-spacing:.1px}
.sb-foot{padding:10px;border-top:1px solid var(--border);display:flex;align-items:center;gap:8px}
.avatar{width:30px;height:30px;border-radius:50%;background:linear-gradient(135deg,var(--blue),var(--blue-2));color:#fff;display:grid;place-items:center;font-size:12px;font-weight:650;flex:0 0 auto}

.main{flex:1;min-width:0;display:flex;flex-direction:column;height:100vh}
.topbar{
  height:var(--top);flex:0 0 var(--top);background:rgba(255,255,255,.78);backdrop-filter:saturate(180%) blur(20px);
  border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;padding:0 20px;z-index:40;
}
[data-theme="dark"] .topbar{background:rgba(23,23,27,.78)}
.tb-title{font-size:16px;font-weight:650;letter-spacing:-.2px;display:flex;align-items:center;gap:8px;min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tb-title small{font-weight:400;color:var(--muted);font-size:12px}
.tb-spacer{flex:1}
.icon-btn{width:34px;height:34px;border-radius:10px;border:1px solid var(--border);background:var(--surface);display:grid;place-items:center;cursor:pointer;color:var(--text-2);transition:all .18s}
.icon-btn:hover{background:var(--surface-3);color:var(--text);transform:translateY(-1px)}
.icon-btn svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.content{flex:1;overflow-y:auto;overflow-x:hidden;padding:22px 24px 60px;scroll-behavior:smooth;position:relative;z-index:1}
.wrap{max-width:1280px;margin:0 auto}

/* ===== 卡片 / 网格 ===== */
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--shadow-1);padding:18px;transition:box-shadow .25s,transform .25s}
.card.hoverable:hover{box-shadow:var(--shadow-2);transform:translateY(-2px)}
.card-pad-0{padding:0;overflow:hidden}
.grid{display:grid;gap:16px}
.g2{grid-template-columns:repeat(2,minmax(0,1fr))}
.g3{grid-template-columns:repeat(3,minmax(0,1fr))}
.g4{grid-template-columns:repeat(4,minmax(0,1fr))}
.grid-blocks{display:grid;gap:16px;grid-template-columns:repeat(12,minmax(0,1fr))}
.blk{grid-column:span 12;min-width:0}
.blk[data-w="6"]{grid-column:span 6}
.blk[data-w="4"]{grid-column:span 4}
.blk[data-w="3"]{grid-column:span 3}
.blk[data-w="8"]{grid-column:span 8}
.blk[data-w="12"]{grid-column:span 12}

/* KPI */
.kpi{position:relative;overflow:hidden}
.kpi-label{font-size:12.5px;color:var(--muted);font-weight:550;display:flex;align-items:center;gap:6px}
.kpi-val{font-size:32px;font-weight:680;letter-spacing:-1px;margin:6px 0 2px;line-height:1.1;font-variant-numeric:tabular-nums}
.kpi-sub{font-size:12px;color:var(--muted);display:flex;align-items:center;gap:6px}
.kpi-ic{position:absolute;right:16px;top:16px;width:38px;height:38px;border-radius:12px;display:grid;place-items:center}
.kpi-ic svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.kpi-spark{height:34px;margin-top:8px}
.delta{font-weight:650;font-size:12px}
.delta.up{color:var(--green)} .delta.down{color:var(--red)}

/* ===== 按钮 / 输入 ===== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;border:0;border-radius:999px;
  padding:9px 18px;font-size:13.5px;font-weight:600;cursor:pointer;background:var(--blue);color:#fff;
  transition:transform .16s var(--ease),box-shadow .16s,opacity .16s;white-space:nowrap;
}
.btn:hover{transform:translateY(-1px);box-shadow:0 6px 18px rgba(0,113,227,.32)}
.btn:active{transform:translateY(0) scale(.985)}
.btn.ghost{background:var(--surface);color:var(--text);border:1px solid var(--border-2)}
.btn.ghost:hover{background:var(--surface-3);box-shadow:none}
/* v1.9.20：驾驶舱「已设为默认首页」按钮激活态（高于 .btn.ghost 以覆盖各主题背景） */
.btn.ghost.home-on{background:var(--blue-soft);color:var(--blue);border-color:transparent}
.btn.ghost.home-on:hover{background:color-mix(in srgb, var(--blue) 14%, transparent);color:var(--blue)}
.btn.soft{background:var(--blue-soft);color:var(--blue)}
.btn.danger{background:var(--red-soft);color:var(--red)}
.btn.sm{padding:6px 13px;font-size:12.5px}
.btn.block{width:100%}
.btn[disabled]{opacity:.5;pointer-events:none}
.btn svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.input,select.input,textarea.input{
  width:100%;border:1px solid var(--border-2);background:var(--surface);border-radius:var(--r-sm);
  padding:9px 12px;font-size:14px;outline:none;transition:border-color .18s,box-shadow .18s;
}
.input:focus{border-color:var(--blue);box-shadow:0 0 0 4px var(--blue-soft)}
textarea.input{min-height:88px;resize:vertical;line-height:1.6}
label.fl{display:block;font-size:12.5px;font-weight:600;color:var(--text-2);margin:0 0 6px}
.field{margin-bottom:14px}
.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.chip{display:inline-flex;align-items:center;gap:5px;border-radius:999px;padding:3px 10px;font-size:11.5px;font-weight:600;background:var(--surface-3);color:var(--text-2)}
.chip.blue{background:var(--blue-soft);color:var(--blue)}
.chip.green{background:var(--green-soft);color:var(--green)}
.chip.amber{background:var(--amber-soft);color:var(--amber)}
.chip.red{background:var(--red-soft);color:var(--red)}
.chip.purple{background:var(--purple-soft);color:var(--purple)}
.switch{width:42px;height:24px;border-radius:999px;background:var(--surface-3);border:1px solid var(--border-2);position:relative;cursor:pointer;transition:background .2s;flex:0 0 auto}
.switch::after{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.25);transition:transform .22s var(--ease)}
.switch.on{background:var(--blue);border-color:var(--blue)}
.switch.on::after{transform:translateX(18px)}

/* ===== 表格 ===== */
.table-wrap{overflow:auto;border-radius:var(--r-md);border:1px solid var(--border);background:var(--surface)}
table.tb{width:100%;border-collapse:separate;border-spacing:0;font-size:13px}
table.tb th{
  position:sticky;top:0;background:var(--surface-2);font-weight:650;text-align:left;padding:10px 12px;
  border-bottom:1px solid var(--border);white-space:nowrap;z-index:2;color:var(--text-2);font-size:12.5px;
}
table.tb td{padding:9px 12px;border-bottom:1px solid var(--border);vertical-align:top;max-width:280px}
table.tb tbody tr{transition:background .14s}
table.tb tbody tr:hover{background:var(--surface-2)}
table.tb td.clip{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* v1.9.31：表格复选框原来是浏览器默认的 15px，点击目标偏小；放大到 17px，
   并让所在单元格整块可点（行本身也支持点击切换选中，见 datatable.js）。 */
table.tb input[type="checkbox"].dt-ck,
table.tb input[type="checkbox"]#dt-ck-all{
  width:17px;height:17px;margin:0;cursor:pointer;accent-color:var(--blue);vertical-align:middle;
}
table.tb th.ck-th,table.tb td.ck-cell{
  width:38px;cursor:pointer;text-align:center;padding-left:6px;padding-right:6px;
}
.cell-link{color:var(--blue);cursor:pointer}

/* ===== 弹层 ===== */
.mask{position:fixed;inset:0;background:rgba(0,0,0,.42);backdrop-filter:blur(4px);z-index:200;display:flex;align-items:center;justify-content:center;padding:20px;animation:fade .2s var(--ease)}
.modal{background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--shadow-2);width:min(560px,100%);max-height:88vh;display:flex;flex-direction:column;animation:pop .28s var(--ease)}
.modal.wide{width:min(920px,100%)}
.modal-hd{padding:16px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px}
.modal-hd h3{margin:0;font-size:16px;font-weight:650;flex:1}
.modal-bd{padding:18px 20px;overflow-y:auto}
.modal-ft{padding:14px 20px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:10px}
#toasts{position:fixed;bottom:26px;left:50%;transform:translateX(-50%);z-index:300;display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none}
.toast{background:var(--text);color:var(--surface);padding:10px 18px;border-radius:999px;font-size:13px;font-weight:550;box-shadow:var(--shadow-2);animation:toastIn .3s var(--ease)}
.toast.ok{background:rgba(35,133,76,.96)} .toast.err{background:rgba(224,52,43,.96)}

/* ===== 登录 ===== */
.login-wrap{position:fixed;inset:0;display:grid;place-items:center;background:transparent;z-index:500;padding:20px}
[data-theme="dark"] .login-wrap{ background:transparent; }
.login-card{width:min(400px,100%);background:var(--surface);border-radius:26px;box-shadow:var(--shadow-2);padding:34px 30px;animation:pop .4s var(--ease)}
.login-logo{width:54px;height:54px;border-radius:16px;background:linear-gradient(135deg,var(--blue),var(--blue-2));display:grid;place-items:center;color:#fff;font-size:22px;font-weight:700;margin:0 auto 16px;box-shadow:0 10px 26px var(--blue-soft)}
.login-card h1{text-align:center;font-size:20px;margin:0 0 4px;font-weight:680;letter-spacing:-.3px}
.login-card p.sub{text-align:center;color:var(--muted);font-size:12.5px;margin:0 0 22px}
.tabs{display:flex;background:var(--surface-3);border-radius:999px;padding:3px;margin-bottom:20px}
.tabs div{flex:1;text-align:center;padding:7px;border-radius:999px;font-size:13px;font-weight:600;cursor:pointer;color:var(--muted);transition:all .2s}
.tabs div.on{background:var(--surface);color:var(--text);box-shadow:var(--shadow-1)}

/* ===== 文案编辑模式 ===== */
body.edit-mode [data-cp]{outline:1px dashed var(--blue);outline-offset:3px;border-radius:4px;cursor:text;transition:outline-color .2s}
body.edit-mode [data-cp]:hover{outline-color:var(--amber);background:rgba(240,165,0,.06)}
body.edit-mode [data-cp]:focus{outline:2px solid var(--blue);background:var(--blue-soft)}
.edit-bar{position:fixed;right:22px;bottom:22px;z-index:250;display:flex;gap:10px;align-items:center}
.edit-bar .btn{box-shadow:var(--shadow-2)}
.edit-hint{position:fixed;left:50%;transform:translateX(-50%);bottom:80px;background:rgba(22,23,26,.9);color:#fff;font-size:12px;padding:7px 14px;border-radius:999px;z-index:250;animation:fade .3s}

/* ===== 杂项 ===== */
.sec-hd{display:flex;align-items:center;gap:10px;margin:0 0 14px}
.sec-hd h2{font-size:17px;font-weight:670;margin:0;letter-spacing:-.2px}
.sec-hd .sp{flex:1}
.muted{color:var(--muted)}
.small{font-size:12px}
.hr{height:1px;background:var(--border);margin:16px 0}
.empty{text-align:center;padding:46px 20px;color:var(--muted)}
.empty svg{width:44px;height:44px;fill:none;stroke:var(--border-2);stroke-width:1.5;margin-bottom:10px}
.skeleton{background:linear-gradient(90deg,var(--surface-3) 25%,var(--surface-2) 37%,var(--surface-3) 63%);background-size:400% 100%;animation:shimmer 1.4s infinite;border-radius:var(--r-sm)}
.pill-tabs{display:flex;gap:6px;overflow-x:auto;padding-bottom:2px}
.pill-tabs .p{padding:6px 14px;border-radius:999px;font-size:12.5px;font-weight:600;color:var(--text-2);background:var(--surface);border:1px solid var(--border);cursor:pointer;white-space:nowrap;transition:all .18s}
.pill-tabs .p.on{background:var(--text);color:var(--surface);border-color:var(--text)}
.list-item{display:flex;align-items:center;gap:12px;padding:11px 12px;border-radius:var(--r-sm);transition:background .16s}
.list-item:hover{background:var(--surface-2)}
.avatar-sm{width:34px;height:34px;border-radius:11px;background:var(--surface-3);display:grid;place-items:center;font-weight:650;font-size:13px;color:var(--text-2);flex:0 0 auto}
.dot{width:7px;height:7px;border-radius:50%;display:inline-block}
.progress{height:7px;border-radius:99px;background:var(--surface-3);overflow:hidden}
.progress > i{display:block;height:100%;border-radius:99px;background:var(--blue);width:0;transition:width .8s var(--ease)}

/* 动画 */
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes pop{from{opacity:0;transform:translateY(14px) scale(.97)}to{opacity:1;transform:none}}
@keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@keyframes shimmer{0%{background-position:100% 0}100%{background-position:0 0}}
@keyframes toastIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
/* fill-mode 用 backwards：both 会把 to{transform:none} 永久钉在元素上，
   动画优先级高于普通声明 → .kpi:hover 等上浮 transform 永远不生效（v1.7.6 修复，同 dmIn） */
.reveal{animation:fadeUp .5s var(--ease) backwards}
.reveal:nth-child(2){animation-delay:.05s}.reveal:nth-child(3){animation-delay:.1s}
.reveal:nth-child(4){animation-delay:.15s}.reveal:nth-child(5){animation-delay:.2s}
.reveal:nth-child(6){animation-delay:.25s}.reveal:nth-child(7){animation-delay:.3s}
.reveal:nth-child(8){animation-delay:.35s}

/* 图表 */
.chart{width:100%;overflow:visible}
.chart text{font-family:var(--font);fill:var(--muted);font-size:11px}
.chart .axis{stroke:var(--border);stroke-width:1}
.chart .gridline{stroke:var(--border);stroke-width:1;stroke-dasharray:3 4;opacity:.7}
.bar-anim{transform-origin:bottom;animation:growY .7s var(--ease) both}
@keyframes growY{from{transform:scaleY(0)}to{transform:scaleY(1)}}
.hbar-anim{transform-origin:left;animation:growX .8s var(--ease) both}
@keyframes growX{from{transform:scaleX(0)}to{transform:scaleX(1)}}
.line-anim{stroke-dasharray:var(--len);stroke-dashoffset:var(--len);animation:draw 1.1s var(--ease) forwards}
@keyframes draw{to{stroke-dashoffset:0}}
.fade-in{animation:fade .8s var(--ease) both}
.pie-anim{animation:pieIn .8s var(--ease) both;transform-origin:center}
@keyframes pieIn{from{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}

/* ===== 响应式 ===== */
@media (max-width:1240px){ .g4{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (max-width:1100px){
  .sidebar{position:fixed;left:0;top:0;bottom:0;transform:translateX(-102%);box-shadow:var(--shadow-2)}
  .sidebar.open{transform:none}
  .sb-mask{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:55;animation:fade .2s}
  #menu-btn{display:grid!important}
  .content{padding:18px 16px 60px}
  .blk[data-w="3"]{grid-column:span 6}
}
@media (max-width:860px){
  .g3,.g2{grid-template-columns:1fr}
  .blk[data-w="4"],.blk[data-w="8"],.blk[data-w="6"]{grid-column:span 12}
  .topbar{padding:0 14px}
  .tb-title{font-size:15px}
  .kpi-val{font-size:27px}
  .modal{border-radius:20px}
}
@media (max-width:560px){
  .content{padding:14px 12px 70px}
  .card{padding:15px;border-radius:16px}
  .g4{grid-template-columns:1fr}
  .btn{padding:9px 15px}
  #toasts{left:12px;right:12px;transform:none;align-items:stretch}
  .toast{text-align:center}
  #tb-actions .btn{display:none}
  #tb-actions{display:none}
  .topbar{padding:0 10px;gap:6px}
  .icon-btn{width:36px;height:36px;border-radius:10px}
  /* v1.9.31：移动端可点控件统一抬到 40px（原来 30px，手指容易点空） */
  .btn,.tbtn,.act-more-btn{min-height:40px}
  .btn.sm{min-height:40px;padding:8px 14px}
  .seg > button{min-height:38px}
  .chip{padding:4px 11px}
}
#menu-btn{display:none}
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms!important;transition-duration:.01ms!important}
}

/* ===================== 10 套皮肤（每套含亮/暗两版，全部变量化） ===================== */
/* 1 极光 Aurora */
[data-skin="aurora"]{--blue:#6f6ff7;--blue-2:#a78bfa;--blue-soft:rgba(111,111,247,.12);--bg:#f4f4fd;--surface:#ffffff;--surface-2:#fafaff;--surface-3:#ececfb;}
[data-theme="dark"][data-skin="aurora"]{--blue:#8b8bff;--blue-2:#c4b5fd;--blue-soft:rgba(139,139,255,.18);--bg:#0c0c16;--surface:#16161f;--surface-2:#1b1b26;--surface-3:#232330;--text:#f2f2f8;--text-2:#c3c3d0;--muted:#8b8b9a;--border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.17);}
/* 2 暖阳 Sunset */
[data-skin="sunset"]{--blue:#f2703a;--blue-2:#ffb067;--blue-soft:rgba(242,112,58,.13);--bg:#fff7f2;--surface:#ffffff;--surface-2:#fffaf6;--surface-3:#fdedE2;}
[data-theme="dark"][data-skin="sunset"]{--blue:#ff8a56;--blue-2:#ffc08a;--blue-soft:rgba(255,138,86,.18);--bg:#170f0b;--surface:#1f1611;--surface-2:#251a14;--surface-3:#2e2119;--text:#fdf3ec;--text-2:#d6c1b4;--muted:#9c8579;--border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.17);}
/* 3 墨玉 Jade（品牌宫殿绿） */
[data-skin="jade"]{--blue:#23854c;--blue-2:#4caf7d;--blue-soft:rgba(35,133,76,.12);--bg:#f1f7f3;--surface:#ffffff;--surface-2:#f7fbf8;--surface-3:#e6f0ea;}
[data-theme="dark"][data-skin="jade"]{--blue:#3cb56b;--blue-2:#7bd6a2;--blue-soft:rgba(60,181,107,.18);--bg:#0a120d;--surface:#131d16;--surface-2:#17241c;--surface-3:#1e2d24;--text:#eef7f1;--text-2:#bcd3c4;--muted:#7d9687;--border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.17);}
/* 4 石墨 Graphite */
[data-skin="graphite"]{--blue:#3f3f46;--blue-2:#71717a;--blue-soft:rgba(63,63,70,.10);--bg:#f4f4f5;--surface:#ffffff;--surface-2:#fafafa;--surface-3:#e9e9ec;}
[data-theme="dark"][data-skin="graphite"]{--blue:#a1a1aa;--blue-2:#d4d4d8;--blue-soft:rgba(161,161,170,.16);--bg:#0b0b0d;--surface:#151517;--surface-2:#1a1a1d;--surface-3:#232327;--text:#f4f4f5;--text-2:#c8c8cc;--muted:#8c8c94;--border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.17);}
/* 5 樱雪 Sakura */
[data-skin="sakura"]{--blue:#ec4899;--blue-2:#fda4c4;--blue-soft:rgba(236,72,153,.12);--bg:#fff6f9;--surface:#ffffff;--surface-2:#fffafc;--surface-3:#fdeaf1;}
[data-theme="dark"][data-skin="sakura"]{--blue:#f472b6;--blue-2:#fbcfe8;--blue-soft:rgba(244,114,182,.18);--bg:#160d13;--surface:#1e141b;--surface-2:#241820;--surface-3:#2d1f28;--text:#fdf0f6;--text-2:#dcbfd0;--muted:#a1848f;--border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.17);}
/* 6 深海 Ocean */
[data-skin="ocean"]{--blue:#0891b2;--blue-2:#22d3ee;--blue-soft:rgba(8,145,178,.12);--bg:#f0f9fb;--surface:#ffffff;--surface-2:#f6fcfd;--surface-3:#e2f1f5;}
[data-theme="dark"][data-skin="ocean"]{--blue:#22d3ee;--blue-2:#67e8f9;--blue-soft:rgba(34,211,238,.18);--bg:#071417;--surface:#0f1e23;--surface-2:#13262c;--surface-3:#193036;--text:#eafafd;--text-2:#b5d8e0;--muted:#7b9aa3;--border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.17);}
/* 7 奶油 Cream */
[data-skin="cream"]{--blue:#b45309;--blue-2:#e0b878;--blue-soft:rgba(180,83,9,.12);--bg:#fdfaf3;--surface:#ffffff;--surface-2:#fdf8ee;--surface-3:#f5ebd9;}
[data-theme="dark"][data-skin="cream"]{--blue:#d99a2b;--blue-2:#f0cf8e;--blue-soft:rgba(217,154,43,.18);--bg:#15110b;--surface:#1d1811;--surface-2:#241d14;--surface-3:#2d2418;--text:#fdf6e8;--text-2:#dccdae;--muted:#9c8c6d;--border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.17);}
/* 8 霓虹 Neon */
[data-skin="neon"]{--blue:#7c3aed;--blue-2:#06b6d4;--blue-soft:rgba(124,58,237,.13);--bg:#f2f4ff;--surface:#ffffff;--surface-2:#f8f9ff;--surface-3:#e8ebff;--shadow-1:0 1px 2px rgba(124,58,237,.08),0 4px 14px rgba(124,58,237,.10);--shadow-2:0 6px 18px rgba(124,58,237,.16),0 22px 48px rgba(124,58,237,.14);}
[data-theme="dark"][data-skin="neon"]{--blue:#a855f7;--blue-2:#22d3ee;--blue-soft:rgba(168,85,247,.20);--bg:#07060f;--surface:#120e1f;--surface-2:#171228;--surface-3:#1f1833;--text:#f2eeff;--text-2:#c9bce8;--muted:#8d7fb0;--border:rgba(168,85,247,.22);--border-2:rgba(168,85,247,.34);--shadow-1:0 1px 2px rgba(168,85,247,.20),0 6px 18px rgba(168,85,247,.18);--shadow-2:0 10px 30px rgba(168,85,247,.28),0 24px 60px rgba(168,85,247,.22);}
/* 9 极简 Pure */
[data-skin="pure"]{--blue:#111111;--blue-2:#555555;--blue-soft:rgba(0,0,0,.07);--bg:#ffffff;--surface:#ffffff;--surface-2:#fbfbfb;--surface-3:#f0f0f0;--r-lg:10px;--r-md:8px;--r-sm:6px;--shadow-1:0 0 0 1px rgba(0,0,0,.07);--shadow-2:0 8px 28px rgba(0,0,0,.10);}
[data-theme="dark"][data-skin="pure"]{--blue:#ffffff;--blue-2:#b0b0b0;--blue-soft:rgba(255,255,255,.14);--bg:#000000;--surface:#0a0a0a;--surface-2:#111111;--surface-3:#1a1a1a;--text:#ffffff;--text-2:#d0d0d0;--muted:#8a8a8a;--border:rgba(255,255,255,.14);--border-2:rgba(255,255,255,.24);--shadow-1:0 0 0 1px rgba(255,255,255,.12);--shadow-2:0 8px 28px rgba(0,0,0,.6);}
[data-theme="dark"][data-skin="pure"] .btn{color:#000}
[data-theme="dark"][data-skin="pure"] .btn.ghost{color:#fff}
/* 10 宝蓝 Sapphire */
[data-skin="sapphire"]{--blue:#1d4ed8;--blue-2:#60a5fa;--blue-soft:rgba(29,78,216,.12);--bg:#f2f6fd;--surface:#ffffff;--surface-2:#f7fafe;--surface-3:#e4ecfa;}
[data-theme="dark"][data-skin="sapphire"]{--blue:#3b82f6;--blue-2:#93c5fd;--blue-soft:rgba(59,130,246,.18);--bg:#070b16;--surface:#0f1522;--surface-2:#141b2b;--surface-3:#1b2436;--text:#eef4ff;--text-2:#bfd0ea;--muted:#7f8ea8;--border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.17);}

/* 11 正红 Crimson（v1.9.112 新增） */
[data-skin="crimson"]{--blue:#d7261e;--blue-2:#ff6b52;--blue-soft:rgba(215,38,30,.12);--bg:#fff5f4;--surface:#ffffff;--surface-2:#fffafa;--surface-3:#fbe6e4;}
[data-theme="dark"][data-skin="crimson"]{--blue:#ff4d3d;--blue-2:#ff8f7a;--blue-soft:rgba(255,77,61,.20);--bg:#160b0a;--surface:#1e1210;--surface-2:#251614;--surface-3:#2e1c19;--text:#fdf0ee;--text-2:#dcbcb6;--muted:#a1847e;--border:rgba(255,77,61,.20);--border-2:rgba(255,77,61,.32);}

/* 皮肤选择器面板 */
.skin-panel{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.skin-card{border:1px solid var(--border);border-radius:var(--r-md);padding:12px;cursor:pointer;transition:all .2s var(--ease);background:var(--surface)}
.skin-card:hover{transform:translateY(-2px);box-shadow:var(--shadow-2);border-color:var(--blue)}
.skin-card.on{border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-soft)}
.skin-sw{height:38px;border-radius:9px;margin-bottom:9px;display:flex;overflow:hidden;border:1px solid var(--border)}
.skin-sw i{flex:1}
.skin-name{font-weight:650;font-size:13px}
.skin-desc{font-size:11px;color:var(--muted);margin-top:2px}

/* ===================== 侧边栏折叠（桌面端） ===================== */
.sb-collapsed .sidebar{width:var(--sb-mini);flex-basis:var(--sb-mini)}
.sb-collapsed .sb-title,.sb-collapsed .sb-sub,.sb-collapsed .nav-txt,.sb-collapsed .nav-badge{display:none}

.sb-collapsed .sb-brand{flex-direction:column;justify-content:center;padding:12px 8px;gap:10px}
.sb-collapsed .sb-brand > div:not(.sb-logo){display:none}
.sb-collapsed .sb-logo{width:36px;height:36px;font-size:16px;margin:0;flex:0 0 auto}
.sb-collapsed #sb-collapse{width:100%;justify-content:center;padding:6px 4px;font-size:12.5px}
.sb-collapsed .nav-item{justify-content:center;padding:10px 0}
.sb-collapsed .nav-item.active::before{left:-6px;height:16px}
.sb-collapsed .sb-foot{flex-direction:column;gap:6px;padding:12px 6px}
.sb-collapsed .sb-foot > div{display:none}
.nav-item{transition:justify-content .2s,padding .2s}

/* ===================== 文字按钮（图标全面文字化） ===================== */
.tbtn{
  display:inline-flex;align-items:center;gap:6px;border:1px solid transparent;background:transparent;
  color:var(--text-2);font-size:13px;font-weight:600;padding:7px 12px;border-radius:999px;cursor:pointer;
  white-space:nowrap;transition:background .18s var(--ease),color .18s var(--ease),transform .16s var(--ease),box-shadow .18s var(--ease);
}
.tbtn:hover{background:var(--surface-3);color:var(--text)}
.tbtn:active{transform:scale(.96)}
.tbtn:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.tbtn.block{width:100%;justify-content:center}
.tbtn.on{background:var(--blue-soft);color:var(--blue)}
.tbadge{
  min-width:17px;height:17px;border-radius:9px;background:var(--red);color:#fff;
  font-size:10px;line-height:17px;font-weight:700;padding:0 5px;text-align:center;
}
.sw-row{display:flex;align-items:center;gap:8px}
.plugin-foot{display:flex;align-items:center;gap:8px;margin-top:12px}
.card-off{opacity:.66}
.card-off:hover{opacity:1}

/* ===================== 增强表格（筛选 / 排序 / 搜索 / 分页） ===================== */
.dt-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.dt-search{max-width:260px}
.dt-count{white-space:nowrap}
.dt-filters{
  display:block;
  background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-md);padding:12px;margin-bottom:12px;
  animation:fadeUp .22s var(--ease) both;
}
.dt-f .fl{margin-bottom:4px}
.dt-f .row{gap:6px}
.dt-th{cursor:pointer;user-select:none;white-space:nowrap;transition:background .15s}
.dt-th:hover{background:var(--surface-3)}
.dt-sort{font-size:10px;color:var(--blue);margin-left:3px}
.dt-page{display:flex;align-items:center;gap:8px;justify-content:center;margin-top:12px;flex-wrap:wrap}
.table-wrap{box-shadow:var(--shadow-1)}

/* ===================== 全局文案编辑：可见可感 ===================== */
body.edit-mode [data-cp-auto]{
  outline:1px dashed var(--blue);outline-offset:3px;border-radius:5px;cursor:text;
  transition:outline-color .18s,background .18s;
}
body.edit-mode [data-cp-auto]:hover{outline-color:var(--amber);background:rgba(240,165,0,.08)}
body.edit-mode [data-cp-auto]:focus{outline:2px solid var(--blue);background:var(--blue-soft)}
body.edit-mode .card{outline:1px dashed var(--border-2);outline-offset:-1px}

/* ===================== 体验优化：动效 / 反馈 / 质感 ===================== */
:root{--ease:cubic-bezier(.32,.72,0,1);--ease-soft:cubic-bezier(.4,0,.2,1)}
*{scrollbar-width:thin}
.btn{transition:transform .16s var(--ease),box-shadow .2s var(--ease),background .18s,opacity .18s}
.btn:active{transform:translateY(0) scale(.97)}
.btn:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.btn[disabled]{opacity:.45;pointer-events:none;filter:saturate(.6)}
.card{transition:box-shadow .28s var(--ease),transform .28s var(--ease),border-color .2s}
.card.hoverable:hover{box-shadow:var(--shadow-2);transform:translateY(-3px)}
.nav-item{transition:background .2s var(--ease),color .2s,transform .18s var(--ease)}
.nav-item:active{transform:scale(.98)}
.nav-item.active{box-shadow:0 1px 3px rgba(0,113,227,.18)}
.input,select.input,textarea.input{transition:border-color .2s,box-shadow .2s,background .2s}
.input:focus{box-shadow:0 0 0 4px var(--blue-soft)}
.switch{box-shadow:inset 0 1px 2px rgba(0,0,0,.10)}
.switch::after{box-shadow:0 1px 3px rgba(0,0,0,.28);transition:transform .26s var(--ease)}
table.tb tbody tr{cursor:pointer}
table.tb tbody tr:active{background:var(--surface-3)}
table.tb thead th{backdrop-filter:blur(6px)}
.toast{animation:toastIn .34s var(--ease) both;box-shadow:var(--shadow-2)}
.mask{animation:fade .18s var(--ease) both}
.modal{animation:pop .3s var(--ease) both}
.skeleton{animation:shimmer 1.3s infinite linear;background-size:400% 100%}
.content{scroll-behavior:smooth}
.kpi-val{transition:color .3s}
.pill-tabs .p{transition:all .2s var(--ease)}
.pill-tabs .p:active{transform:scale(.96)}
.chip{transition:background .2s,color .2s}
img{transition:opacity .35s var(--ease)}
img.fade-in-img{opacity:0}
img.fade-in-img.loaded{opacity:1}

/* 移动端：顶栏文字按钮收敛，避免拥挤 */
@media (max-width:860px){
  #btn-skin,#btn-theme{display:none}
  .dt-search{max-width:100%;flex:1 1 160px}
}
@media (max-width:560px){
  .tbtn{padding:6px 10px;font-size:12.5px}
  #btn-queue{display:none}
}

/* ===================== 筛选面板（按需添加条件，不铺开全部字段） ===================== */
.dt-fbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.dt-chips{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:10px;padding-top:10px;border-top:1px dashed var(--border)}
.dt-chip{
  display:inline-flex;align-items:center;gap:6px;background:var(--blue-soft);color:var(--blue);
  border:1px solid transparent;border-radius:999px;padding:5px 6px 5px 12px;font-size:12.5px;font-weight:600;
  max-width:100%;animation:pop .2s var(--ease) both;
}
.dt-chip-op{font-weight:500;opacity:.75}
.dt-chip button{
  width:18px;height:18px;border-radius:50%;border:0;background:rgba(0,0,0,.08);color:inherit;
  cursor:pointer;line-height:1;font-size:13px;display:grid;place-items:center;flex:0 0 auto;transition:background .16s;
}
.dt-chip button:hover{background:var(--blue);color:#fff}

/* ===================== 多行筛选编辑器 ===================== */
.dt-fl-bar{display:flex;align-items:center;gap:8px;margin-bottom:10px;padding-bottom:8px;border-bottom:1px dashed var(--border)}
.dt-fl-rows{display:flex;flex-direction:column;gap:6px}
.dt-fl-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap;animation:pop .2s var(--ease) both}
.dt-fl-col,.dt-fl-op,.dt-fl-v{flex:0 0 auto;padding:6px 10px;font-size:13px}
.dt-fl-col{min-width:160px;max-width:200px}
.dt-fl-op{min-width:90px;max-width:110px}
.dt-fl-vbox{flex:1;min-width:150px;display:flex}
.dt-fl-vbox .input{flex:1;min-width:0;width:100%}
.dt-fl-del{
  width:26px;height:26px;padding:0;border:1px solid var(--border);
  border-radius:8px;background:transparent;color:var(--muted);font-size:16px;
  cursor:pointer;display:grid;place-items:center;flex:0 0 auto;
  transition:background .16s,color .16s,border-color .16s;
}
.dt-fl-del:hover{background:#fee;color:#c33;border-color:#fbb}
.dt-fl-row:focus-within .dt-fl-del{opacity:1}
@media (max-width:720px){
  .dt-fl-row{flex-direction:column;align-items:stretch}
  .dt-fl-col,.dt-fl-op,.dt-fl-vbox,.dt-fl-vbox .input{width:100%;max-width:none;min-width:0}
  .dt-fl-del{align-self:flex-end;width:32px;height:32px}
}

/* ===================== 数据表格：增强横向滚动条 + 拖动提示 ===================== */
.table-wrap{
  position:relative;
  /* 自定义滚动条（WebKit/Blink + Firefox） */
  scrollbar-width:thin;
  scrollbar-color:var(--blue-soft) transparent;
}
.table-wrap::-webkit-scrollbar{height:14px;width:14px}
.table-wrap::-webkit-scrollbar-track{background:var(--surface-2);border-radius:7px;margin:2px}
.table-wrap::-webkit-scrollbar-thumb{
  background:var(--blue);border-radius:7px;border:3px solid var(--surface-2);
  min-width:60px;cursor:grab;transition:background .2s var(--ease);
}
.table-wrap::-webkit-scrollbar-thumb:hover{background:var(--blue-600,color-mix(in srgb,var(--blue) 88%,#000))}
.table-wrap::-webkit-scrollbar-thumb:active{cursor:grabbing;background:var(--blue-600,color-mix(in srgb,var(--blue) 88%,#000))}

/* 表格右上角的「↔ 共 N 列可拖动」浮动徽章 */
.dt-scroll-hint{
  position:absolute;top:8px;right:14px;z-index:5;
  display:flex;align-items:center;gap:5px;
  padding:5px 12px;border-radius:999px;
  background:var(--blue);color:#fff;
  font-size:11.5px;font-weight:600;letter-spacing:.2px;
  box-shadow:0 4px 14px rgba(0,113,227,.35);
  pointer-events:none;opacity:0;transform:translateY(-6px) scale(.94);
  transition:opacity .3s var(--ease),transform .3s var(--ease);
}
.dt-scroll-hint svg{width:13px;height:13px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
.table-wrap.is-scrollable-x .dt-scroll-hint{opacity:.95;transform:translateY(0) scale(1)}

/* 触摸设备：滚动条更显眼（很多人不知道 touchpad 可以横滑） */
@media (hover:none){
  .table-wrap::-webkit-scrollbar{height:18px}
  .table-wrap::-webkit-scrollbar-thumb{border:2px solid var(--surface-2)}
}

/* ===================== 冻结左侧列（横向拖动时学号/姓名固定可见） ===================== */
table.tb th.fz, table.tb td.fz{
  position:sticky;z-index:2;
  background:var(--surface);
  box-shadow:inset -2px 0 0 var(--border);
}
.table-wrap thead th.fz{z-index:4}
table.tb tbody tr:hover td.fz{background:var(--surface-2)}
table.tb tbody tr:active td.fz{background:var(--surface-3)}
/* 冻结列右缘渐隐阴影（提示左侧固定） */
.table-wrap.is-scrollable-x th.fz:last-of-type::after,
.table-wrap.is-scrollable-x td.fz:last-of-type::after{
  content:'';position:absolute;top:0;right:-8px;bottom:-1px;width:8px;
  background:linear-gradient(90deg,rgba(0,0,0,.06),transparent);
  pointer-events:none;
}

/* 表头拖拽换列序视觉反馈 */
.dt-th{transition:background .15s}
.dt-th.drag-over{box-shadow:inset 3px 0 0 var(--blue);background:var(--blue-soft)}
.dt-th[draggable="true"]{cursor:grab}
.dt-th[draggable="true"]:active{cursor:grabbing}

/* v1.9.0 表头右边界拖拽把手：常态隐形，悬停/拖拽时显形 */
.dt-th{position:relative}
.dt-rsz{
  position:absolute;top:0;right:-3px;width:8px;height:100%;
  cursor:col-resize;z-index:3;touch-action:none;
}
.dt-rsz::before{
  content:'';position:absolute;top:20%;right:3px;width:2px;height:60%;
  border-radius:2px;background:var(--blue);opacity:0;
  transition:opacity .15s var(--ease);
}
.dt-th:hover .dt-rsz::before,.dt-rsz:hover::before{opacity:.45}
.dt-rsz:hover::before{opacity:1}
.dt-th.resizing .dt-rsz::before{opacity:1}
.dt-th.resizing{background:var(--blue-soft)}

/* ===================== 全站右键菜单（Apple 风格） ===================== */
.ctx-menu{
  position:fixed;z-index:9999;min-width:220px;max-width:320px;
  background:var(--surface);border:1px solid var(--border);border-radius:12px;
  box-shadow:0 12px 40px rgba(0,0,0,.18),0 2px 8px rgba(0,0,0,.08);
  padding:5px;animation:ctxIn .14s var(--ease) both;
}
@keyframes ctxIn{from{opacity:0;transform:scale(.97) translateY(-3px)}to{opacity:1;transform:none}}
.ctx-item{
  display:block;width:100%;text-align:left;padding:8px 12px;
  border:0;border-radius:8px;background:transparent;color:var(--text);
  font-size:13px;font-weight:550;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:background .12s var(--ease);
}
.ctx-item:hover{background:var(--blue);color:#fff}
.ctx-item:active{transform:scale(.99)}
.ctx-item[disabled]{color:var(--muted);cursor:default;pointer-events:none}
.ctx-item.danger{color:var(--red,#e5484d)}
.ctx-item.danger:hover{background:var(--red,#e5484d);color:#fff}
.ctx-item.dim{color:var(--muted);font-weight:500}
.ctx-item.dim:hover{background:var(--surface-3);color:var(--text-2)}
.ctx-sep{height:1px;margin:4px 8px;background:var(--border)}
[data-theme="dark"] .ctx-menu{box-shadow:0 12px 40px rgba(0,0,0,.6),0 2px 8px rgba(0,0,0,.4)}

/* ===================== 表格多选 / 批量编辑 ===================== */
.dt-selbadge{
  display:inline-flex;align-items:center;padding:5px 12px;border-radius:999px;
  background:var(--surface-3);color:var(--muted);font-size:12.5px;font-weight:650;
  transition:background .2s var(--ease),color .2s var(--ease);
}
.dt-selbadge.on{background:var(--blue-soft);color:var(--blue)}
.ck-th,.ck-cell{width:36px;min-width:36px;padding:8px 4px 8px 10px;text-align:center}
.ck-th{position:sticky;left:0;z-index:4;background:var(--surface)}
.ck-cell{position:sticky;left:0;z-index:2;background:var(--surface);box-shadow:inset -2px 0 0 var(--border)}
.ck-cell input,.ck-th input{width:15px;height:15px;cursor:pointer;accent-color:var(--blue)}
tr.row-selected td{background:var(--blue-soft)}
tr.row-selected td.ck-cell{background:var(--blue-soft)}
tr.row-selected:hover td{background:color-mix(in srgb,var(--blue-soft) 80%,var(--surface-2))}

/* ===================== 行尾「编辑」按钮列（最右侧固定） ===================== */
.op-th,.op-cell{
  position:sticky;right:0;text-align:center;
  background:var(--surface);
  box-shadow:inset 2px 0 0 var(--border);
}
thead th.op-th{z-index:5;font-weight:600;color:var(--muted)}
tbody td.op-cell{z-index:2;min-width:74px}
tbody tr:hover td.op-cell{background:var(--surface-2)}
tbody tr:active td.op-cell{background:var(--surface-3)}
tbody tr.row-selected td.op-cell{background:var(--blue-soft)}
.op-cell .dt-edit{padding:4px 14px;font-weight:600}

/* ===================== 数据支撑中心 ===================== */
.dh-row{border:1.5px solid var(--border);border-radius:12px;padding:11px 12px;margin-bottom:9px;cursor:pointer;transition:all .15s var(--ease);background:var(--surface)}
.dh-row:hover{transform:translateY(-1px);box-shadow:0 6px 16px rgba(0,0,0,.08)}
.dh-row.act{border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-soft)}
.dh-row .switch{transform:scale(.85)}
.dh-chip{display:inline-block;font-size:10.5px;background:var(--surface-2);border-radius:6px;padding:2px 7px;margin:2px 3px 0 0;color:var(--muted);font-weight:600}
.st-dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:5px;flex:0 0 auto}
.dh-err{margin-top:8px;border-radius:10px;background:#fdecec;border:1px solid #f5c2c2;padding:10px 12px;font-size:12px;color:#a33;display:flex;flex-direction:column;gap:6px}
.dh-err span{line-height:1.6}
.dh-err button{align-self:flex-start;padding:4px 14px;border-radius:999px;border:0;background:#e5484d;color:#fff;font-size:11.5px;font-weight:700;cursor:pointer}
.dh-off-hint{font-size:11px;color:var(--muted);background:var(--surface-2);border-radius:8px;padding:6px 9px;margin-top:8px}
.dh-nodata{margin-top:10px;display:flex;flex-direction:column;gap:6px;align-items:flex-start;
  border:1px dashed var(--g-line);border-radius:12px;padding:12px 13px;background:var(--surface-2)}
.dh-nodata b{font-size:12.5px;color:var(--warn,#e0342b)}
.dh-nodata span{font-size:11.5px;color:var(--muted);line-height:1.7}
.dh-nodata button{margin-top:2px;padding:5px 14px;border-radius:999px;border:0;background:var(--blue,#0071e3);color:#fff;font-size:11.5px;font-weight:700;cursor:pointer}


/* ===================== 可视化搭建（DIY）模块样式 ===================== */
.num{font-variant-numeric:tabular-nums;font-feature-settings:'tnum'}
.b-card{background:var(--d-card);border:1px solid var(--d-border);border-radius:12px;padding:14px 16px;position:relative;overflow:hidden;animation:cardIn .5s cubic-bezier(.2,.8,.2,1) both}
@keyframes cardIn{from{opacity:0;transform:translateY(14px) scale(.98)}to{opacity:1;transform:none}}
.spark{display:flex;align-items:flex-end;gap:4px;height:44px;margin-top:10px}
.spark i{flex:1;background:linear-gradient(180deg,var(--d-accent),rgba(88,166,255,.15));border-radius:3px 3px 0 0;min-height:6px;animation:grow .8s cubic-bezier(.2,.8,.2,1) both}
.l-card{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:16px;animation:cardIn .5s cubic-bezier(.2,.8,.2,1) both}
.l-card .lt{font-size:12px;font-weight:650;color:var(--muted);letter-spacing:.3px}
.l-hero .lt{color:rgba(255,255,255,.75)}
.wcard{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:16px;animation:cardIn .5s cubic-bezier(.2,.8,.2,1) both}
.notice-scroll .nitem{padding:7px 10px;border-radius:9px;font-size:12.5px;margin-bottom:6px;line-height:1.5}
.duty{display:grid;grid-template-columns:repeat(5,1fr);gap:6px}
.duty .d{text-align:center;padding:8px 2px;border-radius:10px;background:var(--surface-3);font-size:11.5px}
.duty .d b{display:block;font-size:12.5px;margin-top:3px}
.duty .d.today{background:#e8f1fd;border:1px solid var(--blue)}
.au-card{background:rgba(255,255,255,.05);backdrop-filter:blur(18px);border:1px solid rgba(255,255,255,.12);border-radius:16px;padding:18px;animation:cardIn .6s cubic-bezier(.2,.8,.2,1) both}
.pal-item{display:flex;align-items:center;gap:9px;padding:9px 11px;border-radius:10px;border:1px solid var(--border);background:var(--surface-3);font-size:12.5px;font-weight:650;margin-bottom:7px;cursor:grab;transition:all .15s;user-select:none}
.pal-item:hover{transform:translateY(-1px);border-color:var(--blue);color:var(--blue);box-shadow:0 4px 12px rgba(0,113,227,.14)}
.pal-item:active{cursor:grabbing}
.pal-item .pi{font-size:15px}
.pal-item .sz{margin-left:auto;font-size:10px;color:var(--muted);font-weight:700}
.diy-canvas{min-height:600px;display:grid;grid-template-columns:repeat(6,1fr);gap:14px;border:2px dashed transparent;border-radius:16px;padding:14px;background:var(--surface-3);transition:all .2s;align-content:start}
.diy-canvas.over{border-color:var(--blue);background:#e8f1fd}
.dmod{position:relative}
.dmod .dm-del{position:absolute;top:-8px;right:-8px;width:20px;height:20px;border-radius:50%;background:#e5484d;color:#fff;border:0;font-size:11px;cursor:pointer;z-index:7;opacity:0;transition:opacity .15s;line-height:1}
.dmod .dm-del{right:-8px;background:#e5484d}
.dmod:hover .dm-del{opacity:1}
.dmod.dragging{opacity:.4}
.dmod .l-card{height:100%}
.gm-kpi .v{font-size:30px;font-weight:800;margin-top:6px}
.gm-kpi .v em{font-style:normal;font-size:13px;color:var(--muted)}
.gm-bar-row{display:flex;align-items:center;gap:9px;margin-top:9px;font-size:12px}
.gm-bar-row .nm{width:52px;color:var(--muted)}
.gm-bar-row .bar{flex:1;height:7px;border-radius:4px;background:var(--surface-3)}
.gm-bar-row .bar i{display:block;height:100%;border-radius:4px;background:linear-gradient(90deg,var(--blue),#4da3ff)}
.gm-bar-row .pv{width:38px;text-align:right;font-weight:700}
.gm-count .c{display:flex;gap:8px;margin-top:10px}
.gm-count .cp{flex:1;text-align:center;padding:9px 2px;border-radius:10px;background:var(--surface-3)}
.gm-count .cp .n{font-size:21px;font-weight:800;color:var(--blue)}
.gm-count .cp .t{font-size:10.5px;color:var(--muted)}
.gm-birth{display:flex;gap:10px;margin-top:10px}
.gm-birth .av{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;color:#fff;font-weight:800;font-size:13px}
.gm-weather{display:flex;align-items:center;gap:12px;margin-top:8px}
.gm-weather .ic{font-size:32px}
.gm-weather .t{font-size:26px;font-weight:800}
.gm-todo .ti{display:flex;gap:8px;align-items:center;padding:6px 0;border-bottom:1px dashed var(--border);font-size:12.5px}
.gm-todo .ck{width:15px;height:15px;border-radius:4px;border:1.5px solid #c7c7cc;flex:0 0 auto}
.gm-feed .fi{display:flex;gap:7px;font-size:12px;padding:5px 0;border-bottom:1px dashed var(--border);color:var(--muted)}
.gm-feed .fi b{color:var(--text)}
.gm-heat{display:grid;grid-template-columns:repeat(18,1fr);gap:3px;margin-top:10px}
.gm-heat i{aspect-ratio:1;border-radius:2px;background:var(--surface-3)}
.gm-heat i.l1{background:#c8e6c9}.gm-heat i.l2{background:#81c784}.gm-heat i.l3{background:#4caf50}
.gm-note .txt{font-size:12.5px;line-height:1.8;color:var(--muted);margin-top:8px;white-space:pre-wrap}
.gm-gauge{display:flex;align-items:center;gap:14px;margin-top:9px}
.gm-donut{width:88px;height:88px;border-radius:50%;display:grid;place-items:center;flex:0 0 auto}
.gm-donut i{width:58px;height:58px;border-radius:50%;background:#fff;display:grid;place-items:center;font-style:normal;font-weight:800;font-size:16px}
.gm-leg2{font-size:12px;color:var(--muted);line-height:2}
.gm-leg2 b{color:var(--text);font-size:13.5px}
.gm-pie{display:flex;align-items:center;gap:14px;margin-top:9px}
.gm-pie .pd{width:84px;height:84px;border-radius:50%;flex:0 0 auto}
.gm-leg3{font-size:11.5px;color:var(--muted);line-height:2}
.gm-leg3 i{width:8px;height:8px;border-radius:2px;display:inline-block;margin-right:5px}
.gm-cal{display:grid;grid-template-columns:repeat(7,1fr);gap:3px;margin-top:9px}
.gm-cal i{aspect-ratio:1;border-radius:4px;background:var(--surface-3);display:grid;place-items:center;font-size:9px;font-style:normal;color:var(--muted)}
.gm-cal i.ev{background:#e8f1fd;color:var(--blue);font-weight:800}
.gm-tl .ti2{display:flex;gap:8px;font-size:12px;padding:6px 0;border-bottom:1px dashed var(--border);align-items:flex-start}
.gm-tl .ti2:last-child{border:0}
.gm-tl .dot2{width:8px;height:8px;border-radius:50%;margin-top:4px;flex:0 0 auto}
.gm-tl .tm3{margin-left:auto;color:var(--muted);font-size:10.5px}
.gm-links{display:flex;flex-wrap:wrap;gap:7px;margin-top:9px}
.gm-links a{font-size:12px;font-weight:650;padding:6px 13px;border-radius:999px;background:var(--surface-3);border:1px solid var(--border);color:var(--text);text-decoration:none;transition:all .15s}
.gm-links a:hover{color:var(--blue);border-color:var(--blue);transform:translateY(-1px)}
.gm-stats{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}
.gm-stats .st3{background:var(--surface-3);border-radius:10px;padding:9px 6px;text-align:center}
.gm-stats .st3 b{display:block;font-size:19px;font-weight:800}
.gm-stats .st3 span{font-size:10.5px;color:var(--muted)}
.gm-prog .pr{margin-top:10px;font-size:12px}
.gm-prog .pr .lb{display:flex;justify-content:space-between}
.gm-prog .pr .lb b{font-weight:700}
.gm-prog .pr .bar{height:7px;border-radius:4px;background:var(--surface-3);margin-top:4px;overflow:hidden}
.gm-prog .pr .bar i{display:block;height:100%;border-radius:4px;background:linear-gradient(90deg,var(--green),#6fd39b);animation:growX 1s cubic-bezier(.2,.8,.2,1) both;transform-origin:left}
.gm-table{width:100%;border-collapse:collapse;font-size:11.5px;margin-top:9px}
.gm-table td,.gm-table th{padding:5px 6px;text-align:left;border-bottom:1px solid var(--border);white-space:nowrap}
.gm-table th{color:var(--muted);font-weight:650;font-size:10.5px}
.gm-photos{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:9px}
.gm-photos i{aspect-ratio:1;border-radius:8px;display:grid;place-items:center;font-style:normal;font-size:17px}
.gm-quote{margin-top:9px;font-size:13.5px;line-height:1.8;font-weight:650;border-left:3.5px solid var(--blue);padding-left:11px}
.gm-quote .by{display:block;font-size:11px;color:var(--muted);font-weight:500;margin-top:6px}
.gm-clock{text-align:center;margin-top:10px}
.gm-clock .t3{font-size:32px;font-weight:800;letter-spacing:1px;font-variant-numeric:tabular-nums}
.gm-clock .dt{font-size:11.5px;color:var(--muted);margin-top:3px}
.gm-leave .lv{display:flex;justify-content:space-between;font-size:12.5px;padding:7px 0;border-bottom:1px dashed var(--border)}
.gm-leave .lv:last-child{border:0}
.gm-leave .lv b{font-weight:700}
.drag-ghost{position:fixed;z-index:999;pointer-events:none;background:var(--blue);color:#fff;font-size:12.5px;font-weight:700;padding:8px 16px;border-radius:999px;box-shadow:0 12px 32px rgba(0,113,227,.4);transform:translate(0,0);white-space:nowrap}
.vd-selected .dm-del,.vd-selected .vdel-btn{opacity:1}
.vd-selected .rz-se,.dmod:hover>.rz-se,body.edit-mode .b-card:hover>.rz-se,body.edit-mode .l-card:hover>.rz-se,body.edit-mode .wcard:hover>.rz-se,body.edit-mode .bk:hover>.rz-se,body.edit-mode .au-card:hover>.rz-se{display:block}
.rz-se:hover{transform:scale(1.25);opacity:1}
.resizing{cursor:nwse-resize!important}
.resizing *{pointer-events:none!important}
.rz-se{width:26px;height:26px}
.add-mod-tile{display:grid;place-items:center;border:2px dashed #9ec6f0;border-radius:14px;color:var(--blue);font-weight:700;font-size:13px;cursor:pointer;min-height:90px;transition:all .15s;background:rgba(0,113,227,.04)}
.add-mod-tile:hover{background:#e8f1fd;transform:translateY(-2px)}
/* DIY 页面骨架 */
.diy-cols{display:grid;grid-template-columns:250px 1fr;gap:14px;align-items:start}
.pal{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:12px;position:sticky;top:16px;max-height:calc(100vh - 120px);overflow:auto}
#pal-search{border:1.5px solid var(--border);border-radius:9px;padding:7px 10px;font-size:12.5px;outline:none;background:var(--surface-2);color:var(--text)}
#pal-search:focus{border-color:var(--blue)}
.dh-loading{padding:28px 0;text-align:center;color:var(--muted);font-size:12px}
.dh-badge{font-size:10.5px;color:var(--muted);margin-top:6px}
.dmod{touch-action:none}
.pal-item{touch-action:none}
@media (max-width:900px){.diy-cols{grid-template-columns:1fr}.pal{position:static;max-height:none}}

/* ===================== Glassmorphism 2.0 全局升级 ===================== */
body::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(720px 480px at 8% -6%, rgba(0,113,227,.13), transparent 62%),
    radial-gradient(820px 560px at 96% 4%, rgba(123,92,255,.11), transparent 64%),
    radial-gradient(680px 520px at 55% 108%, rgba(35,133,76,.10), transparent 60%);
}
[data-theme="dark"] body::before{
  background:
    radial-gradient(760px 500px at 6% -8%, rgba(10,132,255,.16), transparent 62%),
    radial-gradient(860px 580px at 98% 2%, rgba(123,92,255,.14), transparent 64%),
    radial-gradient(700px 540px at 52% 110%, rgba(48,209,88,.08), transparent 60%);
}
.sidebar{background:rgba(255,255,255,.58);backdrop-filter:blur(28px) saturate(180%);-webkit-backdrop-filter:blur(28px) saturate(180%)}
[data-theme="dark"] .sidebar{background:rgba(20,20,26,.62)}
.topbar{background:rgba(255,255,255,.62);backdrop-filter:blur(30px) saturate(190%);-webkit-backdrop-filter:blur(30px) saturate(190%)}
[data-theme="dark"] .topbar{background:rgba(18,18,24,.62)}
.card{
  /* v1.9.62：.66 → .86，与 .dm / --g-1 统一。
     原因：body 最上压了一层 rgba(255,255,255,.84) 白蒙版把背景照片压成淡底纹（~246 亮度），
     .card 只有 .66 不透明度时，叠上去的最终亮度 ≈ 252 —— 与底只差 5~6 级，肉眼等同「没有背景色」。
     提到 .86 后卡片≈254，与底拉开约 8 级，卡片的面才立得住。
     ⚠️ 别为了「更透」把这个值调回去：.dm（驾驶舱模块）一直用 .86，两者不一致本身就是这次的 bug。 */
  background:var(--g-1);
  backdrop-filter:blur(22px) saturate(170%);-webkit-backdrop-filter:blur(22px) saturate(170%);
  border:1px solid var(--g-line);
  box-shadow:var(--g-shadow), inset 0 1px 0 var(--g-hi);
}
[data-theme="dark"] .card{
  background:color-mix(in srgb, #1c1c24 86%, transparent);border-color:rgba(255,255,255,.09);
  box-shadow:var(--g-shadow), inset 0 1px 0 var(--g-hi);
}
.card.hoverable:hover{box-shadow:var(--g-shadow-2), inset 0 1px 0 var(--g-hi)}
.modal{background:rgba(255,255,255,.78);backdrop-filter:blur(34px) saturate(190%);-webkit-backdrop-filter:blur(34px) saturate(190%);border:1px solid rgba(255,255,255,.6)}
[data-theme="dark"] .modal{background:rgba(26,26,34,.80);border-color:rgba(255,255,255,.10)}
.ctx-menu{background:rgba(255,255,255,.80)!important;backdrop-filter:blur(30px) saturate(190%);-webkit-backdrop-filter:blur(30px) saturate(190%);border:1px solid rgba(255,255,255,.6)!important}
[data-theme="dark"] .ctx-menu{background:rgba(28,28,36,.84)!important;border-color:rgba(255,255,255,.10)!important}
.input,select.input,textarea.input{background:rgba(255,255,255,.60);backdrop-filter:blur(8px)}
[data-theme="dark"] .input,[data-theme="dark"] select.input,[data-theme="dark"] textarea.input{background:rgba(255,255,255,.06)}
.btn.ghost{background:rgba(255,255,255,.86);backdrop-filter:blur(10px)}
[data-theme="dark"] .btn.ghost{background:rgba(255,255,255,.11)}
/* v1.9.28：数据表/表格模块改为接近实色的面板，避免背景照片从行间透出（同一张表出现白/蓝不均的行） */
.dt,.tb-wrap,.l-card{background:color-mix(in srgb, var(--surface) 94%, transparent)}
.pal,.diy-canvas{backdrop-filter:blur(18px) saturate(160%)}
.pal{background:rgba(255,255,255,.62)}
[data-theme="dark"] .pal{background:rgba(28,28,36,.62)}

/* ===== 数据大屏模式（首页可切换） ===== */
body.screen-mode{--bg:#070b16}
body.screen-mode::before{
  background:
    radial-gradient(900px 620px at 4% -10%, rgba(10,132,255,.22), transparent 60%),
    radial-gradient(980px 660px at 100% 0%, rgba(123,92,255,.18), transparent 62%),
    radial-gradient(820px 600px at 50% 115%, rgba(48,209,88,.12), transparent 60%),
    linear-gradient(180deg,#070b16,#0a1020);
}
body.screen-mode .sidebar{display:none}
body.screen-mode .main{width:100%}
body.screen-mode .topbar{background:rgba(10,14,26,.55);border-bottom-color:rgba(120,160,255,.12)}
body.screen-mode .content{padding:16px 20px 40px}
body.screen-mode .wrap{max-width:none}
body.screen-mode .card{
  background:rgba(13,20,40,.55);border:1px solid rgba(120,160,255,.16);
  box-shadow:0 10px 34px rgba(0,0,0,.35), inset 0 1px 0 rgba(160,190,255,.10);
  backdrop-filter:blur(18px) saturate(150%);border-radius:16px;padding:15px;
}
body.screen-mode .kpi-val{font-size:38px;color:#eaf1ff}
body.screen-mode .kpi-label,body.screen-mode .small,body.screen-mode .sec-hd h2{color:#9fb4d8}
body.screen-mode .sec-hd h2{color:#eaf1ff}
body.screen-mode .grid-blocks{gap:12px}
body.screen-mode table.tb td{color:#cfe0ff}
#sx-exit{position:fixed;right:22px;bottom:22px;z-index:200;display:none}
body.screen-mode #sx-exit{display:inline-flex}

/* ===== 表格密度模式 ===== */
.seg{display:inline-flex;border:1px solid var(--border-2);border-radius:999px;padding:2px;background:rgba(255,255,255,.5);backdrop-filter:blur(8px)}
[data-theme="dark"] .seg{background:rgba(255,255,255,.06)}
.seg button{border:0;background:transparent;border-radius:999px;padding:4px 12px;font-size:12px;font-weight:600;color:var(--muted);cursor:pointer;transition:all .15s var(--ease)}
.seg button.on{background:var(--blue);color:#fff;box-shadow:0 2px 8px var(--blue-soft)}
.dt.d-compact table.tb td{padding:5px 10px;font-size:12.3px}
.dt.d-compact table.tb th{padding:7px 10px;font-size:11.5px}
.dt.d-dense table.tb td{padding:2px 8px;font-size:11.8px;line-height:1.35}
.dt.d-dense table.tb th{padding:4px 8px;font-size:11px}
.dmod .gm-table.d2 tbody td{padding:4px 8px;font-size:11.5px}
.dmod .gm-table.d3 tbody td{padding:1px 6px;font-size:11px;line-height:1.3}

/* ===== 全页面 DIY：FAB + 模块抽屉 ===== */
#diy-fab{
  position:fixed;right:22px;bottom:22px;z-index:180;height:46px;padding:0 20px;border-radius:999px;border:1px solid rgba(255,255,255,.55);
  background:linear-gradient(135deg,rgba(0,113,227,.92),rgba(0,98,196,.92));color:#fff;font-weight:700;font-size:13.5px;cursor:pointer;
  box-shadow:0 12px 34px rgba(0,113,227,.4);backdrop-filter:blur(12px);display:inline-flex;align-items:center;gap:8px;transition:transform .18s var(--ease),box-shadow .18s;
}
#diy-fab:hover{transform:translateY(-2px);box-shadow:0 16px 40px rgba(0,113,227,.5)}
body.screen-mode #diy-fab{bottom:78px}
#diy-drawer{
  position:fixed;top:0;right:-340px;width:320px;height:100vh;z-index:190;
  background:rgba(255,255,255,.78);backdrop-filter:blur(34px) saturate(190%);-webkit-backdrop-filter:blur(34px) saturate(190%);
  border-left:1px solid rgba(255,255,255,.6);box-shadow:-18px 0 50px rgba(0,0,0,.14);
  transition:right .32s var(--ease);display:flex;flex-direction:column;padding:16px 14px;
}
[data-theme="dark"] #diy-drawer{background:rgba(24,24,32,.82);border-left-color:rgba(255,255,255,.10)}
#diy-drawer.open{right:0}
#diy-drawer .dh-off-hint{margin:8px 0 10px}
#diy-extra{margin-top:18px}
#diy-extra .diy-extra-hd{display:flex;align-items:center;gap:8px;margin-bottom:10px}
#diy-extra .diy-extra-hd .lt{flex:1}

/* ===== 新模块：日历视图 / 时间轴 / 组件小屋 ===== */
.dh-cal{margin-top:8px}
.dh-cal-hd{display:grid;grid-template-columns:repeat(7,1fr);gap:3px;margin-bottom:4px}
.dh-cal-hd i{font-style:normal;text-align:center;font-size:10.5px;color:var(--muted);font-weight:650}
.dh-cal-g{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}
.dh-cal-g i{font-style:normal;text-align:center;font-size:11.5px;padding:5px 0;border-radius:7px;color:var(--text-2);font-variant-numeric:tabular-nums}
.dh-cal-g i.ev{background:var(--blue-soft);color:var(--blue);font-weight:700}
.dh-cal-g i.today{background:var(--green);color:#fff;font-weight:700}
.dh-cal-lg{display:flex;gap:14px;margin-top:8px;font-size:10.5px;color:var(--muted)}
.dh-cal-lg i{display:inline-block;width:9px;height:9px;border-radius:3px;margin-right:4px;vertical-align:-1px}
.dh-tl{margin-top:8px;position:relative;padding-left:14px}
.dh-tl::before{content:"";position:absolute;left:4px;top:6px;bottom:6px;width:2px;background:var(--border-2);border-radius:2px}
.dh-tl-row{position:relative;display:flex;gap:9px;padding:5px 0}
.dh-tl-dot{position:absolute;left:-14px;top:10px;width:9px;height:9px;border-radius:50%;border:2px solid var(--surface);box-shadow:0 0 0 1.5px var(--border-2)}
.dh-tl-row>div:last-child{margin-left:8px}
.dh-hut{display:grid;grid-template-columns:repeat(4,1fr);gap:9px;margin-top:9px}
.dh-hut-cell{background:var(--surface-2);border:1px solid var(--border);border-radius:12px;padding:10px 8px;text-align:center}
.dh-hut-tip{margin-top:8px;font-size:11px;color:var(--muted);background:var(--surface-2);border-radius:8px;padding:6px 9px}
body.screen-mode .dh-hut-cell{background:rgba(255,255,255,.05);border-color:rgba(120,160,255,.14)}
body.screen-mode .dh-hut-tip{background:rgba(255,255,255,.05)}

/* 拖动提示条 + 落位闪烁 */
#drag-hint{
  position:fixed;top:14px;left:50%;transform:translate(-50%,-70px);z-index:300;
  background:rgba(0,113,227,.92);backdrop-filter:blur(14px);color:#fff;font-size:13px;font-weight:650;
  padding:9px 20px;border-radius:999px;box-shadow:0 10px 30px rgba(0,113,227,.4);
  transition:transform .28s var(--ease);pointer-events:none;white-space:nowrap;max-width:92vw;overflow:hidden;text-overflow:ellipsis;
}
#drag-hint.on{transform:translate(-50%,0)}
@keyframes dropFlash{0%{outline:3px solid var(--blue);outline-offset:3px;box-shadow:0 0 0 6px var(--blue-soft)}100%{outline:3px solid transparent;outline-offset:3px}}
.dmod.flash{animation:dropFlash 1.3s var(--ease)}

/* ===================== Glassmorphism 2.0 — 完整覆盖层 ===================== */
/* 玻璃令牌：颜色随主题/皮肤自动适配（依赖 color-mix，Chrome 111+） */
:root{
  --d-card:color-mix(in srgb, var(--surface) 92%, transparent);
  --d-border:color-mix(in srgb, var(--border-2) 90%, transparent);
  --d-accent:var(--blue);
  /* v1.9.28：62/66/72 → 86/90/93。原值过低时背景照片会透过卡片/工具栏，
     把整体染蓝并吃掉对比度（按钮文字、表格内容都看不清） */
  --g-1:color-mix(in srgb, var(--surface) 86%, transparent);     /* 卡片 / 模层 */
  --g-2:color-mix(in srgb, var(--surface-2) 90%, transparent);  /* 次级面：表头/筛选条 */
  --g-3:color-mix(in srgb, var(--surface-3) 93%, transparent);  /* 三级面：芯片/进度槽 */
  --g-line:color-mix(in srgb, var(--border) 60%, transparent);
  --g-hi:rgba(255,255,255,.55);                                 /* 内高光（亮） */
  --g-shadow:0 1px 2px rgba(0,0,0,.04), 0 4px 14px rgba(0,0,0,.05);
  --g-shadow-2:0 6px 18px rgba(0,0,0,.08), 0 22px 48px rgba(0,0,0,.10);
  --blur:22px; --sat:170%;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-7:32px; --sp-8:48px;
}
[data-theme="dark"]{
  --g-hi:rgba(255,255,255,.06);
  --g-shadow:0 1px 2px rgba(0,0,0,.4), 0 6px 18px rgba(0,0,0,.35);
  --g-shadow-2:0 10px 30px rgba(0,0,0,.5), 0 24px 60px rgba(0,0,0,.45);
}

/* 通用「玻璃面」复用类 */
.glass{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(var(--blur)) saturate(var(--sat));
  backdrop-filter:blur(var(--blur)) saturate(var(--sat));
  border:1px solid var(--g-line);
  box-shadow:var(--g-shadow), inset 0 1px 0 var(--g-hi);
}
.glass-2{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(18px) saturate(160%);
  backdrop-filter:blur(18px) saturate(160%);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}

/* 按钮全态玻璃化 */
.btn{
  background:linear-gradient(180deg, color-mix(in srgb, var(--blue) 96%, transparent), color-mix(in srgb, var(--blue) 88%, transparent));
  -webkit-backdrop-filter:blur(10px) saturate(180%);
  backdrop-filter:blur(10px) saturate(180%);
  box-shadow:0 1px 2px color-mix(in srgb, var(--blue) 35%, transparent), inset 0 1px 0 rgba(255,255,255,.32);
  border:1px solid color-mix(in srgb, var(--blue) 70%, transparent);
}
.btn:hover{box-shadow:0 6px 18px color-mix(in srgb, var(--blue) 36%, transparent), inset 0 1px 0 rgba(255,255,255,.36)}
.btn.ghost{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(14px) saturate(170%);
  backdrop-filter:blur(14px) saturate(170%);
  color:var(--text);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.btn.ghost:hover{background:var(--g-3);box-shadow:var(--g-shadow), inset 0 1px 0 var(--g-hi)}
.btn.soft{
  background:color-mix(in srgb, var(--blue-soft) 80%, transparent);
  color:var(--blue);
  border:1px solid color-mix(in srgb, var(--blue-soft) 90%, transparent);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.btn.danger{
  background:color-mix(in srgb, var(--red-soft) 90%, transparent);
  color:var(--red);
  border:1px solid color-mix(in srgb, var(--red) 18%, transparent);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.btn.danger:hover{background:color-mix(in srgb, var(--red) 12%, transparent)}

/* 图标按钮 */
.icon-btn{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(14px) saturate(170%);
  backdrop-filter:blur(14px) saturate(170%);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.icon-btn:hover{background:var(--g-3)}

/* 文字按钮：玻璃浮起 */
.tbtn{
  background:transparent;
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);
}
.tbtn:hover{
  background:color-mix(in srgb, var(--surface-3) 78%, transparent);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
  padding:7px 11px;  /* 抵消边框占位 */
}
.tbtn.on{
  background:color-mix(in srgb, var(--blue-soft) 85%, transparent);
  color:var(--blue);
  border:1px solid color-mix(in srgb, var(--blue-soft) 90%, transparent);
  padding:7px 11px;
}

/* 输入/选择/文本域：玻璃感输入 */
.input,select.input,textarea.input{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);
  border:1px solid var(--border-2);
  box-shadow:inset 0 1px 0 var(--g-hi);
  transition:border-color .2s, box-shadow .2s, background .2s;
}
.input:focus{
  border-color:var(--blue);
  background:var(--g-1);
  box-shadow:0 0 0 4px var(--blue-soft), inset 0 1px 0 var(--g-hi);
}
.input::placeholder{color:var(--muted)}

/* 胶囊标签 */
.chip{
  background:color-mix(in srgb, var(--surface-3) 88%, transparent);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.chip.blue{background:color-mix(in srgb, var(--blue-soft) 88%, transparent);border-color:transparent}
.chip.green{background:color-mix(in srgb, var(--green-soft) 88%, transparent);border-color:transparent}
.chip.amber{background:color-mix(in srgb, var(--amber-soft) 88%, transparent);border-color:transparent}
.chip.red{background:color-mix(in srgb, var(--red-soft) 88%, transparent);border-color:transparent}
.chip.purple{background:color-mix(in srgb, var(--purple-soft) 88%, transparent);border-color:transparent}

/* 开关：玻璃面板 */
.switch{
  background:color-mix(in srgb, var(--surface-3) 88%, transparent);
  border:1px solid var(--border-2);
  box-shadow:inset 0 1px 0 var(--g-hi), inset 0 1px 2px rgba(0,0,0,.08);
}
[data-theme="dark"] .switch{box-shadow:inset 0 1px 0 rgba(255,255,255,.04), inset 0 1px 2px rgba(0,0,0,.4)}

/* 进度条 */
.progress{
  background:color-mix(in srgb, var(--surface-3) 88%, transparent);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.progress > i{box-shadow:0 0 8px color-mix(in srgb, var(--blue) 30%, transparent)}

/* 表格：玻璃面板 + 玻璃表头 */
.table-wrap{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(18px) saturate(165%);
  backdrop-filter:blur(18px) saturate(165%);
  border:1px solid var(--g-line);
  box-shadow:var(--g-shadow), inset 0 1px 0 var(--g-hi);
}
table.tb th{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(14px) saturate(165%);
  backdrop-filter:blur(14px) saturate(165%);
  border-bottom:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
table.tb tbody tr:hover{background:color-mix(in srgb, var(--surface-2) 70%, transparent)}
table.tb tbody tr:active{background:color-mix(in srgb, var(--surface-3) 70%, transparent)}
table.tb td{border-bottom:1px solid var(--g-line)}
table.tb tbody tr:last-child td{border-bottom:0}

/* 冻结列 / 选择列 / 操作列：半透明，避免覆盖玻璃面板 */
table.tb th.fz, table.tb td.fz{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(14px) saturate(165%);
  backdrop-filter:blur(14px) saturate(165%);
  box-shadow:inset -1px 0 0 var(--g-line);
}
table.tb tbody tr:hover td.fz{background:color-mix(in srgb, var(--surface-2) 75%, transparent)}
.ck-th,.ck-cell{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(14px) saturate(165%);
  backdrop-filter:blur(14px) saturate(165%);
  box-shadow:inset -1px 0 0 var(--g-line);
}
table.tb tbody tr:hover td.ck-cell{background:color-mix(in srgb, var(--surface-2) 75%, transparent)}
.op-th,.op-cell{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(14px) saturate(165%);
  backdrop-filter:blur(14px) saturate(165%);
  box-shadow:inset 1px 0 0 var(--g-line);
}
table.tb tbody tr:hover td.op-cell{background:color-mix(in srgb, var(--surface-2) 75%, transparent)}
tr.row-selected td{background:color-mix(in srgb, var(--blue-soft) 75%, transparent)}
tr.row-selected td.ck-cell,tr.row-selected td.op-cell{background:color-mix(in srgb, var(--blue-soft) 80%, transparent)}

/* 表格密度下保持紧凑但玻璃感 */
.dt.d-compact table.tb th, .dt.d-dense table.tb th{padding-top:7px;padding-bottom:7px}

/* 筛选条 / 选择徽章：玻璃 */
.dt-filters{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(14px) saturate(160%);
  backdrop-filter:blur(14px) saturate(160%);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.dt-selbadge{
  background:color-mix(in srgb, var(--surface-3) 80%, transparent);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.dt-selbadge.on{background:color-mix(in srgb, var(--blue-soft) 88%, transparent);border-color:transparent}
.dt-chip{
  background:color-mix(in srgb, var(--blue-soft) 88%, transparent);
  border:1px solid transparent;
}
.dt-chip button{background:rgba(0,0,0,.08)}
[data-theme="dark"] .dt-chip button{background:rgba(255,255,255,.14)}

/* 多行筛选编辑器 */
.dt-fl-bar{border-bottom-color:var(--g-line)}
.dt-fl-row{animation:pop .2s var(--ease) both}
.dt-fl-col,.dt-fl-op,.dt-fl-v{
  background:var(--g-2);
  border:1px solid var(--border-2);
  border-radius:9px;
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.dt-fl-del{background:transparent;border-color:var(--g-line)}
.dt-fl-del:hover{
  background:color-mix(in srgb, var(--red-soft) 92%, transparent);
  color:var(--red);
  border-color:color-mix(in srgb, var(--red) 22%, transparent);
}

/* 列表项 / 头像 / 徽标 */
.list-item{
  background:transparent;border:1px solid transparent;
}
.list-item:hover{
  background:var(--g-2);
  border-color:var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.avatar,.avatar-sm{
  background:linear-gradient(135deg, var(--blue), var(--blue-2));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32), 0 4px 12px var(--blue-soft);
  border:1px solid color-mix(in srgb, var(--blue) 30%, transparent);
}
.avatar-sm{
  background:color-mix(in srgb, var(--surface-3) 88%, transparent);
  color:var(--text-2);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.nav-badge{
  background:color-mix(in srgb, var(--surface-3) 88%, transparent);
  border:1px solid var(--g-line);
  color:var(--text-2);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.tbadge{box-shadow:0 4px 10px color-mix(in srgb, var(--red) 30%, transparent), inset 0 1px 0 rgba(255,255,255,.3)}

/* Tab / Pill tabs */
.tabs{
  background:color-mix(in srgb, var(--surface-3) 80%, transparent);
  -webkit-backdrop-filter:blur(10px);
  backdrop-filter:blur(10px);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.tabs div{color:var(--text-2)}
.tabs div.on{
  background:var(--g-1);
  color:var(--text);
  box-shadow:var(--g-shadow), inset 0 1px 0 var(--g-hi);
}
.pill-tabs .p{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.pill-tabs .p.on{
  background:color-mix(in srgb, var(--text) 88%, transparent);
  color:var(--surface);
  border-color:transparent;
}
[data-theme="dark"] .pill-tabs .p.on{background:color-mix(in srgb, var(--surface-2) 88%, transparent);color:var(--text)}

/* 骨架 / 空状态 */
.skeleton{
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--surface-3) 80%, transparent) 25%,
    color-mix(in srgb, var(--surface-2) 88%, transparent) 37%,
    color-mix(in srgb, var(--surface-3) 80%, transparent) 63%);
  background-size:400% 100%;
}
.empty{color:var(--muted)}
.empty svg{stroke:var(--border-2)}

/* 皮肤卡片 / 配置行 */
.skin-card{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(14px) saturate(160%);
  backdrop-filter:blur(14px) saturate(160%);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.skin-card.on{
  border-color:var(--blue);
  box-shadow:0 0 0 3px var(--blue-soft), inset 0 1px 0 var(--g-hi);
}
.skin-sw{border:1px solid var(--g-line)}
.dh-row{
  background:var(--g-2);
  -webkit-backdrop-filter:blur(12px) saturate(160%);
  backdrop-filter:blur(12px) saturate(160%);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.dh-row.act{
  border-color:var(--blue);
  box-shadow:0 0 0 3px var(--blue-soft), inset 0 1px 0 var(--g-hi);
}
.dh-chip{background:color-mix(in srgb, var(--surface-2) 86%, transparent)}
.dh-off-hint{background:color-mix(in srgb, var(--surface-2) 86%, transparent);border:1px solid var(--g-line)}
/* 修复硬编码浅色错误块（暗色主题同样可见） */
.dh-err{
  background:color-mix(in srgb, var(--red-soft) 80%, transparent);
  border:1px solid color-mix(in srgb, var(--red) 22%, transparent);
  color:var(--red);
}
.dh-err button{background:var(--red);color:#fff;box-shadow:inset 0 1px 0 rgba(255,255,255,.3)}

/* 模块抽屉 / 画布 */
.pal{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(22px) saturate(170%);
  backdrop-filter:blur(22px) saturate(170%);
  border:1px solid var(--g-line);
  box-shadow:var(--g-shadow), inset 0 1px 0 var(--g-hi);
}
.pal-item{
  background:color-mix(in srgb, var(--surface-3) 82%, transparent);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.diy-canvas{
  background:color-mix(in srgb, var(--surface-3) 70%, transparent);
  -webkit-backdrop-filter:blur(14px) saturate(160%);
  backdrop-filter:blur(14px) saturate(160%);
  border:2px dashed transparent;
}
.diy-canvas.over{
  border-color:var(--blue);
  background:color-mix(in srgb, var(--blue-soft) 60%, transparent);
}
.add-mod-tile{
  background:color-mix(in srgb, var(--blue-soft) 50%, transparent);
  border:2px dashed color-mix(in srgb, var(--blue) 38%, transparent);
}
.add-mod-tile:hover{background:color-mix(in srgb, var(--blue-soft) 80%, transparent)}
#pal-search{
  background:var(--g-2);
  border:1px solid var(--border-2);
  box-shadow:inset 0 1px 0 var(--g-hi);
}

/* DIY 模块卡片：玻璃面板 */
.b-card{
  background:var(--d-card);
  border:1px solid var(--d-border);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.l-card,.wcard{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(18px) saturate(165%);
  backdrop-filter:blur(18px) saturate(165%);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.au-card{
  background:rgba(255,255,255,.10);
  -webkit-backdrop-filter:blur(20px) saturate(180%);
  backdrop-filter:blur(20px) saturate(180%);
  border:1px solid rgba(255,255,255,.16);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18);
}

/* spark / progress bar 内填充：使用 --d-accent 已定义 */
.spark i{
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--d-accent) 95%, transparent),
    color-mix(in srgb, var(--blue-2) 50%, transparent));
  box-shadow:0 0 8px color-mix(in srgb, var(--d-accent) 30%, transparent);
}

/* DIY 单元：硬编码浅色 → 玻璃化 */
.gm-bar-row .bar{background:color-mix(in srgb, var(--surface-3) 88%, transparent);border:1px solid var(--g-line)}
.gm-count .cp{
  background:var(--g-2);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.gm-birth .av{box-shadow:inset 0 1px 0 rgba(255,255,255,.3)}
.gm-todo .ti{border-bottom-color:var(--g-line)}
.gm-todo .ck{
  background:var(--g-1);
  border:1.5px solid var(--border-2);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.gm-feed .fi{border-bottom-color:var(--g-line)}
.gm-feed .fi b{color:var(--text)}
.gm-tl .ti2{border-bottom-color:var(--g-line)}
.gm-prog .pr .bar{background:color-mix(in srgb, var(--surface-3) 88%, transparent);border:1px solid var(--g-line)}
.gm-leave .lv{border-bottom-color:var(--g-line)}
.gm-heat i{background:color-mix(in srgb, var(--surface-3) 88%, transparent);border:1px solid var(--g-line)}
.gm-heat i.l1{background:color-mix(in srgb, #4caf50 22%, transparent)}
.gm-heat i.l2{background:color-mix(in srgb, #4caf50 48%, transparent)}
.gm-heat i.l3{background:color-mix(in srgb, #4caf50 78%, transparent)}
.gm-table td,.gm-table th{border-bottom-color:var(--g-line)}
.gm-donut{
  background:conic-gradient(var(--blue) 0 70%, var(--surface-3) 70% 100%);
  box-shadow:inset 0 0 0 1px var(--g-line);
}
.gm-donut i{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
  color:var(--text);
}
.gm-links a{
  background:var(--g-2);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.gm-quote{
  border-left-color:var(--blue);
  background:color-mix(in srgb, var(--blue-soft) 30%, transparent);
  border-radius:0 12px 12px 0;
  padding:10px 12px;
}

/* 单元小屋 / 日历 / 时间轴 */
.dh-hut-cell{
  background:var(--g-2);
  border:1px solid var(--g-line);
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.dh-hut-tip{background:color-mix(in srgb, var(--surface-2) 86%, transparent)}
.dh-cal-hd i{color:var(--muted)}
.dh-cal-g i{
  background:transparent;
  border:1px solid transparent;
}
.dh-cal-g i.ev{
  background:color-mix(in srgb, var(--blue-soft) 90%, transparent);
  border-color:transparent;
  box-shadow:inset 0 1px 0 var(--g-hi);
}
.dh-cal-g i.today{
  background:linear-gradient(180deg, var(--green), color-mix(in srgb, var(--green) 80%, #000 18%));
  color:#fff;box-shadow:0 4px 12px color-mix(in srgb, var(--green) 35%, transparent);
}
.dh-tl::before{background:var(--g-line)}
.dh-tl-dot{box-shadow:0 0 0 1.5px var(--blue), 0 0 0 3px var(--g-1)}

/* duty.today 硬编码修复 */
.duty .d.today{
  background:color-mix(in srgb, var(--blue-soft) 80%, transparent);
  border:1px solid color-mix(in srgb, var(--blue) 30%, transparent);
  box-shadow:inset 0 1px 0 var(--g-hi);
}

/* 编辑模式工具栏 */
.edit-bar .btn{box-shadow:var(--g-shadow-2)}
.edit-hint{background:rgba(22,23,26,.92);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}

/* Toast：玻璃化 */
.toast{
  background:color-mix(in srgb, var(--text) 88%, transparent);
  -webkit-backdrop-filter:blur(14px) saturate(180%);
  backdrop-filter:blur(14px) saturate(180%);
  border:1px solid color-mix(in srgb, var(--surface) 18%, transparent);
  color:var(--surface);
  box-shadow:var(--g-shadow-2);
}
.toast.ok{background:color-mix(in srgb, var(--green) 92%, transparent)}
.toast.err{background:color-mix(in srgb, var(--red) 92%, transparent)}

/* 登录卡片：玻璃 */
.login-wrap{ background:transparent; }
.login-card{
  background:var(--g-1);
  -webkit-backdrop-filter:blur(30px) saturate(190%);
  backdrop-filter:blur(30px) saturate(190%);
  border:1px solid var(--g-line);
  box-shadow:var(--g-shadow-2), inset 0 1px 0 var(--g-hi);
}

/* 模态头部 / 底部与正文间距统一 */
.modal-hd,.modal-ft{padding:14px 22px}
.modal-bd{padding:20px 22px}
.modal-ft{border-top:1px solid var(--g-line)}
.modal-hd{border-bottom:1px solid var(--g-line)}

/* FAB 模块搭按钮（页面右下）玻璃感 */
#diy-fab{
  -webkit-backdrop-filter:blur(18px) saturate(190%);
  backdrop-filter:blur(18px) saturate(190%);
  border:1px solid color-mix(in srgb, var(--blue) 60%, transparent);
}
#diy-drawer{
  -webkit-backdrop-filter:blur(34px) saturate(190%);
  backdrop-filter:blur(34px) saturate(190%);
  border-left:1px solid var(--g-line);
}
[data-theme="dark"] #diy-drawer{
  background:color-mix(in srgb, var(--surface) 82%, transparent);
  border-left-color:rgba(255,255,255,.08);
}
#diy-drawer .dh-off-hint{margin:8px 0 10px}
#diy-extra{margin-top:var(--sp-5)}

/* 拖动幽灵 / 落位指示器 */
.drag-ghost{
  background:color-mix(in srgb, var(--blue) 92%, transparent);
  -webkit-backdrop-filter:blur(10px);
  backdrop-filter:blur(10px);
  border:1px solid color-mix(in srgb, var(--blue) 60%, transparent);
  box-shadow:0 12px 32px color-mix(in srgb, var(--blue) 40%, transparent), inset 0 1px 0 rgba(255,255,255,.3);
}
#drag-hint{
  -webkit-backdrop-filter:blur(14px) saturate(180%);
  backdrop-filter:blur(14px) saturate(180%);
  border:1px solid color-mix(in srgb, var(--blue) 60%, transparent);
}

/* 表格横滚提示徽标 */
.dt-scroll-hint{
  background:color-mix(in srgb, var(--blue) 92%, transparent);
  -webkit-backdrop-filter:blur(10px);
  backdrop-filter:blur(10px);
  border:1px solid color-mix(in srgb, var(--blue) 60%, transparent);
  box-shadow:0 6px 18px color-mix(in srgb, var(--blue) 35%, transparent), inset 0 1px 0 rgba(255,255,255,.3);
}

/* 右键菜单浮起感 */
.ctx-menu{
  background:var(--g-1)!important;
  -webkit-backdrop-filter:blur(30px) saturate(190%)!important;
  backdrop-filter:blur(30px) saturate(190%)!important;
  border:1px solid var(--g-line)!important;
  box-shadow:var(--g-shadow-2), inset 0 1px 0 var(--g-hi);
}
.ctx-item:hover{background:color-mix(in srgb, var(--blue) 92%, transparent)!important}
.ctx-item.danger:hover{background:color-mix(in srgb, var(--red) 92%, transparent)!important}
.ctx-sep{background:var(--g-line)}

/* 玻璃模块删除小红点 */
.dmod .dm-del{
  box-shadow:0 4px 10px rgba(0,0,0,.18), inset 0 1px 0 rgba(255,255,255,.3);
}

/* ===================== 间距统一（克制修改，仅补齐 JS 内联风格的回归基线） ===================== */
.content{padding:var(--sp-5) var(--sp-6) var(--sp-7)}
.wrap{max-width:1280px;margin:0 auto}
.card{padding:var(--sp-5)}
.grid,.grid-blocks{gap:var(--sp-4)}
.sec-hd{margin:0 0 var(--sp-4)}
.sec-hd + .grid,
.sec-hd + .grid-blocks{margin-top:0}
.field{margin-bottom:var(--sp-4)}
.row{gap:var(--sp-3)}
.dt-bar{margin-bottom:var(--sp-3)}

/* 内容区直接子元素之间补一个统一 18px 间距（不影响单独小节） */
.content > .wrap > .sec-hd:first-child{margin-top:0}
.content .wrap > .sec-hd + div{margin-top:0}

/* 模块市场按钮组留白 */
.pal-list-d + .sec-hd{margin-top:var(--sp-5)}

/* 移动端：保持节奏一致 */
@media (max-width:860px){
  .content{padding:18px var(--sp-4) var(--sp-7)}
  .card{padding:var(--sp-4);border-radius:18px}
}

/* ===== 暗色主题下强化玻璃可读性 ===== */
[data-theme="dark"] .topbar{background:color-mix(in srgb, var(--surface) 62%, transparent)}
[data-theme="dark"] .sidebar{background:color-mix(in srgb, var(--surface) 60%, transparent)}
[data-theme="dark"] .card{
  /* v1.9.62：56% → 86%，与亮色侧及 .dm 对齐。
     原来 56% 比后面那条 .72 还弱，暗色下卡片面几乎与底同色（本次「背景色没了」的暗色侧成因）。 */
  background:color-mix(in srgb, var(--surface) 86%, transparent);
  border-color:rgba(255,255,255,.10);
  box-shadow:var(--g-shadow), inset 0 1px 0 var(--g-hi);
}
[data-theme="dark"] .modal{
  background:color-mix(in srgb, var(--surface) 78%, transparent);
  border-color:rgba(255,255,255,.08);
}
[data-theme="dark"] .ctx-menu{
  background:color-mix(in srgb, var(--surface) 80%, transparent)!important;
  border-color:rgba(255,255,255,.10)!important;
}
[data-theme="dark"] .input,
[data-theme="dark"] select.input,
[data-theme="dark"] textarea.input{
  background:color-mix(in srgb, var(--surface-2) 88%, transparent);
  border-color:rgba(255,255,255,.14);
  color:var(--text);
}
[data-theme="dark"] .l-card,
[data-theme="dark"] .wcard,
[data-theme="dark"] .b-card{
  background:color-mix(in srgb, var(--surface) 56%, transparent);
  border-color:rgba(255,255,255,.08);
}
[data-theme="dark"] .gm-donut i{
  background:color-mix(in srgb, var(--surface) 60%, transparent);
  color:var(--text);
  border-color:rgba(255,255,255,.10);
}
[data-theme="dark"] table.tb tbody tr:hover td.fz,
[data-theme="dark"] .ck-th,
[data-theme="dark"] .ck-cell,
[data-theme="dark"] .op-th,
[data-theme="dark"] .op-cell{
  background:color-mix(in srgb, var(--surface) 70%, transparent);
}
[data-theme="dark"] .dh-cal-g i.today{
  background:linear-gradient(180deg, var(--green), color-mix(in srgb, var(--green) 60%, #000 30%));
}

/* 数据大屏模式：在玻璃基础上再加深一档 */
body.screen-mode{
  --g-1:rgba(13,20,40,.55);
  --g-2:rgba(18,28,52,.50);
  --g-3:rgba(22,34,60,.46);
  --g-line:rgba(120,160,255,.16);
  --g-hi:rgba(160,190,255,.10);
  --blur:18px;
}
body.screen-mode .card{
  box-shadow:0 10px 34px rgba(0,0,0,.35), inset 0 1px 0 rgba(160,190,255,.10);
}
body.screen-mode .topbar{background:rgba(10,14,26,.55);border-bottom-color:rgba(120,160,255,.12)}
body.screen-mode .sidebar{display:none}
body.screen-mode .content{padding:16px 20px 40px}
body.screen-mode .wrap{max-width:none}
body.screen-mode .kpi-val{color:#eaf1ff;font-size:38px}
body.screen-mode .kpi-label,body.screen-mode .small,body.screen-mode .sec-hd h2{color:#9fb4d8}
body.screen-mode .sec-hd h2{color:#eaf1ff}
body.screen-mode .grid-blocks{gap:12px}
body.screen-mode table.tb td{color:#cfe0ff}

/* ===================== 可自定义驾驶舱（dash） ===================== */
.dash-wrap{display:flex;flex-direction:column;height:100%;min-height:0}
.dash-bar{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:10px 12px;margin-bottom:var(--sp-4);
  background:var(--g-2);-webkit-backdrop-filter:blur(18px) saturate(170%);backdrop-filter:blur(18px) saturate(170%);
  border:1px solid var(--g-line);border-radius:14px;box-shadow:inset 0 1px 0 var(--g-hi);
}
.db-pages{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}
.db-page{
  padding:6px 13px;border-radius:999px;border:1px solid transparent;background:transparent;
  color:var(--text-2);font-size:13px;font-weight:600;cursor:pointer;transition:all .18s var(--ease);
  white-space:nowrap;max-width:190px;overflow:hidden;text-overflow:ellipsis;
}
.db-page:hover{background:var(--g-3);color:var(--text)}
.db-page.on{background:var(--blue);color:#fff;box-shadow:0 4px 14px var(--blue-soft)}
.db-add{padding:6px 12px;border-radius:999px;border:1px dashed var(--border-2);background:transparent;color:var(--muted);font-size:12.5px;cursor:pointer;transition:all .18s}
.db-add:hover{border-color:var(--blue);color:var(--blue);background:var(--blue-soft)}
.db-sp{flex:1;min-width:8px}
.db-sep{width:1px;height:20px;background:var(--g-line);margin:0 4px}

.dash-canvas-box{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding-right:2px;padding-bottom:40px}
.dash-canvas{
  display:grid;grid-template-columns:repeat(var(--cols,12),1fr);
  grid-auto-rows:var(--row,96px);gap:var(--gap,14px);
  position:relative;align-content:start;
}
.dash-canvas.show-grid{background-image:linear-gradient(90deg,var(--blue-soft) 1px,transparent 1px);background-size:calc(100% / var(--cols,12)) 100%;}

.dash-empty{
  grid-column:1/-1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
  padding:64px 20px;color:var(--muted);text-align:center;
  background:var(--g-1);border:1px dashed var(--border-2);border-radius:18px;
}
.dash-empty .ic{font-size:40px;opacity:.5}
.dash-empty .t{font-size:15px;font-weight:650;color:var(--text-2)}
.dash-empty .s{font-size:12.5px;max-width:420px;line-height:1.7}

.dm-ghost{
  /* 位置一律交给 transform（left/top 恒为 0）：位移走合成层，不产生重排 */
  position:absolute;left:0;top:0;
  border:2px dashed var(--blue);border-radius:16px;
  background:var(--blue-soft);opacity:.32;pointer-events:none;
  /* 必须高于 .dm.dragging(50)：缩放时被拖模块原地不动，否则占位框会被完全盖住 */
  z-index:60;will-change:transform;
  /* 只过渡尺寸；位移不设过渡，否则占位框会滞后于指针、产生「不跟手」 */
  transition:width .09s var(--ease),height .09s var(--ease);
}
/* 缩放态：边框完全实心、背景透明（不遮挡模块内容），外加实时尺寸角标，缩小/放大都清晰可见 */
.dm-ghost.resizing{
  opacity:1;background:transparent;
  box-shadow:0 0 0 3px color-mix(in srgb, var(--blue) 10%, transparent);
}
.dm-ghost-badge{
  position:absolute;right:8px;bottom:7px;
  font-size:11px;font-weight:700;letter-spacing:.02em;color:var(--blue);
  background:var(--surface);border:1px solid var(--blue);border-radius:999px;
  padding:1px 9px;line-height:1.6;white-space:nowrap;
}

/* ---------- 模块 ---------- */
.dm{
  position:relative;display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden;
  border-radius:16px;padding:12px 14px 14px;
  background:var(--g-1);-webkit-backdrop-filter:blur(22px) saturate(175%);backdrop-filter:blur(22px) saturate(175%);
  border:1px solid var(--g-line);box-shadow:var(--g-shadow),inset 0 1px 0 var(--g-hi);
  /* 统一动效：入场渐显（按顺序错开） + 悬停高亮
     fill-mode 必须用 backwards：both 会把 to{transform:none} 永久钉在元素上，
     动画优先级高于普通声明 → .dm:hover 的上浮 transform 永远不生效 */
  animation:dmIn .44s cubic-bezier(.22,.9,.24,1) backwards;
  animation-delay:calc(var(--i,0) * 30ms);
  transition:box-shadow .22s var(--ease),transform .2s var(--ease),border-color .22s,background .22s;
  /* 不要在这里常驻 will-change：会把每个模块都提升成独立合成层，
     再叠加上面的 backdrop-filter，模块一多拖拽就会明显掉帧（v1.6.0 移除） */
}
@keyframes dmIn{from{opacity:0;transform:translateY(12px) scale(.985)}to{opacity:1;transform:none}}
/* 悬停高亮：仅描边发光 + 顶部光晕，**不再上浮位移**——之前与 backdrop-filter 叠加
   会触发 Chromium 子元素文字 subpixel 重绘，使标题向左偏移一像素且被边框遮挡。 */
.dm:hover{
  transform:none;
  border-color:color-mix(in srgb,var(--blue) 42%,var(--g-line));
  box-shadow:0 14px 34px color-mix(in srgb,var(--blue) 16%,transparent),var(--g-shadow-2),inset 0 1px 0 var(--g-hi);
}
/* 数据切换过渡：模块重渲染时内容淡入 */
@keyframes dmSwap{from{opacity:.2;transform:translateY(5px)}to{opacity:1;transform:none}}
.dm-swap{animation:dmSwap .3s var(--ease) both}
.dm.dragging,.dm.dragging:hover{opacity:.94;transform:scale(1.012);z-index:50;box-shadow:0 22px 54px rgba(0,0,0,.20),inset 0 1px 0 var(--g-hi);cursor:grabbing}
.dm.flash{animation:dmFlash 1.2s var(--ease)}
@keyframes dmFlash{0%{box-shadow:0 0 0 3px var(--blue),0 0 0 8px var(--blue-soft)}100%{box-shadow:var(--g-shadow),inset 0 1px 0 var(--g-hi)}}
body.dash-dragging{cursor:grabbing;user-select:none}
body.dash-dragging .dm{transition:grid-column .18s var(--ease),grid-row .18s var(--ease)}
body.dash-dragging .dm:not(.dragging){opacity:.82}
/* ---- 拖拽性能专项（v1.6.0）----
   ① 只给被拖元素提升合成层，其它模块保持默认（避免 N 个合成层互相打架）
   ② 被拖元素逐帧位移时临时关闭 backdrop-filter —— 毛玻璃需要按帧重采样背后像素，
      是拖拽掉帧的最大元凶；用接近实色的底色顶上，视觉几乎无差别
   ③ 屏蔽 hover 上浮，避免指针划过其它模块时产生多余样式计算与动画 */
body.dash-dragging .dm{will-change:auto}
body.dash-dragging .dm:hover{transform:none;box-shadow:var(--g-shadow),inset 0 1px 0 var(--g-hi);border-color:var(--g-line)}
body.dash-dragging .dm.dragging,.dm.dragging:hover{
  will-change:transform;
  -webkit-backdrop-filter:none;backdrop-filter:none;
  background:color-mix(in srgb,var(--surface) 93%,transparent);
}
/* 尊重系统「减少动态效果」设置 */
@media (prefers-reduced-motion:reduce){
  .dm,.dm-swap,.dash-canvas .dm{animation:none!important}
  .dm:hover{transform:none}
  .dm-ghost{transition:none}
}

.dm-hd{display:flex;align-items:center;gap:8px;min-width:0;margin-bottom:9px;cursor:grab;user-select:none}
.dm-hd:active{cursor:grabbing}
.dm-t{font-size:13.5px;font-weight:680;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.dm-badge{font-size:11px;color:var(--muted);background:var(--g-3);padding:2px 7px;border-radius:999px;white-space:nowrap;flex:none}
.dm-ops{margin-left:auto;display:flex;gap:2px;flex:none;opacity:0;transition:opacity .18s}
.dm:hover .dm-ops,.dm.dragging .dm-ops{opacity:1}
.dm-op{
  width:28px;height:28px;border-radius:8px;border:1px solid transparent;background:transparent;
  color:var(--muted);font-size:12px;line-height:1;cursor:pointer;display:grid;place-items:center;transition:all .15s;
}
.dm-op:hover{background:var(--g-3);color:var(--text);border-color:var(--g-line)}
.dm-op.danger:hover{background:var(--red-soft);color:var(--red)}
/* 模块内容区：一律不出现滚动条，改为自适应高度（放不下的条目由 JS 折叠并提示“还有 N 项”） */
.dm-bd{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column}
.dm-bd::-webkit-scrollbar{display:none}
/* 内容一律不超出可视高度，杜绝任何形式的模块内滚动 */
.dm-bd > *{min-height:0;max-height:100%;flex-shrink:1;overflow:hidden}
/* 自适应折叠提示 */
/* v1.9.36：「还有 N 项」提示跟随模块自身的水平对齐（--dm-align 由 applyModStyle 写在 .dm-bd 上）。
   行式模块默认靠左后，一条居中的提示会显得跟正文脱节；图表/KPI 类仍是居中，观感不变。 */
.dm-more{font-size:11px;color:var(--muted);text-align:var(--dm-align,center);padding:3px 0 0;flex:none;letter-spacing:.2px}
.dm-rz{
  position:absolute;right:2px;bottom:2px;width:16px;height:16px;cursor:nwse-resize;z-index:5;
  background:linear-gradient(135deg,transparent 46%,var(--border-2) 46%,var(--border-2) 54%,transparent 54%,transparent 62%,var(--border-2) 62%,var(--border-2) 70%,transparent 70%);
  border-radius:0 0 14px 0;opacity:.55;transition:opacity .18s;
}
.dm:hover .dm-rz{opacity:1}
.dm-loading,.dm-empty{display:grid;place-items:center;height:100%;min-height:60px;color:var(--muted);font-size:12.5px;text-align:center;padding:8px}
.dm-empty.dm-nodata{grid-auto-flow:row;gap:6px;align-content:center;color:var(--warn,#e0342b);opacity:.9}
.dm-empty.dm-nodata svg{width:20px;height:20px;opacity:.75}

/* ---------- 模块内容 ---------- */
.dm-kpi{display:flex;flex-direction:column;flex:1;min-height:0;gap:4px}
.dm-kpi-top{display:flex;align-items:center;gap:8px;min-width:0}
.dm-kpi-ic{width:28px;height:28px;border-radius:9px;display:grid;place-items:center;font-size:15px;flex:none}
.dm-kpi-lb{font-size:12.5px;color:var(--text-2);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-kpi-val{font-size:32px;font-weight:700;line-height:1.1;letter-spacing:-.5px}
.dm-kpi-cmp{font-size:11.5px;font-weight:650}
.dm-kpi-cmp.up{color:var(--green)}.dm-kpi-cmp.down{color:var(--red)}
.dm-kpi-cmp span{color:var(--muted);font-weight:500;margin-left:3px}
.dm-kpi-spark{margin-top:auto;height:30px;opacity:.9}

.dm-chart{flex:1;min-height:0;width:100%}
.dm-grid{stroke:var(--g-line);stroke-width:1}
.dm-ax{fill:var(--muted);font-size:9px}
.dm-hbar{display:flex;flex-direction:column;gap:7px;justify-content:center;height:100%}
/* v1.9.36：行式模块在**窄卡**里必须能收缩，否则整行最小宽度（名称 74 + 条 20 + 数值 38 + 间距 18 = 150px）
   一旦超过卡片宽度，右侧的数值就被 .dm-bd 的 overflow:hidden 切掉 —— 线上实测 174px 宽的排行卡
   数值越界 50px。改法：名称 `flex:0 1 <基准>`、条 `flex:1 1 <小基准>`（都能缩但都不长），
   数值保持 flex:none 不被压缩（关键信息优先保住）。基准值让宽卡上的对齐观感完全不变。 */
.dm-hbar-row{display:flex;align-items:center;gap:9px;font-size:12px;min-width:0}
.dm-hbar-row .nm{width:74px;flex:0 1 74px;min-width:0;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-hbar-row .bar{flex:1 1 20px;height:9px;border-radius:5px;background:var(--g-3);overflow:hidden;min-width:10px}
.dm-hbar-row .bar i{display:block;height:100%;border-radius:5px;transition:width .5s var(--ease)}
.dm-hbar-row .pv{width:38px;text-align:right;flex:none;font-weight:680;font-size:12px}

.dm-pie{display:flex;flex-direction:column;gap:8px;height:100%;align-items:center;justify-content:center}
.dm-pie svg{flex:1;min-height:0}
.dm-legend{display:flex;flex-wrap:wrap;gap:4px 12px;justify-content:center;font-size:11px;color:var(--text-2);max-height:52px;overflow:hidden;width:100%}
.dm-legend span{display:flex;align-items:center;gap:4px;white-space:nowrap}
/* v1.9.35：图例放不下时折成「+N」小标签（按实测高度动态裁剪，见 dashdata.js svgPie）——
   双行放不下就只显示一行 + 「+N」，不再让第三行被 max-height 裁掉半截 */
.dm-legend .dm-legend-more{display:flex;align-items:center;padding:0 6px;height:15px;border-radius:8px;
  background:var(--g-2,rgba(0,0,0,.06));color:var(--text-2);font-size:10px;font-weight:700;flex:none}
.dm-legend i{width:8px;height:8px;border-radius:3px;flex:none}
.dm-donut-n{fill:var(--text);font-size:22px;font-weight:700}
.dm-donut-t{fill:var(--muted);font-size:10px}

.dm-gauge-box{flex:1;min-height:0;display:grid;place-items:center}
.dm-gauge{width:100%;height:100%;display:grid;place-items:center}
.dm-gauge svg{width:100%;height:100%;max-height:150px}
.dm-gauge-n{fill:var(--text);font-size:26px;font-weight:700}
.dm-gauge-t{fill:var(--muted);font-size:10px}
.dm-gauge-sub{text-align:center;font-size:12px;color:var(--muted);margin-top:-6px}

.dm-prog{display:flex;flex-direction:column;gap:9px;justify-content:center;height:100%}
.dm-prog-row .hd{display:flex;justify-content:space-between;gap:8px;font-size:12px;margin-bottom:4px}
/* v1.9.36：名称侧要能收缩，否则长名称会把右侧数值挤出卡片（flex item 默认 min-width:auto） */
.dm-prog-row .hd span{color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto;min-width:0}
.dm-prog-row .hd b{font-weight:680;flex:none}
.dm-prog-row .bar{height:8px;border-radius:5px;background:var(--g-3);overflow:hidden}
.dm-prog-row .bar i{display:block;height:100%;border-radius:5px;transition:width .5s var(--ease)}

.dm-heat{display:flex;flex-wrap:wrap;gap:3px;align-content:flex-start;flex:1;min-height:0;overflow:hidden}
.dm-heat i{width:11px;height:11px;border-radius:3px;background:var(--g-3);border:1px solid var(--g-line);flex:none}
.dm-heat i.l1{background:color-mix(in srgb,var(--hc,#23854c) 25%,transparent);border-color:transparent}
.dm-heat i.l2{background:color-mix(in srgb,var(--hc,#23854c) 48%,transparent);border-color:transparent}
.dm-heat i.l3{background:color-mix(in srgb,var(--hc,#23854c) 72%,transparent);border-color:transparent}
.dm-heat i.l4{background:var(--hc,#23854c);border-color:transparent}
.dm-heat-ft{display:flex;justify-content:space-between;font-size:10.5px;color:var(--muted);margin-top:6px;flex:none}

.dm-cal{display:flex;flex-direction:column;gap:6px;height:100%}
.dm-cal-hd{font-size:13px;font-weight:680;color:var(--text);flex:none}
.dm-cal-w,.dm-cal-g{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}
.dm-cal-w i{font-size:10px;color:var(--muted);text-align:center;font-style:normal}
.dm-cal-g i{
  aspect-ratio:1;display:grid;place-items:center;font-size:10.5px;font-style:normal;border-radius:6px;
  color:var(--text-2);background:var(--g-3);border:1px solid transparent;
}
.dm-cal-g i.pad{background:transparent}
.dm-cal-g i.ev{background:color-mix(in srgb,var(--hc,#0071e3) 22%,transparent);color:var(--text);font-weight:650}
.dm-cal-g i.today{background:var(--hc,#0071e3);color:#fff;font-weight:700}

.dm-tl{display:flex;flex-direction:column;gap:9px;position:relative;padding-left:2px}
.dm-tl-i{display:flex;gap:9px;position:relative;padding-left:14px}
.dm-tl-i::before{content:'';position:absolute;left:4px;top:14px;bottom:-9px;width:1.5px;background:var(--g-line)}
.dm-tl-i:last-child::before{display:none}
.dm-tl-i .dot{position:absolute;left:0;top:5px;width:9px;height:9px;border-radius:50%;box-shadow:0 0 0 2px var(--g-1)}
.dm-tl-i .d{font-size:10.5px;color:var(--muted);flex:none;width:64px;padding-top:1px}
.dm-tl-i .bd{min-width:0;flex:1}
.dm-tl-i .t{font-size:12.5px;font-weight:620;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-tl-i .s{font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.dm-todo{display:flex;flex-direction:column;gap:7px}
/* v1.9.8 待办按账号隔离：他人待办无权限时的占位态 */
.dm-todo-lock{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;
  height:100%;min-height:120px;text-align:center;color:var(--muted);
  background:color-mix(in srgb,var(--g-2) 60%,transparent);border-radius:12px;padding:14px}
.dm-todo-lock .t{font-size:13px;font-weight:600;color:var(--text-1)}
.dm-todo-lock .s{font-size:11.5px;max-width:260px;line-height:1.5}
/* v1.9.2 待办清单「+ 新增待办」入口：常驻显示，不依赖 hover，触屏也能点 */
.dm-todo-tools{display:flex;justify-content:flex-end;margin:0 0 2px;flex:none}
.dm-todo-tools .dm-todo-add,
.dm-todo-tools .dm-op{
  /* v1.9.8b：必须覆盖全局 .dm-op 的 width/height:24px 定尺寸，否则文字被塞进竖条挤压换行
     v1.9.9：class 改用独立的 dm-todo-add——dm-op 会被 draw 统一绑定循环覆盖 onclick（吞点击） */
  width:auto;height:auto;white-space:nowrap;display:inline-flex;align-items:center;gap:3px;
  opacity:1;font-size:11px;padding:3px 9px;border-radius:8px;
  border:1px dashed color-mix(in srgb,var(--blue) 45%,var(--g-line));
  color:var(--blue);background:color-mix(in srgb,var(--blue) 8%,transparent)}
.dm-todo-tools .dm-todo-add:hover,
.dm-todo-tools .dm-op:hover{
  background:color-mix(in srgb,var(--blue) 16%,transparent);
  border-style:solid;color:var(--blue)}
.dm-todo-i{display:flex;align-items:flex-start;gap:8px;font-size:12.5px}
.dm-todo-i .ck{width:14px;height:14px;border-radius:5px;border:1.5px solid var(--border-2);flex:none;margin-top:2px;background:var(--g-1)}
.dm-todo-i .tx{flex:1;min-width:0;color:var(--text-2);line-height:1.5}
.dm-todo-i .dt{font-size:10.5px;color:var(--muted);flex:none}

.dm-count{display:flex;gap:10px;flex-wrap:wrap;height:100%;align-items:center;justify-content:space-around}
.dm-count .cp{text-align:center;min-width:56px}
.dm-count .n{font-size:26px;font-weight:700;color:var(--c,var(--blue));line-height:1}
.dm-count .t{font-size:11px;color:var(--muted);margin-top:3px}

.dm-notice{display:flex;flex-direction:column;gap:9px}
.dm-notice-i{display:flex;gap:9px;align-items:flex-start}
.dm-notice-i .dot{width:7px;height:7px;border-radius:50%;flex:none;margin-top:5px}
/* v1.9.36：正文块（裸 div）同样要 min-width:0 + flex:1 —— 否则 flex item 的 min-width:auto
   会被 .m 的 nowrap 文案撑到 357px（父级内容区只有 304px），横向越界 69px 后被裁掉，
   .m 上的 text-overflow:ellipsis 永远不触发。与 .dm-list-i .bd 同一类问题。 */
.dm-notice-i > div{min-width:0;flex:1}
.dm-notice-i .t{font-size:12.5px;font-weight:620;color:var(--text);line-height:1.45}
.dm-notice-i .m{font-size:11px;color:var(--muted);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.dm-list{display:flex;flex-direction:column;gap:7px}
.dm-list-i{display:flex;gap:9px;align-items:center;padding:5px 6px;border-radius:9px;transition:background .15s}
.dm-list-i:hover{background:var(--g-3)}
.dm-list-i .av{width:26px;height:26px;border-radius:9px;display:grid;place-items:center;font-size:12px;font-weight:680;flex:none}
/* v1.9.36：文本块必须 min-width:0 + flex:1，否则 flex item 的 min-width:auto 会让它
   被「一行长说明」撑得比行还宽（实测 .bd 307px > 行 295px），.t/.s 的 text-overflow:ellipsis
   因为容器本身没被约束而**永远不触发** —— 文字横向溢出、被 .dm-bd 的 overflow:hidden 切掉，
   垂直方向测不出来所以一直没被发现（时间轴 .dm-tl-i .bd 早就有这两条，列表漏了）。
   配 v1.9.36 的「行式模块默认靠左」，行内文字才真正贴左并可读地截断。 */
.dm-list-i .bd{min-width:0;flex:1}
.dm-list-i .t{font-size:12.5px;font-weight:620;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-list-i .s{font-size:10.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.dm-stat{display:flex;gap:10px;height:100%;align-items:center;overflow:hidden}
.dm-stat.col{flex-direction:column;align-items:stretch;justify-content:center;gap:8px}
.dm-stat-i{flex:1;min-width:0;text-align:center;padding:8px 6px;border-radius:11px;background:color-mix(in srgb,var(--c) 8%,transparent);border:1px solid var(--g-line)}
.dm-stat.col .dm-stat-i{display:flex;align-items:center;gap:10px;text-align:left}
.dm-stat-i .v{font-size:22px;font-weight:700;color:var(--c);line-height:1.1}
.dm-stat-i .l{font-size:11.5px;color:var(--text-2);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-stat-i .p{font-size:10.5px;color:var(--muted)}
.dm-stat.col .dm-stat-i .v{width:54px;text-align:right;flex:none}
.dm-stat.col .dm-stat-i .l{flex:1;margin:0}
.dm-stat.col .dm-stat-i .p{width:44px;text-align:right;flex:none}

.dm-funnel{display:flex;flex-direction:column;gap:8px;justify-content:center;height:100%}
.dm-fn-row{display:flex;align-items:center;gap:9px;font-size:12px;min-width:0}
.dm-fn-row .nm{width:76px;flex:0 1 76px;min-width:0;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-fn-row .tr{flex:1 1 auto;position:relative;height:22px;display:flex;align-items:center;min-width:10px}
.dm-fn-row .tr i{display:block;height:100%;border-radius:5px;transition:width .5s var(--ease)}
.dm-fn-row .tr b{position:absolute;right:7px;font-size:11.5px;color:var(--text);font-weight:680}

.dm-rank{display:flex;flex-direction:column;gap:6px;height:100%;justify-content:center}
/* v1.9.36：同上，窄卡里可收缩（线上 174px 宽的排行卡原来数值被切 50px） */
.dm-rank-row{display:flex;align-items:center;gap:7px;font-size:12px;min-width:0}
.dm-rank-row .rk{width:16px;flex:none;text-align:center;color:var(--muted);font-weight:680;font-size:11px}
.dm-rank-row .rk.top{color:var(--amber)}
.dm-rank-row .av{width:20px;height:20px;border-radius:7px;display:grid;place-items:center;color:#fff;font-size:10px;font-weight:700;flex:none}
.dm-rank-row .nm{width:56px;flex:0 1 56px;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--text-2)}
.dm-rank-row .bar{flex:1 1 16px;height:7px;border-radius:4px;background:var(--g-3);overflow:hidden;min-width:8px}
.dm-rank-row .bar i{display:block;height:100%;border-radius:4px}
.dm-rank-row .pv{width:30px;text-align:right;flex:none;font-weight:680;font-size:11.5px}

.dm-text{font-size:13px;line-height:1.75;color:var(--text-2);border-left:3px solid var(--c,var(--blue));padding:4px 0 4px 12px;border-radius:0 10px 10px 0;background:color-mix(in srgb,var(--c,#0071e3) 5%,transparent);overflow:hidden}

.dm-tbwrap{flex:1;min-height:0;overflow:hidden;border-radius:10px;display:flex;flex-direction:column}
table.dm-tb{width:100%;border-collapse:collapse;font-size:11.5px}
table.dm-tb th{
  position:sticky;top:0;z-index:2;text-align:left;padding:6px 9px;font-weight:660;color:var(--text-2);
  background:var(--g-2);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  border-bottom:1px solid var(--g-line);white-space:nowrap;
}
table.dm-tb td{padding:6px 9px;border-bottom:1px solid var(--g-line);color:var(--text);white-space:nowrap;max-width:180px;overflow:hidden;text-overflow:ellipsis;text-align:left}
table.dm-tb tbody tr:hover td{background:var(--g-3)}
table.dm-tb.dense th,table.dm-tb.dense td{padding:4px 8px}

/* ---------- 参数抽屉 ---------- */
.dash-cfg{
  position:fixed;top:0;right:0;bottom:0;width:376px;max-width:94vw;z-index:140;
  display:flex;flex-direction:column;transform:translateX(102%);transition:transform .3s var(--ease);
  background:var(--g-1);-webkit-backdrop-filter:blur(34px) saturate(190%);backdrop-filter:blur(34px) saturate(190%);
  border-left:1px solid var(--g-line);box-shadow:-24px 0 60px rgba(0,0,0,.16);
}
[data-theme="dark"] .dash-cfg{background:color-mix(in srgb,var(--surface) 84%,transparent);border-left-color:rgba(255,255,255,.09)}
.dash-cfg.open{transform:translateX(0)}
.dc-hd{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--g-line);flex:none}
.dc-hd .ic{font-size:20px;flex:none}
.dc-hd .tt{flex:1;min-width:0;display:flex;flex-direction:column}
.dc-hd .tt b{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dc-bd{flex:1;overflow-y:auto;padding:16px}
.dc-ft{flex:none;padding:12px 16px;border-top:1px solid var(--g-line);display:flex;justify-content:flex-end;gap:8px}
/* v1.9.116：面板底部左侧多了一个「复制给别的客户」——用 .sp 把关闭按钮仍顶到右侧 */
.dc-ft .sp{flex:1 1 auto;min-width:0}
.dc-f{margin-bottom:14px}
.dc-f .fl{display:block;margin-bottom:5px}
.dc-hint{font-size:11px;color:var(--muted);margin-top:5px}
.dc-hint.warn{color:var(--warn,#e0342b)}
.dc-sec{margin-top:18px;padding-top:14px;border-top:1px solid var(--g-line)}
.dc-sec-t{font-size:12.5px;font-weight:660;color:var(--text-2);margin-bottom:9px}
.dc-flt{display:grid;grid-template-columns:1fr 78px 1fr auto;gap:6px;margin-bottom:8px;align-items:center}
.dc-flt .input{min-width:0;font-size:12px;padding:6px 9px}

/* 显示列勾选器（全选 / 反选 / 排序 / 已选回显） */
.dc-cols{display:flex;flex-direction:column;gap:8px}
.dc-cols-bar{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.dc-cols-bar .small{margin-left:auto}
.dc-cols-pick{
  display:flex;flex-wrap:wrap;gap:5px;max-height:150px;overflow-y:auto;
  padding:9px;border:1px solid var(--g-line);border-radius:11px;background:var(--g-2);
}
.col-chip{
  font-size:11.5px;line-height:1;padding:6px 10px;border-radius:999px;cursor:pointer;
  border:1px solid var(--border);background:var(--surface);color:var(--text-2);
  transition:all .15s var(--ease);max-width:100%;
}
.col-chip:hover{border-color:var(--blue);color:var(--blue)}
.col-chip.on{
  background:var(--blue-soft);border-color:color-mix(in srgb,var(--blue) 45%,transparent);
  color:var(--blue);font-weight:620;
}
.dc-cols-sel{display:flex;flex-direction:column;gap:4px;max-height:176px;overflow-y:auto}
.col-sel-row{
  display:flex;align-items:center;gap:6px;padding:5px 7px;border-radius:9px;
  border:1px solid var(--g-line);background:var(--g-2);font-size:12px;
}
.col-sel-row .cg{color:var(--muted);display:grid;place-items:center;flex:none;opacity:.65}
.col-sel-row .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:560}
.col-sel-row .tbtn{padding:2px 5px;font-size:11px}

/* ---------- v1.9.103：详情弹窗里的「显示列」设置（.gro-*） ----------
   与 .dc-cols 同一套视觉，但**嵌在弹窗 body 里**、宽度不定（弹窗是 wide），
   所以网格改成两列自适应，避免几十个字段排成一长条把弹窗撑得老高。
   背景一律走主题令牌，亮暗主题都不用改。 */
.gro-cbar{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:8px}
.gro-cbar .small{margin-left:auto}
.gro-pick{
  display:flex;flex-wrap:wrap;gap:5px;max-height:132px;overflow-y:auto;
  padding:9px;border:1px solid var(--g-line);border-radius:11px;background:var(--g-2);
}
.gro-sel{display:flex;flex-direction:column;gap:4px;max-height:150px;overflow-y:auto}
#grp-cfg>.dc-fold-b{padding-top:8px}

/* ---------- v1.9.99：色环取色（背景色这类"自由色"参数） ----------
   内联在参数面板里，**不做浮层** —— 面板本身可滚动，浮层会被 overflow 裁掉。
   背景一律走主题令牌（--g-1/-2/-3、--g-line），亮暗两套主题都不用改。 */
.dc-color .cw-row{display:flex;align-items:center;gap:15px}
.cw-ring{
  position:relative;width:104px;height:104px;flex:none;border-radius:50%;cursor:crosshair;
  touch-action:none;user-select:none;outline:none;
  background:conic-gradient(from -90deg,
    hsl(0 80% 56%),hsl(45 80% 56%),hsl(90 80% 56%),hsl(135 80% 56%),
    hsl(180 80% 56%),hsl(225 80% 56%),hsl(270 80% 56%),hsl(315 80% 56%),hsl(360 80% 56%));
  box-shadow:0 0 0 1px var(--g-line) inset,0 1px 5px rgba(0,0,0,.16);
}
.cw-ring:focus-visible{box-shadow:0 0 0 1px var(--g-line) inset,0 0 0 3px color-mix(in srgb,var(--blue) 45%,transparent)}
.cw-hole{
  position:absolute;inset:17px;border-radius:50%;pointer-events:none;
  background:var(--g-2);display:grid;place-items:center;
  font-size:11px;color:var(--muted);letter-spacing:.5px;
  box-shadow:0 0 0 1px var(--g-line) inset;
}
.cw-knob{
  position:absolute;left:50%;top:50%;width:15px;height:15px;margin:-7.5px 0 0 -7.5px;
  border-radius:50%;background:var(--g-3);pointer-events:none;
  box-shadow:0 0 0 2px rgba(0,0,0,.34),0 1px 4px rgba(0,0,0,.3);
}
.cw-info{display:flex;flex-direction:column;gap:8px;min-width:0}
.cw-prev{
  width:30px;height:30px;border-radius:9px;box-shadow:0 0 0 1px var(--g-line) inset;
  /* 棋盘格底：没选色（透明）的时候，一眼能看出是"空"而不是"白" */
  background-image:linear-gradient(45deg,var(--g-line) 25%,transparent 25%,transparent 75%,var(--g-line) 75%),
                   linear-gradient(45deg,var(--g-line) 25%,transparent 25%,transparent 75%,var(--g-line) 75%);
  background-size:10px 10px;background-position:0 0,5px 5px;
}
.cw-val{font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums;letter-spacing:.2px}
.cw-presets{display:flex;gap:6px;flex-wrap:wrap;max-width:152px}
.cw-p{
  width:22px;height:22px;border-radius:7px;border:0;padding:0;cursor:pointer;
  box-shadow:0 0 0 1px var(--g-line) inset;transition:transform .12s ease;
}
.cw-p:hover{transform:translateY(-1px)}
.cw-p-none{
  background:var(--g-1);color:var(--muted);font-size:11px;line-height:1;
  display:grid;place-items:center;
}

/* ---------- v1.9.99：模块「背景色」叠色（项目卡环等） ----------
   用 inset 超大扩散 box-shadow 叠色，**不改 `background`** ——
   `.dm` 的玻璃底是 `var(--g-1)` + `backdrop-filter:blur(22px)`，覆盖 background 会把玻璃质感顶掉。
   box-shadow 画在「背景之上、内容之下」，所以卡里的文字/图形不被遮；
   把原有的 `--g-shadow` 与外层高光一起带上，避免丢高度感。 */
.dm.dm-tinted{box-shadow:var(--g-shadow),inset 0 1px 0 var(--g-hi),inset 0 0 0 9999px var(--dm-tint,transparent)}

/* ---------- 添加模块 ---------- */
.dm-add-search{margin-bottom:14px}
.dm-add-grp{margin-bottom:16px}
.dm-add-gt{font-size:12px;font-weight:680;color:var(--muted);margin-bottom:8px;letter-spacing:.3px}
.dm-add-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(126px,1fr));gap:9px}
.dm-add-tile{
  display:flex;flex-direction:column;align-items:center;gap:5px;padding:14px 8px;cursor:pointer;
  border-radius:13px;border:1px solid var(--g-line);background:var(--g-2);
  box-shadow:inset 0 1px 0 var(--g-hi);transition:all .18s var(--ease);color:var(--text);
}
.dm-add-tile:hover{border-color:var(--blue);background:var(--blue-soft);transform:translateY(-2px);box-shadow:var(--g-shadow-2)}
.dm-add-tile .ic{font-size:22px}
.dm-add-tile .nm{font-size:12.5px;font-weight:640;text-align:center}
.dm-add-tile .sz{font-size:10px;color:var(--muted)}

/* ---------- 添加模块 · AI 区（v1.9.79） ---------- */
/* 背景一律用玻璃令牌 --g-1/-2/-3，禁止手写 rgba(255,255,255,.xx)
   —— 暗色主题下硬编码白色会把整块面板洗白，之前踩过。 */
.dai{border:1px solid var(--g-line);background:var(--g-2);border-radius:15px;padding:14px 15px;box-shadow:inset 0 1px 0 var(--g-hi)}
.dai-hd{display:flex;align-items:baseline;gap:9px;margin-bottom:10px;flex-wrap:wrap}
.dai-t{font-size:13.5px;font-weight:680}
.dai-sub{font-size:11.5px;color:var(--muted);min-width:0}
.dai-row{display:flex;gap:9px}
.dai-row .input{flex:1;min-width:0}
.dai-hint{font-size:11.5px;color:var(--muted);margin-top:8px;line-height:1.5}
.dai-hint.warn{color:var(--amber)}
.dai-hint.bad{color:var(--red)}
.dai-split{display:flex;align-items:center;gap:10px;margin:14px 0;color:var(--muted);font-size:11.5px}
.dai-split:before,.dai-split:after{content:'';flex:1;height:1px;background:var(--g-line)}
.dai-out{margin-top:12px}
.dai-bar{display:flex;align-items:center;gap:9px;margin-bottom:11px}
.dai-count{font-size:12px;color:var(--muted)}
.dai-sp{flex:1}
.dai-list{display:flex;flex-direction:column;gap:12px}
.dai-card{border:1px solid var(--g-line);border-radius:13px;background:var(--g-1);padding:11px 12px;box-shadow:inset 0 1px 0 var(--g-hi)}
.dai-c-hd{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.dai-ck{display:flex;align-items:center;gap:7px;cursor:pointer;min-width:0}
.dai-c-t{font-size:13px;font-weight:620}
.dai-c-meta{font-size:11px;color:var(--muted);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dai-why{font-size:11.5px;color:var(--muted);margin-top:6px;line-height:1.5}
.dai-pvwrap{margin-top:10px}
/* 预览不可交互：模块里可能带待办勾选、地图、右键等交互，
   在弹窗里被误触会改到真实数据 —— 预览只用来「看」，一律屏蔽指针事件。 */
.dai-pv{pointer-events:none;user-select:none}
/* 预览是逐个渲染的，后面的卡片要等前面画完 —— 没有这行占位文案，
   用户看到的就是一张空白卡片，会以为"又坏了"（多卡片时空白能持续好几秒）。 */
.dai-pv-load{grid-column:1 / span 12;grid-row:1 / span 2;display:flex;align-items:center;justify-content:center;
  font-size:12px;color:var(--muted);border:1px dashed var(--g-line);border-radius:12px;background:var(--g-2)}
.dai-note{margin-top:11px;font-size:11.5px;color:var(--muted);line-height:1.6;border-left:2px solid var(--g-line);padding-left:10px}
.dai-note b{color:var(--text);font-weight:620;display:block;margin-bottom:3px}
.dai-note ul{margin:0;padding-left:16px}
.dai-note.warn{border-left-color:var(--amber)}
/* 空卡提示：预览渲染完发现这张卡取不到数据 → 自动取消勾选并就地说明。
   比"加进去之后在画布上看到一张空卡、还得自己找原因"便宜得多。 */
.dai-empty-tip{margin-top:7px;font-size:11.5px;color:var(--amber);line-height:1.5;
  border-left:2px solid var(--amber);padding-left:9px}

/* ---------- 页面排序 ---------- */
.dm-sortlist{display:flex;flex-direction:column;gap:7px}
.dm-sortrow{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:11px;background:var(--g-2);border:1px solid var(--g-line)}
.dm-sortrow .ic{font-size:16px;flex:none}
.dm-sortrow .nm{flex:1;min-width:0;font-size:13px;font-weight:620;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-sortrow .cnt{font-size:11px;color:var(--muted);flex:none}
.dm-sortrow .ops{display:flex;gap:3px;flex:none}

/* ---------- 响应式 ---------- */
/* v1.9.35：≤1100px 时模块改为单列自适应高度，原来 min-height 只有 150px，
   而 KPI 卡「图标行 + 数值 + 口径说明」三行内容至少要 ~97px（.dm-bd 内），
   加上标题行与内边距就超了 → 卡片底部被 .dm-bd 的 overflow:hidden 硬裁 4px
   （实测 1100px 下 9 个 KPI 卡全部裁 4px）。统一提到 170px，与 ≤700px 一致。 */
@media (max-width:1100px){
  .dash-canvas{grid-template-columns:repeat(6,1fr);grid-auto-rows:minmax(88px,auto)}
  .dash-canvas > .dm{grid-column:1/-1!important;grid-row:auto!important;min-height:170px}
}
@media (max-width:700px){
  .dash-canvas > .dm{min-height:170px}
}
@media (max-width:700px){
  .dash-bar{padding:9px 10px;gap:6px}
  .db-page{max-width:130px;font-size:12px;padding:5px 10px}
  /* v1.9.35：行高必须是「至少 88px」而不是固定 88px —— .dm 有 min-height:170px，
     固定行高会让 170px 高的卡片在 88px 的行里溢出并与下一行重叠 */
  .dash-canvas{grid-auto-rows:minmax(88px,auto)}
  .dash-cfg{width:100%;max-width:100%}
  .dc-flt{grid-template-columns:1fr 1fr;grid-template-areas:'f f' 'o v' 'x x'}
  .dc-flt .f-f{grid-area:f}.dc-flt .f-o{grid-area:o}.dc-flt .f-v{grid-area:v}.dc-flt .tbtn{grid-area:x}
}

/* 驾驶舱全高布局（仅 dash 页面生效，自动识别，无需 JS 钩子） */
.content:has(> .wrap > .dash-wrap){overflow:hidden;padding-bottom:0;display:flex;flex-direction:column}
.content:has(> .wrap > .dash-wrap) > .wrap{max-width:none;width:100%;flex:1;min-height:0;display:flex;flex-direction:column}

/* ============================================================
 *  左栏编辑增强（编辑文案模式）：拖动排序 / 新建分组
 *  + 线稿图标容器 + 嵌入式驾驶舱
 * ============================================================ */
.sb-newgrp{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin:0 0 10px;padding:9px 10px;border-radius:12px;
  border:1px dashed color-mix(in srgb,var(--blue) 45%,var(--border));
  background:var(--blue-soft);
}
.sb-newgrp .small{line-height:1.5;flex:1;min-width:120px}
.nav-drag{
  display:grid;place-items:center;width:18px;height:18px;flex:none;
  color:var(--muted);opacity:.65;cursor:grab;
}
.nav-drag:active{cursor:grabbing}
.nav-mv{
  width:20px;height:20px;border-radius:6px;border:1px solid transparent;background:transparent;
  color:var(--muted);display:grid;place-items:center;cursor:pointer;flex:none;padding:0;transition:all .15s;
}
.nav-mv:hover{background:var(--surface-3);color:var(--blue);border-color:var(--g-line)}
.nav-item[draggable="true"]{cursor:grab}
.nav-item.dragging{opacity:.45;border:1px dashed var(--blue)}
.nav-item.dropi{box-shadow:inset 0 2px 0 0 var(--blue)}
.sb-group.drop{background:var(--blue-soft);border-radius:10px;box-shadow:inset 0 0 0 1px var(--blue)}

/* 线稿图标容器（emoji 兜底替换用） */
.emj-ico{display:inline-flex;align-items:center;justify-content:center;vertical-align:-3px;color:inherit}
.emj-ico svg{display:block}

/* 嵌入式驾驶舱（台账页顶部） */
.dash-embed{
  margin-bottom:16px;padding:14px;border-radius:16px;
  background:var(--g-1);border:1px solid var(--g-line);
  -webkit-backdrop-filter:blur(22px) saturate(175%);backdrop-filter:blur(22px) saturate(175%);
  box-shadow:var(--g-shadow),inset 0 1px 0 var(--g-hi);
}
.dash-embed.compact{padding:10px}
.de-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.de-bar .de-t{display:inline-flex;align-items:center;gap:6px;font-size:13.5px;font-weight:680;color:var(--text)}
.de-bar .de-sp{flex:1}
.de-bar .btn{display:inline-flex;align-items:center;gap:4px}
.dash-embed.de-lazy{border:1px dashed var(--line);border-radius:var(--r-md,14px);padding:14px 16px;background:var(--bg-soft,rgba(127,127,127,.05))}
.de-lazy .de-bar{margin-bottom:6px}
.de-lazy-tip{line-height:1.6;opacity:.75}

.sb-empty-g{
  padding:8px 10px;margin:2px 0 6px;border-radius:9px;font-size:11.5px;color:var(--muted);
  border:1px dashed var(--border);background:var(--surface-2);text-align:center;
}

/* ============================================================
 *  v1.7.0 新增：图标选择器 / 模块悬浮动效 / 字体自适应 /
 *              数据样式配置 / 数据来源悬浮说明
 * ============================================================ */

/* ---------- 1. 图标选择器（设置里改菜单图标时用） ---------- */
.ic-picker{display:flex;flex-direction:column;gap:12px;max-height:56vh}
.ic-search{display:flex;align-items:center;gap:10px}
.ic-search .input{flex:1;max-width:340px}
.ic-body{overflow-y:auto;max-height:44vh;padding-right:4px}
.ic-grp{margin-bottom:14px}
.ic-gt{font-size:11.5px;font-weight:680;color:var(--muted);letter-spacing:.4px;margin:0 0 7px}
.ic-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:7px}
.ic-tile{
  height:44px;border:1px solid var(--border);border-radius:10px;background:var(--surface-2);
  color:var(--text-2);cursor:pointer;display:grid;place-items:center;padding:0;
  transition:transform .16s var(--ease),background .18s var(--ease),border-color .18s var(--ease),color .18s var(--ease),box-shadow .18s var(--ease);
}
.ic-tile:hover{transform:translateY(-2px);background:var(--surface-3);border-color:var(--blue);color:var(--blue);box-shadow:0 4px 12px rgba(0,113,227,.14)}
.ic-tile.on{background:var(--blue-soft);border-color:var(--blue);color:var(--blue);box-shadow:0 0 0 2px var(--blue-soft)}
.ic-tile svg{width:19px;height:19px}

/* ---------- 2. 全模块悬浮动效（v1.7.6 统一重做） ----------
   原则：
   ① 只动 transform / filter / opacity / box-shadow / background —— 不触发布局重排，
      全部可由合成器或廉价重绘完成，保证流畅不卡顿
   ② 节奏统一：小元素 .15~.18s、模块级 .26s，缓动统一 var(--ease)
   ③ 类名已逐一与 dashmods.js / dashdata.js / charts.js 真实渲染 DOM 核对
     （v1.7.0 旧版一半选择器是死样式，且两处 .dm:hover 互相覆盖，本段整体重写）
   ④ 系统开启「减少动态效果」时自动降级（见段尾） */

/* 2.1 SVG 图表元素级悬浮：transform-box:fill-box 让每个图形绕自身中心变换 */
.dm-bd svg rect,.dm-bd svg circle,.dm-bd svg path,.dm-bd svg text{
  transition:transform .18s var(--ease),filter .18s var(--ease),opacity .18s var(--ease);
}
/* 柱状图：悬浮提亮 + 轻微上浮拉伸 */
.dm-chart svg rect{transform-box:fill-box;transform-origin:center bottom}
.dm-chart svg rect:hover{transform:translateY(-1.5px) scaleY(1.02);filter:brightness(1.14)}
/* 折线图数据点：悬浮放大 + 发光 */
.dm-chart svg circle{transform-box:fill-box;transform-origin:center}
.dm-chart svg circle:hover{transform:scale(1.8);filter:drop-shadow(0 0 4px rgba(0,113,227,.55))}
.dm-chart svg .line-anim:hover{filter:drop-shadow(0 2px 5px rgba(0,113,227,.4))}
/* 饼 / 环：悬停扇区放大提亮，其余扇区同步淡出，焦点更清晰（:has 仅在悬停到扇区时生效，
   避免鼠标在圆心文字上时全图变暗） */
.dm-pie svg path{transform-box:fill-box;transform-origin:center}
.dm-pie svg path:hover{transform:scale(1.035);filter:brightness(1.1)}
.dm-pie svg:has(path:hover) path:not(:hover){opacity:.62}
/* 仪表盘：悬停整体辉光 */
.dm-gauge svg{transition:filter .26s var(--ease)}
.dm-gauge svg:hover{filter:drop-shadow(0 0 7px color-mix(in srgb,var(--blue,#0071e3) 45%,transparent))}
/* 图例：悬停点亮 + 色点微放大 */
.dm-legend i{transition:transform .16s var(--ease),box-shadow .16s var(--ease)}
.dm-legend span{transition:color .16s}
.dm-legend span:hover{color:var(--text)}
.dm-legend span:hover i{transform:scale(1.45);box-shadow:0 0 0 2px var(--g-3)}

/* 2.2 列表 / 行条目（排行榜、横向条、进度、漏斗、清单、时间轴、公告、待办、图文）：
       右移 3px + 底色浮现，全模块同一节奏 */
.dm-hbar-row,.dm-rank-row,.dm-prog-row,.dm-fn-row,
.dm-list-i,.dm-tl-i,.dm-notice-i,.dm-todo-i,.pv-i{
  border-radius:8px;
  transition:transform .18s var(--ease),background .18s var(--ease);
}
.dm-hbar-row:hover,.dm-rank-row:hover,.dm-prog-row:hover,.dm-fn-row:hover,
.dm-list-i:hover,.dm-tl-i:hover,.dm-notice-i:hover,.dm-todo-i:hover,.pv-i:hover{
  transform:translateX(3px);background:var(--surface-3);
}
.dm-list-i:hover .nm,.dm-tl-i:hover{color:var(--text)}

/* 2.3 网格型内容：热力格 / 日历格 / 统计格 —— 放大 + 浮起 */
.dm-heat i{transition:transform .15s var(--ease),box-shadow .15s var(--ease)}
.dm-heat i:hover{transform:scale(1.5);box-shadow:0 2px 8px rgba(0,0,0,.22);position:relative;z-index:2}
/* v1.9.4：日历/热力图格子悬浮提示（全局唯一浮层，替代原生 title） */
.dm-cell-tip{
  position:fixed;z-index:9999;pointer-events:none;opacity:0;
  transform:translateY(3px);transition:opacity .13s var(--ease),transform .13s var(--ease);
  background:#1c1c1e;color:#fff;font-size:11.5px;font-weight:600;letter-spacing:.2px;
  padding:5px 9px;border-radius:8px;white-space:nowrap;box-shadow:0 6px 18px rgba(0,0,0,.28)}
.dm-cell-tip.on{opacity:1;transform:translateY(0)}
.dm-cal-g i{transition:transform .15s var(--ease),box-shadow .15s var(--ease),filter .15s var(--ease)}
.dm-cal-g i:hover{transform:scale(1.14);filter:brightness(1.06);box-shadow:0 2px 7px rgba(0,0,0,.14)}
.dm-stat-i{border-radius:10px;transition:transform .2s var(--ease),background .2s var(--ease)}
.dm-stat-i:hover{transform:translateY(-2px);background:var(--surface-3)}
/* 统计数字：所在模块被悬停时数字轻微放大聚焦 */
.dm-stat-i .v,.dm-kpi-val,.dm-count .n{transition:transform .26s var(--ease)}
.dm:hover .dm-stat-i .v,.dm:hover .dm-kpi-val,.dm:hover .dm-count .n{transform:scale(1.04)}

/* 2.4 进度 / 排行 / 横向条 / 漏斗条：所在模块悬停时高光扫过一次 */
.dm-prog .bar,.dm-rank .bar,.dm-hbar-row .bar,.dm-fn-row .tr{position:relative;overflow:hidden}
.dm-prog .bar::after,.dm-rank .bar::after,.dm-hbar-row .bar::after,.dm-fn-row .tr::after{
  content:'';position:absolute;inset:0;transform:translateX(-101%);
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.35),transparent);
  transition:transform .65s var(--ease);pointer-events:none;
}
.dm:hover .dm-prog .bar::after,.dm:hover .dm-rank .bar::after,
.dm:hover .dm-hbar-row .bar::after,.dm:hover .dm-fn-row .tr::after{transform:translateX(101%)}

/* 2.5 首页 / 概览与图表卡（charts.js 渲染的 .card.kpi / .chip / .progress） */
.kpi:hover{transform:translateY(-3px);box-shadow:var(--shadow-2)}
.kpi-ic{transition:transform .24s var(--ease)}
.kpi:hover .kpi-ic{transform:scale(1.1) rotate(-5deg)}
.card .progress > i{transition:width .8s var(--ease),filter .2s var(--ease)}
.card:hover .progress > i{filter:brightness(1.1)}
/* 仅作用于真正的图表 SVG（charts.js 统一带 .chart 类），避免误伤卡片内装饰性小图标 */
.card svg.chart path,.card svg.chart rect,.card svg.chart circle{
  transform-box:fill-box;transform-origin:center;
  transition:transform .18s var(--ease),filter .18s var(--ease),opacity .18s var(--ease);
}
.card svg.chart rect{transform-origin:center bottom}
.card svg.chart rect:hover{transform:translateY(-1.5px);filter:brightness(1.12)}
.card svg.chart circle:hover{transform:scale(1.6);filter:drop-shadow(0 0 4px rgba(0,113,227,.5))}
.card svg.chart path:hover{transform:scale(1.03);filter:brightness(1.08)}
.card svg.chart:has(path:hover) path:not(:hover){opacity:.72}
.chip{transition:background .18s,color .18s,transform .18s var(--ease)}
.chip:hover{background:var(--surface);color:var(--text);transform:translateY(-1px)}

/* 2.6 降级与护栏：减少动态效果 / 触屏设备自动关闭悬浮位移 */
@media (prefers-reduced-motion:reduce){
  .dm-bd svg rect,.dm-bd svg circle,.dm-bd svg path,.dm-bd svg text,
  .dm-gauge svg,.dm-legend i,.dm-legend span,
  .dm-hbar-row,.dm-rank-row,.dm-prog-row,.dm-fn-row,.dm-list-i,.dm-tl-i,.dm-notice-i,.dm-todo-i,.pv-i,
  .dm-heat i,.dm-cal-g i,.dm-stat-i,.dm-stat-i .v,.dm-kpi-val,.dm-count .n,
  .kpi,.kpi-ic,.card .progress > i,.card svg.chart path,.card svg.chart rect,.card svg.chart circle,.chip{transition:none!important}
  .dm-chart svg rect:hover,.dm-chart svg circle:hover,.dm-pie svg path:hover,
  .dm-hbar-row:hover,.dm-rank-row:hover,.dm-prog-row:hover,.dm-fn-row:hover,
  .dm-list-i:hover,.dm-tl-i:hover,.dm-notice-i:hover,.dm-todo-i:hover,.pv-i:hover,
  .dm-heat i:hover,.dm-cal-g i:hover,.dm-stat-i:hover,.dm-stat-i:hover .v,
  .dm:hover .dm-stat-i .v,.dm:hover .dm-kpi-val,.dm:hover .dm-count .n,
  .kpi:hover,.kpi:hover .kpi-ic,.card svg.chart rect:hover,.card svg.chart circle:hover,.card svg.chart path:hover,.chip:hover{transform:none!important}
}

/* ---------- 3. 模块拉伸后字体变形修复（需求七） ----------
   图表 SVG 现在按容器真实像素建 viewBox（1 单位 = 1px），
   因此只改变绘图区大小，字号/线宽不再被整体缩放。 */
.dm-chart svg{width:100%;height:100%;display:block}
/* 模块内容统一走 --dm-scale（由 JS 按模块面积算出），文字比例恒定
   v1.9.35 修正：兜底值原来声明在 .dm-bd 上，而自定义属性按「最近祖先」取值 ——
   .dm-bd 自己声明了 1 就不再继承 .dm 上的自动缩放值，导致 applyModStyle 写进 .dm 的
   --dm-scale **被遮蔽**，「模块拉伸后字体自适应」（需求七）一直没生效。
   兜底改挂 .dm：没有 applyModStyle 的场合仍是 1，有的话正常生效；
   溢出降级时 fitOverflow 在 .dm-bd 上覆盖，作用域也更贴近内容。 */
.dm{--dm-scale:1}
.dm-bd .dm-fit,.dm-bd .dm-text,.dm-bd .dm-list,.dm-bd .dm-todo,.dm-bd .dm-tl,.dm-bd .dm-notice{
  font-size:calc(12.5px * var(--dm-scale));
}
.dm-bd .dm-ax{font-size:calc(10px * var(--dm-scale)) !important}

/* ---------- 4. 模块内数据样式自定义（需求八） ---------- */
.dm-bd{
  --dm-align:center;    /* 水平：left / center / right（v1.9.29 默认改为居中） */
  --dm-valign:center;   /* 垂直：start / center / end（v1.9.29 默认改为居中） */
  --dm-pad:14px;        /* 内边距 */
  --dm-zoom:1;          /* 缩放 */
  --dm-lh:1.55;         /* 行高 */
}
.dm-bd[data-style="1"]{
  text-align:var(--dm-align);
  padding:var(--dm-pad);
  line-height:var(--dm-lh);
}
.dm-bd[data-style="1"] > *{
  text-align:var(--dm-align);
  justify-content:var(--dm-jc,flex-start);
  /* 注意：这里刻意不设 align-items。历史写法是 align-items:var(--dm-ai,flex-start)，
     而 --dm-ai 从未被 JS 赋值 → 等于把所有模块的顶层容器强制 flex-start，
     于是排行 / 横向条 / 漏斗 / 列表这些「行」被压成内容宽度，进度条直接缩没（v1.9.29 发现）。
     去掉后各模块恢复自身设计的 align-items（.dm-stat/.dm-count 居中、其余 stretch）。 */
}
.dm-bd[data-style="1"]{
  display:flex;flex-direction:column;
  justify-content:var(--dm-vj,flex-start);
  align-items:var(--dm-ah,stretch);
}
.dm-bd[data-style="1"] > *{max-width:100%}
/* 缩放：整体等比缩放（transform-origin 由配置决定，默认左上） */
.dm-bd[data-style="1"] .dm-zoomwrap{
  transform:scale(var(--dm-zoom));
  transform-origin:var(--dm-origin,left top);
  width:calc(100% / var(--dm-zoom));
  flex:0 0 auto;
}
/* ---------- v1.9.29：默认居中后的收尾修正 ----------
   KPI 卡片里的「图标 + 标题」行本身是 flex（.dm-kpi-top），text-align 管不到 flex 子项，
   必须把它的主轴对齐切到配置值，否则默认居中后这一行仍然顶在左边。
   其它模块类型不受影响，故不放开通用规则（免得表格 / 排行条宽度塌陷）。 */
.dm-bd[data-style="1"] .dm-kpi-top{justify-content:var(--dm-jc,flex-start)}

/* ---------- 5. 模块左上角名称：悬浮显示数据来源（需求十一，v1.7.4 重做） ----------
   全局唯一浮层挂在 body：不受 .dm{overflow:hidden} 裁剪、窄标题不截断、全模块统一样式。
   JS 在 dash.js（mouseover/mouseout 委托 + 视口翻转定位）。 */
.dm-t{cursor:help}
.src-float{
  position:fixed;z-index:4000;
  min-width:230px;max-width:min(440px,86vw);
  background:var(--surface);color:var(--text);
  border:1px solid var(--border-2);border-radius:12px;
  box-shadow:0 12px 34px rgba(0,0,0,.16);
  padding:11px 13px;font-size:12px;line-height:1.75;text-align:left;
  opacity:0;visibility:hidden;transform:translateY(-4px);
  transition:opacity .18s var(--ease),transform .18s var(--ease),visibility .18s;
  pointer-events:none;white-space:normal;font-weight:400;
}
.src-float.on{opacity:1;visibility:visible;transform:translateY(0)}
.src-float .s-hd{font-weight:700;font-size:12.5px;margin-bottom:5px;color:var(--text)}
.src-float .s-row{display:flex;gap:8px;color:var(--text-2)}
.src-float .s-row > b{flex:0 0 58px;font-weight:600;color:var(--muted)}
.src-float .s-row > span{flex:1;min-width:0;word-break:break-all}
.src-float .s-tip{margin-top:6px;color:var(--muted);font-size:11px}

/* ---------- 6. 右键菜单：增加图标位与快捷提示 ---------- */
.ctx-item{display:flex;align-items:center;gap:8px}
.ctx-item .ci-k{margin-left:auto;font-size:10.5px;color:var(--muted)}

/* ---------- 7. 设置页「菜单与图标」 ---------- */
.navcfg-row{
  display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:10px;
  transition:background .18s var(--ease);
}
.navcfg-row:hover{background:var(--surface-3)}
.navcfg-row .n-ic{width:30px;height:30px;border-radius:9px;background:var(--surface-3);display:grid;place-items:center;color:var(--text-2);flex:0 0 auto;cursor:pointer;transition:background .18s var(--ease),color .18s var(--ease)}
.navcfg-row .n-ic:hover{background:var(--blue-soft);color:var(--blue)}
.navcfg-row .n-nm{flex:1;min-width:0;font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.navcfg-row .n-hash{font-size:11px;color:var(--muted);flex:0 0 auto}

/* ---------- 8. 真实地图模块（需求九） ---------- */
.dm-map{position:relative;width:100%;height:100%;border-radius:10px;overflow:hidden;background:var(--surface-3)}
.dm-map .map-canvas{position:absolute;inset:0}
.dm-map .map-fallback{position:absolute;inset:0;background-size:cover;background-position:center}
.dm-map .map-mask{position:absolute;left:0;right:0;bottom:0;padding:6px 9px;font-size:11px;color:#fff;
  background:linear-gradient(transparent,rgba(0,0,0,.45));pointer-events:none}
.dm-map .map-badge{position:absolute;right:8px;top:8px;padding:2px 8px;border-radius:999px;
  background:rgba(0,0,0,.42);color:#fff;font-size:10.5px;pointer-events:none}
.map-pick{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.map-pick .input{flex:1;min-width:120px}
.map-sug{position:absolute;left:0;right:0;top:100%;z-index:200;max-height:190px;overflow-y:auto;
  background:var(--surface);border:1px solid var(--border-2);border-radius:10px;box-shadow:var(--shadow-2);margin-top:4px}
.map-sug button{display:block;width:100%;text-align:left;padding:7px 10px;border:0;background:transparent;cursor:pointer;font-size:12.5px}
.map-sug button:hover{background:var(--surface-3)}

/* ---------- v1.7.0 补充样式 ---------- */
/* 参数设置按钮的忙碌态（需求三·5 防重复触发的视觉反馈） */
.dm-op.is-busy{opacity:.45;pointer-events:none}
.dm-op{transition:opacity .16s var(--ease),background .16s var(--ease),color .16s var(--ease),transform .16s var(--ease)}
.dm-op:hover{transform:scale(1.12)}
.dash-cfg.flash{animation:cfgFlash .5s var(--ease)}
@keyframes cfgFlash{0%{transform:translateX(0)}25%{transform:translateX(-6px)}50%{transform:translateX(6px)}75%{transform:translateX(-3px)}100%{transform:translateX(0)}}

/* 配置抽屉：显示样式区（需求八） */
.dc-style{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px}
.dc-st{display:flex;flex-direction:column;gap:4px}
.dc-st > span{font-size:11.5px;color:var(--muted);font-weight:600}
.dc-st .input{width:100%}

/* 只读字段标签（需求三·4） */
.ro-chip{
  font-size:10px;padding:0 6px;height:16px;line-height:16px;border-radius:999px;
  background:var(--surface-3);color:var(--muted);font-weight:600;vertical-align:middle;
  display:inline-flex;align-items:center;
}
.field input:disabled,.field input[readonly]{opacity:.62;cursor:not-allowed;background:var(--surface-3)}

/* 设置页「菜单与图标」（需求十） */
.navcfg-grp{margin-bottom:16px}
.navcfg-ghd{
  display:flex;align-items:center;gap:8px;padding:6px 10px;margin-bottom:6px;
  border-bottom:1px solid var(--border);
}
.navcfg-ghd .n-nm{font-size:12px;font-weight:700;color:var(--muted);letter-spacing:.4px}
.navcfg-ghd .sp{flex:1}
.navcfg-row .n-ic svg{width:16px;height:16px}

/* ---------- 待办清单：可勾选回写（v1.7.3） ---------- */
.dm-todo-i{cursor:default;border-radius:8px;padding:2px 6px;margin:0 -6px;transition:background .2s var(--ease),opacity .25s var(--ease),transform .2s var(--ease)}
.dm-todo-i:hover{background:color-mix(in srgb,var(--blue) 6%,transparent);transform:translateX(2px)}
.dm-todo-i .ck{cursor:pointer;position:relative;transition:background .18s var(--ease),border-color .18s,transform .15s var(--ease)}
.dm-todo-i .ck:hover{transform:scale(1.18)}
.dm-todo-i .ck.on{background:var(--c,#0071e3);border-color:var(--c,#0071e3)!important}
.dm-todo-i .ck.on::after{content:'';position:absolute;left:3.5px;top:.5px;width:5px;height:9px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(42deg)}
.dm-todo-i.done{opacity:.52}
.dm-todo-i.done .tx{text-decoration:line-through;text-decoration-thickness:1.5px;text-decoration-color:color-mix(in srgb,var(--c,#0071e3) 60%,transparent);color:var(--muted)}
.dm-todo-i .st{flex:none;font-size:10px;line-height:1.7;padding:0 7px;border-radius:999px;background:var(--g-2);color:var(--muted);border:1px solid var(--g-line);margin-top:1px;transition:background .2s var(--ease),color .2s,border-color .2s}
.dm-todo-i .st.ok{background:color-mix(in srgb,var(--c,#0071e3) 15%,transparent);color:color-mix(in srgb,var(--c,#0071e3) 75%,var(--text-1));border-color:color-mix(in srgb,var(--c,#0071e3) 35%,transparent);font-weight:600}

/* ---------- 表头字段名原位编辑输入框（v1.7.5） ---------- */
.th-inline-input{
  width:100%;min-width:80px;max-width:220px;font-size:12.5px;font-weight:600;color:var(--text);
  background:var(--surface);border:1.5px solid var(--blue,#0071e3);border-radius:7px;
  padding:3px 8px;outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--blue,#0071e3) 14%,transparent);
}
.th-inline-input:disabled{opacity:.55}

/* ---------- 差分渲染：数据更新型重绘抑制入场动画（v1.7.5） ---------- */
.dm-silent{animation:none !important}

/* ============================================================
 *  v1.7.7 绿透 green-glass 皮肤 + 流体玻璃组件库
 *  视觉体系来源：LearnPrompt/green-glass（MIT）
 *  token 全部变量化：换主色只改 --gg-h（色相），S/L 全程派生
 * ============================================================ */

/* ---------- 1. 绿透皮肤（暗色专用：明/暗模式下均为纯黑体系） ----------
   底色阶（5 级微跨度）：#000 / #050807(侧栏) / #0a0e0c(面板) / #101613(卡) / #1b211e(选中)
   描边：一律 1px 白 4.5%~7%；主绿 hsl(161 90% 41%) 只用于信号点/深绿按钮/绿字徽章 */
[data-skin="greenglass"],
[data-theme="dark"][data-skin="greenglass"]{
  --gg-h:161;
  --bg:#000000; --surface:#0a0e0c; --surface-2:#101613; --surface-3:#1b211e;
  --text:#f4f8f6; --text-2:rgba(232,239,235,.62); --muted:rgba(232,239,235,.45);
  --border:rgba(255,255,255,.06); --border-2:rgba(255,255,255,.07);
  --blue:hsl(var(--gg-h),90%,41%); --blue-2:hsl(var(--gg-h),90%,45%);
  --blue-600:hsl(var(--gg-h),90%,34%); --blue-soft:hsla(var(--gg-h),90%,45%,.13);
  --green:hsl(var(--gg-h),90%,41%); --green-text:hsl(var(--gg-h),80%,62%);
  --amber:#ffb457; --amber-soft:rgba(255,180,87,.14); --red:#ff7d6b;
  --r-lg:16px; --r-md:12px; --r-sm:7px; --r-xs:5px;
  --shadow-1:0 0 0 1px rgba(255,255,255,.04);
  --shadow-2:0 18px 44px rgba(0,0,0,.55);
  --font:'Space Grotesk','PingFang SC','Hiragino Sans GB','Microsoft YaHei',system-ui,sans-serif;
  --font-mono:'JetBrains Mono','SF Mono',Consolas,Menlo,monospace;
  font-feature-settings:'tnum' 1;
}
/* 侧栏/顶栏贴 #050807 轨道色，保持 1px 描边分层 */
[data-skin="greenglass"] .sidebar{background:rgba(5,8,7,.78);border-color:rgba(255,255,255,.06)}
[data-skin="greenglass"] .topbar{background:rgba(5,8,7,.72);border-color:rgba(255,255,255,.06)}
/* 主按钮按 token 规范走深绿实底（L11%，描边主绿 34%，字白），不做大面积亮绿 */
[data-skin="greenglass"] .btn:not(.ghost){
  background:hsl(var(--gg-h),90%,11%);color:#f2fbf6;
  box-shadow:inset 0 0 0 1px hsla(var(--gg-h),90%,41%,.34);
}
[data-skin="greenglass"] .btn:not(.ghost):hover{background:hsl(var(--gg-h),90%,15%)}
[data-skin="greenglass"] .nav-item.active{box-shadow:0 0 12px hsla(var(--gg-h),90%,45%,.25)}
/* 信号点（导航选中/在跑状态）：绿点 + 光晕 */
[data-skin="greenglass"] .nav-item.active .n-dot,
[data-skin="greenglass"] .dot{box-shadow:0 0 12px hsla(var(--gg-h),90%,55%,.55)}
/* 覆盖 Glassmorphism 2.0 浅色硬编码玻璃底（.card 在亮色模式写死白色半透明）：
   绿透下卡片回到「只比纯黑亮一点 + 1px 描边分层」的规范 */
[data-skin="greenglass"] .card{
  background:color-mix(in srgb, var(--surface) 80%, transparent);
  border-color:rgba(255,255,255,.07);
  box-shadow:var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.04);
}

/* ---------- 2. 皮肤激活时的流体玻璃统计面（纯 CSS，自动作用于统计/KPI 卡） ---------- */
[data-skin="greenglass"] .dm-stat,
[data-skin="greenglass"] .card.kpi{
  position:relative;overflow:hidden;background:#080b0a;border-color:rgba(255,255,255,.07);
}
[data-skin="greenglass"] .dm-stat::before,
[data-skin="greenglass"] .card.kpi::before{
  content:'';position:absolute;inset:-18%;z-index:0;pointer-events:none;
  filter:blur(30px);opacity:.82;
  background:
    radial-gradient(46% 58% at 24% 42%, hsla(var(--gg-h),90%,26%,.95) 0%, transparent 70%),
    radial-gradient(42% 55% at 72% 18%, hsla(calc(var(--gg-h) - 58),90%,28%,.90) 0%, transparent 70%),
    radial-gradient(48% 52% at 56% 82%, hsla(calc(var(--gg-h) - 104),85%,27%,.90) 0%, transparent 70%);
  animation:ggcDrift 24s ease-in-out infinite alternate;
}
[data-skin="greenglass"] .dm-stat::after,
[data-skin="greenglass"] .card.kpi::after{
  content:'';position:absolute;inset:0;z-index:0;pointer-events:none;
  background:linear-gradient(168deg,rgba(0,0,0,.18),rgba(0,0,0,.52)),linear-gradient(158deg,rgba(255,255,255,.08),transparent 44%);
}
[data-skin="greenglass"] .dm-stat > *,[data-skin="greenglass"] .card.kpi > *{position:relative;z-index:1}
@keyframes ggcDrift{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(2.4%,-3%,0) scale(1.08)}}

/* ---------- 3. 组件① 流体玻璃统计卡（.ggc-*，任意皮肤可用） ---------- */
.ggc-frow{
  display:grid;gap:14px;
  grid-template-columns:repeat(auto-fit,minmax(var(--ggc-min,210px),1fr));
}
.ggc-fcard{
  position:relative;overflow:hidden;height:146px;border-radius:16px;
  background:#080b0a;border:1px solid rgba(255,255,255,.07);
  transition:transform .28s var(--ease),box-shadow .28s var(--ease),border-color .28s;
}
.ggc-fcard.clickable{cursor:pointer}
.ggc-fcard:hover{transform:translateY(-3px);border-color:rgba(255,255,255,.14);box-shadow:0 14px 34px rgba(0,0,0,.5)}
.ggc-fluid{position:absolute;inset:-18%;filter:blur(30px);opacity:.82}
.ggc-fluid i{position:absolute;border-radius:50%;animation:ggcBlob 22s ease-in-out infinite alternate;will-change:transform}
.ggc-fluid i:nth-child(2){animation-duration:27s;animation-delay:-6s}
.ggc-fluid i:nth-child(3){animation-duration:19s;animation-delay:-12s}
@keyframes ggcBlob{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(9%,-11%,0) scale(1.22)}}
.ggc-shade{position:absolute;inset:0;background:linear-gradient(168deg,rgba(0,0,0,.18),rgba(0,0,0,.52))}
.ggc-sheen{position:absolute;inset:0;background:linear-gradient(158deg,rgba(255,255,255,.08),rgba(255,255,255,0) 44%)}
.ggc-body{position:absolute;inset:0;display:flex;flex-direction:column;padding:15px 17px}
.ggc-cap{
  font-family:var(--font-mono,'JetBrains Mono',Consolas,monospace);font-size:9.5px;
  letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.72);
}
.ggc-name{font-size:14.5px;font-weight:700;color:#fff;margin-top:7px}
.ggc-val{display:flex;align-items:baseline;gap:7px;margin-top:auto}
.ggc-val b{
  font-family:var(--font-mono,'JetBrains Mono',Consolas,monospace);font-size:34px;font-weight:400;
  letter-spacing:-.02em;color:#fff;font-feature-settings:'tnum' 1;
}
.ggc-val span{font-size:11.5px;color:rgba(255,255,255,.72)}
.ggc-note{display:flex;gap:6px;margin-top:8px;font-size:10.5px;color:rgba(255,255,255,.6)}
.ggc-note b{font-weight:600}
.tone-up{color:hsl(var(--gg-h,161),80%,62%)}
.tone-warn{color:#ffb457}
.tone-risk{color:#ff8f6b}

/* ---------- 4. 组件② 3D 项目卡环（.ggc-ring，任意皮肤可用） ---------- */
.ggc-ring-wrap{position:relative;border-radius:16px;background:#050807;border:1px solid rgba(255,255,255,.06)}
.ggc-ring{position:absolute;inset:0;perspective:1100px}
.ggc-rcard{
  position:absolute;left:50%;top:50%;cursor:pointer;border-radius:13px;
  background:linear-gradient(160deg,#f2f6f3,#d3dbd6);box-shadow:0 18px 34px -18px rgba(0,0,0,.9);
  padding:13px 14px;display:flex;flex-direction:column;overflow:hidden;
  transition:transform .55s cubic-bezier(.4,0,.2,1),width .55s cubic-bezier(.4,0,.2,1),
    height .55s cubic-bezier(.4,0,.2,1),opacity .45s,box-shadow .55s;
  will-change:transform;outline:none;
}
.ggc-rcard .rid{font-family:var(--font-mono,'JetBrains Mono',Consolas,monospace);font-size:7.5px;color:rgba(20,32,26,.45)}
.ggc-rcard .nm{font-size:12px;font-weight:700;color:rgba(16,26,21,.88);margin-top:8px;word-break:break-all;line-height:1.3}
.ggc-rcard .meta{font-family:var(--font-mono,'JetBrains Mono',Consolas,monospace);font-size:8.5px;color:rgba(20,32,26,.55);margin-top:6px}
.ggc-rcard .note2{font-size:9px;line-height:1.5;color:rgba(20,32,26,.5);margin-top:auto;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ggc-rcard .when2{font-family:var(--font-mono,'JetBrains Mono',Consolas,monospace);font-size:8px;color:rgba(20,32,26,.4);margin-top:5px}
.ggc-rcard .st{
  display:inline-flex;align-items:center;gap:5px;align-self:flex-start;
  font-family:var(--font-mono,'JetBrains Mono',Consolas,monospace);font-size:8px;
  padding:2.5px 7px;border-radius:5px;background:rgba(20,32,26,.08);color:rgba(20,32,26,.6);margin-top:8px;
}
.ggc-rcard .st i{width:5px;height:5px;border-radius:99px;background:rgba(20,32,26,.35)}
.ggc-rcard .st i.live{background:#0ac98c;box-shadow:0 0 7px rgba(10,201,140,.8)}
.ggc-rcard .openbtn{display:none;align-items:center;justify-content:center;gap:6px;margin-top:9px;
  padding:7px 0;border-radius:999px;background:rgba(4,32,20,.32);color:#eafff5;font-size:10px;font-weight:600}
.ggc-rcard.focus{width:178px;height:206px;z-index:5;transform:translate(-50%,-50%);border-radius:15px;padding:15px 16px;
  background:linear-gradient(155deg,hsl(var(--gg-h,161),75%,62%),hsl(var(--gg-h,161),85%,36%));
  box-shadow:0 0 44px -6px hsla(var(--gg-h,161),90%,45%,.55),0 22px 44px -20px rgba(0,0,0,.95)}
.ggc-rcard.focus .rid{font-size:8.5px;color:rgba(255,255,255,.7)}
.ggc-rcard.focus .nm{font-size:14.5px;color:#fff;margin-top:9px}
.ggc-rcard.focus .meta{font-size:9.5px;color:rgba(255,255,255,.8);margin-top:7px}
.ggc-rcard.focus .note2{font-size:10px;color:rgba(255,255,255,.72)}
.ggc-rcard.focus .when2{font-size:8.5px;color:rgba(255,255,255,.55)}
.ggc-rcard.focus .st{background:rgba(4,32,20,.28);color:#eafff5;font-size:8.5px}
.ggc-rcard.focus .st i{background:#b8ffe0;box-shadow:0 0 7px rgba(184,255,224,.9)}
.ggc-rcard.focus .openbtn{display:flex}
.ggc-rcard.l1,.ggc-rcard.r1{width:138px;height:168px;z-index:4}
.ggc-rcard.l1{transform:translate(calc(-50% - 136px),-50%) rotateY(26deg) scale(.96)}
.ggc-rcard.r1{transform:translate(calc(-50% + 136px),-50%) rotateY(-26deg) scale(.96)}
.ggc-rcard.l2,.ggc-rcard.r2{width:110px;height:142px;z-index:3;opacity:.88}
.ggc-rcard.l2{transform:translate(calc(-50% - 238px),-50%) rotateY(34deg) scale(.9)}
.ggc-rcard.r2{transform:translate(calc(-50% + 238px),-50%) rotateY(-34deg) scale(.9)}
.ggc-rcard.l2 .note2,.ggc-rcard.r2 .note2,.ggc-rcard.l2 .when2,.ggc-rcard.r2 .when2{display:none}
.ggc-rcard.hidden2{opacity:0;pointer-events:none;transform:translate(-50%,-50%) scale(.4);z-index:1}
.ggc-rcard:focus-visible{box-shadow:0 0 0 2px hsla(var(--gg-h,161),90%,55%,.7)}

/* ---------- 5. 示例页（#/glass） ---------- */
.gg-head{margin:4px 0 18px}
.gg-title{font-size:24px;font-weight:700;letter-spacing:-.015em}
.gg-sub{margin-top:8px;font-size:12.5px;line-height:1.65;color:var(--text-2);max-width:760px}
.gg-sec{margin:22px 0 12px}
.gg-st{font-size:14.5px;font-weight:700}
.gg-code{
  font-family:var(--font-mono,'JetBrains Mono',Consolas,monospace);font-size:11.5px;line-height:1.7;
  background:var(--surface-2);border:1px solid var(--border-2);border-radius:12px;
  padding:15px 17px;overflow:auto;white-space:pre;color:var(--text-2);
}
.gg-foot{margin-top:20px;font-size:11px;color:var(--muted)}

/* ---------- 6. 响应式与降级 ---------- */
@media (max-width:900px){
  .ggc-rcard.l1{transform:translate(calc(-50% - 92px),-50%) rotateY(26deg) scale(.96)}
  .ggc-rcard.r1{transform:translate(calc(-50% + 92px),-50%) rotateY(-26deg) scale(.96)}
  .ggc-rcard.l2,.ggc-rcard.r2{transform:translate(-50%,-50%) scale(.5);opacity:0;pointer-events:none}
  .ggc-frow{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
  .ggc-fcard{height:124px}
  .ggc-val b{font-size:26px}
}
@media (prefers-reduced-motion:reduce){
  .ggc-fluid i,.ggc-fcard,.ggc-rcard{animation:none!important;transition:none!important}
  [data-skin="greenglass"] .dm-stat::before,[data-skin="greenglass"] .card.kpi::before{animation:none!important}
}

/* ============================================================
 * v1.7.9 待办完成时间 · 查看全部弹窗 · 地图视角控制
 * ============================================================ */
/* 「还有 N 项」可点击 */
.dm-more{cursor:pointer;transition:color .2s var(--ease)}
.dm-more:hover{color:var(--blue)}
/* 查看全部弹窗 */
.dm-all-wrap{max-height:62vh;overflow:auto;padding:2px}
.dm-all-clone{max-height:none!important;overflow:visible!important}
/* 地图视角控制按钮（badge 下方竖排，pointer-events 打开） */
.dm-map .map-ctrls{position:absolute;right:8px;top:38px;display:flex;flex-direction:column;gap:6px;z-index:700}
.dm-map .map-ctrls button{
  pointer-events:auto;border:1px solid rgba(255,255,255,.32);background:rgba(0,0,0,.46);color:#fff;
  font-size:11px;font-weight:600;padding:3px 10px;border-radius:8px;cursor:pointer;
  backdrop-filter:blur(6px);transition:background .2s,transform .2s;
}
.dm-map .map-ctrls button:hover{background:rgba(0,0,0,.68);transform:translateX(-1px)}

/* ================= v1.8.1 组件演示页 / 菜单合并补充样式 ================= */
.ck-btn{
  width:24px;height:24px;flex:0 0 auto;border:1.5px solid var(--border-2);border-radius:8px;
  background:var(--surface);color:var(--blue);font-size:14px;line-height:1;cursor:pointer;
  display:grid;place-items:center;transition:all .18s ease;padding:0
}
.ck-btn:hover:not(:disabled){border-color:var(--blue);background:var(--blue-soft);transform:scale(1.06)}
.ck-btn:disabled{opacity:.45;cursor:not-allowed}
.sb-hidden-g{
  font-style:normal;font-size:10.5px;color:var(--muted);margin-left:6px;
  padding:1px 6px;border-radius:6px;background:var(--surface-3);white-space:nowrap
}
[data-demo] .sec-hd h2{font-size:15px}

/* v1.9.101：台账 / 记录页里「点姓名看个人信息」的姓名（与驾驶舱里可点的姓名同一套观感） */
.lb-nm{cursor:pointer;transition:color .15s}
.lb-nm:hover{color:var(--blue);text-decoration:underline;text-underline-offset:3px}
/* ---------- v1.9.101 台账看板的「快捷筛选行」（表格上方，右键自定义） ---------- */
.qf-bar{
  display:flex;align-items:center;gap:6px;flex-wrap:wrap;
  margin:0 0 10px;padding:8px 10px;border-radius:12px;
  background:var(--g-2);border:1px solid var(--g-line)
}
.qf-bar .qf-t{font-size:11px;letter-spacing:.5px;color:var(--muted);margin-right:2px}
.qf-chip{
  font:inherit;font-size:12px;line-height:1.6;color:var(--text);
  padding:4px 11px;border-radius:999px;cursor:pointer;
  background:var(--g-1);border:1px solid var(--g-line);transition:all .16s
}
.qf-chip:hover{border-color:color-mix(in srgb,var(--blue) 45%,transparent);color:var(--blue)}
.qf-chip.on{background:var(--blue-soft);border-color:var(--blue);color:var(--blue);font-weight:600}
.qf-chip.bad{opacity:.62;border-style:dashed}
.qf-chip.add{padding:4px 10px;color:var(--muted)}
.qf-chip.clear{color:var(--muted)}
.qf-menu{
  display:none;position:fixed;z-index:9999;min-width:150px;padding:5px;
  background:var(--g-3);border:1px solid var(--g-line);border-radius:11px;
  box-shadow:0 10px 30px rgba(0,0,0,.16);backdrop-filter:blur(18px)
}
.qf-menu button{
  display:block;width:100%;text-align:left;font:inherit;font-size:12.5px;
  padding:7px 10px;border:0;border-radius:8px;background:none;color:var(--text);cursor:pointer
}
.qf-menu button:hover{background:var(--blue-soft);color:var(--blue)}
.qf-menu button.danger{color:var(--red,#e0342b)}
.qf-menu button.danger:hover{background:color-mix(in srgb,var(--red,#e0342b) 12%,transparent)}
.qf-menu-sep{height:1px;background:var(--g-line);margin:5px 4px}
/* ---------- v1.9.1 底部入口（登录页底部 / 左侧菜单底部） ---------- */
.login-links{
  margin-top:16px;display:flex;gap:4px;justify-content:center;flex-wrap:wrap;
  padding-top:12px;border-top:1px solid var(--border)
}
.login-links a{
  display:inline-flex;align-items:center;gap:5px;font-size:12.5px;color:var(--muted);
  text-decoration:none;padding:5px 10px;border-radius:999px;transition:all .18s
}
.login-links a:hover{color:var(--blue);background:var(--blue-soft)}
.sb-links{
  display:flex;align-items:center;gap:4px;flex-wrap:wrap;
  padding:7px 12px;border-top:1px solid var(--border)
}
.sb-links a{
  display:inline-flex;align-items:center;gap:5px;font-size:11.5px;color:var(--muted);
  text-decoration:none;padding:4px 9px;border-radius:999px;transition:all .18s
}
.sb-links a:hover{color:var(--blue);background:var(--blue-soft)}
.sb-links .lk-t{font-size:10px;letter-spacing:.5px;color:var(--muted);opacity:.7;margin-right:2px}
/* 方案列表固定 / 锁定按钮（与台账卡片一致的图标按钮） */
.db-lock{opacity:.35}
.db-lock.on{opacity:1;color:var(--blue)}
/* v1.9.6：方案「置顶为首页」按钮 + 左侧菜单 🏠 徽标 */
.db-home{opacity:.45}
.db-home.on{opacity:1;color:var(--blue)}
.nav-badge.nav-home{background:var(--blue-soft);color:var(--blue);font-size:10px;padding:1px 4px}

/* ============================================================
   Liquid Glass v1.9.16 —— 苹果液态玻璃拟态升级
   来源参考：fu-liquiglass-skill + Liquid-Glass-Vue + 介绍页已落地系统
   材质：半透明磨砂 + 背景模糊/饱和 + 方向性边缘高光 + 内阴影厚度
   折射：缓慢流动的彩色极光（可被玻璃 backdrop-filter 折射）
   层级：L1 极光背光 → L2 卡片 → L3 导航/浮层 → L4 控件
   动效：hover 抬升 + 指针跟随高光；响应式 + 明暗 + 降级适配
   ============================================================ */
:root{
  /* 方向性边缘高光（左上强→右下弱），构成玻璃“棱” */
  --g-hi-grad:linear-gradient(150deg,
      rgba(255,255,255,.95) 0%,
      rgba(255,255,255,.30) 24%,
      rgba(255,255,255,0) 52%,
      rgba(255,255,255,.32) 100%);
  /* 内阴影厚度：玻璃的厚度与立体感 */
  --g-inner:
      inset 0 1px 0 rgba(255,255,255,.92),
      inset 0 -1px 0 rgba(255,255,255,.34),
      inset 1px 0 0 rgba(255,255,255,.30),
      inset -1px 0 0 rgba(255,255,255,.12);
  --g-spot:rgba(255,255,255,.50);      /* 指针跟随高光 */
  --g-ring:0 0 0 3px rgba(0,113,227,.45);
}
[data-theme="dark"]{
  --g-hi-grad:linear-gradient(150deg,
      rgba(255,255,255,.34) 0%,
      rgba(255,255,255,.09) 24%,
      rgba(255,255,255,0) 52%,
      rgba(255,255,255,.11) 100%);
  --g-inner:
      inset 0 1px 0 rgba(255,255,255,.26),
      inset 0 -1px 0 rgba(255,255,255,.05),
      inset 1px 0 0 rgba(255,255,255,.11),
      inset -1px 0 0 rgba(255,255,255,.04);
  --g-spot:rgba(255,255,255,.18);
  --g-ring:0 0 0 3px rgba(10,132,255,.55);
}

/* —— 折射背光：缓慢流动的极光，给玻璃提供可折射的彩色底色 —— */
.app-aurora{
  position:fixed; inset:-25%; z-index:-3; pointer-events:none;
  background:
    radial-gradient(48% 42% at 18% 22%, rgba(0,113,227,.34), transparent 60%),
    radial-gradient(46% 40% at 82% 18%, rgba(123,92,255,.30), transparent 62%),
    radial-gradient(50% 46% at 70% 82%, rgba(35,133,76,.24), transparent 60%),
    radial-gradient(44% 40% at 28% 78%, rgba(10,161,176,.22), transparent 62%);
  filter:saturate(135%) blur(40px) url(#lg-refract);
  animation:aurora 26s ease-in-out infinite alternate;
  opacity:.9;
}
html[data-theme="dark"] .app-aurora{opacity:1}
@keyframes aurora{
  0%{transform:translate3d(0,0,0) scale(1)}
  50%{transform:translate3d(2%,-2%,0) scale(1.06)}
  100%{transform:translate3d(-2%,2%,0) scale(1.03)}
}

/* —— 方向性边缘高光（液态玻璃“棱”） ——
   ⚠ 此处只给「未定位」的元素补 position:relative，作为 ::before 的定位参照。
   绝不可把已明确 fixed 的成员列进来：.sidebar（移动端 fixed）、.ctx-menu（fixed）、
   #diy-fab / #diy-drawer（fixed）。同权重且后出现的声明会把它们的 fixed 覆盖成
   relative —— 结果是右键菜单进入文档流、跑到页面最底部（视口外，等于"什么也不显示"），
   悬浮按钮/参数抽屉同理错位。v1.9.27 修复。 */
.lg-edge, .topbar, .card, .modal, .login-card, .glass, .glass-2, .seg{ position:relative; }
/* v1.9.27 定位守护：显式钉住下列元素，防止被上方通用规则改写定位 */
.ctx-menu{ position:fixed; }
#diy-fab, #diy-drawer{ position:fixed; }
@media (max-width:1100px){ .sidebar{ position:fixed; } }
.lg-edge::before,
.sidebar::before, .topbar::before, .card::before, .modal::before,
.ctx-menu::before, .login-card::before, .glass::before, .glass-2::before,
.seg::before, #diy-fab::before, #diy-drawer::before{
  content:''; position:absolute; inset:0; padding:1px; border-radius:inherit;
  background:var(--g-hi-grad);
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
  pointer-events:none; z-index:2;
}
/* —— 内阴影厚度 —— */
.sidebar, .topbar, .card, .modal, .ctx-menu, .login-card, .glass, .glass-2{
  box-shadow:var(--g-shadow), var(--g-inner);
}
/* —— 指针跟随高光 ——
   v1.9.60：用户要求「全局的鼠标悬浮光晕去掉」，于是整层停用。
   做法是**保留选择器、只把 `content` 去掉**（而不是删规则）：
   一来 `:hover` 规则与 prefers-reduced-motion / forced-colors 里对它的引用都还成立，不会连带报错；
   二来将来想恢复只需把 content 加回来，不用重推一遍定位与层级。
   ⚠️ 别顺手删 `.lg-spec::after` 这组：它是「棱」（::before 边缘高光）的姊妹层，
   删掉会造成同名伪元素在别处的引用悬空。 */
.lg-spec::after,
.sidebar::after, .topbar::after, .card::after, .modal::after,
.login-card::after, .glass::after, .glass-2::after{
  content:none;
}
.lg-spec:hover::after,
.sidebar:hover::after, .topbar:hover::after, .card:hover::after,
.modal:hover::after, .login-card:hover::after, .glass:hover::after, .glass-2:hover::after{ opacity:1; }

/* —— 键盘焦点：液态光环 —— */
.sidebar:focus-visible, .topbar:focus-visible, .card:focus-visible,
.modal:focus-visible, .login-card:focus-visible,
.btn:focus-visible, .nav-item:focus-visible, .input:focus-visible, .icon-btn:focus-visible{
  outline:none; box-shadow:var(--g-ring), var(--g-shadow), var(--g-inner);
}

/* —— 卡片 / 浮层 hover 抬升（克制） —— */
.card.hoverable{ transition:transform .25s var(--ease), box-shadow .3s var(--ease), background .2s; }
.card.hoverable:hover{ transform:translateY(-4px); box-shadow:var(--g-shadow-2), var(--g-inner); }
.modal{ transition:box-shadow .3s var(--ease); }

/* —— 降级：不支持 backdrop-filter 时退回实色，关闭极光，保可读性 —— */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  /* ⚠️ v1.9.118：`.sb-pins` 是 background:transparent（透出 .sidebar 的玻璃底）。
     这里 .sidebar 退回实色 --surface 后，透明段自然跟着变成 --surface，颜色仍一致 ——
     但别把 .sb-pins 也塞进这个 `!important` 列表：它当前没问题，写进来只是冗余；
     真要改的是「别给 .sb-pins 单独写死颜色」这条（见文件上方 .sb-pins 注释）。 */
  .sidebar, .topbar, .card, .modal, .ctx-menu, .login-card, .glass, .glass-2,
  .input, select.input, textarea.input, .btn, .btn.ghost{
    background:var(--surface) !important;
  }
  .app-aurora{ display:none; }
}
/* —— 减少动态效果 —— */
@media (prefers-reduced-motion: reduce){
  .app-aurora{ animation:none; }
  .lg-spec::after, .sidebar::after, .topbar::after, .card::after,
  .modal::after, .login-card::after, .glass::after, .glass-2::after{ transition:none; }
  .card.hoverable:hover{ transform:none; }
}
/* —— 强制颜色模式：去掉装饰性高光与极光 —— */
@media (forced-colors: active){
  .lg-edge::before, .sidebar::before, .topbar::before, .card::before, .modal::before,
  .ctx-menu::before, .login-card::before, .glass::before, .glass-2::before,
  .seg::before, #diy-fab::before, #diy-drawer::before,
  .lg-spec::after, .sidebar::after, .topbar::after, .card::after, .modal::after,
  .login-card::after, .glass::after, .glass-2::after, .app-aurora{ display:none; }
}
/* —— 移动端：降模糊与饱和，去掉折射滤镜以保性能 —— */
@media (max-width:680px){
  .app-aurora{ filter:saturate(120%) blur(30px); }
  :root{ --blur:16px; --sat:150%; }
}

/* v1.9.17 patch：深色模式下卡片填充略不透明，提升玻璃面文字对比度 */
/* v1.9.62：.72 → .86，同上（与 .dm 的暗色面保持一致，否则暗色下卡片同样「看不出面」） */
[data-theme="dark"] .card{background:color-mix(in srgb, #1c1c24 86%, transparent)}

/* ==========================================================================
   v1.9.30 按钮收纳：「更多 ▾」下拉（全站通用）
   顶栏 / 驾驶舱工具条 / 看板工具条 / 数据表格工具条只保留少量重要按钮，
   其余统一收进本下拉，降低视觉噪声。
   注意：这里的定位规则放在文件最末，且显式声明 position:relative，
   避免被上方通用定位规则改写（历史踩坑：通用 position:relative 覆盖 fixed）。
   ========================================================================== */
.act-more{ position:relative; display:inline-flex; align-items:center; flex:0 0 auto; }
.topbar .act-more{ position:relative; }
.act-more > .act-more-btn{ position:relative; z-index:1; }
.act-more-btn .tb-caret{ margin-left:5px; font-size:10px; line-height:1; opacity:.7; transition:transform .18s var(--ease, ease) }
.act-more.open > .act-more-btn .tb-caret{ transform:rotate(180deg) }
.act-more > .act-more-btn.on{ background:var(--blue-soft); color:var(--blue); border-color:transparent }

.act-more > .act-menu{
  position:absolute; top:calc(100% + 7px); right:0; z-index:120;
  min-width:172px; max-width:min(80vw, 320px);
  padding:6px; border-radius:14px;
  background:var(--surface, #fff);
  border:1px solid var(--border);
  box-shadow:0 14px 40px rgba(12,20,40,.18), 0 2px 8px rgba(12,20,40,.08);
  display:none; flex-direction:column; gap:2px;
}
.act-more.open > .act-menu{ display:flex; }
.act-more > .act-menu[hidden]{ display:none; }
.act-menu > .btn, .act-menu > .tbtn, .act-menu > .act-group > .btn, .act-menu > .act-group > .tbtn{
  width:100%; justify-content:flex-start; text-align:left;
  height:34px; padding:0 11px; border-radius:10px; font-weight:550;
  background:transparent; border-color:transparent; box-shadow:none;
}
.act-menu > .btn:hover, .act-menu > .tbtn:hover,
.act-menu > .act-group > .btn:hover, .act-menu > .act-group > .tbtn:hover{ background:var(--fill, rgba(0,0,0,.05)) }
.act-menu .btn.danger, .act-menu .tbtn.danger{ color:var(--red) }
.act-group{ display:flex; flex-direction:column; gap:2px; }
.act-sep{ height:1px; margin:5px 8px; background:var(--border) }
[data-theme="dark"] .act-more > .act-menu{ background:#1c1c24; border-color:rgba(255,255,255,.12) }
[data-theme="dark"] .act-menu > .btn:hover, [data-theme="dark"] .act-menu > .tbtn:hover,
[data-theme="dark"] .act-menu > .act-group > .btn:hover, [data-theme="dark"] .act-menu > .act-group > .tbtn:hover{ background:rgba(255,255,255,.08) }
/* 表格工具条的「更多」里元素类型更杂：统一成整行块 */
.dt-bar .act-menu > *{ width:100% }
.dt-bar .act-menu .dt-count{ padding:4px 11px }
.dt-bar .act-menu .seg{ align-self:stretch; width:100%; margin:2px 0 }
.dt-bar .act-menu .seg > button{ flex:1 }
.toast.warn{ background:color-mix(in srgb, var(--amber, #f0a500) 92%, transparent) }

/* v1.9.30 模块标题去重：计数类模块（KPI / 条件计数 / 仪表）左上角不再重复标题与图标，
   标题与图标只在模块中部出现；含峰谷波浪的图表模块保持原样（标题仍在左上角）。
   类名 dm-cnt 而不是 dm-count：后者是「计数」模块内层容器的类名（1870 行有一组
   display:flex / gap / justify-content 规则），复用会让整张卡片被误伤。 */
.dm.dm-cnt > .dm-hd > .dm-t,
.dm.dm-cnt > .dm-hd > .dm-badge{ display:none }
.dm.dm-cnt > .dm-hd{ justify-content:flex-end; min-height:0 }
/* 无编辑权限时头部只剩空壳，连 9px 的下边距一起去掉（:has 不支持时退化为空行，不影响功能） */
.dm.dm-cnt > .dm-hd:not(:has(.dm-op)){ display:none }

/* ==========================================================================
   v1.9.30 图标风格统一：彩色图标底 → 单色线稿
   仅作用于「图标容器」本身（底 + 描边色），折线 / 柱状 / 饼图等
   数据可视化色板属于数据语义，不在此列。
   ========================================================================== */
.kpi-ic, .dm-kpi-ic, .dm-list-i .av, .dm-rank-row .av, .rank-badge,
.kpi-head .kpi-ic, .gm-birth .av, .ico-chip, .icon-chip{
  background:color-mix(in srgb, var(--text) 8%, transparent) !important;
  color:var(--text) !important;
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--text) 12%, transparent) !important;
}
.dm-kpi-ic svg, .dm-list-i .av svg, .kpi-ic svg{ stroke:currentColor }

/* ==========================================================================
   v1.9.31 UI 细节打磨
   1) 彩色状态标签（chip）文字对比度不足：11.5px 小字需 WCAG AA 4.5。
      亮色主题：浅底上加深文字（color-mix 掺黑）；暗色主题：深底上提亮文字（掺白）。
      只改 color，不动背景/尺寸/圆角，观感与层级保持不变。
   2) 表格工具条与顶栏按钮在触屏下的最小高度已在上方 @media 处理。
   ========================================================================== */
.chip.green{ color:color-mix(in srgb, var(--green) 75%, #000) }
.chip.blue{ color:color-mix(in srgb, var(--blue) 78%, #000) }
.chip.amber{ color:color-mix(in srgb, var(--amber) 60%, #000) }
.chip.red{ color:color-mix(in srgb, var(--red) 78%, #000) }
.chip.purple{ color:color-mix(in srgb, var(--purple) 76%, #000) }
[data-theme="dark"] .chip.green{ color:color-mix(in srgb, var(--green) 42%, #fff) }
[data-theme="dark"] .chip.blue{ color:color-mix(in srgb, var(--blue) 62%, #fff) }
[data-theme="dark"] .chip.amber{ color:color-mix(in srgb, var(--amber) 88%, #fff) }
[data-theme="dark"] .chip.red{ color:color-mix(in srgb, var(--red) 52%, #fff) }
[data-theme="dark"] .chip.purple{ color:color-mix(in srgb, var(--purple) 58%, #fff) }
/* chip 默认（无彩色类）用的是 --text-2，本来就达标；仅补 hover 态的可读性兜底 */
.chip:hover{ color:var(--text) }

/* 3) 键盘焦点环补齐：.btn / .nav-item / .icon-btn / .input 走液态玻璃光环（见上方 --g-ring），
   但 .sb-gop / .nav-hide / .dm-op / .sb-group / 表格复选框 / 链接 这些只有浏览器默认轮廓，
   与整体风格不一致、且在密集小按钮上不易辨认。统一补成主题色实心环。 */
.sb-group:focus-visible,
.sb-gop:focus-visible,
.nav-hide:focus-visible,
.dm-op:focus-visible,
.seg > button:focus-visible,
.pill-tabs .p:focus-visible,
table.tb input[type="checkbox"]:focus-visible,
a:focus-visible{
  outline:2px solid var(--blue);
  outline-offset:2px;
}

/* 4) 驾驶舱调色板「文字色」达标修正。
   COLOR_VAL 的蓝/绿/黄/紫/青/红 同时被当作色块与折线的填充色（数据语义，保持不动），
   但也被直接当文字色用（KPI 大数字、图标、头像首字）。在白/浅底上实测对比度：
     蓝 4.70 ✓   绿 4.64 ✓   黄 2.08 ✗   紫 4.36 ✗   青 3.12 ✗   红 4.47 ✗
   这里只针对「内联 color: 就是该色」的文字元素，在浅色主题下压深到 ink 变体；
   暗色主题下深底浅字本来就达标，维持原色。 */
:root{ --amber-ink:#9a6400; --cyan-ink:#0a7c87; --purple-ink:#5b3fd6; --red-ink:#c22a22 }
.dm-rank-row .rk.top{ color:var(--amber-ink) }
[data-theme="dark"] .dm-rank-row .rk.top{ color:var(--amber) }

:root:not([data-theme="dark"]) .dm-kpi-val[style*="color:#f0a500"],
:root:not([data-theme="dark"]) .dm-kpi-ic[style*="color:#f0a500"],
:root:not([data-theme="dark"]) .av[style*="color:#f0a500"]{ color:var(--amber-ink) !important }

:root:not([data-theme="dark"]) .dm-kpi-val[style*="color:#0aa1b0"],
:root:not([data-theme="dark"]) .dm-kpi-ic[style*="color:#0aa1b0"],
:root:not([data-theme="dark"]) .av[style*="color:#0aa1b0"]{ color:var(--cyan-ink) !important }

:root:not([data-theme="dark"]) .dm-kpi-val[style*="color:#7b5cff"],
:root:not([data-theme="dark"]) .dm-kpi-ic[style*="color:#7b5cff"],
:root:not([data-theme="dark"]) .av[style*="color:#7b5cff"]{ color:var(--purple-ink) !important }

:root:not([data-theme="dark"]) .dm-kpi-val[style*="color:#e0342b"],
:root:not([data-theme="dark"]) .dm-kpi-ic[style*="color:#e0342b"],
:root:not([data-theme="dark"]) .av[style*="color:#e0342b"]{ color:var(--red-ink) !important }

/* ==========================================================================
   v1.9.33 修复：KPI 卡片的迷你走势（spark）只显示半截
   现象：2 行高的 KPI 卡里，走势折线只露出上半截，下半截被卡片下缘切掉。
   根因（CDP 实测，非推测）：
     · 居中样式 .dm-bd[data-style="1"] 自带 padding:14px（上下共 28px）；
     · 2 行高卡片 .dm 高 206px → .dm-bd 141px → 内容区只剩 113px；
     · 而 KPI 内容实际需要 124px（图标行 28 + 数值 35 + 环比 18 + 走势 30 + 4 处间距 16）；
     · 多出的 11px 被 .dm-kpi 自身的 overflow:hidden（来自 .dm-bd > * 统一规则）吞掉 →
       dash.js 里「空间不足就隐藏 [data-shrink]」的兜底探测的是 .dm-bd 层级是否溢出，
       永远是 0，于是不会触发降级，走势被硬切一半。
   修法：
     ① 计数类卡片头部本来就没有标题，只剩一个悬停才出现的操作行，
        把 9px 下边距收到 3px、内部间距 4px 收到 2px，把 10px 高度还给内容 ——
        内容 117px 就能放进 121px，走势完整显示；
     ② 走势本身允许 flex 收缩（原来 min-height:auto 会把它顶死在 30px），
        SVG 高度改 100% 跟随容器 —— 即使卡片被拖得更小，也只会变矮，绝不裁切。
   v1.9.35 修正：这两条收紧缩原来挂在 .dm-cnt 上，而 .dm-cnt 被 v1.9.34 的「模块标题去重」
   开关控制 —— 用户一关开关，收紧就失效、走势重新被裁。现改挂 .dm-tight（只由
   「是不是计数卡」决定），与标题显隐彻底解耦。 */
.dm.dm-tight > .dm-hd{ margin-bottom:3px }
.dm.dm-tight > .dm-bd .dm-kpi{ gap:2px }
.dm-kpi-spark{ min-height:0 }

/* --------------------------------------------------------------------------
   v1.9.33 下拉菜单边界自适应（配套 core.js 的 fitMenu）
   ① 左侧空间不足时改为「在按钮右侧展开」——原来固定右对齐（向左展开），内容区
      左边缘的按钮左侧只有二十几个像素，172px 的菜单会越过 .content 的
      overflow-x:hidden 边界被硬裁，看起来「没显示全」；
   ② 下方空间不足时向上翻转；
   ③ 实在放不下则在菜单内部纵向滚动，不再溢出。
   这里比文件末尾「定位守护块」里的默认规则多一个类名，权重更高，靠后生效，
   默认（无附加类）行为完全不变。 */
.act-more > .act-menu{ overflow-y:auto; overscroll-behavior:contain }
/* 浮层态：菜单在展开瞬间被搬到 body 下（见 core.js 的 fitMenu），从而脱离所有
   祖先的 overflow 裁剪（.content 的 overflow-x:hidden、卡片的 overflow:hidden）
   与 backdrop-filter 包含块，定位完全由 JS 按视口计算。
   这里把 .act-more > .act-menu 的视觉规则原样镜像一份，外观零变化。 */
.act-menu-float{
  position:fixed; z-index:3000;
  display:flex; flex-direction:column; gap:2px;
  min-width:172px; max-width:min(80vw, 320px);
  padding:6px; border-radius:14px;
  background:var(--surface, #fff);
  border:1px solid var(--border);
  box-shadow:0 14px 40px rgba(12,20,40,.18), 0 2px 8px rgba(12,20,40,.08);
  overflow-y:auto; overscroll-behavior:contain;
}
.act-menu-float[hidden]{ display:none !important }
[data-theme="dark"] .act-menu-float{ background:#1c1c24; border-color:rgba(255,255,255,.12) }
/* 从数据表格工具条搬出来的菜单：原来靠 `.dt-bar .act-menu` 前缀生效的整行规则在此补齐 */
.act-menu-float[data-from="dt-bar"] > *{ width:100% }
.act-menu-float[data-from="dt-bar"] .dt-count{ padding:4px 11px }
.act-menu-float[data-from="dt-bar"] .seg{ align-self:stretch; width:100%; margin:2px 0 }
.act-menu-float[data-from="dt-bar"] .seg > button{ flex:1 }

/* ==========================================================================
   v1.9.34 台账概览：真实统计卡片
   原来台账详情页顶部的概览区在未创建看板时只显示一句「尚未创建概览看板」的
   提示，没有任何数据。现在改为直接渲染四个**真实指标**（台账记录 / 源表总数 /
   显示字段 / 筛选条件），数据来自本页已加载的源表记录，零额外请求。
   有真实数据时去掉外层虚线占位框（.de-real），让指标卡直接作为内容呈现。
   ========================================================================== */
.dash-embed.de-lazy.de-real{ border:none; background:transparent; padding:0 }
.de-stats{ display:grid; grid-template-columns:repeat(auto-fit, minmax(168px, 1fr)); gap:12px; margin-top:10px }
/* min-height 必须容得下「图标行 + 数值 + 说明」三行（约 107px）：
   .dm-bd 是 overflow:hidden 的，给不够就会被硬裁（v1.9.33 的 KPI 半截就是这么来的） */
.de-stats .de-stat{ min-height:114px; padding:12px 14px }
.de-stats .de-stat .dm-bd{ overflow:visible }
.de-stats .de-stat .dm-kpi-val{ font-size:28px }
.de-stat-hint{ font-size:11.5px; color:var(--muted); margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
@media (max-width:640px){
  .de-stats{ grid-template-columns:repeat(auto-fit, minmax(140px, 1fr)); gap:10px }
  .de-stats .de-stat{ min-height:106px }
  .de-stats .de-stat .dm-kpi-val{ font-size:24px }
}

/* v1.9.34 模块标题去重 — 关闭态还原
   v1.9.30 起计数类模块（KPI 数值卡 / 完成率仪表）的左上角标题与图标被隐藏，
   避免与卡片中部的内容重复；现做成可选项：html[data-dm-dedupe="0"] 时把左上角
   标题 + 类型徽标还原回来，与中部内容同时显示。用属性开关实现，切换即时生效。 */
html[data-dm-dedupe="0"] .dm.dm-cnt:not(.dm-fix) > .dm-hd{ justify-content:flex-start; min-height:26px }
html[data-dm-dedupe="0"] .dm.dm-cnt:not(.dm-fix) > .dm-hd > .dm-t,
html[data-dm-dedupe="0"] .dm.dm-cnt:not(.dm-fix) > .dm-hd > .dm-badge{ display:inline-block }
html[data-dm-dedupe="0"] .dm.dm-cnt:not(.dm-fix) > .dm-hd:not(:has(.dm-op)){ display:flex }

/* ==========================================================================
   v1.9.35 模块内容「完整可见」兜底（配套 dash.js 的 fitOverflow 重写）
   现象（用户截图）：多个模块内容被裁 —— 本月生日共 8 人只显示 6 人、KPI 走势只露
   半截、图表下方的说明行不见、长文本被切。根因三类，CSS 侧做结构修正，JS 侧实测降级：
   ①「主区 height:100% + 后置说明行」：主区把高度吃光，后追加的说明必然溢出被裁
     （时段分布 / 星期分布 / 校区雷达 / 矩形树图 / 滚动播报都是这个写法）。
     统一把主区语义改成「占满剩余空间」，说明行不参与伸缩。
     必须 !important —— 模块是把 height:100% 写在行内 style 上的。
   ② 说明行（.dm-more）不参与压缩，避免被挤掉后「有折叠却没提示」。
   ③ 滚动兜底：所有降级都失败时 fitOverflow 给 .dm-bd 加 .dm-bd-scroll，
     用细滚动条代替静默裁切 —— 宁可多一根滚动条，也不能让内容看不见。
   ========================================================================== */
.dm-bd > [style*="height:100%"]{ height:auto!important; flex:1 1 auto; min-height:0 }
.dm-bd > [style*="height: 100%"]{ height:auto!important; flex:1 1 auto; min-height:0 }
.dm-more{ flex:0 0 auto!important; max-height:none!important; overflow:visible!important }
.dm-bd > .small.muted{ flex:0 0 auto; max-height:none; overflow:visible }
.dm-bd.dm-bd-scroll{ overflow-y:auto!important; scrollbar-width:thin; scrollbar-color:var(--border-2) transparent }
.dm-bd.dm-bd-scroll::-webkit-scrollbar{ width:6px; display:block }
.dm-bd.dm-bd-scroll::-webkit-scrollbar-thumb{ background:var(--border-2); border-radius:99px }
.dm-bd.dm-bd-scroll::-webkit-scrollbar-track{ background:transparent }

/* ==========================================================================
   v1.9.35 选择操作栏（.dt-selbar）
   用户要求：表格类的批量编辑，勾选后**从表格上方显示出来**，不要放在下拉菜单里。
   勾选任意记录 → 操作栏在表格上方淡入；清空选择 → 自动收起、不占位置。
   ========================================================================== */
.dt-selbar{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin:0 0 10px;padding:8px 12px;border-radius:12px;
  background:var(--blue-soft);border:1px solid color-mix(in srgb,var(--blue) 26%,transparent);
  animation:dtSelIn .22s var(--ease);
}
.dt-selbar[hidden]{ display:none }
@keyframes dtSelIn{ from{opacity:0;transform:translateY(-4px)} to{opacity:1;transform:none} }
.dt-sel-n{ display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:650;color:var(--blue) }
.dt-sel-n b{ font-size:14px }
.dt-selbar .btn{ margin:0 }
@media (prefers-reduced-motion:reduce){ .dt-selbar{ animation:none } }
@media (max-width:640px){
  .dt-selbar{ gap:6px;padding:8px 10px }
  .dt-selbar .dt-sel-n{ width:100%;margin-bottom:2px }
  .dt-selbar .btn{ flex:1 1 auto;justify-content:center }
}

/* ==========================================================================
   v1.9.35 「主区占满剩余空间」的标准结构类（.dm-fill）
   原来时段分布 / 星期分布 / 雷达 / 矩形树图 / 滚动播报这类模块，都是
   `el.innerHTML = '<div style="width:100%;height:100%">'` 再往后面追加一行说明 ——
   主区把高度吃光，说明行必然溢出被裁（用户看到的「图表下面那行字没了」）。
   ① 语义改为 flex:1（占满剩余空间），说明行自然有位置；
   ② **svg 默认是 display:inline**，行内元素坐在文字基线上，底部会多出一段基线间隙
      （实测正好 6px）—— 这就是「容器莫名溢出 6px」的真凶。
      `.dm-chart svg` 早有 display:block，这些没有 .dm-chart 类名的匿名主区就漏了。
   注意不能对 .dm-bd 全量 svg 生效：模块里还有夹在文字中的小图标 svg（如待办的工具行），
   display:block 会把它们挤成独占一行。
   ========================================================================== */
.dm-bd .dm-fill{ flex:1 1 auto;min-height:0;width:100% }
.dm-bd .dm-fill > svg{ display:block;width:100%;height:100% }
/* 百度地图是第三方 DOM，内部比例尺也是行内 svg，给个 block 消掉那 6px 基线间隙 */
.dm-map svg,.dm-map [class^="BMap_"] svg,.dm-map [class*=" BMap_"] svg{ display:block }

/* v1.9.35 矩形树图格子自适应（配套 dashmods.js treemap）
   格子高度按占比分配，条目一多每格只剩 30 多像素，而「标签+数值」两行至少 44px
   （含 5px 上下内边距）→ 必然被 overflow:hidden 裁掉。按实测高度逐级降级，
   信息不丢（悬浮提示始终带完整名称与占比）。 */
.dm-bd .tm-c{ display:flex;flex-direction:column;justify-content:center }
/* v1.9.35：名称**允许完整换行**（不裁剪）—— 格子高的时候「信息科学与工程学院」这类长名
   要能整行显示完；万一换行后仍然放不下，由 JS 的 needH() 判定降级成单行（tm-one）或色块（tm-min），
   绝不静默裁掉第 3 行。旧的 white-space:nowrap 会把长名一律缩成「信息科…」，
   而改 −webkit-line-clamp:2 只是把「裁两行」换成「裁三行」，本质还是切掉内容、且 offsetHeight
   只报裁剪后的高度、needH 测不出来。 */
.dm-bd .tm-c .tm-l{ word-break:break-word;line-height:1.3 }
/* 树图是密集图表，行距按「能排下」而不是「好看」来定：
   .num 默认行高 1.55（14px → 21.7px）、标签 1.55（11px → 17.05px），
   于是「标签 3 行 + 数值」要 51+22+10 = 83px；收紧到 1.3/1.15 后只要 69px，
   68px 宽的窄列（内容宽 54px，9 字学院名排 3 行）就能用竖排完整显示，
   而不必退化成单行省略号「信息…」。 */
.dm-bd .tm-c .tm-v{ line-height:1.15 }
/* v1.9.35：列向 flex item 默认 flex-shrink:1，单元格偏矮时标签行会被压到 11px（内容 17px）
   → 元素自身 scrollHeight>clientHeight 被判「被裁」。让降级类（tm-one/tm-min）去处理小格，
   标签/数值自身永不被压缩。 */
.dm-bd .tm-c > *{ flex:0 0 auto;min-height:0 }
.dm-bd .tm-c.tm-one{ flex-direction:row;align-items:center;gap:6px }
.dm-bd .tm-c.tm-one .tm-l{ flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis }
.dm-bd .tm-c.tm-one .tm-v{ flex:none;font-size:12px }
.dm-bd .tm-c.tm-min{ padding:0!important }
.dm-bd .tm-c.tm-min > *{ display:none }
/* 单行模式（<44px 的窄格）：垂直内边距收到 1px、行高压到 1.05（消掉字体自带的行距），
   一行文字 ≈ 12px + 2px 内边距 = 14px —— 实测 16px 的格子（1100px 下「回族=2」）也能
   完整显示「回族 2」，不至于退化到只剩色块。原来是 2px/7px + 默认行高（≈21px），
   16px 的格子仍会裁掉 5px。
   水平内边距 6px→4px、间距 6px→4px：树图里少数派那一列可能只有 4% 宽（≈43px），
   要保证「满族 3」这种两字名称 + 一位数字排得下（22+4+7+8=41px）。 */
.dm-bd .tm-c.tm-one{ padding:1px 4px!important;gap:4px }
.dm-bd .tm-c.tm-one .tm-l,.dm-bd .tm-c.tm-one .tm-v{ line-height:1.05 }

/* ===================== v1.9.53 模块骨架（分批渲染期间的占位） =====================
   刻意放在文件末尾：需要靠「同权重、后出现者胜」压过
   `.dm-bd[data-style="1"] > *{justify-content:var(--dm-jc,flex-start)}`，
   否则骨架会被顶到上边、看着像「加载了一半」。 */
.dm-bd > .dm-skel{
  flex:1 1 auto;min-height:0;height:auto;width:100%;overflow:hidden;
  display:flex;flex-direction:column;justify-content:center;gap:9px;
}
.dm-skel i{
  display:block;flex:none;border-radius:6px;
  background:linear-gradient(90deg,var(--surface-3) 25%,var(--surface-2) 37%,var(--surface-3) 63%);
  background-size:400% 100%;animation:shimmer 1.4s infinite;
}
.dm-skel > div{display:flex;min-height:0}
.dm-skel .sk-kpi{flex-direction:column;align-items:center;justify-content:center;gap:8px}
.dm-skel .sk-kpi .sk-big{height:30px;width:52%;border-radius:8px}
.dm-skel .sk-kpi .sk-cap{height:10px;width:34%}
.dm-skel .sk-chart{flex-direction:row;align-items:flex-end;gap:5px;flex:1 1 auto;min-height:26px}
.dm-skel .sk-chart i{flex:1 1 0;min-height:4px}
.dm-skel .sk-rows{flex-direction:column;justify-content:center;gap:10px;flex:1 1 auto}
.dm-skel .sk-rows .sk-row{height:9px;width:100%}
.dm-skel .sk-rows .sk-row:nth-child(2n){width:78%}
.dm-skel .sk-rows .sk-row:nth-child(3n){width:88%}
@media (prefers-reduced-motion:reduce){.dm-skel i{animation:none}}

/* ===================== v1.9.56 重要节点（日历标注 / 待办同步条） ===================== */
.dm-cal i.nd{ box-shadow: inset 0 0 0 2px var(--amber); font-weight: 800 }
.dm-nodes-strip{ display:flex; gap:7px; overflow:hidden; margin-bottom:9px; flex:none }
.dm-nodes-strip .i{
  display:flex; align-items:center; gap:5px; padding:3px 9px; border-radius:99px; max-width:52%;
  background:var(--amber-soft); color:var(--amber); font-size:11.5px; font-weight:650; white-space:nowrap;
}
.dm-nodes-strip .i .num{ font-variant-numeric:tabular-nums }
.dm-nodes-strip .i .t{ overflow:hidden; text-overflow:ellipsis }

/* ===================== v1.9.60 可下拉的输入框（combobox 浮层） =====================
   用途：「类型 / 活动类型」这类「有固定候选、但允许填新值」的字段。
   浮层挂在 body 上（fixed），所以**不要**把它加进任何 `position:relative` 的通用列表；
   z-index 取 4200（高于 .mask 的 200 与 .ctx-menu）。 */
.fx-pop{
  background:var(--surface); border:1px solid var(--border-2); border-radius:var(--r-sm);
  box-shadow:var(--shadow-2); padding:4px; box-sizing:border-box;
  animation:pop .16s var(--ease) both;
}
.fx-opt{
  padding:8px 11px; border-radius:7px; font-size:13.5px; cursor:pointer; line-height:1.35;
  color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.fx-opt:hover{ background:var(--surface-2) }
.fx-opt.on{ background:var(--blue-soft); color:var(--blue); font-weight:650 }
.fx-opt.fx-empty{ color:var(--text-2); cursor:default; font-style:italic }
.fx-opt.fx-empty:hover{ background:transparent }

/* ===== v1.9.67 驾驶舱模块：打卡照片墙 =====
   原来照片墙长在「日常打卡」插件页里，现在变成模块（模块库 → 展示 → 打卡照片墙）。
   插件页那套是固定 150px 高的图片 + 卡片标题，放进模块会撑破卡片，
   所以这里用「自适应网格 + 4:3 缩略图 + 底部一条半透明署名带」的紧凑版式。 */
.dm-pw{display:grid;grid-template-columns:repeat(auto-fill,minmax(86px,1fr));gap:8px;
  height:100%;overflow:hidden;align-content:start;min-width:0}
.dm-pw-i{position:relative;border-radius:11px;overflow:hidden;background:var(--g-3);
  cursor:pointer;aspect-ratio:4/3;min-width:0}
.dm-pw-i img{width:100%;height:100%;object-fit:cover;display:block}
.dm-pw-t{position:absolute;left:0;right:0;bottom:0;padding:4px 7px;font-size:11px;line-height:1.3;
  background:rgba(0,0,0,.5);color:#fff;display:flex;justify-content:space-between;gap:6px;min-width:0}
.dm-pw-t b{font-weight:500;color:#fff;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dm-pw-t .muted{color:#fff;opacity:.82;flex:none}

/* ===== v1.9.67 点学生姓名 → 学生信息弹窗 =====
   姓名做虚线底边 + 变蓝，明确「这里能点」；信息用「字段名 / 值」两列，值列 min-width:0 防长地址溢出。 */
.stu-link{cursor:pointer;border-bottom:1px dashed transparent;
  transition:color .15s var(--ease),border-color .15s var(--ease)}
.stu-link:hover{color:var(--blue);border-bottom-color:var(--blue)}
.stuinfo-row{display:flex;gap:12px;align-items:baseline;padding:7px 0;
  border-bottom:1px solid var(--border);font-size:13px;min-width:0}
.stuinfo-row:last-child{border-bottom:0}
.stuinfo-k{flex:none;width:7.6em;color:var(--muted);font-size:12.5px}
.stuinfo-v{flex:1;min-width:0;color:var(--text);word-break:break-all;line-height:1.6}
.stuinfo-pick{display:flex;align-items:center;gap:8px;padding:5px 4px;font-size:13px;
  cursor:pointer;border-radius:8px}
.stuinfo-pick:hover{background:var(--surface-3)}
.stuinfo-pick input{width:16px;height:16px;accent-color:var(--blue);flex:none}

/* ===== v1.9.68 驾驶舱模块：签到概览 =====
   12 列满宽模块。上半是一行汇总 chip，下半是可滚动的班级表：
   班级 / 应签到 / 已签到 / 未签到 / 未签到名单（姓名可点，点开看详情）。
   表格用 grid 而不是 <table>：列宽固定、数字列右对齐且等宽（tabular-nums），扫读更快。 */
.dm-sign{display:flex;flex-direction:column;gap:8px;height:100%;min-height:0}
.dm-sign-sum{display:flex;gap:6px;align-items:center;flex-wrap:wrap;flex:none}
.dm-sign-tb{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
  border:1px solid var(--border);border-radius:12px;overflow:hidden}
.dm-sign-r{display:grid;grid-template-columns:78px 62px 62px 62px 1fr;align-items:center;
  gap:8px;padding:7px 10px;font-size:12.5px;min-width:0}
.dm-sign-r.hd{background:var(--g-3);color:var(--muted);font-weight:600;font-size:12px;flex:none}
.dm-sign-r>i{font-style:normal;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dm-sign-r>i.num{text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
.dm-sign-r>i.ok{color:var(--green)}
.dm-sign-r>i.bad{color:var(--red)}
.dm-sign-r>b{font-weight:400;min-width:0;display:flex;gap:7px;flex-wrap:wrap;align-items:center}
.dm-sign-bd{flex:1 1 auto;min-height:0;overflow:auto}
.dm-sign-bd .dm-sign-r{border-top:1px solid var(--border)}
.dm-sign-bd .dm-sign-r:first-child{border-top:0}
.dm-sign-nm{cursor:pointer;border-bottom:1px dashed transparent;color:var(--text);
  transition:color .15s var(--ease),border-color .15s var(--ease)}
.dm-sign-nm:hover{color:var(--blue);border-bottom-color:var(--blue)}

/* ===== v1.9.68 未签到人员详情弹窗（三段式） ===== */
.sd-sec{padding:10px 0;border-bottom:1px solid var(--border)}
.sd-sec:last-child{border-bottom:0;padding-bottom:0}
.sd-t{display:flex;align-items:center;gap:8px;font-size:12.5px;font-weight:600;
  color:var(--muted);margin-bottom:6px}
.sd-t .btn{margin-left:auto}
.sd-rec{display:flex;align-items:center;gap:8px;padding:5px 0;font-size:12.5px;min-width:0}
.sd-rec .sd-d{color:var(--text-2);flex:none;font-variant-numeric:tabular-nums}
.sd-rec .sd-tm{color:var(--muted);flex:none;font-variant-numeric:tabular-nums}
.sd-reason{font-size:13px;line-height:1.7;color:var(--text);background:var(--g-3);
  border-radius:10px;padding:8px 11px;white-space:pre-wrap;word-break:break-word}

/* ===== v1.9.69 驾驶舱模块：签到概览（重设计） =====
   旧版是一张朴素的四列表格（数字列、名单挤在最后一格），客户反馈「有点丑」。
   新版改成**每班一块**：班级 + 签到率进度条 + 已签/应签 + 未签徽标，
   下面一行是未签到人员的姓名胶囊（可点看详情）。扫读顺序与人眼的关注点一致：
   先看哪个班缺得多（进度条 + 红色徽标），再看具体是谁。 */
.dm-sign{display:flex;flex-direction:column;gap:9px;height:100%;min-height:0}
.dm-sign-bar{display:flex;align-items:center;gap:8px;flex:none;min-width:0}
.dm-sign-seg{display:inline-flex;background:var(--g-3);border-radius:9px;padding:2px;flex:none}
.dm-sign-seg button{border:0;background:transparent;cursor:pointer;font:inherit;font-size:12px;
  color:var(--muted);padding:3px 11px;border-radius:7px;transition:background .15s var(--ease),color .15s var(--ease)}
.dm-sign-seg button:hover{color:var(--text)}
.dm-sign-seg button.on{background:var(--surface);color:var(--text);font-weight:600;box-shadow:var(--shadow-1,0 1px 2px rgba(0,0,0,.08))}
.dm-sign-day{font-size:12.5px;color:var(--text-2);font-variant-numeric:tabular-nums;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.dm-sign-grow{flex:1 1 auto;min-width:0}
.dm-sign-rt{font-size:12.5px;color:var(--muted);flex:none}
.dm-sign-rt b{color:var(--text);font-variant-numeric:tabular-nums}
.dm-sign-sum{display:flex;gap:6px;align-items:center;flex-wrap:wrap;flex:none}
.dm-sign-list{flex:1 1 auto;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:8px}
.dm-sign-item{border-radius:12px;padding:9px 12px;background:var(--g-2);
  border:1px solid transparent;transition:border-color .15s var(--ease)}
.dm-sign-item:hover{border-color:var(--border-2)}
.dm-sign-item.done{background:transparent;border-color:var(--border)}
.dm-sign-l1{display:flex;align-items:center;gap:11px;min-width:0}
.dm-sign-cls{font-weight:600;font-size:13px;flex:none;min-width:3.4em}
.dm-sign-pb{flex:1 1 auto;min-width:40px;height:6px;border-radius:99px;background:var(--g-3);overflow:hidden}
.dm-sign-pb i{display:block;height:100%;border-radius:99px;background:var(--green)}
.dm-sign-item:not(.done) .dm-sign-pb i{background:var(--blue)}
.dm-sign-pc{flex:none;width:3.1em;text-align:right;font-size:12px;color:var(--muted);
  font-variant-numeric:tabular-nums}
.dm-sign-cn{flex:none;font-size:12.5px;font-variant-numeric:tabular-nums;min-width:3.6em;text-align:right}
.dm-sign-cn b{font-weight:600}
.dm-sign-tag{flex:none;font-size:11.5px;padding:2px 9px;border-radius:99px;min-width:4.8em;text-align:center}
.dm-sign-tag.bad{background:var(--red-soft,rgba(224,52,43,.12));color:var(--red)}
.dm-sign-tag.ok{background:var(--green-soft,rgba(35,133,76,.12));color:var(--green)}
.dm-sign-names{display:flex;gap:7px;flex-wrap:wrap;align-items:center;margin-top:8px}
.dm-sign-nm{cursor:pointer;font-size:12.5px;padding:2px 9px;border-radius:99px;
  background:var(--surface);border:1px solid var(--border);color:var(--text-2);
  transition:color .15s var(--ease),border-color .15s var(--ease),background .15s var(--ease)}
.dm-sign-nm:hover{color:var(--blue);border-color:var(--blue);background:var(--blue-soft)}

/* ===== v1.9.71 驾驶舱模块：名字墙可点 =====
   原来名字只是纯色标签，看不出能点。加悬停反馈（浮起 + 变实心）并统一 cursor。 */
.dm-nmwall{transition:transform .14s var(--ease),filter .14s var(--ease),box-shadow .14s var(--ease)}
.dm-nmwall:hover{transform:translateY(-1px);filter:brightness(.94);box-shadow:0 2px 6px rgba(0,0,0,.12)}
.dm-nmwall:active{transform:translateY(0)}

/* ===================== v1.9.76 参数面板精简：可折叠分区 =====================
   背景：模块参数面板里「显示样式」7 项 + 「筛选条件」常年全展开，把面板塞满，
   用户真正要配的参数（平均 6.9 项）反被淹没。现在这三块收进 <details>：
   显示样式（有自定义时自动展开）/ 筛选条件（有筛选时自动展开）/ 高级选项（有值时才展开）。 */
.dc-fold{margin-top:16px;border-top:1px solid var(--g-line);padding-top:2px}
.dc-fold>summary{display:flex;align-items:center;gap:8px;cursor:pointer;list-style:none;padding:11px 2px;user-select:none;border-radius:9px}
.dc-fold>summary::-webkit-details-marker{display:none}
.dc-fold>summary:hover .dc-fold-t{color:var(--text-1)}
.dc-fold-t{font-size:12.5px;font-weight:660;color:var(--text-2);flex:none}
.dc-fold-h{font-size:11.5px;color:var(--muted);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dc-caret{margin-left:auto;flex:none;color:var(--muted);font-size:15px;line-height:1;transition:transform .22s var(--ease)}
.dc-fold[open] .dc-caret{transform:rotate(90deg)}
.dc-fold-b{padding:2px 0 8px;animation:dcFold .24s var(--ease)}
@keyframes dcFold{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
.dc-fold .dc-f:last-child{margin-bottom:6px}

/* ---------- v1.9.111 · 「品牌外观」上传面板（主背景/打卡头图/离返校头图/收集表头图的背景与 Logo） ---------- */
.sk-brand-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}
.sk-brand-item{display:flex;gap:12px;align-items:flex-start;padding:12px;border:1px solid var(--border);border-radius:14px;background:var(--surface-2);min-width:0}
.sk-brand-prev{flex:none;width:104px;border-radius:10px;overflow:hidden;background:var(--surface-3);border:1px solid var(--border);position:relative;display:grid;place-items:center}
.sk-brand-prev img{width:100%;height:100%;object-fit:cover;display:block}
.sk-brand-def{position:absolute;right:5px;bottom:5px;font-size:10px;padding:1px 6px;border-radius:6px;background:rgba(0,0,0,.5);color:#fff;letter-spacing:.4px}
.sk-brand-info{flex:1;min-width:0}
.sk-brand-t{font-weight:600;font-size:13.5px;margin-bottom:3px}
.sk-brand-st{font-size:12px;color:var(--muted);margin-top:5px}
.sk-brand-act{flex:none;display:flex;flex-direction:column;gap:6px;align-items:stretch}
.sk-brand-act .btn{white-space:nowrap;font-size:12.5px;padding:6px 10px}
.sk-brand-act .btn[disabled]{opacity:.45;cursor:not-allowed}
