/* ==========================================================================
   全局变量与主题系统 (CSS Variables)

   ── v3.1.0 界面改造（2026-09-18）────────────────────────────────────────────
   用户要求界面参照 learn.oaiai.ai 的风格：**网格底纹 + 大标题 + 卡片式分区**。
   ⚠️ 远程站点的原始 CSS 取不到（WebFetch 只拿回渲染文本），故这里是**按描述做**，
      不是照抄 —— 做出来是给人看的，不满意就调令牌，不改结构。

   做法边界（刻意守住）：
   · **只动令牌与容器层**，业务模块选择器一个不改 ⇒ 37 个业务键的渲染不受影响；
   · **变量名全部保留**（--primary-color/--bg-card/…）⇒ 其它文件里的
     `var(--bg-card)` 引用照常解析，不必全仓搜替换；
   · **卡片保持不透明纯色**，不做玻璃拟态 —— 财务数字要清晰；
   · 底纹画在 `html::before` 一层上 ⇒ 不新增 DOM、不参与重排、不盖住任何内容。
   ========================================================================== */
:root {
  /* 品牌与核心色彩 */
  --primary-color: #5b5bd6;
  --primary-hover: #4a4ac4;
  --primary-light: rgba(91, 91, 214, 0.10);
  --primary-ring: rgba(91, 91, 214, 0.18);

  /* 功能状态颜色 */
  --income-color: #0f9d70;
  --income-light: rgba(15, 157, 112, 0.12);
  --expense-color: #dc4b4b;
  --expense-light: rgba(220, 75, 75, 0.12);
  --transfer-color: #7c5cd6;
  --transfer-light: rgba(124, 92, 214, 0.12);
  --warning-color: #d99212;
  --warning-light: rgba(217, 146, 18, 0.14);

  /* 亮色模式底色与字色 */
  --bg-main: #f5f6fa;
  --bg-card: #ffffff;
  --bg-input: #f1f2f7;
  --bg-inset: #f8f9fc;
  --text-main: #16181f;
  --text-muted: #6b7280;
  --border-color: #e5e7ee;
  --border-strong: #d3d6e0;
  --shadow-sm: 0 1px 2px rgba(16, 18, 31, 0.05), 0 1px 3px rgba(16, 18, 31, 0.04);
  --shadow-md: 0 4px 10px rgba(16, 18, 31, 0.07), 0 1px 3px rgba(16, 18, 31, 0.04);
  --shadow-lg: 0 18px 40px rgba(16, 18, 31, 0.14);
  --glass-bg: rgba(255, 255, 255, 0.88);
  --glass-border: rgba(255, 255, 255, 0.5);

  /* 网格底纹（v3.1.0）：格子 32px、线宽 1px。
     透明度刻意压到 0.038/0.055：底纹的作用是「分区感」而不是「被看见」——
     一旦能一眼看清格子，报表数字的对比度就会被拖下来。 */
  --grid-line: rgba(16, 18, 31, 0.038);
  --grid-line-strong: rgba(16, 18, 31, 0.055);
  --grid-size: 32px;

  /* 圆角与动画 transition */
  --radius-sm: 8px;
  --radius-md: 14px;
  --radius-lg: 20px;
  --transition-fast: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-normal: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

  /* 字号阶梯（v3.1.0）：档位之间保持约 1.25 倍，避免「1.1 / 1.25」这种
     分不清谁大谁小的密集档位（改造前 .card-title 1.1 与 .modal-title 1.25 挨得过近） */
  --fs-display: 1.7rem;
  --fs-h1: 1.45rem;
  --fs-h2: 1.15rem;
  --fs-body: 0.95rem;
  --fs-caption: 0.8rem;
  --tracking-display: -0.02em;
  --tracking-label: 0.06em;
}

/* 暗黑模式重置变量 */
[data-theme="dark"] {
  --bg-main: #0b0f1a;
  --bg-card: #151a27;
  --bg-input: #1e2434;
  --bg-inset: #111623;
  --text-main: #eef1f7;
  --text-muted: #98a1b3;
  --border-color: #262d3e;
  --border-strong: #333c52;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 18px 40px rgba(0, 0, 0, 0.6);
  --glass-bg: rgba(21, 26, 39, 0.9);
  --glass-border: rgba(255, 255, 255, 0.08);
  --primary-color: #7b7bf0;
  --primary-hover: #8f8ff5;
  --primary-light: rgba(123, 123, 240, 0.16);
  --primary-ring: rgba(123, 123, 240, 0.24);
  --income-color: #34c795;
  --expense-color: #f07171;
  --transfer-color: #a48bf0;
  /* 暗色下的网格线要**更淡**而不是更亮：深底上白线极易变成可见条纹 */
  --grid-line: rgba(255, 255, 255, 0.028);
  --grid-line-strong: rgba(255, 255, 255, 0.042);
}

/* ==========================================================================
   基础与 Reset
   ========================================================================== */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

body {
  background-color: var(--bg-main);
  color: var(--text-main);
  line-height: 1.5;
  transition: background-color 0.3s, color 0.3s;
  min-height: 100vh;
}

/* ── 网格底纹（v3.1.0 界面改造）─────────────────────────────────────────────
 *
 * 用户要求「网格底纹」参照 learn.oaiai.ai。做法与权衡：
 *
 * · **画在 `html::before` 而不是 `body` 背景上**：body 有自己的背景色，
 *   若把图案写在 body 的 `background-image` 上，图案会**跟着内容滚走**
 *   （只在页面顶部可见）；固定在视口上才是「底纹」而不是「一条花纹」。
 * · `z-index: -1` + 挂在 `html` 上 ⇒ 不参与布局、不盖住任何元素，
 *   也不需要给 37 个业务面板逐个调 z-index。
 * · **点阵而非实线格**：实线格与表格 `border-collapse` 的边框会在同一水平线上，
 *   让表格看起来「多了一层外框」，点阵不会。
 * · 两档点阵（32px 细点 + 128px 略重的点）叠出层次，否则整片底纹是平的。
 * · `pointer-events: none` —— 底纹绝不能截走点击（否则整页点不动，且极难定位）。
 * · 打印时 `display: none`：底纹耗碳粉，且与「打印出来对账」无关。
 *
 * ⚠️ 浏览器用例读它时**必须查伪元素**（`getComputedStyle(html, '::before')`）：
 *    量 `html` 自身的 `backgroundImage` 永远是 none，那是恒真的假判据。
 */
