/* ==========================================================================
   达探 · 海外版 — 视觉 A 版（2026-09-16）
   只有**两套主题**：白天 = Stripe 风（浅色细腻）· 黑夜 = Linear 风（深色克制）。
   切换只换 token 值 —— 结构 / DOM / 数据逻辑一行不动（沿用 <html data-theme> 挂载）。
   token 分两层：① 基础原子（颜色 / 8pt 间距 / 字阶 / 圆角 / 阴影）
                  ② 语义别名（--gap-* / --fs-* / --sh-*，全站只引用这一层）
   间距节奏 8pt：4 / 8 / 12 / 16 / 24 / 32；字阶固定：12 / 14 / 16 / 20 / 22。
   正文 ≥13px（本轮统一落在 --fs-body = 14px）；弱阴影只有一档。
   ========================================================================== */
:root {
  /* ── ①-1 中性面（白天）────────────────────────────────────────────── */
  --bg: #ffffff;            /* 页面底 */
  --surface: #ffffff;       /* 面板 / 卡片 */
  --surface-2: #fafafb;     /* 次级面 / 悬停底 */
  --field: #f6f6f8;         /* 输入框底 */
  --text: #061b31;          /* 正文（对 #ffffff 17.4:1） */
  --muted: #4c5563;         /* 次要文字（对 #ffffff 7.5:1，仍 ≥AA） */
  --muted-strong: #2b3644;  /* 辅助小字（12.3:1） */
  --faint: #6b7280;         /* 最轻一档，但**仍 ≥AA**（对白 4.83:1）——
                               它被 .sm-k / .step-note / 未采集胶囊等承载真实标签，
                               旧值 #9aa1ad 只有 2.6:1，属于「灰到看不清」
                               ⚠ 只在 --surface(#fff 4.83:1) / --surface-2(#fafafb 4.75:1)
                               上使用。落到 --field(#f6f6f8) 只有 4.48:1，**低于 AA 4.5** ——
                               2026-09-26 实测确认当前无此用法，加注防止以后踩。 */
  --border: #e7e7ee;        /* 分隔线 */
  --border-strong: #d6d7e0;

  /* ── ①-2 强调色：**全站只此 1 个色族**（白天 #533afd）────────────── */
  --accent: #533afd;
  --accent-strong: #4029d8;      /* hover / active 一档（同色族，不新增第二个强调色） */
  /* 放在 --accent **实底**上的文字色。深色下 --accent 是浅紫(#b3a9ff)，
     白字只有 2.09:1 → 必须换深墨。为什么加 token 而不是逐条改：
     全站 12 条规则都在"accent 实底 + 硬编码 #fff"这同一个模式上（G10v 实测）。 */
  --accent-ink: #ffffff;         /* 白 on #533afd = 6.19:1 */
  /* 强调**实底上的小胶囊/徽标**底色。白字要 ≥4.5:1 就必须比实底更暗。
     白天 --accent-ink 是白 → 用黑叠加；黑夜 --accent-ink 是深墨 → 用白叠加。
     G10ac 实测：`.tab.active .tab-count` 原用 rgba(255,255,255,.24)，白天合成为
     rgb(124,105,253)，白字只有 3.97:1（12px 小字需 4.5）。 */
  --chip-on-accent: rgba(0, 0, 0, .26);
  --accent-2: #7a68fd;           /* 渐变/图表用的浅一档，同色族 */
  --accent-rgb: 83, 58, 253;
  --accent-weak: rgba(83, 58, 253, .08);
  /* 静态强调描边（1px 边框）：徽标 / 胶囊 / 页签 / 开关的强调边。
     收敛前此处有 .38/.4/.45/.5 四个手写 alpha（同一语义 4 个值 = 不一致）。
     取原四值中位数 .425 → .42；alpha 最大变动 .08（1px 线，肉眼不可辨）。
     走 var(--accent-rgb)：黑夜自动变 --accent-strong 色族，无需在暗色块里再定义。 */
  --accent-line: rgba(var(--accent-rgb), .42);
  --grad: linear-gradient(135deg, var(--accent), var(--accent-2));

  /* ── ①-3 语义色：低饱和底（HSL 饱和度 ≤30%）+ 同色系文字 ──────────── */
  --ok: #296b4a;  --ok-bg: #f2f8f5;  --ok-bd: #c9e3d6;
  --err: #6b2932; --err-bg: #f8f2f3; --err-bd: #e3c9cd;
  --warn: #6b4f29;--warn-bg: #f8f5f2;--warn-bd: #e3d8c9;
  --star: #b7791f;
  /* 浮层提示（toast）：白天用墨底浅字（与白底拉开），黑夜用抬一档的面 —— 两个主题都「盖得住」 */
  --toast-bg: #061b31;  --toast-tx: #f7f8f8;  --toast-bd: rgba(255, 255, 255, .10);
  /* 顶栏磨砂底（backdrop-filter 之上的半透明面）与抽屉遮罩 —— 原为字面量，收进 token */
  --topbar-bg: rgba(255, 255, 255, .82);
  --mask: rgba(12, 15, 20, .38);

  /* ── ①-4 圆角 / 阴影 / 动效 ──────────────────────────────────────── */
  --r: 6px;  --r-sm: 4px;  --r-lg: 8px;  --r-card: 6px;
  --sh-weak: 0 2px 8px rgb(15 23 42 / .08);   /* **唯一的弱阴影档** */
  --sh-1: var(--sh-weak);
  --sh-2: var(--sh-weak);
  /* 浮层阴影（抽屉/弹层）—— 不是「弱阴影档」，是叠加在 mask 之上的层级信号 */
  --sh-3: 0 20px 48px rgb(15 23 42 / .16), var(--sh-weak);
  --ring: 0 0 0 3px rgba(var(--accent-rgb), .18);
  /* 强调色控件的「静止态微弱投影」—— 收敛前是 .28/.3/.35 三个手写 alpha + 3 种几何（同一语义）。
     取 alpha 中位数 .3、几何众数 0 1px 3px，收成**一个** token（不再三档并列）。
     视觉影响：.tab.active 由 .28 / 4px 模糊 → .3 / 3px（Δalpha .02、模糊 −1px，肉眼不可辨）；
     .theme-chip.active 不是「投影」而是「描边」，见下一行；其余站点字节级不变。 */
  --sh-accent: 0 1px 3px rgba(var(--accent-rgb), .3);
  /* 「选中态强调描边」（inset 1px 环）—— 与上面的「投影」不是同一语义（描边 vs 抬升），
     故不共用签名；也**不新增 alpha**：直接复用 09-18 那轮建的静态强调描边 --accent-line(.42)。
     视觉影响：.theme-chip.active 的 .35 → .42（1px 线，Δ.07，与 P0 那批 19 处同口径）。 */
  --sh-accent-ring: inset 0 0 0 1px var(--accent-line);
  /* 控件专用面（暗色统一覆盖） */
  --track: #e4e4ec;           /* 滑杆轨道未填充段 */
  --switch-off: #d6d7e0;      /* 开关关态轨道 */
  --zebra: rgba(6, 27, 49, .018);  /* 明细表格斑马行（对比度 ≤2%，不靠斑马纹看行） */
  --thumb: #d6d7e0;  --thumb-hover: #c2c3d0;  /* 滚动条 */
  --t-fast: .15s;
  --ease: cubic-bezier(.2, .6, .3, 1);

  /* ── ①-5 间距节奏 8pt + 语义别名（旧值全部归一，旧变量名保留）──────── */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px;  --sp-4: 16px;  --sp-5: 24px;  --sp-6: 32px;
  --gap-page: var(--sp-4);    /* 页面区块之间 */
  --gap-block: var(--sp-3);   /* 卡片 / 表格行之间 */
  --panel-gap: var(--sp-3);   /* 抽屉内大块间距 */
  /* 分组卡片内纵向节奏：2026-09-18 设计管线出稿由 8px 收到 12px。
     实测：区块标题 → 子标签组 = 8px，子标签组 → 卡片 = 8px（.tto-subgroup gap），
     父子两级**同值** → 层级无对比，读者分不出「区块」和「区块内的块」。
     改 12px 后 父:子 = 12:8 = 1.5×，两级可辨。12px = --sp-3，stripe / linear 刻度内。 */
  --sec-gap: var(--sp-3);     /* 分组卡片内纵向节奏 */
  --sec-pad: var(--sp-3);     /* 分组卡片内边距 */
  --row-gap: var(--sp-2);     /* 字段行之间 */

  /* ── ①-6 字阶 12 / 14 / 16 / 20 / 22 + 语义别名（旧变量名保留）────── */
  --fs-12: 12px;  --fs-14: 14px;  --fs-16: 16px;  --fs-20: 20px;  --fs-22: 22px;
  --fs-label: var(--fs-12);   /* 字段标签 / 徽标（下线 12px） */
  --fs-body: var(--fs-14);    /* 正文（硬线 ≥13px） */
  --fs-lead: var(--fs-16);    /* 强调正文 / 卡片主数值 */
  --fs-h3: var(--fs-20);      /* 区块标题 */
  --fs-h1: var(--fs-22);      /* 页面主数值 */
  --fs-k: var(--fs-12);       /* 旧名：字段标签 */
  --fs-v: var(--fs-14);       /* 旧名：字段值 */
  --fs-value: var(--fs-20);   /* 旧名：卡片主数值 */
  --fs-tab: var(--fs-14);     /* 页签文字 */
  --tab-gap: var(--sp-4);     /* 页签间距（6 个页签在 520px 抽屉里必须全部可见） */
  --lh-body: 1.55;            /* 正文行高 */

  /* 页签指示器：强调色（A 版「全站只留 1 个强调色」，旧 TTO 青绿 --tab-ink 作废） */
  --tab-ink: var(--accent);
  --tab-ink-w: 4px;           /* 当前页签底线 4px */

  /* G10i 效果趋势柱状图（数据可视化专用色板，不参与「1 个强调色」约束） */
  --tto-chart-brand: #dfcce0;      /* 品牌内容 */
  --tto-chart-nonbrand: #8987f1;   /* 非品牌内容 */
  --tto-chart-boosted: #469794;    /* 通过付费流量提升 */
  --tto-chart-grid: var(--border);
  --tto-chart-axis: var(--border-strong);

  /* 受众环图色板（数据可视化分类色：8 片必须互相可辨，第 1 片用强调色） */
  --donut-0: var(--accent);
  --donut-1: #469794;
  --donut-2: #8b83f0;
  --donut-3: #b08968;
  --donut-4: #d8b98a;
  --donut-5: #5aa9d6;
  --donut-6: #a78bfa;
  --donut-7: #9ca3af;
  --donut-track: #f0f1f4;

  /* 徽标（品类 / 国家 / 来源 / 状态）：低饱和底（HSL S≤30%）+ 1px 同色系描边 */
  --badge-rose-bg: #f8f2f3;    --badge-rose-bd: #e6d1d6;    --badge-rose-tx: #762d3f;
  --badge-violet-bg: #f4f2f8;  --badge-violet-bd: #dad1e6;  --badge-violet-tx: #4b2d76;
  --badge-amber-bg: #f8f5f2;   --badge-amber-bd: #e6ddd1;   --badge-amber-tx: #76582d;
  --badge-cyan-bg: #f2f7f8;    --badge-cyan-bd: #d1e2e6;    --badge-cyan-tx: #2d6a76;
  --badge-emerald-bg: #f2f8f5; --badge-emerald-bd: #d1e6dd; --badge-emerald-tx: #2d7658;
  --badge-slate-bg: #f2f4f8;   --badge-slate-bd: #d1d8e6;   --badge-slate-tx: #2d4576;
}

/* ==========================================================================
   黑夜档 = Linear 风（data-theme="dark" 挂在 <html>，htmx 局部刷新不换 html → 不丢）。
   只覆盖 token 值（含间距/字阶：深色**只换色不换密度**）。
   ========================================================================== */
[data-theme="dark"] {
  --bg: #0b0c0e;            /* 页面底 */
  --surface: #121317;       /* 面板 */
  --surface-2: #16181d;     /* 次级面 / 悬停底 */
  --field: #14161a;         /* 输入框底 */
  --text: #f7f8f8;          /* 正文（对 --surface 17.5:1） */
  --muted: #8a8f98;         /* 次要文字（对 --surface 5.7:1） */
  --muted-strong: #a8adb8;  /* 辅助小字（8.3:1） */
  --faint: #7e838c;         /* 最轻一档，仍 ≥AA（对面板 4.87:1 / 对底 5.14:1） */
  --border: #1f2024;        /* 分隔线 */
  --border-strong: #2a2c32;

  --accent: #b3a9ff;            /* 黑夜强调色（对 --surface 8.9:1） */
  --accent-strong: #c9c1ff;
  --accent-2: #c9c1ff;
  --accent-rgb: 179, 169, 255;
  --accent-weak: rgba(179, 169, 255, .12);
  /* 深色下 --accent 是**浅紫**，白字落在它上面只有 2.09:1（G10v 实测四处：
     平台页签当前档 / 收藏选中按钮 ×2 / FAB 角标）。深墨 on #b3a9ff = 9.36:1。 */
  --accent-ink: #0b0c0e;
  --chip-on-accent: rgba(255, 255, 255, .24);
  --grad: linear-gradient(135deg, var(--accent), var(--accent-2));

  --ok: #a1d9bd;  --ok-bg: #23342b;  --ok-bd: #3c5d4d;
  --err: #d9a1a8; --err-bg: #342325; --err-bd: #5d3c40;
  --warn: #d9c1a1;--warn-bg: #342d23;--warn-bd: #5d4f3c;
  --star: #d9c1a1;
  --toast-bg: var(--surface-2); --toast-tx: var(--text); --toast-bd: var(--border-strong);
  --topbar-bg: rgba(11, 12, 14, .78);   /* 黑夜顶栏磨砂底 */

  --sh-weak: 0 2px 8px rgb(0 0 0 / .5);   /* **唯一的弱阴影档**（黑夜） */
  --sh-1: var(--sh-weak);
  --sh-2: var(--sh-weak);
  --sh-3: 0 20px 48px rgb(0 0 0 / .62), var(--sh-weak);
  --ring: 0 0 0 3px rgba(var(--accent-rgb), .26);

  --track: #26282e;
  --switch-off: #33363d;
  --zebra: rgba(247, 248, 248, .018);
  --thumb: #33363d;  --thumb-hover: #43464e;

  /* 数据可视化色板（暗底加亮，保证与底色对比够、8 片互相可辨） */
  --tto-chart-brand: #cdbcd6;
  --tto-chart-nonbrand: #8f8df5;
  --tto-chart-boosted: #4faeaa;
  --donut-1: #4faeaa;
  --donut-2: #a7a4ff;
  --donut-3: #d2a98c;
  --donut-4: #e3c79b;
  --donut-5: #7cc0e8;
  --donut-6: #bda5ff;
  --donut-7: #8b93a3;
  --donut-track: #1f2024;

  /* 徽标（暗底低饱和，HSL S≤20%） */
  --badge-rose-bg: #342327;    --badge-rose-bd: #593b43;    --badge-rose-tx: #ddb0bc;
  --badge-violet-bg: #2a2334;  --badge-violet-bd: #473b59;  --badge-violet-tx: #c3b0dd;
  --badge-amber-bg: #342d23;   --badge-amber-bd: #594c3b;   --badge-amber-tx: #ddcbb0;
  --badge-cyan-bg: #233134;    --badge-cyan-bd: #3b5459;    --badge-cyan-tx: #b0d6dd;
  --badge-emerald-bg: #23342d; --badge-emerald-bd: #3b594c; --badge-emerald-tx: #b0ddcb;
  --badge-slate-bg: #232834;   --badge-slate-bd: #3b4559;   --badge-slate-tx: #b0bfdd;
}


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

html, body {
  min-height: 100%;
  /* A 版：底＝实色 #ffffff（白天）/ #0b0c0e（黑夜）。
     旧的品牌径向渐变已去掉 —— 渐变会让「正文/背景对比度」随位置漂移，无法逐像素复核。 */
  background: var(--bg);
  color: var(--text);
  /* G10n §6：中文字体栈**不引外部字体**（生产离线可用），后面几个只是同义回退 */
  font-family: -apple-system, "PingFang SC", "Microsoft YaHei", system-ui,
    BlinkMacSystemFont, "Hiragino Sans GB", "Noto Sans SC", "Segoe UI", sans-serif;
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.hidden { display: none !important; }

button { cursor: pointer; font-family: inherit; }
input, select { font-family: inherit; font-size: inherit; color: inherit; }

/* 细滚动条（克制） */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--thumb);
  border-radius: 8px;
  border: 2px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--thumb-hover); background-clip: content-box; }

/* ---------- 通用控件（btn / 输入 / select 共形） ---------- */
.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast),
    box-shadow var(--t-fast), transform var(--t-fast);
}
.btn-ghost:hover:not(:disabled) {
  color: var(--accent);
  border-color: rgba(var(--accent-rgb), .55);
  background: var(--accent-weak);
}
.btn-ghost:active:not(:disabled) { transform: translateY(1px); }
.btn-ghost:focus-visible { outline: none; box-shadow: var(--ring); }
.btn-ghost:disabled { opacity: .4; cursor: default; }
.btn-ghost .badge-count { margin-left: 2px; }

.btn-mini {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font-size: 12px;
  white-space: nowrap;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.btn-mini:hover { border-color: rgba(var(--accent-rgb), .55); color: var(--accent); background: var(--accent-weak); }
/* 特异性**不能**只用 0,2,0：`.btn-mini.btn-primary`（:280）也是 0,2,0 且写在**后面**
   并设了 `box-shadow: var(--sh-accent)` → 主操作按钮的焦点环被整条压掉。
   2026-09-27 g10ab 视图覆盖率扫描实测：人工核对 188 处、商务路由 8、报价单 4、
   飞书导入 4，全部 `:focus-visible` 命中（fv=True）而计算样式零变化。
   `.btn-mini.btn-ghost`（:288）没设 box-shadow，所以不受影响 —— 这解释了为什么
   只有 btn-primary 中招。g10w 只扫列表页+达人抽屉，这些视图从未被覆盖，故一直没被发现。
   与批次 19 的 `.list-ops .btn-fav-sel:hover` 是同一类：同权重 + 源码顺序。 */
.btn-mini:focus-visible,
.btn-mini.btn-primary:focus-visible { outline: none; box-shadow: var(--ring); }
.btn-mini.btn-primary {
  border: 1px solid transparent;
  color: var(--accent-ink);
  font-weight: 600;
  background: var(--accent);
  box-shadow: var(--sh-accent);
}
.btn-mini.btn-primary:hover { color: var(--accent-ink); background: var(--accent-strong); border-color: var(--accent-strong); }
.btn-mini.btn-ghost { color: var(--muted); background: transparent; }
.btn-mini.btn-ghost:hover { color: var(--accent); background: var(--accent-weak); border-color: var(--border-strong); }
.btn-accent { color: var(--accent); border-color: var(--accent-line); background: var(--accent-weak); }

/* 行内图标 / SVG 星形（默认 outline，.filled = 实心） */
.btn-ico { width: 15px; height: 15px; flex-shrink: 0; }
/* G10n：四档主题切换器（简洁白/暖白/灰蓝/深色）+ 保留 🌙/☀️ 快捷深浅切换。
   chips 是一排按钮：键盘可达、aria-pressed 跟当前档；窄屏自动收起为图标位不换行。 */
.theme-switch {
  display: inline-flex; align-items: center; gap: 2px; flex: 0 0 auto;
  padding: 2px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-2);
}
.theme-chip {
  border: 0; background: transparent; color: var(--muted);
  font-size: 12px; line-height: 1; padding: 4px 8px; border-radius: 8px;
  white-space: nowrap; transition: background var(--t-fast), color var(--t-fast);
  /* G10v 实测：`padding:4px 8px` + `line-height:1` + 12px 字 → **40×20**，
     高度差 4px 不达 WCAG 2.2 SC 2.5.8（≥24×24）。只补 min-height，
     **不改 padding 值** —— 4px/8px 都在 `--sp` 刻度上，改 6px 会引入非刻度值。 */
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 24px;
}
.theme-chip:hover { color: var(--text); background: var(--surface); }
.theme-chip.active {
  color: var(--accent); background: var(--accent-weak); font-weight: 600;
  box-shadow: var(--sh-accent-ring);
}
/* G10w 实测（2026-09-26）：焦点环必须排在 `.active` **之后** ——
   `.theme-chip:focus-visible` 与 `.theme-chip.active` 特异性相同（各 2 个 class 级），
   CSS 靠**源序**决胜；原来 focus 在前，`.active` 的 box-shadow 把它整条覆盖 →
   键盘 Tab 到「当前选中」的主题 chip 时**完全没有焦点提示**（WCAG 2.4.7，AA）。
   全仓 38 条 `:focus-visible` 已穷举核对，只有此处与 `.tab` 两例。 */
.theme-chip:focus-visible { outline: none; box-shadow: var(--ring); }
@media (max-width: 720px) {
  /* 窄屏只留色点：4 个文字 chip 会把顶栏挤爆 */
  .theme-chip { font-size: 0; padding: 4px 8px; }
  .theme-chip::before {
    content: ""; display: block; width: 10px; height: 10px; border-radius: 50%;
    background: currentColor; opacity: .75;
  }
  .theme-chip.active::before { opacity: 1; }
}
/* 主题切换按钮：icon-only 胶囊；🌙/☀️ 由 JS 依 data-theme 切 .hidden */
.theme-toggle { padding: 8px 8px; line-height: 0; }
.theme-toggle svg { display: block; }
svg.star-ic { display: block; }
svg.star-ic path { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linejoin: round; }
svg.star-ic.filled path { fill: currentColor; stroke: currentColor; stroke-width: 1; }
/* ghost 轻底按钮：全选/清除 */
.btn-soft { background: var(--field); border-color: var(--border); color: var(--muted-strong); }
.btn-soft:hover { color: var(--accent); border-color: var(--accent-line); background: var(--surface); }

/* 通用输入面：search / number / select / lang */
.search-input, .select, .nf-num, .lang-select, #login-password,
.fav-product, .quote-customer, .route-row input, .rrow-ops input,
.import-form .import-ref, .import-form .import-textarea {
  border: 1px solid var(--border);
  background: var(--field);
  color: var(--text);
  outline: none;
  transition: border-color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}
.search-input:hover, .select:hover, .nf-num:hover, .lang-select:hover,
.fav-product:hover, .quote-customer:hover, .route-row input:hover, .rrow-ops input:hover,
.import-form .import-ref:hover { border-color: var(--border-strong); }
.search-input:focus, .select:focus, .nf-num:focus, .lang-select:focus,
#login-password:focus, .fav-product:focus, .quote-customer:focus,
.route-row input:focus, .rrow-ops input:focus,
.import-form .import-ref:focus, .import-form .import-textarea:focus {
  border-color: var(--accent);
  background: var(--surface);
  box-shadow: var(--ring);
}
.search-input { border-radius: 8px; }
.select { border-radius: 8px; cursor: pointer; }
.lang-select { border-radius: 8px; padding: 8px 12px; font-size: 12px; cursor: pointer; color: var(--muted); }
.lang-select:hover, .lang-select:focus { color: var(--text); border-color: var(--border-strong); }

/* ---------- 登录 ---------- */
.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.login-card {
  width: 100%;
  max-width: 396px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 32px 32px 32px;
  text-align: center;
  box-shadow: var(--sh-3);
}
.login-logo { font-size: 22px; margin-bottom: 12px; text-align: center; }
.login-logo-img { height: 64px; width: auto; display: inline-block; filter: none; box-shadow: none; }
.login-title {
  font-size: 22px;
  font-weight: 700;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.login-sub { color: var(--muted); font-size: 14px; margin: 8px 0 24px; }
#login-form { display: flex; flex-direction: column; gap: 12px; }
#login-username,
#chpw-form input,
#login-password {
  padding: 12px 16px;
  border-radius: var(--r-sm);
  font-size: 14px;
  background: var(--field);
}
#login-btn {
  padding: 12px;
  border: none;
  border-radius: var(--r-sm);
  font-size: 14px;
  font-weight: 600;
  color: var(--accent-ink);
  background: var(--accent);
  box-shadow: var(--sh-accent);
  transition: opacity var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}
#login-btn:hover:not(:disabled) { box-shadow: 0 6px 18px rgba(var(--accent-rgb), .32); transform: translateY(-1px); }
#login-btn:active:not(:disabled) { transform: translateY(0); }
#login-btn:disabled { opacity: .6; cursor: default; box-shadow: none; transform: none; }
.login-error { color: var(--err); font-size: 14px; margin-top: 12px; min-height: 18px; }
.login-admin-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--muted);
  font-size: 12px;
  cursor: pointer;
  user-select: none;
}
.login-admin-wrap input { accent-color: var(--accent); width: 15px; height: 15px; cursor: pointer; }
.login-lang { margin-top: 16px; }

/* ---------- t10：个人账号（用户标识 / 改密弹层 / 一次性密码展示） ---------- */
.user-chip {
  color: var(--muted);
  font-size: 13px;
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chpw-wrap {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, .45);
}
.chpw-card { text-align: left; }
.chpw-title { font-size: 17px; font-weight: 700; margin: 0 0 16px; text-align: center; }
#chpw-form { display: flex; flex-direction: column; gap: 12px; }
#chpw-submit {
  padding: 12px;
  border: none;
  border-radius: var(--r-sm);
  font-size: 14px;
  font-weight: 600;
  color: var(--accent-ink);
  background: var(--accent);
}
#chpw-submit:disabled { opacity: .6; cursor: default; }
/* 新建/重置账号的一次性明文密码：醒目框 + 等宽字，只可复制不可再查 */
.pw-reveal {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px dashed var(--accent);
  border-radius: var(--r-sm);
  background: var(--field);
}
.pw-reveal code { font-size: 15px; font-weight: 700; letter-spacing: .5px; user-select: all; }
.acct-form { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }
.acct-form input, .acct-form select {
  padding: 8px 10px;
  border-radius: var(--r-sm);
  font-size: 13px;
  background: var(--field);
}
.acct-form input { min-width: 140px; }
.acct-ops { display: flex; gap: 6px; flex-wrap: wrap; }
.acct-ops select { max-width: 120px; }

