/* ==========================================================================
   达播工作台 — components.css
   按钮 / 输入 / 徽章 / 卡片
   ========================================================================== */

/* ---- 写操作按钮的「权限门」（2026-09-24）-------------------------------
   由 `App.applyPermGate()`（public/js/app.js）给无权限的元素打上
   `data-perm-hidden="1"`，这里负责真正藏起来。

   ⛔⛔ 为什么必须用 CSS 规则 + `!important`，而不是在 JS 里写内联 `display:none`：
      页面代码里**大量**存在自己控制显隐的写法（典型：导入页的
      `root.querySelector('#imp-go').style.display = ''` 在预览出数据后把按钮显示出来）。
      内联样式会被这些代码**覆盖** ⇒ 权限门看起来"有时生效、有时不生效"，
      而且无法从权限门这一侧排查（改的是同一个 style 属性）。
      CSS 规则带 `!important` 的优先级高于内联样式 ⇒ 页面怎么改都盖不住。

   ⚠️ 用属性选择器而不是 `[hidden]`：`hidden` 会被任何 `display:flex/block` 的
      类规则覆盖（本项目按钮大量带 flex 类），同样会静默失效。 */
[data-perm-hidden="1"] {
  display: none !important;
}

/* ---- 按钮 ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /* ⭐ 2026-09-26 两档制：36 → **44（标准档）**
     ⚠️ 原来 36 是"第三档"—— 既不是紧凑（34）也不是标准（44），
        导致它跟旁边的 select(44) 同排时矮 8px（报销/结算工具栏实测）。
     ⚠️ 顶栏与页面头部的按钮不受影响：它们用 `.btn--lg`（也是 44）或各自作用域规则。
     ⚠️ 放进 `.toolbar` 的按钮会被全局兜底压到 34px（紧凑档，见 table.css）。 */
  height: var(--control-height);
  padding: 0 var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  /* ⭐ 2026-09-23 补 `background` / `color` / `border-color` —— **原来这三项一个都没定义**，
     后果是：不带颜色变体的 `.btn`（如 `class="btn btn--sm"`）掉进**浏览器原生按钮样式**。
     实测计算值（无头 Chrome 读 getComputedStyle）：
       background = `rgb(239,239,239)`（= Chrome 的 `buttonface`，不是任何设计令牌）
       color      = `rgb(0,0,0)`（原生黑，不是 `--color-fg` 的 #1C1E21）
     ⇒ 表现是「一块原生灰底黑字」，既不在设计系统里，也和旁边真正的按钮不像一套
       （乐哥看到「指定某人的审批人 / 从飞书同步部门」两个方块会问"颜色要不要调"，
        根因就在这：它们压根不是被 CSS 画的）。
     ⚠️ 只补**中性默认**（白底 + 常规边框 + 正文色）；既有变体（primary / secondary /
        ghost / danger / scope / icon）各自 `background` 覆盖，行为一字未变。 */
  background: var(--color-surface);
  color: var(--color-fg);
  border-color: var(--color-border);
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-medium);
  line-height: 1;
  white-space: nowrap;
  transition: background-color var(--motion-fast) var(--motion-ease-standard),
    color var(--motion-fast) var(--motion-ease-standard),
    border-color var(--motion-fast) var(--motion-ease-standard),
    transform var(--motion-fast) var(--motion-ease-standard),
    box-shadow var(--motion-fast) var(--motion-ease-standard);
}

.btn:hover:not(:disabled) {
  background: var(--color-surface-2);
}

.btn:active:not(:disabled) {
  /* ⚠️ 原来这里是 `background: var(--color-surface-2)` —— **与 .btn:hover 完全相同**，
     等于按下没有任何视觉变化（hover/pressed 不可区分，违反 ui-ux-pro-max
     「state-clarity：hover/pressed/disabled 三态必须可区分」+「press-feedback」）。
     改为深一档（gray-100）+ 极轻缩放：缩放用 transform，不触发重排（transform-performance）。 */
  background: var(--color-gray-100);
  transform: scale(var(--motion-press));
}

/* ⭐ 2026-09-26 动效：主按钮「悬停微浮 + 按下回弹」（乐哥：「轻盈灵动，不要傻快」）
   ──────────────────────────────────────────────────────────────────────────
   为什么只给 `.btn--primary` 加位移：它是**页面级 CTA**（新增 / 导入 / 保存），
   一屏通常只有 1~2 个 ⇒ 值得给一个"可被点击"的强暗示。
   次级按钮（ghost / secondary）一屏几十个，全都上下浮动会显得整页在抖。
   ⚠️ 上浮只 1px：到 3px 就成了"按钮在跳"，是廉价感。
   ⚠️ 投影用**同色系**（主色的低透明蓝）而不是中性黑 —— 中性黑投影落在浅蓝按钮下方
      会发灰发脏（大面积阴影实测过这个问题）。
   ⚠️ `:active` 必须把 translateY 归零再叠加小缩放：
      不归零的话"按下"会继承 hover 的 -1px 再缩放，位移与缩放叠加后位置偏上。 */
.btn--primary:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 3px 8px rgba(0, 100, 224, 0.18);
}
.btn--primary:active:not(:disabled) {
  transform: translateY(0) scale(var(--motion-press));
  box-shadow: 0 1px 2px rgba(0, 100, 224, 0.16);
}

.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn--lg {
  height: var(--control-height);   /* 标准档（与 .btn 同值，保留类名兼容既有页面） */
  padding: 0 var(--space-5);
}

.btn--sm {
  /* ⭐ 2026-09-26 两档制：30 → **34（紧凑档）**
     ⚠️ 它主要用在**表格行内**（如业绩总表的「维护」）。改成 34 后与同排的
        `.icon-btn`（也是 34）齐平 —— 改前差 6px（30 vs 36），肉眼可见的错位。
     ⚠️ 配套：`.icon-btn` 基础值同时 36 → 34（见 layout.css）。 */
  height: var(--control-height-sm);
  padding: 0 var(--space-3);
  font-size: var(--font-size-sm);
}

.btn--primary {
  background: var(--button-primary-bg);
  /* ⭐ 2026-09-25 UI 美化第二刀（组件层）：主 CTA 接入品牌「蓝→青」渐变。
     为什么改这里：`.btn--primary` 全站 185 处引用，是全站出现频率最高的彩色元素；
     改为渐变后每屏的"品牌色存在感"立刻提升，且**面积很小**（符合"彩色只出现在小面积元素上"）。
     为什么用 background-image 而不是 background：`background` 简写会把 border-color 一起重置，
     而下面那行注释说明了本类必须显式保住 border-color: transparent（否则主按钮会挂一圈灰边）。
     ⇒ 用 `background-image` 只叠渐变层，底色 `--button-primary-bg` 仍在（渐变不支持的场景自动回落纯色）。
     ⚠️ 三态必须配套（hover / active 见下方），否则某态会回落成纯色造成"闪变"。 */
  background-image: var(--button-primary-image);
  color: var(--button-primary-fg);
  /* ⚠️ 必须显式声明：`.btn` 现在默认 `border-color: var(--color-border)`（见上），
     不写这一句主按钮会**多出一圈浅灰描边**（实测 border = rgb(229,232,236)）——
     实心色按钮周围挂一圈灰边看着很脏。danger 同理。 */
  border-color: transparent;
}

.btn--primary:hover:not(:disabled) {
  background: var(--button-primary-hover);
  background-image: var(--button-primary-image-hover);
}

.btn--primary:active:not(:disabled) {
  background: var(--button-primary-active);
  background-image: var(--button-primary-image-active);
}

.btn--secondary {
  background: var(--button-secondary-bg);
  color: var(--button-secondary-fg);
  border-color: var(--button-secondary-border);
}

.btn--secondary:hover:not(:disabled) {
  border-color: var(--color-accent-text);
  background: var(--color-primary-50);
}

.btn--ghost {
  background: var(--button-ghost-bg);
  color: var(--button-ghost-fg);
  border-color: var(--color-border);
}

.btn--ghost:hover:not(:disabled) {
  background: var(--color-surface-2);
  border-color: var(--color-gray-400);
}

/* ==========================================================================
   费用大类的语义色按钮（2026-09-18 乐哥拍板）
   --------------------------------------------------------------------------
   用途：批量操作栏的三个归属按钮（达人溯源直播 / 商务BD / 其他费用），
   让「按钮颜色」与「列表标签颜色」是同一套 —— 用户在勾选维护时，
   看到的色相与他在列表里认出的大类一致，不需要重新学一套。

   ⚠️ 色值不在 CSS 里写死，由 JS 通过 --scope-fg / --scope-bg 注入，
      来源唯一（dict.js 的 Dict.expenseScopeStyle）——
      色义规则写在那边，这里只负责"怎么用"。
      两处各写一份色值就会出现"按钮是绿、标签是蓝"的静默不一致。
   ⚠️ 底色用浅底（--scope-bg）：整排彩色按钮若用实心色会过分抢眼，
      抢掉真正该被注意的金额与异常状态；实心色只留给"选中态"（见 .seg__btn--scope）。
   ========================================================================== */
.btn--scope {
  color: var(--scope-fg, var(--color-fg-2));
  background: var(--scope-bg, transparent);
  border-color: var(--scope-bg, var(--color-border));
}

.btn--scope:hover:not(:disabled) {
  background: var(--scope-bg, var(--color-surface-2));
  border-color: var(--scope-fg, var(--color-gray-400));
}

/* 分段选项的语义色选中态：选中的那一项用**它自己的归属色**做实心底 + 白字。
   用途：行内「费用归属」弹窗的选项（达人溯源直播/商务BD/其他费用…）——
   用户点开一条记录时，一眼看出"当前这笔算什么"。 */
.seg__btn--scope.is-active {
  background: var(--scope-fg, var(--color-accent));
  color: #FFFFFF;
}

.btn--danger {
  background: var(--button-danger-bg);
  color: var(--button-danger-fg);
  border-color: transparent;   /* 同 .btn--primary：实心色按钮不要灰描边 */
}

