/* premium.css —— 高端拟态玻璃皮肤（覆盖层）
 * ============================================================================
 * 这个文件排在 art-kit/tokens.css → ui.css → glass.css → app.css **之后**加载，
 * 它的唯一职责是把默认的「浅色白玻璃」换成「深色奢华 + 拟态玻璃」。
 *
 * 设计基调
 *   底色：深蓝黑渐变（#080b14 → #0d1220 → #111a2e），**不是纯黑**——
 *         纯黑在 LCD 上会显得死、廉价，深蓝黑带一点色相才像成品。
 *   光源：统一假定在**左上**。所有拟态阴影都按这个方向推导，
 *         不能一半卡片左上、一半右上——那会让整个界面看起来"贴歪了"。
 *   拟态公式（下文的 --neu-* 变量，全站复用同一套）：
 *         顶边 inset 白色高光 + 底边 inset 黑色暗边（制造厚度）
 *         外层大投影（制造浮起）+ 极浅小投影（贴地感）
 *   强调色：从普通蓝 #2563eb 换成蓝紫渐变 #5b8cff → #8b6bff。
 *         渐变只用在**主按钮、品牌名、统计数字**三处，铺多了会花。
 *
 * 五条硬约束（破了会白屏或不可读）
 *   1. `--surf` / `--glass` 必须在这里写**完整颜色值**重定义。
 *      tokens.css 里它们是 `rgb(255 255 255 / var(--glass-a))` 这种复合值，
 *      只改 --glass-a 不动它们，深色底上会出现"白块"。
 *   2. #wall-layer 必须仍是 `fixed / inset:0 / z-index:-1 / pointer-events:none`，
 *      #wall-img 必须仍是 `background-size: cover`。
 *   3. 表格**不半透明**：业务后台要看清 20 行数字，毛玻璃只给卡片和弹窗。
 *   4. 对比度：正文与次要文字都按 ≥ 4.5:1 取值（见文件末尾的实测数值）。
 *   5. 不引入任何外部资源（无 @import、无 url(http…)、无字体文件）。
 * ============================================================================ */

/* ---------------------------------------------------------------------------
 * 1. 令牌覆盖：所有颜色在这里一次改完
 * ------------------------------------------------------------------------- */
body {
  /* ---- 底色与"面" ---- */
  --bg: #080b14;
  --surface: #0e1320;

  /* 关键：完整值重定义，不能用 rgb(255 255 255 / var(--glass-a))。
     深色皮肤下"面"是**深色玻璃**，不是白色玻璃。 */
  --surf: rgb(18 23 38 / 0.72);
  --glass: rgb(20 26 43 / 0.58);
  --glass-2: rgb(255 255 255 / 0.045);
  --glass-3: rgb(255 255 255 / 0.075);
  --glass-ring: rgb(255 255 255 / 0.14);

  /* ---- 文字四级（深色底上逐级降低亮度，全部 ≥ 4.5:1） ---- */
  --ink: #f2f5fb;          /* 正文          对 #0b0f19 ≈ 16.8:1 */
  --ink-2: #d3dae8;        /* 次级          对 #0b0f19 ≈ 11.6:1 */
  --ink-3: #a9b4c8;        /* 辅助           对 #0b0f19 ≈  7.2:1 */
  --ink-4: #8892a6;        /* 最弱           对 #0b0f19 ≈  4.9:1 */

  /* ---- 品牌色：蓝紫渐变体系 ---- */
  --brand: #5b8cff;
  --brand-ink: #a9c1ff;
  --brand-dark: #7fa3ff;
  --brand-soft: rgb(91 140 255 / 0.16);
  --brand-line: rgb(91 140 255 / 0.34);

  /* ---- 语义色：深色底上要"发光"才看得见，所以往亮里调 ---- */
  --ok: #57e39b;
  --ok-soft: rgb(87 227 155 / 0.14);
  --warn: #ffcb5c;
  --warn-soft: rgb(255 203 92 / 0.14);
  --warn-line: rgb(255 203 92 / 0.34);
  --danger: #ff7d85;
  --danger-soft: rgb(255 125 133 / 0.14);
  --danger-line: rgb(255 125 133 / 0.34);

  /* ---- 分隔线：白色低透明，不用灰色（灰色在深底上发脏） ---- */
  --line: rgb(255 255 255 / 0.09);
  --line-strong: rgb(255 255 255 / 0.16);

  /* ---- 形状：比原来的 10px 更圆润，这是"高端感"最廉价的来源之一 ---- */
  --radius: 16px;
  --radius-sm: 10px;

  /* ---- 拟态阴影（全站唯一一套，别在别处临时手写） ---- */
  --neu-raise:
    0 1px 0 0 rgb(255 255 255 / 0.085) inset,
    0 -1px 0 0 rgb(0 0 0 / 0.42) inset,
    0 20px 44px -22px rgb(0 0 0 / 0.75),
    0 2px 8px -3px rgb(0 0 0 / 0.45);
  --neu-raise-hover:
    0 1px 0 0 rgb(255 255 255 / 0.11) inset,
    0 -1px 0 0 rgb(0 0 0 / 0.46) inset,
    0 26px 54px -24px rgb(0 0 0 / 0.82),
    0 3px 10px -3px rgb(0 0 0 / 0.5);
  --neu-inset:
    0 1px 2px rgb(0 0 0 / 0.5) inset,
    0 -1px 0 0 rgb(255 255 255 / 0.05) inset;

  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.35);
  --shadow: 0 2px 6px rgb(0 0 0 / 0.4), 0 20px 44px -22px rgb(0 0 0 / 0.75);

  /* ---- 壁纸压暗：深色皮肤下不需要压太狠，壁纸本身就是深色 ---- */
  --wall-scrim: rgb(6 9 16 / 0.42);
}