/* ---------- 顶栏 ---------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  /* flex-wrap 必须在**基线**上：原来只有 `#main-view .topbar`（:626）加了 wrap，
     于是另外 11 个视图的顶栏内容挤成一行 —— g10ac 实测 390px 视口下
     `div#xxx-view` 的 scrollWidth = 782（≈2× 视口），整个视图横向溢出 392px。
     g10x 的重排扫描只覆盖主视图 + 抽屉，所以这个缺陷一直没被发现。 */
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  background: var(--topbar-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.brand { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
/* 主 brand 放真实 logo 图：强制无背景底块（!important 防缓存/旧规则覆盖；用户 2026-09-09：不要渐变圆角底） */
.brand-logo-zh { background: transparent !important; border-radius: 0 !important; width: auto !important; height: 34px !important; padding: 0 !important; box-shadow: none !important; color: inherit !important; }
.brand-logo-zh .brand-img { height: 34px; width: auto; max-width: 220px; display: block; filter: none; box-shadow: none; }
.brand-icon {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  background: var(--grad);
  color: var(--accent-ink);
  font-size: 16px;
  box-shadow: 0 2px 6px rgba(var(--accent-rgb), .26);
  flex-shrink: 0;
}
.brand-name { font-weight: 700; font-size: 16px; white-space: nowrap; letter-spacing: .01em; }
.search-input { padding: 8px 16px; font-size: 14px; }
/* 收藏夹顶栏的客户名输入框：品牌左、操作右 */
#fav-view .topbar .search-input { flex: 1 1 200px; max-width: 380px; }
#fav-view .topbar .btn-accent { margin-left: auto; }

/* ---------- 登录态外的公共容器 ---------- */
.content { width: 100%; max-width: 1160px; margin: 0 auto; padding: 16px 24px 32px; }

/* 状态 / 加载 / 错误 */
.status { text-align: center; color: var(--muted); padding: 32px 16px; font-size: 14px; }
.status.error { color: var(--err); font-weight: 500; }
.htmx-ind { display: none; }
.htmx-ind.htmx-request {
  display: inline-flex;
  align-items: center;
  position: fixed;
  top: 66px;
  left: 50%;
  transform: translateX(-50%);
  padding: 8px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--sh-2);
  color: var(--muted);
  font-size: 14px;
  z-index: 60;
}
.htmx-ind.htmx-request::before {
  content: "";
  width: 12px;
  height: 12px;
  margin-right: 8px;
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- 筛选控件（base，平台 tabs / chips / switch） ---------- */
.platform-tabs { display: flex; gap: 8px; flex-wrap: wrap; }
.tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--muted);
  font-size: 14px;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast),
    box-shadow var(--t-fast);
}
.tab img { width: 16px; height: 16px; border-radius: 4px; }
.tab:hover { color: var(--text); border-color: rgba(var(--accent-rgb), .55); }
.tab.active {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: var(--sh-accent);
}
/* 焦点环必须排在 `.tab.active` 之后 —— 原因同 `.theme-chip`（特异性相同、源序决胜）。 */
.tab:focus-visible { outline: none; box-shadow: var(--ring); }
/* `:hover` 的底色来自 `.tab.active`（本规则自己不写 background），所以它同样是
   「accent 实底 + 文字」—— 批次 9 按「本块内有没有 background」划作用域时漏掉了它，
   深色下白 on #b3a9ff 只有 2.09:1。改用 --accent-ink。 */
.tab.active:hover { color: var(--accent-ink); }

.chip-group { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
/* 粉丝档位行：全勾选也不换行（单位在标题「粉丝（万）」，档位为纯数字） */
.nf-bands { flex-wrap: nowrap !important; }
.nf-bands .chip { flex: 1 1 0; min-width: 0; padding: 8px 16px; justify-content: center; text-align: center; }
.nf-bands .chip-text { font-size: 12px; letter-spacing: 0; line-height: 1.2; white-space: nowrap; }
/* ── 换行纪律（TASK-20260921-107 缺陷第 3 项）─────────────────────────────
   根因：不折行容器（`.fg-category .chip-group`，见下方 `flex-wrap: nowrap`）里 chip
   仍是 flex item，默认 `flex-shrink: 1`；被压扁后文案按**中文逐字**折行 →
   9 个品类 chip 全部两行、chip 高 41px（设计基线 32px）、整排被撑到 65px。
   处置与上方「粉丝档位」那排同构：容器保持横滑（它本就有 `overflow-x: auto`），
   chip **不收缩**、文案**不折行** —— 压缩压力回到容器的横滑，而不是压字。
   范围是 `#filter-topbar` 下**所有** `.chip-group`（不只品类那排）：「更多指标」里
   每一个 chip 组都是同一个坑，只是宽屏下没触发；`.nf-bands` 已有自己的等宽规则
   （`flex: 1 1 0` + nowrap），显式排除，别把它改掉。 */
#filter-topbar .chip-group:not(.nf-bands) > .chip { flex: 0 0 auto; }
#filter-topbar .chip-text { white-space: nowrap; }
.chip { cursor: pointer; user-select: none; }
.chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip-text {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  font-size: 12px;
  line-height: 1.3;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast),
    box-shadow var(--t-fast);
}
.chip:hover .chip-text { color: var(--text); border-color: var(--border-strong); }
.chip input:focus-visible + .chip-text { outline: none; box-shadow: var(--ring); }
.chip.active .chip-text,
/* 静态档位 chips（粉丝/报价，无 OOB 回显）勾选高亮 —— :checked 同后端烘焙 .active 视觉 */
.chip input:checked + .chip-text {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 500;
  box-shadow: 0 1px 4px rgba(var(--accent-rgb), .24);
}
.chip.active .chip-text::before,
.chip input:checked + .chip-text::before { content: "✓"; font-size: 12px; line-height: 1; }

.switch-wrap { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
.switch-wrap input { display: none; }
.switch {
  width: 38px;
  height: 22px;
  border-radius: 8px;
  background: var(--switch-off);
  position: relative;
  transition: background var(--t-fast);
  flex-shrink: 0;
}
.switch::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--sh-weak);          /* A 版：唯一弱阴影档 */
  transition: transform var(--t-fast) var(--ease);
}
.switch-wrap input:checked + .switch { background: var(--accent); }
.switch-wrap input:checked + .switch::after { transform: translateX(16px); }
.switch-wrap input:focus-visible + .switch { box-shadow: var(--ring); }
.switch-label { font-size: 14px; color: var(--text); }

/* ==========================================================================
   主视图：固定一屏高，顶栏/面板不滚，仅内容内部滚动。
   左筛选面板 + 右列表区 = 两张悬浮白卡（浅灰底 + 圆角 + 细边 + 极浅阴影）。
   ========================================================================== */
#main-view {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
#main-view .topbar { gap: 8px; flex-wrap: wrap; }
#main-view .topbar > .btn-ghost:first-of-type { margin-left: auto; }
#main-view .main-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: stretch;
  gap: 16px;
  padding: 16px;
  overflow: hidden;
}

/* 左筛选面板：卡片化白面 */
.filter-panel {
  flex: 0 0 292px;
  width: 292px;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: var(--sh-1);
  overflow: hidden;
}
.fp-head {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 12px 8px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
/* 主行分组视觉分隔（搜索 | 平台 | 品类 | ops） */
.fp-head .f-cell + .f-cell {
  border-left: 1px solid var(--border);
  padding-left: 12px;
}
.fp-head .f-cell { min-width: 0; }
.fp-title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--text);
  line-height: 1.3;
}
.fp-title .fp-ico { color: var(--accent); width: 14px; height: 14px; }
.fp-toggle { display: none; padding: 4px 12px; font-size: 14px; line-height: 1; }
.filter-scroll {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 8px 12px 8px;
  background: var(--surface);
}

#filter-panel .filter-row {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 0;
}
/* 普通区块（非折叠）：标题在控件上方，紧凑纵列 */
.f-group { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.f-title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
  letter-spacing: .02em;
  line-height: 1.3;
}
/* 折叠区块（details.fg）：标题行 = summary，点击折叠；内容包在 .fg-body */
.f-group.fg { display: block; }
.fg > .f-title {
  cursor: pointer;
  list-style: none;
  -webkit-appearance: none;
  appearance: none;
  user-select: none;
  color: var(--muted-strong);
  transition: color var(--t-fast);
}
.fg > .f-title::-webkit-details-marker,
.fg > .f-title::marker { display: none; }
.fg > .f-title:hover { color: var(--accent); }
.fg-mark {
  width: 0;
  height: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 5px solid var(--faint);
  flex-shrink: 0;
  transition: transform var(--t-fast) var(--ease), border-color var(--t-fast);
}
.fg > .f-title:hover .fg-mark { border-left-color: var(--accent); }
.fg[open] > .f-title .fg-mark { transform: rotate(90deg); }
.fg-body {
  margin-top: 4px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
#filter-panel .platform-tabs { gap: 4px; }
#filter-panel .platform-tabs .tab { padding: 4px 12px; font-size: 12px; }
/* 平台 tab 只留 logo（用户 2026-09-09：放不下文字） */
#filter-panel .platform-tabs .tab.logo-only { padding: 3px; }
#filter-panel .platform-tabs .tab.logo-only img { width: 20px; height: 20px; display: block; margin: 0; border-radius: 4px; }
#filter-panel .chip-group { gap: 4px; }
#filter-panel .chip-text { padding: 4px 8px; font-size: 12px; }
#filter-panel .search-input { width: 100%; max-width: none; padding: 8px 12px; font-size: 14px; background: var(--field); }
#filter-panel .select { width: 100%; max-width: none; padding: 8px 12px; font-size: 14px; }
/* 高级折叠组内嵌子块：CPM/排序 是独立 .f-group 小节，块间留 8px */
#filter-panel .fg-more .fg-body { gap: 8px; }
#filter-panel .fg-more .fg-body > .f-group { gap: 8px; }
#filter-panel .fg-more .f-title { font-size: 12px; }
.f-switch { flex-direction: row; align-items: center; justify-content: flex-start; gap: 8px; padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2); }
.f-switch .switch-label { flex: 1; color: var(--text); font-size: 12px; }
.f-switch .switch { margin-left: auto; }
/* 筛选面板收尾操作行：独立于滚动区的置底条，始终可见（重置按钮 + 提示说明） */
.filter-foot {
  flex-shrink: 0;
  padding: 8px 12px 8px;
  border-top: 1px solid var(--border);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.filter-foot .reset-filter { width: 100%; justify-content: center; padding: 8px 12px; }
.filter-hint {
  font-size: 12px;
  color: var(--muted);
  text-align: center;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
}

/* 数值筛选：双端滑杆（自定义轨道/拇指）+ min/max 输入 + 当前值标签 */
.nf-inputs { display: flex; align-items: center; gap: 8px; }
.nf-inputs .nf-num {
  flex: 1;
  min-width: 0;
  width: 0;
  padding: 8px 8px;
  border-radius: var(--r-sm);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.nf-inputs .nf-num::-webkit-outer-spin-button,
.nf-inputs .nf-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.nf-inputs .nf-num { -moz-appearance: textfield; appearance: textfield; }
.nf-inputs .dash { flex-shrink: 0; color: var(--faint); }
/* 双端滑杆合并单轨：两根 range 绝对重叠，thumb 各自可拖，轨道整行禁指针
   （fill 渐变仍由 app.js paintRange 逐根绘制，视觉 = 0→右拇指区间高亮） */
.nf-ranges {
  position: relative;
  height: 22px;
}
.nf-ranges .nf-range {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 22px;
  margin: 0;
  background: transparent;
  pointer-events: none;
  --fill: 0%;
}
/* 层级：min(下限) thumb 必须在上层可见可拖；max 在下层画区间渐变轨道。
   min 轨道已透明 → 上移不遮视觉，只把 min thumb 提到 max 轨道之上（修左 thumb 被盖） */
.nf-ranges .nf-range:first-child { z-index: 2; }
.nf-ranges .nf-range:last-child  { z-index: 1; }
.nf-ranges .nf-range:focus { outline: none; }
.nf-ranges .nf-range::-webkit-slider-thumb { pointer-events: auto; cursor: grab; }
.nf-ranges .nf-range::-webkit-slider-thumb:active { cursor: grabbing; }
.nf-ranges .nf-range::-moz-range-thumb { pointer-events: auto; cursor: grab; }
.nf-ranges .nf-range:first-child::-webkit-slider-runnable-track {
  background: transparent;  /* min 根只露 thumb，区间视觉由 max 根统一画（防双 fill 打架） */
}
.nf-range::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 8px;
  background: linear-gradient(to right,
    var(--track) 0, var(--track) var(--fill-from, 0%),
    var(--accent) var(--fill-from, 0%), var(--accent) var(--fill-to, 100%),
    var(--track) var(--fill-to, 100%));
}
.nf-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  margin-top: -5.4px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--accent);
  box-shadow: var(--sh-weak);          /* A 版：唯一弱阴影档 */
  transition: transform var(--t-fast), box-shadow var(--t-fast);
}
.nf-range::-moz-range-track { height: 4px; border-radius: 8px; background: var(--track); }
.nf-range::-moz-range-progress { height: 4px; border-radius: 8px; background: var(--accent); }
.nf-range::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--accent);
  box-shadow: var(--sh-weak);          /* A 版：唯一弱阴影档 */
}
.nf-range:hover::-webkit-slider-thumb { transform: scale(1.08); }
.nf-range:active::-webkit-slider-thumb,
.nf-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 5px rgba(var(--accent-rgb), .18); }
.nf-range:focus-visible { outline: none; }
.nf-range:active::-moz-range-thumb,
.nf-range:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 5px rgba(var(--accent-rgb), .18); }

.nf-cur {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 12px;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}
.nf-cur .nf-sep { color: var(--faint); }
.nf-cur .nf-cur-multi { font-weight: 600; color: var(--accent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: inline-block; max-width: 100%; vertical-align: bottom; }
.nf-cur b { color: var(--accent); font-weight: 600; }

/* 档位参考刻度尺（对数滑杆下）：贴住滑杆轨道下方，1K→100M */
.nf-scale {
  position: relative;
  height: 10px;
  margin-top: -1px;
  font-size: 12px;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
  user-select: none;
}
.nf-scale span {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  white-space: nowrap;
  line-height: 10px;
}
/* 刻度对齐分段边界（每段 20%：10K@20 100K@40 500K@60 1M@80 100M@100） */
.nf-scale span:nth-child(1) { left: 20%; }
.nf-scale span:nth-child(2) { left: 40%; }
.nf-scale span:nth-child(3) { left: 60%; }
.nf-scale span:nth-child(4) { left: 80%; }
.nf-scale span:nth-child(5) { left: 100%; transform: translateX(-100%); }

/* 自定义范围折叠入口（details/summary）：档位外的 min/max 精确输入 */
.nf-more { margin-top: 0; }
.nf-more-sum {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--muted);
  user-select: none;
  padding: 1px 0;
  transition: color var(--t-fast);
}
.nf-more-sum::-webkit-details-marker { display: none; }
.nf-more-sum:hover { color: var(--accent); }
.nf-more-sum::before {
  content: "";
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 4px solid currentColor;
  transition: transform var(--t-fast);
}
.nf-more[open] .nf-more-sum::before { transform: rotate(180deg); }
.nf-more .nf-inputs { margin-top: 2px; }
.nf-more .nf-cur { margin-top: 2px; }

/* 右列表区：白框 + 灰底滚动内容，达人卡为悬浮白卡 */
.list-area {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: var(--sh-1);
  overflow: hidden;
}
.list-head {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 12px 16px 12px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.ph-text { min-width: 0; }
.ph-title { font-size: 20px; font-weight: 700; color: var(--text); line-height: 1.3; letter-spacing: -.01em; }
.ph-sub { font-size: 14px; color: var(--muted); margin-top: 3px; }
.list-ops { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; flex-wrap: wrap; }
.list-ops .btn-ghost { padding: 8px 12px; font-size: 12px; }
/* 收藏选中：品牌蓝实底按钮，白色实心星（与全选/清除的轻底 ghost 区分层级） */
.btn-fav-sel {
  color: var(--accent-ink);
  border-color: var(--accent);
  background: var(--accent);
  font-weight: 600;
  box-shadow: var(--sh-accent);
}
.btn-fav-sel svg.star-ic path { fill: currentColor; stroke: currentColor; stroke-width: 1; }
.btn-fav-sel:hover, .list-ops .btn-fav-sel:hover { color: var(--accent-ink); background: var(--accent-strong); border-color: var(--accent-strong); box-shadow: var(--sh-weak); }
/* 底色继承自 `.btn-fav-sel`（本规则不写 background）→ 同样属「accent 实底 + 文字」，
   批次 9 按「本块内有无 background」划作用域时漏掉了它。 */
/* 特异性**不能**只用 0,2,0：`.list-ops .btn-fav-sel:hover`（:953）是 0,3,0 且写在前面，
   焦点规则若只是 0,2,0 就会被它压掉 —— **鼠标恰好停在按钮上时键盘焦点环整个消失**。
   2026-09-27 实测：hover=False 时 boxShadow 前=--sh-accent 后=--ring（正常）；
   hover=True 时前后都是 --sh-weak，`:focus-visible` 虽命中但样式零变化。
   批次 19 只改布局，把 390px 下的满宽按钮挪到了鼠标停驻点，才让这个既有缺陷显形
   （g10w 由 1460/1460 变 1459/1460 就是这个原因，不是批次 19 本身的问题）。 */
.btn-fav-sel:focus-visible,
.list-ops .btn-fav-sel:focus-visible { color: var(--accent-ink); box-shadow: var(--ring); }

#main-view .content {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  max-width: none;
  margin: 0;
  width: 100%;
  padding: 16px;
  background: var(--bg);
}
#main-view .content .cards { width: 100%; }
#main-view .cards > .status {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 220px;
  padding: 32px 16px;
  background: var(--surface);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r);
  color: var(--muted);
}
#main-view .cards > .status::before { content: "🔍"; font-size: 22px; opacity: .65; }

/* 达人列表：行卡 */
.cards { display: flex; flex-direction: column; gap: 12px; }
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 16px 24px;
  cursor: pointer;
  box-shadow: none;                    /* A 版：静止态不投影（弱阴影只有 hover 一档） */
  transition: border-color var(--t-fast), box-shadow var(--t-fast), transform var(--t-fast);
}
.card:hover {
  border-color: rgba(var(--accent-rgb), .48);
  box-shadow: var(--sh-weak);           /* A 版：唯一弱阴影档 */
  transform: translateY(-1px);
}
.card:focus-within { border-color: rgba(var(--accent-rgb), .6); }
.card, .row-main, .card-detail { min-width: 0; }

/* 顶行：三列分组 + 操作控件。列标签顶对齐（stretch），勾选/星标自身垂直居中 */
.row-main { display: flex; align-items: stretch; gap: 16px; min-height: 66px; }
.row-ops { display: flex; align-items: center; gap: 8px; flex-shrink: 0; align-self: center; }
/* 复选框 24×24 热区（label 包 input，.fav-box 悬停/焦点环） */
.fav-box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 8px;
  cursor: pointer;
  flex-shrink: 0;
  transition: background var(--t-fast), box-shadow var(--t-fast);
}
.fav-box:hover { background: var(--accent-weak); }
.fav-box:focus-within { box-shadow: var(--ring); }
.fav-box .fav-check { width: 16px; height: 16px; margin: 0; accent-color: var(--accent); cursor: pointer; flex-shrink: 0; }