.btn--danger:hover:not(:disabled) {
  /* 必须显式保持红色背景：否则会被 .btn:hover 的 background:surface-2 覆盖，白字在浅灰底上看不清 */
  background: var(--button-danger-bg);
  filter: brightness(0.9);
}

.btn--icon {
  width: 36px;
  padding: 0;
}

/* ---- 输入 / 选择 ---- */
.input,
.select,
.textarea {
  height: var(--control-height);   /* 标准档 44px（两档制，见 design-tokens 的说明） */
  padding: 0 var(--space-3);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  background: var(--input-bg);
  color: var(--color-fg);
  font-size: var(--font-size-base);
  transition: border-color var(--motion-fast) var(--motion-ease-standard),
    box-shadow var(--motion-fast) var(--motion-ease-standard);
}

.textarea {
  height: auto;
  padding: var(--space-2) var(--space-3);
  resize: vertical;
  min-height: 96px;
}

/* 下拉选择框：去掉默认箭头，用自定义向下箭头，离右边框留白避免贴边 */
.select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%238595A4' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 12px 12px;
  padding-right: 32px;
}

/* 带下拉提示的输入框（datalist）：去掉浏览器原生黑色箭头，用自定义向下箭头 */
.input[list] {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%238595A4' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 12px 12px;
  padding-right: 32px;
}
/* 移除 WebKit 对 datalist 输入框的原生下拉指示器（黑色实心箭头，hover/focus 时出现；必须 !important 覆盖浏览器内置样式） */
.input[list]::-webkit-calendar-picker-indicator {
  display: none !important;
  opacity: 0 !important;
}

/* 数字输入框：去掉上下增减箭头（spinner） */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

.input::placeholder,
.textarea::placeholder {
  color: var(--color-placeholder);   /* #B9C1CC，设计稿占位符色 */
}

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--input-focus-border);
  box-shadow: var(--focus-ring);
}

.input:disabled,
.select:disabled {
  background: var(--input-disabled-bg);
  color: var(--input-disabled-text);
  cursor: not-allowed;
}

/* 可清空下拉（sel-clear）：包一层 wrapper，右侧 ✕ 位于箭头左侧 */
.sel-clear-wrap {
  position: relative;
  display: inline-block;
  width: 100%;
}
.sel-clear-wrap select.sel-clear {
  width: 100%;
  padding-right: 52px; /* 给右侧 ✕ + 原生箭头让位 */
}
.sel-clear-x {
  position: absolute;
  right: 30px; /* 原生箭头在 right 12px 处，✕ 放它左侧 */
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--color-fg-2);
  border-radius: 50%;
  line-height: 1;
}
.sel-clear-x:hover {
  color: var(--color-fg);
  background: var(--color-surface-2);
}

/* 字段级错误态：红边框 + 就近提示 */
.input.is-error,
.select.is-error,
.textarea.is-error {
  border-color: var(--color-danger);
}
.input.is-error:focus,
.select.is-error:focus,
.textarea.is-error:focus {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px var(--color-danger-bg);
}
.field-error {
  margin-top: var(--space-1);
  font-size: var(--font-size-xs);
  color: var(--color-danger);
}
/* 飞书选人组件等复合控件的错误态 */
.is-error .fp__box {
  border-color: var(--color-danger);
}

.input--search {
  position: relative;
  display: inline-flex;
  align-items: center;
}

/* 放大镜图标：绝对定位到输入框内部左侧（页面里图标是裸 svg 或 .search-icon 包裹，两种都兼容） */
.input--search .search-icon,
.input--search > svg {
  position: absolute;
  left: var(--space-3);
  z-index: 1;
  color: var(--color-meta);
  pointer-events: none;
  display: inline-flex;
}

.input--search .input,
.input--search .select {
  padding-left: var(--space-8);
}

/* 日期范围筛选：日历图标 + 两个日期选择器 + 「至」分隔，与输入框同高同风格 */
.range-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-meta);
}
.range-filter > svg {
  flex-shrink: 0;
  color: var(--color-meta);
}
.range-filter__sep {
  color: var(--color-meta);
  font-size: var(--font-size-sm);
  flex-shrink: 0;
}

/* 密码框：右侧眼睛切换显示/隐藏 */
.input--password {
  position: relative;
  display: flex;
  align-items: center;
}
.input--password .input {
  width: 100%;
  padding-right: var(--space-10);
}
.pwd-toggle {
  position: absolute;
  right: var(--space-1);
  border: none;
  background: none;
  cursor: pointer;
  color: var(--color-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: var(--control-height-sm);   /* 两档制：32 → 34（紧凑档） */
  border-radius: var(--radius-sm);
  transition: color var(--motion-fast) var(--motion-ease-standard),
    background-color var(--motion-fast) var(--motion-ease-standard);
}
.pwd-toggle:hover {
  color: var(--color-fg);
  background: var(--color-surface-2);
}
.pwd-toggle:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.field-label {
  display: block;
  margin-bottom: var(--space-2);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-fg-2);
}

.field-hint {
  margin-top: var(--space-1);
  font-size: var(--font-size-xs);
  color: var(--color-muted);
}

.field-hint.is-error {
  color: var(--color-danger);
}

/* 字段宽度工具类（按业务语义，替代内联 grid 列比例）：数字窄 / 日期金额中 / 下拉宽 */
.f-w-xs { width: 96px; }
.f-w-sm { width: 140px; }
.f-w-md { width: 220px; }

/* ---- 徽章（深字 + 浅底成对） ---- */
.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  /* ⭐ 2026-09-25 UI 美化第三刀（表格/标签精简）：
     height 24→22、字重 500→400、圆角 `--radius-pill`(全圆 9999px) → `--radius-seg`(6px)。
     为什么（实测依据）：一屏数据表实测 **113 个胶囊**（达人管理 93 个），
     全圆胶囊+中等字重+实心底三者叠加，让每个标签都成为一块"鼓起来的彩色积木"，
     整屏读起来碎、吵（乐哥原话「感觉还是不够清新简约，包括表格，表格里的标签这些」）。
     ⇒ 改小圆角（精确感替代糖果感）+ 降字重 + 缩短高度，三处一起把"视觉重量"降下来，
        但**保留底色**——底色是"这是状态"的信号，完全去掉会让它和「—」占位符混在一起分不清。
     ⚠️ 只改基础形状与重量，**不动任何语义色**（未授权仍为橙、未入驻仍为灰，业务语义不变）。 */
  height: 22px;
  /* 中文字面在行盒内偏上：顶部留 1px、底部 0，视觉上居中 */
  padding: 1px var(--space-2) 0;
  border-radius: var(--radius-seg);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-regular);
  line-height: 1;
  white-space: nowrap;
}

.badge--success { color: var(--badge-success-fg); background: var(--badge-success-bg); }
.badge--warning { color: var(--badge-warning-fg); background: var(--badge-warning-bg); }
.badge--danger  { color: var(--badge-danger-fg);  background: var(--badge-danger-bg); }
.badge--info    { color: var(--badge-info-fg);    background: var(--badge-info-bg); }
.badge--neutral { color: var(--color-fg-2);       background: var(--color-surface-2); }

/* ---- 「审批中」列表标识（2026-09-22 新增，见 ui.js 的 pendingApprovalBadge）----
   ⚠️ 与 `.badge` 同族但**更小更轻**：它常与"已锁定"这类状态胶囊并排出现在**同一格**里，
      用 `.badge` 的 24px 高会把那一格撑得很挤。故单独一档（20px）。
   ⚠️ 配色**复用 warning 令牌**（不新造颜色）—— 与"已锁定"同色系，因为它们都是
      "这行有需要留意的状态"；区分靠图标（clock vs lock）与文案。
   ⚠️ 可点击（进审批详情）⇒ 保留 cursor:pointer 与 hover 反馈，与"纯展示"的 `.badge` 不同。 */
.pending-approval {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 20px;
  margin-left: 6px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  line-height: 1;
  white-space: nowrap;
  /* ⚠️ 用 `--badge-warning-*` 这一对（`--color-warning-fg` 在本项目**不存在**——
     写成不存在的变量会静默失效、文字变黑，这类"看不见的错"最常见） */
  background: var(--badge-warning-bg);
  color: var(--badge-warning-fg);
  cursor: pointer;
}
.pending-approval:hover {
  background: var(--color-warning);
  color: #fff;
}
.pending-approval__n {
  font-size: var(--font-size-xs);
  opacity: 0.8;
}

.badge--outline {
  background: transparent;
  border: 1px solid var(--color-border);
  color: var(--color-fg-2);
}

/* ---- 彩色标签（达人类型 / 平台等，颜色由 JS 通过 --tag-fg/bg 内联注入，无边框对齐 badge 风格） ---- */
.tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  /* ⭐ 2026-09-25 UI 美化第三刀：height 22→20、字重 500→400、圆角全圆→6px。
     与 `.badge` 同一套轻量化逻辑（见 .badge 的注释），保持两类标签形状语言一致。 */
  height: 20px;
  /* 同 .badge：顶部留白补偿中文字面偏上，视觉居中 */
  padding: 1px 6px 0;
  border-radius: var(--radius-seg);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-regular);
  line-height: 1;
  white-space: nowrap;
  color: var(--tag-fg, var(--color-fg-2));
  background: var(--tag-bg, var(--color-surface-2));
}
.tag--sm {
  height: 18px;
  padding: 1px 6px 0;
  font-size: var(--font-size-xs);
}

