/* ============================================================
   LedgerHub · 统一记账台 — 样式表
   拆分自原 index.html(2026-10-02)，CSS 段未做任何改动
   ============================================================ */

/* ============================================================
   1. 设计令牌 (Design Tokens)
   - :root            = 暗色（默认/主设计）
   - [data-theme="light"] = 浅色
   命名前缀：--bg / --surface / --text / --accent / --pos / --c-*
   ============================================================ */
:root{
  color-scheme:dark;
  /* ---- 背景层级：每级保留可感知的明度差，避免「全靠 1px 描边分层」 ---- */
  --bg-void:#05070b;
  --bg-primary:#090b11;
  --bg-elevated:#0e121a;
  --bg-subtle:#131824;
  --bg-hover:#181e2c;
  --bg-active:#202739;
  --bg-inset:#06080d;
  /* 玻璃面 */
  --glass-bg:rgba(10,13,19,.72);
  --glass-bg-strong:rgba(11,14,21,.92);
  --glass-border:rgba(255,255,255,.07);
  --glass-hover:rgba(255,255,255,.055);
  --glass-highlight:rgba(255,255,255,.06);
  /* 描边 */
  --border:#1f2634;
  --border-strong:#333e52;
  --border-soft:rgba(255,255,255,.055);
  /* 文字层级（对比度按 --bg-primary / --bg-subtle / --bg-elevated 三档实测，正文一律 >=4.5:1） */
  --text-primary:#e9edf4;       /* on --bg-primary = 16.3:1 */
  --text-secondary:#a7b1c0;     /* on --bg-primary =  8.9:1 · on --bg-subtle = 7.9:1 */
  --text-muted:#939dab;         /* on --bg-subtle  =  6.3:1（11px 小字仍达标） */
  --text-ghost:#7d8896;         /* on --bg-subtle  =  4.8:1（占位符 / hover 描边） */
  --text-inverse:#0b0e13;
  /* ---- 品牌强调色：与「盈利绿」刻意区分 ----
     改造前 accent 与 --pos 同为 #54d6a0，导致「可点击」与「收入/盈利」共用一种颜色，
     导航高亮、按钮、链接与利润数字无法在语义上区分。现在交互层用蓝，钱用绿。 */
  --accent:#5e8bff;             /* on --bg-primary ≈ 6.8:1 · 偏靛的现代品牌蓝 */
  --accent-hover:#82a6ff;
  --accent-active:#4e7af2;
  --accent-soft:rgba(94,139,255,.15);
  --accent-border:rgba(94,139,255,.38);
  --accent-ink:#081226;
  /* 落在 accent-soft tint 上时专用（tint 底色比纯背景亮，需更亮文字才达标） */
  --accent-on-soft:#9cbcff;     /* nav 选中态 ≈ 8.4:1 */
  --accent-2:#9179ff;           /* 渐变副色：仅品牌标记 / 登录页光晕，不做交互语义 */
  --focus-ring:rgba(94,139,255,.45);
  --selection-bg:rgba(94,139,255,.34);
  /* ---- 主按钮材质令牌（.btn-primary 只写一份规则，两套主题各给一组值）----
     要「淡」不要「重」：按钮不再是整块高饱和实心蓝，而是淡色底 + 深色字。
     顺带解决了白字问题——浅色主题下白字压 #3b5bdb 只有 5.9:1，
     换成深靛字落在淡蓝底上反而 ≈ 7.5:1，更清晰也更轻。 */
  --primary-ink:#081226;                                    /* on --primary-bot ≈ 5.8:1 */
  --primary-top:color-mix(in srgb,var(--accent) 84%,#e8efff);
  --primary-bot:var(--accent);
  --primary-top-h:color-mix(in srgb,var(--accent) 66%,#fff);
  --primary-bot-h:var(--accent-hover);
  --primary-edge:var(--accent-active);
  --primary-hi:rgba(255,255,255,.34);                      /* 顶部 1px 高光（釉面感） */
  --primary-lo:rgba(6,14,32,.14);                           /* 底部内阴影，压住渐变收边 */
  --primary-sheen:rgba(255,255,255,.34);                    /* 掠过的斜向光泽 */
  --primary-ring:0 14px 28px -12px color-mix(in srgb,var(--accent) 58%,transparent);
  --primary-ring-h:0 18px 36px -12px color-mix(in srgb,var(--accent) 70%,transparent);
  --primary-ring-sm:0 8px 16px -8px color-mix(in srgb,var(--accent) 50%,transparent);
  /* ---- 语义色（账务类型与状态专用） ---- */
  --pos:#34d399;          --pos-soft:rgba(52,211,153,.14);   --pos-border:rgba(52,211,153,.32);   --pos-on-soft:#4ade9f;
  --neg:#f87171;          --neg-soft:rgba(248,113,113,.14);  --neg-border:rgba(248,113,113,.32);  --neg-on-soft:#fb8f8f;
  --warn:#fbbf24;         --warn-soft:rgba(251,191,36,.14);  --warn-border:rgba(251,191,36,.30);  --warn-on-soft:#fcc94d;
  --info:#a78bfa;         --info-soft:rgba(167,139,250,.14); --info-border:rgba(167,139,250,.32); --info-on-soft:#b9a3fb;
  --danger:var(--neg);
  /* 间距刻度（4px 基准，8 号位修正为 48 与 40 同栅格） */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-7:32px; --sp-8:40px; --sp-9:48px;
  /* 圆角刻度：整体上调一档，大容器更柔和（2025+ 趋势）
     再整体圆润一档：40px 高的按钮配 20px 圆角（= 一半高度）是「软而不胶囊」的甜点；
     输入框、下拉、面板共用同一刻度，同一行的控件才不会一个方一个圆。 */
  --r-xs:8px; --r-sm:10px; --r-md:13px; --r-lg:20px; --r-xl:24px; --r-2xl:30px; --r-full:999px;
  /* 控件高度：按钮 / 输入框 / 下拉共用同一刻度，保证同一行严格对齐 */
  --ctl-h:40px; --ctl-h-sm:32px; --ctl-h-lg:44px;
  /* 阴影层级：深色主题下阴影要收敛，带蓝黑底色避免「脏灰」，层次主要靠「明度差 + 顶部高光」 */
  --sh-1:0 1px 2px rgba(2,4,10,.5);
  --sh-2:0 1px 2px rgba(2,4,10,.45),0 12px 28px -16px rgba(2,4,10,.75);
  --sh-3:0 16px 40px -14px rgba(2,4,10,.8);
  --sh-4:0 32px 80px -24px rgba(2,4,10,.9);
  --sh-rim:inset 0 1px 0 rgba(255,255,255,.05);
  /* 动效 */
  --dur-1:110ms; --dur-2:170ms; --dur-3:240ms; --dur-4:340ms;
  --ease-out:cubic-bezier(.22,.61,.36,1);
  --ease-inout:cubic-bezier(.4,0,.2,1);
  --ease-spring:cubic-bezier(.34,1.42,.64,1);
  /* 字体：仅系统字体栈，禁止外部字体 */
  --font-sans:system-ui,-apple-system,"Segoe UI Variable Text","Segoe UI",Roboto,"Helvetica Neue","PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans SC",sans-serif;
  --font-mono:ui-monospace,"Cascadia Mono",SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono","Courier New",monospace;
  /* 字号刻度：改造前散布 16 种字号（11/11.5/12/12.5/13/13.5/14…），此处收敛为 9 档 */
  --fs-2xs:11px; --fs-xs:12px; --fs-sm:13px; --fs-base:14px;
  --fs-md:15px; --fs-lg:18px; --fs-xl:22px; --fs-2xl:28px; --fs-3xl:34px;
  --fw-normal:400; --fw-medium:500; --fw-semibold:600; --fw-bold:700;
  /* 字距：中文正文不加负字距（CJK 方块字负字距会挤压字面），仅西文标签用宽字距 */
  --tracking-tight:-.012em; --tracking-caps:.14em;
  /* 布局 */
  --sidebar-w:252px; --topbar-h:64px; --content-max:1560px;
  --z-drawer:60; --z-scrim:55; --z-modal:90; --z-toast:120;
}
[data-theme="light"]{
  color-scheme:light;
  --bg-void:#e9edf4;
  --bg-primary:#f5f7fb;
  --bg-elevated:#ffffff;
  --bg-subtle:#edf1f7;
  --bg-hover:#e6ebf3;
  --bg-active:#dce3ee;
  --bg-inset:#ffffff;
  --glass-bg:rgba(255,255,255,.8);
  --glass-bg-strong:rgba(255,255,255,.95);
  --glass-border:rgba(16,24,40,.08);
  --glass-hover:rgba(16,24,40,.05);
  --glass-highlight:rgba(255,255,255,.9);
  --border:#dbe1ec;
  --border-strong:#c3ccda;
  --border-soft:rgba(16,24,40,.06);
  --text-primary:#0e1420;      /* on --bg-primary ≈ 16.6:1 */
  --text-secondary:#3f4a5e;    /* on --bg-primary ≈  8.1:1 */
  --text-muted:#4e5a6f;        /* on --bg-primary ≈  6.4:1 */
  --text-ghost:#667184;        /* on --bg-subtle  ≈  4.6:1 */
  --text-inverse:#ffffff;
  --accent:#3b5bdb;            /* 纯白底 ≈ 5.9:1 · 靛蓝 */
  --accent-hover:#2f4bc4;
  --accent-active:#2841ad;
  --accent-soft:rgba(59,91,219,.10);
  --accent-border:rgba(59,91,219,.32);
  --accent-ink:#ffffff;
  /* 落在 accent-soft tint 上时用更深的值：在合成底色上 ≈ 7.2:1 */
  --accent-on-soft:#2b46b8;
  --accent-2:#6d3fd1;
  --focus-ring:rgba(59,91,219,.32);
  --selection-bg:rgba(59,91,219,.22);
  /* 浅色下的主按钮：淡蓝渐变底 + 深靛字（≈7.5:1），比「深靛实心 + 白字」轻一个量级，
     高光与投影也一并调淡，避免小按钮上出现塑料感。 */
  --primary-ink:#2a44b5;
  --primary-top:color-mix(in srgb,var(--accent) 8%,#fff);
  --primary-bot:color-mix(in srgb,var(--accent) 18%,#fff);
  --primary-top-h:color-mix(in srgb,var(--accent) 12%,#fff);
  --primary-bot-h:color-mix(in srgb,var(--accent) 26%,#fff);
  --primary-edge:rgba(59,91,219,.34);
  --primary-hi:rgba(255,255,255,.9);
  --primary-lo:color-mix(in srgb,var(--accent) 10%,transparent);
  --primary-sheen:rgba(255,255,255,.55);
  --primary-ring:0 12px 26px -14px color-mix(in srgb,var(--accent) 40%,transparent);
  --primary-ring-h:0 16px 32px -14px color-mix(in srgb,var(--accent) 52%,transparent);
  --primary-ring-sm:0 8px 18px -10px color-mix(in srgb,var(--accent) 38%,transparent);
  --pos:#067a52;          --pos-soft:rgba(6,122,82,.10);    --pos-border:rgba(6,122,82,.28);    --pos-on-soft:#05603f;
  --neg:#b3261e;          --neg-soft:rgba(179,38,30,.08);   --neg-border:rgba(179,38,30,.28);   --neg-on-soft:#a3231b;
  --warn:#8a5a00;         --warn-soft:rgba(138,90,0,.12);   --warn-border:rgba(138,90,0,.28);   --warn-on-soft:#754d00;
  --info:#6d3fd1;         --info-soft:rgba(109,63,209,.09); --info-border:rgba(109,63,209,.26); --info-on-soft:#5f34bd;
  --danger:var(--neg);
  --sh-1:0 1px 2px rgba(16,24,40,.06);
  --sh-2:0 1px 2px rgba(16,24,40,.05),0 12px 28px -18px rgba(16,24,40,.18);
  --sh-3:0 16px 40px -14px rgba(16,24,40,.18);
  --sh-4:0 32px 80px -26px rgba(16,24,40,.28);
  --sh-rim:inset 0 1px 0 rgba(255,255,255,.9);
}
/* 主题切换过渡：仅由 JS 在切换瞬间挂 .theme-anim（约 400ms 后移除），
   避免「给全站每个元素永久挂 240ms 过渡」——那会让 hover 变得迟钝，也让宽表格重绘卡顿。 */
html.theme-anim,
html.theme-anim *,
html.theme-anim *::before,
html.theme-anim *::after{
  transition:background-color var(--dur-3) var(--ease-inout),
             border-color     var(--dur-3) var(--ease-inout),
             color            var(--dur-3) var(--ease-inout),
             fill             var(--dur-3) var(--ease-inout),
             box-shadow       var(--dur-3) var(--ease-inout);
}

/* ============================================================
   2. 基础重置与排版
   ============================================================ */
*,*::before,*::after{box-sizing:border-box}
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;color:var(--text-primary);
  font:var(--fs-base)/1.6 var(--font-sans);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
  /* 环境光：两团极淡的品牌色光晕铺在视口对角，深色下制造「空气感」，
     浅色下几乎不可见 —— 页面不再是纯平色板。色值走令牌，主题切换自动跟随。 */
  background:
    radial-gradient(1080px 580px at 86% -12%,color-mix(in srgb,var(--accent) 7%,transparent) 0,transparent 62%),
    radial-gradient(880px 520px at -10% 110%,color-mix(in srgb,var(--accent-2) 6%,transparent) 0,transparent 58%),
    var(--bg-primary);
}
/* 中文是方块字，负字距会挤压字面：标题只做极小收紧，正文保持 0 */
h1,h2,h3,h4{margin:0;font-weight:var(--fw-semibold);letter-spacing:var(--tracking-tight);line-height:1.28;color:var(--text-primary)}
h1{font-size:var(--fs-2xl)}
h2{font-size:var(--fs-md)}
h3{font-size:var(--fs-base)}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer;background:none;border:0;padding:0;-webkit-tap-highlight-color:transparent}
a{color:var(--accent);text-underline-offset:2px}
:focus{outline:none}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r-xs)}
:/* 输入类控件用「边框 + 光晕」表达焦点，避免再叠一圈 outline 出现双重描边 */
.input:focus-visible,.select:focus-visible,textarea.input:focus-visible{outline:none}
::selection{background:var(--selection-bg);color:var(--text-primary)}
.tnum,.num,.amount,.mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.num-pos{color:var(--pos)}
.num-neg{color:var(--neg)}
.visually-hidden{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.hidden{display:none!important}
input,select,textarea{accent-color:var(--accent)}
::-webkit-scrollbar{width:11px;height:11px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:var(--r-full);border:3px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:var(--text-ghost);border:3px solid transparent;background-clip:content-box}
::-webkit-scrollbar-corner{background:transparent}
*{scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent}

/* ============================================================
   3. 通用组件
   ============================================================ */
/* --- 图标蒙版：用 mask 给按钮加图标，而不是往文字里塞 ↻ ＋ ↓ 这类字形。
   字形图标在不同平台字重/基线不一致（是「界面不精致」最直观的来源），且 setBusy()
   会用 innerHTML 重写按钮内容把内联 SVG 抹掉 —— 伪元素图标不受影响，天然安全。 --- */
:root{
  --i-refresh:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 12a8.5 8.5 0 1 1-2.9-6.4'/%3E%3Cpath d='M20.5 3.6v5h-5'/%3E%3C/svg%3E");
  --i-logout:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.4 4.6H6.8v14.8h7.6'/%3E%3Cpath d='M17.4 8.4 21 12l-3.6 3.6'/%3E%3Cpath d='M21 12h-9.2'/%3E%3C/svg%3E");
  --i-plus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M12 5.2v13.6'/%3E%3Cpath d='M5.2 12h13.6'/%3E%3C/svg%3E");
  --i-download:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.4v11.4'/%3E%3Cpath d='M7.6 10.4 12 14.8l4.4-4.4'/%3E%3Cpath d='M4.2 19.4h15.6'/%3E%3C/svg%3E");
  --i-warn:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.8 21.2 19.6H2.8z'/%3E%3Cpath d='M12 9.8v4.2'/%3E%3Cpath d='M12 17.2h.01'/%3E%3C/svg%3E");
  --i-empty:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.6 13.4V6.8a2.4 2.4 0 0 1 2.4-2.4h12a2.4 2.4 0 0 1 2.4 2.4v6.6'/%3E%3Cpath d='M3.6 13.4h4.6l1.3 2.3h5l1.3-2.3h4.6v3.8a2.4 2.4 0 0 1-2.4 2.4H6a2.4 2.4 0 0 1-2.4-2.4z'/%3E%3C/svg%3E");
  --i-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M6 6 18 18'/%3E%3Cpath d='M18 6 6 18'/%3E%3C/svg%3E");
  --i-check:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.7'/%3E%3Cpath d='M8.2 12.4l2.7 2.7 5-5.5'/%3E%3C/svg%3E");
}

/* --- 按钮 --- */
.btn{
  position:relative;overflow:hidden;isolation:isolate;
  display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-2);
  height:var(--ctl-h);padding:0 var(--sp-4);
  border:1px solid var(--border);border-radius:var(--r-lg);
  background:var(--bg-subtle);color:var(--text-primary);
  font-size:var(--fs-sm);font-weight:var(--fw-medium);white-space:nowrap;
  box-shadow:var(--sh-rim);
  transition:background-color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out),
             color var(--dur-2) var(--ease-out),filter var(--dur-1) var(--ease-out),
             transform var(--dur-1) var(--ease-out),box-shadow var(--dur-2) var(--ease-out);
}
.btn[data-icon]::before{
  content:"";width:15px;height:15px;flex:none;background:currentColor;opacity:.92;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-size:contain;mask-size:contain;
}
.btn[data-icon="refresh"]::before{-webkit-mask-image:var(--i-refresh);mask-image:var(--i-refresh)}
.btn[data-icon="plus"]::before{-webkit-mask-image:var(--i-plus);mask-image:var(--i-plus)}
.btn[data-icon="download"]::before{-webkit-mask-image:var(--i-download);mask-image:var(--i-download)}
.btn[data-icon="logout"]::before{-webkit-mask-image:var(--i-logout);mask-image:var(--i-logout)}
/* 加载态由 setBusy() 插入 .spinner，此时隐藏图标避免两个图形并存 */
.btn.is-loading[data-icon]::before{display:none}
.btn:active{transform:translateY(0) scale(.985);filter:brightness(.97)}
/* 主按钮：淡色底 + 深色字的「釉面」材质 —— 上浅下深的柔渐变、顶部 1px 高光、
   底部一道内阴影压住渐变收边，再配同色低透明投影；整体明度比纯平色低一档，
   放在浅底上不抢页面的视觉重心。 */
.btn-primary{
  background:linear-gradient(180deg,var(--primary-top) 0%,var(--primary-bot) 100%);
  border-color:var(--primary-edge);color:var(--primary-ink);
  font-weight:var(--fw-semibold);
  box-shadow:inset 0 1px 0 var(--primary-hi),inset 0 -1px 0 var(--primary-lo),var(--primary-ring);
}
/* 光泽扫过：仅主按钮，hover 时一道斜向高光掠过 —— 微交互里成本最低、质感提升最明显的一种。
   带宽调大、斜度调缓：与大圆角按钮更搭，扫过去像一层薄光而不是一道白条。 */
.btn-primary::after{
  content:"";position:absolute;top:-2px;bottom:-2px;left:0;width:46%;z-index:1;
  background:linear-gradient(100deg,transparent,var(--primary-sheen),transparent);
  transform:translateX(-170%) skewX(-12deg);
  transition:transform .8s var(--ease-out);
  pointer-events:none;
}
.btn-ghost{background:transparent;border-color:transparent;color:var(--text-secondary);box-shadow:none}
.btn-danger{background:var(--bg-subtle);border-color:var(--neg-border);color:var(--neg-on-soft)}
/* 站点行操作列：同步 + 删除并排 */
.row-actions{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
/* 小号按钮圆角按比例缩到 13px（32px 高的三分之一强），比大按钮更紧凑但依然圆润 */
.btn-sm{height:var(--ctl-h-sm);padding:0 var(--sp-4);font-size:var(--fs-xs);border-radius:var(--r-md)}
/* 小号主按钮把投影收窄，否则 32px 高度上会显得头重脚轻 */
.btn-sm.btn-primary{box-shadow:inset 0 1px 0 var(--primary-hi),inset 0 -1px 0 var(--primary-lo),var(--primary-ring-sm)}
/* 方形图标按钮：圆角按大按钮走，40px 见方配 20px 圆角刚好是「圆角方块」 */
.btn-icon{width:var(--ctl-h);padding:0;flex:none;border-radius:var(--r-lg)}
/* 悬停只在真有指针设备的场景生效：触摸端不会留下「粘住」的 hover 态 */
@media (hover:hover) and (pointer:fine){
  .btn:hover{background:var(--bg-hover);border-color:var(--border-strong);transform:translateY(-1px);box-shadow:var(--sh-1)}
  .btn-primary:hover{
    background:linear-gradient(180deg,var(--primary-top-h) 0%,var(--primary-bot-h) 100%);
    border-color:var(--primary-edge);
    box-shadow:inset 0 1px 0 var(--primary-hi),inset 0 -1px 0 var(--primary-lo),var(--primary-ring-h);
  }
  .btn-primary:hover::after{transform:translateX(430%) skewX(-12deg)}
  .btn-ghost:hover{background:var(--bg-hover);border-color:var(--border);color:var(--text-primary);box-shadow:none}
  .btn-danger:hover{background:var(--neg-soft);border-color:var(--neg);box-shadow:none}
}
/* 按下：主按钮沿用 hover 的浅一档底色并轻微下沉，非主按钮保持上面那条明度微调 */
.btn-primary:active{transform:translateY(1px) scale(.99);box-shadow:inset 0 2px 6px -2px var(--primary-lo)}
.btn-sm.btn-primary:active{box-shadow:inset 0 2px 5px -2px var(--primary-lo)}
/* 加载 / 禁用时不跑光泽 */
.btn.is-loading::after,.btn[disabled]::after{display:none}
/* 真正禁用：可整体淡化（WCAG 1.4.3 对「非活动组件」有豁免）。
   加载态必须放在后面：setBusy() 会同时加 [disabled] + .is-loading，
   同特异性下靠源码顺序让 .is-loading 胜出，只轻微淡化以保住「保存中…」的可读性。 */
.btn[disabled]{opacity:.5;cursor:not-allowed;transform:none;box-shadow:none}
.btn.is-loading{opacity:.92;cursor:progress;transform:none}
/* 兼容页面仍在使用的 .primary / .ghost 类名 */
.btn.primary{background:linear-gradient(180deg,var(--primary-top) 0%,var(--primary-bot) 100%);
  border-color:var(--primary-edge);color:var(--primary-ink);font-weight:var(--fw-semibold);
  box-shadow:inset 0 1px 0 var(--primary-hi),inset 0 -1px 0 var(--primary-lo),var(--primary-ring)}
.btn.ghost{background:transparent;border-color:transparent;color:var(--text-secondary);box-shadow:none}
@media (hover:hover) and (pointer:fine){
  .btn.primary:hover{background:linear-gradient(180deg,var(--primary-top-h) 0%,var(--primary-bot-h) 100%);
    border-color:var(--primary-edge);box-shadow:inset 0 1px 0 var(--primary-hi),inset 0 -1px 0 var(--primary-lo),var(--primary-ring-h)}
  .btn.ghost:hover{background:var(--bg-hover);border-color:var(--border);color:var(--text-primary)}
}

/* --- 面板 / 卡片 --- */
.panel{
  background:var(--bg-elevated);border:1px solid var(--border);border-radius:var(--r-lg);
  box-shadow:var(--sh-2),var(--sh-rim);overflow:hidden;
}
.panel-head{
  display:flex;justify-content:space-between;align-items:center;gap:var(--sp-3);
  padding:0 var(--sp-5);border-bottom:1px solid var(--border);
  min-height:54px;background:linear-gradient(180deg,color-mix(in srgb,var(--bg-subtle) 42%,transparent),transparent);
}
.panel-head h2{font-size:var(--fs-base);font-weight:var(--fw-semibold);display:flex;align-items:center;gap:var(--sp-2)}
/* 标题前的强调竖条：让「面板分区」在不加大字号的前提下也能一眼识别
   （用后代选择器：趋势图的 h2 被包在 .trend-head 里，不是 .panel-head 的直接子元素） */
.panel-head h2::before{
  content:"";width:3px;height:13px;border-radius:var(--r-full);flex:none;
  background:var(--accent);opacity:.85;
}
.panel-head span{color:var(--text-secondary);font-size:var(--fs-xs)}
.panel-body{padding:var(--sp-5)}
/* 面板内子区块标题（如分站点核算下的内部账号明细） */
.sub-head{display:flex;justify-content:space-between;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-5);border-top:1px solid var(--border);border-bottom:1px solid var(--border);min-height:44px;background:var(--bg-subtle)}
.sub-head h3{margin:0;font-size:var(--fs-sm);font-weight:var(--fw-semibold)}
.sub-head span{color:var(--text-secondary);font-size:var(--fs-xs)}
.card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-5);box-shadow:var(--sh-2),var(--sh-rim)}