html::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(circle at center, var(--grid-line) 1px, transparent 1.2px),
    radial-gradient(circle at center, var(--grid-line-strong) 1.4px, transparent 1.6px);
  background-size: var(--grid-size) var(--grid-size),
                   calc(var(--grid-size) * 4) calc(var(--grid-size) * 4);
  background-position: 0 0, 0 0;
}

@media print {
  html::before { display: none; }
  /* 🔴 v3.9.1：打印 / 存 PDF 时**不能出现界面控件**。`#jump-nav`（右下角那对「到表头 / 到表尾」
     的圆形按钮）在 `.app-container` **之外**，而发票打印路径只藏了 `.app-container` 与
     `.modal-overlay` ⇒ 它会**被一起印进发票**（用户 2026-10-13 报的截图）。这里统一藏掉。 */
  #jump-nav { display: none !important; }
}

/* 按钮重置 */
button {
  cursor: pointer;
  border: none;
  background: none;
  font-size: 1rem;
  transition: var(--transition-fast);
}

/* ==========================================================================
   布局结构 (Layout)
   ========================================================================== */
.app-container {
  display: flex;
  min-height: 100vh;
}

/* 侧边栏 Sidebar */
.sidebar {
  width: 260px;
  background-color: var(--bg-card);
  border-right: 1px solid var(--border-color);
  display: flex;
  flex-direction: column;
  padding: 1.5rem;
  position: fixed;
  height: 100vh;
  z-index: 100;
  transition: var(--transition-normal);
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 2.5rem;
}

.brand-icon {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.brand-title {
  font-size: 1.2rem;
  font-weight: 800;
  letter-spacing: var(--tracking-display);
}

.nav-menu {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  flex: 1;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.72rem 1rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-weight: 500;
  font-size: var(--fs-body);
  text-decoration: none;
  transition: var(--transition-fast);
  border: 1px solid transparent;
}

.nav-item:hover {
  background-color: var(--primary-light);
  color: var(--primary-color);
}

.nav-item.active {
  background-color: var(--primary-color);
  color: #ffffff;
  border-color: var(--primary-color);
  box-shadow: 0 3px 10px var(--primary-ring);
}

.nav-item i {
  font-size: 1.15rem;
}

.sidebar-footer {
  padding-top: 1rem;
  border-top: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.theme-toggle-btn {
  padding: 0.5rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
}

.theme-toggle-btn:hover {
  background-color: var(--bg-input);
  color: var(--text-main);
}

/* 主内容区 Main Content */
.main-content {
  margin-left: 260px;
  flex: 1;
  padding: 2rem;
  max-width: 1400px;
  /* 🔴 flex 子项默认 `min-width: auto` —— **不会收缩到比内容更窄**（2026-09-17 实测）。
   * 表格单元格多为 `white-space: nowrap`，把这一项撑到内容宽度，于是
   * `.transactions-table-wrapper` 的 `overflow-x: auto` **永远不触发**，
   * 溢出被推给整个页面：900px 视口下实测 `document.scrollWidth = 1660`
   * （= margin-left 260 + max-width 1400，分毫不差）。
   * 后果：宽表最右边的「操作」列被推出屏幕，用户以为功能不存在
   * —— 2026-09-17 用户报「账单确认里没有修改和删除」，真因就是这个。
   * ⚠️ 这也是为什么「给操作列加 sticky」单独做没用：sticky 吸附的是**容器**右缘，
   *    而容器右缘当时本身就在屏幕外（实测 x≈1603 > 视口 900）。
   * ⇒ 必须先让容器收缩回视口内，sticky 才有意义。两者缺一不可。
   */
  min-width: 0;
}

.header-bar {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1.25rem;
  margin-bottom: 1.6rem;
  flex-wrap: wrap;
}

/* ── 大标题区（v3.1.0 界面改造）────────────────────────────────────────────
 * 参照 learn.oaiai.ai 的「大标题 + 小标签」：标题加粗加大、行高收紧，
 * 上方一行极小的全大写标签（eyebrow）说明「这是哪个板块」。
 * 标签用 `letter-spacing` 拉开而不是加字重 —— 全大写小字加粗会糊成一团。
 */
.page-title h1 {
  font-size: var(--fs-display);
  font-weight: 800;
  letter-spacing: var(--tracking-display);
  line-height: 1.15;
}

.page-title p {
  color: var(--text-muted);
  font-size: var(--fs-body);
  margin-top: 0.35rem;
}

.page-eyebrow {
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--text-muted);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  margin-bottom: 0.3rem;
}

.header-actions {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  align-items: center;
  /* 顶栏右侧那组按钮（导出/导入/恢复/双跑核对/附件盘点/记一笔…）在 1440px 下
   * 会换行，而换行后**「记一笔」被推到第二行**（v3.1.0 改造时实测截图确认）。
   * 「记一笔」是全站最常用的入口，被挤下去是实打实的退步。
   * 取 `justify-content: flex-end`：主按钮保持在**末位**，换行时它落在第二行右端，
   * 仍是视觉终点。
   * ⚠️ 不改成「单行 nowrap」—— 那会让窄窗口下按钮被压扁或溢出屏幕。 */
  justify-content: flex-end;
}

/* 按钮组件 */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.62rem 1.15rem;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.9rem;
  border: 1px solid transparent;
  white-space: nowrap;
}

.btn-primary {
  background-color: var(--primary-color);
  color: #ffffff;
  border-color: var(--primary-color);
  box-shadow: 0 3px 10px var(--primary-ring);
}