/* ---- 卡片（白底 + 1px 浅描边 + 极轻投影，对齐 Meta 设计语言） ----
   ⭐ 2026-09-25 UI 美化第二刀：`box-shadow` 由 `none` 改为 `--shadow-sm`。
   为什么：v2 把页面底压到近白（#F8FAFC）后，卡片与底的明度差只剩 2%，
   纯靠 1px 边框区分会显得"平贴在纸上"、「框」的存在感弱（乐哥要调「那些框」）。
   极轻投影（0 1px 2px + 0 1px 3px，最深仅 6% 透明度）让卡片**微微浮起**，
   在不破坏"近白简洁"的前提下补回层次。
   ⚠️ 用 `--shadow-sm` 而非 `--shadow-md/lg`：后两者扩散大，在近白底上会形成"脏边"而非纵深
      （design-tokens 里已注明这条）。 */
.card {
  /* ⭐ 2026-09-25 Gashora 骨架落地：卡片从「白底 + 阴影浮起」改为**靠浅边框划界**。
     原因：卡片现在住在**白色大卡（.page-stack #FCFCFC）里面**，与底盘同色系——
     阴影在"白上白"的场景几乎不可见（还容易显脏），改用 1px 浅边框（#EBECEF）
     才能清晰划出每张模块卡的边界（参考图正是这个做法：子卡全部细边框、无阴影）。
     ⚠️ 弹窗/下拉/抽屉这类**浮层**不在此列，它们仍用阴影表达层级（见 overlays.css）。 */
  background: var(--color-surface);
  border: 1px solid var(--color-frame-border);
  border-radius: var(--radius-lg);
  box-shadow: none;
}

/* ==========================================================================
   卡片级间距统一（2026-09-25 UI 美化第四刀「呼吸感」）
   --------------------------------------------------------------------------
   标准：**相邻卡片 20px**（`--space-5`），与 `.module-card + .module-card` 同一标准。
   ⭐ 2026-09-28：`--space-8`(32) → `--space-5`(20) —— 与 09-27 的「模块卡间距 32→20」对齐
   （那条改了 `.module-card + .module-card`，却漏了这条 `.card` 内联兜底 ⇒ 同为"卡片"却差 12px，
   乐哥：内部排版乱）。
   为什么要有这条：全站约 27 张卡片的间距是**写在 JS 内联 style 里**的
   （实测 `var(--space-6)` 24px ×25、`var(--space-4)` 16px ×2，其中一处就是看板
    「快捷入口」那张卡 —— 16px 让它与下方图表卡几乎粘在一起，是首屏最明显的一处"紧"）。
   内联样式优先级最高 ⇒ 必须 `!important` 才能覆盖。
   ⭐ 这是项目**既有做法**，不是新引入的 hack —— 见本文件顶部对
      「为什么必须用 CSS 规则 + !important，而不是在 JS 里写内联」的说明。
   ⚠️ 只匹配**卡片类**（`.card` / `.chart-card`）且只匹配这两个具体值：
      · 不碰 `.cell-sub`(39 处) / `.toolbar` / `.kpi-row` / `.field-label` 等非卡片元素；
      · 不动表单页 `var(--space-3)`(12px) 那 3 处 —— 那是刻意的紧凑表单分组，不是遗留。
   ⚠️ 内联写法有两种格式（实测 150 处无空格 + 1 处有空格），故两条属性选择器都写。
   ⚠️ 若以后新增卡片，直接在 CSS 里排版式（别再用内联 margin-bottom），
      这样天然命中标准、不需要这条兜底。
   ========================================================================== */
.card[style*="margin-bottom:var(--space-6)"],
.card[style*="margin-bottom:var(--space-4)"],
.card[style*="margin-bottom: var(--space-6)"],
.card[style*="margin-bottom: var(--space-4)"],
.chart-card[style*="margin-bottom:var(--space-6)"],
.chart-card[style*="margin-bottom:var(--space-4)"],
.chart-card[style*="margin-bottom: var(--space-6)"],
.chart-card[style*="margin-bottom: var(--space-4)"] {
  /* ⭐ 2026-09-28：20(--space-5) → **16(--space-4)**（乐哥：「这些卡片整体的上下间距
     是不是太大了，要不要小一点点」）—— 全站卡片间距统一口径从 20 收一档到 16，
     与卡片内边距（24）形成「内 24 / 间 16」—— 外层小于内层，卡片更抱团、页面更紧凑。 */
  margin-bottom: var(--space-4) !important;
}

/* ============================================================
   模块卡（全站通用）—— 信息模块的统一容器
   用法：
     <div class="module-card">
       <div class="module-card__head">…</div>                          有状态开关 → 标题栏状态底色
       <div class="module-card__head module-card__head--plain">…</div>  无开关   → 默认色 + 分隔线
       <div class="module-card__title">模块名</div>
     </div>
   规律（重要）：标题栏**有底色就不加线，没底色才用线补分界**；
   状态色只出现在标题栏与状态开关上，不外溢到卡片边框（禁止彩色描边 / 彩色外发光）。
   **间距标准：相邻模块卡之间固定 24px（由卡片自身用 + 选择器保证，不依赖外层容器配置）**。
   ============================================================ */
.module-card {
  /* ⭐ 2026-09-25 Gashora 骨架落地：同 .card——改浅边框划界（理由见 .card 注释）。 */
  background: var(--color-surface);
  border: 1px solid var(--color-frame-border);
  border-radius: var(--radius-lg);
  box-shadow: none;
  padding: var(--space-6);   /* ⭐ 2026-09-27：20(--space-5) → 24(--space-6)。
     乐哥：「文字跟模块的边距也要调整。像现在这个就很挤，之前不觉得挤，
     是因为它中间还有一层底」—— 去掉内容区白大卡后，卡片直接落灰底，
     原 20px 内边距在"卡片 vs 灰底 9 阶色差"的强边界下显得**相对更挤**。
     实测 padding 20→24：表格页**横滚无新增**（达人列表 1px→1px，看板/编辑无横滚）。
     ⚠️ 不再加回 28+：表格可用宽度会再缩，1440 视口下宽表会新增横滚。 */
}
/* 模块间距（标准）：相邻模块卡之间 20px（⭐ 2026-09-27 由 32 改为 20）。
   乐哥：「模块与模块之间间距…感觉不对」—— 对照 PMS 参考图与大厂（GitHub/Linear），
   卡片间距统一为 20px：与卡片内边距（24）形成「内 24 / 间 20」的紧凑节奏，
   比原「内 24 / 间 32」更聚拢、更像一个整体页面而非散落的卡。
   放在卡片自身而不是容器 gap 上 —— 任何容器里都自动生效。 */
.module-card + .module-card {
  /* ⭐ 2026-09-28：20(--space-5) → **16(--space-4)**（乐哥：「上下间距太大，小一点点」）*/
  margin-top: var(--space-4);
}
/* 表格类模块卡（通栏变体）：卡内是「工具栏 + 表格」，两者**自带内边距**，
   所以卡片自身不留内边距 —— 观感与全站表格页一致，也**不挤压表格的可用宽度**
   （订单明细/商品汇总这类表的列宽是按容器宽度抠过的，多 32px 内缩就会让长商品名折行）。
   用法：<div class="module-card module-card--flush">…</div> 后直接放 .table-toolbar / .table-wrap。
   注意：卡内**不要**再用 .card（那会套两层白底）。 */