.col-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  justify-content: flex-start;
  padding-left: 16px;
  border-left: 1px solid var(--border);
}
.col-group.group-basic { flex: 0 1 320px; padding-left: 0; border-left: none; }
.col-group.group-content { flex: 1; }
.col-group.group-biz {
  flex: 0 1 220px;
  align-items: flex-end;
}
.group-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: .02em;
  line-height: 16px;
  white-space: nowrap;
}
.group-body { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* 账号区：logo + handle/fans 双行（层级分开，基线不再打架） */
.row-left { gap: 8px; min-width: 0; }
.row-left img { width: 22px; height: 22px; flex-shrink: 0; border-radius: 4px; }
/* 账号区整体链接（logo + handle/粉丝 → 主页，新窗口）：继承排版不产生下划线/变蓝 */
.acc-link {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}
.acc-link:hover .card-handle { color: var(--accent); }
.acc-main {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.card-handle {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.card-fans {
  font-size: 12px;
  font-weight: 400;
  color: var(--muted);
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.row-mid { gap: 8px; min-width: 0; flex-wrap: wrap; }
/* 品类标签：基础灰底中性；品类浅色系最多 6 色（深字浅底），country 独立中性 */
.tag {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  line-height: 16px;
  font-weight: 500;
  padding: 3px 8px;
  border-radius: 8px;
  background: var(--badge-slate-bg);
  color: var(--badge-slate-tx);
  border: 1px solid var(--badge-slate-bd);
  white-space: nowrap;
}
.tag-country { background: var(--badge-slate-bg); color: var(--badge-slate-tx); border-color: var(--badge-slate-bd); }
/* UID 短显 chip：内容区最右（push right），悬停 title 见全量；过长省略号不可见用 … */
.card-uid {
  margin-left: auto;
  font-size: var(--fs-12);
  line-height: 16px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: .01em;
  padding: 2px 8px;
  border-radius: 8px;
  background: var(--badge-slate-bg);
  color: var(--badge-slate-tx);
  border: 1px solid var(--badge-slate-bd);
  white-space: nowrap;
  align-self: center;
  cursor: help;
}
/* A 版：徽标 = 低饱和底（白天 HSL S≤30% / 黑夜 ≤20%）+ 1px 同色系描边 + 同色系文字 ≥12px */
.tag-cat-rose { background: var(--badge-rose-bg); color: var(--badge-rose-tx); border-color: var(--badge-rose-bd); }
.tag-cat-violet { background: var(--badge-violet-bg); color: var(--badge-violet-tx); border-color: var(--badge-violet-bd); }
.tag-cat-amber { background: var(--badge-amber-bg); color: var(--badge-amber-tx); border-color: var(--badge-amber-bd); }
.tag-cat-cyan { background: var(--badge-cyan-bg); color: var(--badge-cyan-tx); border-color: var(--badge-cyan-bd); }
.tag-cat-emerald { background: var(--badge-emerald-bg); color: var(--badge-emerald-tx); border-color: var(--badge-emerald-bd); }
.tag-cat-slate { background: var(--badge-slate-bg); color: var(--badge-slate-tx); border-color: var(--badge-slate-bd); }
.card-source { font-size: 12px; color: var(--muted-strong); font-variant-numeric: tabular-nums; }

/* 右商业区：价格块与「暂无报价」共用统一高度，垂直居中，跨卡对齐 */
.row-right { flex-shrink: 0; text-align: right; }
.group-biz .group-body {
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 3px;
  min-height: 46px;
}
.card-rate { font-size: 12px; color: var(--muted); white-space: nowrap; }
.card-rate .amount {
  color: var(--text);
  font-weight: 700;
  font-size: 16px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.card-rate.muted { color: var(--muted); font-size: 12px; }
/* 报价逐行列表：产品本地化名 + 源文本价，超高（多产品/双币种）内滚 */
.rate-scroll {
  width: 100%;
  max-height: 140px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-right: 3px;
}
.rate-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
  line-height: 1.4;
}
.rate-prod {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
  color: var(--muted);
  font-size: 12px;
}
.rate-val {
  flex: none;
  text-align: right;
  color: var(--text);
  font-weight: 600;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.card-cpm {
  font-size: 12px;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.group-biz .group-body > .card-cpm { margin-top: 4px; }

/* 收藏星标（SVG：未收藏 = 描边灰，hover/active = 琥珀实心） */
.fav-star {
  border: none;
  background: transparent;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--faint);
  border-radius: 8px;
  padding: 0;
  flex-shrink: 0;
  transition: color var(--t-fast), background var(--t-fast), transform var(--t-fast);
}
.fav-star svg { width: 17px; height: 17px; }
.fav-star:hover { color: var(--star); background: rgba(245, 158, 11, .12); transform: scale(1.06); }
.fav-star.active { color: var(--star); }
.fav-star.active svg.star-ic path { fill: currentColor; stroke: currentColor; stroke-width: 1; }
.fav-star:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(245, 158, 11, .28); }

/* 来源元信息行：独立于顶行标签区，卡片底部细字（不干扰三列对齐） */
.card-meta {
  margin-top: 12px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
  display: flex;
  align-items: center;
  min-width: 0;
}
.card-meta .card-source {
  font-size: 12px;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* 卡片展开详情 */
.card-detail { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); cursor: default; }
.card-detail:empty { display: none; }
.detail-loading { color: var(--muted); font-size: 14px; padding: 8px 0; }
.detail-section-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
  letter-spacing: .04em;
  margin: 12px 0 8px;
}
.detail-section-title:first-child { margin-top: 4px; }
.plat-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
  margin-bottom: 8px;
  font-size: 14px;
}
.plat-row img { width: 17px; height: 17px; flex-shrink: 0; }
.plat-row .p-handle { flex: 1; min-width: 0; word-break: break-all; color: var(--text); font-weight: 500; }
.plat-row .p-fans { color: var(--muted-strong); font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }
.plat-row a { color: var(--muted); text-decoration: none; font-size: 12px; white-space: nowrap; }
.plat-row a:hover { color: var(--accent); text-decoration: underline; }
/* handle 本身可点主页时保持 p-handle 排版（覆盖上面通用 a 的小字灰） */
.plat-row a.p-handle {
  flex: 1;
  color: var(--text);
  font-weight: 500;
  font-size: 14px;
  text-decoration: none;
  min-width: 0;
  word-break: break-all;
}
.plat-row a.p-handle:hover { color: var(--accent); text-decoration: underline; }
.rate-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.rate-table th, .rate-table td { text-align: left; padding: 8px 8px; border-bottom: 1px solid var(--border); }
.rate-table tr:last-child td { border-bottom: none; }
.rate-table th { color: var(--muted); font-weight: 600; font-size: 12px; letter-spacing: .02em; }
.rate-table .idr { color: var(--text); font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.neg-yes { color: var(--ok); font-weight: 600; }
.neg-no { color: var(--faint); }
/* 明细表格斑马行（浅色极淡 / 暗色微亮，见 --zebra） */
.rate-table tbody tr:nth-child(even) td { background: var(--zebra); }
.table-wrap { overflow-x: auto; }

/* ---------- 分页 ---------- */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.page-info { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.pager .btn-ghost { padding: 8px 12px; }

/* ==========================================================================
   收藏夹 / 报价单 / 核对 / 路由 / 导入（共用白卡语言）
   ========================================================================== */
.review-tip {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.7;
  margin: 8px 0 16px;
  padding: 12px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}
.tab-count {
  font-size: 12px;
  font-weight: 600;
  padding: 1px 8px;
  border-radius: 8px;
  background: var(--accent-weak);
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
/* 底色走主题令牌：白天的原值让白字只有 3.97:1（见 --chip-on-accent 注释）。 */
.tab.active .tab-count { background: var(--chip-on-accent); color: var(--accent-ink); }

.badge-count {
  display: inline-block;
  min-width: 18px;
  padding: 1px 8px;
  border-radius: 8px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 12px;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.review-list, .routing-list { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.rrow, .frow, .route-row, .quote-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 12px 16px;
  box-shadow: none;                    /* A 版：静止态不投影（弱阴影只有 hover 一档） */
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.rrow:hover, .frow:hover, .route-row:hover, .quote-card:hover { border-color: var(--border-strong); box-shadow: var(--sh-1); }

.rrow-main, .frow-main { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rrow-main img, .frow-main img { width: 20px; height: 20px; flex-shrink: 0; border-radius: 4px; }
.r-handle { font-size: 14px; font-weight: 650; word-break: break-all; color: var(--text); }
.r-fans { font-size: 12px; color: var(--muted-strong); font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }
.r-link { color: var(--muted); text-decoration: none; font-size: 12px; white-space: nowrap; }
.r-link:hover { color: var(--accent); text-decoration: underline; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 500;
  padding: 3px 8px;
  border-radius: 8px;
  white-space: nowrap;
  border: 1px solid transparent;
}
.badge-warn { background: var(--warn-bg); color: var(--warn); border-color: var(--warn-bd); }
.badge-err { background: var(--err-bg); color: var(--err); border-color: var(--err-bd); }
.badge-ok { background: var(--ok-bg); color: var(--ok); border-color: var(--ok-bd); }

.rrow-note { color: var(--muted); font-size: 12px; line-height: 1.6; margin-top: 8px; word-break: break-all; }
.rrow-ops, .rrow-result {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.rrow-ops input { padding: 8px 12px; border-radius: var(--r-sm); font-size: 12px; width: 180px; }
.rrow-ops input[name="new_fans"] { width: 118px; }
.r-result-detail { color: var(--muted); font-size: 12px; }

.frow-plat { font-size: 12px; color: var(--muted); }
.frow-ops {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.fav-product { max-width: 240px; padding: 8px 12px; border-radius: var(--r-sm); font-size: 12px; }
.fav-price {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  min-width: 120px;
}

/* 报价单 */
.quote-preview { margin-top: 16px; }
.quote-card { padding: 16px 16px; margin-bottom: 12px; }
.quote-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.quote-no { font-size: 16px; font-weight: 700; letter-spacing: .02em; color: var(--text); }
.quote-customer { font-size: 14px; color: var(--text); }
.quote-date { font-size: 12px; color: var(--muted); }
.quote-group { padding: 12px 0; border-bottom: 1px dashed var(--border); }
.quote-group:last-of-type { border-bottom: none; padding-bottom: 2px; }
.quote-group-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.quote-biz { font-size: 14px; font-weight: 650; color: var(--text); }
.quote-group-meta { font-size: 14px; color: var(--muted); }
.quote-contact { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.quote-contact-label { font-size: 12px; color: var(--muted); }
.contact-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 12px;
  border-radius: 8px;
  border: 1px solid var(--ok-bd);
  background: var(--ok-bg);
  color: var(--ok);
  font-size: 12px;
  font-weight: 500;
  text-decoration: none;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.contact-btn:hover { background: rgba(4, 120, 87, .14); border-color: var(--ok); }
.quote-ops {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.quote-total {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  margin-right: auto;
}
.quote-ops .btn-mini { text-decoration: none; display: inline-flex; }

.quote-detail > summary { list-style: none; cursor: pointer; display: flex; align-items: center; }
.quote-detail > summary::-webkit-details-marker { display: none; }
.quote-expand { margin-left: auto; color: var(--faint); font-size: 12px; transition: transform var(--t-fast); }
.quote-detail[open] .quote-expand { transform: rotate(180deg); }
.quote-items {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 8px;
  padding: 8px 8px 2px 16px;
  border-left: 2px solid rgba(var(--accent-rgb), .22);
}
.qitem { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 12px; color: var(--muted); }
.qitem-handle { color: var(--text); font-weight: 600; text-decoration: none; }
a.qitem-handle:hover { color: var(--accent); text-decoration: underline; }
.qitem-product { color: var(--text); }
.qitem-rate { color: var(--text); font-weight: 700; margin-left: auto; font-variant-numeric: tabular-nums; }
.qitem-cpm { font-size: 12px; color: var(--muted-strong); font-variant-numeric: tabular-nums; }

/* 全局 toast */
.toast {
  position: fixed;
  left: 50%;
  bottom: 36px;
  transform: translateX(-50%);
  z-index: 90;
  padding: 8px 16px;
  border-radius: 8px;
  background: var(--toast-bg);
  border: 1px solid var(--toast-bd);
  color: var(--toast-tx);
  font-size: var(--fs-body);
  box-shadow: var(--sh-weak);
  animation: toast-in .2s ease-out;
  white-space: nowrap;
}
@keyframes toast-in {
  from { opacity: 0; transform: translate(-50%, 8px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

/* 商务路由配置 */
.route-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.route-row.route-add { border-style: dashed; }
.route-row input { padding: 8px 12px; border-radius: var(--r-sm); font-size: 12px; width: 118px; }
.route-row input[name="country"] { width: 76px; }
.route-row input[name="category"] { width: 138px; }
.route-row input[name="note"] { width: 160px; }
.route-ops { display: inline-flex; gap: 8px; }

/* 飞书导入 */
.import-body { max-width: 980px; }
.import-col-spec { font-size: 12px; color: var(--muted); margin: 8px 0 12px; }
.import-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--surface);
  border: 1px dashed var(--accent-line);
  border-radius: var(--r);
  padding: 16px 16px;
  margin-bottom: 12px;
}
.import-form .import-ref { padding: 8px 12px; border-radius: var(--r-sm); font-size: 14px; }
.import-form .import-textarea {
  padding: 8px 12px;
  border-radius: var(--r-sm);
  font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  resize: vertical;
  min-height: 120px;
}
.import-form .btn-mini { align-self: flex-start; }
.import-result { margin: 8px 0 16px; }
.import-result-ok {
  font-size: 14px;
  font-weight: 600;
  color: var(--ok);
  padding: 12px 12px;
  border: 1px solid var(--ok-bd);
  border-radius: var(--r);
  background: var(--ok-bg);
}
.import-err-list { margin-top: 8px; }
.import-err-row { font-size: 12px; color: var(--err); padding: 3px 0; }
.import-stats { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 4px 0 12px; }
.import-stats-label { font-size: 12px; color: var(--muted); }
.import-batches {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* `.batch-row` 是 `grid-template-columns: 170px 1fr 64px 64px 64px 64px`
     的固定网格，最小宽 ~490px —— 390px 视口下把整个 #import-view 撑破
     （g10ac 实测 sw=503 cw=390，溢出 113px）。套用本项目既有的横向滚动
     容器范式（同 `.table-wrap`），让表格自己滚而不是把页面撑破。 */
  overflow-x: auto;
}
.batch-row {
  display: grid;
  grid-template-columns: 170px 1fr 64px 64px 64px 64px;
  gap: 8px;
  align-items: center;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.batch-row.batch-head {
  background: none;
  border: none;
  color: var(--faint);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  padding: 2px 12px;
}
.batch-time { color: var(--muted); white-space: nowrap; }
.batch-ref { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.batch-ok { color: var(--ok); font-weight: 650; }
.batch-bad { color: var(--err); font-weight: 650; }

/* ==========================================================================
   数字对齐：金额/粉丝/计数统一 tabular-nums（K/M/千分位列对齐）
   ========================================================================== */
.quote-no, .quote-group-meta, .qitem-fans, .qitem-plat,
.card-source { font-variant-numeric: tabular-nums; }

/* ==========================================================================
   暗色局部覆盖：变量已随 [data-theme=dark] 全套换掉，这里只补 base 里
   写死、无法走变量的元素（顶栏毛玻璃 / 品类标签浅色系 / 收藏星 / toast /
   原生 select 下拉 / 页面底纹）。
   ========================================================================== */
html[data-theme="dark"],
html[data-theme="dark"] body {
  background: var(--bg);
}
[data-theme="dark"] .topbar { background: var(--topbar-bg); }   /* 黑夜：Linear 底 #0b0c0e */
/* 品类 / 国家 / UID 徽标：颜色全部走 --badge-* token（低饱和底 + 1px 同色系描边），
   这里不再写死色值 —— 两套主题各给一套 token 值即可。 */
[data-theme="dark"] .card-uid { background: var(--badge-slate-bg); color: var(--badge-slate-tx); border-color: var(--badge-slate-bd); }
[data-theme="dark"] select option { background: var(--surface); color: var(--text); }

/* 暗色平台 logo：黑白单色 SVG 在深面板不可见 → logo-only 胶囊垫白底浅边，彩色 logo 也统一 */
[data-theme="dark"] .filter-panel .platform-tabs .tab.logo-only:not(.active) {
  background: #fff;
  border-color: rgba(255, 255, 255, .9);
}
[data-theme="dark"] .filter-panel .platform-tabs .tab.logo-only:not(.active):hover {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(var(--accent-rgb), .25);
}

/* ==========================================================================
   响应式：保持原折叠逻辑；窄屏不破版。
   ========================================================================== */
/* 折叠：HTML 初始 .collapsed，宽屏强制展开，<900px 才有 ☰。
   操作行(筛选/重置)与内容一起折：窄屏折叠时只留标题头。 */
.filter-panel.collapsed .filter-scroll,
.filter-panel.collapsed .filter-foot { display: none; }
@media (min-width: 900px) {
  .filter-panel.collapsed .filter-scroll { display: block; }
  .filter-panel.collapsed .filter-foot { display: flex; }
}

@media (max-width: 899.98px) {
  #main-view .main-body { flex-direction: column; padding: 8px; gap: 8px; }
  #main-view .topbar { padding: 8px 12px; }
  .filter-panel { flex: none; width: 100%; }
  .filter-panel:not(.collapsed) { max-height: 56vh; }
  .fp-toggle { display: inline-flex; }
  .fp-head { padding: 8px 12px; }
  .filter-scroll { padding: 12px; }
  .list-area { flex: 1 1 auto; }
  #main-view .content { padding: 12px; }
  .list-head { padding: 12px 12px; }
  .list-ops { margin-left: 0; width: 100%; }
  .list-ops .btn-ghost { flex: 1; justify-content: center; }
  .ph-sub { display: none; }
}

@media (max-width: 560px) {
  body { font-size: 14px; }
  .topbar { gap: 8px; padding: 8px 12px; }
  .brand-icon { width: 30px; height: 30px; font-size: 14px; border-radius: 8px; }
  .brand-name { font-size: 14px; }
  .content { padding: 12px 12px 32px; }
  .card { padding: 12px 16px; }
  .row-main { flex-wrap: wrap; gap: 8px 8px; min-height: 0; }
  .row-ops { width: 100%; justify-content: flex-end; }
  .col-group { padding-left: 0; border-left: none; }
  .col-group.group-basic { flex-basis: 100%; }
  .col-group.group-biz { flex: 1 1 100%; align-items: flex-start; margin-left: 0; }
  .group-biz .group-body { align-items: flex-start; text-align: left; }
  .row-right { text-align: left; }
  .list-head { flex-direction: column; align-items: flex-start; gap: 8px; }
  .list-ops .btn-ghost { width: 100%; }
  .rrow, .frow, .route-row, .quote-card { padding: 12px 12px; }
  .rrow-ops input { flex-basis: 100%; width: auto; }
  .quote-ops { flex-direction: column; align-items: stretch; }
  .quote-ops .btn-mini, .quote-ops .quote-total { align-self: flex-start; }
  .route-row input { flex-basis: 45%; }
  .quote-total { margin-right: 0; }
}

/* ==========================================================================
   2026-09-09 布局重构 v20260909：左筛右列 → 上筛下列。
   顶部可折叠筛选面板（#filter-topbar，默认折叠成「筛选 ▾」一条，
   展开后筛选控件网格横向排布）+ 全宽列表区 + 行式全信息表格。
   ========================================================================== */

/* ---------- 主布局：纵向（筛选面板上、列表区下全宽） ---------- */
#main-view .main-body { flex-direction: column; align-items: stretch; }
#main-view .list-area { width: 100%; }

/* ---------- 顶部筛选工具栏 v3（现代 SaaS：主行高频 + 展开中频 + popover 低频） ---------- */
#filter-topbar {
  flex: none;
  width: 100%;
  min-width: 0;
  position: relative;
  z-index: 60;              /* popover 浮在下列列表区之上 */
  background: transparent;
}
/* 承载面：主行 fp-head / 中频行 topbar-body 各自成卡，圆角随开合状态切分 */
#filter-topbar .fp-head,
#filter-topbar .topbar-body {
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--sh-1);
}
#filter-topbar.collapsed .fp-head { border-radius: var(--r); }
#filter-topbar:not(.collapsed) .fp-head { border-radius: var(--r) var(--r) 0 0; }
#filter-topbar:not(.collapsed) .topbar-body { border-top: none; border-radius: 0 0 var(--r) var(--r); }
#filter-topbar:not(.collapsed) .fp-head { box-shadow: none; }
#filter-topbar:not(.collapsed) .topbar-body { box-shadow: none; }
#filter-topbar.collapsed .topbar-body { display: none; }
.filter-topbar .filter-row { display: block; }
.filter-topbar .filter-row > input[type="hidden"] { display: none; }

/* ---- 主行布局 ---- */
#filter-topbar .fp-head {
  position: relative;         /* popover 定位锚 */
  display: flex;
  justify-content: flex-start;   /* 覆盖旧 .fp-head 的 space-between：左侧控件自然排布 */
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  padding: 8px 8px 8px 12px;
  min-height: 48px;
}
/* 高频 cell：搜索（宽，胶囊形） */
#filter-topbar .f-cell { flex: 0 1 auto; min-width: 0; display: flex; align-items: center; }
/* 2026-09-17 taste 审计 —— HTML 用的是 `.fg-search/.fg-platform/.fg-category`
   （static/index.html:78/86/89），这里原本只写 `.f-cell-*` → 三条规则全部空跑：
   搜索格丢了 `flex:1 1 300px/min-width:230px/max-width:430px`，实测被压到 211px，
   输入框内容宽 196px = 占位符宽 196px，正好把「搜索达人账号…（回车搜索）」截断成
   「搜索达人账号…（回车」；`.search-ic` 也丢了绝对定位。两套 class 同时保留。 */
#filter-topbar .f-cell-search, #filter-topbar .fg-search {
  position: relative; flex: 1 1 300px; min-width: 230px; max-width: 430px; }
#filter-topbar .f-cell-search .search-ic, #filter-topbar .fg-search .search-ic {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--muted);
  pointer-events: none;
}
#filter-topbar .search-input {
  width: 100%;
  height: 30px;               /* 2026-09-17 与 .tab/.more-btn/.nf-num 统一 30px */
  padding: 4px 12px 4px 32px;
  border-radius: 8px;
  font-size: 14px;
  background: var(--field);
}
/* 「跳到主内容」skip link（WCAG 2.4.1 Bypass Blocks / G1）。
   常态移到屏外、键盘聚焦时滑入左上角；**必须用 top 偏移而不是 display:none** ——
   display:none 的元素不可聚焦，等于没有这个链接。
   实测依据：从加载到第一条结果行要 35 次 Tab（scripts/g10s2_filter_usability.py）。 */
.skip-link {
  /* 批次 16b：原 `padding: 10px 16px` 的 10px 不在 8pt 刻度上
     → design_system_conformance 报 P1 野值 ×2（浅/深各一次，×40 次出现）。
     改 var(--sp-2)/var(--sp-4)（8px/16px，都是 token）。链接高 42→38px，
     `top: -64px` 仍足以完全移出屏外（它本身未被判野值）。 */
  position: fixed; left: 8px; top: -64px; z-index: 200;
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r);
  background: var(--accent); color: var(--accent-ink);
  font-size: var(--fs-14); font-weight: 600; text-decoration: none;
  box-shadow: var(--sh-1);
  transition: top var(--t-fast) var(--ease);
}
.skip-link:focus, .skip-link:focus-visible {
  top: 8px; outline: none; box-shadow: var(--ring);
}

/* 仅供读屏的文本：视觉隐藏但**保留在无障碍树里**。
   为什么不用 display:none / visibility:hidden —— 那两者会把元素从无障碍树摘掉，
   等于没有这个标签（批次 14 用它给 46 个数值输入补「最小值/最大值」后缀）。
   position:absolute 使它脱离 flex 流，因此放进 .nf-inputs 也不影响布局。 */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 搜索框有值 → accent 描边（激活态可视化） */
#filter-topbar .search-input.has-value { border-color: rgba(var(--accent-rgb), .6); box-shadow: var(--ring); }
#filter-topbar .f-cell-platform, #filter-topbar .fg-platform { gap: 8px; }
#filter-topbar .f-cell-category, #filter-topbar .fg-category { flex: 2 1 340px; max-width: 620px; }
#filter-topbar .f-cell-category .chip-group, #filter-topbar .fg-category .chip-group {
  flex-wrap: nowrap;
  overflow-x: auto;
  padding: 2px 2px 4px;
  scrollbar-width: none;
}
#filter-topbar .f-cell-category .chip-group::-webkit-scrollbar,
#filter-topbar .fg-category .chip-group::-webkit-scrollbar { display: none; }

/* 平台/品类/档位 chips、tabs 统一 30px 手感 */
#filter-topbar .platform-tabs .tab { padding: 4px 12px; font-size: 12px; min-height: 30px; }
#filter-topbar .platform-tabs .tab.logo-only { padding: 4px 8px; }
#filter-topbar .platform-tabs .tab img { width: 17px; height: 17px; }
#filter-topbar .chip-text { padding: 4px 8px; font-size: 12px; line-height: 1.3; }

/* ---- 右侧操作：计数徽标 / 展开 chevron / 更多筛选 ---- */
#filter-topbar .fp-ops {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  flex-shrink: 0;
}
#filter-topbar .active-count {
  display: inline-flex;
  align-items: center;
  height: 30px;               /* 2026-09-17 与工具条其余控件统一 30px */
  padding: 0 12px;
  border-radius: 8px;
  border: 1px solid var(--accent-line);
  background: var(--accent-weak);
  color: var(--accent);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: default;
}
#filter-topbar .active-count.hidden { display: none; }
/* ── 实时结果计数（批次 19）────────────────────────────────────────────────
   面板展开占 0.81~0.88 屏、首卡 top=1087px、面板不自动收起 → 改完筛选看不到反馈。
   挂 `.fp-head`（折叠/展开两态都常驻），不挂 `.fp-ops`（5 项 + 实测挤压史）。
   高度 30px 与 `.active-count` 一致：`ui_taste_audit` F3「工具条控件高度唯一」
   的实测集虽不含本元素，但工具条内控件参差同样看得出来。 */
#filter-topbar .result-count {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 var(--sp-3);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--muted-strong);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
  cursor: default;
}
/* `:empty` 必须整元素撤出 flex 流：`.fp-head` 是 `gap: 8px 12px` 的 flex，
   0 宽空 span 也算一个 flex item，会多算一份 12px column-gap。 */
#filter-topbar .result-count:empty { display: none; }
#filter-topbar .topbar-toggle {
  width: 30px;
  height: 30px;
  /* G10v 实测：同一条 `.fp-ops` 行里被挤到 **18px**（CSS 明明写 30px）。
     尺寸仍是 30×30 —— 它是 `:3861-3866` 已登记的 44px 例外
     （抬它会让 ui_taste_audit F3「工具条控件高度唯一」报红），此处只让它回到设计值。 */
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--muted-strong);
  cursor: pointer;
  padding: 0;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
#filter-topbar .topbar-toggle:hover,
#filter-topbar .topbar-toggle.is-open { color: var(--accent); border-color: var(--accent-line); background: var(--accent-weak); }
#filter-topbar .topbar-toggle .tb-chev { transition: transform .18s var(--ease); }
#filter-topbar:not(.collapsed) .topbar-toggle .tb-chev { transform: rotate(180deg); }
#filter-topbar .topbar-toggle:focus-visible { outline: none; box-shadow: var(--ring); }
#filter-topbar .more-btn {
  position: relative;
  height: 30px;
  padding: 0 12px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border-radius: 8px;
  font-size: 12px;
  white-space: nowrap;
}
#filter-topbar .more-btn .more-ic { color: var(--accent); flex-shrink: 0; }
#filter-topbar .more-btn .more-caret { color: var(--muted); flex-shrink: 0; transition: transform .18s var(--ease); }
/* 展开态箭头翻转：`is-open` 是 JS 实际写的类（app.js:1223 setMoreOpen）。
   原选择器写的是 `#filter-topbar.popover-open`，而 `popover-open` **全仓只有
   这一处引用、JS 从不添加** → 展开「更多筛选」时箭头永不旋转，明眼用户拿不到
   开合反馈（只有 aria-expanded 给读屏）。同级 .topbar-toggle 用 .is-open 驱动
   （上方 1746/1748 行），此处与它统一。 */
#filter-topbar .more-btn.is-open .more-caret { transform: rotate(180deg); }
#filter-topbar .more-btn .more-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  position: absolute; top: 2px; right: 2px;
}
#filter-topbar .more-btn.is-active { color: var(--accent); border-color: var(--accent-line); background: var(--accent-weak); }

/* ── 筛选器精简开关（TASK-20260921-109）：A 分层折叠 / B 三档预设 ═══════════════
   老板要「做两个给我选择，可切换对比」。挂在 `.fp-ops` 首位 —— `.fp-head` 常驻
   （面板收起时也在），所以这就是「页面上一处可见开关」，不需要展开面板才能切。
   段控件只在需要的档位出现：「档位」是 B 的概念（A 没有档位），「更多筛选」按钮是
   A 的等价物（B 由档位段控件承担）—— 两个都摆 = 两套「更多」，反而更乱。 */
.fp-switch { display: inline-flex; align-items: center; gap: 4px; }
.fps-seg {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface-2);
}
.fps-btn {
  height: 24px;
  padding: 0 8px;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--muted-strong);
  font-size: var(--fs-12);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--t-fast), background var(--t-fast), border-color var(--t-fast);
}
.fps-btn:hover { color: var(--accent); }
.fps-btn.is-on {
  color: var(--accent);
  background: var(--surface);
  border-color: var(--accent-line);
  box-shadow: var(--sh-weak);
}
.fps-btn:focus-visible { outline: none; box-shadow: var(--ring); }
#filter-topbar:not([data-fp="B"]) #fp-tier { display: none; }
#filter-topbar[data-fp="B"] #more-filters-btn { display: none; }

/* 档位/分层折叠的隐藏**只用这一个类** —— 不内联 style、不 moving DOM、不 disabled、
   不改 value、不改 name。折叠起来的控件仍在 `#filter-row` 里，`hx-include="#filter-row"`
   照样收得到 → 「未展示」≠「空值」（任务书 §数据类语义断言）。 */
#filter-topbar .fp-off { display: none !important; }

/* 精简提示条：本档藏了几个、去哪儿找 —— 「保留全部字段可用性」的可见入口。
   数字由 app.js **当场数渲染结果**得出，所以屏幕上写的和屏幕上有的永远一致。 */
.fp-hint {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px;
  padding: 8px 12px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg);
  background: var(--surface-2);
  color: var(--muted);
  font-size: var(--fs-12);
}
.fp-hint.hidden { display: none; }
.fph-btn {
  height: 24px;
  padding: 0 8px;
  border: 1px solid var(--accent-line);
  border-radius: var(--r-sm);
  background: var(--accent-weak);
  color: var(--accent);
  font-size: var(--fs-12);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.fph-btn:hover { background: var(--surface); }
.fph-btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* ---- 「更多筛选」popover：低频（地区/CPM/排序/有报价/重置） ---- */
#filter-topbar .more-popover {
  position: absolute;
  top: calc(100% + 8px);
  right: 8px;
  z-index: 90;
  width: min(420px, calc(100vw - 48px));
  max-height: calc(100dvh - 210px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
  box-shadow: var(--sh-3);
  overflow: hidden;
}
#filter-topbar .more-popover.hidden { display: none; }
.mp-body { overflow-y: auto; overscroll-behavior: contain; padding: 4px 16px 2px; }
.mp-section { padding: 12px 0; border-bottom: 1px solid var(--border); }
.mp-section:last-child { border-bottom: none; }
.mp-label {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
  letter-spacing: .02em;
  margin-bottom: 8px;
}
.mp-label::before {
  content: "";
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--faint);
  flex-shrink: 0;
}
.mp-section .chip-group { gap: 8px; }
.mp-section .nf-inputs .nf-num,
.mp-section .select { height: 30px; }
.mp-section .select { width: 100%; }
.mp-section .nf-inputs .dash { font-size: 14px; }
.mp-section .f-switch { width: 100%; padding: 8px 12px; }
.mp-section .nf-ranges { margin-top: 2px; }
.mp-section .nf-cur { margin-top: 2px; }
.mp-foot {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}
.mp-foot .reset-filter { padding: 8px 12px; font-size: 12px; }
/* 精确数值输入：右对齐 + 与其余控件统一 30px 手感 */
#filter-topbar .nf-num { text-align: right; }
#filter-topbar .topbar-body .nf-num,
#filter-topbar .more-popover .nf-num { height: 30px; padding-top: 4px; padding-bottom: 4px; }