.btn-primary:hover {
  background-color: var(--primary-hover);
  border-color: var(--primary-hover);
  transform: translateY(-1px);
}

.btn-secondary {
  background-color: var(--bg-card);
  color: var(--text-main);
  border: 1px solid var(--border-color);
}

.btn-secondary:hover {
  background-color: var(--bg-input);
  border-color: var(--border-strong);
}

.btn-danger {
  background-color: var(--expense-light);
  color: var(--expense-color);
}

.btn-danger:hover {
  background-color: var(--expense-color);
  color: #fff;
}

.btn-warning {
  background-color: var(--warning-color);
  color: #ffffff;
  box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);
}

.btn-warning:hover {
  background-color: #d97706;
  transform: translateY(-1px);
}

/* ==========================================================================
   仪表盘与统计卡片 (Overview Cards)
   ========================================================================== */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2rem;
}

.stat-card {
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1.35rem;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  transition: var(--transition-fast);
}

.stat-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  border-color: var(--border-strong);
}

.stat-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.01em;
}

.stat-icon {
  width: 38px;
  height: 38px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
}

.stat-icon.total {
  background-color: var(--primary-light);
  color: var(--primary-color);
}

.stat-icon.income {
  background-color: var(--income-light);
  color: var(--income-color);
}

.stat-icon.expense {
  background-color: var(--expense-light);
  color: var(--expense-color);
}

.stat-icon.balance {
  background-color: var(--transfer-light);
  color: var(--transfer-color);
}

.stat-amount {
  font-size: 1.7rem;
  font-weight: 800;
  margin: 0.7rem 0 0.25rem 0;
  letter-spacing: var(--tracking-display);
  font-variant-numeric: tabular-nums;
}

.stat-footer {
  font-size: var(--fs-caption);
  color: var(--text-muted);
}

/* ==========================================================================
   图表与主要板块 (Charts & Sections)
   ========================================================================== */
.charts-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 1.5rem;
  margin-bottom: 2rem;
}

@media (max-width: 1024px) {
  .charts-grid {
    grid-template-columns: 1fr;
  }
}

.card {
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1.5rem;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.25s;
}

.card:hover {
  box-shadow: var(--shadow-md);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.25rem;
}

/* ── 卡片分区标题（v3.1.0）────────────────────────────────────────────────
 * 标题左侧一根 3px 竖条。**只用 `box-shadow: inset` 画，不新增 DOM 节点**
 * —— `.card-title` 在 index.html 里出现 14 次、app.js 里更多，逐个加 `<span>`
 * 动的是 HTML 契约，风险大且没必要。竖条用 `--primary-color`，
 * 暗色主题下该变量自己会变亮，不必单独写一套。
 * `padding-left` 必须同时给，否则竖条会压在第一个字上。
 */
.card-title {
  font-size: var(--fs-h2);
  font-weight: 700;
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: center;
  padding-left: 0.6rem;
  box-shadow: inset 3px 0 0 0 var(--primary-color);
}

/* 嵌套卡片（收在 `revenue-panel` 等容器里的内层 `.card`）**不重复画竖条** ——
 * 一根接一根会变成花纹，反而看不出分区。
 * ⚠️ 选择器写成 `.card > * > .card`（隔一层），**不能用 `.card .card`**：
 *    index.html 里 `.card-header` 直接就在 `.card` 内部，而 `div.card-header`
 *    这个类名里含 `.card` 字样 —— 后代选择器会把内层标题的**所有**祖先都算进去，
 *    实测已确认这里必须隔层才对（否则内层竖条根本不会被去掉）。
 */
.card > * > .card > .card-header > .card-title,
.card > * > * > .card > .card-header > .card-title {
  padding-left: 0;
  box-shadow: none;
}

.chart-container {
  position: relative;
  height: 300px;
  width: 100%;
}

/* ==========================================================================
   账户卡片与明细表格 (Accounts & Transactions Table)
   ========================================================================== */
.accounts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.account-item-card {
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  transition: var(--transition-fast);
  cursor: pointer;
}