.module-card--flush {
  padding: 0;
  overflow: hidden; /* 让内部表格/工具栏跟随卡片圆角裁切 */
}
/* flush 卡没有内边距 → 标题栏不需要负 margin 抵消；顶部圆角回到卡片圆角本身 */
.module-card--flush > .module-card__head {
  margin: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
/* 无内容体变体：卡内只有标题栏、没有正文（如排期页「大概排期」开关关闭时）。
   必须**同时**清掉标题栏的 margin-bottom 与卡片 padding-bottom —— 两者相加是 28px 空隙，
   留着的后果是卡片下沿多出一块空白、与下方内容视觉粘连（2026-09-15 乐哥反馈「排期展示有问题」）。
   顺带去掉标题栏的下分隔线：没有内容就没有分界的必要，留着会紧贴卡片底边像多画了一条线。 */
.module-card--bodyless {
  padding-bottom: 0;
}
.module-card--bodyless > .module-card__head {
  margin-bottom: 0;
  border-bottom: none;
}
/* 去卡片化变体（2026-09-15）：用于「一行分组标题 + 一行内容」这类**轻量区块**。
   乐哥原话：「大概排期就不要那个底了，直接和下面的板块一根线隔开就行，然后上下间距大点」。
   改前：整块是浮影卡片（白底 + 阴影 + 圆角 + 16px 内边距），与下方板块是「两个盒子」的关系；
   改后：去掉底（背景 / 阴影 / 圆角 / 内边距），退化为「标题行 + 内容」，
   用**一条分隔线**与下方断开 —— 与详情页 `.detail-block` 的视觉语言一致。
   做成通用变体而不是就地 hack：这类"轻量分组"在表单页会反复出现。

   ⚠️ 分隔线放在**整块的下沿**（border-bottom），**不是**标题行下面：
      语义是"这一组到此结束"；放标题下方会被读成"标题栏的装饰线"，与分组无关。 */
.module-card--bare {
  background: none;
  box-shadow: none;
  border-radius: 0;
  padding: 0 0 var(--space-6); /* 分隔线**上方**的留白（下方的留白由后继元素自己的 margin-top 给） */
  /* ⛔⛔ 2026-09-28 修一个**渲染成空框**的 bug（乐哥截图报「uibug」）——
     本变体的意图是"去掉整个盒子、只留**一条底部分隔线**"（见上方说明），
     但原实现**只覆盖了 `border-bottom`**，基类 `.module-card` 的
     `border: 1px solid var(--color-frame-border)` 其余三边仍在 ⇒
     实际渲染成「上/左/右细框 + 底部分隔线」的**透明空盒子**。
     实测（`#/schedule/138/edit` 的「大概排期」，开关关闭的 bodyless 态）：
       高度只剩标题行 36px，却画出完整四边框 ⇒ 看上去就是一个**多出来的空框**
       （乐哥：「上面那个…uibug」+「不要外面的框框了，多余」）。
     ✅ 显式清掉四边、再单独给底部一条线（顺序不能反：`border: 0` 必须在前面）。
     ⚠️ 影响面：全站仅 3 处用 `--bare`（schedule-form 大概排期 / t-tickets 2 处），
        都是"轻量分组"语义，本就该只有一条底线 ⇒ 修正是全局一致的方向。 */
  border: 0;
  border-bottom: 1px solid var(--color-border);
}
/* 内边距归零后，标题栏不需要负 margin 抵消；底色与它自带的分隔线也一并去掉（线已挪到整块下沿）。
   ⚠️ 但**上内边距要保留** `--space-3`（2026-09-15 收尾实测发现）：
      普通卡的标题靠 `.module-card__head` 自身的 `padding-top: --space-3` 把文字压到
      「卡片顶 + 12px」；`--plain` 版的原实现把 padding 一并清零 →
      同一页里两个 tab 的标题文字顶差 3px、区块起点差 8px，切 tab 时标题会"跳"。
      去卡片化要去的是**底**（背景/阴影/圆角）和**线的位置**，不是标题行的呼吸。
      左右仍为 0：bare 块没有底色盒，标题与它自己的内容必须共享同一条左基线。 */
.module-card--bare > .module-card__head {
  margin: 0 0 var(--space-4);
  padding: var(--space-3) 0 0;
  background: none;
  border-radius: 0;
  border-bottom: 0;
  min-height: 0;
}
/* 无内容体（开关关闭）时高度只剩标题行 —— 底部留白要收窄，否则线上方吊着一段空白。
   与 --bodyless 同一个诉求（"没有内容就别留内容的位置"），故两条变体合并处理。
   ⚠️ 必须用**双类**选择器：单类 `.module-card--bare` 与 `.module-card--bodyless` 特异性相同(0,1,0)，
      谁写在后面谁赢 —— 靠源码顺序"碰巧生效"是最脆的那种写法，显式提高特异性才稳。 */
.module-card--bodyless.module-card--bare {
  padding-bottom: var(--space-4);
}
.module-card--bodyless.module-card--bare > .module-card__head {
  margin-bottom: 0;
}
/* 模块卡内的二级区块（同一趴里的子分组，如佣金配置卡内的「排期单独维护」）：
   与上方内容用一条浅分隔线断开，标题用 .detail-section__title */
.module-card__sub {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border-soft);
}
/* 标题栏：通栏（负 margin 抵消卡片内边距，四角跟随卡片圆角） */
.module-card__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin: calc(var(--space-4) * -1) calc(var(--space-4) * -1) var(--space-3);
  padding: var(--space-3) var(--space-4);
  /* ⭐ 2026-09-25 Gashora 骨架落地：模块卡标题栏的**浅色底块**改透明。
     原来"标题栏铺一层浅灰底"与"卡片标题下画一条线"是同一目的（分隔标题与正文）；
     参考图两者都不用 ⇒ 去掉底色块，标题靠字重/字号与正文区分。 */
  background: transparent;
  border-radius: calc(var(--radius-lg) - 1px) calc(var(--radius-lg) - 1px) 0 0;
}
/* 开启态：标题栏底色/字色切到"黄"。
   两种写法都要认 —— 有的页面把 is-on 加在标题栏自身（schedule-form.js），
   有的加在外层卡片上（influencer-detail.js / schedule-detail.js）。
   只认前者的话，后两处的"单独维护"会落到默认的关闭态绿底，语义正好相反（2026-09-10 排查发现）。 */
.module-card__head.is-on,
.module-card.is-on > .module-card__head {
  background: var(--color-head-on-bg);
}
/* 标题行内的开关：靠右，并清掉开关自带的上下外边距 */
.module-card__head .switch {
  margin-left: auto;
  margin-top: 0;
  margin-bottom: 0;
}
.module-card__title {
  /* ⭐ 2026-09-28 全站提档：14(sm) → 16(lg) —— 卡片标题是卡片内的**一级信息**，
     与正文(14)同号会淹没；按令牌既定语义（lg = 卡片标题）与达人两页的 .ia-page 先行实践统一。
     字重保持 medium(500)：18:12 定的层级「卡片标题 16/500 · 正文 14/400 · 注释 12/400」不变。 */
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-medium);
  color: var(--color-head-off-fg);
}
.module-card__head.is-on .module-card__title,
.module-card.is-on > .module-card__head .module-card__title {
  color: var(--color-head-on-fg);
}
/* 无开关 / 无状态的模块：标题栏默认色（不着色），用一条分隔线与内容区分 */
.module-card__head--plain {
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}
.module-card__head--plain .module-card__title {
  color: var(--color-fg);
}

.card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);   /* ⭐ 2026-09-28：左右 20(--space-5) → 24(--space-6)，
     与 `.card__body`(24) 对齐 —— 原 20 让卡片标题比正文左缩 4px（乐哥：内部排版乱）。 */
  /* ⭐ 2026-09-25 Gashora 骨架落地：去掉标题与正文之间的分隔线（乐哥：「他那边有些标题跟下面的
     正文中间是没有线分隔的，咱们这边有些是有线分隔的，把这个线也去掉」）。
     参考图的卡片标题直接压在卡上、下面不画线——靠**间距**分组而非线条（更少线条、更干净）。 */
  border-bottom: 0;
}

.card__title {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--color-fg);
}

.card__body {
  padding: var(--space-6);   /* ⭐ 2026-09-27：与 .module-card 同步 20 → 24
     （去白大卡后卡片直接落灰底，"文字跟模块的边距"需要加大，见 .module-card 注释） */
}

/* 卡片内嵌的「内容分组 Tab」/ 工具栏 / KPI（整页内容包一个白卡片时，各区左右留白对齐）
   ⚠️⚠️ 2026-09-26 托盘化：缩进必须用 **margin** 而不是 padding。
      改前是 `padding: 0 20px`；若沿用 padding，它会因特异性 (0,2,0) > `.tabs` 的 (0,1,0)
      **覆盖掉 `.tabs` 自身的托盘内边距 `padding: 4px`** ⇒ 白块紧贴灰托盘边缘（没有呼吸），
      实测 .tabs 高度从应有的 40px 变成 32px（真机量到，肉眼还没那么明显）。
      ⇒ 改 `margin: 16px 20px`：左右 20 与卡片内工具栏左缘对齐（原意图不变），
        上下 16 给托盘与卡片顶部 / 下方内容留呼吸（原来是 0，靠旧方案 44px 行高自己撑）。 */
/* 卡片内嵌的「内容分组 Tab」的呼吸（上下 16 / 左右 20）。
   ⚠️ 本条对"**自身没有内边距**的卡片"是正确的（如达人详情 `.sf-shell`、排期表单）——
      16px 就是托盘与卡片边的间距。
   ⛔ 但"**自带 padding 的卡片**"会与它**叠加**：`.pf-card` 自身 `padding: 20px`，
      叠加后上方 = 20 + 16 = **36px**，而左右只有 20px ⇒ **托盘偏下、上下不对称**。
      实测（业绩总表，乐哥实报「二级 tab 样式不对」）：
        托盘 top=261 / 卡片内容顶=245 ⇒ 上方 36px；托盘 bottom=301 / 工具栏 top=321 ⇒ 下方 20px。
   ✅ 处理办法：自带内边距的卡片**自己把 margin-top 归零**（见 pages.css 的 `.pf-card > .tabs`），
      让它只吃自己的 padding —— 这样"上 = 左右 = 20px"，整齐。
   ⚠️ 别在这里写 `:not(.pf-card)` 之类的排除法：将来再出现一个"自带 padding 的卡片"，
      排除法不会自动生效、又会踩同一个坑。**谁有内边距谁负责归零**才是收敛的规则。 */
.card > .tabs {
  /* ⭐ 2026-09-28 下外边距 16 → **0**（乐哥：「tab 栏和下面内容模块间距太大了，全局要一致」）——
     卡内 tab 与内容的间距改由**紧跟的 card__body 的 padding-top(16)** 唯一承担：
     改前「tab margin 16 + card__body padding 24 = 40px」是两处叠加的产物（全站最大的一处空隙）。
     ⇒ 配合下方 `.card > .tabs + .card__body` 的 padding-top 收档，间距 = 16，与全站一致。
     ⚠️ 原 `border-bottom: 0`（下划线基线时代的"去基线"）已删——现在基类是**完整 1px 边框**，
        留着它会让容器缺底边、胶囊上下项距不对称（实测 7px vs 6px，探针抓到）。 */
  margin: var(--space-4) var(--space-5) 0;
  /* ⭐⭐ 2026-09-28 **卡内 tab 也吸顶**（乐哥：「然后上面 tab 没悬浮」——指编辑排期页）——
     该页（`#/schedule/:id/edit`）的 tab 是 `.card > .tabs` 结构（唯一一处），
     而上一轮「表单页吸顶」只覆盖了 `.sf-tabs` / `.sf-tabs__track` 两种外壳
     ⇒ 这页的 tab **完全没吸顶**（实测：滚动 500px 后 top 从 322 变 275，跟着页面滚走）。
     ▸ sticky 挂在本层（`.tabs` 自己）：父级是 `.card`（实测高 1968px）⇒ 吸附余量充足。
     ▸ `width` **不能用 100%**（这是 2026-09-28 我自己埋的 bug，当日修）：
       本块已有 `margin: 16px 20px 0`（左右各 20），再叠 `width: 100%` ⇒
       实际宽 = 父内容宽 1278 + 只有左 margin 生效的错觉，实测**右缘戳出卡片 19px**
       （tabs r=1738.5 / card r=1719.5），白条跨过卡片右边框 —— 截图肉眼可见。
       ⚠️ 基类 `.tabs` 是 `width: fit-content`（408px）—— 吸顶时若只有内容宽，
          会变成"一条窄条浮着"，所以要覆盖；但覆盖值必须是 **`auto`**
          （块级 flex 容器 = 填满含 margin 的可用宽 ⇒ 1278−40=1238，左右各留 20 对称），
          而**不是** 100%（100% 不含 margin，必然溢出）。
       实测修后：tabs 460.5→1698.5（1238 宽），卡片 439.5→1719.5，两侧各留 20 ✓
     ⚠️ `.card` 的 `overflow` 必须是 visible（实测 ✓）—— hidden/auto 会让 sticky 失效。 */
  width: auto;
  position: sticky;
  top: calc(var(--tabs-bar-height) + var(--frame-gap) + 4px);
  z-index: 60;
  transition: box-shadow var(--motion-base) var(--motion-ease-standard),
              background-color var(--motion-base) var(--motion-ease-standard);
}
/* 卡内 tab 的「贴顶变玻璃」——与二级页 / 表单页同一套 `.is-stuck` 机制
   （`app.js` 的 updateStuck 扫描列表里已含 `.tabs`）。
   ⚠️ 用 `.tabs.is-stuck`（不限定 `.card >`）：别的 `.tabs` 没有 sticky ⇒ 永远不会挂上本类 ⇒ 安全。 */