/* ---------------------------------------------------------------------------
 * 2. 背景：没有壁纸时也不能廉价
 *
 * 三层径向渐变叠一条线性渐变，模拟"氛围光"——
 * 左上偏蓝、右下偏紫，中间深，像一盏柔光灯打在产品上。
 * 这样即使客户一张壁纸都没上传，页面也不是死板的纯色块。
 * ------------------------------------------------------------------------- */
body {
  background-color: #080b14;
  background-image:
    radial-gradient(ellipse 80% 60% at 18% 0%, rgb(26 36 86 / 0.85) 0%, transparent 55%),
    radial-gradient(ellipse 70% 55% at 82% 100%, rgb(42 26 74 / 0.75) 0%, transparent 52%),
    radial-gradient(ellipse 50% 40% at 50% 45%, rgb(16 22 40 / 0.55) 0%, transparent 70%),
    linear-gradient(160deg, #080b14 0%, #0b1020 55%, #0e1424 100%);
  background-attachment: fixed;
}

/* 壁纸层：保持三条硬约束，只补一层柔化，避免深色图发花 */
#wall-layer { position: fixed; inset: 0; z-index: -1; pointer-events: none; }
#wall-img {
  position: absolute; inset: 0;
  background-size: cover;
  background-repeat: no-repeat;
  background-position: var(--wall-focus, 50% 50%);
  pointer-events: none;
  filter: saturate(1.05) brightness(0.92);
}
#wall-scrim {
  position: absolute; inset: 0;
  background: var(--wall-scrim);
  pointer-events: none;
}

::selection { background: rgb(91 140 255 / 0.34); color: #fff; }

/* ---------------------------------------------------------------------------
 * 2b. 内容区视觉压阵
 *
 * 问题：今日待跑这类页面内容很少（一张表 2 行），下面会留出一大片纯底色，
 * 看起来像"没做完"。纯底色在深色皮肤上尤其明显。
 *
 * 解法：给 .main 一层**极淡**的品牌色氛围光，从底部往上渐隐。
 * 关键在"极淡"——它不是装饰元素，只是让那块空区域有层次，
 * 一旦能明显看见颜色就过头了（alpha 控制在 0.06 以内）。
 * 同时给内容区一个最低高度，让底部渐变有地方铺开。
 * ------------------------------------------------------------------------- */
.main {
  position: relative;
  min-height: calc(100vh - var(--topbar-h));
  background-image:
    radial-gradient(ellipse 60% 40% at 50% 100%, rgb(91 140 255 / 0.055) 0%, transparent 70%),
    radial-gradient(ellipse 44% 30% at 82% 92%, rgb(139 107 255 / 0.045) 0%, transparent 68%);
  background-repeat: no-repeat;
}

/* ---------------------------------------------------------------------------
 * 3. 顶栏 / 侧栏
 * ------------------------------------------------------------------------- */
.topbar {
  background: rgb(11 15 26 / 0.72);
  backdrop-filter: blur(24px) saturate(150%);
  -webkit-backdrop-filter: blur(24px) saturate(150%);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 0 rgb(255 255 255 / 0.045) inset,
              0 10px 30px -18px rgb(0 0 0 / 0.8);
}
.topbar strong#brand,
#brand {
  font-size: 15px;
  font-weight: 680;
  letter-spacing: -0.01em;
  /* 品牌名用渐变字：全站只有这一处 + 主按钮 + 统计数字用渐变，别铺开 */
  background: linear-gradient(96deg, #7fa3ff 0%, #a98bff 55%, #6f8dff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: #9db4ff;
}
.page-title {
  border-left-color: var(--line-strong);
  color: var(--ink-3);
}
.who { color: var(--ink-4); }

.sidebar {
  background: rgb(10 14 24 / 0.55);
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  border-right: 1px solid var(--line);
}

.nav-item {
  border-radius: var(--radius-sm);
  color: var(--ink-3);
  font-weight: 550;
  position: relative;
  transition: background 160ms cubic-bezier(.2,.8,.2,1),
              color 160ms cubic-bezier(.2,.8,.2,1);
}
.nav-item:hover {
  background: rgb(255 255 255 / 0.055);
  color: var(--ink);
}
.nav-item:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgb(91 140 255 / 0.55);
}
.nav-item[aria-current="page"] {
  background: linear-gradient(96deg, rgb(91 140 255 / 0.22), rgb(139 107 255 / 0.16));
  color: #dbe6ff;
  font-weight: 620;
  box-shadow: 0 1px 0 0 rgb(255 255 255 / 0.08) inset,
              0 8px 20px -14px rgb(91 140 255 / 0.9);
}
/* 选中项左侧一条发光的竖线：让人一眼知道"我在哪一页" */
.nav-item[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 2px; top: 50%;
  width: 2px; height: 18px;
  transform: translateY(-50%);
  border-radius: 2px;
  background: linear-gradient(180deg, #7fa3ff, #a98bff);
  box-shadow: 0 0 10px rgb(122 163 255 / 0.9);
}
.nav-item[aria-current="page"] .nav-ico { color: #9db4ff; }
.nav-ico { color: var(--ink-4); }

/* ---------------------------------------------------------------------------
 * 4. 卡片 —— 拟态玻璃的主战场
 *
 * 每张卡片三层：
 *   ::before  顶边渐隐高光条（1px）—— 光源从上方来的暗示
 *   background 深色半透明 + 顶部略亮的线性渐变（受光面朝上）
 *   box-shadow --neu-raise
 * ------------------------------------------------------------------------- */
.card {
  position: relative;
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.055) 0%, rgb(255 255 255 / 0.012) 42%, rgb(0 0 0 / 0.06) 100%),
    rgb(17 22 36 / 0.62);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--neu-raise);
  backdrop-filter: blur(28px) saturate(150%);
  -webkit-backdrop-filter: blur(28px) saturate(150%);
  transition: transform 180ms cubic-bezier(.2,.8,.2,1),
              box-shadow 180ms cubic-bezier(.2,.8,.2,1),
              border-color 180ms cubic-bezier(.2,.8,.2,1);
}
/* 顶边高光：中间最亮、两端渐隐，比"整条白线"自然得多 */
.card::before {
  content: "";
  position: absolute;
  left: 14px; right: 14px; top: 0;
  height: 1px;
  border-radius: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgb(255 255 255 / 0.16) 22%,
    rgb(255 255 255 / 0.24) 50%,
    rgb(255 255 255 / 0.16) 78%,
    transparent 100%);
  pointer-events: none;
}
.card:hover {
  border-color: rgb(255 255 255 / 0.14);
}
/* 只有"可交互"的卡片才做浮起。纯展示卡片跟着动会晃眼，
   所以默认不做 translateY，加 .is-lift 才生效。 */