/* ---- 中频行（展开）：粉丝 + 报价 两栏面板 ---- */
#filter-topbar .topbar-body {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 16px;
  padding: 12px 16px 12px;
  /* 批次 43（2026-09-27 实测）：原 `100dvh - 240px` 只给页面其余部分留 240px，
     而非面板实测占用 254px → 面板吃到 88%、首条结果被挤出 900px 视口 144px，
     用户调筛选时**一条结果都看不到**。改为留 600px，并加 220px 下限防矮屏压死。
     滚动层数不变（仍只有 `.topbar-body` 这一层），只是把上限收紧。 */
  max-height: max(220px, calc(100dvh - 600px));
  overflow-y: auto;
  overscroll-behavior: contain;
}
#filter-topbar .topbar-body .fg-fans,
#filter-topbar .topbar-body .fg-price { min-width: 0; }
#filter-topbar .topbar-body .fg-price {
  border-left: 1px solid var(--border);
  padding-left: 16px;
}
#filter-topbar .topbar-body .fg-fans .fg-body,
#filter-topbar .topbar-body .fg-price .fg-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
}
#filter-topbar .topbar-body .f-title { font-size: 12px; }
#filter-topbar .topbar-body .nf-bands .chip-text { font-size: 12px; padding: 4px 3px; }

/* ---- 已激活筛选 pills 行（结果列表上方） ---- */
.filter-pills {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 8px 16px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  min-height: 0;
}
.filter-pills.hidden { display: none; }
/* ── 面板内的「已选条件」镜像（批次 20）────────────────────────────────────
   为什么需要：面板展开占 0.81~0.88 屏、首卡 top=1087px，外层 #filter-pills
   跟结果一起被推出视野，用户看不到自己筛了什么，只能在 104 个控件里翻找。
   sticky：面板体（.topbar-body）自身有 max-height、内部可滚动，不 sticky 就会
   在滚到进阶层时同样消失 —— 那就等于没做。
   grid-column 1/-1：.topbar-body 在窄屏是 grid（style.css:2349），不跨列会只占
   一个格子；非 grid 容器下该属性被忽略，无害。
   z-index 取 2：面板内部没有更高的层，够挡住下方控件。 */
#filter-panel-bar {
  grid-column: 1 / -1;
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-2);
  border: 1px solid var(--accent-line);
  border-radius: var(--r);
  background: var(--surface-2);
}
#filter-panel-bar.hidden { display: none; }
#filter-pills-panel {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  min-width: 0;
}
/* 「查看结果 →」（批次 21）：26px 与 .fp-pill / .pills-clear 同高，同一行不参差。 */
#filter-panel-bar .panel-apply {
  margin-left: auto;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  height: 26px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--accent);
  border-radius: var(--r-lg);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
#filter-panel-bar .panel-apply:hover {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
}
/* 焦点环特异性：带 ID 前缀 = (1,2,0)，与上面的 :hover 同级且写在后面 → 焦点胜出。
   批次 19 实测过反面教材：`.list-ops .btn-fav-sel:hover` 压掉 `.btn-fav-sel:focus-visible`
   → 鼠标停在按钮上时焦点环整个消失。新按钮不要重蹈。 */
#filter-panel-bar .panel-apply:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
.fp-pill {
  display: inline-flex;
  align-items: center;
  max-width: 320px;
  height: 26px;
  padding: 0 4px 0 12px;
  border-radius: 8px;
  border: 1px solid var(--accent-line);
  background: var(--accent-weak);
  font-size: 12px;
  white-space: nowrap;
}
.fp-pill .pp-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fp-pill .pp-prefix { color: var(--muted-strong); font-weight: 600; }
.fp-pill .pp-sep { color: var(--faint); margin: 0 4px; }
.fp-pill .pp-val { color: var(--text); }
.fp-pill .pp-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  margin-left: 4px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--muted-strong);
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
  padding: 0;
  transition: background var(--t-fast), color var(--t-fast);
}
.fp-pill .pp-x:hover { background: rgba(var(--accent-rgb), .18); color: var(--accent); }
.pills-clear {
  height: 26px;
  padding: 0 8px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--muted-strong);
  font-size: 12px;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.pills-clear:hover { background: var(--accent-weak); color: var(--accent); }

/* 暗色下 pills / popover 面 */
[data-theme="dark"] .fp-pill { background: rgba(var(--accent-rgb), .13); }
/* ---------- 行式全信息列表：单层表格（表头 + 行卡共用列模板） ---------- */
#main-view .cards {
  /* G10k：来源列 96px → 190px（老板要的状态徽标不能截断）；报价列 220 → 200 让总宽不涨 */
  /* G10t（2026-09-26）：列宽最小档由**真浏览器实测**重定，不再凭感觉。
     实测脚本 scripts/g10t_th_width_measure.py（五语 x 4 档视口，语言断言 180/180）。
     原配额下 19 格表头被省略号截断，集中在三列（括号内=固有宽度最大的那门语言）：
       列4 粉丝 76 → 96   th「ผู้ติดตาม」45px，需 84（+12% 跨平台字体余量）
       列5 评级 58 → 88   en/id「Rating」38px，需 77 —— 到 1440 都还在截断，最严重
       列7 国家 60 → 80   en「Country」46px，需 71（静态列，无箭头占位）
     来源列的旧注释（96 → 190「状态徽标不能截断」）就是同一类问题的先例。 */
  /* 批次 66：删「国家」列（11 → 10 列）；「状态」列只需放 2 枚徽标 → 190 → 170。
     列序：勾选 星标 账号 粉丝 评级 品类 **状态** 报价 CPM 操作 */
  --lg-cols: 30px 34px minmax(150px, 1.6fr) minmax(96px, .7fr) minmax(88px, .5fr)
             minmax(120px, 1.2fr) minmax(170px, 1.2fr)
             minmax(230px, 1.7fr) minmax(92px, .7fr) 108px;
  /* 表头与行卡**必须同宽**，否则列错位（两处 min-width 原为手写重复的 1180px）。
     收敛成一个 token，改列宽时不可能再漏改一处。 */
  --lg-minw: 1280px;
  gap: 0;
  /* A 版：这里**不再**做滚动容器（旧的 overflow-x:auto）。
     原因：overflow 非 visible 会让 .cards 自己变成滚动容器 → 粘性表头相对它定位，
     而它自身永不滚动 → sticky 形同虚设。横向溢出交给真正的滚动祖先 #main-view .content
     （它本来就是纵向滚动容器，overflow-x 因此已经是 auto），sticky 才真正生效。 */
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--sh-weak);
}
#main-view .cards:empty { min-height: 170px; }
#main-view .cards > .status {
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  width: 100%;
}
/* 表头行 */
.lg-head {
  display: grid;
  grid-template-columns: var(--lg-cols);
  column-gap: 12px;
  align-items: center;
  min-width: var(--lg-minw);
  padding: 8px 16px;
  background: var(--field);
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
  letter-spacing: .01em;
}
.lg-head .thc { overflow: hidden; text-overflow: ellipsis; }
/* 行卡：表内白条，行底细分隔；整行可点开详情 */
.cards .card {
  min-width: var(--lg-minw);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  box-shadow: none;
  padding: 8px 16px;
  cursor: pointer;
  transition: background var(--t-fast);
}
.cards .card:last-child { border-bottom: none; }
.cards .card:hover { background: var(--accent-weak); transform: none; box-shadow: none; }
.cards .card:focus-within { border-bottom-color: var(--accent-line); }
/* 行**自身**的焦点环（批次 11：行现在 tabindex=0，键盘可开详情）。
   与上面的 :focus-within 区分：那是「行内子控件」聚焦时的细线，
   这个是「整行被选中」——所以给完整焦点环 + 底色，一眼能看出当前停在哪一行。 */
.cards .card:focus-visible { outline: none; box-shadow: var(--ring);
  background: var(--accent-weak); }
.card .row-grid {
  display: grid;
  grid-template-columns: var(--lg-cols);
  column-gap: 12px;
  align-items: center;
}
/* 单元格通用 */
.cell { min-width: 0; }
.cell-na { color: var(--muted); font-size: var(--fs-body); }
/* 勾选 / 星标 */
/* G10v 实测（2026-09-26）：上面基础规则声明的是「复选框 24×24 热区」，
   这一行却把它覆盖成 22×22 —— 列表里每个勾选框都低于自己声明的口径，
   也低于 WCAG 2.2 SC 2.5.8（点击目标 ≥24×24）。30px 的勾选列放得下 24px。 */
.cell-sel .fav-box { width: 24px; height: 24px; }
.cell-sel .fav-check { width: 15px; height: 15px; }
.cell-fav { display: flex; }
/* 账号：logo + handle（可点主页）+ uid 短显 */
.cell-acc .acc-link {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}
.cell-acc .acc-link img { width: 24px; height: 24px; border-radius: 6px; flex-shrink: 0; }
.cell-acc .acc-cols { display: flex; flex-direction: column; gap: 1px; min-width: 0; line-height: 1.28; }
.cell-acc .acc-handle {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cell-acc .acc-link:hover .acc-handle { color: var(--accent); }
.cell-acc .acc-uid {
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* 粉丝数 */
.cell-fans .fans-val {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* 评级 LSx */
.cell-ls .ls-pill {
  display: inline-block;
  padding: 2px 8px; line-height: 16px;   /* 2026-09-17 与 .country-pill / .cell-cat .tag 对齐 */
  border-radius: 8px;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  white-space: nowrap;
  background: var(--badge-amber-bg);
  color: var(--badge-amber-tx);
  border: 1px solid var(--badge-amber-bd);
}
/* 品类标签组 */
.cell-cat { display: flex; flex-wrap: wrap; gap: 4px 4px; }
/* 2026-09-17 taste 审计 F4：与 .ls-pill / .country-pill 同排相邻 → 上下内边距必须同值
   （此前这里是 1px，另外两者 2px，同一行里三种胶囊高矮差 2px）。 */
.cell-cat .tag { font-size: 12px; line-height: 16px; padding: 2px 8px; }
/* 国家（ISO 码 + 全名 title） */
.cell-ctry .country-pill {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
  padding: 2px 8px; line-height: 16px;
  border-radius: 8px;
  background: var(--field);
  border: 1px solid var(--border-strong);
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
}
/* 来源 */
.cell-src {
  font-size: var(--fs-body);   /* A 版：来源列 = 数据正文 14px（徽标才用 12px） */
  color: var(--muted-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* 报价：多价 inline 逐行（短视频/直播…本地化产品名 + 源文本价），无价 → — */
.cell-rate .rate-list { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.q-line {
  display: flex;
  /* 2026-09-26（G10v 实测修复）：原来这里是 `justify-content: space-between` 且**不能折行**，
     而 `.q-val` 是 `flex-shrink: 0`、`.q-prod` 是行内唯一可压缩项 →
     同产品双币种合并成一行后（`Rp175,000,000 · $10,000` = 166px），
     移动端 175px 的行里 `.q-prod` 只剩 `175 − 8 − 166 = 1px`，**产品名整条不可见**
     （桌面端也只有 29px，需要 42–74px；330 格/轮命中，五语全中）。
     改为**允许折行**：放不下时金额折到第二行，产品名独占第一行 —— 信息完整。
     为什么不加宽列：id 的产品名 `Short video + keranjang kuning` 固有 203px，
     单行容下需列宽 406px（现 200px），加宽救不了最长的语言。 */
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 8px;                  /* 行内 8px；折行后两行之间 0 —— 读作一个整体 */
  min-width: 0;
  font-size: var(--fs-body);   /* A 版：报价是**数据正文**，不许落在 12px 标签档 */
  line-height: 1.5;
}
.q-prod {
  color: var(--muted);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.q-val {
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  /* 金额是这一列的主数据，**绝不压缩**成 `Rp175,00…` */
  flex-shrink: 0;
  /* 折行后金额独占一行时靠右（`justify-content: space-between` 在单元素行上会推到左边） */
  margin-left: auto;
}
.cell-rate .cell-na { white-space: nowrap; }
/* CPM：紧凑 K/M，title 全量 IDR */
.cell-cpm .cpm-val {
  font-size: var(--fs-body);   /* A 版：CPM = 数据正文 14px */
  font-weight: 600;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* 操作按钮：完整显示不被挤 */
.cell-ops { text-align: left; }
.cell-ops .row-open-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.cell-ops .row-open-btn:hover { border-color: var(--accent-line); color: var(--accent); }
.cell-ops .row-open-btn:focus-visible { outline: none; box-shadow: var(--ring); }
/* 详情展开仍在下插一行（整宽） */
.cards .card .card-detail { margin-top: 8px; padding-top: 8px; }
/* 空态提示在表内保持无框居中 */
#main-view .cards > .status { min-height: 200px; }

/* 暗色适配（新增元素） */

/* ---------- 窄屏：筛选主行纵向堆叠；列表横滚保按钮不被切 ---------- */
@media (max-width: 1099.98px) {
  #filter-topbar .f-cell-search, #filter-topbar .fg-search { flex: 1 1 100%; max-width: none; }
  #filter-topbar .f-cell-platform, #filter-topbar .fg-platform { flex: 0 1 auto; }
  #filter-topbar .f-cell-category, #filter-topbar .fg-category { flex: 2 1 340px; }
  #filter-topbar .fp-head { gap: 8px 8px; }
}
@media (max-width: 899.98px) {
  #filter-topbar .fp-head { padding: 8px; }
  #filter-topbar .f-cell-platform, #filter-topbar .fg-platform,
  #filter-topbar .f-cell-category, #filter-topbar .fg-category { flex: 1 1 100%; }
  #filter-topbar .f-cell-platform .platform-tabs,
  #filter-topbar .fg-platform .platform-tabs { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none; }
  #filter-topbar .f-cell-platform .platform-tabs::-webkit-scrollbar,
  #filter-topbar .fg-platform .platform-tabs::-webkit-scrollbar { display: none; }
  #filter-topbar .f-cell-category, #filter-topbar .fg-category { max-width: none; }
  #filter-topbar .fp-ops { width: 100%; justify-content: flex-end; }
  #filter-topbar .more-popover { right: 8px; left: 8px; width: auto; max-height: calc(100dvh - 200px); }
  #filter-topbar .topbar-body { grid-template-columns: minmax(0, 1fr);
    max-height: max(220px, calc(100dvh - 600px)); }   /* 批次 43：原 -230px 太宽松 */
  #filter-topbar .topbar-body .fg-price { border-left: none; padding-left: 0; border-top: 1px solid var(--border); padding-top: 12px; margin-top: 2px; }
  .filter-pills { padding: 8px 12px; }
}
@media (max-width: 699.98px) {
  #filter-topbar .topbar-body { padding: 12px; }
  #filter-topbar .fp-ops .active-count { flex-shrink: 0; }
  .more-txt { display: none; }   /* 窄屏更多钮只留图标，省宽度 */
}

/* ==========================================================================
   v22 表头点击排序 + 列间细分隔线（行式全信息表格增强；叠加不破坏暗色变量体系）
   可排序列头 = button.th-sort（点击状态机见 app.js sortByHeader）：
   hover 高亮 + cursor:pointer；active 列标 is-sorted（文字+箭头 accent）。
   ========================================================================== */
#main-view .cards { gap: 0; }
/* 行高 44px：整行 min-height 撑住，单元格靠 align-items:center 居中（内容再长也只是变高） */
#main-view .cards .card { padding: 0 16px; min-height: 44px; }

/* ① 列内垂直呼吸下沉到单元格 → 分隔线可贯穿整行视觉高度 */
#main-view .cards .lg-head {
  /* 粘性表头：滚动容器是 #main-view .content（筛选栏 / 列表页头都在它的**外面**，
     不参与滚动）→ 表头吸顶位置就是滚动口顶边，偏移量 0 即「永远在筛选栏下方」。
     若日后把筛选栏放进同一个滚动容器，只需把这里的 top 改成筛选栏高度。 */
  position: sticky;
  /* 吸顶位置：吃掉滚动容器的 16px 内边距带（Chrome 把 sticky 偏移算在滚动口的
     **内容盒**顶边，top:0 会停在 padding 下沿 → 行内容会从表头上方那道缝里漏出来）。
     取负值 = 表头贴住滚动口真正的顶边；未滚动时仍在原位（16px 呼吸），不影响静止观感。 */
  top: calc(-1 * var(--sp-4));
  z-index: 6;                     /* 压在行卡之上，且低于 .flow-fab(70) / .drawer(80) */
  min-height: 44px;
  padding: 0 16px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border-strong);
  box-shadow: var(--sh-weak);     /* 吸顶后与行卡分层（唯一的弱阴影档） */
}
#main-view .cards .lg-head,
#main-view .cards .card .row-grid { column-gap: 0; align-items: stretch; }

#main-view .cards .lg-head > *,
#main-view .cards .row-grid > .cell {
  display: flex;
  align-items: center;
  min-width: 0;
}
/* 前两列（勾选/星标）无左分隔线，也不吃横向 padding */
#main-view .cards .lg-head > *:nth-child(-n+2),
#main-view .cards .row-grid > .cell:nth-child(-n+2) { padding: 8px 0; }
/* 主列：淡色细分隔线 + 统一横向内距 */
#main-view .cards .lg-head > *:nth-child(n+3),
#main-view .cards .row-grid > .cell:nth-child(n+3) {
  border-left: 1px solid var(--border);
  padding: 8px 12px;
}

/* ①-2 数字列右对齐：粉丝(4) / 评级(5) / 报价(9) / CPM(10) —— 列序与 --lg-cols 一一对应。
   配合全站 tabular-nums：等宽数字 + 右对齐 → 竖着能对位比大小。 */
#main-view .cards .lg-head > *:nth-child(4),
#main-view .cards .lg-head > *:nth-child(5),
#main-view .cards .lg-head > *:nth-child(9),
#main-view .cards .lg-head > *:nth-child(10),
#main-view .cards .row-grid > .cell:nth-child(4),
#main-view .cards .row-grid > .cell:nth-child(5),
#main-view .cards .row-grid > .cell:nth-child(9),
#main-view .cards .row-grid > .cell:nth-child(10) { justify-content: flex-end; text-align: right; }
/* 报价列：产品名保持左、**金额贴在右边缘**（.q-line 的 space-between），金额仍右对齐 */
#main-view .cards .cell-rate .q-line { width: 100%; }

/* ② stretch 后子元素需填满列宽才能保住原有省略/两端对齐 */
#main-view .cards .cell-acc > * { flex: 1 1 0; min-width: 0; }
#main-view .cards .cell-src > * { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#main-view .cards .cell-rate > .rate-list { flex: 1 1 0; min-width: 0; }
#main-view .cards .cell-ops { justify-content: flex-start; }
#main-view .cards .cell-ops > * { flex: 0 0 auto; align-self: center; }
#main-view .cards .cell-cat { align-content: center; }

/* ③ 可排列表头按钮样式 */
#main-view .cards .th-sort {
  margin: 0;
  border-top: none; border-right: none; border-bottom: none;
  border-left: 1px solid var(--border);   /* 主列分隔线由 nth-child 统一给，此处仅兜底 */
  background: none;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--muted);
  text-align: left;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
#main-view .cards .th-sort .th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
#main-view .cards .th-sort .th-arr {
  display: inline-block;
  flex: 0 0 auto;
  min-width: 11px;
  margin-left: 3px;
  font-size: 12px;
  line-height: 1;
  text-align: center;
  opacity: 0;
  transition: opacity var(--t-fast), color var(--t-fast);
}
#main-view .cards .th-sort:not(.is-sorted) .th-arr::before { content: "↕"; opacity: .45; }
#main-view .cards .th-sort:hover { color: var(--accent); }
#main-view .cards .th-sort:hover .th-arr { opacity: 1; }
#main-view .cards .th-sort:focus-visible { outline: none; box-shadow: inset 0 0 0 2px rgba(var(--accent-rgb), .3); }

/* active 排序列：文字 + 箭头 accent（仅加粗无底色，用户 2026-09-09） */
#main-view .cards .th-sort.is-sorted { color: var(--accent); font-weight: 700; background: transparent; }
#main-view .cards .th-sort.is-sorted .th-arr { opacity: 1; color: var(--accent); }
#main-view .cards .th-sort.is-sorted .th-arr::before { content: none; }
/* 数值列表头也右对齐（含箭头方向一致） */
#main-view .cards .lg-head > *:nth-child(4) .th-sort,
#main-view .cards .lg-head > *:nth-child(5) .th-sort,
#main-view .cards .lg-head > *:nth-child(9) .th-sort,
#main-view .cards .lg-head > *:nth-child(10) .th-sort { text-align: right; }

/* ④ 详情展开（下插行）在卡片内自带上下留白，不再依赖 .card padding */
#main-view .cards .card .card-detail { margin-top: 0; padding: 4px 0 12px; }

/* ---------- 待捞池看板（T05）：复用现有配色变量，不引新框架 ---------- */
.pool-bar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:8px 0 12px}
.pool-input{padding:8px 8px;border:1px solid var(--line,var(--border));border-radius: 8px;background:transparent;color:inherit;font-size:14px}
.pool-chk{display:flex;gap:8px;align-items:center;font-size:14px;opacity:.9}
.pool-list{overflow-x:auto}
.pool-table{width:100%;border-collapse:collapse;font-size:14px}
.pool-table th,.pool-table td{padding:8px 8px;border-bottom:1px solid var(--line,var(--border));text-align:left;white-space:nowrap}
.pool-table th{font-weight:600;opacity:.85}
.pool-table td.num{text-align:right}
.pool-h{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.pool-ops{display:flex;gap:8px}
.pool-act{font-size:12px;padding:3px 8px}
.pool-flag{display:inline-block;padding:1px 8px;border-radius: 6px;border:1px solid var(--warn-bd);background:var(--warn-bg);color:var(--warn);font-size:12px}
.pool-flash{margin:8px 0}
.pool-empty{opacity:.7;text-align:center;padding:16px}

/* ==========================================================================
   v2（2026-09-14）① 覆盖维度筛选组 ② FAB + 右侧流程抽屉 ③ 4 模式详情块
   一律复用既有变量（暗色自动适配，不写死颜色）；窄屏（抽屉 ≤380px / 手机全宽）
   单列纵向、不横向溢出。
   ========================================================================== */

/* ---------- ① 覆盖维度组（#filter-row 内，与 .fg-fans/.fg-price 同级） ---------- */
#filter-topbar .topbar-body .cover-filters {
  grid-column: 1 / -1;                 /* 横跨「粉丝 / 报价」两栏 */
  border-top: 1px solid var(--border);
  padding-top: 12px;
  margin-top: 2px;
}
.cover-filters .cf-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 12px 16px;
  margin-top: 8px;
}
.cf-sec { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.cf-label {
  display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap;
  font-size: 12px; font-weight: 600; color: var(--text);
  padding-bottom: 3px; border-bottom: 1px dashed var(--border);
}
.cf-src { font-size: 12px; font-weight: 400; color: var(--faint); }
.cf-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.cf-k { flex: 0 0 64px; font-size: 12px; color: var(--muted-strong); }
.cf-mini { flex-shrink: 0; font-size: 12px; color: var(--muted); }
.cf-row .chip-group, .cf-row .nf-inputs { flex: 1 1 auto; min-width: 0; }
.cover-filters .cf-date {
  text-align: left; font-size: 12px; padding-top: 4px; padding-bottom: 4px;
  font-variant-numeric: tabular-nums;
}
.cf-row-scores .nf-inputs { gap: 8px; }
.cf-row-scores .nf-num { font-size: 12px; padding: 4px; }
/* 置灰 chip（bound_by_others）：可见但不可点，后缀标明「未采集」（设计 §5.1 #7） */
.chip-disabled { cursor: not-allowed; }
.chip-disabled input { pointer-events: none; }
.chip-disabled .chip-text {
  background: var(--surface-2); color: var(--muted);
  border-style: dashed; opacity: .9;
}
.chip-disabled:hover .chip-text { color: var(--muted); border-color: var(--border); }
.chip-suffix {
  font-style: normal; font-size: 12px; line-height: 1.6; margin-left: 4px;
  padding: 0 4px; border-radius: 6px;
  background: var(--warn-bg); color: var(--warn); border: 1px solid var(--warn-bd);
}

/* 列表页头：名单读回时间（新鲜度）＋ 降级/名单未读回横幅（内容由 fragment OOB 填） */
.roster-meta { display: block; margin-top: 4px; font-size: 12px; color: var(--faint); }
.degraded-bar, .roster-banner {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 8px; padding: 8px 12px;
  border: 1px solid var(--warn-bd); border-radius: var(--r-sm);
  background: var(--warn-bg); color: var(--warn);
  font-size: 12px; line-height: 1.5;
}
.roster-banner { border-color: var(--err-bd); background: var(--err-bg); color: var(--err); }
.degraded-bar.hidden, .roster-banner.hidden { display: none; }

/* ---------- ② 右下角 FAB + 右侧飞入抽屉（设计 §6） ---------- */
.flow-fab {
  position: fixed; right: 20px; bottom: 20px; z-index: 70;
  width: 48px; height: 48px; padding: 0;
  display: grid; place-items: center;
  border: 1px solid var(--accent-line);
  border-radius: 50%;
  background: var(--grad); color: var(--accent-ink);
  box-shadow: var(--sh-3);
  transition: transform var(--t-fast) var(--ease), box-shadow var(--t-fast);
}
.flow-fab:hover { transform: translateY(-1px); box-shadow: 0 18px 40px rgba(var(--accent-rgb), .34); }
.flow-fab:focus-visible { outline: none; box-shadow: var(--ring), var(--sh-3); }
.flow-fab .flow-fab-ic { display: block; }
.fab-badge {
  position: absolute; top: -5px; right: -5px;
  min-width: 20px; height: 20px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px; border: 2px solid var(--surface);
  background: var(--accent); color: var(--accent-ink);
  font-size: 12px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
}
.fab-badge.hidden { display: none; }

.drawer { position: fixed; inset: 0; z-index: 80; visibility: hidden; }
.drawer.drawer-open { visibility: visible; }
.drawer-mask {
  position: absolute; inset: 0;
  background: var(--mask);
  opacity: 0; transition: opacity .2s var(--ease);
}
.drawer-open .drawer-mask { opacity: 1; }
.drawer-panel {
  position: absolute; top: 0; right: 0; bottom: 0;
  width: min(100vw, 420px);
  display: flex; flex-direction: column;
  background: var(--surface); border-left: 1px solid var(--border);
  box-shadow: var(--sh-3);
  transform: translateX(100%);
  transition: transform .2s var(--ease);
  overflow: hidden;
}
.drawer-open .drawer-panel { transform: translateX(0); }
.drawer-head {
  flex-shrink: 0; display: flex; align-items: center; gap: 8px;
  padding: 12px 12px; border-bottom: 1px solid var(--border); background: var(--surface-2);
}
.drawer-title { font-size: 14px; font-weight: 700; }
.drawer-role {
  margin-left: auto; padding: 2px 8px; border-radius: 8px; white-space: nowrap;
  background: var(--accent-weak); border: 1px solid var(--accent-line);
  color: var(--accent); font-size: 12px; font-weight: 600;
}
.drawer-close {
  flex-shrink: 0; width: 26px; height: 26px; padding: 0; line-height: 1;
  display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--surface); color: var(--muted); font-size: 12px;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.drawer-close:hover { color: var(--err); border-color: var(--err-bd); background: var(--err-bg); }
.drawer-close:focus-visible { outline: none; box-shadow: var(--ring); }
.drawer-sec-h {
  font-size: 12px; font-weight: 600; letter-spacing: .06em;
  color: var(--muted); text-transform: uppercase; margin-bottom: 8px;
}
.drawer-nav { flex-shrink: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 12px 12px 0; }
.drawer-nav > .drawer-sec-h { grid-column: 1 / -1; }
.drawer-nav-item {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 8px 12px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text);
  font-size: 12px; text-align: left;
  transition: border-color var(--t-fast), background var(--t-fast), color var(--t-fast);
}
.drawer-nav-item:hover:not([disabled]) { border-color: var(--accent-line); background: var(--surface); }
.drawer-nav-item:focus-visible { outline: none; box-shadow: var(--ring); }
.drawer-nav-item .dn-ic { flex-shrink: 0; width: 16px; text-align: center; color: var(--star); }
.drawer-nav-item .dn-tx { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.drawer-nav-item .badge-count { margin-left: auto; }
.drawer-nav-item.is-disabled, .drawer-nav-item[disabled] {
  color: var(--faint); background: transparent;
  border-style: dashed; cursor: not-allowed;
}
.drawer-nav-item.is-disabled .dn-ic { color: var(--faint); }

.drawer-stage {
  flex: 0 1 auto; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: 8px;
  margin-top: 12px; padding: 12px; border-top: 1px solid var(--border);
}
.stage-item {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 8px 8px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text);
  font-size: 12px; text-align: left;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.stage-item:hover:not([disabled]) { border-color: var(--accent-line); }
.stage-item:focus-visible { outline: none; box-shadow: var(--ring); }
.st-no {
  flex-shrink: 0; width: 18px; height: 18px;
  display: grid; place-items: center;
  border-radius: 50%; background: var(--accent-weak); color: var(--accent);
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.st-tx { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.st-lock { margin-left: auto; font-size: 12px; color: var(--faint); }
.stage-item[disabled] {
  color: var(--faint); background: transparent;
  border-color: var(--border); border-style: dashed; cursor: not-allowed;
}
.stage-item[disabled] .st-no { background: var(--surface-2); color: var(--faint); }

/* ── 抽屉步进向导（2026-09-14 任务书 §1/§2 · 设计 §6）：步头 / 步内容 / 步操作 ──
   步面板与 10 步列表**互斥显示**（.hidden 切换，不整块替换节点）。 */
.drawer-wizard { flex-shrink: 0; max-height: 62vh; overflow-y: auto; padding: 12px 12px 0; }
.step-panel { display: flex; flex-direction: column; gap: 8px; min-width: 0; outline: none; }
.step-panel:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-sm); }
.step-head-t { font-size: 14px; font-weight: 700; }
.step-head-s { margin-top: 2px; font-size: 12px; color: var(--faint); }
.step-src {
  font-size: 12px; color: var(--faint);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere;
}
.step-body { display: flex; flex-direction: column; gap: 8px; }
.step-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.step-metric {
  display: flex; flex-direction: column; gap: 2px; padding: 8px 8px;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-2);
  min-width: 0;
}
.sm-k { font-size: 12px; color: var(--faint); }
.sm-v { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.sm-none { font-weight: 500; color: var(--faint); }
.step-none {
  margin: 0; padding: 8px; border: 1px dashed var(--border-strong);
  border-radius: var(--r-sm); font-size: 12px; color: var(--muted);
}
.step-hint { margin: 0; font-size: 12px; color: var(--warn); }
.step-rows-title { font-size: 12px; font-weight: 600; color: var(--faint); }
.step-rows { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
.step-row {
  display: flex; flex-direction: column; gap: 2px; padding: 8px 8px;
  border-radius: 8px; background: var(--surface-2); min-width: 0;
}
.sr-t { font-size: 12px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr-m { font-size: 12px; color: var(--faint); overflow-wrap: anywhere; }
.step-note { margin: 0; font-size: 12px; color: var(--faint); }
.step-nav { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.step-nav-btn[disabled] { opacity: .55; cursor: not-allowed; }
.step-back { margin-left: auto; }
.step-open-full {
  align-self: flex-start; font-size: 12px; color: var(--accent);
  text-decoration: underline; text-underline-offset: 2px;
}
.step-open-full:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 6px; }
.step-loading { padding: 8px 0; font-size: 12px; color: var(--faint); }
.step-err { padding: 8px 0; font-size: 12px; color: var(--err); }

.drawer-sel {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 12px; border-top: 1px solid var(--border); background: var(--surface);
}
.drawer-sel-info { display: flex; flex-direction: column; gap: 8px; }
.sel-empty { font-size: 12px; color: var(--muted); }
.sel-n { font-size: 14px; font-weight: 600; }
.sel-handle { font-size: 14px; font-weight: 700; overflow-wrap: anywhere; }
.drawer-fav-btn, .drawer-detail-btn { align-self: flex-start; }
.sel-vt {
  padding: 8px 8px; border-radius: var(--r-sm); font-size: 12px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--muted-strong);
}
.sel-vt.vt-ok { border-color: var(--ok-bd); background: var(--ok-bg); color: var(--ok); }
.sel-vt.vt-no { border-color: var(--err-bd); background: var(--err-bg); color: var(--err); }
.sel-vt.vt-unknown { border-color: var(--warn-bd); background: var(--warn-bg); color: var(--warn); }
.drawer-detail { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; min-width: 0; }

/* ---------- ③ 关系条 / 数据源徽标 / 4 模式详情块（类名由后端渲染，此处只表达视觉） ---------- */
.rel-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 8px; border-radius: var(--r-sm); font-size: 12px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--muted-strong);
}
.rel-bar.rel-bound { border-color: var(--ok-bd); background: var(--ok-bg); color: var(--ok); }
.rel-bar.rel-not-bound { border-color: var(--err-bd); background: var(--err-bg); color: var(--err); }
.rel-bar.rel-unknown { border-color: var(--border); background: var(--surface-2); color: var(--muted-strong); }
.rel-bar .rel-state { font-weight: 600; }
.rel-bar .rel-share, .rel-bar .rel-since { font-size: 12px; color: var(--muted); }
.rel-bar .rel-source { font-size: 12px; color: var(--muted); overflow-wrap: anywhere; }
.src-badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 8px; border-radius: 8px; white-space: nowrap;
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--muted-strong); font-size: 12px; font-weight: 600;
}
.src-badge.ds-tto { border-color: var(--accent-line); background: var(--accent-weak); color: var(--accent); }
.src-badge.ds-collected { border-color: var(--border-strong); background: var(--surface-2); color: var(--muted-strong); }
/* G10k：列表页徽标（老板要求：非绑定 / TTO 可同步 / 详情已回读 / 可值单 一眼可见 + 悬停有释义） */
.src-badges { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; row-gap: 4px; }
.src-badge.ds-read { border-color: var(--ok-bd); background: var(--ok-bg); color: var(--ok); }
.src-badge.ds-pending { border-color: var(--warn-bd); background: var(--warn-bg); color: var(--warn); }
.src-badge.quote-yes { border-color: var(--ok-bd); background: var(--ok-bg); color: var(--ok); }
.src-badge.quote-no { border-color: var(--border-strong); background: var(--surface-2); color: var(--muted-strong); }