.account-item-card:hover {
  border-color: var(--primary-color);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.account-type {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.account-name {
  font-weight: 600;
  font-size: 0.95rem;
}

.account-balance {
  font-size: 1.1rem;
  font-weight: 700;
  margin-top: 0.25rem;
  color: var(--primary-color);
}

/* 表格与筛选器 */
.table-filter-bar {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

.filter-group {
  display: flex;
  gap: 0.75rem;
  align-items: center;
}

.input-control, .select-control {
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  color: var(--text-main);
  padding: 0.55rem 0.85rem;
  border-radius: var(--radius-sm);
  outline: none;
  font-size: 0.9rem;
  transition: var(--transition-fast);
}

.input-control:focus, .select-control:focus {
  border-color: var(--primary-color);
  box-shadow: 0 0 0 3px var(--primary-light);
}

/* ── 宽表的横向滚动（2026-09-21）──────────────────────────────────────────────
 *
 * 🔴 由来：用户报「账单确认列表横幅太宽，隐掉了数据，要加左右滚动」。
 *    实测确认：**横向滚动本来就是好的**（`overflow-x: auto`），表也确实溢出
 *    （账单确认 12 列 = 1586px，容器 1066px）。问题是**看不出来可以滚** ——
 *    macOS 的 overlay 滚动条「不滚就不显示」，所以中间几列（折算 USD / 已关联剩余 /
 *    状态 / 文件）就那么静静地待在容器外，用户以为数据被吞了。
 *
 * ⚠️ 这条与 `test_v3014_sticky_actions_browser.js` 记的那个是同族、但**不是同一个**：
 *    那一次的真因是 flex 子项不收缩（`min-width: auto`），修法在 `.main-content`；
 *    这一次容器宽度是对的、滚动能力也是对的，**缺的只是「可滚动」这件事的可见性**。
 *    ⇒ 两处都要在，缺一不可：
 *       `.main-content { min-width: 0 }`  ← 让容器收缩回视口内（已修，2026-09-17）
 *       本规则                            ← 让「还能往右看」这件事看得见
 *
 * ⚠️ 为什么用 `scrollbar-gutter: stable`：不预留槽位的话，出现滚动条时会挤掉
 *    十几 px 的内容宽度，那一瞬间表格会重排（列宽跳动）。预留后不论有没有滚动条，
 *    内容宽度一致。
 *
 * ⚠️ 只给**真的溢出**的表加视觉提示：`:has()` 在支持的浏览器上按实际溢出加类，
 *    不支持的浏览器只是少一个边框色提示，**滚动能力不受影响**（功能不依赖它）。
 */
.transactions-table-wrapper {
  overflow-x: auto;
  scrollbar-gutter: stable;
  /* 滚动条**常显**且加粗一点：默认的 overlay 样式在 macOS 上要滚动才出现，
   * 而「看不出来能滚」正是这次要修的东西。 */
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}

.transactions-table-wrapper::-webkit-scrollbar {
  height: 10px;
}

.transactions-table-wrapper::-webkit-scrollbar-track {
  background: var(--bg-inset);
  border-radius: 5px;
}

.transactions-table-wrapper::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 5px;
}

.transactions-table-wrapper::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

/* ── 「右边还有内容」的边缘提示（2026-09-21）────────────────────────────────────
 *
 * 滚动条在**底部**，而用户看的是**表格中部** —— 中间几列被截断时，底部那根滚动条
 * 不在他的视野里。故在容器**右缘**加一道渐隐，明确告诉他「这里被切断了、还能往右看」。
 *
 * ⚠️ `position: relative` 只加在本容器上（它是 `overflow-x: auto`，
 *    不构成定位祖先的问题：这个伪元素是它的**子级**，会跟着内容一起滚 —— 所以用
 *    `position: sticky; right: 0` 把它钉在**可视右缘**，否则它会被滚走。
 * ⚠️ `pointer-events: none`：它盖在操作列上面，绝不能让鼠标点不到按钮。
 * ⚠️ 只在 `.is-overflowing` 时显示 —— 不溢出的表右侧不该有这条线（那会是假提示）。
 *    该类由 `js/app.js` 的 `markScrollableTables()` 按实测宽度加，见那里。
 */
.transactions-table-wrapper.is-overflowing {
  position: relative;
}

.transactions-table-wrapper.is-overflowing::after {
  content: '';
  position: sticky;
  right: 0;
  float: right;
  width: 28px;
  height: 100%;
  margin-left: -28px;
  pointer-events: none;
  background: linear-gradient(to right, transparent, rgba(15, 23, 42, 0.10));
  z-index: 2;
}

.transactions-table {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
  font-variant-numeric: tabular-nums;
}

.transactions-table th {
  padding: 0.8rem 1rem;
  color: var(--text-muted);
  font-weight: 700;
  font-size: 0.72rem;
  border-bottom: 1px solid var(--border-strong);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  background-color: var(--bg-card);
  /* 表头在长表里吸顶（v3.1.0）。`position: sticky` 只在**有滚动条的祖先**里
   * 才生效，而 `.transactions-table-wrapper` 是 `overflow-x: auto`（横向），
   * 纵向滚动发生在**页面**上 ⇒ 这一条实际由页面滚动驱动，不需要改 wrapper。
   * ⚠️ 背景取 `--bg-card`（两套主题下都是不透明纯色）：吸顶时下面的行不会透出来。
   *    （曾试 `--bg-inset`，它在亮色下是浅灰、与相邻白卡片差一层，表头看着像"没了底色"。）
   * ⚠️ `z-index: 3`：低于 `sticky-actions` 那格表头的 4，高于普通数据格 —— 否则横向
   *    滚动时操作列表头会被同行其它表头盖住（那是 v3.0.14 修复的回归点）。 */
  position: sticky;
  top: 0;
  z-index: 3;
}

.transactions-table td {
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--border-color);
  font-size: var(--fs-body);
  vertical-align: middle;
}

.transactions-table tbody tr:last-child td {
  border-bottom: none;
}

.transactions-table tr:hover {
  background-color: var(--bg-inset);
}

/* ── 操作列吸附在右侧（2026-09-17）────────────────────────────────────────────
 *
 * 🔴 由来：用户反馈「账单确认里没有修改和删除，我觉得是 bug」。
 *    实查后：`updateBillConfirmation` / `deleteBillConfirmation` 都在，
 *    按钮也**无条件渲染**（不分草稿/已确认），该区块更没有权限门控。
 *    真因是 —— 那张表有 **12 列**，「操作」是最后一列，而容器是 `overflow-x: auto`
 *    ⇒ 窗口放不下时操作列被滑出屏幕右侧。**功能在，但人找不到。**
 *
 * ⚠️ 这不是一处而是**一类**：index.html 里末列为「操作」的表共 **20 张**，
 *    其中 12 列 2 张、11 列 1 张、10 列 4 张 —— 都可能复现同一现象。
 *    而「确认 / 撤销确认」也在同一列 ⇒ 四个关键动作会一起消失。
 *
 * 修法取 sticky 而不是「把操作列挪到最前」：不改变既有列顺序（用户已形成肌肉记忆），
 * 只保证它永远可见。
 *
 * ⚠️ 背景色必须跟着两种状态走，否则横向滚动时下层单元格会从吸附列底下透出来：
 *    · 常态 `--bg-card`
 *    · `tr:hover` 时 `--bg-input`（漏了这条，悬停会出现一块不跟随的色块）
 *    两个变量在 `[data-theme="dark"]` 下各自重定义，故暗色主题自动正确。
 */
.transactions-table.sticky-actions th:last-child,
.transactions-table.sticky-actions td:last-child {
  position: sticky;
  right: 0;
  z-index: 1;
  background-color: var(--bg-card);
  /* 左侧描边：让「这一列是浮在上面的」这件事可见，否则用户会以为表就这么宽 */
  box-shadow: -6px 0 6px -6px rgba(0, 0, 0, 0.18);
}

.transactions-table.sticky-actions tr:hover th:last-child,
.transactions-table.sticky-actions tr:hover td:last-child {
  /* ⚠️ 必须与 `.transactions-table tr:hover` 的背景**逐字一致**（现为 `--bg-inset`）。
   *    v3.1.0 把悬停底色从 `--bg-input` 改成 `--bg-inset`，此处同步改；
   *    只改一处会让悬停时吸附列出现一块不跟随的色块（这条注释就是这么来的）。 */
  background-color: var(--bg-inset);
}

/* 表头那一格要压在数据格之上（两者都 sticky 时靠 z-index 分层）。
 * ⚠️ 4 而不是 2：v3.1.0 给 `thead th` 整体加了 `z-index: 3`（吸顶表头），
 *    这里若仍写 2，横向滚动时**操作列表头会被同行其它表头盖住**。 */
.transactions-table.sticky-actions thead th:last-child {
  z-index: 4;
}

/* ── 首列吸附在左侧（v3.5.20，2026-09-23 用户点名）─────────────────────────────
 *
 * 用户原话：「月度利润表 固定项目（总是显示），滚动数据」。
 * 那张表是 **13 列**（科目 + 12 个月 + 全年合计），容器 `overflow-x: auto`
 * ⇒ 往右滚看 11、12 月时，「收入/成本/毛利…」这一列会被滑出屏幕，
 * 数字还在、但**不知道那是哪一行** —— 与 v3.0.14「操作列被滑走」是同族问题，
 * 方向相反（那次守右缘，这次守左缘）。
 *
 * ⚠️ 与 `sticky-actions`（右侧吸附）的**三个不同点**，照抄会错：
 *   ① `left: 0` 而不是 `right: 0`；
 *   ② 描边方向相反：阴影要在**右侧**（`6px 0` 而不是 `-6px 0`），
 *      表示「这一列浮在内容之上」；
 *   ③ **两张表各自的 sticky 列不能同时启用**（一左一右会挤掉中间的可用宽度），
 *      故用独立类名 `.sticky-first`，只给需要的表加。
 *
 * ⚠️ 背景色与 hover 必须与 `sticky-actions` **逐字一致**（`--bg-card` / `--bg-inset`）：
 *    不透明才盖得住底下滚过去的单元格；hover 不跟随就会出现一块不跟着变的色块。
 * ⚠️ `z-index` 分层（与 sticky-actions 同一套数值，因为它们可能共存于不同表）：
 *    数据格 1 < 普通表头 3 < **吸附列表头 4** —— 横向滚动时首列表头必须压住
 *    同行其它表头，否则那一格会被旁边滚过来的表头盖掉。
 */
.transactions-table.sticky-first th:first-child,
.transactions-table.sticky-first td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background-color: var(--bg-card);
  box-shadow: 6px 0 6px -6px rgba(0, 0, 0, 0.18);
}