.card.is-lift:hover {
  transform: translateY(-1px);
  box-shadow: var(--neu-raise-hover);
}

.card-head {
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgb(255 255 255 / 0.03), transparent);
  border-radius: var(--radius) var(--radius) 0 0;
}
.card-head h3 {
  color: var(--ink);
  font-size: 14px;
  font-weight: 640;
  letter-spacing: -0.005em;
}
.card-head .card-note { color: var(--ink-4); }

/* 统计卡：数字是主角，给它渐变 + 等宽数字 */
.stat {
  position: relative;
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.05), rgb(0 0 0 / 0.05)),
    rgb(16 21 35 / 0.6);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--neu-raise);
  padding: 14px 16px;
  overflow: hidden;
}
.stat::before {
  content: "";
  position: absolute;
  left: 12px; right: 12px; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.2), transparent);
}
.stat .k {
  color: var(--ink-4);
  font-size: var(--fs-xs);
  font-weight: 560;
  letter-spacing: 0.03em;
}
.stat .v {
  color: var(--ink);
  font-size: var(--fs-num);
  font-weight: 680;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  margin-top: 2px;
}
.stat .v small {
  color: var(--ink-4);
  font-size: var(--fs-sm);
  font-weight: 560;
  letter-spacing: 0;
  margin-left: 3px;
}
.stat .x { color: var(--ink-4); }
/* 语义统计卡：只把数字染色，别给整张卡铺底色（会破坏拟态的干净） */
.stat.is-ok .v { color: var(--ok); }
.stat.is-bad .v { color: var(--danger); }
.stat.is-brand .v {
  background: linear-gradient(96deg, #8fb2ff 0%, #b79aff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ---------------------------------------------------------------------------
 * 5. 按钮
 * ------------------------------------------------------------------------- */
.btn {
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: rgb(255 255 255 / 0.045);
  color: var(--ink-2);
  font-weight: 560;
  transition: background 150ms cubic-bezier(.2,.8,.2,1),
              border-color 150ms, color 150ms, transform 90ms;
  box-shadow: 0 1px 0 0 rgb(255 255 255 / 0.055) inset,
              0 1px 3px rgb(0 0 0 / 0.28);
}
.btn:hover {
  background: rgb(255 255 255 / 0.085);
  border-color: rgb(255 255 255 / 0.22);
  color: var(--ink);
}
.btn:active { transform: translateY(0.5px); }
.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgb(91 140 255 / 0.55);
}

/* 主按钮：全站唯一允许用渐变填充的元素 */
.btn-primary {
  background: linear-gradient(96deg, #5b8cff 0%, #8b6bff 100%);
  border-color: rgb(139 107 255 / 0.55);
  color: #fff;
  font-weight: 620;
  box-shadow:
    0 1px 0 0 rgb(255 255 255 / 0.28) inset,
    0 -1px 0 0 rgb(0 0 0 / 0.28) inset,
    0 10px 24px -12px rgb(91 140 255 / 0.85);
}
.btn-primary:hover {
  background: linear-gradient(96deg, #6e9aff 0%, #9a7cff 100%);
  border-color: rgb(154 124 255 / 0.7);
  box-shadow:
    0 1px 0 0 rgb(255 255 255 / 0.32) inset,
    0 -1px 0 0 rgb(0 0 0 / 0.3) inset,
    0 14px 30px -12px rgb(91 140 255 / 0.95);
}

.btn-danger {
  background: rgb(255 125 133 / 0.10);
  border-color: rgb(255 125 133 / 0.36);
  color: #ff9ba1;
  box-shadow: 0 1px 0 0 rgb(255 255 255 / 0.045) inset;
}
.btn-danger:hover {
  background: rgb(255 125 133 / 0.18);
  border-color: rgb(255 125 133 / 0.55);
  color: #ffb9be;
}

.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--ink-3);
  box-shadow: none;
}
.btn-ghost:hover {
  background: rgb(255 255 255 / 0.06);
  border-color: transparent;
  color: var(--ink);
}
.btn[disabled], .btn[aria-busy="true"] { opacity: 0.42; }

/* 复制小按钮：图标化后要有"可按"的手感 */
.copy-btn {
  border-radius: 7px;
  border: 1px solid var(--line-strong);
  background: rgb(255 255 255 / 0.05);
  color: var(--ink-3);
  box-shadow: 0 1px 0 0 rgb(255 255 255 / 0.05) inset;
  transition: all 130ms;
}
.copy-btn:hover {
  border-color: rgb(91 140 255 / 0.55);
  color: #a9c1ff;
  background: rgb(91 140 255 / 0.14);
}
.copy-btn[data-done="1"] {
  color: var(--ok);
  border-color: rgb(87 227 155 / 0.5);
  background: rgb(87 227 155 / 0.14);
}

/* ---------------------------------------------------------------------------
 * 6. 表单
 * ------------------------------------------------------------------------- */
input, select, textarea,
.filter-bar input, .filter-bar select,
.modal-form input, .modal-form select,
.login-card .field > input {
  background: rgb(8 11 19 / 0.62);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--ink);
  box-shadow: var(--neu-inset);
  transition: border-color 150ms, box-shadow 150ms, background 150ms;
}
input::placeholder, textarea::placeholder { color: var(--ink-4); }
input:focus, select:focus, textarea:focus,
.filter-bar input:focus, .filter-bar select:focus,
.modal-form input:focus, .modal-form select:focus {
  background: rgb(10 14 24 / 0.8);
  border-color: rgb(91 140 255 / 0.72);
  box-shadow: var(--neu-inset), 0 0 0 3px rgb(91 140 255 / 0.18);
  outline: none;
}
/* 下拉的选项列表是原生渲染，深色模式下给个兜底底色 */
select option { background: #10151f; color: var(--ink); }

.filter-bar label > span,
.modal-form label > span,
.login-card .field > span {
  color: var(--ink-3);
  font-weight: 560;
}

/* ---------------------------------------------------------------------------
 * 7. 表格 —— **不半透明**
 *
 * 这是业务后台，一屏要看 14 行、每行 12 列数字。
 * 毛玻璃会让相邻行互相渗色，读数成本极高。所以表格用近实心深色，
 * 只保留一点点"玻璃感"（边框与顶边高光），不做 backdrop-filter。
 * ------------------------------------------------------------------------- */
.dense-table { color: var(--ink-2); }

.dense-table thead th {
  background: rgb(12 16 27 / 0.94);
  color: var(--ink-4);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.045em;
  border-bottom: 1px solid var(--line-strong);
  padding: 10px 10px;
}
.dense-table tbody td {
  color: var(--ink-2);
  border-bottom: 1px solid var(--line);
  padding: 0 10px;
  background: transparent;
}
.dense-table tbody tr { transition: background 120ms; }
.dense-table tbody tr:hover td { background: rgb(255 255 255 / 0.042); }
.dense-table tbody tr:last-child td { border-bottom: none; }

/* 数字列统一等宽，避免"1.00"和"¥0.50"宽度跳动 */
.dense-table .num, .stat .v, .table-sum b, .group-meta b {
  font-variant-numeric: tabular-nums;
}
.dense-table .mono { color: var(--ink-3); }

/* 表格容器的边框与圆角：表格本身不加毛玻璃，靠外层卡片的玻璃衬托 */
.table-scroll {
  border-radius: var(--radius-sm);
  /* 列多时（自定义字段会一直加列）必须能横向滚，不能被父级裁掉 */
  overflow-x: auto;
  overflow-y: visible;
  max-width: 100%;
}

/* ★ 关键：不让表格被 100% 强行压缩。
   原来 `width:100%` + 每格 `nowrap`，列一多浏览器就把列压窄，
   内容溢出到卡片外被裁掉 ——「操作」列只露半个就是这么来的。
   改成 `width: max-content` + `min-width: 100%`：
   内容少时撑满（不显空），内容多时按内容撑开，交给外层横向滚动。 */
.dense-table {
  width: max-content;
  min-width: 100%;
}
.dense-table thead th,
.dense-table tbody td {
  /* 给每列一个下限，避免中文被压成竖排；上限避免单格撑爆整表 */
  min-width: 64px;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* 第一列（勾选框/#）与操作列不需要这么宽 */
.dense-table thead th:first-child,
.dense-table tbody td:first-child { min-width: 38px; max-width: 48px; }
.dense-table thead th:last-child,
.dense-table tbody td:last-child { min-width: 150px; max-width: none; overflow: visible; }

/* ★ 操作列钉在右边。
   为什么：自定义字段会让列数不断增长（现在已经有院系/校区/年级三列额外列），
   默认视图里"操作"列会被推出屏幕外 —— 用户看得到数据却找不到按钮，
   而且不一定意识到要横向滚动。把操作列 sticky 在右侧，
   无论加多少字段，按钮始终可点。
   勾选框列同理钉在左边（批量操作时要一直看得见选中状态）。 */
.dense-table thead th:last-child,
.dense-table tbody td:last-child {
  position: sticky;
  right: 0;
  z-index: 2;
  background: rgb(13 17 29 / 0.98);
  box-shadow: -10px 0 16px -12px rgb(0 0 0 / 0.9);
}
.dense-table thead th:last-child { z-index: 3; background: rgb(12 16 27 / 0.99); }

.dense-table thead th:first-child,
.dense-table tbody td:first-child {
  position: sticky;
  left: 0;
  z-index: 2;
  background: rgb(13 17 29 / 0.98);
}
.dense-table thead th:first-child { z-index: 3; background: rgb(12 16 27 / 0.99); }

/* sticky 单元格里的 hover 底色要跟着亮，否则悬停时那一格是"洞" */
.dense-table tbody tr:hover td:first-child,
.dense-table tbody tr:hover td:last-child {
  background: rgb(28 34 52 / 0.98);
}

/* 汇总行 */
.table-sum {
  color: var(--ink-4);
  border-top: 1px solid var(--line);
  background: linear-gradient(180deg, transparent, rgb(255 255 255 / 0.018));
}
.table-sum b { color: var(--ink-2); font-weight: 620; }

/* 分组头（今日待跑按代理分组的那一栏） */
.group-head {
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgb(255 255 255 / 0.035), transparent);
}
.group-name { color: var(--ink); font-weight: 650; }
.group-meta { color: var(--ink-4); }
.group-meta b { color: var(--ink-2); font-weight: 620; }

/* ---------------------------------------------------------------------------
 * 8. 徽标 / 状态
 * ------------------------------------------------------------------------- */
.badge {
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: rgb(255 255 255 / 0.055);
  color: var(--ink-3);
  font-weight: 570;
  letter-spacing: 0.01em;
}
.badge-ok {
  color: var(--ok);
  background: var(--ok-soft);
  border-color: rgb(87 227 155 / 0.36);
}
.badge-brand {
  color: #a9c1ff;
  background: rgb(91 140 255 / 0.16);
  border-color: rgb(91 140 255 / 0.38);
}
.badge-muted {
  color: var(--ink-4);
  background: rgb(255 255 255 / 0.045);
  border-color: var(--line);
}

/* 金额正负：深色底上"红/绿"要亮，暗红暗绿看不见 */
.money-neg { color: var(--danger); font-weight: 640; }
.money-pos { color: var(--ok); font-weight: 600; }

.mark-done { color: var(--ok); font-weight: 600; }
.mark-bad { color: var(--danger); font-weight: 600; }
.mark-void { color: var(--ink-4); }
.mark-none { color: var(--ink-4); }

/* ---------------------------------------------------------------------------
 * 9. 弹窗
 * ------------------------------------------------------------------------- */
.modal-mask {
  background: rgb(4 6 12 / 0.66);
  backdrop-filter: blur(6px) saturate(120%);
  -webkit-backdrop-filter: blur(6px) saturate(120%);
}
.modal-box {
  position: relative;
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.06), rgb(0 0 0 / 0.08)),
    rgb(15 20 33 / 0.96);
  border: 1px solid rgb(255 255 255 / 0.12);
  border-radius: var(--radius);
  box-shadow:
    0 1px 0 0 rgb(255 255 255 / 0.12) inset,
    0 40px 90px -40px rgb(0 0 0 / 0.9),
    0 8px 24px -12px rgb(0 0 0 / 0.6);
  backdrop-filter: blur(30px) saturate(150%);
  -webkit-backdrop-filter: blur(30px) saturate(150%);
  animation: pp-modal-in 190ms cubic-bezier(.2,.8,.2,1);
}
.modal-box::before {
  content: "";
  position: absolute;
  left: 16px; right: 16px; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.26), transparent);
}
@keyframes pp-modal-in {
  from { opacity: 0; transform: translateY(8px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
.modal-head {
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgb(255 255 255 / 0.04), transparent);
}
.modal-head h3 { color: var(--ink); font-weight: 650; }
.modal-body p { color: var(--ink-2); }
.modal-foot { border-top: 1px solid var(--line); }

/* ---------------------------------------------------------------------------
 * 10. toast
 * ------------------------------------------------------------------------- */
.toast {
  border-radius: var(--radius-sm);
  background: rgb(16 21 35 / 0.95);
  border: 1px solid var(--line-strong);
  color: var(--ink);
  box-shadow:
    0 1px 0 0 rgb(255 255 255 / 0.07) inset,
    0 20px 44px -20px rgb(0 0 0 / 0.85);
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  animation: pp-toast-in 180ms cubic-bezier(.2,.8,.2,1);
}
.toast[data-kind="ok"] {
  border-color: rgb(87 227 155 / 0.42);
  background: rgb(10 26 20 / 0.95);
  color: #8bf0bb;
}
.toast[data-kind="warn"] {
  border-color: rgb(255 203 92 / 0.42);
  background: rgb(28 22 8 / 0.95);
  color: #ffd98a;
}
.toast[data-kind="err"] {
  border-color: rgb(255 125 133 / 0.42);
  background: rgb(30 12 14 / 0.95);
  color: #ffa4a9;
}
@keyframes pp-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------------------
 * 11. 折叠区 / 空态 / 分页 / 筛选栏
 * ------------------------------------------------------------------------- */
.fold {
  background: rgb(15 20 33 / 0.55);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: 0 1px 0 0 rgb(255 255 255 / 0.04) inset;
}
.fold > summary { color: var(--ink-2); font-weight: 600; }
.fold-body { color: var(--ink-2); }
.blocked-row { color: var(--ink-2); }
.blocked-row + .blocked-row { border-top: 1px dashed var(--line); }

.empty-slot, .loading-slot { color: var(--ink-4); }
.section-title h2 { color: var(--ink); font-weight: 650; }
.section-title .hint { color: var(--ink-4); }

.pager { color: var(--ink-4); }
.pager b { color: var(--ink-2); }

.filter-bar { border-bottom: 1px solid var(--line); }

/* ---------------------------------------------------------------------------
 * 12. 一次性凭据 / 壁纸页
 * ------------------------------------------------------------------------- */
.secret-box {
  background: linear-gradient(180deg, rgb(91 140 255 / 0.12), rgb(139 107 255 / 0.07));
  border: 1px dashed rgb(91 140 255 / 0.45);
  border-radius: var(--radius-sm);
}
.secret-line { color: var(--ink-2); }
.secret-line code {
  background: rgb(8 11 19 / 0.8);
  border: 1px solid var(--line-strong);
  color: #b7c8ff;
}
.secret-warn { color: var(--warn); }

.wall-preview {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--neu-inset);
  background-color: rgb(8 11 19 / 0.7);
}
.wall-meta { color: var(--ink-4); }
.file-pick {
  background: rgb(255 255 255 / 0.05);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  box-shadow: 0 1px 0 0 rgb(255 255 255 / 0.05) inset;
}
.file-pick:hover {
  border-color: rgb(91 140 255 / 0.55);
  color: var(--ink);
  background: rgb(91 140 255 / 0.1);
}

/* ---------------------------------------------------------------------------
 * 13. 登录页
 * ------------------------------------------------------------------------- */
.login-body {
  background-image:
    radial-gradient(ellipse 70% 55% at 50% 8%, rgb(91 140 255 / 0.22) 0%, transparent 60%),
    radial-gradient(ellipse 60% 50% at 50% 100%, rgb(139 107 255 / 0.18) 0%, transparent 55%),
    linear-gradient(165deg, #070a11 0%, #0b1020 55%, #0e1424 100%);
}
.login-card {
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.07), rgb(0 0 0 / 0.06)),
    rgb(15 20 33 / 0.78);
  border: 1px solid rgb(255 255 255 / 0.12);
  border-radius: 20px;
  box-shadow:
    0 1px 0 0 rgb(255 255 255 / 0.14) inset,
    0 -1px 0 0 rgb(0 0 0 / 0.4) inset,
    0 44px 90px -40px rgb(0 0 0 / 0.92),
    0 10px 30px -16px rgb(0 0 0 / 0.7);
  backdrop-filter: blur(32px) saturate(155%);
  -webkit-backdrop-filter: blur(32px) saturate(155%);
}
.login-card::before {
  content: "";
  position: absolute;
  left: 20px; right: 20px; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.3), transparent);
}
/* h1.login-brand：必须带元素名提高优先级。
   ui.css / tokens.css 里有 `h1 { color: var(--ink) }`，单靠 .login-brand 一个类
   会被它压过去 —— 表现就是"品牌名是白字，渐变没出来"。 */