.dt-block {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
  padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2);
}
.dt-title { font-size: 12px; font-weight: 700; color: var(--text); }
.dt-note {
  font-size: 12px; padding: 3px 8px; border-radius: 6px;
  border: 1px dashed var(--warn-bd); background: var(--warn-bg); color: var(--warn);
}
.dt-field {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0;
  font-size: 12px; padding-top: 4px; border-top: 1px solid var(--border);
}
.dt-field:first-child { padding-top: 0; border-top: none; }
.dt-k { flex: 0 0 auto; min-width: 74px; font-size: 12px; color: var(--muted); }
.dt-v { flex: 1 1 auto; min-width: 0; color: var(--text); overflow-wrap: anywhere; }
/* 未采集：灰底 + 斜体（暗色下 --field 比块底更深 → 仍可读，不退化成空串/0/-） */
.dt-v.missing {
  padding: 0 8px; font-style: italic;
  background: var(--field); color: var(--muted);
  border: 1px dashed var(--border-strong); border-radius: 6px;
}
.probe-warn {
  font-size: 12px; padding: 4px 8px; border-radius: 6px;
  border: 1px solid var(--warn-bd); background: var(--warn-bg); color: var(--warn);
}

/* ---------- G10b 达人详情抽屉（1:1 对齐 TTO 达人详情面板，2026-09-15） ----------
   复用 .drawer / .drawer-panel 体系；内容 .tto-panel 由后端片段直出。 */
/* 抽屉宽度：老板口径「**内容区 491px**」（他在浏览器量到的就是这一个数）。
   改前 = 面板 520 − 1px 描边 − 2×14px 内边距 = 491 —— 数字对得上，所以 491 指的是内容区宽。
   A 版内边距归一到 8pt 的 12px → 面板外框收 4px（520 → 516），内容区仍 **491px** 一字不差。
   验算：516 − 1(border-left) − 2×12(padding) = 491。 */
.creator-drawer .drawer-panel { width: min(100vw, 516px); }
.tto-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 12px; display: flex; flex-direction: column; gap: 12px;
}
.tto-loading, .tto-panel-empty { color: var(--muted); font-size: 14px; padding: 8px 0; }
.tto-panel { display: flex; flex-direction: column; gap: var(--panel-gap); min-width: 0; }

/* 头部区：handle + 昵称 + 「查看 TikTok 主页」；其下「标签 + 值」两列 */
.tto-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 8px; flex-wrap: wrap; min-width: 0;
}
.tto-ident { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tto-handle { font-size: 16px; font-weight: 700; color: var(--text); overflow-wrap: anywhere; }
.tto-nick { font-size: 14px; color: var(--muted); overflow-wrap: anywhere; }
.tto-view {
  flex: 0 0 auto; font-size: 12px; color: var(--accent); text-decoration: none;
  padding: 4px 8px; border: 1px solid var(--accent-line); border-radius: 8px;
  white-space: nowrap;
}
.tto-view:hover { background: var(--accent-weak); }
.tto-view:focus-visible { outline: none; box-shadow: var(--ring); }
.tto-hmeta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* G10n 可阅读性：标签/值两级字号拉开（11px vs 13px）+ 标签加字距；值行高放宽到
   --lh-body（长简介/长标题不再挤成一坨）；数字统一 tabular-nums（千分位/百分比能上下对齐）。 */
.tto-field {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0;
  font-size: var(--fs-v); line-height: var(--lh-body);
  padding-top: var(--row-gap); border-top: 1px solid var(--border);
}
.tto-hmeta .tto-field { border-top: none; padding-top: 0; }
.tto-k {
  flex: 0 0 auto; min-width: 92px; font-size: var(--fs-k); color: var(--muted);
  letter-spacing: .2px; line-height: 1.5;
}
.tto-v {
  flex: 1 1 auto; min-width: 0; color: var(--text); overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}
/* 缺数态：去掉中文假斜体（CJK 斜体是硬倾斜，反而更难读），改用更高对比的虚框标签 */
.tto-v.missing {
  padding: 1px 8px; line-height: 1.45;
  background: var(--field); color: var(--muted-strong);
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
}
.tto-score-row { align-items: center; }
.tto-score { font-size: 22px; font-weight: 800; color: var(--accent); line-height: 1; }
.tto-score-tag {
  font-size: 12px; font-weight: 600; color: var(--accent); padding: 2px 8px; border-radius: 8px;
  background: var(--accent-weak); border: 1px solid var(--accent-line); white-space: nowrap;
}
.tto-cur { font-size: 12px; color: var(--muted); }

/* Tab 条 + 面板：第一个 Tab 默认激活，其余 pane 隐藏 */
/* G10k（2026-09-15 老板：下面切换请严格按照 TTO 的样式）——
   TTO 页签条实测（byted-anchor，本机登录态 DOM 量取）：
   · 条高 48px、flex 排列、间距 **32px**、无下边框
   · 文字 14px / 字重 **500**（激活与未激活同字重）
   · 未激活色 **#6D6E70**，激活色 **#121415**（激活不是主题色，只有下划线是青色）
   · 指示器＝激活页签下方实线，宽度**等于文字宽**（不撑满、不带三角）
     　　A 版变更：线宽 3px → **4px**（--tab-ink-w），颜色由 TTO 青绿 → **主题强调色**
     　　（老板 2026-09-16：「强调色全站只留 1 个」，TTO 青绿属于第二个强调色，已废）
   （TTO 页签条本身**没有三角形**，实测已核；已把量取结果写进 docs/UI_PARITY_G10k.md） */
.tto-tabs {
  /* A 版：① 间距走 8pt token（--tab-gap = 16px）—— 六个页签在 491px 内容区里一屏可见；
     ② 真溢出时**横向滚动**（overflow-x:auto + flex:0 0 auto，绝不换行、绝不压缩页签）；
     ③ 页签条自身不许被压扁：min-width:0 让滚动发生在自己身上而不是撑破抽屉。 */
  display: flex; gap: var(--tab-gap); overflow-x: auto; flex-wrap: nowrap; min-width: 0;
  border-bottom: 0; margin: 0; padding: 0; height: 48px; align-items: stretch;
  scrollbar-width: none;
}
.tto-tabs::-webkit-scrollbar { display: none; }

/* 2026-09-26 显示修复：页签溢出时的可滚动提示。
   背景：上面的设计假设是「**六个**页签一屏可见」，但现在抽屉有 7 个 →
   实测 en 需 572px / 容器 491px（末页签只露 23px）、420 视口下可见 0px；
   而滚动条被 scrollbar-width:none 藏了 → 「右边还有内容」没有任何提示。
   设计同时要求「绝不换行、绝不压缩」，故只加两端渐隐（mask 不改布局与尺寸）。
   打标由 app.js:wireTabOverflow() 按滚动位置完成。 */
/* 批次 13：同一套渐隐推广到另外两个「能滚但看不见滚动条」的容器 ——
   品类 chips 与平台页签也设了 scrollbar-width:none。g10x Reflow 实测：
   320px 下品类行溢出 739px(en)/453px(zh)、390px 下 383px，而屏幕上毫无线索。
   只加 mask，不改布局与尺寸；打标仍由 app.js 的 wireTabOverflow() 完成。 */
.tto-tabs.is-more-right,
#filter-topbar .fg-category .chip-group.is-more-right,
#filter-topbar .f-cell-category .chip-group.is-more-right,
#filter-topbar .fg-platform .platform-tabs.is-more-right,
#filter-topbar .f-cell-platform .platform-tabs.is-more-right {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
          mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
}
.tto-tabs.is-more-left,
#filter-topbar .fg-category .chip-group.is-more-left,
#filter-topbar .f-cell-category .chip-group.is-more-left,
#filter-topbar .fg-platform .platform-tabs.is-more-left,
#filter-topbar .f-cell-platform .platform-tabs.is-more-left {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 28px);
          mask-image: linear-gradient(to right, transparent 0, #000 28px);
}
.tto-tabs.is-more-left.is-more-right,
#filter-topbar .fg-category .chip-group.is-more-left.is-more-right,
#filter-topbar .f-cell-category .chip-group.is-more-left.is-more-right,
#filter-topbar .fg-platform .platform-tabs.is-more-left.is-more-right,
#filter-topbar .f-cell-platform .platform-tabs.is-more-left.is-more-right {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 28px,
                                      #000 calc(100% - 28px), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 28px,
                                      #000 calc(100% - 28px), transparent 100%);
}
.tto-tab {
  /* flex:0 0 auto = 不压缩；white-space:nowrap = 不换行 → 溢出只可能横滚（见 .tto-tabs） */
  flex: 0 0 auto; white-space: nowrap;
  font-size: var(--fs-tab); font-weight: 500; color: var(--muted);
  background: none; border: none; padding: 16px 0 0; cursor: pointer;
  border-bottom: var(--tab-ink-w) solid transparent; transition: color .15s, border-color .15s;
}
.tto-tab:hover { color: var(--text); }
.tto-tab:focus-visible { outline: none; box-shadow: var(--ring); }
.tto-tab.active { color: var(--text); border-bottom-color: var(--tab-ink); font-weight: 500; }
.tto-tabpanes { display: flex; flex-direction: column; gap: var(--panel-gap); min-width: 0; }
.tto-tabpane { display: none; flex-direction: column; gap: var(--panel-gap); min-width: 0; }
.tto-tabpane.active { display: flex; }

/* 分组卡片 + 子标签/筛选（G10n：子标签是**真交互**，不再是只读胶囊） */
.tto-sec {
  display: flex; flex-direction: column; gap: var(--sec-gap); min-width: 0;
  padding: var(--sec-pad); border: 1px solid var(--border); border-radius: var(--r-card);
  background: var(--surface-2);
}
.tto-sec-title { font-size: 12px; font-weight: 700; color: var(--text); margin: 0;
  letter-spacing: .1px; }