.transactions-table.sticky-first tr:hover th:first-child,
.transactions-table.sticky-first tr:hover td:first-child {
  background-color: var(--bg-inset);
}

/* ⚠️ 表头那一格要在普通表头（z-index: 3）之上 —— 见上面第 ③ 条注释 */
.transactions-table.sticky-first thead th:first-child {
  z-index: 4;
}

/* 无月份数据时（如未来年份）不该有描边，否则看起来像被切断了 */
.transactions-table.sticky-first:not(.is-overflowing) th:first-child,
.transactions-table.sticky-first:not(.is-overflowing) td:first-child {
  box-shadow: none;
}

.category-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  border-radius: 20px;
  font-size: 0.82rem;
  font-weight: 500;
}

.type-income {
  color: var(--income-color);
  font-weight: 700;
}

.type-expense {
  color: var(--expense-color);
  font-weight: 700;
}

.type-transfer {
  color: var(--transfer-color);
  font-weight: 700;
}

.action-btn {
  color: var(--text-muted);
  padding: 0.35rem;
  border-radius: 4px;
}

.action-btn:hover {
  color: var(--expense-color);
  background-color: var(--expense-light);
}

/* ==========================================================================
   模态框 (Modal Window)
   ========================================================================== */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(15, 23, 42, 0.5);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  opacity: 0;
  visibility: hidden;
  transition: var(--transition-normal);
  padding: 1.5rem 1rem;
  overflow-y: auto;
}

.modal-overlay.active {
  opacity: 1;
  visibility: visible;
}

.modal-card {
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  width: 100%;
  max-width: 520px;
  max-height: 88vh;
  overflow-y: auto;
  padding: 1.75rem;
  box-shadow: var(--shadow-lg);
  transform: translateY(20px);
  transition: var(--transition-normal);
  margin: auto;
}

/* 自定义弹窗平滑滚动条 */
.modal-card::-webkit-scrollbar {
  width: 6px;
}
.modal-card::-webkit-scrollbar-thumb {
  background-color: rgba(100, 116, 139, 0.3);
  border-radius: 4px;
}
.modal-card::-webkit-scrollbar-thumb:hover {
  background-color: rgba(100, 116, 139, 0.5);
}

.modal-overlay.active .modal-card {
  transform: translateY(0);
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.5rem;
}

.modal-title {
  font-size: 1.25rem;
  font-weight: 700;
}

.close-btn {
  color: var(--text-muted);
  font-size: 1.25rem;
  padding: 0.25rem;
}

.close-btn:hover {
  color: var(--text-main);
}

.form-group {
  margin-bottom: 1.25rem;
}

.form-label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: 0.4rem;
  color: var(--text-main);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

.type-selector {
  display: flex;
  background-color: var(--bg-input);
  padding: 0.25rem;
  border-radius: var(--radius-sm);
  margin-bottom: 1.25rem;
}

.type-option {
  flex: 1;
  text-align: center;
  padding: 0.5rem;
  font-weight: 600;
  font-size: 0.9rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
}

.type-option.active {
  background-color: var(--bg-card);
  color: var(--primary-color);
  box-shadow: var(--shadow-sm);
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-top: 1.5rem;
}

