/* 陪玩店财务系统 · 前台样式
 *
 * 设计取向：前台上机环境光线杂、老板在旁边看，所以对比度拉高、字号偏大、
 * 关键数字用等宽字体对齐小数点。核心动作（查余额/报单）≤3 次点击。
 *
 * ── 配色体系 ──
 * 底色走**中性灰**而不是带蓝调的深色：中后台信息密度高，
 * 带色相的底会让表格和数字发闷，中性灰则把注意力全留给内容。
 * 灰阶分五档（页面/卡片/输入/hover/边框），互不重复，层次靠明度差而不是描边。
 *
 * 主色用「色阶」而不是散落的 rgba：由 --accent 按 10% 步进混白混黑生成 9 级，
 * 这样 hover、选中底、淡背景、边框都能从同一个主色推出来，
 * 以后换主题色只改 --accent 一行，不用满文件找 rgba。
 */

* { box-sizing: border-box; margin: 0; padding: 0; }

/* ═══════════════════════════════════════════════════════════
   主题：双套变量，同名互换
   ═══════════════════════════════════════════════════════════
   规则只有一条：**除了这个文件开头，别处不允许出现色值**。
   两套主题用同一批变量名，切换时只换值，不动任何选择器。

   深色写在 :root（默认），浅色写在 html[data-theme="light"] 覆盖。
   这样即使 JS 没跑起来、data-theme 没写上，页面也是可用的深色，
   不会出现「变量全空 → 白底白字」的灾难。

   注意三处必须跟着主题走的语义色，不能一套用到底：
     1. --*-fg（语义色作文字）：深色底上要提亮，浅色底上要压暗
     2. --*-aNN（语义色淡底）：浅色底上要更淡，否则像色块
     3. --sh-*（阴影）：深色界面靠明度分层，浅色界面才真的靠阴影
   ═══════════════════════════════════════════════════════════ */

:root {
  /* ——— 灰阶 ———
     一条连续阶梯，每档有明确职责，不允许「差不多」的野生色值：
       页面底 < 侧栏 < 卡片 < 输入 < 悬浮 < hover < 边框
     深色下层次靠明度差建立，浅色下靠极淡的灰 + 阴影。 */
  --bg: #0f1117;          /* 页面底 */
  --rail: #12151c;        /* 侧栏 */
  --panel: #171a21;       /* 卡片 */
  --panel-2: #1e222b;     /* 输入框 / 次级块 */
  --panel-3: #262b35;     /* hover 态、禁用底 */
  --hover: #1a1e26;       /* 表格行悬浮 */
  --sunken: #161a21;      /* 凹陷块（只读金额、聚焦输入底） */
  --line: #2c3240;        /* 常规分隔线 */
  --line-soft: #222731;   /* 表格行细分隔线 */
  --line-strong: #3a4252; /* 需要强调的边框 */
  --scroll: #333a48;

  /* ——— 文字：四级，靠明度差别而不是字号 ——— */
  --fg: #e8ecf3;
  --fg-2: #b6bfd0;
  --fg-dim: #838e9f;
  --fg-mute: #5d6779;
  /* 强调用的最亮一档。深色下是纯白，浅色下必须压成近黑 ——
     写死 #fff 的地方在浅色主题里会变成「白底白字」。 */
  --fg-strong: #ffffff;
  /* 与背景反向的文字（按钮上的字）。深色主题按钮是深蓝底配白字；
     浅色主题同理，所以两套都用白，但单独留变量以便日后调。 */
  --on-accent: #ffffff;
  /* 需要「比正文更弱」的虚线、分隔装饰 */
  --dash: rgba(255, 255, 255, .14);
  /* 浮层页脚压暗（深色）或压灰（浅色） */
  --foot-tint: rgba(0, 0, 0, .16);

  /* ——— 主色与语义色（基色，两套主题共用） ——— */
  --accent: #4a9eff;
  --accent-deep: #2d6bb8;
  --ok: #3ecf8e;
  --warn: #f5a623;
  --danger: #ff5c5c;
  --danger-deep: #b93b3b;
  --deposit: #8b6cff;

  /* ——— 语义色作「文字」时的版本：深色底要提亮 ——— */
  --danger-fg: #ff9b9b;
  --danger-fg-2: #ff8f8f;
  --danger-fg-3: #ff8080;
  --ok-fg: #7fe0b6;
  --warn-fg: #f5a623;
  --deposit-fg: #b3a0ff;

  /* ——— 主色色阶与透明度 ——— */
  --accent-l1: #5ca8ff;
  --accent-l2: #6eb2ff;
  --accent-l3: #80bbff;
  --accent-l4: #92c5ff;
  --accent-l5: #a5ceff;
  --accent-l6: #b7d8ff;
  --accent-l7: #c9e2ff;
  --accent-a08: rgba(74, 158, 255, .08);
  --accent-a14: rgba(74, 158, 255, .14);
  --accent-a22: rgba(74, 158, 255, .22);
  --accent-a35: rgba(74, 158, 255, .35);

  /* ——— 语义色淡底 ——— */
  --ok-a10: rgba(62, 207, 142, .10);
  --ok-a20: rgba(62, 207, 142, .20);
  --warn-a10: rgba(245, 166, 35, .10);
  --warn-a22: rgba(245, 166, 35, .22);
  --danger-a08: rgba(255, 92, 92, .08);
  --danger-a20: rgba(255, 92, 92, .20);
  --deposit-a14: rgba(139, 108, 255, .14);

  /* 侧栏选中项的「实心胶囊」。深色主题下反而要用浅色胶囊才跳得出来 ——
     整个界面是深底，再给个深胶囊就糊在一起了。 */
  /* ——— 液态质感 ———
     深色底上「高光」要很克制，太亮会显得油腻；内阴影同理。 */
  --glass-tint: .035;        /* 卡片左上角的白色渐变强度 */
  --glass-edge: .06;         /* 顶部高光边的强度 */
  --glass-glow: .05;         /* 鼠标跟光的强度 */
  --glass-hover-line: var(--line-strong);
  --glass-lift: .3;          /* 悬浮时的投影浓度 */

  --nav-on-bg: #f0f3f8;
  --nav-on-fg: #12151c;
  --nav-on-sh: 0 2px 10px rgba(0, 0, 0, .35);

  --scroll-hover: rgba(71, 80, 97, .5);
  --toast-err-bg: #3a2020;
  --toast-suc-bg: #16302a;

  /* ——— 圆角 ——— */
  --r-sm: 5px;
  --r: 7px;
  --r-lg: 10px;

  /* 登录页左侧品牌区的渐变。深色主题下用亮一点的蓝，浅色下压深显得沉稳。 */
  --brand-grad: linear-gradient(160deg, var(--accent-l1) 0%, var(--accent-deep) 100%);
  /* 品牌区里的半透明白（标签底、装饰条）——白底蓝渐变上要用白，深底上同理 */
  --brand-fg: #ffffff;

  /* 卡片描边宽度。深色下卡片和背景明度接近，必须描边才分得清；
     浅色下靠阴影就够了，描边可以更淡 —— 所以做成变量。 */
  --card-line: var(--line);

  /* 阴影：深色界面靠阴影分层是无效的，只用它压住浮层 ——— */
  --sh-pop: 0 16px 40px rgba(0, 0, 0, .55);
  --sh-card: 0 1px 2px rgba(0, 0, 0, .22);

  color-scheme: dark;
}

/* ═══════════ 浅色 ═══════════
   不是把深色「反过来」那么简单：
   浅底上灰阶的层次感弱得多，所以要靠更明显的边框 + 真实的阴影补回来，
   否则整页会糊成一片白。 */