.tto-sec-label { font-size: 12px; font-weight: 700; color: var(--text); }
.tto-subgroup { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.tto-subtabs { display: flex; gap: 4px; flex-wrap: wrap; }
.tto-subtabs-ro { opacity: .85; }
.tto-subtab {
  font-size: 12px; line-height: 1.2; color: var(--muted-strong); padding: 4px 8px;
  border-radius: 8px; border: 1px solid var(--faint); background: var(--surface);
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.tto-subtab:hover { color: var(--text); border-color: var(--faint); }
.tto-subtab:focus-visible { outline: none; box-shadow: var(--ring); }
.tto-subtab.active {
  color: var(--accent); border-color: var(--accent-line);
  background: var(--accent-weak); font-weight: 600;
}
/* 变体没数据：置灰（虚线边 + faint 文字）但**可点** —— 点开就是「未采集（原因）」 */
.tto-subtab.is-empty {
  color: var(--faint); border-style: dashed; background: transparent; cursor: pointer;
}
.tto-subtab.is-empty.active {
  color: var(--muted-strong); border-color: var(--border-strong);
  background: var(--surface); font-weight: 600;
}
.tto-subblocks { display: flex; flex-direction: column; min-width: 0; }
.tto-subblock { display: none; flex-direction: column; gap: var(--sec-gap); min-width: 0; }
.tto-subblock.active { display: flex; }
.tto-subnone { display: flex; min-width: 0; }
/* 2026-09-17 三档口径：子标签底部的**平台口径提示**（块级整行小字，可折行、不省略）——
   品牌/非品牌档必须如实写出「与全部逐项全等的比例」，所以这里不能用卡片注解那套
   nowrap+省略号（长句会被截掉，等于没写）。字号走字阶 12px，与其它注解小字同级。 */
.tto-scope-note {
  display: block; min-width: 0; font-size: 12px; line-height: 1.5;
  color: var(--muted); padding-top: 2px;
}
/* G10q 整块缺数说明（老板 2026-09-15：整块全空只出一条，不再逐字段重复「未采集」）——
   一行主句（该达人暂无 XX 数据（原因））+ 可点「为什么？」释义（原生 <details>，零依赖）。 */
/* 2026-09-26 清理：`.tto-blocknone` / `.tto-blocknone-main` 全仓 0 生产者（删除区口径：缺数不渲染，不再需要"整块无"的样式），已删除。 */
.tto-why { font-size: var(--fs-k); color: var(--muted); }
.tto-why > summary {
  width: fit-content; cursor: pointer; color: var(--accent); font-weight: 600;
  list-style: none; padding: 1px 0;
}
.tto-why > summary::-webkit-details-marker { display: none; }
.tto-why > summary::after { content: " ▾"; font-size: 12px; }
.tto-why[open] > summary::after { content: " ▴"; }
.tto-why > summary:hover { text-decoration: underline; }
.tto-why > summary:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 4px; }
.tto-why-body { margin-top: 4px; line-height: 1.6; color: var(--muted-strong); }
.tto-filters { display: flex; gap: 4px; flex-wrap: wrap; }
.tto-filter-chip {
  font-size: 12px; color: var(--muted); padding: 2px 8px; border-radius: 8px;
  border: 1px solid var(--border-strong); background: var(--surface);
}

/* ---------- G10n 受众环图（性别/年龄/设备/画像）：内联 SVG + 图例（带百分比） ----------
   结构：<div.tto-donut-wrap> [caption] + [donut svg 120×120] + [legend]
   弧长按**原值**画（不做归一化）；总和不足 100% 时余量留空（轨道可见）+ 图例标「其余未列出」。 */
.tto-donut-wrap {
  display: grid; grid-template-columns: 120px minmax(0, 1fr); gap: 8px 12px;
  align-items: center; min-width: 0;
}
.tto-donut-cap {
  grid-column: 1 / -1; font-size: var(--fs-k); color: var(--muted);
  letter-spacing: .2px;
}
.tto-donut-box { display: flex; align-items: center; justify-content: center; min-width: 0; }
.tto-donut { display: block; }
.tto-donut-track { fill: none; stroke: var(--donut-track); stroke-width: 14; }
.tto-donut-arc {
  fill: none; stroke-width: 14; stroke-linecap: butt;
  transition: stroke-width var(--t-fast);
}
.tto-donut-arc:hover { stroke-width: 17; }
.tto-donut-c0 { stroke: var(--donut-0); }
.tto-donut-c1 { stroke: var(--donut-1); }
.tto-donut-c2 { stroke: var(--donut-2); }
.tto-donut-c3 { stroke: var(--donut-3); }
.tto-donut-c4 { stroke: var(--donut-4); }
.tto-donut-c5 { stroke: var(--donut-5); }
.tto-donut-c6 { stroke: var(--donut-6); }
.tto-donut-c7 { stroke: var(--donut-7); }
.tto-donut-legend {
  /* 2026-09-17 taste 审计 B1：行间距 3px 不在 8pt 节奏（{4,8,12,16,24,32}）上，改 4px。 */
  display: flex; flex-wrap: wrap; gap: 4px 12px; min-width: 0;
  font-size: 12px; line-height: 1.5;
}
.tto-donut-lg { display: inline-flex; align-items: center; gap: 4px; min-width: 0; }
.tto-donut-dot {
  flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%;
  background: var(--donut-7);
}
.tto-donut-dot.tto-donut-c0 { background: var(--donut-0); }
.tto-donut-dot.tto-donut-c1 { background: var(--donut-1); }
.tto-donut-dot.tto-donut-c2 { background: var(--donut-2); }
.tto-donut-dot.tto-donut-c3 { background: var(--donut-3); }
.tto-donut-dot.tto-donut-c4 { background: var(--donut-4); }
.tto-donut-dot.tto-donut-c5 { background: var(--donut-5); }
.tto-donut-dot.tto-donut-c6 { background: var(--donut-6); }
.tto-donut-dot.tto-donut-c7 { background: var(--donut-7); }
.tto-donut-dot-none { background: transparent; box-shadow: inset 0 0 0 1px var(--border-strong); }
.tto-donut-dot-rest { background: var(--donut-track); box-shadow: inset 0 0 0 1px var(--border-strong); }
.tto-donut-k { color: var(--text); overflow-wrap: anywhere; }
.tto-donut-v {
  color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.tto-donut-lg-rest .tto-donut-k, .tto-donut-lg-rest .tto-donut-v { color: var(--muted-strong); }
@media (max-width: 420px) {
  .tto-donut-wrap { grid-template-columns: minmax(0, 1fr); justify-items: start; }
}

/* 值形态：标签串 / 图例 / 单位 / 前N%胶囊 / 行业基准 */
.tto-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.tto-tag {
  padding: 1px 8px; border-radius: 8px; font-size: 12px;
  background: var(--accent-weak); border: 1px solid var(--accent-line); color: var(--accent);
}
.tto-legend { display: flex; flex-wrap: wrap; gap: 4px; }
.tto-unit { font-size: 12px; color: var(--muted); flex: 0 0 auto; }
.tto-chip {
  font-size: 12px; font-weight: 600; color: var(--accent); padding: 1px 8px; border-radius: 8px;
  background: var(--accent-weak); border: 1px solid var(--accent-line); white-space: nowrap;
}
.tto-ann { display: inline-flex; align-items: baseline; gap: 4px; }
.tto-ann-k { font-size: 12px; color: var(--muted); }

/* 分布（性别/年龄/设备/画像/国家）：键 + 占比 */
.tto-dists { display: flex; flex-direction: column; gap: 4px; }
.tto-dist-caption { font-size: 12px; font-weight: 600; color: var(--muted); }
.tto-dist { display: flex; gap: 8px; align-items: baseline; }
.tto-dist-k { font-size: 12px; color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.tto-dist-v {
  font-size: 12px; color: var(--muted); margin-left: auto; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* 视频卡片网格：封面位（含播放量角标）+ 描述 + 发布时间
   G10h：TTO 面板同样不渲染封面（自身显示 "Audio/video is not supported" 灰框），
   所以用中性占位框 —— 不引外部图片、不引 CDN。 */
.tto-field.tto-block { flex-direction: column; align-items: stretch; gap: 4px; }
.tto-sub { display: flex; flex-direction: column; gap: 4px; }
.tto-videos { display: grid; gap: 8px; min-width: 0;
  grid-template-columns: repeat(1, minmax(0, 1fr)); }
.tto-video-item {
  display: flex; flex-direction: column; gap: 4px; min-width: 0; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: inherit; text-decoration: none;
  transition: border-color .15s ease;
}
.tto-video-item:hover { border-color: var(--accent-line); }
.tto-video-item:hover .tto-video-title { color: var(--accent); }
.tto-video-item:focus-visible { outline: none; box-shadow: var(--ring); }
.tto-video-thumb {
  position: relative; display: block; width: 100%; height: 132px;
  background: var(--field); border-bottom: 1px solid var(--border);
}
.tto-video-views {
  position: absolute; left: 6px; bottom: 6px;
  font-size: 12px; font-weight: 700; color: var(--text); white-space: nowrap;
  background: var(--surface); border-radius: 8px; padding: 1px 8px;
  font-variant-numeric: tabular-nums;
  box-shadow: var(--sh-1);
}
/* G10n：标题统一**两行截断**（15 张卡不再因为标题长短不一而高低错落），
   元信息（发布时间）用等宽数字，卡片底部对齐。 */
.tto-video-title {
  font-size: 12px; line-height: 1.45; color: var(--text); overflow-wrap: anywhere;
  padding: 0 8px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.tto-video-meta {
  font-size: 12px; color: var(--muted); padding: 0 8px 8px; margin-top: auto;
  font-variant-numeric: tabular-nums;
}
.tto-video-item { min-height: 0; }
.tto-recent-no-title { color: var(--muted); font-style: italic; }

/* ---------- G10h 视觉拉齐（2026-09-15）----------
   证据：docs/reference/ui_parity/tto_panel_maayang_live.png / .txt（TTO 面板真值）。
   只改版式/间距/对齐；取值口径与三态纪律一字未动。 */

/* 头部区字段：标签小字在上、值在下（TTO 面板是纵向堆叠，不是左右两列） */
.tto-hmeta .tto-field { flex-direction: column; align-items: stretch; gap: 2px; }
.tto-hmeta .tto-k { min-width: 0; }
/* 长文本字段（达人个人简介）**独占整行**：半栏宽会把一段话压成 3~4 行窄柱，最难读 */
.tto-field-wide { grid-column: 1 / -1; }
.tto-field-wide .tto-v { line-height: 1.7; word-break: break-word; }
/* 合作评估：大分一行 + 「高传播度评分」胶囊换行在下方 */
.tto-score-row { align-items: flex-start; }
.tto-score-wrap { display: flex; flex-direction: column; align-items: flex-start;
  gap: 4px; min-width: 0; }
/* Expected rate：金额与币种分两行（数字一行、IDR 小字一行） */
.tto-rate { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
.tto-rate-num { font-size: 14px; font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums; }

/* 总体评分大卡（标签在上、大分在下） */
.tto-field-big { flex-direction: column; align-items: stretch; gap: 2px;
  padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); }
.tto-field-big .tto-k { min-width: 0; }
.tto-field-big .tto-score { font-size: 22px; }

/* KPI 卡片网格：列数 = 卡片数（上限 3），与 TTO 面板「一行最多三张」一致 */
.tto-cards { display: grid; gap: 8px; min-width: 0;
  grid-template-columns: repeat(1, minmax(0, 1fr)); }
.tto-cards[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.tto-cards[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.tto-card {
  display: flex; flex-direction: column; gap: 4px; min-width: 0; position: relative;
  /* 2026-09-17 taste 审计 A4/A5：注解行**脱离文档流**（绝对定位到底部）+ 用
     padding-bottom 给所有卡预留同一条注解带。这样「有注解的卡」与「没注解的卡」
     数值行距卡底恒定 → 同排数值行同基线（商业表现·品牌合作行此前差 69px/33px）。 */
  padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface);
}
/* 只在「本行有注解」时预留注解带（fragments.py 给 .tto-cards 打 data-ann="1"）；
   全行都没注解时不留白。数值行盒底到卡底 = 注解带 21px（实测）+ 数值行↔细线 7px（实测）
   + 距卡底 4px = --sp-6 32px（2026-09-18 收档，旧值 37px 为刻度外野值）。 */
.tto-cards[data-ann="1"] .tto-card { padding-bottom: var(--sp-6); }
/* G10i：`前 N%` 徽标与标签同行（TTO 同款「互动率 ⓘ [前 1 %]」） */
.tto-card-k { display: flex; align-items: center; column-gap: 4px; row-gap: 0; flex-wrap: wrap;
  font-size: var(--fs-k); color: var(--muted); letter-spacing: .2px;
  /* 2026-09-18 设计管线出稿（老板「内容成效……在完整的情况下考虑界面友好」）——
     标签带原先只有 line-height:1.5（18px），1 行 / 2 行的卡标签带实测 18 / 36 / 22px 高，
     标签底到数值顶的空档因此在 4.14 / 22 / 42.14px 之间跳（同排三张卡三种节奏）。
     收成：行高 16px（与 .ls-pill / .country-pill / .cell-cat .tag 的 12px 标签行高同值）
     + min-height: var(--sp-6)=32px（正好 2 行）+ align-content:flex-start
     → 标签带恒 32px，标签底↔数值顶空档三张卡同值（实测 ✓0px 差）。 */
  line-height: 16px; min-height: var(--sp-6); align-content: flex-start; }
/* 2026-09-17 taste 审计 A4/A5（老板指摘「格式没对齐」）——
   同排卡片的**标签换行数不同**（1 行 / 2 行 / 带「前 N %」徽标 1.2 行）会把数值行顶到
   三个不同高度（实测 1440 下差 18px）。`.tto-card` 是 flex column，`margin-top:auto`
   把「数值 + 注解」整组压到卡片底部：卡片由 grid stretch 等高 → 整组距底恒定 →
   三张卡的数值行/注释行自动同基线。只动对齐，不动任何数值口径与 DOM。 */
/* 数值行容器走 flex：子元素（数值 / 单位 / 空态文案）盒高 = 各自 line-height，
   底对齐 → 同排「有值卡 vs 空态卡」的数值行 top 严格相等（实测差 4.32px → 0）。 */
.tto-card-b { min-width: 0; margin-top: auto; display: flex; align-items: flex-end;
  flex-wrap: wrap; }
/* 2026-09-17 taste 审计 A4/A5（老板截图同一类「没对齐」；商业表现·品牌合作行实测
   同排数值行差 69px）——两个折行源都要掐掉，card-b 恒等于 1 行：
     ① 卡内缺数文案「未采集（平台未返回该字段）」在窄卡折成 2 行 → 与 1 行的有值卡不同高；
     ② 注解行「平台近 90 天 · 覆盖 27.5%」折成 2 行 → 该卡整组高 1 行。
   缺数文案完整原因由 fragments.py 挂 `title`（悬停可见），信息不丢。 */
.tto-card-b > .tto-v.missing, .tto-field-big > .tto-v.missing { display: block; }
.tto-card-b > .tto-v.missing {
  /* 与 `.tto-card-v` 同**盒高**（行高 1.3 × 主数值字号）→ 空态卡与有值卡数值行严格同 top。
     写死盒高而不是靠 line-height：空态文案字号更小（14px），line-height 撑出的行盒
     仍比数值行高 4px（实测 30 vs 26），同排会差 4.00px。
     卡内文案走短文案 `drawer_tto.missing_short`（fragments.py），完整原因在 title。 */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  height: calc(var(--fs-value) * 1.3); line-height: calc(var(--fs-value) * 1.3);
  color: var(--muted);
}
.tto-card-v { font-size: var(--fs-value); font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere; line-height: 1.3; }
.tto-card-unit { font-size: 12px; font-weight: 500; color: var(--muted); margin-left: 4px; }
/* G10i：卡片底部注解（行业基准）拉满整行 —— 标签居左、值右对齐到卡片右边缘（TTO 同款），
   并与数值之间加一道细分隔线（TTO 卡片同为「值 / 细线 / 行业基准」三段）。 */
.tto-card .tto-ann { display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; border-top: 1px solid var(--border); padding-top: 3px;
  white-space: nowrap; position: absolute; left: 12px; right: 12px; bottom: var(--sp-1);
  /* 2026-09-18 设计管线出稿：注解带高度必须**可溯源**，旧值靠 8px 上下内边距 + 1.55 行高
     撑出 30.69px，再写死 padding-bottom:37px（既不在 8pt 刻度上，还比注解带窄 1.69px →
     细线与数值行盒实测有 1.69px 重叠）。现按档收：细线到注解文字 = --sp-1(4px，
     由 1px 描边 + 3px 内边距组成)· 注解行盒 = 16px（与全站 12px 标签同值）·
     距卡底 = --sp-1(4px) → 注解带实测 21px · 数值行盒底 → 细线实测 7px ·
     卡底内距 = --sp-6(32px)。声明的档位只有 1 / 3（光学微调档）/ 16 / 4 / 32，
     全部落在 8pt 刻度或闸门已登记的 <4px 光学档上。 */
  line-height: 16px; }
/* 注解行恒 1 行：长注解（如「平台近 90 天 · 覆盖 27.5%」）在窄卡折行会把该卡的
   数值行整体顶高一行 → 同排错位。这里改成省略号截断，数值侧不参与收缩、不被截。 */
.tto-card .tto-ann .tto-ann-k { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* `.tto-v` 自带 flex:1 1 auto（会吃掉剩余空间）→ 用 text-align 把值顶到右边缘 */
.tto-card .tto-ann .tto-v { text-align: right; }

/* 内联统计行（效果趋势：最高/最低/平均播放量 同行） */
.tto-inlinestats { display: flex; flex-wrap: wrap; gap: 8px 16px; min-width: 0; }
.tto-inline { display: inline-flex; align-items: baseline; gap: 4px; min-width: 0; }
.tto-inline-k { font-size: 12px; color: var(--muted); }
.tto-inline-v { font-size: 14px; font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums; }

/* ---------- G10i 效果趋势柱状图（内联 SVG；无图表库、无外部资源） ----------
   结构：<figure.tto-chart> → 滚动容器 + svg + 图例（TTO 图例在柱子下方）。
   柱子宽度写死在 SVG 属性里（服务端算），这里只管配色与排版。 */
.tto-chart { margin: 0; display: flex; flex-direction: column; gap: 8px;
  min-width: 0; max-width: 100%; }
.tto-chart-scroll { min-width: 0; max-width: 100%; overflow-x: auto; overflow-y: hidden;
  scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
/* 横向滚动条必须**常显**：抽屉内容宽 465px < 15 柱所需 672px，
   不显滚动条会被误读成「图被截断/画错了」。 */
.tto-chart-scroll::-webkit-scrollbar { height: 8px; }
.tto-chart-scroll::-webkit-scrollbar-track { background: transparent; }
.tto-chart-scroll::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: 8px; border: none; }
.tto-chart-svg { display: block; height: auto; }
.tto-chart-grid { stroke: var(--tto-chart-grid); stroke-width: 1; stroke-dasharray: 3 4; }
.tto-chart-base { stroke: var(--tto-chart-axis); stroke-width: 1; }
.tto-chart-avg { stroke: var(--tto-chart-nonbrand); stroke-width: 1; stroke-dasharray: 4 4;
  opacity: .8; }
.tto-bar-brand { fill: var(--tto-chart-brand); }
.tto-bar-nonbrand { fill: var(--tto-chart-nonbrand); }
.tto-bar-boosted { fill: var(--tto-chart-boosted); }
.tto-bar-gap { fill: none; stroke: var(--border-strong); stroke-width: 1;
  stroke-dasharray: 2 2; }
/* 字号由服务端按柱数在 <svg style="font-size:Npx"> 上给定，这里只继承（1em） */
.tto-chart-val { font-size: 1em; fill: var(--muted-strong); text-anchor: middle;
  font-variant-numeric: tabular-nums; }
.tto-chart-date { font-size: 1em; fill: var(--muted); text-anchor: middle;
  font-variant-numeric: tabular-nums; }
.tto-chart-legend { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.tto-chart-lg { display: inline-flex; align-items: center; gap: 4px; font-size: 12px;
  color: var(--muted); }
.tto-chart-sw { flex: 0 0 auto; display: inline-block; width: 9px; height: 9px;
  border-radius: 8px; }
.tto-chart-sw-brand { background: var(--tto-chart-brand); }
.tto-chart-sw-nonbrand { background: var(--tto-chart-nonbrand); }
.tto-chart-sw-boosted { width: 12px; height: 14px; border-radius: 0; background: none; }
.tto-chart-drop { display: block; fill: var(--tto-chart-boosted); }
.tto-chart-note { font-size: 12px; color: var(--muted); }

/* 顶部「数据来源 / 缺数原因」标记：原生 <details>，可点击展开释义（零 JS） */
.tto-src { border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); font-size: 12px; }
.tto-src-sum { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 8px; cursor: pointer; list-style: none; color: var(--muted); }
.tto-src-sum::-webkit-details-marker { display: none; }
.tto-src-sum:focus-visible { outline: none; box-shadow: var(--ring); }
.tto-src-dot { flex: 0 0 auto; width: 7px; height: 7px; border-radius: 8px;
  background: var(--muted); }
.tto-src[data-ds="collected"] .tto-src-dot,
.tto-src[data-ds="no_raw"] .tto-src-dot { background: var(--warn); }
.tto-src[data-ds="ok"] .tto-src-dot { background: var(--ok); }
.tto-src-v { color: var(--text); font-weight: 600; }
.tto-src-more { margin-left: auto; color: var(--accent); white-space: nowrap; }
/* 展开后释义正文已在眼前，隐藏「释义」提示（保留占位避免行高跳动） */
.tto-src[open] .tto-src-more { visibility: hidden; }
.tto-src-body { display: flex; flex-direction: column; gap: 4px; padding: 0 8px 8px;
  color: var(--muted-strong); line-height: 1.55; }

/* 窄屏：三列卡片压回两列/单列，不横向溢出 */
@media (max-width: 519.98px) {
  .tto-cards[data-cols="3"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 420px) {
  .tto-videos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.rel-bar .rel-src { margin-left: auto; font-size: 12px; color: var(--muted); }
.panel-warn {
  font-size: 12px; padding: 8px 8px; border-radius: var(--r-sm);
  border: 1px solid var(--err-bd); background: var(--err-bg); color: var(--err); font-weight: 600;
}
.panel-warn.panel-warn-unknown { border-color: var(--warn-bd); background: var(--warn-bg); color: var(--warn); }

/* ≤768px：达人详情抽屉全屏展开（任务书硬约束「移动端可全屏展开、可关闭」） */
@media (max-width: 767.98px) {
  .creator-drawer .drawer-panel { width: 100vw; }
}

/* v2：顶部只留品牌 + 主题/语言/退出 —— 后三项右对齐（原来靠 6 个入口按钮撑满） */
/* G10n：切换器在**右上角**（原来只有 🌙 按钮吃 margin-left:auto，会把 chips 挤到左边） */
.topbar > .theme-switch { margin-left: auto; }
.topbar > .theme-switch + .theme-toggle { margin-left: 0; }
.topbar > .theme-toggle { margin-left: auto; }

/* 窄屏：抽屉 min(100vw,380px) → 手机全宽；覆盖维度组单列 */
@media (max-width: 899.98px) {
  .drawer-panel { width: min(100vw, 380px); }
  .cover-filters .cf-grid { grid-template-columns: 1fr; }
}
@media (max-width: 519.98px) {
  .drawer-panel { width: 100vw; }
  .drawer-nav { grid-template-columns: 1fr; }
}

/* 无障碍：prefers-reduced-motion → 去掉飞入/悬停位移，只做显隐（设计 §6.4） */
@media (prefers-reduced-motion: reduce) {
  .drawer-mask, .drawer-panel, .flow-fab, .drawer-nav-item, .stage-item, .drawer-close,
  .chip-text, .tab, .switch, .switch::after {
    transition: none !important;
  }
  .flow-fab:hover { transform: none; }
}

/* ================= 二期视图（项目/推号/选择库/履约/看板/设置） =================
   设计取向：沿用既有 token（--surface/--border/--accent/--ok/--err），加**层次**而非新配色。
   状态语义靠颜色承担：可得=绿、部分可得=橙、暂无数据源=灰（**不给数字位**）。 */
.p2-body { display: flex; flex-direction: column; gap: 12px; }
.p2-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 12px; }
/* 窄屏收成单列（批次 24）：卡片的列跨距是**内联** style（app.js:3364
   `card.style.gridColumn = "span " + (c.span || 6)`，来自用户持久化的看板布局），
   所以这里必须 `!important` 才能盖住内联值。
   为什么必须收：366px 容器下 12 列每列仅 ~19.5px，`span 6` = 175px，
   卡片内容（.p2-empty 187 / .p2-note 149）撑破卡片 → 整个 #dashboard-view
   横向溢出（g10ac 实测 sw=406 cw=390）。用户的跨距偏好在桌面端仍然生效。 */
@media (max-width: 719.98px) {
  .p2-grid > .p2-card { grid-column: 1 / -1 !important; }
}
.p2-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 4px 0 8px; }

.p2-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 12px 16px;
  box-shadow: var(--sh-1);
  min-width: 0;
}
.p2-grid .p2-card { transition: box-shadow .16s ease, transform .16s ease; }
.p2-grid .p2-card:hover { box-shadow: var(--sh-2); }
.p2-grid .p2-card[draggable="true"] { cursor: grab; }
.p2-grid .p2-card[draggable="true"]:active { cursor: grabbing; transform: scale(.995); }
.p2-grid .p2-card[draggable="true"]::before {
  content: "⠿"; position: absolute; top: 10px; right: 12px;
  color: var(--faint); font-size: 14px; letter-spacing: -1px;
}

.p2-card-h { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; }
.p2-card-t { font-weight: 600; color: var(--text); font-size: 14px; }
.p2-badge {
  font-size: 12px; padding: 1px 8px; border-radius: 8px;
  background: var(--surface-2); color: var(--muted-strong);
  border: 1px solid var(--border);
}
.p2-state-ok .p2-badge     { color: var(--ok);   background: var(--ok-bg);   border-color: var(--ok-bd); }
.p2-state-partial .p2-badge{ color: var(--warn); background: var(--warn-bg); border-color: var(--warn-bd); }
.p2-state-no_source, .p2-state-empty { background: var(--surface-2); }
.p2-state-no_source .p2-badge, .p2-state-empty .p2-badge { color: var(--muted); }

.p2-val { font-size: 14px; color: var(--text); word-break: break-word; }
.p2-note { font-size: 12px; color: var(--muted); margin-top: 8px; line-height: 1.55; }
/* 「暂无数据源」是**显式空态**，不是留白：给虚线框 + 明确文案，防止被读成 0 */
.p2-empty {
  font-size: 12px; color: var(--muted-strong);
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  padding: 8px 8px; margin-top: 8px; background: var(--surface-2);
}
.p2-actions { margin-top: 8px; display: flex; gap: 8px; }
.p2-list { margin: 8px 0 0; padding-left: 16px; font-size: 12px; color: var(--muted-strong); }
.p2-list li { margin: 3px 0; }

.p2-table { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 8px; }
.p2-table th { text-align: left; color: var(--muted); font-weight: 600; padding: 8px 8px;
  border-bottom: 1px solid var(--border); }
.p2-table td { padding: 8px 8px; border-bottom: 1px solid var(--border); color: var(--text); }
.p2-table tbody tr:nth-child(even) { background: var(--zebra); }

/* 售前/售中/售后 三段 + 闸门 */
.p2-flow { margin-top: 8px; border-top: 1px dashed var(--border); padding-top: 8px; }
.p2-seg { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
.p2-seg-t { font-size: 12px; font-weight: 600; color: var(--text); min-width: 38px; }

/* 新建项目表单 / 流程推进单步表单（B1~B12 的 HTTP 入口 UI） */
.p2-form { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: flex-end; margin-top: 4px; }
.p2-field { display: flex; flex-direction: column; gap: 3px; flex: 1 1 104px; min-width: 0; }
.p2-field-k { font-size: 12px; color: var(--muted); letter-spacing: .2px; }
.p2-field .nf-num { padding: 8px 8px; border-radius: var(--r-sm); font-size: 12px; min-width: 0; }
.p2-adv {
  margin-top: 8px; padding: 8px 8px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--zebra);
  display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center;
}
.p2-adv-t { flex: 1 1 100%; font-size: 12px; font-weight: 600; color: var(--text); }
.p2-adv .nf-num { padding: 8px 8px; border-radius: var(--r-sm); font-size: 12px; }
.p2-adv .p2-adv-json { flex: 1 1 100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.p2-adv .p2-note { flex: 1 1 100%; margin: 0; }

/* 缺员工种红条（常驻，不静默） */
.p2-alert {
  border: 1px solid var(--err-bd); background: var(--err-bg); color: var(--err);
  border-radius: var(--r); padding: 8px 12px; font-size: 12px; line-height: 1.6;
}

.p2-x {
  position: absolute; top: 8px; right: 34px; border: 0; background: transparent;
  color: var(--faint); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 4px;
}
.p2-x:hover { color: var(--err); }
/* 看板重排按钮（批次 38 · WCAG 2.2 SC 2.5.7）：**24×24 起**，不依赖
   `.p2-x` 那条「2.5.8 Spacing 例外」——重排是本节新增的**唯一**非拖拽入口，
   点击目标做足尺寸比省几个像素重要。 */
.p2-mv { display: inline-flex; gap: 4px; margin-top: 8px; margin-left: 6px; vertical-align: top; }
.p2-mvb {
  min-width: 24px; min-height: 24px; padding: 0;
  font-size: 13px; line-height: 1;
  color: var(--muted-strong); background: var(--field);
  border: 1px solid var(--border); border-radius: var(--r-sm); cursor: pointer;
}
.p2-mvb:hover:not([disabled]) { color: var(--accent); border-color: var(--accent); }
.p2-mvb[disabled] { opacity: .4; cursor: default; }
.p2-span {
  margin-top: 8px; font-size: 12px; color: var(--muted-strong);
  background: var(--field); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 2px 8px;
}

/* 看板卡片的键值行（替代 JSON dump）：键在左灰字，值在右主色字，
   一眼能扫；长值允许换行不撑破卡片 */
.p2-kv { display: flex; flex-direction: column; gap: 4px; margin-top: 2px; }
.p2-kv-row { display: flex; align-items: baseline; gap: 8px; font-size: 14px; }
.p2-kv-k { color: var(--muted); flex: 0 0 auto; min-width: 84px; font-size: 12px; }
.p2-kv-v { color: var(--text); font-weight: 600; word-break: break-word; }
/* 2026-09-26：原 content:"暂无数据源" 是硬编码中文，五语用户全看中文。
   实际 JS（app.js p2Kv）已保证 span 永不为空，这条是兜底；
   兜底也必须是**语言中性**的，故改为长破折号。 */
.p2-kv-v:empty::after { content: "—"; color: var(--muted-strong); font-weight: 400; }

/* ---------- G10j 头部两列重排（2026-09-15 老板：上面太挤，重排 2 排）----------
   只动版式：达人资料区 2 列网格；合作评估 / Expected rate 独立成 hero 两列。
   取值口径、三态纪律、i18n 文案一字未动。 */
.tto-hmeta {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 8px; row-gap: var(--row-gap);
  margin-top: 12px;         /* G10k：去掉顶部三行备注后，头部与资料区之间留出合理间隔 */
  min-width: 0;
}
.tto-hmeta .tto-field {
  flex-direction: column; align-items: flex-start; gap: 4px;
  min-width: 0; max-width: 100%;
  padding: 8px 8px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2);
}
.tto-hmeta .tto-field .tto-k { min-width: 0; font-size: 12px; letter-spacing: .02em; }
.tto-hmeta .tto-field .tto-v { width: 100%; font-size: 14px; }
.tto-hmeta .tto-field .tto-v.missing { align-self: stretch; }

.tto-hero {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px; margin-top: 8px; min-width: 0;
}
.tto-hero .tto-field {
  flex-direction: column; align-items: flex-start; gap: 8px;
  min-width: 0; max-width: 100%;
  padding: 12px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2);
}
.tto-hero .tto-field .tto-k { min-width: 0; font-size: 12px; letter-spacing: .02em; }
.tto-hero .tto-score { font-size: 22px; }
/* 长金额（如 52,401,899）不许顶到边：字号收一档 + 允许断行 */
.tto-hero .tto-rate-num { font-size: 20px; overflow-wrap: anywhere; line-height: 1.15; }

/* 窄容器（抽屉在手机上）回落单列，避免两列挤爆 */
@media (max-width: 520px) {
  .tto-hmeta, .tto-hero { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   G10m（2026-09-15）筛选器按 5 簇重排（设计 §5.1/§5.2）
   ① 默认区 = 6 个默认展开控件，按决策链顺序排成 5 张簇卡
   ② 「更多指标」 = 其余指标按同一套簇名分组，折叠收纳
   一律复用既有变量与既有 .cf-* 行样式，不新造视觉语言；窄屏单列不横向溢出。
   ========================================================================== */
#filter-topbar .f-default,
#filter-topbar .f-more { grid-column: 1 / -1; }
#filter-topbar .f-default {
  display: grid;
  /* 三层重构（2026-09-16）：桌面**固定 3 列**分组（设计 §二.3），不再 auto-fit ——
     auto-fit 在 1440px 下会铺成 4~5 列，把「规模 → 对口 → 成交/风险」的阅读顺序打散。 */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px 16px;
  align-items: start;              /* 各簇卡按自身高度排布，不被最高的一列拉出一片空白 */
}
#filter-topbar .f-default .f-cluster {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 8px 12px 12px;
}
/* 簇卡里的行改成「标题在上、控件在下」—— 230px 窄列放不下 64px 定宽标签 + 双输入框 */
#filter-topbar .f-default .cf-row,
.f-more-grid .cf-row { flex-direction: column; align-items: stretch; gap: 4px; }
#filter-topbar .f-default .cf-k,
.f-more-grid .cf-k { flex: none; font-size: 12px; }
#filter-topbar .f-default .nf-inputs,
.f-more-grid .nf-inputs { flex-wrap: wrap; }
#filter-topbar .f-default .chip-group,
.f-more-grid .chip-group { flex-wrap: wrap; }

.f-cluster { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.f-cluster-wide { grid-column: 1 / -1; }
.fc-title {
  display: flex; align-items: center; gap: 8px; margin: 0;
  font-size: 12px; font-weight: 600; color: var(--text);
  padding-bottom: 4px; border-bottom: 1px solid var(--border);
}
.fc-title::before {
  content: ""; width: 3px; height: 11px; border-radius: 4px;
  background: var(--accent); flex-shrink: 0;
}
.fc-body { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
/* 簇卡内的子分组（粉丝数档位块）去掉二次留白，避免套娃感 */
#filter-topbar .f-default .fc-body > .f-group.fg { background: transparent; }

/* 「更多指标」折叠区：标题行 + 两列自适应分组网格 */
#filter-topbar .topbar-body .f-more {
  border-top: 1px solid var(--border);
  padding-top: 12px;
  margin-top: 2px;
}
.f-more-grid {
  display: grid;
  /* 进阶层同样是桌面 3 列；高度由「进阶层内部滚动」兜住，不把整页推长（设计 §二.2） */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px 16px;
  margin-top: 8px;
}

/* 快捷档按钮（分位型指标：代理商只会点「前 25%」「高于同行」，不会算分位数 §5.4） */
.qbtns { display: flex; flex-wrap: wrap; gap: 8px; }
.qbtn {
  font: inherit; font-size: 12px; line-height: 1;
  padding: 4px 8px; border-radius: 8px; cursor: pointer;
  color: var(--muted-strong); background: var(--surface);
  border: 1px dashed var(--border-strong);
  transition: color var(--duration-fast, .15s), border-color var(--duration-fast, .15s);
}
.qbtn:hover { color: var(--accent); border-color: var(--accent); }
.qbtn.is-on {
  color: var(--accent); border-style: solid; border-color: var(--accent);
  background: var(--accent-weak); font-weight: 600;
}
.qbtn:focus-visible { outline: none; box-shadow: var(--ring); }

@media (max-width: 720px) {
  #filter-topbar .f-default,
  .f-more-grid { grid-template-columns: minmax(0, 1fr); }
}

/* 「内容标签」Top 20 + 搜索（§5.1）：搜索框在上、chips 在下，剩下的靠关键词捞 */
.tag-wrap { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.tag-search {
  width: 100%; height: 30px; font-size: 12px; text-align: left;   /* 统一 30px */
  padding: 4px 8px; border-radius: 8px;
}
.tag-hint { font-size: 12px; color: var(--faint); }

/* ==========================================================================
   A 版期二 · 4 —— 批量操作条（勾选后从底部固定浮出）
   出现条件：有勾选（.is-on）；未勾选 = display:none（**不占位**，列表底部不留白）。
   位置：viewport 固定底边，居中、限宽，与内容区同宽感；底部安全区用 env()。
   ========================================================================== */
.batch-bar {
  display: none;
  position: fixed;
  left: 50%;
  bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 75;                     /* 浮在列表之上、抽屉(.drawer 80)之下 */
  align-items: center;
  gap: var(--sp-2);
  max-width: calc(100vw - 2 * var(--sp-4));
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--sh-weak);
}
.batch-bar.is-on { display: flex; }
.batch-count {
  font-size: var(--fs-14);
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.batch-gap { flex: 1 1 auto; min-width: var(--sp-2); }
.batch-btn { padding: 8px 12px; font-size: var(--fs-14); white-space: nowrap; }
.batch-btn svg.star-ic { flex: 0 0 auto; }
/* 窄屏：文案与三个按钮换行也不溢出 */
@media (max-width: 599.98px) {
  /* 窄屏整条铺开，但给右下角的流程 FAB 让出位置（否则会被操作条压住） */
  .batch-bar.is-on { flex-wrap: wrap; justify-content: center; }
  .batch-bar { left: var(--sp-2); right: calc(var(--sp-6) + var(--sp-4)); transform: none; max-width: none; }
}

/* ==========================================================================
   筛选面板三层重构（2026-09-16）
   依据：/tmp/filter_drawer_audit.md（34 条不合理）+ /tmp/gpt6_filter_design.md（三层方案）
   结构：核心层（默认可见 12 项）/ 进阶层（「更多筛选」，26 项，内部滚动）/
        折叠层（进阶层内再展开 10 项 + 2 组整组折叠）
   规矩：① 只用既有 token（双主题自动同步，没有一个写死的颜色）
        ② 正文 ≥13px、可点区域 ≥40×40、表格行高 ≥40px
        ③ 移动端不横向滚动（窄屏退一列，控件一律自适应宽度）
   ========================================================================== */

/* ── 分组标题行：折叠开关 + 已选计数 + 一键清空 ─────────────────────────── */
#filter-topbar .fc-title { gap: 8px; }
.fc-fold {
  display: flex; align-items: center; gap: 8px; min-width: 0; min-height: 24px;
  font: inherit; font-size: 13px; font-weight: 600; color: var(--text);
  background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
}
.fc-fold > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fc-fold:hover { color: var(--accent); }
.fc-fold:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-sm); }
.fc-fold::after {                     /* 折叠态指示：不用图标字体，纯 CSS 三角 */
  content: ""; flex-shrink: 0; width: 0; height: 0;
  border-left: 4px solid var(--faint); border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent; transition: transform .15s ease;
}
.fc-fold[aria-expanded="true"]::after { transform: rotate(90deg); }
.fc-count {
  flex-shrink: 0; font-size: 12px; font-weight: 600; line-height: 1;
  padding: 2px 6px; border-radius: 999px;
  color: var(--accent); background: var(--accent-weak);
}
.fc-count.hidden { display: none; }
.fc-clear {
  margin-left: auto; flex-shrink: 0; font: inherit; font-size: 12px; line-height: 1;
  padding: 4px 6px; min-height: 24px; border-radius: var(--r-sm); cursor: pointer;
  color: var(--faint); background: none; border: 1px solid transparent;
}
.fc-clear:hover { color: var(--err); border-color: var(--err-bd); background: var(--err-bg); }
.fc-clear:focus-visible { outline: none; box-shadow: var(--ring); }
.fc-clear.hidden { display: none; }
/* 折叠态：只留标题行（设计目标「低频折叠组每组标题高度 40–48px」） */
.f-cluster[data-collapsed="1"] > .fc-body { display: none; }
.f-cluster[data-collapsed="1"] { padding-bottom: var(--sp-1); }
/* 2026-09-26：6px 不在 --sp 刻度(4/8/12/16/24/32)里，是野值。
   这条规则此前从没生效过（data-collapsed 从未被写上），2026-09-26 落实默认折叠后
   才被激活 → 设计系统闸门实测 P1 野值×4。取 --sp-1(4px)，与折叠态「标题高 40–48px」
   的紧凑目标一致（6→4 差 2px，肉眼不可辨）。 */
.f-cluster-wide { grid-column: 1 / -1; }

/* ── 进阶层：**面板内部滚动**（不让整页被面板推长）────────────────────
   为什么滚动容器是 `.topbar-body` 而不是进阶层自己：
   `#filter-topbar` 在 `.main-body`（`overflow: hidden`，高 = 视口）里是 `flex: 0 0 auto`，
   **超出部分既看不见、也滚不到**（实测：放开到 1222px 后 `documentElement.scrollHeight`
   仍 = 900，面板底部 380px 永久不可达，底部提示 / 折叠层控件点不到）。
   所以高度必须封在「一屏内」，滚动只能有一层：
     · `.topbar-body` 是唯一滚动容器（`max-height: max(220px, calc(100dvh - 600px))`，见文件上方；
       批次 43 起预留量由 240px 提到 600px（实测：400px 时桌面只露出 16px、移动端仍被挤出））；
     · 进阶层不再建第二个滚动条 —— 两层嵌套滚动在小屏上极难操作。
   代价：展开后整页仍是 ~0.8 屏而不是设计稿的 1.4~1.6 屏 —— 那个数字在本容器里
   **物理上达不到**（把面板推到 1.4 屏就必然裁掉内容），已在报告 §未做/偏差 里写明。 */
#filter-topbar .topbar-body .f-more > .fg-body {
  max-height: none;
  overflow-y: visible;
}
#filter-topbar .topbar-body {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
#filter-topbar .topbar-body .f-more > .fg-body::-webkit-scrollbar { width: 10px; }
#filter-topbar .topbar-body .f-more > .fg-body::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}
/* 反例四的逃生口：底部渐隐 + 「还有更多条件」，避免用户以为筛选项已经结束 */
.f-more-scroll-hint {
  grid-column: 1 / -1;               /* 面板体是网格：不横跨就会占掉一列 */
  position: sticky; bottom: 0; margin: 0; padding: 6px 0 2px;
  font-size: 12px; color: var(--faint); text-align: center;
  background: linear-gradient(to bottom, transparent, var(--surface) 60%);
  pointer-events: none;
}
.f-more-scroll-hint.hidden { display: none; }

/* ── 组内子折叠（折叠层）────────────────────────────────────────────── */
.f-sub {
  border: 1px dashed var(--border); border-radius: var(--r);
  padding: var(--sp-2); background: var(--surface-2);
}
.f-sub > .f-title { font-size: 12px; color: var(--muted-strong); }
.f-sub > .fg-body { padding-top: var(--sp-2); }

/* ── 范围控件：最小值 / 最大值 + 快捷档 + 非法值提示 ─────────────────── */
.cf-range { display: flex; flex-direction: column; gap: 8px; min-width: 0; width: 100%; }
.cf-range .nf-inputs { min-width: 0; }
.cf-range .nf-num { flex: 1 1 0; min-width: 0; width: auto; }
.cf-unit { margin-left: 4px; font-size: 12px; color: var(--faint); }
.cf-err {
  margin: 0; font-size: 12px; line-height: 1.35; color: var(--err);
  background: var(--err-bg); border: 1px solid var(--err-bd);
  border-radius: var(--r-sm); padding: 4px 6px;
}
.cf-err.hidden { display: none; }
/* 非法值：输入框即时描红（app.js 在 input 事件里挂 .is-invalid） */
.cf-range input.is-invalid,
.cf-row input.is-invalid { border-color: var(--err-bd); background: var(--err-bg); }

/* ── 全量态适配（TASK-20260921-115）：行内滑竿 / 等级滑竿 / 非必要项不上屏 ──────
   滑竿轨道与区间读值**不新增一行样式**：直接复用既有 `.nf-ranges` / `.nf-range` /
   `.nf-cur`（style.css:762 起）—— 那套的颜色、字号、轨道高度、thumb 都是既有 token。
   这里只加两处新布局，取值全部落回既有 8pt 刻度 {0,4,8,12,16,24,32} 与既定字阶： */
/* 行内滑竿容器：`.cf-range` 已是 flex column + gap 8px，插进去的 .nf-ranges 自然占满宽 */
.cf-range.nf .nf-ranges { margin-top: 0; }
/* 等级滑竿：`.cf-row` 本身 flex-wrap:wrap，用 flex-basis 100% 让它单独占一行，
   与上方 cf-k + 9 个 chip 不抢横向空间（不拆不改原有结构，只追加一个兄弟节点） */
.tier-slide {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);        /* 8px：与 .cf-range / .nf-inputs 同值 */
  margin-top: var(--sp-1); /* 4px：与 .nf-more[open] 同值的微间隔 */
}
/* 等级区间读值：数值域是 1~8（没有 0 这一档），故不复用 `.nf-cur`（那个下限空值显示 0），
   样式按 .nf-cur 逐值对齐（style.css:826）——字号/颜色/等宽数字都不新引入 token */
.tier-cur {
  font-size: var(--fs-label);      /* 12px */
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}
/* 非必要项不上屏：只隐藏，DOM 与 name 参数一个不删（详见 app.js 的 FP_NONMATERIAL） */

/* ── 口径说明小字（审计要求：每个被质疑的字段都写清时间窗口/覆盖率/口径）── */
.cf-note { margin: 0; font-size: 12px; line-height: 1.4; color: var(--faint); }
.f-sub > .fg-body > .cf-note { margin-bottom: 4px; }

/* ── 标签搜索框（多选可搜索 chip）──────────────────────────────────── */
.tag-wrap { display: flex; flex-direction: column; gap: 8px; width: 100%; min-width: 0; }
.tag-search { width: 100%; min-width: 0; font-size: 13px; }
.tag-search::-webkit-search-cancel-button { -webkit-appearance: none; }

/* ── 内部/兼容键区块（置灰 + 写明原因）：不进正常使用路径 ────────────── */
.f-cluster[data-group="legacy"] { background: var(--surface-2); border: 1px dashed var(--border); }
.f-cluster[data-group="legacy"] .cf-row { opacity: .75; }

/* ── 可点区域与字号（设计验收：正文 ≥13px、控件 ≥40×40）────────────── */
#filter-topbar .chip { min-height: 32px; }
/* 2026-09-17 taste 审计 C4：同一页面里 .chip-text 此前 12px/13px 两档并存（这里 13px、
   其余 6 处 12px）→ 统一回 12px，与 .chip-text 基础档一致。 */
#filter-topbar .fc-body .chip .chip-text { font-size: 12px; }
#filter-topbar .cf-note,
#filter-topbar .cf-err,
#filter-topbar .cf-unit { font-size: 12px; }
#filter-topbar .qbtn { min-height: 30px; font-size: 12px; }
#filter-topbar .f-default .cf-k,
#filter-topbar .f-more-grid .cf-k { font-size: 13px; }

/* ── 响应式：1440 / 1280 / 1024 / 窄屏都**不横向滚动** ─────────────── */
@media (max-width: 1180px) {
  #filter-topbar .f-default,
  .f-more-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 收窄屏幕（≤1180）：面板体再收一点，给结果列表留位置。
     批次 43 更正：原值是 `calc(100dvh - 200px)` —— **比基准的 -240 更宽松**，
     面板反而更高，与这条注释的意图（"再收一点"）正相反。改为加大减数。 */
  #filter-topbar .topbar-body { max-height: max(220px, calc(100dvh - 600px)); }
}
@media (max-width: 767.98px) {
  #filter-topbar .f-default,
  .f-more-grid { grid-template-columns: minmax(0, 1fr); }
  .f-more-scroll-hint { display: none; }
  #filter-topbar, #filter-topbar .filter-row, #filter-topbar .topbar-body { max-width: 100%; overflow-x: hidden; }
  #filter-topbar .nf-num, #filter-topbar .chip, #filter-topbar .tag-search { max-width: 100%; }
}

/* ── 空态（无结果）放宽条件提示：app.js 在 #cards 为空时注入 ─────────── */
.empty-relax {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-top: 10px; font-size: 13px; color: var(--muted);
}
.empty-relax .er-btn {
  font: inherit; font-size: 13px; line-height: 1; padding: 8px 12px;
  min-height: 40px; border-radius: var(--r); cursor: pointer;
  color: var(--accent); background: var(--accent-weak); border: 1px solid transparent;
}
.empty-relax .er-btn:hover { border-color: var(--accent); }
.empty-relax .er-btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* ── 加载态：明确「正在查」而不是「没结果」──────────────────────────── */
#loadingBox.htmx-request { opacity: 1; }
#cards[aria-busy="true"] { opacity: .55; transition: opacity .12s ease; }

/* ---------- TASK-20260920-88：类似达人卡片块（A9–A14 · 1:1 还原 TTO 源站形态）----------
   源站：卡片**横向轮播**（右侧 `›` 翻页、一页 10 张），卡片上方**三档匹配度切换器**；
   卡片内自上而下 = 头像圆 · handle · 昵称 · 国家+国旗 · 右上匹配度徽标 · 三指标
   （粉丝 / 播放量中位数 / 互动率）· 3 个视频缩略图 · 「✦ 相似点」+ 说明句 · 费率行 ·
   「按其他地区查看」。证据：`/tmp/tto_src_text.txt:264-427` + 截图「类似达人」。
   纯 CSS（无外部字体/图片/CDN）：头像与缩略图是占位块，国旗是 Unicode 区域指示符。 */
.tto-sim { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0;
  /* 宽度必须**钉在容器上**：`100%` 是对包含块（抽屉内容区）解析 —— 实测不加这一条时
     整块会被 10 张卡的固有宽度撑到 2532px（抽屉只有 465px），轮播不但不滚动，
     还会把抽屉内容区撑出横向滚动条。 */
  width: 100%; max-width: 100%; }
.tto-sim-switch { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.tto-sim-pill {
  font: inherit; font-size: var(--fs-12); line-height: 1; padding: var(--sp-2) var(--sp-3); border-radius: 999px;
  color: var(--muted-strong); background: var(--surface-2); border: 1px solid var(--border);
  cursor: pointer; white-space: nowrap;
}
.tto-sim-pill:hover { border-color: var(--accent-line); color: var(--accent); }
/* TASK-20260921-107（缺陷第 2 项）：该档源站没给（面板里一条值都没有）→ pill 真禁用，
   `.tto-sim-pill:hover` 的 accent 反馈一并收掉，避免「看着能点、点了没反应」。 */
.tto-sim-pill.is-disabled,
.tto-sim-pill.is-disabled:hover { opacity: .45; cursor: not-allowed;
  color: var(--muted); border-color: var(--border); }
.tto-sim-pill.active {
  color: var(--accent); background: var(--accent-weak); border-color: var(--accent-line);
  font-weight: 600;
}
.tto-sim-pill:focus-visible { outline: none; box-shadow: var(--ring); }
.tto-sim-carousel { position: relative; min-width: 0; width: 100%; max-width: 100%;
  overflow: hidden; }
.tto-sim-track {
  display: flex; gap: var(--sp-2); min-width: 0; width: 100%; max-width: 100%;
  box-sizing: border-box; padding-bottom: 2px;
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth;
  scrollbar-width: thin;
}
.tto-sim-card {
  display: flex; flex-direction: column; gap: var(--sp-2); flex: 0 0 246px; max-width: 246px;
  scroll-snap-align: start;
  padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface);
}
.tto-sim-head { display: grid; grid-template-columns: 32px minmax(0, 1fr) auto;
  align-items: center; gap: var(--sp-2); }
.tto-sim-avatar {
  width: 32px; height: 32px; border-radius: 50%; background: var(--field);
  border: 1px solid var(--border);
}
.tto-sim-id { display: flex; flex-direction: column; min-width: 0; }
.tto-sim-handle {
  font-size: 13px; font-weight: 600; color: var(--text); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tto-sim-handle:hover { color: var(--accent); }
.tto-sim-handle:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-sm); }
.tto-sim-nick {
  font-size: var(--fs-12); color: var(--muted); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}
.tto-sim-badge {
  font-size: 13px; font-weight: 700; color: var(--accent); background: var(--accent-weak);
  border: 1px solid var(--accent-line); border-radius: var(--r-lg); padding: 2px var(--sp-2);
  font-variant-numeric: tabular-nums;
}
/* 三档匹配度：同一徽标里逐档显示（由 `.tto-sim[data-match]` 决定 —— 有值显值、
   该档没有值显 `—`，绝不拿综合档冒充另外两档） */
.tto-sim-s { display: none; }
.tto-sim[data-match="overall"] .s-overall,
.tto-sim[data-match="profile"] .s-profile,
.tto-sim[data-match="audience"] .s-audience { display: inline; }
.tto-sim-meta { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-12);
  color: var(--muted); }
.tto-sim-flag { font-size: var(--fs-14); line-height: 1; }
.tto-sim-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-2); padding: var(--sp-2) 0; border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border); }
.tto-sim-metric { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tto-sim-mv { font-size: 13px; font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums; }
.tto-sim-mk {
  /* 源站三指标是**完整标签**（粉丝 / 播放量中位数 / 互动率）；窄卡里「播放量中位数」
     放不下一行 → 允许换行，**绝不省略成「播放量中…」**（那是信息损失，源站没有）。 */
  font-size: var(--fs-12); color: var(--muted); line-height: 1.25; overflow-wrap: anywhere;
}
.tto-sim-thumbs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-1); }
.tto-sim-thumb {
  display: block; height: 52px; border-radius: var(--r); background: var(--field);
  border: 1px solid var(--border);
}
.tto-sim-reason { display: flex; flex-direction: column; gap: 2px; }
.tto-sim-reason-k { font-size: var(--fs-12); font-weight: 600; color: var(--muted-strong); }
.tto-sim-reason-k::before { content: "✦ "; color: var(--accent); }
.tto-sim-reason-v { font-size: var(--fs-12); line-height: 1.5; color: var(--text);
  overflow-wrap: anywhere; }