/* 空数据提示 */
.empty-state {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--text-muted);
}

.empty-state i {
  font-size: 3rem;
  margin-bottom: 1rem;
  color: var(--border-color);
}

/* ==========================================================================
   收入专属表单扩展与往来公司 / 币种样式 (Income Extra & Custom Badges)
   ========================================================================== */
.income-extra-box {
  background-color: var(--income-light);
  border: 1px dashed rgba(16, 185, 129, 0.35);
  border-radius: var(--radius-sm);
  padding: 1rem;
  margin-bottom: 1.25rem;
}

.label-with-action {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.4rem;
}

.label-with-action .form-label {
  margin-bottom: 0;
}

.quick-add-link {
  font-size: 0.78rem;
  color: var(--income-color);
  font-weight: 600;
  text-decoration: none;
  border: none;
  background: none;
  cursor: pointer;
  padding: 0 4px;
  border-radius: 4px;
  transition: var(--transition-fast);
}

.quick-add-link:hover {
  background-color: rgba(16, 185, 129, 0.15);
  text-decoration: underline;
}

/* 表格中的币种标签 */
.currency-tag {
  display: inline-block;
  padding: 0.2rem 0.55rem;
  border-radius: 6px;
  background-color: var(--primary-light);
  color: var(--primary-color);
  font-weight: 600;
  font-size: 0.8rem;
  font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
}

/* 往来公司流动图示 */
.company-flow-box {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  max-width: 320px;
}

.company-payer {
  color: var(--text-main);
  font-weight: 600;
  background-color: var(--bg-input);
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  border: 1px solid var(--border-color);
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  max-width: 140px;
}

.company-arrow {
  color: var(--income-color);
  font-size: 0.75rem;
  flex-shrink: 0;
}

.company-payee {
  color: var(--income-color);
  font-weight: 600;
  background-color: var(--income-light);
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  max-width: 140px;
}

/* ==========================================================================
   融资/借款专属区块与利息模拟器样式 (Financing & Interest Simulator)
   ========================================================================== */
.financing-extra-box {
  background-color: rgba(2, 132, 199, 0.08);
  border: 1px dashed rgba(2, 132, 199, 0.4);
  border-radius: var(--radius-sm);
  padding: 1rem;
  margin-bottom: 1.25rem;
}

.interest-simulator-card {
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 0.85rem 1rem;
  margin-top: 0.75rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  box-shadow: var(--shadow-sm);
}

.simulator-item {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.simulator-label {
  font-size: 0.8rem;
  color: var(--text-muted);
  font-weight: 500;
}

.simulator-val {
  font-size: 1.05rem;
  font-weight: 700;
  color: #0284c7;
}

.simulator-val.total-val {
  color: var(--expense-color);
  font-size: 1.15rem;
}

/* 表格中的融资人员与利息标签 */
.financing-person-box {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.82rem;
}

.creditor-name {
  font-weight: 700;
  color: #0284c7;
}

.proxy-name {
  color: var(--text-muted);
}

.financing-interest-tag-box {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.8rem;
}

.rate-badge {
  color: var(--text-main);
  font-weight: 500;
}

.est-interest-badge {
  color: var(--expense-color);
  font-weight: 700;
}

/* 编辑修改按钮 hover 状态 */
.edit-tx-btn:hover {
  color: var(--primary-color);
  background-color: var(--primary-light);
}

/* ==========================================================================
   转账与兑换专属区块样式 (Transfer & Exchange)
   ========================================================================== */
.exchange-extra-box {
  background-color: rgba(139, 92, 246, 0.08);
  border: 1px dashed rgba(139, 92, 246, 0.4);
  border-radius: var(--radius-sm);
  padding: 1rem;
  margin-bottom: 1.25rem;
}

/* ==========================================================================
   概览多维汇总与多条件筛选工具栏 (Breakdown & Filter Toolbar)
   ========================================================================== */
.breakdown-tabs {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.breakdown-tab {
  padding: 0.4rem 0.8rem;
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-muted);
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  cursor: pointer;
  transition: var(--transition-fast);
}

.breakdown-tab:hover {
  color: var(--primary-color);
  border-color: var(--primary-color);
}

.breakdown-tab.active {
  color: #ffffff;
  background-color: var(--primary-color);
  border-color: var(--primary-color);
}

.breakdown-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.breakdown-table th {
  padding: 0.75rem 1rem;
  background-color: var(--bg-input);
  color: var(--text-muted);
  font-weight: 600;
  text-align: left;
  border-bottom: 1px solid var(--border-color);
}

.breakdown-table td {
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--border-color);
}

.category-breakdown-list {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  padding: 0.5rem 0;
}

.category-breakdown-item {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.cat-item-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.88rem;
}

.cat-bar-bg {
  height: 8px;
  width: 100%;
  background-color: var(--bg-input);
  border-radius: 4px;
  overflow: hidden;
}

.cat-bar-fill {
  height: 100%;
  border-radius: 4px;
  transition: width 0.4s ease;
}

/* 多维筛选工具栏 */
.filter-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  width: 100%;
}

.filter-item {
  font-size: 0.82rem;
  padding: 0.4rem 0.6rem;
}

.search-item {
  flex: 1;
  min-width: 160px;
}

/* ==========================================================================
   预算与应收应付款模块 (Budget & AR/AP)
   ========================================================================== */
.budget-summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
  margin-top: 1rem;
  margin-bottom: 0.5rem;
}