html[data-theme="light"] {
  --bg: #f5f6f8;          /* 页面底：带一点冷灰，纯白太刺眼 */
  --rail: #ffffff;        /* 侧栏比内容白，形成前后关系 */
  --panel: #ffffff;       /* 卡片纯白 */
  --panel-2: #f7f8fa;     /* 输入框 */
  --panel-3: #eef0f4;     /* hover 态 */
  --hover: #f7f8fa;
  --sunken: #f2f4f7;
  --line: #e3e6ec;        /* 浅底上边框要收着点，太深会显得脏 */
  --line-soft: #eef0f4;
  --line-strong: #cfd4de;
  --scroll: #c8cdd6;

  --fg: #1c2029;
  --fg-2: #4a5160;
  --fg-dim: #6b7280;
  --fg-mute: #9aa1ad;
  /* 浅色下「强调」是更深，不是更白 */
  --fg-strong: #0d1017;
  --on-accent: #ffffff;
  --dash: rgba(0, 0, 0, .12);
  --foot-tint: rgba(20, 26, 38, .03);

  /* 主色在浅底上要压深，否则按钮上的白字看不清 */
  --accent: #2b7de9;
  --accent-deep: #1f66c9;

  /* 语义色作文字时要压暗 —— 深色那套 #ff9b9b 放在白底上根本读不出来 */
  --danger-fg: #c0392b;
  --danger-fg-2: #b93b3b;
  --danger-fg-3: #a52f2f;
  --ok-fg: #16794f;
  --warn-fg: #96650a;
  --deposit-fg: #6244c9;

  --accent-l1: #4a91ee;
  --accent-l2: #69a3f1;
  --accent-l3: #88b6f4;
  --accent-l4: #a7c8f7;
  --accent-l5: #c5dbfa;
  --accent-l6: #e4edfc;
  --accent-l7: #f2f7fe;
  --accent-a08: rgba(43, 125, 233, .07);
  --accent-a14: rgba(43, 125, 233, .12);
  --accent-a22: rgba(43, 125, 233, .2);
  --accent-a35: rgba(43, 125, 233, .32);

  /* 淡底在浅色下要更淡，否则像贴了块色纸 */
  --ok-a10: rgba(22, 121, 79, .09);
  --ok-a20: rgba(22, 121, 79, .18);
  --warn-a10: rgba(150, 101, 10, .09);
  --warn-a22: rgba(150, 101, 10, .18);
  --danger-a08: rgba(192, 57, 43, .07);
  --danger-a20: rgba(192, 57, 43, .16);
  --deposit-a14: rgba(98, 68, 201, .1);

  /* 浅色下卡片已靠阴影浮起，但描边仍要看得见 ——
     用 --line-soft(#eef0f4) 贴 #f5f6f8 的底几乎量不出来，卡片会糊成一片。
     这里取 --line 再淡一点点，配合阴影刚好。 */
  --card-line: #e8ebf0;
  /* 浅色下品牌区用更深的蓝，白字才压得住 */
  --brand-grad: linear-gradient(160deg, #3f8fee 0%, #1f5fb8 100%);

  --scroll-hover: rgba(120, 128, 140, .5);
  /* 浅色下白卡片本身就是「亮」的，高光要更轻，否则一片惨白；
     但要靠投影把浮起感补回来。 */
  --glass-tint: .5;
  --glass-edge: .9;
  --glass-glow: .5;
  --glass-hover-line: var(--line-strong);
  --glass-lift: .12;

  /* 浅色主题下侧栏是白的，选中胶囊就用深色实心 + 白字（和截图一致） */
  --nav-on-bg: #1c2029;
  --nav-on-fg: #ffffff;
  --nav-on-sh: 0 2px 10px rgba(20, 26, 38, .22);
  --toast-err-bg: #fdecea;
  --toast-suc-bg: #e8f7f0;

  /* 浅色界面靠阴影分层是真的有效，所以给得实一些 */
  --sh-pop: 0 12px 32px rgba(20, 26, 38, .14), 0 2px 6px rgba(20, 26, 38, .06);
  --sh-card: 0 1px 2px rgba(20, 26, 38, .06), 0 1px 3px rgba(20, 26, 38, .05);

  color-scheme: light;
}

body {
  background: var(--bg);
  color: var(--fg);
  font-family: Inter, -apple-system, "Segoe UI", "PingFang SC",
    "Microsoft YaHei", "微软雅黑", sans-serif;
  font-size: 14px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* 滚动条：细、圆、hover 才显眼 —— 默认太抢眼会打断阅读 */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--scroll); border-radius: 8px;
  border: 2px solid transparent; background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--scroll-hover); background-clip: content-box; }

/* 数字：等宽 + 表格数位，金额竖排能对齐小数点 */
.num {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.2px;
}

/* 焦点可见性：键盘操作时必须有明确反馈，鼠标点则不显示（:focus-visible） */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ————— 登录 —————
   左右分栏：左边品牌区（蓝底，交代这是什么产品），右边表单区（干净，专注输入）。
   窄屏时品牌区收起，只留表单，避免手机上要滚半天才看到输入框。 */
#login {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; padding: 24px;
  background: var(--bg);
}
.login-card {
  display: grid; grid-template-columns: 380px 1fr;
  width: 100%; max-width: 880px;
  background: var(--panel);
  border: 1px solid var(--card-line);
  border-radius: 16px; overflow: hidden;
  box-shadow: var(--sh-pop);
}

/* ——— 左：品牌区 ——— */
.login-brand {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column;
  padding: 30px 30px 22px;
  background: var(--brand-grad);
  color: var(--brand-fg);
}
/* 一层极淡的光斑，避免大块纯蓝显得死板 */
.login-brand::after {
  content: ''; position: absolute; right: -80px; top: -60px;
  width: 260px; height: 260px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, .16), transparent 68%);
}
.lb-logo { display: flex; align-items: center; gap: 11px; position: relative; z-index: 1; }
/* 品牌标记：Logo 图片本身是透明底（PNG 带 alpha），
   小羊有黑色轮廓线，直接放在蓝色渐变上就能看清 ——
   不用垫白底，垫了会在图上多出一个方块。 */
.lb-mark {
  width: 36px; height: 36px; flex: none;
  display: grid; place-items: center;
}
.lb-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
.lb-mark.sm { width: 30px; height: 30px; }
.lb-name { font-size: 15px; font-weight: 600; line-height: 1.25; letter-spacing: .3px; }
.lb-name small {
  display: block; font-size: 10px; font-weight: 400;
  letter-spacing: 1px; opacity: .75;
}

.lb-body { margin: 34px 0 0; position: relative; z-index: 1; }
.lb-body h1 { font-size: 24px; line-height: 1.42; letter-spacing: .5px; margin-bottom: 12px; }
.lb-body p { font-size: 13px; line-height: 1.75; opacity: .82; }

.lb-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; position: relative; z-index: 1; }
.lb-tag {
  font-size: 11.5px; padding: 5px 11px; border-radius: 20px;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .2);
  white-space: nowrap;
}