/* --- 表格 --- */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}
.data-table{width:100%;border-collapse:separate;border-spacing:0;min-width:760px}
/* 关键修复：.stack 同时是布局工具类（.stack{display:grid}，见页面骨架区），
   挂在 <table> 上会把 display:table 覆盖成 grid —— 表格布局算法整体失效，
   thead 与 tbody 各自排版，表头与数据列永远对不齐（错位 bug 的根因）。
   这里显式恢复表格语义；窄屏的卡片化堆叠由后方的媒体查询规则接管。 */
.data-table.stack{display:table}
.data-table th{
  font-size:var(--fs-2xs);color:var(--text-muted);font-weight:var(--fw-semibold);text-align:left;
  letter-spacing:.05em;
  background:var(--bg-subtle);padding:var(--sp-3) var(--sp-4);
  border-bottom:1px solid var(--border);white-space:nowrap;position:sticky;top:0;z-index:1;
}
.data-table td{
  padding:var(--sp-4);border-bottom:1px solid var(--border);
  white-space:nowrap;color:var(--text-secondary);vertical-align:middle;
  transition:background-color var(--dur-1) var(--ease-out);
}
/* 行入场：stagger() 写入的 animation-delay 此前是死代码（行上没有任何 animation），
   现在真正生效。用 backwards 填充而不是 both —— both 会让动画终态的 transform
   永久压制 :hover 的位移，导致悬浮反馈失效。 */