.tabs.is-stuck {
  background: var(--liquid-bg);
  backdrop-filter: var(--liquid-blur);
  -webkit-backdrop-filter: var(--liquid-blur);
  border-color: var(--liquid-edge);
  box-shadow: var(--liquid-shadow);
}
/* 卡内 tab 紧跟内容区时：padding-top 收一档（24 → 16），配合上一条 margin 归零
   ⇒ tab 底 → 内容首行 = 16px（= 全站卡片间距）。
   ⚠️ 只命中「tabs 的相邻兄弟 card__body」，卡内其它位置的 card__body 不受影响。 */
.card > .tabs + .card__body {
  padding-top: var(--space-4);
}
.card > .toolbar {
  padding: var(--space-4) var(--space-5) var(--space-3);
  margin: 0;
}
.card > .kpi-row {
  padding: var(--space-3) var(--space-5);
  margin-bottom: 0;
}

/* ---- 开关 switch ---- */
.switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex-direction: row-reverse; /* 文字在左，开关轨道在右 */
  cursor: pointer;
  user-select: none;
}
.switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  margin: 0;
}
.switch__track {
  position: relative;
  width: 40px;
  height: 22px;
  background: var(--color-border);
  border-radius: var(--radius-pill);
  flex-shrink: 0;
  transition: background-color var(--motion-fast) var(--motion-ease-standard);
}
.switch__thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  /* ⭐ 2026-09-26：滑块用 **弹入曲线**（落位时轻微过冲 ~6% 再咬合）。
     开关是"小物件蹦一格"，过冲是它该有的手感；用通用位移曲线会显得"滑过去就停了"。
     ⚠️ 轨道变色仍用普通 ease —— 它是"状态色"不是"运动"，跟着弹会花。 */
  transition: transform var(--motion-base) var(--motion-ease-pop);
}
.switch input:checked + .switch__track {
  background: var(--switch-active-bg);
}
.switch input:checked + .switch__track .switch__thumb {
  transform: translateX(18px);
}
.switch input:focus-visible + .switch__track {
  box-shadow: var(--focus-ring);
}
.switch input:disabled + .switch__track {
  opacity: 0.5;
  cursor: not-allowed;
}
.switch__label {
  margin-right: var(--space-2);
  font-size: var(--font-size-sm);
  color: var(--color-fg);
}
.switch--sm .switch__track {
  width: 34px;
  height: 19px;
}
.switch--sm .switch__thumb {
  width: 15px;
  height: 15px;
  top: 2px;
  left: 2px;
}
.switch--sm input:checked + .switch__track .switch__thumb {
  transform: translateX(15px);
}

/* ---- 分段控件 / 筛选条（白容器 + 选中项内缩蓝色圆角块，对齐乐哥截图：T+35口径 样式）---- */
.seg {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);                    /* 选项间 4px 间隙（不紧贴） */
  padding: 4px;                            /* 容器内边距 → 选中块内缩 */
  background: var(--color-surface);        /* 白色容器 */
  border: 1px solid var(--color-border);   /* #E5E8EC */
  border-radius: var(--radius-md);          /* 8px 圆角矩形 */
}
.seg__btn {
  padding: 6px 16px;
  border: none;
  border-radius: var(--radius-seg);         /* 6px：选中块自身圆角 */
  background: transparent;
  color: var(--color-fg-2);                 /* 未选中深字 #3F4753 */
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--motion-fast) var(--motion-ease-standard),
    background var(--motion-fast) var(--motion-ease-standard);
}
.seg__btn:hover {
  color: var(--color-accent-text);
}
.seg__btn.is-active {
  background: var(--color-accent);     /* 选中主色实底 #0064E0（内缩圆角块） */
  /* ⭐ 2026-09-25 UI 美化第二刀：选中态接入品牌渐变，与 `.btn--primary` 同一套语言。
     为什么改这里：分段控件是**全站筛选区最常见的控件**，它一屏可能有 2~4 组。
     原来是纯色实底，与主按钮并排时"两种蓝"（同一品牌色但一个有渐变一个没有）会显得不统一；
     接上同一渐变后，全站所有"实心主色块"（主按钮 / 分段选中 / 胶囊选中）视觉语言一致。
     ⚠️ 用 background-image 叠层（保住上面那行 background 作回落），与 .btn--primary 同款写法。 */
  background-image: var(--gradient-brand);
  color: var(--color-accent-on);       /* 白字 */
}

/* 分段控件内的分组标签 + 下拉 + 分隔线 */
.seg__label {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--space-2) 0 var(--space-3);
  font-size: var(--font-size-sm);
  color: var(--color-muted);
  font-weight: var(--font-weight-medium);
  white-space: nowrap;
}
.seg__divider {
  width: 1px;
  align-self: stretch;
  margin: 4px var(--space-1);
  background: var(--color-border);
}
.seg-select {
  padding: 6px 16px;
  border: none;
  border-radius: var(--radius-seg);
  background: transparent;
  color: var(--color-fg-2);
  font-size: var(--font-size-sm);
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  outline: none;
  transition: color var(--motion-fast) var(--motion-ease-standard),
    background var(--motion-fast) var(--motion-ease-standard);
}
.seg-select:hover {
  color: var(--color-accent-text);
}
.seg-select.is-active {
  background: var(--color-accent);
  color: var(--color-accent-on);
}

/* ---- 筛选条别名（.pill-filter，与 .seg 同规格：白容器 + 选中项内缩蓝色圆角块）---- */
.pill-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 4px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.pill-filter__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 原 6px 16px：改上 6.5 下 5.5，配合 flex 居中补偿中文字面偏上 */
  padding: 6.8px 16px 5.2px;
  border: none;
  border-radius: var(--radius-seg);
  background: transparent;
  color: var(--color-fg-2);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--motion-fast) var(--motion-ease-standard),
    background var(--motion-fast) var(--motion-ease-standard);
}

.pill-filter__item:hover {
  color: var(--color-accent-text);
}

.pill-filter__item.is-active {
  background: var(--color-accent);
  /* ⭐ 2026-09-25 UI 美化第二刀：胶囊选中态同步接品牌渐变（与主按钮 / 分段控件一致）。
     ⚠️ 注意：`.table-tabs` 里的胶囊/分段有**透明底覆盖**（见 table.css 的
        `.table-tabs .pill-filter__item.is-active`）—— 那条特异性更高且写的是 `background: transparent`，
        会把本条的 background-image 一起盖掉（下划线形态保持不变，属预期）。 */
  background-image: var(--gradient-brand);
  color: var(--color-accent-on);
}

/* 胶囊上的人数角标（2026-09-15，提成总览「类目」筛选用）——
   让「点助播能筛出几个人」在点之前就知道。
   ⚠️ 用 <em> 而不是 <span>：<em> 语义上是"强调"，这里恰好是"次要补充信息"，
      用 span 也行但项目里 <em> 已被用于这类数字角标（与 .co-role-n 呼应）。
   ⚠️ 继承当前文字色阶（未选中=次要色、选中=白字），不要写死颜色，
      否则选中态（蓝底）上会出现灰字看不清。 */
.pill-filter__item .co-role-n {
  margin-left: 5px;
  font-size: var(--font-size-xs);
  font-style: normal;
  opacity: .78;
}

/* 0 人的类目：置灰但**不禁用**（禁用会让"这个类目不存在"和"今天没数据"看起来一样） */
.pill-filter__item.is-empty {
  opacity: .45;
}
.pill-filter__item.is-empty.is-active {
  opacity: 1;   /* 已选中的不置灰：用户明确选了它，得看清楚自己选了什么 */
}

/* ---- 货品缩略图 ---- */
.product-thumb {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  border: 1px solid var(--color-border-soft);
}
.product-thumb--empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--color-surface-2);
  color: var(--color-muted);
}

/* ---- 图片上传控件 ---- */
.img-upload {
  position: relative;
  width: 160px;
  height: 160px;
  border: 2px dashed var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--motion-fast) var(--motion-ease-standard);
}
.img-upload:hover {
  border-color: var(--color-accent-text);
}
.img-upload__empty {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  color: var(--color-muted);
  font-size: var(--font-size-sm);
}
.img-upload__preview {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.img-upload__remove {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.5);
  color: #fff;
  cursor: pointer;
}
.img-upload__remove:hover {
  background: rgba(0, 0, 0, 0.7);
}