/* 装饰用的界面骨架：让「这是个后台系统」一眼可读 */
.lb-art {
  margin-top: auto; margin-bottom: 18px;
  border-radius: 10px; overflow: hidden; position: relative; z-index: 1;
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .18);
  opacity: .9;
}
.lb-art-bar {
  display: flex; gap: 5px; padding: 8px 10px;
  background: rgba(255, 255, 255, .1);
}
.lb-art-bar i { width: 7px; height: 7px; border-radius: 50%; background: rgba(255, 255, 255, .45); }
.lb-art-body { display: flex; gap: 8px; padding: 10px; }
.lb-art-side { display: flex; flex-direction: column; gap: 6px; width: 46px; flex: none; }
.lb-art-side i { height: 7px; border-radius: 3px; background: rgba(255, 255, 255, .3); }
.lb-art-main { flex: 1; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.lb-art-kpis { display: flex; gap: 6px; }
.lb-art-kpis i { flex: 1; height: 26px; border-radius: 5px; background: rgba(255, 255, 255, .24); }
.lb-art-rows { display: flex; flex-direction: column; gap: 5px; }
.lb-art-rows i { height: 6px; border-radius: 3px; background: rgba(255, 255, 255, .18); }
.lb-art-rows i:nth-child(2) { width: 78%; }
.lb-art-rows i:nth-child(3) { width: 62%; }

.lb-foot { font-size: 11px; opacity: .7; position: relative; z-index: 1; }

/* ——— 右：表单区 ——— */
.login-form {
  padding: 34px 40px 28px;
  display: flex; flex-direction: column;
  min-width: 0;
}
.lf-logo {
  display: flex; align-items: center; gap: 9px;
  font-size: 14px; font-weight: 600; color: var(--fg);
  justify-content: center; margin-bottom: 22px;
}
.lf-tab {
  align-self: center;
  font-size: 12px; color: var(--accent);
  background: var(--accent-a08);
  border: 1px solid var(--accent-a22);
  padding: 4px 14px; border-radius: 20px; margin-bottom: 18px;
}
.login-form h2 { font-size: 21px; text-align: center; letter-spacing: .5px; margin-bottom: 6px; }
.lf-sub { font-size: 13px; color: var(--fg-dim); text-align: center; margin-bottom: 22px; }
.login-form form { display: flex; flex-direction: column; }
.login-form .field + .field { margin-top: 14px; }
.login-form button[type=submit] {
  width: 100%; margin-top: 22px; padding: 10px 17px; font-size: 14.5px;
  letter-spacing: 2px;
}
#loginVer { margin-top: auto; padding-top: 18px; text-align: center; }

@media (max-width: 780px) {
  .login-card { grid-template-columns: 1fr; max-width: 400px; }
  .login-form { padding: 28px 24px 22px; }
  /* 手机上把品牌区压成一条，只留标识和一句话 */
  .login-brand { padding: 20px 22px; }
  .lb-body { margin-top: 16px; }
  .lb-body h1 { font-size: 18px; }
  .lb-tags, .lb-art { display: none; }
  .lb-foot { margin-top: 14px; }
}

/* ————— 间距工具类 —————
   间距必须成体系，不能到处写 margin-top: 12px / 13px / 14px。
   基准 4px 栅格，常用三档：
     .mt-sm  12px  同组内的元素之间
     .mt     16px  卡片内的块之间
     .mt-lg  22px  分组之间
   页面里出现别的数字就是漏网，应该回来加档位而不是就地写死。 */
.mt-sm { margin-top: 12px; }
.mt { margin-top: 16px; }
.mt-lg { margin-top: 22px; }
.mb-sm { margin-bottom: 12px; }
.mb { margin-bottom: 16px; }
.ml-sm { margin-left: 6px; }
/* 紧贴卡片标题的说明行：上边距收负，把标题和它绑在一起 */
.mt-neg { margin: -8px 0 16px; }
.mt-neg-sm { margin: -6px 0 16px; }
/* 动态显示的区块默认藏起来 */
.hide { display: none; }

/* 勾选框旁边的说明文字 */
.check-label { font-size: 13px; color: var(--fg-dim); cursor: pointer; }
/* 行内文字链接（导出 CSV 这类），和按钮并排时垂直居中对齐 */
.link-inline {
  align-self: center; color: var(--accent);
  font-size: 13px; text-decoration: none; cursor: pointer;
}
.link-inline:hover { text-decoration: underline; }

/* ————— 布局 —————
   关键是 height:100vh 而不是 min-height ——
   用 min-height 的话，main 内容一长整个 #app 就被撑高，页面整体滚动，
   侧栏跟着拉长、底部那块被拖到视口外。改成定高 + 内部各自滚动，
   侧栏头/尾就永远钉在视口里了。 */
#app { display: none; height: 100vh; overflow: hidden; }
#app.on { display: flex; }

aside {
  width: 224px; flex-shrink: 0; height: 100%;
  background: var(--rail); border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  min-height: 0;   /* 允许 flex 子项在溢出时收缩，否则 nav 的 scroll 不生效 */
}

/* 顶部品牌区：深色方块图标 + 两行文字。
   图标用主色底反白，是整页唯一的「品牌锚点」。 */
aside .brand {
  display: flex; align-items: center; gap: 11px;
  padding: 18px 16px 17px;
  border-bottom: 1px solid var(--line);
}
/* 侧栏品牌标记：Logo 图片。
   小羊本身有黑色轮廓线，两套主题下都看得清，所以不用额外垫底色 ——
   加了白底反而在浅色主题上变成一个突兀的方块。 */
.brand-mark {
  width: 40px; height: 40px; flex: none;
  display: grid; place-items: center;
}
.brand-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
.brand-text { display: flex; flex-direction: column; min-width: 0; }
.brand-text b { font-size: 14.5px; font-weight: 600; color: var(--fg); letter-spacing: .2px; }
.brand-text small { font-size: 11px; color: var(--fg-mute); margin-top: 1px; letter-spacing: .3px; }

/* 品牌区不参与压缩：菜再多也不该把店名挤没 */
aside .brand { flex: none; }

/* nav 是侧栏里唯一滚动的部分：菜单项多到装不下时只滚它，
   头部品牌区和底部用户卡都待在原地 */
nav {
  flex: 1 1 auto; min-height: 0;
  padding: 12px 10px; overflow-y: auto; overflow-x: hidden;
  display: flex; flex-direction: column; gap: 2px;
  overscroll-behavior: contain;   /* 滚到底不把滚动传给整页 */
}

/* 导航项：图标 + 文字。
   选中态是**深色实心胶囊**（深色主题下反白），比左侧竖条更有「当前在这」的分量。 */
nav a {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: var(--r);
  color: var(--fg-2); text-decoration: none; font-size: 13.5px;
  transition: background .14s, color .14s, box-shadow .14s;
}
nav a .ic { width: 17px; height: 17px; flex: none; opacity: .82; }
nav a:hover { background: var(--panel-2); color: var(--fg); }
nav a:hover .ic { opacity: 1; }

nav a.on {
  background: var(--nav-on-bg); color: var(--nav-on-fg);
  font-weight: 500;
  box-shadow: var(--nav-on-sh);
}
nav a.on .ic { opacity: 1; }

nav .grp {
  padding: 15px 12px 6px; font-size: 11px;
  color: var(--fg-mute); letter-spacing: .7px;
}

/* 底部用户卡：头像 + 昵称/角色 + 两个按钮。
   flex:none 确保它永远不被 nav 挤压 —— 这是「钉在底部」的关键，
   配合 #app 的定高，无论页面多长、滚到哪里它都在视口里。 */
aside .foot {
  flex: none;
  padding: 12px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--fg-dim);
  background: var(--rail);
}
.who { display: flex; align-items: center; gap: 9px; padding: 2px 4px 11px; }
.who-avatar {
  width: 30px; height: 30px; border-radius: 8px; flex: none;
  display: grid; place-items: center;
  background: var(--accent-a14); color: var(--accent);
  font-size: 13px; font-weight: 600;
}
.who-text { display: flex; flex-direction: column; min-width: 0; }
.who-text b {
  font-size: 13px; font-weight: 500; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.who-text small { font-size: 11px; color: var(--fg-mute); margin-top: 1px; }

/* 两个按钮并排平分，别一个宽一个窄 */
.foot-acts { display: flex; gap: 8px; }
.foot-acts button { flex: 1; min-width: 0; padding: 6px 8px; font-size: 12px; }
/* 主题按钮里的图标和文字要贴在一起居中 */
#themeBtn { display: inline-flex; align-items: center; justify-content: center; gap: 5px; }
/* 主题图标：内联 SVG，跟随按钮文字颜色 */
#themeIcon { display: inline-flex; align-items: center; }
#themeIcon svg { width: 14px; height: 14px; display: block; }

/* main 自己滚，页面不滚 —— 这样侧栏和页头都不会被带着走 */
main {
  flex: 1; padding: 24px 30px 72px; min-width: 0;
  overflow-y: auto; overflow-x: hidden;
  height: 100%;
}

/* ————— 页头 —————
   英文小标签 + 中文大标题 + 右侧操作区。
   英文是纯装饰（让人一眼知道这是哪个模块），所以用小字号、主色、宽字距。
   不加 max-width：页头要和卡片同宽，否则大屏上标题和内容左右错位。 */
.page-hd {
  display: flex; align-items: flex-end; gap: 16px;
  flex-wrap: wrap; margin-bottom: 20px;
}
.page-hd h2 {
  font-size: 22px; font-weight: 600; letter-spacing: .3px;
  margin: 0; color: var(--fg); line-height: 1.2;
}
.ph-en {
  display: block; width: 100%;
  font-size: 11px; font-weight: 600; letter-spacing: 1.4px;
  color: var(--accent); margin-bottom: 5px; opacity: .9;
}
.page-acts { margin-left: auto; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* 视图里原来的 .hd 被抽走按钮后，剩下的空壳不该再占位置 */
.page-hd + .msg + .card .hd:empty,
main > .hd:empty { display: none; }

/* ————— 卡片 · 液态质感 —————
   「液态」靠三样东西叠出来，不是靠透明度：
     1. 顶部一道极淡的高光边（像玻璃的受光面）
     2. 内侧一圈暗描边（厚度感，让卡片看着是「一块」）
     3. 底部一层柔和投影（浮起）
   加一层从左上到右下的微弱渐变，避免大块纯色显得死板。

   刻意**不用 backdrop-filter**：那在低端机和部分浏览器上会掉帧，
   而这是个前台一直在开着的系统，流畅比炫技重要。 */
@property --mx { syntax: '<percentage>'; inherits: false; initial-value: 50%; }
@property --my { syntax: '<percentage>'; inherits: false; initial-value: 50%; }

.card, .kpi, .quick a {
  position: relative;
  background:
    linear-gradient(160deg,
      rgba(255, 255, 255, var(--glass-tint)) 0%,
      rgba(255, 255, 255, 0) 42%),
    var(--panel);
  border: 1px solid var(--card-line);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, var(--glass-edge)),
    var(--sh-card);
}

/* 鼠标划过时一道柔光跟着走 —— 这就是「液态」的动效部分 */
.card::after, .kpi::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none; opacity: 0; transition: opacity .25s;
  background: radial-gradient(220px circle at var(--mx) var(--my),
    rgba(255, 255, 255, var(--glass-glow)), transparent 62%);
}
.card:hover::after, .kpi:hover::after { opacity: 1; }