.data-table tbody tr{animation:lh-fade-up var(--dur-3) var(--ease-out) backwards}
.data-table tr:last-child td{border-bottom:0}
.data-table td strong,.data-table td b{color:var(--text-primary);font-weight:var(--fw-semibold)}
.cell-num,.data-table th.col-num,.data-table td.col-num{text-align:right;font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.cell-truncate{max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
/* 列较多的密集表（分站点核算等）：压缩单元格左右内边距，
   让 8 列在常见窗口宽度下一屏放下，避免最后一列表头被挤出可视区。 */
.table-dense th,.table-dense td{padding-left:var(--sp-3);padding-right:var(--sp-3)}
@media (hover:hover) and (pointer:fine){
  .data-table tbody tr:hover td{background:var(--bg-hover)}
  /* 左侧强调条标出当前行，比整行变色更容易在宽表格里追踪 */
  .data-table tbody tr:hover td:first-child{box-shadow:inset 2px 0 0 var(--accent)}
}

/* --- 表单 --- */
.field{display:flex;flex-direction:column;gap:6px;min-width:0}
.field label{color:var(--text-secondary);font-size:var(--fs-xs);font-weight:var(--fw-medium)}
.form-field{display:flex;flex-direction:column;gap:6px;min-width:0}
.form-field.wide{grid-column:1/-1}
.form-field label{font-size:var(--fs-xs);color:var(--text-secondary);font-weight:var(--fw-medium)}
.form-field small{font-size:var(--fs-2xs);color:var(--text-muted);line-height:1.5}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-4) var(--sp-4)}
.form-actions{display:flex;justify-content:flex-end;gap:var(--sp-3);margin-top:var(--sp-6)}
/* 输入类控件与 .btn 共用 --ctl-h，因此筛选条里按钮和输入框严格等高。
   底色用 --bg-inset（比面板更深的「凹陷」感），聚焦时浮起到 --bg-elevated，一沉一浮表达状态。 */
.input,.select,textarea.input{
  display:block;width:100%;height:var(--ctl-h);padding:0 var(--sp-3);
  border:1px solid var(--border);border-radius:var(--r-md);
  background:var(--bg-inset);color:var(--text-primary);
  font-size:var(--fs-sm);outline:0;
  box-shadow:inset 0 1px 2px rgba(2,4,10,.14);
  transition:border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),background-color var(--dur-2) var(--ease-out);
}
textarea.input{height:auto;min-height:88px;padding:var(--sp-3);resize:vertical;line-height:1.6}
.input::placeholder{color:var(--text-ghost)}
.input:focus,.select:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--focus-ring);background-color:var(--bg-elevated)}
.input[aria-invalid="true"]{border-color:var(--neg);box-shadow:0 0 0 3px var(--neg-soft)}
.input[aria-invalid="true"]:focus{border-color:var(--neg);box-shadow:0 0 0 3px var(--neg-soft)}
.select{
  appearance:none;-webkit-appearance:none;padding-right:var(--sp-7);cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 9.5 12 15l5.5-5.5'/%3E%3C/svg%3E");
  background-position:right 12px center;background-size:14px 14px;background-repeat:no-repeat;
}
[data-theme="dark"] .select{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a7b1c0' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 9.5 12 15l5.5-5.5'/%3E%3C/svg%3E");
}
select option{background:var(--bg-elevated);color:var(--text-primary)}
@media (hover:hover) and (pointer:fine){
  .input:hover:not([aria-invalid="true"]),.select:hover{border-color:var(--text-ghost)}
}
input[type="date"],input[type="datetime-local"]{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
/* color-scheme 已让原生日期图标跟随主题，不再需要 filter:invert 这类近似补丁 */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator{cursor:pointer;opacity:.6;transition:opacity var(--dur-2) var(--ease-out)}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover{opacity:1}

/* --- 徽章 .badge（.tag 为兼容别名）：全圆角胶囊，语义更柔和 --- */
.badge,.tag{
  display:inline-flex;align-items:center;gap:5px;
  height:22px;padding:0 var(--sp-3);border-radius:var(--r-full);
  border:1px solid var(--border);background:var(--bg-subtle);
  color:var(--text-secondary);font-size:var(--fs-2xs);font-weight:var(--fw-medium);letter-spacing:.015em;line-height:1;white-space:nowrap;
}
.badge .dot{width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.badge-pos,.tag.income{color:var(--pos-on-soft);background:var(--pos-soft);border-color:var(--pos-border)}
.badge-neg,.tag.unknown{color:var(--neg-on-soft);background:var(--neg-soft);border-color:var(--neg-border)}
.badge-warn,.tag.cost{color:var(--warn-on-soft);background:var(--warn-soft);border-color:var(--warn-border)}
.badge-info,.tag.admin{color:var(--info-on-soft);background:var(--info-soft);border-color:var(--info-border)}
.badge-neutral{color:var(--text-secondary);background:var(--bg-subtle);border-color:var(--border)}

/* --- 提示 .alert --- */
.alert{
  position:relative;display:none;border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4) var(--sp-3) calc(var(--sp-4) + 20px);
  font-size:var(--fs-xs);line-height:1.65;margin-bottom:var(--sp-4);
  border:1px solid transparent;
}
.alert.show{display:block;animation:lh-fade-up var(--dur-3) var(--ease-out) both}
/* 图标由伪元素提供，JS 里不再往文案前面拼「⚠ 」（字形图标跨平台基线不一致） */
.alert.show::before{
  content:"";position:absolute;left:var(--sp-4);top:calc(var(--sp-3) + 2px);
  width:14px;height:14px;background:currentColor;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-size:contain;mask-size:contain;
}
.alert.error{background:var(--neg-soft);color:var(--neg-on-soft);border-color:var(--neg-border)}
.alert.ok{background:var(--pos-soft);color:var(--pos-on-soft);border-color:var(--pos-border)}
.alert.info{background:var(--info-soft);color:var(--info-on-soft);border-color:var(--info-border)}
.alert.warn{background:var(--warn-soft);color:var(--warn-on-soft);border-color:var(--warn-border)}
.alert.error::before,.alert.warn::before{-webkit-mask-image:var(--i-warn);mask-image:var(--i-warn)}
.alert.ok::before{-webkit-mask-image:var(--i-check);mask-image:var(--i-check)}
.alert.info::before{-webkit-mask-image:var(--i-empty);mask-image:var(--i-empty)}

/* --- 状态点 .status --- */
.status{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-xs);color:var(--text-secondary)}
.status::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 16%,transparent)}
.status.on{color:var(--pos)}
.status.off{color:var(--neg)}
.status.warn{color:var(--warn)}
/* 运行中的状态点呼吸一下，把「正在同步」这类瞬时态讲清楚 */
.status.on::before,.status.warn::before{animation:lh-pulse 2s var(--ease-inout) infinite}
@keyframes lh-pulse{0%,100%{box-shadow:0 0 0 3px color-mix(in srgb,currentColor 16%,transparent)}50%{box-shadow:0 0 0 5px color-mix(in srgb,currentColor 5%,transparent)}}

/* --- 空状态 / 骨架屏 --- */
.empty{display:flex;flex-direction:column;align-items:center;gap:var(--sp-2);padding:var(--sp-9) var(--sp-5);text-align:center;color:var(--text-muted)}
/* 图标改为 mask 绘制的图形：原先是 ∅ / ⚠ 文本字形，跨平台字重与基线都不一致。
   纯装饰（含义由相邻 .empty-title 承担），用法处一律带 aria-hidden="true"。 */
.empty-icon{
  width:38px;height:38px;flex:none;font-size:0;line-height:0;margin-bottom:var(--sp-1);
  background:var(--text-ghost);opacity:.85;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-image:var(--i-empty);mask-image:var(--i-empty);
}
.empty-title{color:var(--text-secondary);font-size:var(--fs-sm);font-weight:var(--fw-medium)}
.empty-desc{font-size:var(--fs-xs);color:var(--text-muted);max-width:40ch;line-height:1.65}
.skeleton{display:block;border-radius:var(--r-sm);background:linear-gradient(90deg,var(--bg-subtle) 25%,var(--bg-hover) 37%,var(--bg-subtle) 63%);background-size:400% 100%;animation:lh-shimmer 1.4s ease-in-out infinite}
.skeleton-row{height:14px;margin:var(--sp-3) 0}
.spinner{display:inline-block;width:14px;height:14px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:lh-spin .7s linear infinite;vertical-align:-2px}
@keyframes lh-shimmer{0%{background-position:100% 0}100%{background-position:0 0}}
@keyframes lh-spin{to{transform:rotate(360deg)}}
@keyframes lh-drift{0%,100%{transform:translate3d(0,0,0) scale(1)}50%{transform:translate3d(-2.5%,2%,0) scale(1.07)}}
@keyframes lh-fade-up{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@keyframes lh-fade-in{from{opacity:0}to{opacity:1}}
@keyframes lh-pop{from{opacity:0;transform:translateY(8px) scale(.985)}to{opacity:1;transform:none}}
@keyframes lh-slide-out{from{opacity:1;transform:none}to{opacity:0;transform:translateX(12px)}}

/* --- 模态 .modal（#costDialog 采用此结构） --- */
.modal{
  position:fixed;inset:0;z-index:var(--z-modal);display:grid;place-items:center;padding:var(--sp-4);
  background:rgba(4,7,12,.62);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  animation:lh-fade-in var(--dur-2) var(--ease-out) both;
}
[data-theme="light"] .modal{background:rgba(16,24,40,.32)}
.modal[hidden]{display:none}
.modal-card{
  width:min(540px,100%);max-height:min(88vh,780px);overflow:auto;
  background:var(--bg-elevated);border:1px solid var(--border);border-radius:var(--r-xl);
  box-shadow:var(--sh-4),var(--sh-rim);
  animation:lh-pop var(--dur-3) var(--ease-out) both;
}
/* 退场：JS 在 closeModal() 里挂 .is-closing 并等动画播完再 hidden，
   否则弹窗是「啪」地瞬间消失，与入场动效不对称。 */
.modal.is-closing{animation:lh-fade-in var(--dur-2) var(--ease-inout) reverse both}
.modal.is-closing .modal-card{animation:lh-pop var(--dur-2) var(--ease-inout) reverse both}
.modal-head{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--sp-4);padding:var(--sp-5) var(--sp-5) var(--sp-3)}
.modal-body{padding:0 var(--sp-5) var(--sp-5)}
.modal-foot{display:flex;justify-content:flex-end;gap:var(--sp-3);padding:var(--sp-4) var(--sp-5);border-top:1px solid var(--border);background:var(--bg-subtle)}
.modal-close{
  width:32px;height:32px;border-radius:var(--r-md);color:var(--text-muted);flex:none;
  display:grid;place-items:center;font-size:0;line-height:0;border:1px solid transparent;
  transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out);
}
.modal-close::before{
  content:"";width:14px;height:14px;background:currentColor;
  -webkit-mask:var(--i-close) center/contain no-repeat;mask:var(--i-close) center/contain no-repeat;
}
@media (hover:hover) and (pointer:fine){
  .modal-close:hover{background:var(--bg-hover);color:var(--text-primary);border-color:var(--border)}
}

/* --- Toast --- */
.toast-stack{position:fixed;inset:auto var(--sp-5) calc(var(--sp-5) + env(safe-area-inset-bottom)) auto;margin:0;padding:0;border:0;background:transparent;color:inherit;overflow:visible;z-index:var(--z-toast);display:flex;flex-direction:column;gap:var(--sp-2);pointer-events:none;max-width:min(400px,calc(100vw - 32px))}
.toast{
  position:relative;overflow:hidden;pointer-events:auto;display:flex;align-items:flex-start;gap:var(--sp-3);
  min-width:264px;padding:var(--sp-3) var(--sp-4) var(--sp-3) var(--sp-5);
  border-radius:var(--r-md);border:1px solid var(--border);
  background:var(--glass-bg-strong);
  backdrop-filter:blur(16px) saturate(1.4);-webkit-backdrop-filter:blur(16px) saturate(1.4);
  box-shadow:var(--sh-3),var(--sh-rim);
  animation:lh-pop var(--dur-3) var(--ease-out) both;
}
/* 左侧语义导轨：比整块染色更克制，也避免彩色底把正文对比度拉低 */
.toast::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--toast-c,var(--accent))}
.toast.leaving{animation:lh-slide-out var(--dur-2) var(--ease-inout) both}
.toast-msg{flex:1;font-size:var(--fs-sm);color:var(--text-primary);word-break:break-word;line-height:1.55;padding-top:1px}
.toast-close{
  flex:none;width:22px;height:22px;border-radius:var(--r-sm);color:var(--text-muted);
  display:grid;place-items:center;font-size:0;line-height:0;
  transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out);
}
.toast-close::before{
  content:"";width:11px;height:11px;background:currentColor;
  -webkit-mask:var(--i-close) center/contain no-repeat;mask:var(--i-close) center/contain no-repeat;
}
.toast-ok{--toast-c:var(--pos)}.toast-ok .toast-icon{color:var(--pos)}
.toast-error{--toast-c:var(--neg)}.toast-error .toast-icon{color:var(--neg)}
.toast-info{--toast-c:var(--info)}.toast-info .toast-icon{color:var(--info)}
.toast-warn{--toast-c:var(--warn)}.toast-warn .toast-icon{color:var(--warn)}
.toast-icon{
  flex:none;width:20px;height:20px;border-radius:50%;display:grid;place-items:center;
  font-size:var(--fs-2xs);font-weight:var(--fw-bold);line-height:1;
  background:color-mix(in srgb,currentColor 16%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,currentColor 30%,transparent);
}
@media (hover:hover) and (pointer:fine){
  .toast-close:hover{color:var(--text-primary);background:var(--bg-hover)}
}