/* ---- 飞书通讯录选人组件 ---- */
.fp {
  position: relative;
}
.fp__box {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  min-height: 40px;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  background: var(--input-bg);
  cursor: text;
}
.fp__box:focus-within {
  border-color: var(--input-focus-border);
  box-shadow: var(--focus-ring);
}
.fp__field {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 1;
  min-width: 120px;
}
.fp__value {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--font-size-base);
}
.fp__placeholder {
  color: var(--color-muted);
}
.fp__search {
  flex: 1;
  min-width: 80px;
  border: none;
  outline: none;
  font-size: var(--font-size-base);
  background: transparent;
}
.fp__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.fp-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px 2px 2px;
  border-radius: var(--radius-pill);
  background: var(--color-surface-2);
  font-size: var(--font-size-sm);
}
.fp-chip__x {
  border: none;
  background: none;
  cursor: pointer;
  color: var(--color-muted);
  display: inline-flex;
  padding: 0;
}
.fp-chip__x:hover {
  color: var(--color-danger);
}
.fp-avatar {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.fp-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.fp-avatar--empty {
  background: var(--color-primary-100);
  color: var(--color-accent-text);
  font-size: var(--font-size-xs);
}
.fp__dropdown {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  width: 100%; /* 显式约束，不让内容撑大溢出到旁边列 */
  max-height: 240px;
  overflow-y: auto;
  overflow-x: hidden; /* 裁剪水平溢出，防止 fp-item 长名字撑开 */
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-raised);
  z-index: var(--z-dropdown);
}
.fp-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  font-size: var(--font-size-sm);
}
/* 下拉项圆角：首项顶部、末项底部跟随弹窗圆角，避免直角突兀 */
.fp__dropdown .fp-item:first-child,
.fp__dropdown .fp-empty:first-child {
  border-top-left-radius: calc(var(--radius-md) - 1px);
  border-top-right-radius: calc(var(--radius-md) - 1px);
}
.fp__dropdown .fp-item:last-child,
.fp__dropdown .fp-empty:last-child {
  border-bottom-left-radius: calc(var(--radius-md) - 1px);
  border-bottom-right-radius: calc(var(--radius-md) - 1px);
}
.fp-item:hover {
  background: var(--color-surface-2);
}
.fp-item__name {
  color: var(--color-fg);
}
.fp-empty {
  padding: var(--space-4);
  text-align: center;
  color: var(--color-muted);
  font-size: var(--font-size-sm);
}
/* 选人组件修复：输入框占满剩余空间，点击任意位置可聚焦 */
.fp__box .fp__value {
  flex-shrink: 0;
  max-width: 100%;
}
.fp__search {
  flex: 1;
  min-width: 80px;
  cursor: text;
}
/* 历史「常用」标签 */
.fp-item__tag {
  margin-left: auto;
  padding: 0 6px;
  font-size: var(--font-size-xs);
  line-height: 16px;
  border-radius: var(--radius-pill);
  background: var(--color-surface-2);
  color: var(--color-muted);
}
/* 下拉可滚动（移动端顺滑） */
.fp__dropdown {
  -webkit-overflow-scrolling: touch;
}
/* 外部人员（不在飞书通讯录，如兼职商务） */
.fp-item--external {
  border-top: 1px dashed var(--color-border-soft);
  margin-top: 4px;
  padding-top: 8px;
}
.fp-item__tag--ext {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

/* ---- 列表操作列按钮：一行展示 + 配色 ---- */
.table .toolbar {
  flex-wrap: nowrap;
}
/* 图标按钮配色：查看灰 / 编辑蓝 / 删除红 */
.icon-btn[data-view] { color: var(--color-muted); }
.icon-btn[data-view]:hover { color: var(--color-fg); background: var(--color-surface-2); }
.icon-btn[data-edit] { color: var(--color-accent-text); }
.icon-btn[data-edit]:hover { color: var(--color-accent-hover); background: var(--color-primary-100); }
.icon-btn[data-del] { color: var(--color-danger); }
.icon-btn[data-del]:hover { color: var(--color-danger); background: var(--color-danger-bg); }

/* ⭐ 2026-09-25 UI 美化第三刀：「编辑」图标在**表格内**改为**中性灰**（hover 才显品牌蓝）。
   为什么（实测依据）：一屏数据表 20 行 × 3 个图标 = **60 个图标**，
   其中 20 蓝 + 20 红全彩 —— 一屏 40 个高饱和小图标，让"操作列"成了表里最花的一块，
   数据反而退居其次（乐哥：「感觉还是不够清新简约…还有文字」）。
   改后一行是「灰 · 灰 · 红」：两个只读类操作（查看/编辑）退为中性，
   只有**删除**保留红色警示（这是真风险操作，颜色要留）。hover 时蓝色回来，可点性不受影响。
   ⚠️ 特异性 `.table .icon-btn[data-edit]`(0,3,0) 高于基础规则 `.icon-btn[data-edit]`(0,2,0)，
      故顺序无关，但写在后面便于阅读。
   ⚠️ 只改**表格内** —— 表格外（详情页、卡片、表单）的编辑按钮数量少、且常是主入口，保持蓝色。
   ⚠️ 不改任何图标语义 / 类名 / JS：`data-edit` 属性照旧，只调颜色。 */
.table .icon-btn[data-edit] { color: var(--color-muted); }
.table .icon-btn[data-edit]:hover { color: var(--color-accent-text); background: var(--color-primary-100); }
/* 表单页小删除按钮（trash 图标）统一红色 */
.icon-btn.n-del,
.icon-btn.sess-del,
.icon-btn.acc-del,
.icon-btn.bf-del,
.icon-btn.pid-del,
.icon-btn.rule-del,
.icon-btn.sk-del,
.icon-btn.item-del,
.icon-btn.pf-prod-del {
  color: var(--color-danger);
}
.icon-btn.n-del:hover,
.icon-btn.sess-del:hover,
.icon-btn.acc-del:hover,
.icon-btn.bf-del:hover,
.icon-btn.pid-del:hover,
.icon-btn.rule-del:hover,
.icon-btn.sk-del:hover,
.icon-btn.item-del:hover,
.icon-btn.pf-prod-del:hover {
  color: var(--color-danger);
  background: var(--color-danger-bg);
}
/* 文字按钮配色（用户管理等）：改角色/重置密码蓝 / 停用启用灰 / 删除红 */
.btn--ghost[data-role], .btn--ghost[data-pwd] { color: var(--color-accent-text); }
.btn--ghost[data-role]:hover, .btn--ghost[data-pwd]:hover { color: var(--color-accent-hover); background: var(--color-primary-100); }
.btn--ghost[data-status] { color: var(--color-muted); }
.btn--ghost[data-status]:hover { color: var(--color-fg); background: var(--color-surface-2); }
.btn--ghost[data-del] { color: var(--color-danger); }
.btn--ghost[data-del]:hover { color: var(--color-danger); background: var(--color-danger-bg); }

/* ---- 必填项星号 ---- */
.field-label .req { color: var(--color-danger); }

/* ---- 移动端：搜索框占满、控件触控目标 ≥40px、表格紧凑 ---- */
@media (max-width: 768px) {
  .input--search {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 100%;
  }
  .input--search .input {
    width: auto !important;
    flex: 1 1 auto;
    min-width: 0;
  }
  /* 触控目标（Apple HIG ≥44px 可点区域）：输入/选择/日期触发 44，按钮/分段 40 */
  .input,
  .select {
    min-height: 44px;
  }
  .dtp-trigger,
  .fp__box {
    min-height: 44px;
  }
  .seg {
    min-height: 40px;
  }
  .btn {
    min-height: 40px;
  }
  .btn--lg {
    min-height: 44px;
  }
  /* 表格更紧凑 */
  .table tbody td {
    padding: 8px 12px;
  }
}

/* ===== 数据导入页 ===== */
.upload-drop {
  border: 2px dashed var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6) var(--space-4);
  text-align: center;
  cursor: pointer;
  color: var(--color-muted);
  transition: border-color .15s, background .15s;
  margin-top: var(--space-2);
}
.upload-drop:hover { border-color: var(--color-accent); background: var(--color-surface-2); }
.upload-drop.is-dragover { border-color: var(--color-accent); background: var(--color-accent-bg); }
.upload-drop svg { color: var(--color-muted); }

.sheet-option {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border-soft);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-2);
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.sheet-option:hover { border-color: var(--color-accent); }
.sheet-option.is-active { border-color: var(--color-accent); background: var(--color-accent-bg); }

/* 导入预览：原始数据可编辑单元格 */
.pv-cell { cursor: text; }
.pv-cell.is-edited { background: var(--color-warning-bg); }

/* 导入预览·「导入后效果」视图（落地结果，只读） */
.ld-ok { color: var(--color-success-text); font-size: var(--font-size-sm); line-height: 1.4; }
.ld-bad { color: var(--color-danger); font-size: var(--font-size-sm); line-height: 1.4; }
.ld-ok + .ld-ok, .ld-bad + .ld-ok, .ld-ok + .ld-bad, .ld-bad + .ld-bad { margin-top: 2px; }
/* 行内 SVG 图标与文字基线对齐（2026-09-14 新增）
   起因：`.ld-ok/.ld-bad` 的状态标记、排期表「其他佣金备注」标记原先用 ✓/✗/✱ **文字符号**当图标，
        违反 P0 规则（禁止用文字符号/emoji 代替图标），已改用 icons.js 的 SVG。
        SVG 默认按基线对齐会略微偏上，故统一下移一点，视觉上与文字居中。 */
.ld-ok > svg, .ld-bad > svg, .icon-inline > svg { vertical-align: -0.15em; }

/* ══════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ 2026-09-28 全站 tab 条「内层小框」（乐哥拍板：统一成一级页那个形态）
   ──────────────────────────────────────────────────────────────────────────
   全站 tab 条统一为**三层**（以一级页为基准）：
     .page-header--has-tabs / .tabs / .sf-tabs__track   ← 白卡（外层）
       .table-tabs--in-header / .tabs__tray             ← **内层小框**（本规则）
         胶囊（.pill-filter__item / .tab / .sf-tab）    ← 高 34
   ▸ 为什么要有中间这层：它把「一组 tab」圈成一个控件（与右侧操作按钮区分开），
     也是"看起来很整"的来源 —— 一级页一直这么做，其余页面缺这层。
   ▸ 本层由 JS 包装产出（见 app.js 的 wrapTabTrays，在 relayoutActive 里跑、幂等），
     **不改 9 个页面的渲染代码**。
   ⚠️ 与本表下方 `.table-tabs--in-header`（一级页的原生内层框）**同规格** ——
      两条规则必须同值（高 44 = 4+34+4+2、圆角 10、边框 1px --color-border、项距 2px），
      门禁 tests/tab-unify.test.js 会锁这个一致性（防两处漂移）。 */