/* 卡片整体轻微抬起，配合光影才成立 */
.card, .kpi, .quick a {
  transition: transform .18s cubic-bezier(.2, .8, .3, 1),
              box-shadow .18s, border-color .18s;
}
.card:hover, .kpi:hover {
  border-color: var(--glass-hover-line);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, var(--glass-edge)),
    0 6px 20px rgba(0, 0, 0, var(--glass-lift));
  transform: translateY(-1px);
}

/* 弹窗也要同样的质感，但不要悬浮位移（它已经在浮层上了） */
.modal {
  background:
    linear-gradient(160deg,
      rgba(255, 255, 255, var(--glass-tint)) 0%,
      rgba(255, 255, 255, 0) 40%),
    var(--panel);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, var(--glass-edge)),
    var(--sh-pop);
}

/* ————— 卡片尺寸 —————
   材质（渐变、高光边、阴影）在上面的「液态质感」里统一给，
   这里只管尺寸。

   **不设 max-width**：曾限过 1180px，理由是「太宽则表格里项目名和
   金额隔太远」。但在 1920px 屏上，主区可用 1636px，卡片只占 1180px，
   右侧白出 456px —— 这才是「到处都是空白」的根源。
   在大屏上，留白比「列隔得远」更刺眼。 */
.card {
  border-radius: var(--r-lg); padding: 20px 22px; margin-bottom: 16px;
}
.card > h3 {
  font-size: 13px; margin-bottom: 16px; color: var(--fg-dim);
  font-weight: 500; letter-spacing: .3px;
}

/* 卡片小标题带操作按钮时用 .hd 包一层 */
.hd { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; gap: 12px; }
.hd h2, .hd h3 { margin: 0; }

/* ————— 转账凭证 —————
   单号 + 截图两部分，填一个就算满足。
   用一块浅底把两者框在一起，让「这是一组、二选一」看得出来。 */
.voucher {
  border: 1px dashed var(--line-strong); border-radius: var(--r);
  padding: 12px 13px; margin-top: 4px;
  background: var(--sunken);
  transition: border-color .15s, background .15s;
}
/* 填好了就收掉虚线，改成实线 + 主色边，给一个「已满足」的信号 */
.voucher.has-voucher {
  border-style: solid; border-color: var(--accent);
  background: var(--accent-a08);
}
.voucher.optional { opacity: .62; }

.vh { display: flex; align-items: center; gap: 8px; margin-bottom: 3px; }
.voucher-t { font-size: 12px; color: var(--fg-dim); letter-spacing: .2px; }
.voucher-req {
  font-size: 10.5px; padding: 1px 7px; border-radius: 20px;
  background: var(--warn); color: var(--on-accent); line-height: 1.6;
}
.voucher.optional .voucher-req { background: var(--panel-3); color: var(--fg-mute); }
.voucher-hint { font-size: 11.5px; color: var(--fg-mute); margin-bottom: 10px; }
.voucher.has-voucher .voucher-hint { color: var(--accent); }

.voucher-grid {
  display: grid; grid-template-columns: minmax(180px, 300px) auto;
  gap: 10px 16px; align-items: start;
}

/* 截图选择区：没图时是虚线按钮，有图变成缩略图 */
.shot-pick { position: relative; }
.shot-file {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.shot-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-width: 116px; height: 36px; padding: 0 14px; cursor: pointer;
  border: 1px dashed var(--line-strong); border-radius: var(--r);
  background: var(--panel-2); color: var(--fg-2);
  font-size: 13px; transition: border-color .14s, color .14s, background .14s;
}
.shot-btn:hover { border-color: var(--accent); color: var(--accent); }
.shot-btn .ic { width: 16px; height: 16px; }
.shot-btn.hide { display: none; }

.shot-thumb { position: relative; display: inline-block; }
.shot-thumb.hide { display: none; }
.shot-thumb img {
  height: 70px; max-width: 190px; object-fit: cover; display: block;
  border-radius: var(--r); border: 1px solid var(--line);
  background: var(--panel-2);
}
.shot-del {
  position: absolute; top: -7px; right: -7px;
  width: 21px; height: 21px; padding: 0; border-radius: 50%;
  border: 1px solid var(--line); background: var(--panel);
  color: var(--fg-2); font-size: 14px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
}
.shot-del:hover { background: var(--danger); color: var(--on-accent); border-color: transparent; }

/* 明细里的凭证展示 */
.vch-cell { display: inline-flex; align-items: center; gap: 7px; }
.vch-no {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px; color: var(--fg-2);
  max-width: 150px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; display: inline-block; vertical-align: bottom;
}
.vch-shot {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--accent); font-size: 12px; text-decoration: none;
  border-bottom: 1px dashed var(--accent-a35);
}
.vch-shot:hover { color: var(--accent-deep); }
.vch-shot .ic { width: 14px; height: 14px; }
.vch-none { color: var(--fg-mute); font-size: 12px; }

/* 图片查看层 */
.lightbox {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0, 0, 0, .82);
  display: grid; place-items: center; padding: 24px;
  cursor: zoom-out;
}
.lightbox img {
  max-width: 100%; max-height: 100%;
  border-radius: var(--r); box-shadow: 0 12px 48px rgba(0, 0, 0, .5);
}

/* ————— 接待工资 —————
   工资算错是信任问题，所以这一页的重点是「把构成摊开」：
   周切换一眼看出算的是哪一周，汇总把抽成/奖励/底薪拆开，每行能点明细。 */