/* ============================================================
   4. 应用外壳：侧栏 / 顶栏 / 内容区
   ============================================================ */
.shell{min-height:100vh;display:flex;background:transparent}
.sidebar{
  width:var(--sidebar-w);flex:none;display:flex;flex-direction:column;
  border-right:1px solid var(--border);
  /* 半透明深底，让 body 的环境光微微透入，侧栏与内容区不再「一刀两断」 */
  background:color-mix(in srgb,var(--bg-void) 88%,transparent);
  padding:var(--sp-5) var(--sp-4);position:sticky;top:0;height:100vh;overflow-y:auto;z-index:var(--z-drawer);
}
.brand{display:block;padding:0 0 var(--sp-5)}
/* 品牌视觉：以 logo.webp 横幅图取代原「图标 + 文字」，宽度铺满侧栏内宽 */
.brand-logo{
  display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;object-position:50% 44%;
  border-radius:var(--r-lg);border:1px solid var(--border);background:var(--bg-subtle);
  box-shadow:var(--sh-2),var(--sh-rim);
}
.nav{display:grid;gap:3px}
.nav button{
  position:relative;display:flex;align-items:center;gap:var(--sp-3);
  min-height:40px;padding:0 var(--sp-3);
  border-radius:var(--r-md);border:1px solid transparent;
  color:var(--text-secondary);font-size:var(--fs-sm);text-align:left;
  transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),
             border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),
             transform var(--dur-1) var(--ease-out);
}
/* 选中态：左侧导轨 + 渐隐胶囊 + 同色微光，三重信号定位「我在哪一页」 */
.nav button.active::before{
  content:"";position:absolute;left:-9px;top:50%;transform:translateY(-50%);
  width:3px;height:18px;border-radius:0 var(--r-full) var(--r-full) 0;background:var(--accent);
  box-shadow:0 0 10px color-mix(in srgb,var(--accent) 80%,transparent);
}
.nav button.active{
  background:linear-gradient(90deg,var(--accent-soft),color-mix(in srgb,var(--accent-soft) 35%,transparent));
  color:var(--accent-on-soft);border-color:var(--accent-border);font-weight:var(--fw-semibold);
  box-shadow:0 8px 18px -12px color-mix(in srgb,var(--accent) 55%,transparent);
}
.nav button:active{transform:scale(.985)}
.nav-icon{width:18px;height:18px;flex:none;display:grid;place-items:center;opacity:.85;transition:transform var(--dur-2) var(--ease-out)}
.nav-icon svg{width:17px;height:17px;display:block}
.nav button.active .nav-icon{opacity:1;transform:scale(1.06)}
.nav-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* .nav button 的 display:flex 会盖过 [hidden]，只读账号隐藏「账号管理」需要这条兜底 */
.nav button[hidden]{display:none}
@media (hover:hover) and (pointer:fine){
  .nav button:hover{background:var(--bg-hover);color:var(--text-primary)}
}

.main{min-width:0;flex:1;display:flex;flex-direction:column}
/* 顶栏：桌面端隐藏（内容区顶部不再压一条空带），≤900px 只留下抽屉开关 */
.topbar{
  display:none;height:var(--topbar-h);flex:none;align-items:center;justify-content:flex-end;gap:var(--sp-4);
  padding:0 var(--sp-7);position:sticky;top:0;z-index:40;
  background:var(--glass-bg);backdrop-filter:blur(18px) saturate(1.5);-webkit-backdrop-filter:blur(18px) saturate(1.5);
  border-bottom:1px solid var(--glass-border);
}
/* 侧栏底部账号区：账号胶囊 + 主题/退出，顶栏移除后这里是唯一的账号入口 */
.side-foot{margin-top:auto;padding-top:var(--sp-4);border-top:1px solid var(--border);display:grid;gap:var(--sp-3)}
.side-foot .user-chip{width:100%;height:40px;padding:0 var(--sp-4)}
.side-foot-actions{display:flex;align-items:center;gap:var(--sp-2)}
.side-foot-actions .logout{flex:1;height:var(--ctl-h)}
/* 用户胶囊：账号名 + 角色徽标收进一颗 pill，顶栏右侧从「散件」变成一个整体 */
.user-chip{
  display:flex;align-items:center;gap:var(--sp-2);color:var(--text-secondary);font-size:var(--fs-sm);
  height:36px;padding:0 var(--sp-4);
  background:var(--bg-subtle);border:1px solid var(--border);border-radius:var(--r-full);
  transition:border-color var(--dur-2) var(--ease-out),background-color var(--dur-2) var(--ease-out);
}
.user-name{
  max-width:14ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--text-primary);font-weight:var(--fw-medium);
}
.theme-toggle{
  width:var(--ctl-h);height:var(--ctl-h);border-radius:var(--r-lg);
  border:1px solid var(--border-strong);background:var(--bg-subtle);color:var(--text-secondary);
  display:grid;place-items:center;flex:none;
  transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),
             border-color var(--dur-2) var(--ease-out),transform var(--dur-1) var(--ease-out);
}
.theme-toggle svg{width:17px;height:17px;display:block}
.theme-icon-light{display:none}
[data-theme="light"] .theme-icon-dark{display:none}
[data-theme="light"] .theme-icon-light{display:block}
@media (hover:hover) and (pointer:fine){
  .theme-toggle:hover{background:var(--bg-hover);color:var(--text-primary);border-color:var(--text-ghost);transform:translateY(-1px)}
}
.mobile-menu{
  display:none;width:var(--ctl-h);height:var(--ctl-h);border-radius:var(--r-lg);
  border:1px solid var(--border-strong);background:var(--bg-subtle);color:var(--text-primary);
  place-items:center;flex:none;margin-right:auto;
}
.mobile-menu svg{width:18px;height:18px;display:block}
/* 退出：沿用 .btn-ghost 的幽灵态，只在顶栏这处收敛尺寸与配色 */
.logout{
  height:var(--ctl-h-sm);padding:0 var(--sp-3);border-color:var(--border);
  border-radius:var(--r-md);color:var(--text-secondary);font-size:var(--fs-xs);
}
.logout::before{width:14px;height:14px}
@media (hover:hover) and (pointer:fine){
  .logout:hover{background:var(--bg-hover);color:var(--text-primary);border-color:var(--text-ghost)}
}
@media (hover:hover) and (pointer:fine){
  .mobile-menu:hover{background:var(--bg-hover)}
  .logout:hover{border-color:var(--neg-border);color:var(--neg-on-soft);background:var(--neg-soft)}
}
.content{
  width:100%;max-width:var(--content-max);margin:0 auto;flex:1;
  padding:var(--sp-7) var(--sp-7) var(--sp-9);
  padding-left:max(var(--sp-7),env(safe-area-inset-left));
  padding-right:max(var(--sp-7),env(safe-area-inset-right));
}
.view{display:none}
.view.active{display:block;animation:lh-fade-up var(--dur-3) var(--ease-out) both}
#view-sites .site-grid{grid-template-columns:minmax(0,1fr)}
#view-sites .platform-instance-panel{margin:var(--sp-4) 0 0}
.platform-instance-dialog{width:min(620px,calc(100vw - 32px));max-height:calc(100dvh - 32px);overflow:auto;overscroll-behavior:contain;border:1px solid var(--border);border-radius:8px;background:var(--bg-elevated);color:var(--text-primary);padding:var(--sp-6);box-shadow:0 18px 48px #0003}
.platform-instance-dialog::backdrop{background:#0008}
.platform-instance-dialog h2{font-size:var(--fs-lg);margin:0 0 var(--sp-5)}
.platform-instance-dialog > form > .form-field{width:100%;margin-bottom:var(--sp-4)}
.platform-instance-dialog select{width:100%;max-width:100%}
.platform-instance-dialog [hidden],#siteFormPanel[hidden]{display:none!important}
.platform-instance-dialog #controlFields>.form-field{margin-bottom:var(--sp-4)}
.platform-instance-dialog .new-instance-field[hidden]{display:none}
.platform-binding-list{display:grid;gap:6px;max-height:120px;overflow:auto;padding:8px;border:1px solid var(--border);border-radius:6px}
.platform-binding-list label{font-size:var(--fs-sm)}

/* 移动端抽屉遮罩 */
.scrim{position:fixed;inset:0;z-index:var(--z-scrim);background:rgba(4,7,12,.62);backdrop-filter:blur(3px);opacity:0;visibility:hidden;transition:opacity var(--dur-3) var(--ease-inout),visibility var(--dur-3)}
[data-theme="light"] .scrim{background:rgba(16,24,40,.34)}
.scrim.show{opacity:1;visibility:visible}

/* ============================================================
   5. 页面骨架
   ============================================================ */
/* 页头不再放页面大标题（标题已由侧栏导航承担），只承载右侧操作区 */
.page-head{display:flex;justify-content:flex-end;align-items:center;gap:var(--sp-5);margin-bottom:var(--sp-4)}
.page-head p{color:var(--text-secondary);margin:var(--sp-2) 0 0;font-size:var(--fs-sm);max-width:72ch;line-height:1.6}
.actions{display:flex;gap:var(--sp-2);align-items:center;flex-wrap:wrap}
.layout-2{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(320px,.85fr);gap:var(--sp-4);margin-top:var(--sp-4)}
.site-grid{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(330px,.8fr);gap:var(--sp-4)}
.stack{display:grid;gap:var(--sp-4)}
/* 总览顶部六张指标卡使用相同的栅格和数值布局。 */
.cards{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:var(--sp-3)}
#metrics{grid-template-columns:repeat(6,minmax(0,1fr));grid-auto-rows:1fr;align-items:stretch}
#metrics .usage-overview,#metrics .hero{grid-column:auto}
.realtime-metric{gap:var(--sp-2)}
.realtime-metric .metric-value small{font-size:var(--fs-xs);color:var(--text-muted)}
.usage-overview-detail{display:flex;gap:var(--sp-2);flex-wrap:wrap;font-size:var(--fs-2xs);color:var(--text-secondary);font-variant-numeric:tabular-nums}
.usage-overview-detail span{white-space:nowrap}
.usage-total{font-family:var(--font-mono);font-size:var(--fs-2xs);font-variant-numeric:tabular-nums;color:var(--text-secondary);white-space:nowrap}
#metrics .usage-overview .metric-label{flex-wrap:wrap}
#metrics .usage-total{margin-left:auto}
@media (max-width:1400px){#metrics{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (max-width:900px){#metrics{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:480px){#metrics{grid-template-columns:1fr}#metrics .usage-overview{grid-column:auto}}
/* 利润周期：今日 / 本周 / 本月 / 本年 四张卡一行 */
#periodCards{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:1150px){ #periodCards{grid-template-columns:repeat(2,minmax(0,1fr))} }
/* ===== 经营总览：统计区间工具条（原为整块面板，站点多时把首屏留给数据） ===== */
/* 统计区间工具条：控件按内容宽度排在一行，右侧 meta 贴边；不再被 width:100% 拉满 */
.range-bar{
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2) var(--sp-3);
  padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-4);
  background:var(--bg-elevated);border:1px solid var(--border);border-radius:var(--r-lg);
  box-shadow:var(--sh-1),var(--sh-rim);
}
.range-bar .range-title{
  flex:none;padding-right:var(--sp-3);border-right:1px solid var(--border);
  color:var(--text-secondary);font-size:var(--fs-xs);font-weight:var(--fw-semibold);letter-spacing:.02em;
}
.range-controls{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);min-width:0}
.range-bar .select,.range-bar .input{height:var(--ctl-h-sm);padding-top:0;padding-bottom:0;font-size:var(--fs-xs)}
.range-bar .select{flex:0 0 auto;width:auto;min-width:12em;max-width:16em}
.range-bar .input{flex:0 0 auto;width:auto;min-width:9.5em}
.range-bar #rangeFromField,.range-bar #rangeToField{display:inline-flex;align-items:center;gap:var(--sp-2)}
.range-bar #rangeToField::before{content:"→";color:var(--text-muted);font-size:var(--fs-xs)}
.range-bar .range-sep{color:var(--text-muted)}
/* 右侧生效区间：淡色胶囊，比裸文字更像「当前口径」 */
.range-bar .range-meta{
  margin-left:auto;padding:2px var(--sp-3);border-radius:var(--r-full);
  background:var(--bg-subtle);border:1px solid var(--border);
  color:var(--text-secondary);font-size:var(--fs-2xs);font-variant-numeric:tabular-nums;white-space:nowrap;
}
/* ===== 分站点核算：排序表头 / 排名 / 利润占比条 / 折叠 ===== */
.data-table th.sortable{cursor:pointer;user-select:none}
.data-table th.sortable:hover{color:var(--text-primary)}
.data-table th.sortable .sort-mark{margin-left:4px;font-size:9px;opacity:0;transition:opacity var(--dur-2) var(--ease-out)}
.data-table th.sortable:hover .sort-mark{opacity:.4}
.data-table th.sortable.on .sort-mark{opacity:1;color:var(--accent)}
.site-name-cell{display:flex;align-items:center;min-width:0}
.profit-cell{display:inline-block;min-width:76px}
.profit-cell .profit-bar{display:block;height:3px;margin-top:3px;border-radius:var(--r-full);background:linear-gradient(90deg,currentColor,transparent);opacity:.55}