.budget-stat-box {
  padding: 1rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
  background-color: var(--bg-input);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.budget-stat-box.ar-box {
  border-left: 4px solid var(--income-color);
}

.budget-stat-box.ap-box {
  border-left: 4px solid var(--expense-color);
}

.budget-stat-box.net-box {
  border-left: 4px solid var(--primary-color);
}

.budget-stat-label {
  font-size: 0.82rem;
  color: var(--text-muted);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.budget-stat-val {
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: -0.5px;
}

.ar-box .budget-stat-val {
  color: var(--income-color);
}

.ap-box .budget-stat-val {
  color: var(--expense-color);
}

/* 徽章 Badge 样式 */
.ar-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.55rem;
  border-radius: var(--radius-sm);
  font-size: 0.8rem;
  font-weight: 600;
  background-color: rgba(16, 185, 129, 0.12);
  color: #10b981;
}

.ap-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.55rem;
  border-radius: var(--radius-sm);
  font-size: 0.8rem;
  font-weight: 600;
  background-color: rgba(239, 68, 68, 0.12);
  color: #ef4444;
}

.status-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.55rem;
  border-radius: 12px;
  font-size: 0.78rem;
  font-weight: 600;
}

/* 账单明细「说明」列的来源标签（转入方来源补充：合同/账期/期次/来源账户/汇率等） */
.tx-src-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.4rem;
  border-radius: 6px;
  font-size: 0.7rem;
  font-weight: 600;
  background: var(--bg-input);
  color: var(--text-muted);
  border: 1px solid var(--border-color);
  white-space: nowrap;
}

.status-tag.pending {
  background-color: rgba(245, 158, 11, 0.12);
  color: #f59e0b;
}

.status-tag.completed {
  background-color: rgba(99, 102, 241, 0.12);
  color: var(--primary-color);
}

.proxy-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.55rem;
  border-radius: var(--radius-sm);
  font-size: 0.8rem;
  font-weight: 600;
  background-color: rgba(99, 102, 241, 0.1);
  color: var(--primary-color);
}

.currency-tag {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.5rem;
  border-radius: 4px;
  font-size: 0.78rem;
  font-weight: 700;
  background-color: rgba(2, 132, 199, 0.12);
  color: #0284c7;
  letter-spacing: 0.3px;
}

.currency-tag.small {
  padding: 0.1rem 0.35rem;
  font-size: 0.72rem;
  border-radius: 3px;
}

.currency-stat-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 1rem;
  font-weight: 700;
  padding: 0.2rem 0;
  border-bottom: 1px dashed rgba(148, 163, 184, 0.2);
}

.currency-stat-row:last-child {
  border-bottom: none;
}

/* 明细记录变动与筛选后实时汇总栏 */
.filtered-summary-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.2rem;
  padding: 0.6rem 0.9rem;
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  width: 100%;
  margin-top: 0.6rem;
  font-size: 0.85rem;
}

.filtered-summary-bar .summary-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--text-muted);
}

.filtered-summary-bar .summary-item.income strong {
  color: var(--income-color);
}

.filtered-summary-bar .summary-item.expense strong {
  color: var(--expense-color);
}

.filtered-summary-bar .summary-item.net strong {
  color: var(--primary-color);
}

/* ==========================================================================
   收入管理模块专属样式 (Revenue Module)
   ========================================================================== */

/* 子标签面板 */
.revenue-panel {
  animation: fadeSlideIn 0.25s ease;
}

@keyframes fadeSlideIn {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 收入模块内的资金流转示意条 */
.rev-formula-box {
  background: linear-gradient(135deg, var(--bg-card), var(--bg-input));
  border-radius: var(--radius-sm);
  padding: 0.85rem 1.15rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text-main);
  border: 1px solid var(--border-color);
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
}

.rev-formula-box .formula-segment {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.65rem;
  border-radius: 6px;
  background-color: var(--bg-input);
  font-weight: 700;
}

/* 客户状态标签颜色 */
.status-active {
  color: #10b981;
  background: rgba(16, 185, 129, 0.12);
}

.status-prospect {
  color: #f59e0b;
  background: rgba(245, 158, 11, 0.12);
}

.status-inactive {
  color: #94a3b8;
  background: rgba(148, 163, 184, 0.12);
}

/* 合同状态标签 */
.contract-status-draft {
  color: #94a3b8;
  background: rgba(148, 163, 184, 0.12);
}

.contract-status-pending {
  color: #f59e0b;
  background: rgba(245, 158, 11, 0.12);
}

.contract-status-active {
  color: #10b981;
  background: rgba(16, 185, 129, 0.12);
}

.contract-status-completed {
  color: #6366f1;
  background: rgba(99, 102, 241, 0.12);
}

.contract-status-terminated {
  color: #ef4444;
  background: rgba(239, 68, 68, 0.12);
}

/* 证明文件上传区域 */
.proof-files-container {
  max-height: 150px;
  overflow-y: auto;
  font-size: 0.82rem;
}

.proof-file-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.3rem 0;
  border-bottom: 1px dashed var(--border-color);
}

.proof-file-item:hover {
  background-color: var(--bg-input);
}

/* 收入大盘 KPI 特殊颜色 */
.rev-kpi-positive {
  color: var(--income-color);
}

.rev-kpi-negative {
  color: var(--expense-color);
}

.rev-kpi-warning {
  color: #f59e0b;
}

.rev-kpi-info {
  color: #8b5cf6;
}

/* 余额核对一致性指示器 */
.recon-match-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
}

.recon-match-dot.ok {
  background-color: #10b981;
  box-shadow: 0 0 6px rgba(16, 185, 129, 0.4);
}

.recon-match-dot.mismatch {
  background-color: #ef4444;
  box-shadow: 0 0 6px rgba(239, 68, 68, 0.4);
}

/* 模态框中 textarea 样式补充 */
textarea.input-control {
  resize: vertical;
  min-height: 60px;
  font-family: inherit;
}

/* 收入模块表格中的公司/客户信息紧凑排列 */
.rev-inline-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.15rem 0.45rem;
  border-radius: 4px;
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
}

/* ==========================================================================
   充值记录按月折叠 (Recharge Records Accordion)
   ========================================================================== */
.rc-accordion-header:hover {
  background: var(--bg-input) !important;
}
.rc-accordion-header:hover .rc-accordion-chevron {
  color: var(--primary-color) !important;
}

#rcrec-toggle-header:hover {
  background: var(--bg-input) !important;
}
#rcrec-toggle-header:hover #rcrec-chevron {
  color: var(--primary-color) !important;
}