.tabs__tray {
  display: inline-flex;
  align-items: center;
  gap: 2px;                                     /* 项距 2px：胶囊是"紧邻的块"，不是散排文字 */
  flex: none;                                   /* 收缩到内容宽（不拉伸，同 .table-tabs--in-header） */
  padding: 4px;                                 /* 4 + 34 + 4 + 2(边框) = 44，与右侧按钮齐平 */
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);              /* 10px */
  background: var(--color-surface);
  max-width: 100%;
  flex-wrap: wrap;                              /* 窄屏换行，不出横向滚动条 */
  /* 贴顶变玻璃时的平滑过渡（乐哥要的是"和其他内容叠加才有"，突变会很生硬） */
  transition: background-color var(--motion-base) var(--motion-ease-standard),
              border-color var(--motion-base) var(--motion-ease-standard);
}

/* 一级 Tab 卡（跨页共用）：业绩总表 ↔ 订单明细 顶部是同一组 tab，切页后 tab 仍在，不会「困在」某一页 */
.tabs-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border-soft);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5) 0;
  margin-bottom: var(--space-4);
}
.tabs-card > .tabs { margin-bottom: 0; }

/* ============ 月份选择组件 UI.MonthPicker ============ */
.mp { position: relative; display: inline-block; }
.mp__trigger {
  height: var(--control-height);   /* 与同排的 .input / .select 齐平（标准档） */
  padding: 0 32px 0 var(--space-3);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  background: var(--input-bg);
  color: var(--color-fg);
  font-size: var(--font-size-base);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .15s;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%238595A4' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 12px 12px;
}
.mp__trigger:hover { border-color: var(--input-focus-border); }

/* 筛选生效中（已选中具体某月）：与「未筛选」的素色态明显区分 —— 主色描边 + 前置筛选图标 + 可点的 ✕。
   设计意图：月份触发器与它旁边那些「全部平台 / 全部状态」下拉长得一样时，用户看不出自己正被月份筛着，
   会误以为看到的是全量数据（搜不到别的月份 → 当成 bug）。所以「正在筛」这件事必须在视觉上说出来。 */
.mp__trigger.is-on {
  border-color: var(--color-accent);
  color: var(--color-accent);
  font-weight: var(--font-weight-semibold);
  background-image: none;              /* 去掉下拉箭头：改由前置筛选图标表达「这是筛选条件」 */
  padding-right: var(--space-3);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.mp__trigger.is-on:hover { border-color: var(--color-accent); }
.mp__trigger .mp__label { white-space: nowrap; }
.mp__trigger.is-on > svg { flex-shrink: 0; }
.mp__clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: 1px;
  opacity: .5;
  transition: opacity .15s;
}
.mp__trigger.is-on:hover .mp__clear { opacity: 1; }

.mp__panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: var(--z-dropdown);
  min-width: 232px;
  padding: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border-soft));
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-raised);
}
.mp__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-2);
}
.mp__nav {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-fg-2);
  font-size: var(--font-size-lg);
  line-height: 1;
  cursor: pointer;
}
.mp__nav:hover:not(:disabled) { border-color: var(--color-accent); color: var(--color-accent-text); }
.mp__nav:disabled { opacity: .35; cursor: not-allowed; }
.mp__year { font-size: var(--font-size-base); font-weight: 600; color: var(--color-fg); }

.mp__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.mp__month {
  padding: 7px 0;
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-fg);
  font-size: var(--font-size-sm);
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.mp__month:hover:not(:disabled) { border-color: var(--color-accent); }
.mp__month.is-active {
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--color-accent-on);
  font-weight: 600;
}
.mp__month.is-disabled,
.mp__month:disabled {
  border-color: var(--input-border);
  background: transparent;
  color: var(--input-disabled-text);
  opacity: .5;
  cursor: not-allowed;
}
/* 当月（今天所在的月）：主色描边 + 主色字。
   要点：必须跟「已选中」区分开 —— 已选中是主色实心，当月是空心描边，两者同月出现时以实心为准。
   当月若没有数据（禁用灰格）也保留描边，让人知道"这是当前月，只是还没数据"。 */
.mp__month.is-current:not(.is-active) {
  border-color: var(--color-accent);
  color: var(--color-accent);
  font-weight: var(--font-weight-semibold);
}
.mp__month.is-current:not(.is-active):disabled {
  color: var(--input-disabled-text);
  opacity: .55;
}

.mp__foot {
  display: flex;
  gap: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-border-soft));
}
/* 底部两个快捷按钮：给底色提亮，并分出主次 ——
   「全部月份」是"清除月份筛选"的出口（主），给主色淡底；「回到当月」是快捷键（次），给中性淡底。 */
.mp__today,
.mp__all {
  flex: 1;
  padding: 8px 0;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  cursor: pointer;
  transition: border-color .12s, background .12s, color .12s;
}
.mp__today {
  background: var(--color-surface-2);
  border-color: var(--color-border);
  color: var(--color-fg);
}
.mp__today:hover:not(:disabled) { border-color: var(--color-accent); color: var(--color-accent-text); }
.mp__today:disabled { color: var(--input-disabled-text); opacity: .5; cursor: not-allowed; }
.mp__all {
  background: var(--color-accent-bg);
  color: var(--color-accent);
  font-weight: var(--font-weight-semibold);
}
.mp__all:hover { border-color: var(--color-accent); }

/* 筛选栏「重置」按钮：高度必须对齐同一行里的输入框 / 下拉 / 月份选择器（都是 44px）。
   用小号按钮（30px）会比邻居矮一截、看着又小又弱 —— 2026-09-10 乐哥反馈"太小了、看不清"。 */
.filter-reset {
  height: var(--control-height);
  padding: 0 var(--space-4);
}

/* 兼职助播结算：费用块（开关 + 标题 + 字段） */
.pta-fee {
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border-soft);
  border-radius: var(--radius-md);
}
.pta-fee__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.pta-fee__title {
  font-weight: var(--font-weight-semibold);
  color: var(--color-fg);
}
.pta-fee__body {
  margin-top: var(--space-3);
}

/* 列表多选批量操作栏 */
.batch-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface-2);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-3);
}
.batch-bar__count {
  font-size: var(--font-size-sm);
  color: var(--color-fg);
  font-weight: var(--font-weight-medium);
}

/* 提成「人为校准」标记 */
.calib-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  color: var(--color-warning);
  background: var(--color-warning-bg);
  border-radius: var(--radius-pill);
  vertical-align: middle;
}

/* 场次提成：展开子行（与主表同列结构，一行一个直播场次 / 支援人力明细） */
.table tr.row-sub > td {
  background: var(--color-surface-2);
  padding-top: var(--space-2);
  padding-bottom: var(--space-2);
}
.table tbody tr.row-sub:hover > td {
  background: var(--table-row-hover);
}
/* 场次提成：岗位分组分隔线（商务 | 助播 | 商务助理 | 支援人力成本） */
.table th.group-sep,
.table td.group-sep {
  border-left: 1px solid var(--color-border);
  padding-left: var(--space-4);
}
/* 人员维度：展开明细里的内嵌子表 */
.table td .table--sub {
  margin: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.table--sub th,
.table--sub td {
  padding: var(--space-2) var(--space-3);
  font-size: var(--font-size-xs);
}
.link-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  border: none;
  background: none;
  color: var(--color-accent-text);
  cursor: pointer;
  font-weight: var(--font-weight-medium);
}
.link-btn:hover {
  color: var(--color-primary-500);
  text-decoration: underline;
}
/* 支援人力「不计成本」：整行淡化 */
.table tr.is-excluded td {
  opacity: 0.55;
}

/* ==========================================================================
   口径提示气泡（tooltip）—— 2026-09-12 新增（配 UI.tip / UI.bindTips）
   · 单例元素挂 body，**position:fixed** —— 必须 fixed：
     表格外层 .table-wrap{overflow-x:auto} 会裁掉 absolute 定位的气泡
   · 默认在触发器上方居中，上方空间不足时由 JS 翻到下方
   ========================================================================== */
.ui-tip {
  position: fixed;
  z-index: var(--z-toast);
  max-width: 320px;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--color-fg);
  color: var(--color-surface);
  box-shadow: var(--shadow-md);
  font-size: var(--font-size-sm);
  line-height: 1.5;
  word-break: break-word;
  /* ⭐ 2026-09-25：支持 `\n` 换行 —— 口径气泡常有"算法定义 + 数字算式"两段
     （如「金额口径：退款额 ÷ 实付总额」/「¥1,548,186.41 ÷ ¥5,189,547.80」），
     挤成一行既长又难读。pre-line 让 JS 里写的 \n 生效、同时保留自动折行。 */
  white-space: pre-line;
  pointer-events: none;      /* 气泡本身不拦鼠标：移开就消失，不闪烁 */
}

/* ==========================================================================
   备注文本展示（乐哥 2026-09-13）
   「所有涉及备注的地方，文字表达、排版都优化下，一句话一行会好点，
     展示实在不行就用弹窗。然后展示重点文字得标出来的。」
   --------------------------------------------------------------------------
   为什么要做成组件：改动前全站 7 处备注列是同一个复制粘贴写法
     （`ellipsis + max-width:96px` + `title` 悬停），另有约 10 处裸输出。
   而真实数据（店铺订单备注 550 条）：中位 12 字、最长 98 字、8% 超 40 字，
   55% 用空格 / 42% 用冒号 / 24% 用逗号把好几件事挤在一行 —— 挤成一行等于看不见。
   配合 js/remark.js：拆句（一句一行）+ 重点高亮 + 超长折叠 / 弹窗。
   -------------------------------------------------------------------------- */