.list-more{display:flex;justify-content:center;padding:var(--sp-3);border-top:1px solid var(--border);background:var(--bg-subtle)}
.pager .pager-jump{display:inline-flex;align-items:center;gap:6px;color:var(--text-muted);font-size:var(--fs-2xs)}
.pager .pager-jump input{width:58px;height:32px;padding:0 var(--sp-2);text-align:center}
.pager{display:flex;justify-content:space-between;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-5);border-top:1px solid var(--border);color:var(--text-secondary);font-size:var(--fs-xs);flex-wrap:wrap}
.filters{
  display:flex;flex-wrap:wrap;gap:var(--sp-3);padding:var(--sp-4) var(--sp-5);
  border-bottom:1px solid var(--border);background:var(--bg-subtle);align-items:flex-end;
}
.filters .field{min-width:136px;flex:0 1 auto}
.filters .field label{font-size:var(--fs-2xs);color:var(--text-muted);letter-spacing:.02em}
.search{min-width:210px}
.filters .search{flex:1 1 210px}
/* 修正原有缺陷：.search 同时挂在内部 <input class="input search"> 上，
   而 .field 是纵向 flex 容器 —— flex-basis:210px 在纵轴会变成「高度」，
   导致搜索框被撑到 210px 高。这里把输入框自身的伸缩重置，
   「占满剩余宽度」只作用于外层 .field 包装。 */
.filters .field>.search{flex:0 1 auto}
/* 指标卡 */
.metric{
  position:relative;display:flex;flex-direction:column;gap:var(--sp-3);
  min-height:108px;padding:var(--sp-4) var(--sp-5);
  /* 顶部一层极淡的纵向提亮（Vercel / Linear 式卡面），
     让卡片脱离「纯色平面」，又不引入第二种颜色 */
  background:linear-gradient(180deg,color-mix(in srgb,var(--bg-subtle) 62%,transparent),transparent 72%),var(--bg-elevated);
  border:1px solid var(--border);border-radius:var(--r-lg);
  box-shadow:var(--sh-2),var(--sh-rim);
  overflow:hidden;
  /* backwards（而非 both）—— both 的终态 transform 会永久压掉下面的 :hover 位移 */
  animation:lh-fade-up var(--dur-3) var(--ease-out) backwards;
  transition:border-color var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out);
}
@media (hover:hover) and (pointer:fine){
  .metric:hover{border-color:var(--border-strong);transform:translateY(-2px);box-shadow:var(--sh-3),var(--sh-rim)}
  .metric.hero:hover{border-color:color-mix(in srgb,var(--hero-c) 48%,var(--border))}
}
/* 主指标卡：跨 2 格 + 顶部语义导轨 + 淡色渐变 + 角落环境光，让「估算利润」在五张卡里立刻被认出 */
.metric.hero{--hero-c:var(--accent);grid-column:span 2}
.metric.hero.pos{--hero-c:var(--pos)}
.metric.hero.neg{--hero-c:var(--neg)}
.metric.hero{
  border-color:color-mix(in srgb,var(--hero-c) 32%,var(--border));
  background:linear-gradient(180deg,color-mix(in srgb,var(--hero-c) 9%,transparent) 0,transparent 64%),var(--bg-elevated);
}
.metric.hero::after{
  content:"";position:absolute;left:14px;right:14px;top:-1px;height:2px;border-radius:var(--r-full);
  background:linear-gradient(90deg,var(--hero-c),transparent);
}
/* 右上角一团语义色环境光：纯装饰，hover 时微微亮起 */
.metric.hero::before{
  content:"";position:absolute;right:-34px;top:-34px;width:150px;height:150px;border-radius:50%;
  background:radial-gradient(circle,color-mix(in srgb,var(--hero-c) 18%,transparent),transparent 70%);
  pointer-events:none;transition:opacity var(--dur-3) var(--ease-out);opacity:.8;
}
@media (hover:hover) and (pointer:fine){
  .metric.hero:hover::before{opacity:1}
}
.metric-label{display:flex;justify-content:space-between;align-items:center;gap:var(--sp-2);color:var(--text-secondary);font-size:var(--fs-xs);font-weight:var(--fw-medium);letter-spacing:.01em;min-height:22px}
/* 顶部 KPI 统一标注全站口径：小胶囊 + 指标名，避免和下方单站点卡混淆 */
.kpi-label{display:inline-flex;align-items:center;gap:var(--sp-1);min-width:0;font-weight:inherit}
.kpi-scope{
  flex:0 0 auto;font-size:10px;font-weight:var(--fw-semibold);line-height:1.4;
  padding:1px 6px;border-radius:999px;white-space:nowrap;
  color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--accent) 28%,transparent);
}
.metric-value{
  font-family:var(--font-mono);font-variant-numeric:tabular-nums;
  font-size:var(--fs-xl);font-weight:var(--fw-semibold);letter-spacing:var(--tracking-tight);
  line-height:1.1;color:var(--text-primary);margin-top:auto;
}
.metric.hero .metric-value{font-size:var(--fs-3xl);font-weight:var(--fw-bold)}
.metric-note{color:var(--text-muted);font-size:var(--fs-2xs);line-height:1.55}
.metric.pos .metric-value{color:var(--pos)}
.metric.neg .metric-value{color:var(--neg)}
.metric.warn .metric-value{color:var(--warn)}
.metric.info .metric-value{color:var(--info)}
/* 兼容旧配色类名 */
.metric.green .metric-value{color:var(--pos)}
.metric.red .metric-value{color:var(--neg)}
.metric.amber .metric-value{color:var(--warn)}
.metric.blue .metric-value{color:var(--info)}
#metrics .metric{
  --hero-c:var(--accent);
  display:flex;
  flex-direction:column;
  gap:var(--sp-2);
  min-height:0;
  border-color:color-mix(in srgb,var(--hero-c) 32%,var(--border));
  background:linear-gradient(180deg,color-mix(in srgb,var(--hero-c) 9%,transparent) 0,transparent 64%),var(--bg-elevated);
}
#metrics .metric.pos{--hero-c:var(--pos)}
#metrics .metric.neg{--hero-c:var(--neg)}
#metrics .metric.info{--hero-c:var(--info)}
#metrics .metric.warn{--hero-c:var(--warn)}
#metrics .metric::after{
  content:"";position:absolute;left:14px;right:14px;top:-1px;height:2px;border-radius:var(--r-full);
  background:linear-gradient(90deg,var(--hero-c),transparent);
}
#metrics .metric.hero::before{display:none}
#metrics .metric .metric-value{
  margin:auto 0;
  align-self:center;
  text-align:center;
  font-size:var(--fs-xl);
  font-weight:var(--fw-bold);
  overflow-wrap:anywhere;
}
#metrics .metric-detail{display:flex;flex-direction:column;gap:var(--sp-1);min-width:0;margin-top:auto}
.user-view header{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--sp-4);gap:var(--sp-3)}
.user-view header h1{font-size:var(--fs-lg)}
.user-view .header-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--sp-2)}
.user-view header p,.user-view .muted,.user-dialog .muted{color:var(--text-muted);font-size:var(--fs-xs)}
.user-view .eyebrow{display:none}
.user-view .stats{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:var(--sp-3);margin-bottom:var(--sp-4)}
.user-view .stats article{display:flex;flex-direction:column;gap:var(--sp-1);padding:var(--sp-3);border:1px solid var(--border);border-radius:var(--r-lg);background:var(--bg-elevated)}
.user-view .stats b{font-family:var(--font-mono);font-size:var(--fs-lg)}
.user-view .stats span{color:var(--text-muted);font-size:var(--fs-xs)}
.user-view .toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);padding:var(--sp-3)}
.user-view .filters{display:flex;flex:1 1 auto;min-width:0;flex-wrap:wrap;gap:var(--sp-2);padding:0;border:0}
.user-view .filters .select{width:auto;min-width:130px;max-width:100%}
.user-view .filters .input{width:min(240px,100%)}
.user-view input:not([type=checkbox]):not(.input),.user-dialog input:not([type=checkbox]):not(.input){font:inherit;font-size:var(--fs-sm);color:var(--text-primary);background-color:var(--bg-inset);border:1px solid var(--border);border-radius:var(--r-md);padding:var(--sp-3)}
.user-view .row-actions,.user-view .page-actions{display:flex;gap:var(--sp-1);flex-wrap:wrap}
.user-view .pagination{display:flex;justify-content:space-between;align-items:center;padding:var(--sp-3);gap:var(--sp-2)}
.user-view .user-name small{display:block;color:var(--text-muted)}
.user-view .money{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.user-view .badge{font-size:var(--fs-2xs);padding:3px 7px;border-radius:var(--r-full);background:var(--bg-subtle)}
.user-view .badge.enabled{color:var(--pos)}
.user-view .badge.disabled,.user-view .error-banner{color:var(--neg)}
.user-view .error-banner{padding:var(--sp-3)}
.user-dialog{width:min(520px,calc(100vw - 32px))}
.user-dialog form,.user-dialog label{display:grid;gap:var(--sp-2)}
.user-dialog form{gap:var(--sp-3)}
.user-dialog .dialog-actions{display:flex;justify-content:flex-end;gap:var(--sp-2)}
#um-categoriesDialog > label,#um-categoriesDialog .category-field{margin-top:var(--sp-3)}
.category-field{display:grid;gap:var(--sp-2)}
.category-controls{display:flex;align-items:center;gap:var(--sp-2)}
.category-controls .select{flex:1;min-width:0}
.category-controls button{flex:none;min-height:var(--ctl-h)}
#um-categoriesDialog > .dialog-actions{margin-top:var(--sp-4);padding-top:var(--sp-4);border-top:1px solid var(--border);flex-wrap:wrap}
.user-dialog .ratio-list{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin:var(--sp-3) 0}
.user-dialog .ratio-chip{padding:6px 10px;border:1px solid var(--border);border-radius:var(--r-md);font-size:var(--fs-xs);overflow-wrap:anywhere}
.user-dialog .ratio-chip.current{color:var(--accent);border-color:var(--accent);background:var(--bg-subtle)}
.user-dialog .ratio-error{color:var(--neg)}
.app-dialog{max-width:calc(100vw - 32px);max-height:90dvh;overflow:auto;overscroll-behavior:contain;padding:var(--sp-5);color:var(--text-primary);background:var(--bg-elevated);border:1px solid var(--border);border-radius:var(--r-xl);box-shadow:var(--sh-4),var(--sh-rim)}
.app-dialog[open]{overflow:auto;overscroll-behavior:contain}
body:has(dialog[open]){overflow:hidden}
.app-dialog::backdrop{background:rgba(4,7,12,.62)}
.app-dialog h2{margin:0 0 var(--sp-4);font-size:var(--fs-lg)}
:is(.channel-view,.channel-dialog,.user-view,.user-dialog) button:not(.btn){display:inline-flex;align-items:center;justify-content:center;min-height:var(--ctl-h-sm);padding:0 var(--sp-3);font:inherit;font-size:var(--fs-xs);font-weight:var(--fw-medium);color:var(--text-primary);background:var(--bg-subtle);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:var(--sh-rim);cursor:pointer;white-space:nowrap}
:is(.channel-view,.channel-dialog,.user-view,.user-dialog) button.primary{background:linear-gradient(180deg,var(--primary-top),var(--primary-bot));border-color:var(--primary-edge);color:var(--primary-ink);font-weight:var(--fw-semibold);box-shadow:var(--primary-ring-sm)}
:is(.channel-view,.channel-dialog,.user-view,.user-dialog) button.danger{color:var(--neg-on-soft);background:var(--bg-subtle);border-color:var(--neg-border)}
:is(.channel-view,.channel-dialog,.user-view,.user-dialog) button:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}
:is(.channel-view,.channel-dialog,.user-view,.user-dialog) button:not(:disabled):hover{border-color:var(--border-strong)}
.channel-view .toolbar button,.user-view header button,.user-view .toolbar button,:is(.channel-dialog,.user-dialog) :is(.actions,.dialog-actions) button{min-height:var(--ctl-h)}
.channel-view .data-table,.channel-dialog .data-table{width:100%;border-collapse:separate;border-spacing:0;text-align:left}
.channel-view .data-table th,.channel-dialog .data-table th{padding:var(--sp-3) var(--sp-4);max-width:none;font-size:var(--fs-2xs);color:var(--text-muted);font-weight:var(--fw-semibold);white-space:nowrap}
.channel-view .data-table td,.channel-dialog .data-table td{padding:var(--sp-3) var(--sp-4);max-width:320px;font-size:var(--fs-xs);white-space:normal;overflow-wrap:anywhere}
.pool-grid{display:grid;grid-template-columns:220px minmax(0,1fr);gap:var(--sp-4);align-items:start}
.pool-instances{display:grid;gap:var(--sp-2)}
.pool-instance{display:flex;flex-direction:column;gap:var(--sp-2);text-align:left;padding:var(--sp-3);font:inherit;color:var(--text-primary);background:var(--bg-elevated);border:1px solid var(--border);border-radius:var(--r-md);cursor:pointer;min-width:0;overflow-wrap:anywhere}
.pool-instance>span:first-child{display:flex;justify-content:space-between;gap:var(--sp-2)}
.pool-instance small{color:var(--text-muted);font-size:var(--fs-2xs)}
.pool-instance.is-selected{border-color:var(--accent);background:var(--bg-subtle)}
.pool-card{min-width:0}
.pool-card .panel-head h2{display:flex;align-items:center;gap:var(--sp-2)}
.pool-actions{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-bottom:var(--sp-3)}
.pool-note{display:block;color:var(--text-muted);font-size:var(--fs-xs);overflow-wrap:anywhere}
.pool-error{color:var(--neg);font-size:var(--fs-xs)}
.pool-card td{overflow-wrap:anywhere}
@media(max-width:760px){.pool-grid{grid-template-columns:1fr}.pool-instances{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}}
@media(max-width:600px){.user-view .stats{grid-template-columns:repeat(2,minmax(0,1fr))}.user-view .pagination{flex-wrap:wrap}.user-view header{align-items:flex-start}}
/* 利润桥 */
.bridge{display:grid;gap:var(--sp-4)}
.bridge-row{display:grid;grid-template-columns:128px minmax(0,1fr) 118px;gap:var(--sp-3);align-items:center;font-size:var(--fs-xs)}
.bridge-label{color:var(--text-secondary)}
.bridge-value{text-align:right;font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--text-primary);font-weight:var(--fw-medium)}
.bar-bg{height:10px;border-radius:var(--r-full);background:var(--bg-subtle);border:1px solid var(--border);overflow:hidden}
/* 条形从左展开 + 行间 70ms 错峰，模拟瀑布「逐级扣减」的节奏；顶部内高光让条形更像实体 */
.bar{
  height:100%;border-radius:var(--r-full);min-width:2px;transition:width var(--dur-4) var(--ease-out);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22);
  transform-origin:left center;animation:lh-bar-grow var(--dur-4) var(--ease-out) backwards;
}
.bridge-row:nth-child(2) .bar{animation-delay:70ms}
.bridge-row:nth-child(3) .bar{animation-delay:140ms}
.bridge-row:nth-child(4) .bar{animation-delay:210ms}
@keyframes lh-bar-grow{from{transform:scaleX(0)}to{transform:scaleX(1)}}
/* 条形用横向渐变收尾，右侧逐渐淡出，避免「硬切」的方块感 */
.bar.income{background:linear-gradient(90deg,var(--pos),color-mix(in srgb,var(--pos) 55%,var(--bg-subtle)))}
.bar.cost{background:linear-gradient(90deg,var(--warn),color-mix(in srgb,var(--warn) 55%,var(--bg-subtle)))}
.bar.expense{background:linear-gradient(90deg,var(--neg),color-mix(in srgb,var(--neg) 55%,var(--bg-subtle)))}
.bar.admin{background:linear-gradient(90deg,var(--info),color-mix(in srgb,var(--info) 55%,var(--bg-subtle)))}
/* 分站点核算：一站点一卡（原横向长表在站点/字段多时读不动），
   全局合计不在此重复，统一由顶部 KPI 的「全站合计」标签承担 */