.tto-sim-rate { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap;
  font-size: var(--fs-12); color: var(--muted); }
.tto-sim-rate-v { font-size: 13px; font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums; }
.tto-sim-rate-cur { font-size: var(--fs-12); color: var(--muted); }
/* 「按其他地区查看」在源站是链接态；我方没有「其他地区」数据 → 非交互文本（不做假控件） */
.tto-sim-more { font-size: var(--fs-12); color: var(--accent); cursor: default; margin-top: auto; }
.tto-sim-nav {
  position: absolute; right: -10px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; border-radius: 50%; font: inherit;
  /* 2026-09-26（批次 8）：原为字面值 `18px`，理由是「U+203A 字形小、需光学补偿」。
     该理由被 `ui_taste_audit` 的 C1 判据否掉 —— C1 要求 style.css 里所有
     `font-size` 字面值必须 ∈ 字阶 {12,14,16,20,22}（13px 是已登记的正文例外档），
     而 `13px` 全文 12 处全部放行、`10.5px` 已修，**当时 C1 唯一的违规就是这一处 18px**。
     闸门优先于我的审美推测（本模型无图像输入，理由无法目视验证）。
     取更近的上一档 `--fs-20` 而非 `--fs-16`：两者与 18 都是 ±2px，但 16px 方向
     已在上面的历史判断里被排除，20px 保住箭头原有视觉权重，30px 圆钮不会溢出。 */
  font-size: var(--fs-20);
  line-height: 1; display: flex; align-items: center; justify-content: center;
  color: var(--text); background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--sh-1); cursor: pointer;
}
.tto-sim-nav:hover { border-color: var(--accent-line); color: var(--accent); }
.tto-sim-nav:focus-visible { outline: none; box-shadow: var(--ring); }