/* 顶部：周切换 + 汇总，两行在宽屏上并排 */
.pay-bar { padding: 16px 20px; }
.pay-week {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.pw-label { display: flex; flex-direction: column; gap: 2px; }
.pw-en {
  font-size: 10px; letter-spacing: 1.4px; color: var(--accent);
  font-weight: 600;
}
.pw-label b { font-size: 14px; color: var(--fg); font-variant-numeric: tabular-nums; }

.pw-quick { display: flex; gap: 6px; flex-wrap: wrap; }
.pw-quick button.on {
  background: var(--accent); border-color: transparent; color: var(--on-accent);
}
.pw-nav { display: flex; gap: 4px; margin-left: auto; }
.pw-nav button { min-width: 30px; font-size: 15px; line-height: 1; padding: 5px 9px; }

/* 汇总条：把总工资拆成几块，一眼看出钱从哪来。
   用 flex 而不是 grid —— 项数会变（接待工资 5 项、陪玩工资 4 项），
   grid 的列数固定，项数不整除时最后一行会留出灰底空格，看着像没做完。
   flex 让每项按内容分摊，永远铺满。 */
.pay-sum {
  display: flex; flex-wrap: wrap;
  gap: 1px; background: var(--line); border-radius: var(--r);
  overflow: hidden; border: 1px solid var(--line);
}
.ps-item {
  background: var(--panel-2); padding: 9px 12px;
  display: flex; flex-direction: column; gap: 3px;
  flex: 1 1 120px; min-width: 0;      /* 够宽就一排，窄了自动换行 */
}
.ps-k { font-size: 11px; color: var(--fg-dim); letter-spacing: .2px; }
.ps-v { font-size: 15px; font-weight: 600; color: var(--fg); font-variant-numeric: tabular-nums; }
.ps-total { background: var(--accent-a08); }
.ps-total .ps-k { color: var(--accent); }
.ps-total .ps-v { color: var(--accent); font-size: 17px; }

/* 满勤勾选。
   原生 checkbox 在各浏览器里外观差异很大（手机上尤其小），
   所以自己画一个：外层 label 当容器，真 input 藏起来只留状态。 */
.att { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font-size: 12.5px; }
.att-cb {
  appearance: none; -webkit-appearance: none;
  width: 16px; height: 16px; flex: none; margin: 0;
  border: 1.5px solid var(--line-strong); border-radius: 4px;
  background: var(--panel-2); cursor: pointer; position: relative;
  transition: background .13s, border-color .13s;
}
.att-cb:hover { border-color: var(--accent); }
.att-cb:checked { background: var(--accent); border-color: var(--accent); }
/* 勾：用两条边框拼出来，不引图标 */
.att-cb:checked::after {
  content: ''; position: absolute; left: 4.5px; top: 1.5px;
  width: 4px; height: 8px;
  border: solid var(--on-accent); border-width: 0 2px 2px 0;
  transform: rotate(42deg);
}
.att-cb:disabled { opacity: .45; cursor: not-allowed; }
.att-cb:focus-visible { outline: 2px solid var(--accent-a35); outline-offset: 2px; }

/* 工资表：数字列用等宽数字，右对齐后能竖着对 */
table.pay td, table.pay th { white-space: nowrap; }
table.pay .grand { font-size: 15px; color: var(--accent); }

/* 「未参与计薪」折叠区：不占版面，要看时再展开 */
.fold {
  margin-top: 14px; border-top: 1px dashed var(--line);
  padding-top: 12px;
}
.fold > summary {
  cursor: pointer; font-size: 12.5px; color: var(--fg-mute);
  list-style: none; user-select: none;
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::before {
  content: '▸'; display: inline-block; margin-right: 6px;
  transition: transform .15s; color: var(--fg-mute);
}
.fold[open] > summary::before { transform: rotate(90deg); }
.fold > summary:hover { color: var(--fg-2); }
.fold-body {
  display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 10px;
}
.idle-row { display: inline-flex; align-items: baseline; gap: 7px; font-size: 13px; }
.who-name { color: var(--fg-2); }

/* 报单时的抽成预览：让前台提交前就看清钱怎么分 */
.cut-hint {
  margin-left: 12px; font-size: 12px; color: var(--fg-dim);
  padding-left: 12px; border-left: 1px solid var(--line);
}
.cut-warn {
  margin-left: 10px; font-size: 12px; color: var(--warn-fg);
  background: var(--warn-a10);
  padding: 1px 8px; border-radius: 20px;
}
/* 明细行里的陪玩下拉，别占太宽 */
.mate-sel { min-width: 0; }
.ml-xs { margin-left: 4px; font-size: 11px; }

/* ————— 店内抽点 —————
   顶部把「当前比例」放大显示：这是全店算钱的基准，改之前必须一眼看清。
   右边配一张换算示例表 —— 光看「20%」没有体感，
   看到「100 元 → 店内 20 / 陪玩 80」才知道这个数意味着什么。 */
.cut-set {
  display: flex; align-items: flex-start; gap: 28px; flex-wrap: wrap;
}
.cut-big {
  display: flex; flex-direction: column; gap: 2px;
  padding: 12px 22px; border-radius: var(--r-lg);
  background: var(--accent-a08); border: 1px solid var(--accent-a35);
  flex: none;
}
.cb-num {
  font-size: 34px; font-weight: 650; color: var(--accent);
  line-height: 1.1; font-variant-numeric: tabular-nums;
}
.cb-label { font-size: 12px; color: var(--accent); letter-spacing: .4px; }

.cut-info { flex: 1 1 260px; min-width: 0; }
.ci-row {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 6px 0; font-size: 13px;
  border-bottom: 1px solid var(--line-soft);
}
.ci-row:last-of-type { border-bottom: none; }
.ci-row > span { color: var(--fg-dim); }
.ci-row > b { color: var(--fg); font-weight: 500; }

/* 范围说明条：告诉用户「你看到的数据为什么只有这些」。
   接待看统计页时只有自己的单，不说明会被当成系统漏数据。 */
.scope-note {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 10px 14px; margin-bottom: 14px;
  border-radius: var(--r); border: 1px solid var(--accent-a35);
  background: var(--accent-a08);
  font-size: 12.5px; line-height: 1.6; color: var(--fg-2);
}
.scope-note .ic { width: 15px; height: 15px; flex: none; margin-top: 2px; color: var(--accent); }
.scope-note strong { color: var(--accent); font-weight: 600; }

/* ————— 报单类别：按类型分区 ————— */
/* 一个类型一张卡片。几十个项目平铺成一张表找不到东西，
   分区之后「游戏类有哪些」一眼就能看到。 */
.cat-group { margin-bottom: 22px; }
.cat-group:last-child { margin-bottom: 0; }
.cat-group-hd {
  display: flex; align-items: center; gap: 10px;
  padding: 0 2px 9px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 12px;
}
.cat-group-hd h4 {
  font-size: 14px; font-weight: 600; color: var(--fg-1);
  margin: 0; letter-spacing: .2px;
}
/* 「未分类」是升级前的老数据落脚处，弱化一点，提示它该被归位 */
.cat-group-hd h4:only-child,
.cat-group-hd h4:first-child:not(:nth-last-child(2)) { color: var(--fg-1); }
.cat-group-n {
  font-size: 11.5px; color: var(--fg-dim);
  padding: 1.5px 8px; border-radius: 999px;
  background: var(--surface-2, var(--bg-2));
  border: 1px solid var(--line);
}
.cat-group-hd button { margin-left: auto; }

/* ————— 表单 —————
   字段用网格自动排布，但**必须给列宽上限**。
   只用 minmax(180px, 1fr) 的话，1156px 的卡片会被切成 6 列，
   每个输入框拉到 180px+，「老板」这种只显示 8 个字的下拉框
   也占 430px —— 空白就是这么来的。

   改成 minmax(180px, 300px)：列宽在 180~300px 之间，
   不够就换行，剩下的空间留白而不是把控件撑开。 */
.form-grid, .row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 300px));
  gap: 14px 16px;
  align-items: start;
  justify-content: start;   /* 列靠左排，别被 justify-content 拉开 */
}
.form-grid { margin-bottom: 16px; }
.form-grid .span-2 { grid-column: span 2; }
.form-grid .span-all { grid-column: 1 / -1; }

/* 确实需要整行的字段（备注之类）单独给类，而不是靠 span 猜 */
.row > .span-all, .form-grid .span-all { grid-column: 1 / -1; max-width: 720px; }

/* 行内小范围（搜索框 + 按钮）走 flex，别被网格拉开 */
.row.inline { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.row.tight { gap: 8px; }
.row > button { justify-self: start; align-self: end; }

.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.field > label {
  font-size: 12px; color: var(--fg-dim); letter-spacing: .2px;
}

input, select, textarea {
  background: var(--panel-2); border: 1px solid var(--line); color: var(--fg);
  padding: 8px 11px; border-radius: var(--r); font-size: 14px;
  font-family: inherit; width: 100%; min-width: 0;
  transition: border-color .12s, box-shadow .12s, background .12s;
}
input:hover:not(:disabled), select:hover:not(:disabled), textarea:hover:not(:disabled) {
  border-color: var(--line-strong);
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent);
  background: var(--sunken);
  box-shadow: 0 0 0 3px var(--accent-a14);
}
input:disabled, select:disabled, textarea:disabled {
  color: var(--fg-mute); cursor: not-allowed; opacity: .7;
}
input::placeholder, textarea::placeholder { color: var(--fg-mute); }
input[readonly] { color: var(--fg-2); background: var(--sunken); cursor: default; }
select { cursor: pointer; }
select option { background: var(--panel-2); color: var(--fg); }
textarea { resize: vertical; line-height: 1.6; }

.form-actions { display: flex; gap: 10px; align-items: center; padding-top: 4px; }

/* ————— 开关行：勾选框 + 它的标签 + 右侧动作按钮 —————
   用 flex 而不是网格：网格会把 label 当成独立一列，和勾选框拉散。 */
.switch-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin-top: 12px;
  padding: 10px 14px; border-radius: var(--r-lg);
  background: var(--panel-2); border: 1px solid var(--line);
}
.switch { display: inline-flex; align-items: center; gap: 9px; cursor: pointer; user-select: none; }
.switch input[type=checkbox] {
  width: 16px; height: 16px; min-width: 16px; flex: none;
  accent-color: var(--accent); cursor: pointer; margin: 0;
}
.switch-text { font-size: 13.5px; color: var(--fg); }

/* 其余场景的勾选框也统一尺寸 */
.row input[type=checkbox], .modal input[type=checkbox] {
  width: 16px; height: 16px; min-width: 16px; accent-color: var(--accent);
}

/* ————— 按钮 ————— */
button {
  background: var(--accent-deep); color: var(--on-accent); border: 1px solid transparent;
  padding: 8px 17px; border-radius: var(--r); font-size: 13.5px;
  font-family: inherit; cursor: pointer; white-space: nowrap;
  transition: background .12s, border-color .12s, color .12s, opacity .12s;
}
button:hover:not(:disabled) { background: var(--accent); }
button:active:not(:disabled) { background: var(--accent-deep); }
/* 禁用态：降透明度 + 去掉主色感。只调 opacity 的话，
   在深底上仍然像个能点的蓝按钮，容易让人反复点。 */
button:disabled {
  background: var(--panel-3); color: var(--fg-mute);
  border-color: var(--line); cursor: not-allowed; opacity: 1;
}
button.ghost:disabled { background: transparent; color: var(--fg-mute); border-color: var(--line); }