.site-cards{grid-template-columns:repeat(auto-fill,minmax(252px,1fr))}
.site-card{gap:var(--sp-2);min-height:0}
.site-card-name{display:flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.site-card-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-2) var(--sp-3);margin-top:auto}
/* 标签在上、金额在下：两列并排时标签与金额同排必然互相挤到省略号 */
.site-card-grid .sc-item{
  display:flex;flex-direction:column;gap:1px;min-width:0;
  font-size:var(--fs-2xs);color:var(--text-muted);
}
.site-card-grid .sc-item i{font-style:normal;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.site-card-grid .sc-item b{
  font-family:var(--font-mono);font-variant-numeric:tabular-nums;white-space:nowrap;
  color:var(--text-secondary);font-weight:var(--fw-medium);
}
.site-card-tail{display:inline-flex;align-items:center;gap:var(--sp-2);flex:0 0 auto}
.site-card-rpm{font-size:10px;font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--text-secondary)}
.site-card-rpm.is-stale{color:var(--text-muted)}
/* 汇总小卡片（成本与充值页面） */
.quick-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3)}
.quick{
  position:relative;
  border:1px solid var(--border);background:var(--bg-subtle);border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);
  transition:border-color var(--dur-2) var(--ease-out),background-color var(--dur-2) var(--ease-out);
}
@media (hover:hover) and (pointer:fine){
  .quick:hover{border-color:var(--border-strong);background:var(--bg-hover)}
}
.quick span{font-size:var(--fs-2xs);color:var(--text-muted);display:block;letter-spacing:.02em}
.quick b{display:block;margin-top:6px;font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:var(--fs-lg);color:var(--text-primary);font-weight:var(--fw-semibold);line-height:1.2}
/* 金额单元格 */
.amount{font-family:var(--font-mono);font-variant-numeric:tabular-nums;text-align:right}
.amount.pos{color:var(--pos)}
.amount.neg{color:var(--neg)}
.site-url{color:var(--text-muted);font-size:var(--fs-xs);max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.spark{width:100%;height:56px;display:block;overflow:visible}

/* --- 趋势图：使用主题令牌与 currentColor 适配双主题 --- */
.trend-head{display:flex;justify-content:space-between;align-items:center;gap:var(--sp-4);flex-wrap:wrap}
.trend-legend{display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap;color:var(--text-secondary);font-size:var(--fs-xs)}
.trend-legend li{display:inline-flex;align-items:center;gap:var(--sp-2);list-style:none}
.trend-legend .lg-line{width:15px;height:2px;border-radius:var(--r-full);flex:none;background:currentColor}
.trend-legend .lg-area{width:15px;height:10px;border-radius:var(--r-xs);flex:none;background:currentColor;opacity:.28}
.trend-legend .lg-line.lg-income{color:var(--pos)}
.trend-legend .lg-area.lg-income{color:var(--pos)}
.trend-legend .lg-line.lg-profit{color:var(--info)}
.trend-legend .lg-bar{width:9px;height:11px;border-radius:var(--r-xs);flex:none;background:currentColor;opacity:.75}
.trend-legend .lg-bar.lg-cost{color:var(--warn)}
/* 趋势时间范围切换（分段控件） */
.seg{display:inline-flex;border:1px solid var(--border);border-radius:var(--r-md);overflow:hidden}
.seg button{border:0;background:transparent;color:var(--text-secondary);font:inherit;font-size:var(--fs-xs);padding:5px 10px;cursor:pointer}
.seg button+button{border-left:1px solid var(--border)}
.seg button.active{background:var(--accent-soft);color:var(--accent-on-soft);font-weight:var(--fw-semibold)}
.trend-actions{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;justify-content:flex-end}
/* 图例「已隐藏」态：当前无 JS 应用该类（保留以备将来启用）。
   原为 opacity:.55（文字会掉到 ~2.6:1）；改为语义令牌 + 删除线，不再叠加 opacity。 */
.trend-legend .is-off{text-decoration:line-through;color:var(--text-muted)}
.trend-chart{margin-top:var(--sp-3);width:100%;font-size:var(--fs-2xs)}
.trend-chart svg{width:100%;height:224px;display:block;overflow:visible}
.trend-chart .tc-band{fill:currentColor;opacity:.02}
.trend-chart .tc-band.on{opacity:.055}
/* 网格与文字用 currentColor，颜色交给下列父级 → 主题切换自动跟随，无需重复定义令牌
   对比度（新调色板重算）：
   - .tc-axis 用 --text-secondary 且**不加 opacity**：暗色 #a7b1c0/#11151c = 8.06:1，
     浅色 #414c5e/#ffffff = 8.68:1 —— 10px 轴标签也稳稳过正文标准
   - .tc-zero 是「盈利/亏损」分界，属有意义的图形，@.7 后仍 >3:1
   - .tc-grid 为纯装饰网格线（数值由轴标签承担），保持低透明度不参与对比度要求 */
.trend-chart .tc-grid{stroke:currentColor;stroke-width:1;opacity:.14;stroke-dasharray:3 5}
.trend-chart .tc-zero{stroke:currentColor;stroke-width:1.2;opacity:.7;stroke-dasharray:none}
.trend-chart .tc-axis{fill:currentColor;color:var(--text-secondary);opacity:1;font-size:10px;font-family:var(--font-mono);font-variant-numeric:tabular-nums}
/* 面积填充改为 SVG 线性渐变（JS 内联 url(#lh-trend-income)，上浓下淡），
   比整块 16% 透明色更接近 Stripe 式「光晕面积图」 */
.trend-chart .tc-area{stroke:none}
.trend-chart .tc-line{fill:none;stroke:currentColor;stroke-width:1.9;stroke-linejoin:round;stroke-linecap:round}
.trend-chart .tc-dot{fill:currentColor;stroke:var(--bg-elevated);stroke-width:1.6}
.trend-chart .tc-dot-hot{fill:currentColor;stroke:var(--bg-elevated);stroke-width:2}
/* 序列末端点：当前值的落点标记，外圈描边把它从面积图上托出来 */
.trend-chart .tc-end{fill:currentColor;stroke:var(--bg-elevated);stroke-width:2}
/* 悬停层：默认让整张图忽略指针，只有热区条接收事件 */
.trend-chart{pointer-events:none}
.trend-chart .tc-hot{fill:transparent;pointer-events:all;cursor:crosshair}
/* 十字准线：悬停时贯穿图表，把「鼠标落在哪个 x 上」讲清楚（此前该样式类没有任何地方生成） */
.trend-chart .tc-hotline{stroke:var(--border-strong);stroke-width:1;stroke-dasharray:3 4;pointer-events:none}
.trend-chart .tc-tip{filter:drop-shadow(0 8px 18px rgba(0,0,0,.28))}
.trend-chart .tc-tip-bg{fill:var(--bg-elevated);stroke:var(--border-strong);stroke-width:1;opacity:1}
/* 逐类指定 fill 而不是依赖 color 继承：tip 组上挂着 .c-accent，
   继承会把「日期/收入/成本」这些标签也染成强调色，失去主次。 */
.trend-chart .tc-tip text{fill:var(--text-secondary);font-size:11px;font-family:var(--font-sans)}
.trend-chart .tc-tip text.tc-tip-v{fill:var(--text-primary);font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-weight:var(--fw-semibold);text-anchor:end}
.trend-chart .tc-tip text.tc-tip-v.c-pos{fill:var(--pos)}
.trend-chart .tc-tip text.tc-tip-v.c-neg{fill:var(--neg)}
.trend-chart .tc-tip text.tc-tip-v.c-warn{fill:var(--warn)}
.trend-chart .tc-tip text.tc-tip-v.c-info{fill:var(--info)}
/* 语义色令牌：SVG 元素不继承祖先的 color，需要在这里显式绑定 */
.trend-chart .c-pos{color:var(--pos)}
.trend-chart .c-neg{color:var(--neg)}
.trend-chart .c-warn{color:var(--warn)}
.trend-chart .c-info{color:var(--info)}
.trend-chart .c-muted{color:var(--text-muted)}
.trend-chart .c-accent{color:var(--accent)}
/* 趋势图下方的日汇总小卡 */
.trend-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:var(--sp-2);margin-top:var(--sp-4)}
.trend-stat{border:1px solid var(--border);border-radius:var(--r-md);background:var(--bg-subtle);padding:var(--sp-3)}
.trend-stat span{display:block;font-size:var(--fs-2xs);color:var(--text-muted)}
.trend-stat b{display:block;margin-top:4px;font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:var(--fs-md);font-weight:var(--fw-semibold);color:var(--text-primary);line-height:1.25}
.trend-stat b.pos{color:var(--pos)}.trend-stat b.neg{color:var(--neg)}.trend-stat b.warn{color:var(--warn)}.trend-stat b.info{color:var(--info)}

/* --- KPI 卡内利润口径 / 风险合并行 --- */
.metric-sub{font-size:var(--fs-2xs);color:var(--text-muted);font-family:var(--font-mono);font-variant-numeric:tabular-nums}
/* ===== hero 卡内嵌利润走势 sparkline（参考 Stripe / Linear 的 KPI 迷你图） =====
   颜色跟随 hero 语义变量 --hero-c（盈=绿 / 亏=红），面积渐变由 SVG defs 提供 */