@media (max-width: 767.98px) {
  .tto-sim-card { flex-basis: 236px; max-width: 236px; }
  .tto-sim-nav { right: 0; }
  .tto-sim-thumb { height: 44px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   筛选器 v2（TASK-20260921-141）· 形态层样式（方案丁实施版）
   ──────────────────────────────────────────────────────────────────────────
   ① 档位按钮组 `.fp2-bands`：源站 4~5 档同构，单选、再点取消（= 不限）
   ② 自定义开关 `.fp2-custom`：每组「一套主控件 + 一个自定义区间」
   ③ 交互面积：筛选面板内可点击元素 ≥44×44px，控件正文 ≥13px（任务书硬约束）
   ④ 补采分诊入口 `.fp2-j4`：自造项也必须有**可见入口**（不得只靠藏）
   只用既有 token 与既有取值档（8px / 12px / 13px / 44px），不引外部字体、CDN。
   ══════════════════════════════════════════════════════════════════════════ */
.fp2-hide { display: none !important; }

.fp2-bands { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 4px 0 8px; }
.fp2b {
  display: inline-flex; align-items: center; justify-content: center;
  font: inherit; font-size: 13px; line-height: 1.2;
  min-height: 44px; min-width: 44px; padding: 12px 16px;
  border-radius: var(--r-lg); cursor: pointer;
  color: var(--muted-strong); background: var(--surface);
  border: 1px solid var(--border);
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.fp2b:hover { color: var(--accent); border-color: var(--accent); }
.fp2b.is-on {
  color: var(--accent); border-color: var(--accent);
  background: var(--accent-weak); font-weight: 600;
}
.fp2b:focus-visible { outline: none; box-shadow: var(--ring); }
.fp2b-any { border-style: dashed; border-color: var(--border-strong); }

.fp2-custom {
  display: inline-flex; align-items: center; justify-content: center;
  font: inherit; font-size: 13px; line-height: 1.2;
  min-height: 44px; min-width: 44px; padding: 12px 16px;
  border-radius: var(--r-lg); cursor: pointer;
  color: var(--muted-strong); background: var(--surface);
  border: 1px dashed var(--border-strong);
  transition: color var(--t-fast), border-color var(--t-fast);
}
.fp2-custom:hover { color: var(--accent); border-color: var(--accent); }
.fp2-custom[aria-expanded="true"] {
  color: var(--accent); border-style: solid; border-color: var(--accent);
  background: var(--accent-weak); font-weight: 600;
}
.fp2-custom:focus-visible { outline: none; box-shadow: var(--ring); }
.fp2-custom-body { margin-top: 8px; }

.fp2-j4 {
  display: inline-flex; align-items: center; justify-content: center;
  font: inherit; font-size: 13px; line-height: 1.2;
  min-height: 44px; padding: 12px 16px; border-radius: var(--r-lg);
  cursor: pointer; color: var(--muted-strong); background: var(--surface);
  border: 1px solid var(--border);
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.fp2-j4:hover { color: var(--accent); border-color: var(--accent); }
.fp2-j4.is-on {
  color: var(--accent); border-color: var(--accent);
  background: var(--accent-weak); font-weight: 600;
}
.fp2-j4:focus-visible { outline: none; box-shadow: var(--ring); }
#filter-row [data-fp2-j4="1"] { border-left: 2px solid var(--accent-line); padding-left: 8px; }

/* 触达面积 ≥44×44px：面板内所有可点击元素（含既有 chip / 快捷档 / 分组折叠 /
   清空本组 / 子折叠 summary / 自定义区间 summary）。文字随之 ≥13px。 */
#filter-row .chip-text,
#filter-row .qbtn,
#filter-row .nf-more-sum,
#filter-row .f-title,
#filter-row .fc-fold,
#filter-row .fc-clear,
#filter-row .f-sub > summary { min-height: 44px; }
/* ⚠ 字号口径（2026-09-21 实测踩到）：把 `.chip-text` 抬到 13px 会让
   `ui_taste_audit` 的 C4「同一 chip 组件字号唯一」报红（实测量字号集=[12px,13px]）。
   取舍：**几何**（触达面积 44px）按任务书抬到位；**字号**保持 chip 组件内唯一（12px，既有值）。
   新增控件（.fp2b/.fp2-custom/.fp2-j4）是**新组件**，正文 13px。 */
#filter-row .chip-text,
#filter-row .qbtn { padding: 15px 16px; }
#filter-row .chip-text,
#filter-row .qbtn,
#filter-row .fc-fold,
#filter-row .fc-clear,
#filter-row .f-title,
#filter-row .nf-more-sum { display: inline-flex; align-items: center; }
#filter-row .f-title,
#filter-row .nf-more-sum { display: flex; }

/* 触达面积补齐（TASK-20260921-141 · 闸门 J3 例外清单里的工具条项）：
   `.fps-btn`（T109 A/B 档位）/ `#reset-filter`（重置）/ `#topbar-toggle`（面板开合）
   实测 42×24 / 54×37.6 / 30×30，均 <44×44。它们**在筛选器改动面内**，按任务书步骤 3
   抬到 44px；导航页签（`.tab`，35×30 / 50×30）属导航不是筛选控件 → 登记为例外不修。 */
#filter-topbar .fps-btn,
#filter-topbar #reset-filter { min-height: 44px; min-width: 44px; flex-shrink: 0; }
/* ↑ `flex-shrink:0` 是 G10v 实测补的：`min-width` 只是**下限**，挡不住 flex 压缩 ——
   ≤899.98px 时 `#filter-topbar .fp-ops` 是 `width:100%`，行内只有 `.active-count`
   加了 `flex-shrink:0`，于是本按钮被压到 42px，英文 `Reset` 溢出 8px 被
   `#filter-topbar{overflow-x:hidden}` 裁掉（实测 need=50 have=42）。 */
/* `#topbar-toggle` **保留 30×30**，登记为 44px 例外：
   `ui_taste_audit` 的 F3「筛选工具条控件高度唯一（不参差）」实测口径**包含**
   `.topbar-toggle`（实测集 = search-input/topbar-toggle/more-btn/tab/nf-num/tag-search）。
   单独把它抬到 44px 会让工具条控件高度参差 → F3 报红（实测：82 PASS / 9 FAIL）。
   取舍：服从**既有**闸门约束（本任务不改判据），把它登记为例外项。
   `.fps-btn` / `#reset-filter` **不在** F3 的实测集里，故可以抬到 44px（J3 达标率因此上升）。 */


/* ══════════════════════════════════════════════════════════════════════
   输入框占位符（2026-09-26 显示修复）
   ──────────────────────────────────────────────────────────────────────
   此前全站没有任何 ::placeholder 规则 → 浏览器 UA 默认色 rgb(117,117,117)。
   按 --field 底色实算对比度：
       白天 #f6f6f8 → 4.269:1  ❌ 不达 AA(4.5)
       黑夜 #14161a → 3.931:1  ❌ 不达 AA(4.5)
   改用 --muted（主题作用域内自动切换）：
       白天 #4c5563 → 6.981:1  ✅
       黑夜 #8a8f98 → 5.574:1  ✅
   ⚠️ 不要用 --faint：它注释自称「对白 4.83:1 仍 ≥AA」，但对 --field 只有
      4.479:1（白天），**不达 AA**。
   ⚠️ opacity:1 是给 Firefox 的：它默认给占位符叠加不透明度，不写会再次变淡。
   ══════════════════════════════════════════════════════════════════════ */
::placeholder { color: var(--muted); opacity: 1; }

/* 批次 60：抽屉工具折叠区（流程链为主，工具收起） */
.drawer-tools { margin: 8px 0 4px; }
.drawer-tools-h {
  cursor: pointer;
  list-style: none;
  opacity: .75;
  font-size: 12px;
  letter-spacing: .04em;
}
.drawer-tools-h::-webkit-details-marker { display: none; }
.drawer-tools-h::before { content: "▸ "; }
.drawer-tools[open] .drawer-tools-h::before { content: "▾ "; }
.drawer-tools[open] .drawer-tools-h { opacity: 1; }

/* ═══════════════════════════════════════════════════════════════════════════
   批次 65（2026-09-29）：单行筛选器 —— 老板「筛选器最多一屏一排」。
   面板 DOM（#filter-body）一个字节不删：整块 CSS 隐藏，里面的控件值照常被
   hx-include="#filter-row" 收集提交（「未展示」≠「空值」）。
   ═══════════════════════════════════════════════════════════════════════════ */
#filter-topbar .topbar-body { display: none !important; }
/* 平台 tabs（99.7% TikTok）撤出单行；OOB 容器与 #platform-input 保留 */
#filter-topbar .fg-platform { display: none !important; }
/* 单行里操作区靠右 */
#filter-topbar .fp-ops { margin-left: auto; flex-shrink: 0; }

/* ---- 行上下拉（.fr-sel）：无 name 的编排控件，真值在 #filter-row 老控件 ---- */
#filter-topbar .fr-cell { display: flex; align-items: center; gap: 8px; flex: 0 2 auto; min-width: 0; }
#filter-topbar .fr-sel {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  height: 34px; padding: 0 24px 0 10px;
  border: 1px solid var(--border); border-radius: 8px;
  background-color: var(--surface, #fff); color: var(--text);
  font-size: 13px; font-weight: 500; line-height: 1; cursor: pointer;
  max-width: 150px; text-overflow: ellipsis;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='11' height='11' fill='none' stroke='%23888' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center;
}
#filter-topbar .fr-sel:hover { border-color: var(--accent); }
#filter-topbar .fr-sel:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
#filter-topbar .fr-sel.is-active { border-color: var(--accent); color: var(--accent); font-weight: 600; }

/* ---- 品类下拉（details 摘要 + chips 弹层）---- */
#filter-topbar .fg-category { flex: 0 1 auto !important; max-width: none !important; position: relative; }
#filter-topbar .fg-category .chip-group { flex-wrap: wrap !important; overflow: visible !important; }
#filter-topbar .fr-dd { position: static; }
#filter-topbar .fr-dd-sum {
  list-style: none; display: inline-flex; align-items: center; gap: 4px;
  height: 34px; padding: 0 10px; border: 1px solid var(--border); border-radius: 8px;
  font-size: 13px; font-weight: 500; cursor: pointer; color: var(--text);
  background-color: var(--surface, #fff); white-space: nowrap;
}
#filter-topbar .fr-dd-sum::-webkit-details-marker { display: none; }
#filter-topbar .fr-dd-sum:hover { border-color: var(--accent); }
#filter-topbar .fr-dd-sum:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
#filter-topbar .fr-dd[open] .fr-dd-sum,
#filter-topbar .fr-dd.is-active .fr-dd-sum,
#filter-topbar .fg-category.is-active .fr-dd-sum { border-color: var(--accent); color: var(--accent); font-weight: 600; }
#filter-topbar .fr-dd[open] .fr-caret { transform: rotate(180deg); }
#filter-topbar .fr-caret { flex: 0 0 auto; }
#filter-topbar .fr-dd-n {
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  /* 12px 是 --fs-label 下限（taste C1/C2）；11px 会被字阶闸门拦下（实测踩过） */
  background: var(--accent); color: #fff; font-size: 12px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}
/* 弹层**必须给宽度**：absolute + 无 width 会 shrink-to-fit 到 ~112px，
   里面的 chip 于是被挤成单列、纵向溢出（实测 9 个品类 = 494px 高塞进 300px 滚动框）。 */
#filter-topbar .fr-dd-body {
  position: absolute; z-index: 40; top: calc(100% + 6px); left: 0;
  background: var(--surface, #fff); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .14); padding: 12px;
  /* ⚠ 必须是**确定宽度**：`width: max-content` 下 `1fr` 轨道按各自 max-content 求解，
     三列会宽窄不一（老板实测「不和谐」）。定宽后 3 列才是真正等分。 */
  width: min(440px, calc(100vw - 32px));
}
/* chip 组走网格（品类是名义维度、个数固定），三列排开；高度上限随视口，
   不再用固定 300px —— 那会把「排不下」变成「出滚动条」的假溢出。 */
#filter-topbar .fr-dd-body .chip-group {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px; max-height: min(420px, calc(100vh - 200px)); overflow: auto;
}
/* 等宽格里长短标签观感一致：**外层的 label 与内层的药丸都要吃满格子**。
   ⚠ 可见药丸是 `.chip-text`（inline-flex + padding，宽度随内容）——
   只给 `.chip` 设 width:100% 的话，label 满了、药丸还是宽窄不一（老板实测截图）。
   与仓库既有写法一致：`.nf-bands .chip{flex:1 1 0}` + `.chip-text{text-align:center}`。 */
#filter-topbar .fr-dd-body .chip-group { align-items: start; }   /* 行高贴合内容，不被拉伸 */
#filter-topbar .fr-dd-body .chip-group > .chip { width: 100%; }
#filter-topbar .fr-dd-body .chip-group > .chip > .chip-text {
  width: 100%; box-sizing: border-box; justify-content: center; text-align: center;
  /* ⚠ 高度不要去"修"：实测药丸 47.6px 的来源是
     `#filter-row .chip-text{padding:15px 16px}`（面板里**刻意的 44px 触控目标**，
     与 taste C4 的字号口径同源，见 style.css:~4080 的注释）。
     下拉在 #filter-row 内 → 继承 44px 触达面积；这里只负责**等宽 + 居中**。 */
}
/* 窄屏：弹层右对齐 + 两列，绝不超出视口 */
@media (max-width: 720px) {
  #filter-topbar .fr-dd-body { left: auto; right: 0; width: calc(100vw - 32px); min-width: 0; }
  #filter-topbar .fr-dd-body .chip-group { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* ---- 窄屏换行降级（闸门只守 1440；更窄由 flex-wrap 自然换行）---- */
@media (max-width: 1200px) {
  #filter-topbar .fr-cell { flex-wrap: wrap; }
}

/* b65 行高口径：行上控件统一 34px（.fr-sel / .fr-dd-sum / .search-input），
   与 8px 上下 padding 一起构成 60~62px 的单行。 */
/* ⚠ #reset-filter 的 min-height:44px 是**刻意的触控目标**（WCAG 2.5.8 意图），
   不为了把 .fp-head 压到 60px 以下而砍掉它 —— 单行口径守「一排 + 高度合理」
   （8+8 padding + 44 = 60~62px），见 g10al 门禁 L1 的阈值与注释。 */
#filter-topbar .fp-ops .active-count { height: 34px; }
#filter-topbar .fg-search .search-input { height: 34px; }

/* ═══════════════════════════════════════════════════════════════════════════
   批次 66（2026-09-29）：状态列 2 枚徽标（合作 · TTO）+ 顶栏「市场」选择器
   + 筛选行「平台」多选下拉。
   ═══════════════════════════════════════════════════════════════════════════ */
/* ---- 合作：有合作=绿 / 非我方机构=灰 / 名单未读到=琥珀（fail-closed 的可见形态）---- */
.src-badge.coop-yes { border-color: var(--ok-bd); background: var(--ok-bg); color: var(--ok); }
.src-badge.coop-no { border-color: var(--border-strong); background: var(--surface-2); color: var(--muted-strong); }
.src-badge.coop-unknown { border-color: var(--warn-bd); background: var(--warn-bg); color: var(--warn); }
/* ---- TTO：入驻=accent / 未入驻=灰 ---- */
.src-badge.tto-in { border-color: var(--accent-line); background: var(--accent-weak); color: var(--accent); }
.src-badge.tto-out { border-color: var(--border-strong); background: var(--surface-2); color: var(--muted-strong); }

/* ---- 顶栏「市场」全局选择器（与语言选择器同高同风格，全局生效 + 记忆）---- */
.market-wrap { display: inline-flex; align-items: center; }
#market-select {
  border-radius: 8px; padding: 8px 12px; font-size: 12px; cursor: pointer;
  color: var(--muted); border: 1px solid transparent; background: transparent;
  max-width: 160px;
}
#market-select:hover, #market-select:focus { color: var(--text); border-color: var(--border-strong); }
#market-select.has-value { color: var(--accent); font-weight: 600; }

/* ---- 筛选行「平台」多选格位（复用 .fr-dd 弹层样式，与品类并列）---- */
#filter-topbar .fg-platform-multi { flex: 0 1 auto; min-width: 0; }

/* 旧「国家」列样式（.cell-ctry）随列删除保留不引用：面板/抽屉里仍有国家展示，删样式反而会波及 */

/* ═══ 批次 66C：顶栏控件同高 34px ═══════════════════════════════════════════
   design-review 审计实测：同一排里并存四种高度 —— 主题切换 30 / 市场 37 /
   语言 37 / 退出 37.6（.theme-chip 的 min-height 是当年为「≥24×24 点击目标」补的，
   不是它必须比别人矮 7px）。统一到筛选行控件同档 34px，间距节奏一致。
   作用域限定 #main-view .topbar：登录页的 .login-lang 不动。 */
/* 芯片 32 + 容器 1px 上下边框 = 34，与同排的市场/语言/退出同高
   （32 仍远高于 .theme-chip 注释里守的 24×24 点击目标下限）。 */
#main-view .topbar .theme-chip { min-height: 32px; }
/* 容器自带垂直 padding 会把整组垫高（实测 34+6=40）→ 只留水平 padding */
#main-view .topbar .theme-switch {
  align-items: center; padding-top: 0; padding-bottom: 0; box-sizing: border-box;
}
#main-view .topbar .lang-select,
#main-view .topbar #market-select,
#main-view .topbar #logout-btn {
  height: 34px; padding-top: 0; padding-bottom: 0; box-sizing: border-box;
}

/* ═══ 批次 68：下拉列数随条目数自适应（≤4 项走 2 列，弹层同步收窄）══════════════
   实测：平台 4 项按 3 列排 → 第二行一个孤儿 + 弹层空一大块（老板：「点平台时下拉框不对」）。
   品类 9 项 3 列正好。列数由 app.js 的 mkDdCols() 写 data-cols，这里只做样式。 */
#filter-topbar .fr-dd-body[data-cols="2"] { width: min(300px, calc(100vw - 32px)); }
#filter-topbar .fr-dd-body[data-cols="2"] .chip-group {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* ═══ 2026-10-02 筛选区合并（方案 A）：tab 面板（#filter-tabs-panel）退役，
   行样式改挂各下拉弹层容器（[data-ft-rows]）。行的 data-ft-* 语义不变
   （app.js 事件委托按属性走，与容器无关）；slider thumb 18→24px（F4 修复，
   对齐项目自己的 24px 触控下限）；行间虚线分隔（一个下拉里多行时不再糊成一片）。 */
#filter-topbar .fr-dd-rows .fr-dd-body { width: min(480px, calc(100vw - 32px)); }
/* 弹层锚点：新下拉容器必须自己当定位锚（品类有 .fg-category{position:relative}，
   这批新 cell 没有 → 弹层飞到整行头部，2026-10-03 用户实测）；弹层统一右对齐
   （右缘 = 触发器右缘），靠右的下拉（佣金/风险/更多指标）不再横向溢出视口。 */
#filter-topbar .fr-cell-dd { position: relative; }
#filter-topbar .fr-cell-dd .fr-dd-body { left: auto; right: 0; }
#filter-topbar .fg-platform-multi { position: relative; }
[data-ft-rows] { min-width: 0; }
[data-ft-rows] button { font: inherit; cursor: pointer; border: 1px solid var(--border); background: var(--surface); color: var(--text); border-radius: 6px; min-height: 32px; padding: 4px 10px; }
[data-ft-rows] button[aria-pressed=true] { color: var(--accent); background: var(--accent-weak); border-color: var(--accent-line); }
[data-ft-rows] [hidden] { display: none !important; }
[data-ft-rows] .ft-row { display: flex; align-items: center; gap: 8px; min-width: 0; min-height: 40px; margin-top: 4px; }
[data-ft-rows] .ft-row + .ft-row { border-top: 1px dashed var(--border); padding-top: 8px; margin-top: 8px; }
[data-ft-rows] .ft-label { flex: 0 0 96px; font-size: 13px; font-weight: 600; }
[data-ft-rows] .ft-cov { font-size: 12px; color: var(--muted); white-space: nowrap; }
[data-ft-rows] .ft-cov:empty { display: none; }
[data-ft-rows] .ft-fields { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
[data-ft-rows] .ft-choices { display: flex; gap: 6px; overflow-x: auto; white-space: nowrap; }
[data-ft-rows] .ft-choices button { flex-shrink: 0; font-size: 12px; }
[data-ft-rows] .ft-numbers { display: flex; gap: 4px; flex: 0 1 200px; min-width: 0; }
[data-ft-rows] input[type=number], [data-ft-rows] select { height: 32px; width: 100%; min-width: 0; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); color: var(--text); padding: 4px 8px; font: inherit; font-size: 13px; box-sizing: border-box; }
[data-ft-rows] .ft-numbers input { width: calc(50% - 3px); }
[data-ft-rows] select { width: auto; max-width: 160px; }
[data-ft-rows] :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
[data-ft-rows] .ft-slider { position: relative; height: 32px; flex: 1; min-width: 100px; background: linear-gradient(to right, var(--border) var(--ft-lo, 0%), var(--accent) var(--ft-lo, 0%), var(--accent) var(--ft-hi, 100%), var(--border) var(--ft-hi, 100%)) center/100% 4px no-repeat; }
[data-ft-rows] .ft-slider input { position: absolute; inset: 0; margin: 0; width: 100%; height: 32px; appearance: none; -webkit-appearance: none; background: transparent; pointer-events: none; }
[data-ft-rows] .ft-slider input::-webkit-slider-thumb { appearance: none; -webkit-appearance: none; width: 24px; height: 24px; border-radius: 50%; border: 2px solid var(--accent); background: var(--surface); pointer-events: auto; cursor: ew-resize; }
[data-ft-rows] .ft-slider input::-moz-range-thumb { width: 22px; height: 22px; border: 2px solid var(--accent); border-radius: 50%; background: var(--surface); pointer-events: auto; }
[data-ft-rows] .ft-slider input:focus-visible { outline: none; }
[data-ft-rows] .ft-slider input:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--accent); outline-offset: 3px; }
@media(max-width:1100px) {
  [data-ft-rows] .ft-fields { gap: 4px; }
  [data-ft-rows] .ft-label { flex-basis: 84px; }
  [data-ft-rows] .ft-numbers { flex-basis: 170px; }
}
@media(max-width:600px) {
  [data-ft-rows] .ft-row { display: grid; grid-template-columns: auto 1fr; gap: 4px; margin-top: 8px; }
  [data-ft-rows] .ft-label { font-size: 12px; }
  [data-ft-rows] .ft-cov { justify-self: end; }
  [data-ft-rows] .ft-fields { grid-column: 1/-1; display: flex; flex-wrap: wrap; gap: 4px; width: 100%; }
  [data-ft-rows] .ft-slider { min-width: 100px; flex: 1; }
  [data-ft-rows] .ft-numbers { flex: 1 1 120px; }
  [data-ft-rows] .ft-choices { flex-wrap: nowrap; }
  [data-ft-rows] select { max-width: 100%; }
}

/* Minimal dual-ended metric rows. Native thumbs own pointer/keyboard behavior. */
#filter-topbar.ft-metric-open { z-index: 75; }
#filter-topbar #fr-dd-more .fr-dd-body { width: min(400px, calc(100vw - 24px)); box-sizing: border-box; overflow-y: auto; overscroll-behavior: contain; }
/* 更多指标：中文标签短名等宽单行；清空按钮独占右侧 52px。 */
#fr-dd-more [data-ft-name="label"] { display: block; }
#fr-dd-more [data-ft-name="label"] > .ft-label { display: block; margin-bottom: 6px; }
#fr-dd-more [data-ft-options="label"] { flex-wrap: wrap; overflow: visible; white-space: normal; }
#fr-dd-more [data-ft-options="label"] button { box-sizing: border-box; max-width: 100%; min-width: 0; white-space: normal; overflow-wrap: anywhere; text-align: left; }
#fr-dd-more [data-ft-options="label"].ft-label-short { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; }
#fr-dd-more [data-ft-options="label"].ft-label-short button { width: 100%; padding: 4px 0; text-align: center; white-space: nowrap; }
[data-ft-rows] .ft-row.ft-metric { position: relative; display: block; padding-top: 4px; margin-top: 4px; }
.ft-metric-head { display: flex; align-items: center; gap: 6px; min-width: 0; min-height: 24px; margin-right: 52px; }
[data-ft-rows] .ft-metric .ft-label { flex: 1; min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
.ft-metric-preview { font-size: 12px; font-variant-numeric: tabular-nums; text-align: right; color: var(--accent); overflow-wrap: anywhere; }
[data-ft-rows] [data-ft-metric-clear] { position: absolute; top: 4px; right: 0; box-sizing: border-box; width: 44px; min-width: 44px; height: 44px; min-height: 44px; padding: 4px; font-size: 12px; }
.ft-metric-track { position: relative; height: 44px; margin: 0 52px 0 0; min-width: 0; background: linear-gradient(to right, var(--border) var(--ft-lo, 0%), var(--accent) var(--ft-lo, 0%), var(--accent) var(--ft-hi, 100%), var(--border) var(--ft-hi, 100%)) center/calc(100% - 44px) 3px no-repeat; }
.ft-metric-track::before, .ft-metric-track::after { content: ''; position: absolute; top: 50%; z-index: 2; box-sizing: border-box; width: 16px; height: 16px; border: 3px solid var(--accent); border-radius: 50%; background: var(--surface); transform: translate(-50%, -50%); pointer-events: none; }
.ft-metric-track::before { left: calc(var(--ft-lo, 0%) + var(--ft-min-inset, 22px)); }
.ft-metric-track::after { left: calc(var(--ft-hi, 100%) + var(--ft-max-inset, -22px)); }
.ft-metric-track input { position: absolute; top: 0; left: 0; margin: 0; padding: 0; border: 0; box-sizing: border-box; width: 100%; height: 44px; appearance: none; -webkit-appearance: none; background: transparent; pointer-events: none; touch-action: pan-y; }
.ft-metric-track input::-webkit-slider-thumb { appearance: none; -webkit-appearance: none; width: 44px; height: 44px; border: 0; border-radius: 50%; background: transparent; pointer-events: auto; cursor: ew-resize; touch-action: pan-y; }
.ft-metric-track input::-moz-range-thumb { width: 44px; height: 44px; border: 0; border-radius: 50%; background: transparent; pointer-events: auto; cursor: ew-resize; }
.ft-metric-track input::-webkit-slider-runnable-track { height: 44px; background: transparent; }
.ft-metric-track input::-moz-range-track { background: transparent; }
.ft-metric-track input:focus-visible { outline: none; }
.ft-metric-track:has(input[data-ft-metric-slide=min]:focus-visible)::before, .ft-metric-track:has(input[data-ft-metric-slide=max]:focus-visible)::after { outline: 2px solid var(--accent); outline-offset: 3px; }
.ft-metric-track:not(.ft-metric-overlap) input[data-ft-metric-slide=min] { clip-path: inset(0 calc(100% - var(--ft-mid, 50%)) 0 0); }
.ft-metric-track:not(.ft-metric-overlap) input[data-ft-metric-slide=max] { clip-path: inset(0 0 0 var(--ft-mid, 50%)); }
.ft-metric-overlap input[data-ft-metric-slide=min] { top: -12px; }
.ft-metric-overlap input[data-ft-metric-slide=max] { top: 12px; }
.ft-metric-overlap::before { top: calc(50% - 12px); }
.ft-metric-overlap::after { top: calc(50% + 12px); }