button.ghost {
  background: transparent; border-color: var(--line-strong); color: var(--fg-2);
}
button.ghost:hover:not(:disabled) {
  background: var(--panel-3); color: var(--fg); border-color: var(--line-strong);
}
button.danger { background: var(--danger-deep); }
button.danger:hover:not(:disabled) { background: var(--danger); }
button.sm { padding: 4px 11px; font-size: 12px; border-radius: var(--r-sm); }
button.icon { padding: 5px 9px; }

/* 表格里成排的小按钮不该抢主按钮的风头 */
td button.ghost.sm { color: var(--fg-dim); border-color: var(--line); }
td button.ghost.sm:hover { color: var(--accent); border-color: var(--accent-a35); background: var(--accent-a08); }

/* ————— 表格 —————
   一律占满卡片宽度。
   曾经想把「列少」的表格缩窄，觉得右边留白比拉散好看 —— 实测是错的：
   「按项目」只有 3 列时缩到 185px，而卡片内宽 1112px，
   表格挤在左边、右边空出 900px，比拉散更难看。

   正确做法是占满 + 给文字列 .grow 吸收多余宽度：
   文字列变宽吃掉空白，数字列保持紧凑并右对齐，
   列与列之间的视觉关系就是紧的，不会隔半个屏幕。 */