.metric-spark{margin:calc(-1 * var(--sp-1)) calc(-1 * var(--sp-2)) 0;height:44px}
.metric.hero .metric-spark{color:var(--hero-c)}
.metric-spark svg{width:100%;height:44px;display:block;overflow:visible}
.metric-spark .ms-line{fill:none;stroke:currentColor;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.metric-spark .ms-dot{fill:currentColor;stroke:var(--bg-elevated);stroke-width:1.6}
.bridge-eq{border-top:1px solid var(--border);padding-top:var(--sp-3);margin-top:var(--sp-1)}
.bridge-eq .bridge-label{color:var(--text-primary);font-weight:var(--fw-semibold)}

.bridge-neg .bridge-value{color:var(--neg)}
.bridge-pos .bridge-value{color:var(--pos)}
.bridge-cost .bridge-value{color:var(--warn)}
.quick.wide{grid-column:1/-1}
.quick b.neg{color:var(--neg)}
.quick b.pos{color:var(--pos)}
.quick b.warn{color:var(--warn)}
.quick .quick-sub{display:block;margin-top:2px;font-size:var(--fs-2xs);color:var(--text-muted);line-height:1.5}

/* --- 流水页筛选 / 分页 / 错误态 --- */
.filters .field-wide{flex:1 1 240px}
.pager .pager-info{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.pager .pager-ctrl{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap}
.pager .pager-pages{display:flex;align-items:center;gap:4px}
.pager .page-btn{
  min-width:32px;height:32px;padding:0 var(--sp-2);
  border:1px solid var(--border-strong);border-radius:var(--r-md);
  background:var(--bg-subtle);color:var(--text-secondary);
  font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:var(--fs-xs);
  transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out);
}
@media (hover:hover) and (pointer:fine){
  .pager .page-btn:hover:not([disabled]){background:var(--bg-hover);color:var(--text-primary)}
}
.pager .page-btn[aria-current="page"]{background:var(--accent-soft);border-color:var(--accent-border);color:var(--accent-on-soft);font-weight:var(--fw-semibold);cursor:default}
.pager .page-btn[disabled]{opacity:.45;cursor:not-allowed}
.pager .pager-ellipsis{color:var(--text-muted);font-family:var(--font-mono);padding:0 2px}
.pager .pager-ctrl .select{width:auto;height:var(--ctl-h-sm);padding:0 var(--sp-7) 0 var(--sp-3);font-size:var(--fs-xs);background-position:right 8px center}
.table-error{
  display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);
  padding:var(--sp-3) var(--sp-5) var(--sp-3) calc(var(--sp-5) + 20px);
  position:relative;background:var(--neg-soft);border-bottom:1px solid var(--neg-border);
  color:var(--neg-on-soft);font-size:var(--fs-xs);flex-wrap:wrap;
}
.table-error::before{
  content:"";position:absolute;left:var(--sp-5);width:14px;height:14px;background:currentColor;
  -webkit-mask:var(--i-warn) center/contain no-repeat;mask:var(--i-warn) center/contain no-repeat;
}
.table-error p{margin:0;display:flex;align-items:center;gap:var(--sp-2)}
.load-bar{height:2px;background:var(--bg-subtle);overflow:hidden}
.load-bar span{display:block;height:100%;width:32%;border-radius:var(--r-full);background:linear-gradient(90deg,transparent,var(--accent),transparent);animation:lh-sweep 1.15s var(--ease-inout) infinite}
@keyframes lh-sweep{0%{transform:translateX(-110%)}100%{transform:translateX(420%)}}
tr.is-clickable{cursor:pointer}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* --- 站点管理 / 同步记录 / 全局交互 --- */
/* 面板内嵌提示条：紧贴面板顶部，去掉通用 .alert 的圆角与外边距 */
.panel-alert{margin:0;border-radius:0;border-left:0;border-right:0;border-top:0;padding-left:calc(var(--sp-5) + 20px)}
.panel-alert.show{margin:0}
.panel-alert::before{left:var(--sp-5)}
/* 字段级校验错误（就近显示在输入框下方） */
.field-hint{color:var(--text-3,var(--text-2));font-size:var(--fs-2xs);line-height:1.55;margin-top:4px}
.field-err{color:var(--neg-on-soft);font-size:var(--fs-2xs);line-height:1.55;display:flex;align-items:flex-start;gap:5px}
.field-err::before{
  content:"";flex:none;width:12px;height:12px;margin-top:2px;background:currentColor;
  -webkit-mask:var(--i-warn) center/contain no-repeat;mask:var(--i-warn) center/contain no-repeat;
}
/* 站点单元格 */
.site-name{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap}
.site-name strong{color:var(--text-primary);font-weight:var(--fw-semibold)}
.site-role{font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:var(--fs-xs);color:var(--text-secondary);line-height:1.7}
.site-when{font-size:var(--fs-xs);color:var(--text-secondary)}
.site-when .metric-note{margin-top:2px}
/* 行内错误块：跨列显示，长错误自动换行不撑破表格 */
.site-err-row>td{background:var(--neg-soft);border-bottom:1px solid var(--neg-border);white-space:normal!important;padding:var(--sp-3) var(--sp-4)}
/* 仅历史失败（当前已恢复）：保留警示但不与当前故障同色，避免误判 */
.site-err{display:flex;align-items:flex-start;gap:var(--sp-2);color:var(--neg-on-soft);font-size:var(--fs-xs);line-height:1.65}
.site-err .err-icon{
  flex:none;width:14px;height:14px;margin-top:2px;font-size:0;line-height:0;background:currentColor;
  -webkit-mask:var(--i-warn) center/contain no-repeat;mask:var(--i-warn) center/contain no-repeat;
}
.site-err .err-text{word-break:break-word;overflow-wrap:anywhere;min-width:0}
.site-err .err-tag{flex:none;font-weight:var(--fw-semibold)}
.site-err code{font-family:var(--font-mono);font-size:var(--fs-2xs);background:var(--bg-subtle);border:1px solid var(--neg-border);border-radius:var(--r-xs);padding:1px 5px;word-break:break-all}
/* 同步记录：耗时与错误摘要 */
.dur{font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:var(--fs-xs);color:var(--text-secondary)}
.dur.slow{color:var(--warn)}
tr.row-running{background:var(--info-soft)}
tr.row-failed>td{border-bottom-color:var(--neg-border)}
/* 分站点核算：合计行强调（与站点/同步表格共用 .data-table 基础样式） */
tr.row-total td{border-top:2px solid var(--accent-border);background:var(--bg-subtle)}
/* 充值记录：按天分组的组头行 */
tr.day-head td{background:var(--bg-subtle);color:var(--text-secondary);font-size:var(--fs-xs);font-weight:var(--fw-semibold);letter-spacing:.02em}
/* 筛选条里的按钮与下拉在窄屏下换行更自然 */
.filters .filters-end{margin-left:auto;display:flex;gap:var(--sp-2);align-items:flex-end}
/* 可点击表格行：键盘可达 */
tr.is-clickable{cursor:pointer}
tr.is-clickable:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

/* ============================================================
   6. 登录页
   ============================================================ */
.login-page{
  position:relative;overflow:hidden;
  min-height:100vh;display:grid;place-items:center;padding:var(--sp-5);
  background:
    radial-gradient(1000px 520px at 84% -14%,color-mix(in srgb,var(--accent) 20%,transparent) 0,transparent 62%),
    radial-gradient(760px 440px at 0% 108%,color-mix(in srgb,var(--accent-2) 16%,transparent) 0,transparent 60%),
    var(--bg-primary);
}
/* 动态极光：两团品牌色柔光缓慢漂移，登录页因此「活」起来。
   位移只动 transform（合成层），26s 一个循环几乎无性能成本；
   prefers-reduced-motion 由全局规则关停。 */