/* 响应式：移动端侧边栏适配 */
@media (max-width: 768px) {
  .revenue-panel {
    padding: 0.5rem 0;
  }

  .budget-summary-grid {
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  }
}

/* ==========================================================================
   合同表格行内编辑 (Inline edit inputs & selects)
   ========================================================================== */
.inline-input {
  width: 100%;
  min-width: 100px;
  font-size: 0.82rem;
  padding: 0.3rem 0.45rem;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--text-main);
  font-family: inherit;
  transition: border-color 0.15s, background 0.15s;
}
.inline-input:hover {
  border-color: var(--border-color);
  background: var(--bg-input);
}
.inline-input:focus {
  outline: none;
  border-color: var(--primary-color);
  background: var(--bg-input);
}
.inline-input::placeholder {
  color: var(--text-muted);
  opacity: 0.6;
}

.inline-select {
  width: 100%;
  font-size: 0.82rem;
  padding: 0.3rem 0.4rem;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  background: var(--bg-input);
  color: var(--text-main);
  cursor: pointer;
  font-family: inherit;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.inline-select:hover {
  border-color: var(--primary-color);
}
.inline-select:focus {
  outline: none;
  border-color: var(--primary-color);
}

/* ── 一键到表头 / 表尾（2026-09-17）──────────────────────────────────────────
 *
 * 由来（用户实测提出）：「打开列表后，比如账单明细和充值记录，显示了一长串数据，
 * 应该做一个机制，一键到表头或到表尾。」
 *
 * 设计取舍：
 * · **跟随当前可见的那张长表**，而不是无脑滚页面顶/底 —— 一个区块里往往
 *   「筛选条 + 汇总卡 + 长表」三段，滚到页面顶会停在筛选条上方，仍要再找一次表头。
 * · 只有**真的够长**时才出现（阈值见 app.js），否则是纯噪音。
 * · `z-index: 90` —— 低于侧栏(100)与弹窗(1000)，**不会盖住模态框**；
 *   若哪天要调，先确认它仍在弹窗之下，否则会挡住「确认/取消」。
 * · 位置贴右下，并留出 `env(safe-area-inset-*)`，防止在带圆角/刘海的屏幕上被裁。
 */
.jump-nav {
  position: fixed;
  right: calc(1.25rem + env(safe-area-inset-right, 0px));
  bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
  z-index: 90;
  display: none;            /* 由 app.js 按「表够不够长」切换 */
  flex-direction: column;
  gap: 0.4rem;
}

.jump-nav.visible {
  display: flex;
}

.jump-nav button {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--border-color);
  background-color: var(--bg-card);
  color: var(--text-muted);
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  transition: color 0.15s, border-color 0.15s, transform 0.15s;
}

.jump-nav button:hover {
  color: var(--primary-color);
  border-color: var(--primary-color);
  transform: translateY(-1px);
}

.jump-nav button:active {
  transform: translateY(0);
}

/* 窄屏上缩小一点，别占掉太多可视面积 */
@media (max-width: 640px) {
  .jump-nav button { width: 36px; height: 36px; font-size: 0.85rem; }
}

/* ==========================================================================
   v3.9.54（用户 2026-10-28）：充值与成本 —— 吸顶快速定位
   板块太长（概览 / 按客户汇总 / 充值明细 / 成本核销 / 中转平台 / 平台数据 /
   预分配 / 客户毛利），顶部一条 chip 直接滚到对应小节；跳到的那块临时描边 1.6 秒。
   ========================================================================== */
.rc-quicknav {
  position: sticky;
  top: 8px;
  z-index: 8;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: center;
  padding: 0.45rem 0.6rem;
  margin: 0.2rem 0 1rem;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: 0 2px 10px rgba(15, 23, 42, 0.08);
}
.rc-quicknav-label {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--text-muted);
  margin-right: 0.2rem;
  white-space: nowrap;
}
.rc-quicknav-chip {
  font-size: 0.78rem;
  padding: 0.28rem 0.65rem;
  border-radius: 999px;
  border: 1px solid var(--border-color);
  background: var(--bg-body);
  color: var(--text-main);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.rc-quicknav-chip:hover { border-color: #0ea5e9; color: #0369a1; }
.rc-quicknav-chip.active { background: #0ea5e9; border-color: #0ea5e9; color: #fff; }
.rc-jump-flash { outline: 2px solid #0ea5e9; outline-offset: 4px; }

/* ==========================================================================
   v3.9.55（用户 2026-10-28）：平台数据导入 —— 弹窗内预览 + 缺列提示
   ========================================================================== */
.tpd-warn {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  padding: 0.5rem 0.65rem;
  margin-bottom: 0.5rem;
  font-size: 0.8rem;
  line-height: 1.6;
  color: #92400e;
  background: rgba(245, 158, 11, 0.12);
  border: 1px solid rgba(245, 158, 11, 0.35);
  border-radius: var(--radius-sm, 8px);
}
.tpd-preview-wrap {
  max-height: 260px;
  overflow: auto;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm, 8px);
}
.tpd-preview-table { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
.tpd-preview-table th, .tpd-preview-table td {
  padding: 0.3rem 0.45rem;
  border-bottom: 1px solid var(--border-color);
  white-space: nowrap;
}
.tpd-preview-table thead th {
  position: sticky;
  top: 0;
  background: var(--bg-body);
  z-index: 1;
  font-weight: 600;
  color: var(--text-muted);
}

/* ==========================================================================
   v3.9.56（用户 2026-10-28）：「所有表单都加筛选」—— 每张表一条「表内筛选」
   ========================================================================== */
.table-filter-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.35rem 0 0.45rem;
}
.table-filter-input {
  width: 260px;
  max-width: 60vw;
  height: 30px;
  font-size: 0.8rem;
  padding: 0 0.55rem;
}
.table-filter-count {
  font-size: 0.75rem;
  color: var(--text-muted);
  white-space: nowrap;
}