table { border-collapse: separate; border-spacing: 0; font-size: 13px; width: 100%; }
thead th {
  text-align: left; font-weight: 500; font-size: 12px;
  color: var(--fg-dim); letter-spacing: .3px;
  padding: 0 12px 10px; border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
tbody td {
  padding: 11px 12px; border-bottom: 1px solid var(--line-soft);
  color: var(--fg-2); vertical-align: middle;
  white-space: nowrap;
}
/* 吸收剩余宽度的列。
   用在列多的表上（老板表 8 列、流水 7 列）——
   列多时铺满是对的，靠它把余量给某一列，其余列保持紧凑。
   注意：3 列的表格千万别用它，文字列会吃掉 1000px，
   「项目」和「金额」隔半个屏幕。那种情况用下面的 .split。 */
th.grow, td.grow { width: 100%; white-space: normal; }

/* ── 3 列的表：铺满 + 中间列居中 ──
   布局是「项目 | 笔数 | 金额」。
   比例 54 / 26 / 20：
     项目列拿 54%（够放长名字）
     笔数列拿 26% —— 给它足够的宽度，让「笔数」两字和数字
       居中落在这块空间的**中间**，而不是挤在右侧
     金额列 20%，右对齐贴卡片边
   中间列给宽之后，视觉上三列是「左 / 中 / 右」三段，读起来最稳。 */
table.split {
  table-layout: fixed; width: 100%;
}
table.split th:first-child, table.split td:first-child { width: 54%; }
table.split th:nth-child(2), table.split td:nth-child(2) { width: 26%; }
table.split th:last-child, table.split td:last-child { width: 20%; }

table.split th, table.split td {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 中间列（笔数/次数）在本列内居中 */
table.split th:nth-child(2), table.split td:nth-child(2) { text-align: center; }
/* 金额列靠右，贴到卡片边缘 */
table.split th:last-child, table.split td:last-child {
  text-align: right; padding-right: 0;
}

/* .fit —— 列数中等的表（4~6 列，如报单类别）。
   铺满卡片，靠 .grow 把余量给「项目名称」那一列，
   别让空白全堆到内容为空的备注列上。 */
table.fit { width: 100%; }
table.fit td.wrap { white-space: normal; min-width: 120px; }
/* 备注是唯一长度不定的列，给它折行能力，别把表撑开 */
table.fit td.wrap { white-space: normal; min-width: 120px; }

/* 备注类列可以折行 */
td.wrap { white-space: normal; min-width: 140px; }
tbody td b { color: var(--fg); font-weight: 500; }
tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background .1s; }
tbody tr:hover td { background: var(--hover); }
th.r, td.r { text-align: right; }
td.nowrap, th.nowrap { white-space: nowrap; }
td.num, th.num { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-variant-numeric: tabular-nums; }
/* 数字列右对齐时，等宽字体的左内边距会让数字离边框太远，收紧一点 */
td.r.num { padding-right: 14px; }

/* 表格外套一层：窄屏时横向滚动，而不是把列挤变形。
   由 JS 给每张表自动包上（见 app.js 的 wrapTables）。
   宽屏时这层不产生任何视觉效果（内容不溢出就不出现滚动条），
   所以不必区分屏幕尺寸。 */
.table-wrap, .scroll-x { overflow-x: auto; margin: 0 -4px; padding: 0 4px; }
.scroll-x { -webkit-overflow-scrolling: touch; }

/* 表格最后一列不留右内边距，让内容和卡片右边缘对齐。
   老板表/流水表最后一列是操作按钮，这条会把按钮也顶到边上 ——
   所以只在没有操作列的表格上用。 */
table.edge td:last-child, table.edge th:last-child { padding-right: 0; }

/* .data 是「数据表」的语义标记（老板、流水、存单、用户…）。
   宽度行为已由基类统一处理，这里不需要额外规则 ——
   保留它是因为 markup 里一眼能看出这张表的性质，
   以后若要给数据表加特性（固定表头、斑马纹）也有落脚点。 */
table.data { width: 100%; }

.empty {
  padding: 34px 16px; text-align: center;
  color: var(--fg-mute); font-size: 13px;
  border: 1px dashed var(--line); border-radius: var(--r-lg);
}

.hint { font-size: 12px; color: var(--fg-dim); line-height: 1.65; }
/* hint 的状态修饰：表单实时校验用（比如改密码时提示「两次不一致」） */
.hint.err { color: var(--danger-fg); }
.hint.ok { color: var(--ok); }

/* 视觉隐藏但保留给读屏：某些字段的分组标题已交代含义，
   但控件仍需一个 label，用它挂上去。 */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ————— KPI —————
   固定每行 4 个，多出的换行。
   用 auto-fit 的话 6 个会挤成一行（每个 183px，标签已经很紧），
   7 个则排成 6+1 —— 最后一行孤零零一个，很难看。
   固定列数后两行能上下对齐，数量变了也不会突然变形。
   窄屏依次降为 2 列 / 3 列，屏幕再小也不会挤成一条。 */
.kpis {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px; margin-bottom: 18px;
}
@media (min-width: 1500px) {
  .kpis { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
@media (max-width: 1100px) {
  .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.kpi {
  border-radius: var(--r-lg); padding: 14px 16px;
  position: relative; overflow: hidden;
}
/* 顶部一条 2px 色带标记分类，比整卡染色克制 */
.kpi::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--line-strong);
}
.kpi .k {
  font-size: 12px; color: var(--fg-dim); margin-bottom: 6px;
  letter-spacing: .2px; white-space: nowrap;
}
.kpi .v { font-size: 20px; font-weight: 600; color: var(--fg); line-height: 1.3; }
.kpi.accent::before { background: var(--accent); }
.kpi.accent .v { color: var(--accent); }
.kpi.ok::before { background: var(--ok); }
.kpi.ok .v { color: var(--ok); }
.kpi.warn::before { background: var(--warn); }
.kpi.warn .v { color: var(--warn); }

/* ————— 标签 ————— */
.tag {
  display: inline-block; padding: 2px 8px; border-radius: 4px;
  font-size: 11.5px; line-height: 1.7; white-space: nowrap;
  background: var(--panel-3); color: var(--fg-2);
}
.tag.deposit { background: var(--deposit-a14); color: var(--deposit-fg); }
.tag.cash { background: var(--warn-a10); color: var(--warn); }
.tag.ok { background: var(--ok-a10); color: var(--ok); }
.tag.off { background: var(--panel-3); color: var(--fg-mute); }
.tag.warn { background: var(--warn-a22); color: var(--warn); }
.tag.role-admin { background: var(--danger-a20); color: var(--danger-fg-2); }
.tag.role-finance { background: var(--warn-a22); color: var(--warn); }
.tag.role-reception { background: var(--ok-a20); color: var(--ok); }

.bal.positive { color: var(--ok); }
.bal.zero { color: var(--fg-mute); }

/* 赠送金额用暖色，和实收区分开 */
.gift, .num.gift { color: var(--warn); }

/* ————— 提示条 / 消息 ————— */
.msg {
  padding: 9px 13px; border-radius: var(--r); font-size: 13px; margin-bottom: 14px;
}
.msg:empty { display: none; }
.msg.err { background: var(--danger-a08); border: 1px solid var(--danger-a20); color: var(--danger-fg); }
.msg.suc { background: var(--ok-a10); border: 1px solid var(--ok-a20); color: var(--ok); }

/* 结算提示条（报单页）。
   左侧竖线 + 淡底，明确是「系统算给你看的」而不是可编辑输入框 ——
   之前和 input 长得太像，容易被当成能改的字段。 */
.settle-echo {
  font-size: 13px; line-height: 1.7;
  padding: 10px 14px; border-radius: 0 var(--r) var(--r) 0;
  border-left: 3px solid var(--accent);
  background: var(--accent-a08);
  color: var(--fg-2);
}
.settle-echo b { color: var(--fg-strong); font-weight: 600; }
.settle-echo:empty { display: none; }

/* 到账金额条：存单弹窗里唯一需要核对数字的地方，单独做成一张小票 */
.amount-bar {
  margin-top: 14px; padding: 13px 15px; border-radius: var(--r-lg);
  background: var(--accent-a08);
  border: 1px solid var(--accent-a22);
  font-size: 13px;
}
.amount-bar .hint { margin: 0; }
.ab-row {
  display: flex; justify-content: space-between; align-items: baseline;
  line-height: 1.95; color: var(--fg-dim);
}
.ab-row .num { color: var(--fg); }
.ab-total {
  margin-top: 8px; padding-top: 9px;
  border-top: 1px dashed var(--dash);
  color: var(--fg); font-weight: 600;
}
.ab-total .num { color: var(--fg-strong); font-size: 18px; }
.ab-cur { margin-top: 9px; font-size: 12px; color: var(--fg-dim); }

/* ————— 编号 ————— */
.code-tag {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px; color: var(--accent);
  background: var(--accent-a08);
  border: 1px solid var(--accent-a22);
  padding: 1px 7px; border-radius: 4px; white-space: nowrap;
}

/* ————— 版本号 ————— */
.ver {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px; color: var(--fg-mute); letter-spacing: .3px;
}
#nav .ver { margin-top: auto; padding: 16px 18px 2px; border-top: 1px solid var(--line); }
#loginVer { margin-top: 16px; text-align: center; }

/* ————— 老板搜索下拉（已弃用输入框，保留样式兼容） ————— */
.suggest { position: relative; }
.suggest .list {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 20;
  background: var(--panel-2); border: 1px solid var(--line-strong);
  border-radius: var(--r); margin-top: 3px; max-height: 220px; overflow-y: auto;
  display: none; box-shadow: var(--sh-pop);
}
.suggest .list.on { display: block; }
.suggest .list div { padding: 7px 10px; cursor: pointer; font-size: 13px; }
.suggest .list div:hover { background: var(--panel-3); }

/* ————— 弹窗 —————
   间距节奏：标题栏 18/22 → 分组 20 → 组标题到字段 14 → 字段之间 14 → 页脚 16/22。
   暗色界面里分组靠留白切分，不画分隔线 —— 线多了整个弹窗会显得碎。 */
.modal-mask {
  position: fixed; inset: 0; z-index: 500;
  background: rgba(6, 8, 13, .78);
  backdrop-filter: blur(3px);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 56px 16px; overflow-y: auto;
}
.modal {
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-radius: 14px; width: 100%; max-width: 520px;
  box-shadow: var(--sh-pop);
  margin: auto 0;
  animation: modal-in .16s cubic-bezier(.2, .8, .3, 1);
}
@keyframes modal-in {
  from { opacity: 0; transform: translateY(-10px) scale(.985); }
  to { opacity: 1; transform: none; }
}

.modal-hd {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 22px 16px; border-bottom: 1px solid var(--line);
}
.modal-hd h3 { font-size: 15px; font-weight: 600; color: var(--fg-strong); margin: 0; letter-spacing: .2px; }
.modal-close {
  background: transparent; border: none; color: var(--fg-dim);
  font-size: 16px; line-height: 1; padding: 4px 8px;
  cursor: pointer; border-radius: var(--r-sm);
}
.modal-close:hover { background: var(--panel-3); color: var(--fg); }

.modal-group { padding: 20px 22px 0; }
.modal-group:last-of-type { padding-bottom: 22px; }
.modal-group > h4 {
  font-size: 12px; font-weight: 500; color: var(--fg-dim);
  margin: 0 0 14px; letter-spacing: .4px;
  display: flex; align-items: center; gap: 8px;
}
.modal-group > h4::before {
  content: ''; width: 3px; height: 12px; border-radius: 2px;
  background: var(--accent); flex: none;
}
.modal .field + .field { margin-top: 14px; }
.modal-group .settle-echo { margin-top: 14px; }

.modal-ft {
  display: flex; justify-content: flex-end; gap: 10px;
  padding: 16px 22px 18px; margin-top: 4px;
  border-top: 1px solid var(--line);
  background: var(--foot-tint);
  border-radius: 0 0 14px 14px;
}
.modal .hint { margin-top: 12px; }

/* ————— 退单确认弹窗 ————— */
.receipt {
  padding: 13px 15px; border-radius: var(--r-lg);
  background: var(--panel-2); border: 1px solid var(--line);
}
.rc-row {
  display: flex; justify-content: space-between; gap: 16px;
  line-height: 1.95; font-size: 13px;
}
.rc-k { color: var(--fg-dim); flex: none; }
.rc-v { color: var(--fg); text-align: right; word-break: break-all; }
.rc-v.num { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

.refund-note {
  font-size: 13px; line-height: 1.7; padding: 11px 15px;
  border-radius: 0 var(--r) var(--r) 0;
  color: var(--fg-2); border-left: 3px solid var(--line-strong); background: var(--panel-2);
}
.refund-note.ok {
  border-left-color: var(--ok); background: var(--ok-a10); color: var(--fg);
}
.refund-note.warn {
  border-left-color: var(--warn); background: var(--warn-a10); color: var(--fg);
}
.refund-note b { color: var(--fg-strong); }
.refund-list { margin-top: 9px; }
.refund-row {
  display: flex; justify-content: space-between; font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--fg-dim); line-height: 1.95; padding-left: 6px;
}
.refund-row .num { color: var(--ok); }

/* 二次确认：勾选框单独做一块，必须动手勾 */
.confirm-wrap {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 13px 15px; border-radius: var(--r-lg);
  background: var(--danger-a08); border: 1px solid var(--danger-a20);
}
.confirm-wrap input[type=checkbox] { margin-top: 3px; flex: none; width: auto; }
.confirm-label { font-size: 13px; line-height: 1.7; color: var(--fg-2); cursor: pointer; }
.confirm-label b { color: var(--danger-fg-3); }

/* ————— Excel 导入预览 ————— */
/* 原生 file 控件在深色底上是个灰色方块，和整体不搭。
   这里把 ::file-selector-button 拉进设计体系。 */
input[type=file] {
  padding: 7px 10px; cursor: pointer;
  background: var(--panel-2); border: 1px dashed var(--line-strong);
}
input[type=file]:hover { border-color: var(--accent-a35); background: var(--sunken); }
input[type=file]::file-selector-button {
  background: var(--accent-deep); color: var(--on-accent); border: none;
  padding: 6px 14px; border-radius: var(--r-sm); font-size: 13px;
  font-family: inherit; cursor: pointer; margin-right: 12px;
  transition: background .12s;
}
input[type=file]::file-selector-button:hover { background: var(--accent); }

.preview {
  max-height: 350px; overflow-y: auto;
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: 11px 13px;
  background: var(--panel-2);
}
.preview .hint { margin: 0; }
.preview table { margin-top: 10px; }
.preview thead th { padding-bottom: 8px; }
.preview th, .preview td { padding: 6px 8px; font-size: 12px; }
.preview tbody tr:hover td { background: var(--hover); }
.import-stats { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ————— 报单多行明细 —————
   每行都是「序号 + 项目 + 金额 + 备注 + 删除」。
   字段带标签：之前光秃秃三个框，新人不知道哪格填什么。 */
/* 「+ 再加一笔」和它的说明：和上面的明细行拉开，别糊在一起 */
.lines-add { margin-top: 12px; gap: 12px !important; }
.lines-add .hint { margin: 0; }

.sec-title {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--fg-dim); letter-spacing: .4px;
  margin: 22px 0 12px;
}
/* 卡片里第一个分组标题不需要额外上边距 */
.card > h3 + .sec-title, .modal-group > h4 + .sec-title { margin-top: 4px; }
.sec-title::before {
  content: ''; width: 3px; height: 12px; border-radius: 2px;
  background: var(--accent); flex: none;
}
.lines { display: flex; flex-direction: column; gap: 10px; }
/* 明细行排两行：项目占满第一行（它是这行最重要的选择），
   金额 / 陪玩 / 备注 / 删除 排第二行。
   六个字段挤在一行会把备注压成一条缝，而且加人之后只会更挤。 */
.line {
  display: grid;
  /* 类型和项目并排放第一行（先选类型再选项目，顺序就是操作顺序）；
     第二行放金额、陪玩、备注。 */
  grid-template-columns: 24px minmax(120px, .8fr) minmax(0, 1.2fr) 110px minmax(150px, 1fr) minmax(0, 1.1fr) 34px;
  grid-template-areas:
    'i g c c c c d'
    'i a m m r r d';
  gap: 10px 14px; align-items: end;
  padding: 12px 14px; border-radius: var(--r-lg);
  background: var(--panel-2); border: 1px solid var(--line);
  transition: border-color .12s;
}
.line:hover { border-color: var(--line-strong); }
.line > .ln-idx { grid-area: i; }
.line > .f-grp { grid-area: g; }      /* 类型 */
.line > .f-cat { grid-area: c; }      /* 项目 */
.line > .f-amt { grid-area: a; }      /* 金额（只读） */
.line > .f-mate { grid-area: m; }     /* 陪玩 */
.line > .f-rem { grid-area: r; }      /* 备注 */
.line > .del { grid-area: d; }
/* 序号对齐到输入框那一行（不是整行居中），否则和标签错位 */
.ln-idx {
  align-self: end; margin-bottom: 10px;
  font-size: 12px; color: var(--fg-mute);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  text-align: center;
}
/* 金额是只读展示：做成带底的块，一眼区分于可输入的框 */
.amt-ro {
  padding: 8px 11px; border-radius: var(--r);
  background: var(--sunken); border: 1px solid var(--line);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  text-align: right; color: var(--fg-mute); font-size: 14px;
}
.amt-ro.on { color: var(--accent); border-color: var(--accent-a22); background: var(--accent-a08); }
.line .del { align-self: end; margin-bottom: 1px; }
@media (max-width: 860px) {
  .line { grid-template-columns: 26px 1fr 96px; grid-template-areas: 'i c a' 'i r d'; }
  .line > .ln-idx { grid-area: i; }
  .line > .field:nth-of-type(1) { grid-area: c; }
  .line > .field.amt { grid-area: a; }
  .line > .field:nth-of-type(3) { grid-area: r; }
  .line > .del { grid-area: d; justify-self: end; }
}

/* ————— 档案式键值对（老板明细的档案卡） ————— */
.kv {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 10px 22px;
}
.kv-row { display: flex; gap: 10px; font-size: 13px; min-width: 0; }
.kv-k { color: var(--fg-dim); flex: none; min-width: 76px; }
.kv-v { color: var(--fg); min-width: 0; word-break: break-all; }

/* ————— 快捷入口 ————— */
.quick {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 11px;
}
.quick a {
  display: block; padding: 15px 17px; border-radius: var(--r-lg);
  color: var(--fg); text-decoration: none; font-size: 13.5px;
}
.quick a:hover { border-color: var(--glass-hover-line); }
.quick a small { display: block; color: var(--fg-dim); font-size: 11.5px; margin-top: 3px; }

/* ————— Toast ————— */
#toast {
  position: fixed; top: 18px; left: 50%; transform: translateX(-50%);
  z-index: 900; display: flex; flex-direction: column; gap: 8px;
  align-items: center; pointer-events: none;
}
#toast > div {
  padding: 10px 18px; border-radius: var(--r-lg); font-size: 13px;
  background: var(--panel-3); border: 1px solid var(--line-strong);
  color: var(--fg); box-shadow: var(--sh-pop);
  animation: toast-in .18s cubic-bezier(.2, .8, .3, 1);
}
#toast > div.err { background: var(--toast-err-bg); border-color: var(--danger-a20); color: var(--danger-fg); }
#toast > div.suc { background: var(--toast-suc-bg); border-color: var(--ok-a20); color: var(--ok-fg); }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: none; }
}