.login-page::after{
  content:"";position:absolute;inset:-18%;z-index:0;pointer-events:none;
  background:
    radial-gradient(560px 560px at 74% 20%,color-mix(in srgb,var(--accent) 15%,transparent) 0,transparent 66%),
    radial-gradient(660px 660px at 18% 86%,color-mix(in srgb,var(--accent-2) 13%,transparent) 0,transparent 68%);
  filter:blur(28px);
  animation:lh-drift 26s var(--ease-inout) infinite;
}
/* 细网格底纹 + 中心遮罩：给大片留白一点材质感，同时不干扰正文 */
.login-page::before{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background-image:
    linear-gradient(var(--border-soft) 1px,transparent 1px),
    linear-gradient(90deg,var(--border-soft) 1px,transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image:radial-gradient(circle at 50% 46%,#000 0,transparent 70%);
  mask-image:radial-gradient(circle at 50% 46%,#000 0,transparent 70%);
}
.login-shell{width:min(432px,100%);animation:lh-fade-up var(--dur-4) var(--ease-out) both;position:relative;z-index:2}
/* 主题开关固定在视口右上角，需高于卡片层，否则会被卡片拦截点击 */
.login-page .theme-toggle{position:fixed;top:var(--sp-5);right:var(--sp-5);z-index:5}
.login-box{
  background:var(--glass-bg-strong);backdrop-filter:blur(20px) saturate(1.4);-webkit-backdrop-filter:blur(20px) saturate(1.4);
  border:1px solid var(--border);border-radius:var(--r-2xl);
  padding:var(--sp-7);box-shadow:var(--sh-4),var(--sh-rim);
}
/* 登录页主视觉：由左上角 52px 方块图标改为居中大图横幅，
   用负 margin 顶到卡片上边缘，宽度铺满卡片内宽，圆角与卡片一致 */
.login-mark{
  margin:calc(var(--sp-7) * -1) calc(var(--sp-7) * -1) var(--sp-4);
  border-radius:var(--r-2xl) var(--r-2xl) 0 0;overflow:hidden;background:var(--bg-subtle);
  box-shadow:inset 0 -1px 0 var(--border);
}
.login-mark img{display:block;width:100%;height:clamp(156px,44vw,200px);object-fit:cover;object-position:50% 46%}
.login-box h1{font-size:var(--fs-xl);margin:var(--sp-2) 0 var(--sp-5);font-weight:var(--fw-semibold);text-align:center}
.login-box>p{color:var(--text-secondary);margin:0 0 var(--sp-6);font-size:var(--fs-sm);line-height:1.6}
.login-box .field{margin-top:var(--sp-4)}
.login-box .btn{
  width:100%;margin-top:var(--sp-6);height:var(--ctl-h-lg);font-size:var(--fs-base);
  /* 胶囊圆角 + 深墨蓝渐变：取自插画里的海与夜色，中性不与插画抢色 */
  border-radius:var(--r-full);border-color:rgba(255,255,255,.14);color:#fff;
  background:linear-gradient(135deg,#25395c 0%,#1b2a45 52%,#131e33 100%);
  box-shadow:0 14px 28px -14px rgba(18,30,52,.72),inset 0 1px 0 rgba(255,255,255,.18);
}
/* 悬停只在真有指针设备的场景生效（与全局按钮一致） */
@media (hover:hover) and (pointer:fine){
  .login-box .btn:hover{
    background:linear-gradient(135deg,#2d4368 0%,#21324f 52%,#18253d 100%);
    border-color:rgba(255,255,255,.2);
    box-shadow:0 18px 34px -14px rgba(18,30,52,.78),inset 0 1px 0 rgba(255,255,255,.24);
  }
}

/* ============================================================
   7. 响应式
   断点：1400 / 1260 / 1080 / 900（抽屉）/ 760（表格卡片化）/ 720 / 480
   ============================================================ */
@media (max-width:1400px){
  .cards{grid-template-columns:repeat(4,minmax(0,1fr))}
}
@media (max-width:1260px){
  .cards{grid-template-columns:repeat(3,minmax(0,1fr))}
  .layout-2,.site-grid{grid-template-columns:1fr}
}
@media (max-width:1080px){
  :root{--sidebar-w:224px}
  .content{padding:var(--sp-6) var(--sp-5) var(--sp-8)}
  .topbar{padding:0 var(--sp-5)}
}
@media (max-width:900px){
  /* 抽屉模式：侧栏绝对定位 + 位移，绝不用 display:none（否则按钮尺寸为 0×0） */
  .sidebar{
    position:fixed;top:0;left:0;bottom:0;height:100vh;width:min(290px,86vw);
    transform:translateX(-100%);transition:transform var(--dur-3) var(--ease-out);
    box-shadow:var(--sh-4);border-right:1px solid var(--border-strong);
    padding-top:max(var(--sp-5),env(safe-area-inset-top));
    padding-bottom:max(var(--sp-5),env(safe-area-inset-bottom));
  }
  .sidebar.is-open{transform:translateX(0)}
  .mobile-menu{display:grid}
  /* 抽屉模式下顶栏只保留汉堡按钮 + 玻璃条，账号入口在抽屉底部 */
  .topbar{display:flex;padding:0 var(--sp-4);gap:var(--sp-3);height:60px}
  .toast-stack{top:auto}
  :root{--topbar-h:60px}
  .content{padding:var(--sp-5) var(--sp-4) var(--sp-8)}
  .cards{grid-template-columns:repeat(2,minmax(0,1fr))}
}
/* 760px 以下：表格不再横向拖拽，每行拆成「标签 / 值」的卡片
   —— 手机上读一条流水不需要左右来回推 760px 宽的表格。 */
@media (max-width:760px){
  .data-table.stack{min-width:0;display:block}
  .data-table.stack thead{display:none}
  .data-table.stack tbody{display:block}
  .data-table.stack tr{display:block;padding:var(--sp-2) var(--sp-4);border-bottom:1px solid var(--border)}
  .data-table.stack tr:last-child{border-bottom:0}
  .data-table.stack td,
  .data-table.stack th{
    display:grid;grid-template-columns:84px minmax(0,1fr);
    gap:var(--sp-3);align-items:baseline;
    width:auto;min-width:0;padding:3px 0;border:0;white-space:normal;text-align:left;
  }
  /* ::before 占第 1 列，单元格自身的子元素一律落到第 2 列并自动换行 */
  .data-table.stack td::before{
    content:attr(data-label);
    color:var(--text-muted);font-size:var(--fs-2xs);line-height:1.75;
  }
  .data-table.stack td>*{grid-column:2;min-width:0}
  .data-table.stack .cell-truncate,
  .data-table.stack .col-num,
  .data-table.stack .cell-num,
  .data-table.stack .amount{text-align:left}
  /* 跨列单元格（空状态 / 行内错误详情）：两种布局都要占满整行 */
  .data-table.stack td[colspan]{display:block;padding:0;grid-template-columns:1fr}
  .data-table.stack td[colspan]::before{content:none}
  .data-table.stack td[colspan]>*{grid-column:1}
  .data-table.stack .site-err-row>td{padding:var(--sp-3) var(--sp-4)}
}
@media (max-width:720px){
  .page-head{margin-bottom:var(--sp-4)}
  /* 统计区间工具条窄屏改为纵向堆叠，控件撑满一行 */
  .range-bar{align-items:stretch;flex-direction:column;gap:var(--sp-2)}
  .range-bar .range-title{padding-right:0;border-right:none}
  .range-controls{flex-direction:column;align-items:stretch}
  .range-bar .select,.range-bar .input{width:100%;max-width:none;min-width:0}
  .range-bar #rangeToField{width:100%}
  .range-bar #rangeToField::before{display:none}
  .range-bar .range-meta{margin-left:0;text-align:center}
  .actions{width:100%}
  .actions .btn{flex:1}
  .metric{min-height:96px;padding:var(--sp-3) var(--sp-4)}
  .metric-value{font-size:var(--fs-lg)}
  .metric.hero .metric-value{font-size:var(--fs-xl)}
  .metric-note{display:none}
  .bridge-row{grid-template-columns:1fr auto;gap:var(--sp-1) var(--sp-3)}
  .bridge-row .bar-bg{grid-column:1/-1;order:3}
  .trend-chart svg{height:190px}
  .pager{justify-content:center}
  .pager .pager-info{width:100%;text-align:center}
  .form-grid{grid-template-columns:1fr}
  .quick-grid{grid-template-columns:1fr 1fr}
  /* 分站点核算卡：窄屏单列，避免小字被挤到换行 */
  .site-cards{grid-template-columns:1fr}
  .filters{padding:var(--sp-3) var(--sp-4);gap:var(--sp-3) var(--sp-2)}
  .filters .field{flex:1 1 44%;min-width:0}
  .filters .search{flex:1 1 100%}
  .panel-body{padding:var(--sp-4)}
  .panel-head{padding:0 var(--sp-4)}
  .toast-stack{left:var(--sp-4);right:var(--sp-4);max-width:none;top:auto;bottom:calc(var(--sp-4) + env(safe-area-inset-bottom))}
  .modal{padding:var(--sp-3);align-items:flex-end}
  .modal-card{width:100%;max-height:92vh;border-radius:var(--r-xl) var(--r-xl) 0 0}
  .site-err{font-size:var(--fs-xs)}
  .filters .filters-end{margin-left:0;width:100%}
  .filters .filters-end .btn{flex:1}
}
@media (max-width:480px){
  .cards{grid-template-columns:1fr}
  .metric.hero{grid-column:auto}
  .metric-note{display:block}
  .metric{min-height:0}
  .actions .btn{height:var(--ctl-h-lg)}
  /* 退出按钮保留（不能为了排版牺牲功能），只压缩内边距 */
  .logout{padding:0 var(--sp-2)}
}

/* ============================================================
   8. 无障碍 / 降级
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important;
  }
}
/* 只读账号：隐藏全部写入口，只保留查看（服务端同样按角色拦截写操作，这里只做界面收敛） */
body.role-viewer [data-view-jump="costs"],
body.role-viewer #costFormPanel,
body.role-viewer #siteFormPanel,
body.role-viewer #syncIntervalField,
body.role-viewer #saveSyncInterval,
body.role-viewer #openAccount,
body.role-viewer #siteOpsHead,
body.role-viewer #costOpsHead,
body.role-viewer #siteRows td[data-label="操作"],
body.role-viewer #costRows td[data-label="操作"]{display:none!important}
/* 已标记删除的成本流水：保留在列表里，但视觉上明确区分，金额划掉表示不计入统计 */
.data-table tr.row-deleted > td{opacity:.6}
.data-table tr.row-deleted .amount{text-decoration:line-through}
/* 站点表单隐藏后，列表独占整行，避免右侧留出空白列 */
body.role-viewer .site-grid{grid-template-columns:minmax(0,1fr)}

/* 高对比模式：交给系统配色，去掉玻璃、渐变与一切纯装饰层，保证信息不依赖半透明叠加 */
@media (forced-colors:active){
  body{background-image:none}
  .panel,.metric,.card,.modal-card,.btn,.input,.select,.badge,.toast{border:1px solid CanvasText}
  .login-page::after,.btn-primary::after,.metric.hero::before{display:none}
  .brand-logo,.load-bar span,.bar,.metric.hero::after,.nav button.active::before{forced-color-adjust:none}
}
/* 打印：强制浅色令牌（深色底打印会糊成一片），并避免表格行被切断 */
@media print{
  :root,[data-theme]{
    --bg-void:#fff;--bg-primary:#fff;--bg-elevated:#fff;--bg-subtle:#f5f5f5;
    --bg-hover:#f0f0f0;--bg-active:#e8e8e8;--border:#c9c9c9;--border-strong:#9a9a9a;
    --text-primary:#000;--text-secondary:#333;--text-muted:#555;--text-ghost:#666;
    --glass-bg:#fff;--glass-bg-strong:#fff;--glass-border:#c9c9c9;--sh-1:none;--sh-2:none;--sh-3:none;--sh-4:none;--sh-rim:none;
  }
  body{background:#fff}
  .sidebar,.topbar,.scrim,.actions,.mobile-menu,.toast-stack,.load-bar,.modal-close,.pager-ctrl{display:none!important}
  .content{padding:0;max-width:none}
  .panel{border:1px solid #c9c9c9;break-inside:avoid}
  .panel-head{border-bottom:1px solid #c9c9c9}
  .data-table{min-width:0}
  .data-table tr{break-inside:avoid}
  .data-table th,.data-table td{color:#000}
}

#topupStats{grid-template-columns:repeat(3,minmax(0,1fr))}
#topupStats:has(> :nth-child(4)){grid-template-columns:repeat(4,minmax(0,1fr))}
@media(max-width:600px){#topupStats,#topupStats:has(> :nth-child(4)){grid-template-columns:repeat(2,minmax(0,1fr))}}

.category-tools{display:flex;gap:var(--sp-2);flex-wrap:wrap;margin:var(--sp-3) 0}
.category-list{max-height:50dvh;overflow:auto;margin:var(--sp-3) 0}
#customUsageDialog[open],#um-categoryUsersDialog[open],#um-categoryManagerDialog[open],#um-ratiosDialog[open]{display:flex;flex-direction:column;overflow:hidden}
:is(#customUsageDialog,#um-categoryUsersDialog,#um-categoryManagerDialog,#um-ratiosDialog)>:is(h2,p,.dialog-actions){flex:none}
:is(#customUsageDialog,#um-categoryUsersDialog,#um-categoryManagerDialog)>.category-list,#um-ratiosContent{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain}
.category-list-row{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);padding:var(--sp-3) 0;border-bottom:1px solid var(--border)}
.category-list-row>span{min-width:0;overflow-wrap:anywhere;font-size:var(--fs-xs)}
.category-list-row>.row-actions{display:flex;flex-wrap:wrap;gap:var(--sp-2);flex-shrink:0}

.usage-overview-detail{align-items:center}
.usage-other{padding:0 6px;border:1px solid var(--border);border-radius:var(--r-md);color:var(--accent);background:var(--bg-subtle);font:inherit;line-height:1.5;cursor:pointer;white-space:nowrap}

/* Pool console: stable table, explicit scopes, capability-based controls. */
.pool-summary{display:flex;flex-wrap:wrap;gap:12px 24px;padding:12px 0 18px}.pool-summary b{font-size:18px;margin-left:6px}
.pool-filters{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:16px 0}.pool-filters input{flex:1 1 220px;min-width:160px}.pool-filters select{width:auto;max-width:190px}
.pool-batch-actions{padding-bottom:8px;border-bottom:1px solid var(--border)}
.pool-account-table{min-width:950px}.pool-account-table td{vertical-align:top;max-width:260px;overflow-wrap:anywhere}.pool-account-table small{display:block;margin-top:4px;color:var(--text-secondary)}.pool-account-table input[type=checkbox]{width:auto}
.pool-row-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;min-width:150px}.pool-row-actions button{min-width:0;padding:5px 8px}
.pool-quota{min-width:145px;display:grid;gap:6px}.pool-quota meter{display:block;width:100%;height:8px}.pool-quota small{font-size:11px}
.pool-pagination{display:flex;justify-content:flex-end;align-items:center;gap:12px;margin:16px 0}
.pool-jobs{border-top:1px solid var(--border);padding-top:12px}.pool-jobs summary{cursor:pointer}.pool-jobs>div{display:grid;gap:6px;padding:12px 0;border-bottom:1px solid var(--border)}.pool-jobs pre{white-space:pre-wrap;max-height:150px;overflow:auto;color:var(--neg);font-size:12px}.pool-jobs small{color:var(--text-secondary)}.pool-jobs progress{width:100%}
.pool-targets{display:grid;gap:10px;max-height:240px;overflow:auto}.pool-targets label{display:flex;gap:8px;align-items:center}.pool-targets input{width:auto}

.pool-distribution-group{display:grid;gap:6px;margin:10px 0;padding:12px;border:1px solid var(--border);border-radius:8px}#pool-bindingChoices label{justify-content:space-between}#pool-bindingChoices select{width:120px}#pool-uploadDialog{width:min(740px,95vw)}

body.role-viewer #pool-settings,body.role-viewer #pool-bindings,body.role-viewer #pool-cards [data-action]:not([data-action="refresh"]):not([data-action="previous"]):not([data-action="next"]):not([data-action="copy-errors"]):not([data-action="clear-selection"]):not([data-action="download"]){display:none!important}

/* 渠道核算：表头与列内容统一居中，长名称允许换行。 */
#credentialProfitDialog .data-table th,
#credentialProfitDialog .data-table td{
  text-align:center;
  vertical-align:middle;
}
#credentialProfitDialog .data-table td:first-child,
#credentialProfitDialog .data-table td:last-child{
  white-space:normal;
  overflow-wrap:anywhere;
}

/* Notification projects share a compact row layout. */
.notification-projects{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}
.notification-project-row{display:flex;align-items:center;gap:16px;padding:18px 24px;min-width:0}
@media(max-width:760px){.notification-projects{grid-template-columns:1fr}}
.notification-project-name{flex:1;font-weight:600;min-width:0}
.notification-switch{position:relative;display:inline-flex;flex:none;width:42px;height:24px;cursor:pointer}
.notification-switch input{position:absolute;inset:0;opacity:0;width:100%;height:100%;margin:0;cursor:pointer}
.notification-switch span{width:42px;height:24px;border-radius:20px;background:#9ca3af;pointer-events:none;transition:background .15s}
.notification-switch span::after{content:'';display:block;width:18px;height:18px;margin:3px;border-radius:50%;background:white;transition:transform .15s}
.notification-switch input:checked+span{background:#16a34a}
.notification-switch input:checked+span::after{transform:translateX(18px)}
.notification-switch input:focus-visible+span{outline:2px solid #3b82f6;outline-offset:3px}
.notification-switch input:disabled+span{opacity:.5}

#view-errors .page-head .actions{flex-wrap:wrap;align-items:end}
#view-errors .page-head label{display:grid;gap:6px;color:var(--text-secondary);font-size:12px}
.error-snapshot{display:flex;justify-content:space-between;gap:12px;color:var(--text-secondary);font-size:12px;margin-bottom:16px}
#errorOverview{grid-template-columns:repeat(4,minmax(0,1fr));margin-bottom:20px}
#errorOverview .metric-value{font-size:clamp(22px,2.4vw,34px)}
.error-analysis-grid{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-bottom:20px}
.error-distribution-row{display:block;width:100%;border:0;background:transparent;color:inherit;text-align:left;padding:12px 0}
button.error-distribution-row{cursor:pointer}
button.error-distribution-row:hover{background:var(--bg-hover)}
.error-distribution-label{display:flex;justify-content:space-between;gap:16px;margin-bottom:9px}
.error-distribution-label small{color:var(--text-secondary);margin-left:12px}
.error-bar{height:7px;background:var(--bg-hover);border-radius:6px;overflow:hidden}
.error-bar span{display:block;height:100%;background:var(--warn,#eab308);border-radius:6px}
#errorSites .error-bar span{background:var(--info,#60a5fa)}
.error-empty{padding:28px;text-align:center;color:var(--text-secondary)}
.error-reasons-table{table-layout:fixed;width:100%}
.error-reasons-table th:first-child{width:64px}.error-reasons-table th:nth-last-child(-n+2){width:90px}
.error-reasons-table td:not(:nth-child(2)){text-align:center;font-variant-numeric:tabular-nums}
.error-reason summary{cursor:pointer;overflow-wrap:anywhere;line-height:1.6}
.error-reason pre{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;background:var(--bg-hover);padding:12px;border-radius:8px}
.error-rank{color:var(--text-secondary)}
@media(max-width:900px){#errorOverview{grid-template-columns:repeat(2,minmax(0,1fr))}.error-analysis-grid{grid-template-columns:1fr}}
@media(max-width:480px){.error-snapshot{flex-direction:column}.error-reasons-table th:nth-last-child(-n+2){width:60px}}

/* 经营总览：缓存率 */
#cacheRateMinutes{width:auto;min-width:115px}
.cache-rate-metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:4px 0}
.cache-rate-metrics>div{display:flex;flex-direction:column;align-items:center;gap:6px;text-align:center}
.cache-rate-metrics>div:nth-child(even){border-left:1px solid var(--border)}
.cache-rate-metrics span{font-size:var(--fs-xs);color:var(--text-secondary)}
.cache-rate-metrics strong{font-size:24px;font-family:var(--font-mono);color:var(--accent-on-soft);line-height:1.2}
.cache-rate-metrics small{font-size:12px;margin-left:3px}

.cache-rate-metrics .cache-error-metric{border-top:1px solid var(--border);padding-top:8px}
.cache-error-metric strong{color:var(--warn)}

.cache-error-count{border:0;background:none;padding:0;font:700 24px/1.2 var(--font-mono);color:var(--warn);cursor:pointer;text-decoration:underline;text-decoration-style:dotted;text-underline-offset:4px}
.cache-error-count:hover{color:var(--accent-on-soft)}
#errorDetailsDialog .table-wrap{max-height:65vh;overflow:auto}