/* ---- 文本块 ---- */
.rmk { line-height: 1.6; }
.rmk-line { display: block; }
/* 多句之间给一点行距，读起来像清单而不是一段话 */
.rmk--block > .rmk-line + .rmk-line { margin-top: 6px; }
.rmk--block { font-size: var(--font-size-sm); color: var(--color-fg); }

/* 表格单元格里的备注：小一号、次要色（是辅助信息，不抢主字段的注意力） */
.rmk--cell { font-size: var(--font-size-xs); color: var(--color-fg-2); }
.rmk--cell > .rmk-line + .rmk-line { margin-top: 2px; }
/* ⚠️ 表格里的每句**必须严格占 1 行**（乐哥 2026-09-13 排查「明显高行」时发现的组件缺陷）：
   JS 的 `maxChars` 是**按字符数**限长的，但中文在窄列里会自动折行 ——
   实测：达人列表备注列 100px，一行只放得下 ~7 个中文字，而 maxChars 设的是 36
   → 一句被折成 5 行，"maxLines:2" 实际渲染出 10 行，行高从 67px 涨到 125px
     （全站 3 张表的"明显高行"都是这一个原因：达人列表 / 成本·滴滴 / 成本·报销）。
   这里用 nowrap 把「1 个 .rmk-line == 1 行」这个前提固定下来；
   放不下的部分由 `text-overflow: ellipsis` 收尾，完整内容仍可 hover（title）或点「还有 N 条」看弹窗。
   ⚠️ 只作用于 `.rmk--cell`：弹窗里的 `.rmk--block` **要保持可折行**（那里空间大，应显示完整句子）。 */
.rmk--cell > .rmk-line {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rmk-empty, .rmk--empty { color: var(--color-muted); }

/* 「还有 N 条 / 展开全文」：视觉上是个轻量文字按钮，不占地方但点得到 */
.rmk-more {
  margin-top: 3px; padding: 0;
  border: 0; background: none; cursor: pointer;
  font-size: var(--font-size-xs); font-family: inherit;
  color: var(--color-accent-text); text-decoration: none;
}
.rmk-more:hover { text-decoration: underline; }
.rmk-more:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; border-radius: 2px; }
.rmk-more-dot { color: var(--color-accent-text); }

/* ---- 重点高亮 ----
   ⚠️ `<mark>` 浏览器默认是「黄底黑字」，必须显式覆盖，否则与莫代尔色系冲突。
   只标三类「能拿去做事的」信息（详见 js/remark.js 的注释）：
     id    单号 → 要拿去查单，等宽 + 浅底 + 描边（像一枚可复制的标签）
     money 金额 → 要对账，沿用项目「价格=红」的既有语义（.price 同色）
     act   动作 → 退货/补发/拒绝这类结论词，警示色加粗，一眼看到"这单要不要处理"
   ---- */
.rmk-hl {
  background: none; color: inherit;      /* 先抹掉 <mark> 的默认黄底 */
  padding: 0 2px; border-radius: var(--radius-sm);
  font-weight: var(--font-weight-medium);
}
/* 单号：等宽字体，方便与订单号逐位核对 */
.rmk-hl--id {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.94em;                    /* 等宽字略宽，缩一点保持整行长度 */
  background: var(--color-surface-2);
  border: 1px solid var(--color-border-soft);
  color: var(--color-fg);
  letter-spacing: -0.01em;
}
/* 金额：与项目「价格红」一致 */
.rmk-hl--money { color: var(--color-price); font-weight: var(--font-weight-semibold); }
/* 动作词：警示色（不是错误，是"需要留意"） */
.rmk-hl--act { color: var(--color-warning-text); font-weight: var(--font-weight-semibold); }

/* ---- 备注弹窗：每句一行、行距舒展 ---- */
.rmk-modal__meta {
  margin-bottom: var(--space-3); padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-border-soft);
  font-size: var(--font-size-xs); color: var(--color-meta);
}
.rmk-modal .rmk--block { font-size: var(--font-size-base); }
.rmk-modal .rmk--block > .rmk-line + .rmk-line { margin-top: var(--space-3); }

/* ==========================================================================
   长文本单行省略（乐哥 2026-09-13「统一收敛行内省略号写法」）
   --------------------------------------------------------------------------
   背景：全站 15 处把 `overflow:hidden;text-overflow:ellipsis;white-space:nowrap`
   写成**行内 style**（商品名 / SKU / 订单号 / 地址 / 用户名），散落 8 个文件、重复 15 遍。
   目标统一成一处定义，行为不变（仍单行省略 + title 悬停看全）。

   ⚠️ 为什么**没有**套用 `.rmk`（备注组件）—— 这是本条的判断点：
     这 15 处全是**长文本字段**（单个长字符串），**没有一处是备注**（多句自然语言）。
     `.rmk` 会做「重点高亮」（单号/金额/动作词），套到商品名上会把
     「益畅(30袋)*3」「YY010107-000002」这类**规格数字误标成金额/单号** —— 反而更乱。
     所以这里抽的是「单行省略」工具类，与 `.rmk`（拆句+高亮）职责不同、各用其所。

   `.ell` 同时给 `min-width:0`：flex 子项若不设它，内容会把父级撑宽、ellipsis 不生效
   （项目里 5 处 flex 场景原本靠外层 `min-width:0;flex:1` 凑合，现在内层自己带上更稳）。
   ========================================================================== */
.ell {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* 直接省略一个 span/div 时它需要是块级才吃得住宽度 */
span.ell, div.ell { display: block; }
/* `td.ell`：在单元格上直接省略（不套内层 div 的场景）——限制在自身宽度内，不撑破表格 */
td.ell { max-width: 100%; }


/* ==========================================================================
   交互反馈补齐（按下 / 键盘可达）—— 2026-09-13，依据 ui-ux-pro-max 规范
   ---------------------------------------------------------------------------
   审计实测发现的缺口（全站范围，非个例）：
     ① `.icon-btn` **完全没有 :active 规则**（全站 83 个图标按钮）
        → 按下零反馈：点完不知道有没有生效，在表格里连点容易误操作。
     ② `.btn:hover` 与 `.btn:active` 背景同色（已在上方修掉）。
     ③ **15 处可点击表格行**只有 cursor:pointer，没有任何按下反馈。
   规范依据：
     · 优先级 2「Touch & Interaction」— press-feedback / state-clarity
     · 优先级 7「Animation」— 只用 transform/opacity（不动 width/height 以免重排）、
       时长落在 150–300ms（沿用项目 --motion-fast=150ms）、缩放幅度取细微的 0.94–1.05
   ⚠️ 按下底色用 `--color-gray-100`（#EEEEEE）——比 hover 的 surface-2(#FAFBFC) 深一档，
      莫代尔色系里没有 surface-3，直接用中性色阶，不新造 token。
   ⚠️ 行按下态必须落在 `td` 上：`tr` 的背景会被 `td` 覆盖，只写 tr 看不到效果。
   ========================================================================== */
.icon-btn:active:not(:disabled) {
  background: var(--color-gray-100);
  transform: scale(0.94);
}

/* 可点击行的按下反馈。
   ⚠️ 按下色必须**与 hover 同色系加深**：行 hover 是 `--color-primary-50`(#EDF4FE)，
      按下用 `--color-primary-100`(#DBE8FE)。**不能**用灰色 —— 悬停是淡蓝、按下变灰
      会产生色相跳变，看着像"状态丢了"（违反 state-clarity 的同色系递进原则）。
      这是本次实现时自己先写错、复核 token 后修正的一处。
   选择器同时列「已知 class」+「行内 cursor:pointer」兜底 ——
   后者是因为本项目 15 处可点击行**统一用行内 style 标记可点**（已核实），
   用属性兜底可覆盖未来新增的同惯例行；已知 class 列出便于 grep 定位。 */
.table tbody tr.c-row:active,
.table tbody tr.hs-row:active,
.table tbody tr.ip-row:active,
.table tbody tr.s-row:active,
.table tbody tr.so-row:active,
.table tbody tr.person-row:active,
.table tbody tr.group-row:active,
.table tbody tr.fe-group:active,
.table tbody tr[data-row]:active,
.table tbody tr[data-key]:active,
.table tbody tr[data-pkey]:active,
.table tbody tr[data-inf]:active,
.table tbody tr[data-id]:active,
.table tbody tr[data-day]:active,
.table tbody tr[style*="cursor:pointer"]:active {
  background: var(--color-primary-100);
}

/* 减弱动效：按下态的缩放属于"动效"，偏好减少动效时去掉（保留底色变化作反馈）。
   全局那段把 transition-duration 归零只能让过渡"瞬间完成"，**不会**取消 transform 本身，
   故这里显式重置。 */
@media (prefers-reduced-motion: reduce) {
  .btn:active:not(:disabled),
  .icon-btn:active:not(:disabled) {
    transform: none;
  }
}

/* ---- 占位隐藏（2026-09-18，乐哥「切 tab 工具组会跳」）----
   与 `display:none` 的区别：**保留布局空间**。
   工具组/页头按钮都是右对齐的，用 display:none 隐藏其中一项会让其余控件补位、
   整组横向跳动（实测 订单明细 105px）。visibility:hidden 位置一个像素不动，
   且天然不可点击/不可聚焦。用法：ui.js 的 UI.setKeepSpace(el, visible)。 */
.keep-space-hidden {
  visibility: hidden;
}

/* ---- 「新增」按钮定宽（2026-09-18，乐哥「切 tab 页头按钮会跳」）----
   兼职助播页两个 tab 下这个按钮的文案不同：
     「助播人员名单」tab → 新增兼职助播（实测宽 150px）
     「兼职主播直播场次」tab → 新增结算（实测宽 122px）
   页头按钮组是**右对齐**的 → 按钮变宽会把左边缘向左推 28px（实测）。
   直接给它最小宽度 = 较宽的那个，两种状态下宽度完全一致，位置一动不动。 */
#pta-add {
  min-width: 150px;
  justify-content: center;
}