/* 窄屏：侧栏收成横向条，主区占满。
   手机上没有空间给「用户卡 + 两个按钮」垂直堆叠，
   所以把它们压成一行横向铺开，仍然钉在底部。 */
@media (max-width: 720px) {
  #app.on { flex-direction: column; }
  aside {
    width: 100%; height: auto; flex: none;
    border-right: none; border-bottom: 1px solid var(--line);
  }
  aside .brand { display: none; }          /* 手机上店名占地方，省掉 */

  /* ——— 顶部条：导航 + 用户操作挤成一行 ———
     手机上垂直空间最宝贵。原来导航一行 + 用户卡一行要 105px，
     挤掉近八分之一的屏幕。现在合成一条：导航横向滚，
     操作按钮固定在右端。 */
  aside { padding: 0; }
  nav {
    flex-direction: row; overflow-x: auto; overflow-y: hidden;
    padding: 6px 4px; flex: 1 1 auto; min-width: 0;
    gap: 2px;
    scrollbar-width: none;           /* 横向滚动条在手机上很难看 */
    scroll-behavior: smooth;
  }
  nav::-webkit-scrollbar { display: none; }
  nav a { white-space: nowrap; padding: 7px 10px; font-size: 13px; }
  nav a .ic { width: 15px; height: 15px; }
  nav a.on { box-shadow: none; }
  nav .grp, #nav .ver { display: none; }

  aside .foot {
    display: flex; align-items: center; gap: 6px;
    padding: 6px 8px 6px 4px;
    border-top: none; border-left: 1px solid var(--line);
    flex: none;
    background: var(--rail);
  }
  .who { display: none; }                  /* 昵称在手机上不看了，让位给按钮 */
  .foot-acts { gap: 6px; }
  .foot-acts button { padding: 6px 9px; font-size: 12px; }
  #themeText { display: none; }            /* 只留图标，省宽度 */

  /* 侧栏整体改成 flex 行 */
  aside { flex-direction: row; align-items: center; }

  main { padding: 18px 16px 40px; }

  /* ——— 表格：手机上横向滚动，不挤压 ———
     390px 就算把 8 列压到每列 45px 也读不了，
     所以给它一个可读的最小宽度，超出部分横向滚动。
     .scroll-x 这个包装层由 JS 自动加上（宽屏下不产生任何效果）。 */
  .scroll-x { margin: 0 -14px; padding: 0 14px; }
  .scroll-x > table { min-width: 600px; }
  /* 3 列的表本来就窄，不需要滚动 */
  .scroll-x > table.split { min-width: 0; width: 100%; }

  /* 弹窗留白收紧，别在小屏上被挤扁 */
  .modal { max-width: none; }
  .modal-mask { padding: 16px 10px; }
  .modal-hd { padding: 15px 16px 13px; }
  .modal-group { padding: 16px 16px 0; }
  .modal-ft { padding: 13px 16px 15px; }

  /* 页头在小屏上竖排，标题和按钮各占一行 */
  .page-hd { gap: 10px; }
  .page-hd h2 { font-size: 19px; }
  .page-acts { margin-left: 0; width: 100%; }
  .page-acts button { flex: 1; }

  /* 卡片内边距收紧，小屏上多留点内容空间 */
  .card { padding: 16px 14px; }

  /* KPI：手机上一行两个。
     2 列时 5 个会排成 2+2+1，最后那个孤零零占一行 ——
     给它单独一条规则撑满整行，看着才收得住。 */
  .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kpis .kpi:last-child:nth-child(odd) { grid-column: 1 / -1; }

  /* KPI 数字略收 */
  .kpi .v { font-size: 18px; }
  .kpi .k { font-size: 11.5px; }

  /* 表单控件占满整行更好点按 */
  .form-grid, .row { grid-template-columns: 1fr; }
  .row.inline { flex-wrap: wrap; }
  .row > .span-all, .form-grid .span-all { max-width: none; }

  /* 报单明细行：手机上竖向堆叠。
       项目 → 金额 → 陪玩 → 备注 各占一行，删除按钮靠右。
     字段多了之后横排必然挤，竖排最好点。 */
  .line {
    grid-template-columns: 1fr;
    grid-template-areas:
      'g'
      'c'
      'a'
      'm'
      'r'
      'd';
    gap: 9px;
    align-items: stretch;
  }
  .line > .ln-idx {
    grid-area: unset; position: absolute; top: 12px; left: 14px;
    margin: 0; padding: 0; text-align: left;
  }
  .line { position: relative; padding-top: 34px; }
  .line > .f-grp { grid-area: g; }      /* 类型 */
  .line > .f-cat { grid-area: c; }      /* 项目 */
  .line > .f-amt { grid-area: a; }      /* 金额 */
  .line > .f-mate { grid-area: m; }     /* 陪玩 */
  .line > .f-rem { grid-area: r; }      /* 备注 */
  .line > .del {
    grid-area: d; justify-self: end; align-self: end;
    margin-top: -4px;
  }

  /* 老板明细的档案卡：两列太挤，改一列 */
  .kv { grid-template-columns: 1fr; }
  .kv-k { min-width: 68px; }
}