h1.login-brand {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
  background: linear-gradient(96deg, #a9c1ff 0%, #c2a8ff 52%, #8fb2ff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  /* 渐变字在某些浏览器需要显式声明，否则 transparent 会被判为无效而回落到 color */
  background-color: transparent;
}
.login-sub { color: var(--ink-4); letter-spacing: 0.08em; }
.login-hint { color: var(--ink-4); }
.login-err {
  background: rgb(255 125 133 / 0.12);
  border: 1px solid rgb(255 125 133 / 0.38);
  border-radius: var(--radius-sm);
  color: #ffa4a9;
}

/* 黄条（首次登录必须改密） */
.banner {
  background: linear-gradient(96deg, rgb(255 203 92 / 0.16), rgb(255 203 92 / 0.08));
  border: 1px solid rgb(255 203 92 / 0.4);
  border-radius: var(--radius-sm);
  color: #ffd98a;
}

/* ---------------------------------------------------------------------------
 * 14. 滚动条（高端感藏在细节里）
 * ------------------------------------------------------------------------- */
* { scrollbar-width: thin; scrollbar-color: rgb(255 255 255 / 0.18) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgb(255 255 255 / 0.14);
  border-radius: 99px;
  border: 3px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: rgb(255 255 255 / 0.26); background-clip: padding-box; }

/* ---------------------------------------------------------------------------
 * 15. 响应式：三档而不是一档
 *
 * 只写 720px 一档覆盖不了真实设备：
 *   ≤430  手机竖屏（iPhone 12~15、多数安卓）—— 表格必然横向滚，重点是"别卡死"
 *   ≤768  手机横屏 / 小平板 —— 侧栏必须让位，主内容要满宽
 *   ≤1024 竖屏平板 / 小笔记本 —— 侧栏收窄成图标条
 * 桌面端（>1024）不需要额外规则，默认已是宽布局。
 *
 * 原则：**表格永远可以横向滚，操作列永远固定**。
 * 业务后台在手机上不可能"一屏看全 12 列"，能滚 + 按钮够大就是正确形态。
 * ------------------------------------------------------------------------- */

/* ---- 竖屏平板 / 小笔记本：侧栏收窄 ---- */
@media (max-width: 1024px) {
  body { --sidebar-w: 62px; }
  .nav-label { display: none; }
  .nav-item {
    justify-content: center;
    padding: 0 6px;
  }
  .nav-ico { width: auto; font-size: 15px; }
  .nav-item[aria-current="page"]::before { display: none; }
  /* 收窄后仍要能看出"这是哪一页"：靠选中底色 + 图标颜色 */
  .main { padding: 16px 14px 32px; }
}

/* ---- 手机横屏 / 小平板：侧栏变成顶部横条 ---- */
@media (max-width: 768px) {
  body { --sidebar-w: auto; --topbar-h: 52px; }
  .shell {
    flex-direction: column;
    /* stretch 会让侧栏吃掉整个剩余高度（变成一条竖着的空白），必须改成 flex-start */
    align-items: stretch;
  }
  .sidebar {
    position: sticky;
    top: var(--topbar-h);
    z-index: 6;
    display: flex;
    flex-direction: row;
    /* 横条模式下自身高度必须由内容决定，不能跟随容器拉伸 */
    align-self: flex-start;
    height: auto;
    max-height: 52px;
    gap: 4px;
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 6px 10px;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    background: rgb(10 14 24 / 0.88);
    backdrop-filter: blur(22px) saturate(145%);
    -webkit-backdrop-filter: blur(22px) saturate(145%);
    scrollbar-width: none;
  }
  .sidebar::-webkit-scrollbar { display: none; }
  .nav-item {
    flex: 0 0 auto;
    white-space: nowrap;
    min-height: 36px;
    padding: 0 12px;
  }
  .nav-item + .nav-item { margin-top: 0; }
  /* 横条模式下必须显示标签：光有图标没人看得懂 ——
     这条要压过 1024px 档的 .nav-label{display:none}，
     所以用更具体的选择器而不是靠顺序（两档都是 max-width，会同时命中）。 */
  .sidebar .nav-item .nav-label { display: inline; }
  .nav-item[aria-current="page"]::before { display: none; }
  .nav-item[aria-current="page"] {
    background: linear-gradient(96deg, rgb(91 140 255 / 0.24), rgb(139 107 255 / 0.18));
  }
  .main {
    padding: 12px 10px 28px;
    min-height: calc(100vh - var(--topbar-h) - 52px);
  }
  .card { border-radius: 14px; }
  .card-head { padding: 11px 13px; }
  .card-body { padding: 12px 13px; }
  .card-body.tight { padding: 0; }

  /* 统计卡：2 列而不是 4 列挤成一排 */
  .stat-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .stat { padding: 11px 12px; }
  .stat .v { font-size: 20px; }

  /* 筛选栏：控件换行堆叠，别把输入框压成 40px 宽 */
  .filter-bar {
    gap: 8px;
    padding: 10px 12px;
    align-items: stretch;
  }
  .filter-bar label { flex: 1 1 132px; min-width: 0; }
  .filter-bar .grow { flex: 1 1 100%; }
  .filter-bar input,
  .filter-bar select { width: 100%; min-height: 38px; }

  /* 表格：允许横向滚，操作列与勾选列继续 sticky（premium.css 上半部分已设） */
  .dense-table thead th,
  .dense-table tbody td { padding: 0 9px; }
  .dense-table tbody td { height: 46px; }     /* 触屏要 ≥44px 才好点 */

  .modal-box { max-width: none; border-radius: 16px; }
  .modal-body { padding: 13px; }
  .modal-form .row2 { flex-direction: column; gap: 0; }
  .toast-host { left: 12px; right: 12px; bottom: 12px; }
  .toast { max-width: none; }
}

/* ---- 手机竖屏：最紧凑的一档 ---- */
@media (max-width: 430px) {
  body { --topbar-h: 50px; }
  .topbar { padding: 0 10px; }
  #brand { font-size: 14px; }
  .page-title { display: none; }      /* 50px 高的顶栏塞不下品牌 + 页名 + 用户 + 退出 */
  .who { display: none; }
  .main { padding: 10px 8px 24px; }
  .stat-grid { gap: 7px; }
  .stat .v { font-size: 18px; }
  .stat .k { font-size: 11px; }
  .card { border-radius: 12px; }
  .card-head h3 { font-size: 13px; }
  .btn { min-height: 38px; }
  .btn-sm { min-height: 34px; padding: 0 9px; }
  .filter-bar label { flex: 1 1 100%; }

  /* 导航横条：高度必须够，否则文字被 padding 挤掉下半截 */
  .sidebar {
    height: auto;
    max-height: none;
    min-height: 44px;
    padding: 5px 8px;
  }
  .nav-item {
    min-height: 34px;
    padding: 0 10px;
    font-size: 12.5px;
    /* 图标在这种宽度下是噪音，只留文字 */
  }
  .nav-ico { display: none; }
  .nav-label { line-height: 34px; }

  .dense-table tbody td { height: 46px; }
  /* 竖屏下每列再收一点，否则横向滚动要划很久才看到字段列 */
  .dense-table thead th,
  .dense-table tbody td { min-width: 48px; padding: 0 7px; }

  /* ★ 竖屏下**取消操作列 sticky**。
     为什么：390px 宽时 sticky 的 108px 会盖住中间所有字段列，
     用户横向滚动看到的是"一半字段 + 固定的操作列"，反而更乱。
     竖屏的正确形态是：一张能滚的完整表格，按钮跟在最后。
     代价是要划到最右才能点按钮 —— 但代理在手机上主要是"看进度"，
     真正的批量操作是在电脑上做的。 */
  .dense-table thead th:last-child,
  .dense-table tbody td:last-child {
    position: static;
    min-width: 96px;
    max-width: none;
    background: transparent;
    box-shadow: none;
  }
  .dense-table thead th:first-child,
  .dense-table tbody td:first-child {
    position: static;
    background: transparent;
  }
  /* 按钮不换行，四个并排：34px 高在 96px 宽里放不下，
     所以竖屏只保留两个最常用的（设目标 / 改里程），其余靠行点击进详情 —— 
     但当前没有详情弹层，所以这里退回：允许两行 + 紧凑字号，行高自动撑开。 */
  .dense-table td .actions {
    flex-wrap: wrap;
    gap: 3px;
    max-width: 108px;
  }
  .dense-table td .actions .btn {
    min-height: 30px;
    height: 30px;
    font-size: 11px;
    padding: 0 6px;
    line-height: 28px;
  }
  /* 行高交给内容，别把两行按钮裁掉 */
  .dense-table tbody td:last-child { height: auto; padding-top: 5px; padding-bottom: 5px; }

  .table-sum { font-size: 11px; gap: 4px 10px; }
  .login-wrap { max-width: none; padding: 0 4px; }
  .login-card { border-radius: 16px; }
  .login-brand { font-size: 19px; }

  /* 竖屏宽表格：在表格上方给一句滚动提示。
     13 列信息塞不进 390px，这是物理限制；与其硬压成残废的列，
     不如明确告诉用户"可以左右滑"，避免以为数据缺失。 */
  .table-scroll { position: relative; }
  .table-scroll::after {
    content: "← 左右滑动查看更多 →";
    position: sticky;
    left: 0;
    display: block;
    width: max-content;
    padding: 3px 8px;
    font-size: 10.5px;
    color: var(--ink-4);
    letter-spacing: 0.02em;
    opacity: 0.85;
    pointer-events: none;
  }
}

/* ---- 触屏设备：去掉 hover 造成的"粘住"效果 ---- */
@media (hover: none) {
  .card.is-lift:hover { transform: none; box-shadow: var(--neu-raise); }
  .dense-table tbody tr:hover td { background: transparent; }
  .dense-table tbody tr:hover td:first-child,
  .dense-table tbody tr:hover td:last-child { background: rgb(13 17 29 / 0.98); }
  .btn:hover { background: rgb(255 255 255 / 0.045); border-color: var(--line-strong); }
  .btn-primary:hover { background: linear-gradient(96deg, #5b8cff 0%, #8b6bff 100%); }
  .nav-item:hover { background: transparent; color: var(--ink-3); }
}

/* ---- 超宽屏：内容不无限拉伸 ---- */
@media (min-width: 1800px) {
  .main { padding: 24px 32px 48px; }
  .card, .stat-grid { max-width: 1600px; }
}


/* ---------------------------------------------------------------------------
 * 16. 降低动态效果（无障碍）
 * ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .card, .btn, .copy-btn, .nav-item, .toast, .modal-box,
  .dense-table tbody tr, input, select, textarea {
    transition: none !important;
    animation: none !important;
  }
  .card.is-lift:hover { transform: none; }
}
