/* ============================================================================
   COPTUS · SVE 单卡铺 —— 品牌视觉层
   落地依据（单一参照源）：
     ① 《卡普塔斯 · 品牌视觉研究笔记》v1 · 2026-08-31
        · 主色 #FFE000，结论：深色做底、黄做光（黄是电灯泡，不是墙面）
        · 面积法则 6:3:1（60% 中性深色 / 30% 浅色承载 / 10% 品牌黄）
        · 四条判死搭配：黄字白底、浅黄底黄、橙+黄、荧光绿+黄
        · 警告旗 V1（6:3:1 语义梯度）/ V2（45° hazard）/ V3（品牌光谱，纯装饰）/ V4（≤6px 降级）
        · 色版偏移只在浅底用 multiply；屏（暗底）走 screen 语法
     ② 《COPTUS ERP · UI 归一规范 阅读版 v1》
        · 语义色权威值 §2.1；按钮 L1/L2/L3 §6.2；选择控件 §6.4；属性徽章 §7.2/§7.4
   前台适配说明（唯一一处偏离，其余不回退）：
        · 规范 §6.2 的 L2「白底描边」定义在 ERP 浅色纸上；本站是品牌前台，
          按研究笔记「屏走深底+黄做光」改为深底描边，半径/字号/选中态语义不变。
        · 规范 §2.1 的 --orange 属 ERP 内部警示语汇；研究笔记明确「橙系一律踢出调色板」，
          故前台不引入橙，告警统一走砖红 #8B1E2D。
   ========================================================================= */

:root {
  /* ── 品牌核心（方案 A · 工业黑金）──────────────────────────── */
  --ink:        #141414;   /* 炭黑 · 主背景，承担 60% 面积 */
  /* ── 背景纹理（工艺试验 T01/T02 · 2026-09-20 接入）──────────
     程序化 SVG 噪声，零请求可无缝平铺：低频云斑给纵深、高频细颗粒给质感，
     与 body 的顶光 radial 组成「底色+软噪+颗粒+光向」四层模型。 */
  --tex-cloud: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27700%27%20height%3D%27700%27%3E%3Cfilter%20id%3D%27c%27%3E%3CfeTurbulence%20type%3D%27fractalNoise%27%20baseFrequency%3D%270.011%27%20numOctaves%3D%273%27%20stitchTiles%3D%27stitch%27%2F%3E%3CfeColorMatrix%20type%3D%27saturate%27%20values%3D%270%27%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%27100%25%27%20height%3D%27100%25%27%20filter%3D%27url%28%23c%29%27%20opacity%3D%270.5%27%2F%3E%3C%2Fsvg%3E");
  --tex-grain: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27220%27%20height%3D%27220%27%3E%3Cfilter%20id%3D%27g%27%3E%3CfeTurbulence%20type%3D%27fractalNoise%27%20baseFrequency%3D%270.9%27%20numOctaves%3D%272%27%20stitchTiles%3D%27stitch%27%2F%3E%3CfeColorMatrix%20type%3D%27saturate%27%20values%3D%270%27%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%27100%25%27%20height%3D%27100%25%27%20filter%3D%27url%28%23g%29%27%20opacity%3D%270.5%27%2F%3E%3C%2Fsvg%3E");
  /* --ink-2 的 RGB 三元组：渐变里要带 alpha 时只能用它（#hex 没法拆出 alpha）。
     🔴 改颜色只改这一行 —— 下面 --ink-2 由它派生，不会出现「面板 #141414 / 底 #1C1C1C」那种色差。 */
  --ink-2-rgb:  28, 28, 28;
  --ink-2:      rgb(var(--ink-2-rgb));   /* 次级容器 / 表头 */
  --ink-3:      #242424;   /* 卡面 / 浮层 */
  --ink-4:      #2E2E2E;   /* 分隔线 / 描边 */
  --gold:       #FFE000;   /* 品牌黄 · **当底色**用（金底黑字）。面积 10% 封顶 */
  /* 两个语义 token（2026-10-24 从 --gold / --ink 里拆出来）：
     · --gold-ink   ：金色**当文字**用。深色主题 = 原金色；浅色主题换成暗金（白底亮金只有 1.2:1）
     · --on-accent  ：压在金色/浅色**底**上的文字色。两个主题都保持深色 */
  --gold-ink:   #FFE000;
  --on-accent:  #141414;
  --gold-hover: #E6C800;   /* 主按钮 hover（笔记 §1 实战配方）*/
  --brand-2:    #b8932e;   /* 暗金 · 降级为 hover / 深底专用（规范 §6.3 双金收口）*/
  --paper:      #F5F5F0;   /* 米白 · 浅色承载面（黄字禁用此底）*/
  --paper-2:    #F7F6F2;   /* 浅色内容卡片底 */
  --concrete:   #6E6A63;   /* 水泥灰 · 降噪 */

  --text:       #F5F5F0;   /* 主要文字 */
  --text-2:     #C9C5BD;   /* 次要文字（笔记 §1 侧边栏/顶栏配方）*/
  /* 三级灰（2026-10-24 提亮一档）：原 #8A857D 压在 --ink-3(#242424) 上只有 4.24:1，
     差一口气到 AA。提到 #918C83 → 4.6:1，肉眼几乎看不出变化，但小字能读了。 */
  --text-3:     #918C83;   /* 三级 / 辅助 */
  --text-on-paper:      #2A2A2A;

  /* ── CMYK 错版四色（研究笔记 §3 四色定色）────────────────── */
  --c-cyan:  #00A8A8;   /* C · 青 H180° */
  --c-mag:   #E6007E;   /* M · 洋红 H327° */
  --c-yel:   #FFE000;   /* Y · 黄 · 恒定不动 */
  --c-key:   #141414;   /* K · 版墨 · 承载一切（前台未直接引用，四色成套保留）*/
  --brick:   #8B1E2D;   /* 砖红 · 告警 / 危险（方案 E，只配做 5% 点缀）*/

  /* ── 语义色（UI 归一规范 §2.1 权威值）────────────────────── */
  --red:     #E5484D;
  /* 2026-10-25：红字专用值。`--red` 同时当背景用（危险按钮白字），
     所以在深色底上当**文字**时永远差一口气（实测 3.97:1，AA 要 4.5）。
     拆一个只给文字的 token：深色底提亮、浅色底压深，两边都过 4.5，且不影响红底按钮。 */
  --danger-text: #FF7A7E;
  --green:   #2EA860;
  --blue:    #3b7ddd;

  /* ── 属性徽章（规范 §7.2 / §7.4，基底统一 r9 / 11px / 700 / 1px 框）── */
  --foil-n:  #9c6b3f;                       /* 平闪 N 普通 · 棕 */
  --lang-bg: #8c2a1c;                       /* 语言 · 牛血红 */
  --cond-nm: #FFE000;                       /* 品相 NM · 卡普黄底黑字 */
  --cond-sp: #7a5aa0;                       /* 品相 SP · 紫 */
  --cond-dmg: #b0b0b0;                      /* 品相 DMG · 灰 */

  /* ── 尺寸 ─────────────────────────────────────────────── */
  --wrap: 1180px;
  --r-l1: 10px;  --r-l3: 5px;  --r-tab: 9px;  --r-nav: 8px;
  --r-panel: 14px;                          /* 大面板 / 弹窗（.dk-sheet 等）*/
  --shadow-2: 0 8px 24px rgba(0,0,0,.28);
  --shadow-3: 0 18px 48px rgba(0,0,0,.42);
}

/* ==========================================================================
   0 · 基础
   ========================================================================== */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--ink);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
               "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
  font-size: 14px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
::selection { background: var(--gold); color: var(--on-accent); }

/* ── 滚动条（🔴 铁律 2026-10-16）────────────────────────────────────────
   用户原话：「这种样式的滑竿条绝对不能出现，一定要贴合主题」——
   指的是 Chrome/Safari 那根**系统默认浅灰滚动条**，深色弹窗里最扎眼（单卡弹窗右边缘先被点名）。
   全站**一处收口**：透明轨道 + 暗灰滑块 + 悬停转暗金 + 按住转品牌黄；细轨、圆角、留白。
   两套都写：Firefox 走 scrollbar-color/width，Chrome/Safari 走 ::-webkit-scrollbar。
   ⚠️ 别再给单个容器写滚动条样式 —— 以前散着 4 份（.filters-in / .up-grid / .fmodal-bd / .fmodal .lim-*），
      口径一定会漂，已全部删掉改吃这一份。
   ⚠️ 例外**只有一类**：横向可滑的导航条 —— 顶栏胶囊条 `.nav`，
      以及 2026-10-17 把二级导航压成横滑条后的 `.bnav` / `.bnav-my`
      （同一个理由：它们是可滑的导航条，不是内容区；留一根滚动条在那儿会很难看）。
      这三条之外**不许**再给任何容器单独写滚动条 —— `_verify_profile.cjs` 的
      「滚动条铁律」那组断言会红（它拿的是具名白名单，不是模糊匹配）。 */
html { scrollbar-color: var(--ink-4) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track,
::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--ink-4); border-radius: 99px;
  border: 3px solid transparent; background-clip: content-box;   /* 3px 透明边 = 视觉上更细 */
}
::-webkit-scrollbar-thumb:hover { background: var(--brand-2); background-clip: content-box; }
::-webkit-scrollbar-thumb:active { background: var(--gold); background-clip: content-box; }
::-webkit-scrollbar-button { display: none; height: 0; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 22px; }
.mono { font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; }
.num  { font-variant-numeric: tabular-nums; }
.muted { color: var(--text-3); }
.hidden { display: none !important; }

/* [hidden] 全站兜底 —— 必须带 !important。
   UA 样式表里的 [hidden]{display:none} 优先级低于任何作者样式，所以只要该元素被
   作者规则写过 display（.dk-env{display:grid} / .dk-toolbar{display:flex} / .dk-grid{display:grid}…），
   `el.hidden = true` 就完全不起作用，元素照样显示。在这一处收口，
   全站不再需要为每个容器手写「.xxx[hidden]{display:none}」。 */
[hidden] { display: none !important; }

/* ==========================================================================
   1 · 品牌元件
   ========================================================================== */

/* 1.1 警告旗 V1 —— 色序即严重度：黄(注意) → 砖红(危险) → 炭黑(终结)，60/30/10 */
.flag {
  height: 24px;
  background: linear-gradient(90deg, var(--gold) 0 60%, var(--brick) 60% 90%, var(--ink) 90% 100%);
}
.flag-v {                                    /* 列表行竖标 宽 3–4px */
  display: block;
  width: 4px;
  background: linear-gradient(180deg, var(--gold) 0 60%, var(--brick) 60% 90%, var(--ink) 90% 100%);
}
.flag-mini {                                 /* V4 小尺寸降级：≤6px 扔掉砖红，只留黄+黑 */
  height: 4px;
  background: linear-gradient(90deg, var(--gold) 0 85%, var(--ink) 85% 100%);
}
/* 🔴 售完卡的顶部色条**也是金色**（2026-10-21 用户：「售完的卡不加特效蒙版，
   和有库存的卡一模一样！」）。曾经有过一条 `.flag-mini.flag-out` 把它转灰，
   已删除 —— 别再按"售完要一眼可分"的思路加回来，那句要求的意思正好相反。 */
.flag-danger {                               /* V2 危险升级：45° hazard，全站最多 1–2 处 */
  height: 28px;
  background:
    linear-gradient(90deg, var(--brick) 0 22%, transparent 22%),
    repeating-linear-gradient(45deg, var(--ink) 0 9px, var(--gold) 9px 18px);
}
/* V3 品牌光谱旗 —— 严格等宽、色相单向巡回，纯装饰不承载语义 */
.flag-spectrum {
  height: 6px;
  background: linear-gradient(90deg,
    var(--c-yel) 0 25%, var(--c-cyan) 25% 50%, #2B1B54 50% 75%, var(--brick) 75% 100%);
}

/* 1.2 色版偏移（错版）—— 纸走 multiply，屏走 screen；偏移 2–6px，正文禁用 */
.plate {
  position: relative;
  display: inline-block;
  isolation: isolate;
  line-height: 1.05;
}
.plate > i {
  position: absolute;
  inset: 0;
  font-style: normal;
  mix-blend-mode: screen;          /* 暗底语法：颜色朝黑衰减而不是朝白 */
  pointer-events: none;
}
.plate > .base { position: relative; color: var(--text); }
.plate > .p-c { color: var(--c-cyan); transform: translate(-3px, -1px); }
.plate > .p-m { color: var(--c-mag);  transform: translate(2.6px, -2px); }
.plate > .p-y { color: var(--c-yel);  transform: translate(-0.6px, 2.8px); }
.plate-lg > .p-c { transform: translate(-5px, -1.6px); }
.plate-lg > .p-m { transform: translate(4.2px, -3.2px); }
.plate-lg > .p-y { transform: translate(-1px, 4.6px); }

/* 1.3 半调网点 —— 真实网屏角度，不透明度压到 15–25%，间距 ≥8px 防摩尔纹 */
.halftone {
  background-image:
    radial-gradient(circle at 2px 2px, rgba(0,168,168,.55) 1px, transparent 1.4px),
    radial-gradient(circle at 7px 6px, rgba(230,0,126,.5) 1px, transparent 1.4px),
    radial-gradient(circle at 4px 9px, rgba(255,224,0,.5) 1px, transparent 1.4px);
  background-size: 11px 11px, 12px 12px, 13px 13px;
  opacity: .22;
}

/* 1.4 套印色标（外框精确 + 内心错版 =「克制的错」）*/

/* ==========================================================================
   2 · 页头 / 页脚
   ========================================================================== */
/* sticky 挂在外层 #site-header 而不是 .topbar 自己（2026-09-20 修正）：
   sticky 的可用行程受「包含块底边」限制 —— .topbar 的父级 #site-header
   高度恰好等于顶栏自身（桌面 66px / 手机换行后 ~111px），顶栏在自身高度
   用尽后就被带走，滚一屏就消失、菜单入口全丢。把 sticky 上移到
   #site-header（body 直接子级、贯穿整页滚动范围）后行程恢复为整页，
   顶栏常驻吸顶。z-index 60 同步上移，弹层(100+)、筛选栏(20)层级不变。 */
#site-header { position: sticky; top: 0; z-index: 60; }
.topbar {
  background: rgba(20,20,20,.94);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--ink-4);
}
.topbar-in {
  display: flex; align-items: center; gap: 18px;
  height: 66px;
}
.brand { display: flex; align-items: center; gap: 11px; flex: none; margin-right: 6px; }
/* 页头只挂反白标准字（深底用），黑标原版仅用于纸质物料。
   伴随标准字的 .brand-txt / .brand-name / .brand-sub 三级文字标已随新版页头下线，
   样式一并删除（2026-09-19）。 */
.brand-logo {
  height: 30px; width: auto; display: block; flex: none;
}
.nav { display: flex; align-items: center; gap: 6px; margin-left: 8px; }
.nav-btn {                                   /* 选择控件 A 主导航 · radius 8 */
  /* 2026-10-26：元素从 <button> 换成 <a>（见 store.js renderHeader 注释）——
     这里补回 <a> 的默认表现（下划线 / 行内盒），视觉与按钮时代完全一致。 */
  display: inline-flex; align-items: center; text-decoration: none;
  padding: 8px 15px;
  border-radius: var(--r-nav);
  border: 1.5px solid transparent;
  background: transparent;
  color: var(--text-2);
  font-size: 13.5px; font-weight: 600;
  cursor: pointer;
  transition: .16s;
}
.nav-btn:hover { color: var(--text); border-color: var(--ink-4); }
.nav-btn.on {                                /* 选中态统一：金底黑字金边 */
  background: var(--gold);
  color: var(--on-accent);
  border-color: var(--gold);
}
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.cart-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 15px; border-radius: var(--r-nav);
  background: transparent; border: 1.5px solid var(--ink-4);
  color: var(--text); font-size: 13.5px; font-weight: 600; cursor: pointer;
  transition: .16s;
}
.cart-btn:hover { border-color: var(--gold); color: var(--gold-ink); }
.cart-count {
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: 999px;
  background: var(--gold); color: var(--on-accent);
  font-size: 11px; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center;
}

/* 2026-10-24 店主：「页脚那块底不要，跟页面一个底」。
   原来这里铺 `--ink-2` —— 浅色主题下是**纯白**、深色下是深面板，
   而页面本身是另一种色，于是页脚整块浮成一层"底图"。
   改成透明：只留顶部彩条 + 这条 1px 分隔线做边界，不再有整块色。
   🔴 改这里要同步 theme-light.css 里那条 `.footer` 覆盖，否则浅色主题又铺回来。 */
.footer {
  margin-top: 72px;
  background: transparent;
  border-top: 1px solid var(--ink-4);
}
.footer-in {
  display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 30px;
  padding: 40px 0 26px;
}
.footer h4 {
  margin: 0 0 12px; font-size: 12px; font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: var(--text-3);
}
.footer p, .footer li { color: var(--text-2); font-size: 13px; }
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { margin-bottom: 7px; }
.footer a:hover { color: var(--gold-ink); }
.footer-note {
  border-top: 1px solid var(--ink-4);
  padding: 16px 0 30px; font-size: 12px; color: var(--text-3);
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
}
/* ── 页脚 2026-10-24 重做时新增的三样（手机端另有整段覆盖，见 brand-touch.css C14）──
   ① 联系方式拆成「岗位 / 待补充」两栏：桌面同一行读完，手机上变成左右对齐的列表；
   ② `在地图中打开`：门店地址的下一步动作，原来只有一个不可点的纯文本地址；
   ③ `回到顶部`：长页面滚到底之后唯一的退路。 */
.footer li em { font-style: normal; color: var(--text-3); font-size: 12px; margin-left: 8px; }
.ft-act {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 34px; padding: 0 13px; margin-top: 4px;
  border: 1px solid var(--ink-4); border-radius: 8px;
  font-size: 12.5px; color: var(--text-2); background: transparent;
  transition: border-color .16s, color .16s;
}
.ft-act:hover { border-color: var(--gold); color: var(--gold-ink); }
.footer-top {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 34px; padding: 0 14px;
  border: 1px solid var(--ink-4); border-radius: 999px;
  background: transparent; color: var(--text-3);
  font-size: 12px; font-weight: 600; cursor: pointer;
  transition: color .16s, border-color .16s;
}
.footer-top:hover { color: var(--gold-ink); border-color: var(--gold); }

/* ==========================================================================
   3 · 按钮（UI 规范 §6.2 三档；L2 底色按前台暗面适配）
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: none; cursor: pointer; white-space: nowrap;
  transition: .16s; font-weight: 600;
  text-align: center;
}
.btn:disabled { opacity: .42; cursor: not-allowed; }

.btn.l1 {                                     /* L1 主按钮 · 金底黑字 */
  border-radius: var(--r-l1); padding: 12px 22px;
  font-size: 15px; font-weight: 600;
  background: var(--gold); color: var(--on-accent);
}
.btn.l1:hover:not(:disabled) { background: var(--gold-hover); }
.btn.l1.danger {                              /* 危险/不可恢复 = 红底白字，金只留给正向主操作 */
  background: var(--red); color: #fff;
}
.btn.l1.danger:hover:not(:disabled) { background: #cf3b40; }

.btn.l2 {                                     /* L2 次级 · 描边，选中态金底 */
  border-radius: var(--r-l1); padding: 10px 18px;
  font-size: 14px; font-weight: 600;
  background: transparent; color: var(--text);
  border: 1.5px solid var(--ink-4);
}
.btn.l2:hover:not(:disabled) { border-color: var(--brand-2); color: var(--gold-ink); }
.btn.l2.on { background: var(--gold); color: var(--on-accent); border-color: var(--gold); }

.btn.l3 {                                     /* L3 轻量 · 行内 */
  border-radius: var(--r-l3); padding: 4px 11px;
  font-size: 12px; font-weight: 600;
  background: transparent; color: var(--text-3);
  border: 1px solid var(--ink-4);
}
.btn.l3:hover { color: var(--gold-ink); border-color: var(--brand-2); }
.btn.l3.danger:hover { color: var(--red); border-color: var(--red); background: rgba(229,72,77,.10); }

.btn.block { width: 100%; }

/* 分段控件 C · 外容器 8px，内按钮直角借裁切，选中深墨底白字 */
.seg {
  display: inline-flex; border-radius: var(--r-nav);
  border: 1px solid var(--ink-4); overflow: hidden;
}
.seg button {
  border: none; background: transparent; color: var(--text-2);
  padding: 7px 13px; font-size: 12.5px; font-weight: 700; cursor: pointer;
  border-radius: 0; transition: .14s;
}
.seg button + button { border-left: 1px solid var(--ink-4); }
.seg button.on { background: var(--ink); color: #fff; }

/* 数量步进器 · 详情页购买数量（− 输入框 +）
   与 .seg 同一套描边/半径语汇；上限 = 当前库存，禁用态由脚本联动。
   中间是真输入框：可直接键入、支持上下键，回车或失焦归一到 1 ~ 库存。 */
.stepper {
  display: inline-flex; align-items: stretch; height: 38px;
  border: 1px solid var(--ink-4); border-radius: var(--r-nav);
  background: var(--ink-2); overflow: hidden;
}
.stepper button {
  width: 38px; border: none; background: transparent; color: var(--text);
  font-size: 17px; font-weight: 800; line-height: 1; cursor: pointer;
  border-radius: 0; transition: .14s;
}
.stepper button:hover:not(:disabled) { background: var(--ink-4); color: var(--gold-ink); }
.stepper button:disabled { color: var(--text-3); opacity: .4; cursor: not-allowed; }
.stepper input {
  width: 54px; min-width: 0; border: none; background: transparent; text-align: center;
  border-left: 1px solid var(--ink-4); border-right: 1px solid var(--ink-4);
  font-size: 14px; font-weight: 800; letter-spacing: .02em; color: var(--text);
}
.stepper input:focus { outline: none; background: rgba(255,224,0,.08); }
.stepper input::-webkit-outer-spin-button,
.stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.stepper input[type=number] { -moz-appearance: textfield; }

/* 数量上限提示 · 只在库存有限（≤5 张）时跟在步进器后面，说明为什么 + 点不动了 */
.qty-cap {
  display: inline-flex; align-items: center; font-size: 11.5px; font-weight: 700;
  color: var(--text-3); letter-spacing: .02em;
}

/* ── 关联卡 · 效果文本里引用到的卡 ────────────────────────────────
   缩略卡：卡图 + 卡名 + 价格（同名多印版时右槽标「N 印版」）。
   auto-fill 让列数自己跟着详情栏宽度走（1440 约 6 列，390 约 3 列），不用写媒体查询。 */
.ref-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
}
.ref-card {
  border: 1px solid var(--ink-4); border-radius: var(--r-tab);
  background: var(--ink-2); padding: 8px; min-width: 0;
  transition: .16s;
}
.ref-card:hover { border-color: var(--gold); transform: translateY(-2px); }
.ref-thumb {
  position: relative; border-radius: 6px; overflow: hidden;
  background: #0d0d0d; aspect-ratio: 5 / 7;
}
.ref-thumb img { width: 100%; height: 100%; object-fit: cover; transition: .3s; }
.ref-card:hover .ref-thumb img { transform: scale(1.03); }
/* 关联卡不标售完（2026-10-21 用户：「售完的卡不加特效蒙版，和有库存的卡一模一样」）：
   这里曾有一条 `.ref-card.is-out .ref-thumb img { opacity: .45 }` 与 `.ref-out` 遮罩，
   已删除 —— 90px 宽的缩略卡盖上遮罩等于把卡面糊掉，能不能买点进去看。 */
.ref-name {
  font-size: 12px; font-weight: 700; line-height: 1.35; margin-top: 7px;
  min-height: 1.35em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* 同名卡选取里的编号行：同名卡之间靠 card_id（卡面印刷编码）区分 */
.ref-no {
  font-size: 11px; color: var(--text-2); margin-top: 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ref-foot {
  display: flex; align-items: baseline; justify-content: space-between; gap: 6px;
  margin-top: 5px;
}
.ref-foot .price { font-size: 12.5px; letter-spacing: 0; }
.ref-lbl { font-size: 10.5px; font-weight: 700; color: var(--text-3); white-space: nowrap; }

/* 详情页右栏的小标题：关联卡 / 进化形态 共用（字级与原先的内联写法完全一致）。
   「同名卡选取」保留自己的 26px 上间距，没有并进来。
   2026-09-19 后只剩两个用户：「补充文本」并入效果正文（.cardtext-sub），小标题一并撤销。 */
.ref-h3 {
  font-size: 13px; font-weight: 800; letter-spacing: .08em;
  color: var(--text-3); margin: 22px 0 10px;
}
/* 「关联卡」与「进化形态」并排一行（2026-09-19 用户拍板）：进化形态原来占页面底部
   一整条（一条里就一张缩略卡，右边全空），现在压缩成一张缩略卡挪到关联卡右边，
   底部那一条空出来给卡组区。flex-basis 200px 是按右栏实际宽度定的 ——
   1440 视口右栏 ≈706px → 两列各 ~340px；≤900 视口 .detail 变单列、右栏全宽，仍是两列；
   390 窄屏 ~358px 放不下两列会自动折成一列。 */
.ref-row { display: flex; flex-wrap: wrap; gap: 18px 26px; margin-top: 22px; }
.ref-col { flex: 1 1 200px; min-width: 0; }
/* 并排时两侧小标题要齐平，所以列内首个标题不带顶部留白（留白交给 .ref-row 的 margin-top） */
.ref-col > .ref-h3:first-child { margin-top: 0; }

/* 选项卡 B · radius 9，选中金底黑字 */
.tabs { display: flex; gap: 8px; flex-wrap: wrap; }
.tab {
  border-radius: var(--r-tab); padding: 8px 16px;
  border: 1.5px solid var(--ink-4); background: transparent;
  color: var(--text-2); font-size: 13px; font-weight: 700; cursor: pointer;
  transition: .15s;
}
.tab:hover { color: var(--text); }
.tab.on { background: var(--gold); color: var(--on-accent); border-color: var(--gold); }

/* 行内切换 D · pill 999 / chip 10 */
.pill {
  border-radius: 999px; padding: 5px 13px;
  border: 1px solid var(--ink-4); background: transparent;
  color: var(--text-2); font-size: 12px; font-weight: 700; cursor: pointer;
  transition: .14s;
}
.pill.on { background: var(--gold); color: var(--on-accent); border-color: var(--gold); }

/* ==========================================================================
   4 · 属性徽章（UI 规范 §7.2 配色 / §7.4 形状与宽度）
      统一基底：r9 · 11px/700 · 1px 框；宽度**由各档自己声明**
      （22 平闪单字 / 30 稀有度 / 32 双字工艺与语言 / 34 联动特殊 /
        40 闪版 / 42 活动卡与卡牌类型 / 54 流通品相），不用 min-width。
   ========================================================================== */
.badge {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 9px; font-size: 11px; font-weight: 700;
  height: 18px; line-height: 1; padding: 0 3px; flex: none;
  border: 1px solid transparent;
  letter-spacing: .02em;
  /* 🔴 徽章是"固定 18px 高的药丸"，文字一旦折行就会撑破它 ——
     实测：「主战者」三字在窄格子里被挤成三行（主/战/者），边框都穿到字上
     （2026-10-25 店主截图）。徽章永远单行，宁可溢出也不折。 */
  white-space: nowrap;
}

/* 平闪 foil · 徽章印中文：平/闪 单字 22px，蚀刻/全息 双字 32px。
   闪版底是浅粉→浅蓝渐变，白字在上面只有 1.9:1 —— 换成炭黑字（≈9.8:1）才读得清 */
.badge.foil-n { width: 22px; background: var(--foil-n); color: #fff; border-color: #7d5430; }
.badge.foil-f { width: 22px; color: var(--on-accent); border-color: #d08aa8;
  background: linear-gradient(135deg, #f7a8c4, #8fd0e6); }
.badge.foil-e { width: 32px; color: #fff; border-color: #64748b;
  background: linear-gradient(135deg, #94a3b8, #475569); }
.badge.foil-h { width: 32px; color: #fff; border-color: #5c7a63;
  background: linear-gradient(135deg, #7a5aa0, #2ea860); }

/* 语言 lang · 印中文（简中 / 日文 / 英文 / 其他），2 字 32px，牛血红 */
.badge.lang { width: 32px; background: var(--lang-bg); color: #fff; border-color: #6d1f14; }

/* 品相 condition · 三档（流通品相 / 瑕疵品 / 残品，2026-09-18 定稿）。
   宽度按字数给：流通品相四字 54px、瑕疵品与残品三字 42px —— 与卡牌类型徽章同规格。
   旧的 MP / HP / POOR 三档已废，配色与徽章一并删除（build_catalog 不再生成对应 SKU）。 */
.badge.cond-nm   { width: 54px; font-size: 10.5px; background: var(--cond-nm); color: var(--on-accent); border-color: var(--ink); }
.badge.cond-sp   { width: 42px; font-size: 10.5px; background: var(--cond-sp); color: #fff; border-color: #5f4480; }
.badge.cond-dmg  { width: 42px; font-size: 10.5px; background: var(--cond-dmg); color: #2A2A2A; border-color: #555; }

/* 稀有度 —— 色值全部取自品牌 CMYK 家族 / 规范语义色，避免引入新色相 */
.badge.rar-sp  { width: 30px; background: var(--c-cyan); color: #fff; border-color: #007b7b; }
.badge.rar-sl  { width: 30px; background: var(--gold); color: var(--on-accent); border-color: var(--ink); }
.badge.rar-ur  { width: 30px; background: var(--c-mag); color: #fff; border-color: #b0005f; }
.badge.rar-lg  { width: 30px; background: var(--brand-2); color: var(--on-accent); border-color: #8a6c1c; }
.badge.rar-gr  { width: 30px; background: var(--brick); color: #fff; border-color: #66141f; }
.badge.rar-sr  { width: 30px; background: var(--blue); color: #fff; border-color: #2a5da3; }
.badge.rar-br  { width: 30px; background: #4a4a4a; color: #e8e8e8; border-color: #2b2b2b; }
/* ┄┄ 字典扩充档：联动特殊 / 活动卡 一律沿用 CMYK 家族 + 中性灰，
      只做明度与描边区分，不新增色相 ┄┄ */
.badge.rar-ssp { width: 34px; border-color: var(--gold); color: var(--gold-ink);
  background: linear-gradient(135deg, #3a2f00, #141414); }
/* 活动卡 —— 编号段 PR，徽章走中文（42px 三字档，描边空档不做实底） */
.badge.rar-pr  { width: 42px; font-size: 10.5px; background: transparent; color: var(--text-2); border-color: var(--ink-4); }

/* 卡牌类型徽章（6 类）—— 稀有度留空的卡（主战者 76 / Token 286 / 进化点 56 等
   共 414 张）用它顶上徽章位。
   🔴 2026-10-25 店主：「像这种小图标要填充（像 LG 一样）重新设计一下」。
      原来类型是**描边空档 + 语义色文字**、稀有度是**实底色块**，靠这点一眼区分
      「这张卡卡面没印罕贵」。改成实底后这条区分没了 —— 换成**靠色相**：
      类型有自己固定的色相（石板灰/暗青/金/青铜/灰绿/洋红/绿），
      稀有度仍用品牌 CMYK 家族；而且一张卡只会出现其中一个徽章（不会并排），
      所以不会看混。
      每个色值都按 WCAG 算过（文字对底色 ≥4.5:1），填充色集中在上面的 `:root`，
      **不要在各个选择器里写死十六进制**。
   宽度 42px 与「活动卡」同规格，容得下最长的「衍生物」「进化点」。
   注：数据值是 'Token'，徽章上印的是卡面写法「衍生物」（store.js 的 CARD_TYPE_LABEL）。 */
:root {
  --t-follower: #54606A;   /* 随从 · 石板灰 */
  --t-spell:    #0F7A7A;   /* 法术 · 暗青（原 #00A8A8 压白字只有 3.5） */
  --t-amulet:   #B4891B;   /* 护符 · 亮金（压深字） */
  --t-leader:   #8A6C1C;   /* 主战者 · 青铜（与护符的金刻意拉开一档明度） */
  --t-token:    #5F7A70;   /* 衍生物 · 灰绿 */
  --t-evo:      #B0005F;   /* 进化点 · 洋红压深（原 #E6007E 压白字 3.9） */
  --t-equip:    #1F7A45;   /* 装备 · 绿（2026-10-25 起该分类并入衍生物，样式保留备用） */
  --t-other:    #6B6862;   /* 兜底 · 暖灰 */
}
.badge.type-follower { width: 42px; font-size: 10.5px; background: var(--t-follower); color: #fff; border-color: rgba(0,0,0,.28); }
.badge.type-spell    { width: 42px; font-size: 10.5px; background: var(--t-spell);    color: #fff; border-color: rgba(0,0,0,.28); }
.badge.type-amulet   { width: 42px; font-size: 10.5px; background: var(--t-amulet);   color: #1B1A14; border-color: rgba(0,0,0,.28); }
.badge.type-leader   { width: 42px; font-size: 10.5px; background: var(--t-leader);   color: #fff; border-color: rgba(0,0,0,.28); }
.badge.type-token    { width: 42px; font-size: 10.5px; background: var(--t-token);    color: #fff; border-color: rgba(0,0,0,.28); }
.badge.type-evo      { width: 42px; font-size: 10.5px; background: var(--t-evo);      color: #fff; border-color: rgba(0,0,0,.28); }
.badge.type-equip    { width: 42px; font-size: 10.5px; background: var(--t-equip);    color: #fff; border-color: rgba(0,0,0,.28); }
.badge.type-other    { width: 42px; font-size: 10.5px; background: var(--t-other);    color: #fff; border-color: rgba(0,0,0,.28); }

/* 闪版 SR / BR / GR —— 同色系 + 斜向提亮 + 亮描边，读作「该罕贵的闪」
   （判据是印刷编号带 P 前缀，如 BP16-P05SC 左下角印 GR → GR闪） */
.badge.rar-gr-f { width: 40px; font-size: 10.5px; color: #fff; border-color: var(--gold);
  background: linear-gradient(135deg, var(--brick), #d9694c); }
.badge.rar-sr-f { width: 40px; font-size: 10.5px; color: #fff; border-color: #cfe2ff;
  background: linear-gradient(135deg, var(--blue), #6f9fe0); }
.badge.rar-br-f { width: 40px; font-size: 10.5px; color: #fff; border-color: #d8d8d8;
  background: linear-gradient(135deg, #4a4a4a, #8f8f8f); }

/* 职业 cls · 七门，纯描边不抢色，只做区分不承载等级 */
.badge.cls { width: auto; padding: 0 7px; background: rgba(245,245,240,.05);
  color: var(--text-2); border-color: var(--ink-4); font-weight: 600; }

/* 编号段 seg · 提示该 SKU 属于哪一段编号（主段不显示） */
.badge.seg { width: auto; padding: 0 6px; background: transparent;
  color: var(--text-3); border-color: var(--ink-4); font-weight: 600; font-size: 10.5px; }

/* 卡牌字段 trait · 卡面左下角、类型徽章旁印的那串（植物族 / 魔法师 / 学院…）。
   与职业徽章同为描边款，只把边框调成青绿以示区分 —— 字段是构造套牌的检索轴，
   但同样不承载等级，所以不给实色底。多值时由 bTrait() 拆成多枚。
   字色是品牌青 --c-cyan 提亮版：H180° 不动，只提亮度到在 --ink 上够对比度
   （原色 #00A8A8 压深底只剩 3.0:1，达不到正文可读）。 */
.badge.trait { width: auto; padding: 0 6px; background: rgba(0,168,168,.08);
  color: #6FD8D8; border-color: rgba(0,168,168,.34); font-weight: 600; font-size: 10.5px; }

/* 品相数标签 · 提示该编号在详情页有多个品相可选（列表页不展示具体品相） */
.badge.condcnt { width: auto; padding: 0 6px; background: rgba(255,224,0,.1);
  color: var(--gold-ink); border-color: rgba(255,224,0,.38); font-weight: 700; font-size: 10.5px; }

/* 起价后缀 · 多品相时价格标「起」 */
.price-from { color: var(--text-3); font-size: 12px; font-weight: 700; margin-left: 3px; }
/* 价格 +「起」打包成一个 flex 子元素。否则 .pcard-foot 的 space-between 会把
   「价格 / 起 / 卡牌类型」当成三个子元素均分到左中右，「起」被推到卡片中间去。 */
.price-box { display: inline-flex; align-items: flex-end; }

/* 进化 evo · 一码两面提示 */
.badge.evo { width: auto; padding: 0 6px; background: rgba(255,224,0,.12);
  color: var(--gold-ink); border-color: rgba(255,224,0,.4); font-weight: 700; font-size: 10.5px; }

.badges { display: inline-flex; gap: 5px; align-items: center; flex-wrap: wrap; }

/* 状态 pill */
.badge.stock-ok   { background: rgba(46,168,96,.14); color: var(--green); border-color: rgba(46,168,96,.4); padding: 0 9px; }
.badge.stock-low  { background: rgba(255,224,0,.14); color: var(--gold-ink); border-color: rgba(255,224,0,.42); padding: 0 9px; }
.badge.stock-out  { background: rgba(139,30,45,.30); color: #FFE9EC; border-color: var(--brick); padding: 0 9px; }

/* ==========================================================================
   5 · 版面块
   ========================================================================== */
.sec { margin: 54px 0; }
.sec-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 18px; margin-bottom: 20px; flex-wrap: wrap;
}
.sec-title {
  font-size: 21px; font-weight: 800; letter-spacing: .01em; margin: 0;
  display: flex; align-items: center; gap: 10px;
}
.sec-title::before {                 /* 标题左黄竖条（规范 .h2 同源）*/
  content: ""; width: 4px; height: 18px; background: var(--gold); border-radius: 1px;
}
.sec-sub { color: var(--text-3); font-size: 12.5px; margin: 4px 0 0 14px; }

/* 浅色承载面（6:3:1 里的 30%）：左 4px 黄竖条 */
.paper-block {
  background: var(--paper-2); color: var(--text-on-paper);
  border-radius: 10px; padding: 20px 22px;
  border-left: 4px solid var(--gold);
}
.paper-block h3 { margin: 0 0 8px; font-size: 15px; font-weight: 800; color: var(--on-accent); }
.paper-block p  { margin: 0; font-size: 13px; color: #4A463F; }
.paper-block .muted { color: #6B655C; }

.panel {
  background: var(--ink-2);
  border: 1px solid var(--ink-4);
  border-radius: 10px;
}
.panel-pad { padding: 18px 20px; }

/* ==========================================================================
   6 · 商品卡 / 网格
   ========================================================================== */
.grid {
  display: grid; gap: 18px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* 品牌页正文的双栏说明网格：比例四档，窄屏统一折成一栏。
   注意：这里必须用类而不能用行内 style —— 行内样式优先级高于媒体查询，
   会在移动端把两栏硬撑出视口（长标识串无法收缩）。 */
.grid.g-21 { grid-template-columns: 1.2fr 1fr; gap: 20px; }
.grid.g-31 { grid-template-columns: 1.3fr 1fr; gap: 20px; }
.grid.g-41 { grid-template-columns: 1.35fr 1fr; gap: 20px; }
.grid.g-11 { grid-template-columns: 1fr 1fr; gap: 20px; }

/* 网格子项默认 min-width:auto，长串（工具名 / URL / 编号）会把网格顶宽。
   统一允许收缩，并让标记类长串可断行。 */
.grid > * { min-width: 0; }
.mono, code, .paper-block a { overflow-wrap: anywhere; word-break: break-word; }

.pcard {
  position: relative;
  background: var(--ink-2);
  border: 1px solid var(--ink-4);
  border-radius: 10px;
  padding: 12px;
  display: flex; flex-direction: column; gap: 10px;
  transition: .18s;
  overflow: hidden;
}
.pcard:hover {
  border-color: var(--brand-2);
  transform: translateY(-2px);
  box-shadow: var(--shadow-2);
}
/* 售完的卡：**与有货卡完全同款**（2026-10-21 用户第二次拍板，原话：
   「售完的卡不加特效蒙版，和有库存的卡一模一样！」）
   🔴 这里曾经有 4 组规则：`.pcard.is-out` 调边框、`.pcard.is-out:hover` 取消抬起、
      `.pcard.is-out .pcard-thumb img { filter: grayscale(1) brightness(.58) }` 去色压暗、
      `.pcard.is-out .price` 金色转灰，外加 `.pcard-out-mask`（砖红「售 完」胶囊）。
      **全部删除，别再按"售完要一眼可分"加回来** —— 20:10 那句「售完的卡牌不会有
      任何特殊表现方式，售完和有库存的表现是一个样式」就是这个意思：
      不做区分。售完只在详情页（状态格 / 售罄按钮）体现。
   ⚠️ `.is-out` 类还留在 DOM 上（store.js 打的语义钩子），但**没有任何样式** ——
      它是给 `_verify_stockout.cjs` 找售完卡用的，不是视觉入口。 */
.pcard .flag-mini {                     /* V4 卡顶边 4px */
  position: absolute; top: 0; left: 0; right: 0;
}
.pcard-thumb {
  position: relative;
  border-radius: 7px; overflow: hidden;
  background: #0d0d0d;
  aspect-ratio: 5 / 7;
}
.pcard-thumb img { width: 100%; height: 100%; object-fit: cover; }
.pcard:hover .pcard-thumb img { transform: scale(1.025); }
.pcard-thumb img { transition: .3s; }
.pcard-name {
  font-size: 13.5px; font-weight: 700; line-height: 1.4;
  /* 卡名最多两行，但不再预留两行高度 —— 第二行的位置留给下面的职业行，
     两行相加 ≈ 原来的预留高，卡片整体不会变高 */
  min-height: 1.4em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* 职业独立一行（图标 + 职业名）：不再和编号挤在同一行里互相压缩，
   长编号 + 四字职业也不会换行错位。视觉层级 卡名 > 职业 > 编号。 */
.pcard-cls {
  display: flex; align-items: center;
  min-height: 20px;                       /* 无职业的卡（56 张）留空行，保住卡片高度一致 */
  font-size: 12px; font-weight: 700; color: var(--text-2);
  margin-top: -4px;                       /* 抵消 .pcard 的 10px gap，让三行凑成一个信息块 */
}
/* 2026-09-20：编号行升级成「系列 + 中文名 · 卡面编码」（如 BP19 天魔八略 · BP19-001SC），
   一行放不下时省略号收尾，完整值靠 title 悬停 —— 卡片高度保持不变。 */
.pcard-no { font-size: 11px; color: var(--text-3); letter-spacing: .04em; margin-top: -5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pcard-foot {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 8px;
  margin-top: auto;
  /* 2026-10-25：加一条极淡的分隔线 + 内边距 ——
     卡片上半是"图 + 名 + 职业 + 编号"，下半是"价格 + 卡牌类型"，
     原来两者只靠 10px gap 区分，同一行卡片因为名字长短不一，价格看着高低不齐。
     margin-top:auto 已经把价格推到底（底边永远齐平），这条线负责让它"看起来"是一个页脚。 */
  padding-top: 9px;
  border-top: 1px solid var(--ink-4);
}
/* 卡脚右槽：「卡牌类型 · 卡牌字段」。价格占左、它占右，仍是两个 flex 子元素，
   所以卡片高度不变。字段最长 23 字（灰姑娘偶像・Cute・Cool・Passion），
   必须允许收缩并省略号收尾 —— 否则会把 19px 的价格挤到换行。完整值在 title 里。 */
.pcard-meta {
  flex: 1 1 auto; min-width: 0; text-align: right; font-size: 11px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.price { font-size: 19px; font-weight: 800; color: var(--gold-ink); letter-spacing: -.01em; }
.price small { font-size: 11px; font-weight: 700; margin-right: 1px; }

/* ==========================================================================
   7 · 筛选栏 / 工具条
   ========================================================================== */
/* 筛选栏：桌面端固定左栏（--fbar-w，默认 360px）。
   用 fixed 钉在视口左侧 —— 「无论滑到多下面，始终在左边、随时能调」。
   左偏移与栏宽对齐 .wrap（max-width 1180 + padding 22）计算：
   left = max(22px, (100vw - 1180px)/2 + 22px)。
   纵向：top 由 --ftop 驱动（= 顶栏底边高度，页面一滚动顶栏离场后归 0），
   高度吃满「顶栏之下 → 视口底部」，所以栏顶永远贴着可视区最上沿；
   内层单条滚动，内容再长也不会撑破视口。
   --fbot 是**底部适应区**：栏是 fixed，页脚滚进视口时会整块钻到栏底下被盖住
   （结果只有一行时页面很矮，尤其明显）。--fbot = 「栏顶 → 页脚顶边」的实测距离 - 20px，
   由 store.js 的 syncFiltersTop() 每帧重算，栏高度取两者较小值 ——
   栏底永远停在页脚上方 20px，不盖页脚。 */
.shop {
  --fbar-w: 360px;             /* 栏宽（响应式在各断点覆写） */
  --fbar-gap: 26px;            /* 栏与结果区的间距 */
  display: block;              /* 结果区独占整行，左栏由 fixed 覆盖在左侧 */
  padding-left: calc(var(--fbar-w) + var(--fbar-gap));
}
.shop > * { min-width: 0; }
/* 底部适应区（结果区侧）：结果区至少与筛选栏等高 —— 撑满「栏顶 → 视口底 - 14px」。
   不这么做的话，结果只剩一行时页面塌成不到一屏高，页脚紧贴在卡片行下面，
   且与 fixed 筛选栏纵向重叠 240px 以上（页脚第一列被整块盖住，实测 1440×900：
   栏 13→886 / 页脚 643→900，重叠 243px）。窄屏栏是横向悬浮块，不需要这条。 */
@media (min-width: 901px) {
  .shop > section { min-height: calc(100vh - var(--ftop, 0px) - 14px); }
}
/* 2026-10-25 排版整理（店主：「感觉有点乱」/「这里太宽了」）——
   原来栏高是 `min(视口高 - 顶栏 - 14, …)`，**永远拉满一屏**：七块方块只占上面 400px，
   下面 500px 是一整片空白面板。左侧因此看着"又宽又空"，右边卡片反而显得散。
   改成**按内容高 + 上限**：内容多时照旧滚（max-height 兜住），内容少时就到哪算哪。
   右侧结果区的 min-height 仍然是整屏（见 .shop > section），所以页面不会塌。 */
.filters {
  position: fixed;
  top: var(--ftop, 0px);
  left: calc(max(22px, (100vw - 1180px) / 2 + 22px));
  width: var(--fbar-w);
  height: auto;
  max-height: min(calc(100vh - var(--ftop, 0px) - 14px), var(--fbot, 100vh));
  display: flex; flex-direction: column;
  min-height: 0;
  z-index: 20;
}
.filters-in {
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-gutter: stable;
  min-height: 0;
  /* 栏高改成 auto 之后，这里**不要再 flex:1 撑满** —— 那会把它撑回整屏高，
     等于白改。0 1 auto：按内容长，超出时由父级的 max-height 触发滚动。 */
  flex: 0 1 auto;
}
/* 滚动条样式已收到文件开头的「🔴 铁律 2026-10-16」那一处，这里不再重复写 */
/* ── 移动端筛选小球（FAB）────────────────────────────────────────
   coptus 字标的「C」缩成一颗悬浮球钉在右下角：点它展开筛选面板，
   再点（球变成 ✕）收回小球。桌面上筛选栏常驻，这颗球永远隐藏。 */
.fab-filters { display: none; }
/* 弹窗头（筛选标题 + ✕）：只在窄屏模态里出现（≤900px 块里 display:flex） */
.fmodal-head { display: none; }
/* 「重置全部筛选」按普通文档流放在筛选栏最底部：不悬浮、不遮挡上面的选项 */
/* 选项组跟着变宽后，长清单不再限高（见下方两列平铺规则） */
.fopts.scroll { max-height: none; }
/* ── 筛选格：九块 + 重置，**全部是小方块**（2026-10-20 用户「我的意思是全部变成小方块」）
   前两轮只把顶部三块做成方块，下面六组还是「标题行 + 一片芯片」，整栏一半方块、一半长条。
   这一轮统一成 3 列小方块（96px），并且：
     · 方块里只留 图标 / 名称 / 当前值 三行；
     · 芯片搬进下方共用的 #fPanel，一次只开一组；
     · 视觉与 .qk-b 完全同构（同底色 / 同描边 / 同圆角 / 同金顶线）——
       它们本来就是同一类东西，不该有两套长相。 */
.fgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
/* 顶部三块（系列/价位/职业）用 display:contents 并进这个网格 ——
   不这样就得把 #qkRow 当成"占满一整行"的子网格，行高由它自己决定，和下面六块永远对不齐。 */
.qk-side { display: contents; }

/* 关键词搜索：**与重置同一行**（2026-10-21 店主手绘重排：搜索框 + 重置并排）。
   占前两格，重置占第 3 格 —— 两者同为 40px 高，视觉上是一行。
   它不是方块 —— 搜索框常驻可见（点开才出现等于多一次点击），
   视觉仍与方块同一族：同底色、同描边、同圆角，只是横过来排。 */
.fq-row {
  grid-column: 1 / 3;
  display: flex; align-items: center; gap: 8px;
  height: 40px; padding: 0 11px;
  background: var(--ink-2); border: 1px solid var(--ink-4); border-radius: 12px;
  transition: border-color .16s, background .16s;
}
.fq-row:hover { border-color: rgba(255, 224, 0, .5); background: var(--ink-3); }
.fq-row:focus-within { border-color: var(--gold); background: rgba(255, 224, 0, .07); }
.fq-row .fq-ic { flex: none; width: 16px; height: 16px; color: var(--text-3); }
.fq-row .fq-ic svg { display: block; width: 16px; height: 16px; }
.fq-row:focus-within .fq-ic { color: var(--gold-ink); }
.fq-row .fq-in {
  flex: 1 1 auto; min-width: 0; width: 100%;
  border: 0; background: transparent; padding: 0;
  font: inherit; font-size: 12.5px; color: var(--text);
}
.fq-row .fq-in::placeholder { color: var(--text-3); }
.fq-row .fq-in:focus { outline: none; }
/* type=search 自带那个"清空"叉太靠边，跟圆角打架，稍微收一下 */
.fq-row .fq-in::-webkit-search-cancel-button { margin-right: 2px; }

/* ── 价格区间：最低价 ～ 最高价（2026-10-21 店主手绘重排）─────────────────
   原来「价位」是一个方块（点开选 5 个预设档 + 自定义区间），现在降成这一行常驻输入。
   理由：价位是连续量，预设档永远不够用；而"限定一个价格带"是这栏最常做的事，
   多点一层没有任何收益。同一功能只留这一个入口 —— 旧的价位方块连同 5 档一起删了。
   两个输入框共享一格宽度、中间用「～」分隔；有值时整行描边转金（与方块的 .has 同语义）。 */
.frange {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 8px;
  height: 40px;
}
.frange-in {
  flex: 1 1 0; min-width: 0; height: 100%;
  display: flex; align-items: center; gap: 7px;
  padding: 0 11px; border-radius: 12px;
  background: var(--ink-2); border: 1px solid var(--ink-4);
  transition: border-color .16s, background .16s;
  cursor: text;
}
.frange-in > span { flex: none; font-size: 11.5px; color: var(--text-3); }
.frange-in input {
  flex: 1 1 auto; min-width: 0; width: 100%;
  border: 0; background: transparent; padding: 0;
  font: inherit; font-size: 12.5px; color: var(--text);
}
.frange-in input::placeholder { color: var(--text-3); }
.frange-in input:focus { outline: none; }
.frange-in:hover { border-color: rgba(255, 224, 0, .5); background: var(--ink-3); }
.frange-in:focus-within { border-color: var(--gold); background: rgba(255, 224, 0, .07); }
.frange-sep { flex: none; font-size: 12px; color: var(--text-3); }
.frange.has .frange-in { border-color: rgba(255, 224, 0, .55); }

/* ── 重置：搜索框右侧那一条（2026-10-21）────────────────────────────────
   2026-10-20 时它是格子里的一块 88px 方块（图标 + 「重置」+ 「清 N 个」三行），
   但它在网格最右下角 —— 要滑到栏底才够得着，而"清空重来"恰恰是最急的动作。
   现在挪到搜索框右边、与搜索框等高：只放 图标 + 「重置」+ 一枚数字徽章。
   没条件时置灰 disabled（原来无条件也能点、点了什么都不变）。 */
.fq-reset {
  grid-column: 3;
  appearance: none; cursor: pointer; font: inherit;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  height: 40px; padding: 0 10px; min-width: 0;
  border-radius: 12px; white-space: nowrap; overflow: hidden;
  background: var(--ink-2); border: 1px solid var(--ink-4);
  color: var(--text-2); font-size: 12.5px; font-weight: 700;
  transition: border-color .16s, background .16s, color .16s;
}
.fq-reset .qk-ic {
  grid-row: auto; flex: none;
  width: 15px; height: 15px; border-radius: 0; background: transparent;
}
.fq-reset .qk-ic svg { width: 15px; height: 15px; }
.fq-reset b { font-size: 12.5px; font-weight: 700; }
.fq-reset-n {
  flex: none; min-width: 17px; height: 17px; padding: 0 5px; border-radius: 999px;
  background: var(--gold); color: #1a1400;
  font-size: 10.5px; font-style: normal; font-weight: 900; line-height: 17px; text-align: center;
}
.fq-reset:hover { border-color: rgba(255, 224, 0, .5); background: var(--ink-3); color: var(--text); }
.fq-reset.on { border-color: var(--gold); color: var(--gold-ink); }
.fq-reset:disabled { cursor: default; opacity: .55; }
.fq-reset:disabled:hover { background: var(--ink-2); border-color: var(--ink-4); color: var(--text-2); }

.fgroup {
  position: relative; display: grid; grid-template-rows: auto auto;
  justify-items: center; align-content: start; gap: 3px;
  min-height: 88px; padding: 11px 7px 10px; text-align: center;
  background: var(--ink-2); border: 1px solid var(--ink-4); border-radius: 12px;
  transition: border-color .16s, background .16s, transform .16s;
}
.fgroup:hover { border-color: rgba(255, 224, 0, .5); background: var(--ink-3); transform: translateY(-2px); }
/* .has = 这块正在参与筛选；.on = 这块的选项正在下面展开（两个是不同状态，别合并） */
.fgroup.has, .fgroup.on { border-color: var(--gold); background: rgba(255, 224, 0, .07); }
.fgroup.has::before, .fgroup.on::before {
  content: ""; position: absolute; left: 12px; right: 12px; top: -1px; height: 2px;
  border-radius: 0 0 2px 2px; background: var(--gold);
}
.fgroup.on { box-shadow: inset 0 0 0 1px rgba(255, 224, 0, .55); }   /* 展开态补一圈内描边，与"已选"区分 */
.fgroup h4 { margin: 0; font-size: 12.5px; font-weight: 800; line-height: 1.3; color: var(--text); }
.fgroup > h4.fhead {
  display: grid; grid-template-rows: auto auto; justify-items: center;
  gap: 3px; width: 100%; margin: 0; padding: 0; min-height: 0;
  outline: none; cursor: pointer; user-select: none; text-align: center;
}
.fgroup > h4.fhead:focus-visible { box-shadow: 0 0 0 2px rgba(214, 178, 74, .55); border-radius: 8px; }
.fhead .fico {
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 9px;
  background: var(--ink-3); color: var(--text-3);
  transition: background .16s, color .16s;
}
.fhead .fico svg { width: 18px; height: 18px; }
.fgroup.has .fhead .fico, .fgroup.on .fhead .fico { background: rgba(255, 224, 0, .14); color: var(--gold-ink); }
.fhead .fmeta { display: flex; flex-direction: column; align-items: center; gap: 1px;
  min-width: 0; width: 100%; }
.fhead .flabel { font-size: 12.5px; font-weight: 800; line-height: 1.3; color: var(--text); white-space: nowrap; }
/* 当前值最多两行（「BP19、BP18」这种多选值折两行也读得完），超了省略 */
.fhead .fsum {
  min-width: 0; max-width: 100%; font-size: 10.5px; line-height: 1.3; color: var(--text-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; word-break: break-all;
}
.fgroup.has .fhead .fsum, .fgroup.on .fhead .fsum { color: var(--gold-ink); font-weight: 700; }

/* ── 共用展开区 ─────────────────────────────────────────────────────────
   点哪块方块，哪一块的芯片在这里出现。一次只开一组 ——
   九组全铺开时整栏 1500px，一屏只看得到两三个条件，那正是这轮要消灭的东西。 */
/* 展开区是 .fgrid 的一个网格项：跨满 3 列，插在被点那一行的下面（JS 挪位置）。
   margin 由 grid 的 gap 负责，这里不再加外边距，否则行间距会突然变宽。 */
/* ══ 筛选栏：方块 → 分组标签云（2026-10-25）══════════════════════════════
   店主：「我的意思是把他一开这一行，这一行就他占一点位置然后其他全空着太难受了」
        +「直接铺成分组的标签云（类型 / 种族 / 系列 各一组带小标题），少一次点击」。
   原来整栏是 3 列小方块（每块 88px，只写 图标/名称/当前值），点开才在共用面板里
   看到芯片 —— 每次筛选至少两次点击，而且方块只占左栏上半截、下面大片空。
   现在：**每组 = 一行标题（可折叠）+ 常驻芯片云**，从上到下一条流。
   作用域全部挂 `.fg-inline`（只有卡库 #fgrid 有），其它页面的 .fgrid 不受影响。 */
.fgrid.fg-inline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0;                       /* 间距交给组自己的 padding-bottom */
  align-items: start;
}
.fgrid.fg-inline > .fq-row { grid-column: 1; }
.fgrid.fg-inline > .freset { grid-column: 2; }
.fgrid.fg-inline > .frange { grid-column: 1 / -1; margin-top: 8px; }

/* 分组块：去掉方块的底色/描边/居中/88px 最小高 */
.fgrid.fg-inline > .fgroup {
  grid-column: 1 / -1;
  display: block; min-height: 0; padding: 0 0 12px; text-align: left;
  background: none; border: 0; border-radius: 0;
  transform: none;
}
.fgrid.fg-inline > .fgroup + .fgroup { border-top: 1px solid var(--ink-4); padding-top: 12px; }
.fgrid.fg-inline > .fgroup:hover { background: none; border-color: transparent; transform: none; }
.fgrid.fg-inline > .fgroup.has { border-top-color: rgba(255, 224, 0, .35); }
.fgrid.fg-inline > .fgroup::before { content: none; }

/* 标题行：图标 + 组名 + 当前值 + 折叠箭头（横排，一行） */
.fgrid.fg-inline > .fgroup > h4.fhead {
  display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 0 0 8px; text-align: left;
}
.fgrid.fg-inline .fhead .fico {
  width: 20px; height: 20px; border-radius: 6px; flex: none;
  background: var(--ink-3); color: var(--text-3);
}
.fgrid.fg-inline .fhead .fico svg { width: 13px; height: 13px; }
.fgrid.fg-inline .fgroup.has .fhead .fico { background: rgba(255, 224, 0, .14); color: var(--gold-ink); }
.fgrid.fg-inline .fhead .fmeta {
  flex: 1 1 auto; flex-direction: row; align-items: baseline;
  gap: 8px; min-width: 0;
}
.fgrid.fg-inline .fhead .flabel { font-size: 12.5px; flex: none; }
/* 当前值：单行省略（多选时「BP19 BP18 BP17…」不该把标题挤成两行） */
.fgrid.fg-inline .fhead .fsum {
  flex: 1 1 auto; min-width: 0; max-width: none;
  font-size: 10.5px; text-align: right;
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 折叠箭头：一条 45° 的折角，收起时朝下、展开时朝上 */
.fgrid.fg-inline .fhead::after {
  content: ""; flex: none; width: 7px; height: 7px; margin-left: 2px;
  border-right: 1.6px solid var(--text-3); border-bottom: 1.6px solid var(--text-3);
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform .2s ease;
}
.fgrid.fg-inline .fgroup.is-fold .fhead::after { transform: rotate(-45deg) translate(-1px, 1px); }
.fgrid.fg-inline .fhead:focus-visible { box-shadow: 0 0 0 2px rgba(214, 178, 74, .55); border-radius: 6px; }

/* 芯片云：常驻；收起时只藏芯片，标题行留着（还能看到"已选了什么"） */
.fgrid.fg-inline > .fgroup > .fopts { display: flex; flex-wrap: wrap; gap: 6px; padding: 0; }
/* 🔴 `.fopts.scroll .fopt { width: 100% }`（旧版"一行一条滚动列表"的遗留）会把每个
   芯片撑满一整行 —— 费用组 15 个数字变成 15 条巨型横条（实测组高 559px）。
   这里在 inline 形态下把宽度交回内容：芯片该多宽就多宽，靠 flex-wrap 换行。 */
.fgrid.fg-inline > .fgroup > .fopts > .fopt { width: auto; flex: 0 0 auto; }
.fgrid.fg-inline > .fgroup.is-fold > .fopts { display: none; }
/* 系列按「补充包 / 预组 / PR卡」分的小标题：占满一行，芯片换行到下面 */
.fg-grp {
  flex: 0 0 100%; margin: 4px 0 0;
  font-size: 10px; font-weight: 800; letter-spacing: .14em;
  color: var(--text-3); text-transform: uppercase;
}
.fg-grp:first-child { margin-top: 0; }
/* 系列/职业带图标（职业那组图标本身有颜色，芯片底保持中性） */
.fgrid.fg-inline .fopt.has-ico { display: inline-flex; align-items: center; gap: 5px; padding-left: 7px; }
.fgrid.fg-inline .fopt-ico { width: 14px; height: 14px; flex: none; }

/* 旧的共用展开区在 inline 形态下彻底退休（元素保留给探针读，不再显示） */
.fgrid.fg-inline > .fpanel { display: none !important; }

.fgrid > .fpanel { grid-column: 1 / -1; }
.fpanel { margin: 0; padding: 10px 12px 12px; border-radius: 12px;
  background: var(--ink-3); border: 1px solid var(--ink-4); }
.fpanel[hidden] { display: none; }
.fpanel-hd { display: flex; align-items: baseline; gap: 8px; margin-bottom: 9px; }
/* 91 个字段芯片全铺开会把面板撑到 700px 高，整栏被它顶得看不到上面的方块 ——
   所以面板体自己滚，栏高稳定在 ~420px 以内。 */
.fpanel-bd { max-height: min(52vh, 420px); overflow: auto; padding-right: 2px; }
.fpanel-hd b { font-size: 12.5px; font-weight: 800; color: var(--text); }
.fpanel-hint { flex: 1 1 auto; font-size: 11px; color: var(--text-3); }
.fpanel-x { appearance: none; cursor: pointer; width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: 7px; background: transparent; color: var(--text-3);
  font-size: 12px; line-height: 1; }
.fpanel-x:hover { background: var(--ink-4); color: var(--gold-ink); }

/* 重置块的旧样式（.qk-b.freset 那套 88px 竖方块）已于 2026-10-21 删除 ——
   它现在是与搜索框同高的横条，样式见上面的 .fq-reset。
   留着旧规则的话，.qk-b 的 grid 布局会和新按钮打架（这正是当初写这条注释的原因：
   `.freset` 单独写会被后加载的 `.qk-b` 同权重盖掉，必须写成 `.qk-b.freset`）。
   现在按钮不再带 .qk-b，所以只需一个类名就够。 */

/* ── 多选（2026-09-19 用户拍板）─────────────────────────────────
   六个维度（系列 / 职业 / 卡牌类型 / 字段 / 稀有度 / 语言）支持同组多选：
   组内取或（选了 SR闪 + BR闪 两种都出），组间取且（再压一个系列）。 */
/* 可多选组的标题角标 —— 光看芯片点不出「还能再点一个」，得有人说 */
.fhead .fmulti {
  flex: none; font-style: normal; font-size: 9.5px; font-weight: 700;
  letter-spacing: .04em; line-height: 1.6; padding: 0 5px;
  border: 1px solid var(--ink-4); border-radius: 999px;
  color: var(--text-3); white-space: nowrap;
}
/* 该组正在参与筛选时，角标跟着标题一起转金（与 .fsum 同待遇） */
.fgroup.has > .fhead .fmulti { border-color: rgba(214, 178, 74, .55); color: var(--gold-ink); }
.fopts { display: flex; flex-wrap: wrap; gap: 6px; }
.fopt {
  border-radius: 8px; padding: 5px 10px;
  border: 1px solid var(--ink-4); background: transparent;
  color: var(--text-2); font-size: 12px; font-weight: 700; cursor: pointer;
  transition: .14s;
}
.fopt:hover { border-color: var(--brand-2); color: var(--text); }
.fopt.on { background: var(--gold); color: var(--on-accent); border-color: var(--gold); }
/* 职业筛选：logo 徽章 */
.fopt.has-ico {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 10px 4px 5px;
}
.fopt-ico { width: 24px; height: 28px; object-fit: contain; flex: none; }
.fopt.has-ico .t { line-height: 1.2; }
/* 选中态图标**保持原色**（2026-09-21 用户拍板：任何芯片选中都不得把图标涂黑——
   曾用 brightness(0) 压黑，金底上糊成一团；改轻投影保对比。新增选中态样式时照此办理。） */
.fopt.has-ico.on img { filter: drop-shadow(0 1px 2px rgba(20, 20, 20, .45)); }
/* 详情页规格 / 卡列表 meta 里的职业小标。
   display 必须显式写成 inline-block —— 全局 img{display:block} 会让图标独占一行，
   把紧跟其后的职业名挤到下一行（.cls-cell 的 flex 布局里会被 blockify，无副作用）。 */
.cls-ico { display: inline-block; width: 17px; height: 20px; object-fit: contain; vertical-align: -5px; }
.cls-cell { display: inline-flex; align-items: center; gap: 6px; }
/* 长清单（36 个系列 / 12 档稀有度）：两列平铺、不再内嵌滚动框。
   整栏只保留一条滚动条，所有选项一眼可见，不会被小方框吞掉。 */
.fopts.scroll {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px 8px;
  max-height: none; overflow: visible;
}
.fopts.scroll .fopt {
  display: flex; align-items: center;
  width: 100%; min-width: 0; text-align: left; padding: 5px 8px;
  font-size: 11.5px;
}
.fopts.scroll .fopt .t {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 稀有度 12 档：芯片已精简成纯代码（SSP / GR闪 / PR …），两列会在右侧留一大片空白，
   改三列紧凑平铺、代码居中。（系列名较长，仍走上面两列的规则） */
.fopts.scroll.cols-3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px 6px;
}
.fopts.scroll.cols-3 .fopt { padding: 5px 6px; justify-content: center; }
/* 费用筛选（2026-09-30 用户拍板：一排 5 个）：档位 15 个、芯片只印数字（0…15，无 13），
   走 5 列紧凑平铺 —— 一行 5 个正好 3 行铺满。比 cols-3 再小一档：
   纯数字芯片不需要横向余量，所以左右 padding 收到 2px、字号降到 11px。
   ⚠ 只给 #fCost 用；字段（91 原子、最长 5 汉字）与稀有度仍在 cols-3。 */
.fopts.scroll.cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 4px; }
.fopts.scroll.cols-5 .fopt { padding: 4px 2px; font-size: 11px; border-radius: 7px; justify-content: center; }
/* 字段筛选（2026-09-30 用户拍板「一排 4 个」）：91 个原子，标签最长 5 汉字（灰姑娘偶像 / 特雷森学园）。
   栏内宽 310px 时 4 列 → 列宽 73px、内容区 63px，容得下 5 字（11.5px × 5 = 57.5px），
   所以左右 padding 从 6px 收到 4px 留出余量（原来 3 列的 99px 列宽纯属浪费）。
   ⚠ 断点联动：`≤1080px` 时 `.shop { --fbar-w: 300px }` 会让 4 列跌到列宽 58px、
   内容区 44px —— 5 字标签必被截成省略号，所以在**同一个断点里退回 3 列**。
   以后改 `--fbar-w` 记得同步复核这里。 */
.fopts.scroll.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px 6px; }
.fopts.scroll.cols-4 .fopt { padding: 5px 4px; justify-content: center; }
/* 种族（字段）筛选 · 筛选**弹窗**里一排 6 个（2026-10-19 用户：「一行多分几个，
   现在一行 2 个太宽了」）。原来走的是 .fopts.scroll 的默认两列 + 每个 width:100%，
   584px 的内容区被两个胶囊对半分，一行只放得下 2 个。
   依据：`.fmodal` = min(640px,100%)、`.fmodal-bd` 左右各 28px → 内容宽 584px；
   6 列 + 4px 间距 ×5 → 列宽 94px，扣左右 padding 8px 还剩 86px，
   最长中文字段 6 字（恶魔伪王国军 / 伊丽莎白牧场）11.5px × 6 = 69px，放得下。
   ⚠ 别照抄 cols-4 的 310px 依据 —— 那条算的是**卡库侧栏**宽度，弹窗比它宽近一倍。
   ⚠ 断点联动：≤680px 内容宽只剩 319px，6 列必截断 → 退回 4 列；≤420px 再退 3 列。 */
.fopts.scroll.cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px 6px; }
.fopts.scroll.cols-6 .fopt { padding: 5px 4px; justify-content: center; }
@media (max-width: 680px) {
  .fopts.scroll.cols-6 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 420px) {
  .fopts.scroll.cols-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* 系列筛选三大类小节标题（补充包 / 预组 / PR卡）：在两列网格里独占整行 */
.fopts .fsub {
  grid-column: 1 / -1;
  margin: 7px 0 3px; padding-top: 7px;
  border-top: 1px solid var(--ink-4);
  font-size: 10.5px; font-weight: 800; letter-spacing: .1em;
  color: var(--text-3);
}
.fopts .fsub:first-child { margin-top: 0; padding-top: 0; border-top: none; }

.toolbar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 12px 16px; margin-bottom: 18px;
  /* 2026-10-25：这条工具栏里只剩「网格 / 列表 / 排序」三个控件，
     但它是以 `.panel` 铺满整行的 —— 左边 500px 留白，右边挤三个按钮，
     一眼看过去像"没做完"。改成**按内容宽 + 靠右**，与卡片区右边缘对齐。 */
  /* 2026-10-25 第二次（店主：「这一行就他占一点位置，然后其他全空着太难受了」）。
     上一版改成 `width: fit-content` + 靠左 —— 左边缘是对齐了，但**整条只剩 245px**，
     右边 700px 全空，看着像"这条控件被丢在角落"。三种排版都试过了：
     靠右（左空）、靠左（右空）、按内容居中（两边都空）—— 只要宽度是 fit-content，
     在一条横跨 1000px 的区域里永远会有大面积空白。
     所以**铺满卡片区宽度**，两端各放东西：
       · 左：结果数「共 N 张卡」（原本 sr-only，只给脚本读 —— 现在有位置了就用上，
             它本来就是这一行最该回答的问题："筛完还剩多少"）；
       · 右：视图切换 + 排序。
     中间那段空白是**两个控件组之间的间隔**，不是没人用的区域。
     ⚠️ `.count` 的 class 不能删：`_smoke.cjs` 等守卫靠 `.toolbar .count` 读结果数，
        所以这里只用 CSS 把 `.sr-only` 的视觉隐藏解掉，不碰 DOM。 */
  width: 100%;
  margin-left: 0;
  justify-content: flex-start;
}
/* 2026-10-25 店主第二次：「把这行字删了替换成搜索框」——
   计数回到纯 sr-only（只给验收脚本读），工具栏那个位置留给搜索框。 */
.toolbar .count { font-size: 13px; color: var(--text-2); }
.toolbar .count b { color: var(--gold-ink); font-size: 15px; }
.toolbar .spacer { margin-left: auto; }
/* 屏读器/脚本可见、视觉隐藏。
   工具栏里那行「共 N 张卡 · M 张多品相可选」已在 2026-09-19 按用户圈选从画面上撤掉，
   但结果计数是验收脚本的主要量具（`_smoke.cjs` 靠读它断言结果数），
   所以保留节点、只把它藏起来 —— 页面上看不到，测试读数不受影响。
   ⚠ 必须用 clip 方案：display:none / visibility:hidden 会让 innerText 返回空串。 */
.sr-only {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%); border: 0;
}
.input {
  background: var(--ink); border: 1px solid var(--ink-4); border-radius: 8px;
  padding: 9px 12px; font-size: 13px; color: var(--text); outline: none;
  transition: .15s; min-width: 0;
}
.input::placeholder { color: #6b675f; }
.input:focus { border-color: var(--gold); }
select.input { cursor: pointer; }

/* ==========================================================================
   8 · 卡详情
   ========================================================================== */
.detail { display: grid; grid-template-columns: 396px minmax(0, 1fr); gap: 34px; align-items: start; }
.detail-art {
  position: relative;
  border-radius: 12px; overflow: hidden;
  background: #0b0b0b;
  border: 1px solid var(--ink-4);
}
.detail-art .halftone { position: absolute; inset: 0; }
.detail-art img { position: relative; width: 100%; }
.detail-title {
  font-size: 27px; font-weight: 800; line-height: 1.25; margin: 0 0 6px;
}
.detail-scan {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--text-3);
}
.detail-price {
  display: flex; align-items: baseline; gap: 12px;
  margin: 20px 0 6px;
}
.detail-price .v { font-size: 40px; font-weight: 800; color: var(--gold-ink); letter-spacing: -.02em; }

.spec {
  /* auto-fit：格数减少时（详情页规格表现只剩四格）空轨道自动收拢，四格拉满整行不留空位 */
  display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: 1px; background: var(--ink-4);
  border: 1px solid var(--ink-4); border-radius: 10px; overflow: hidden;
  margin: 20px 0;
}
.spec > div { background: var(--ink-2); padding: 12px 14px; }
.spec dt { font-size: 11px; color: var(--text-3); margin: 0; letter-spacing: .06em; }
.spec dd { margin: 3px 0 0; font-size: 15px; font-weight: 700; }

.rule { border: none; border-top: 1px solid var(--ink-4); margin: 22px 0; }

.cardtext {
  background: var(--ink-2); border: 1px solid var(--ink-4);
  border-radius: 10px; padding: 16px 18px;
  font-size: 13.5px; line-height: 1.85; color: var(--text-2);
  white-space: pre-wrap; word-break: break-word;
  max-height: 340px; overflow: auto;
}
/* 补充文本并入效果正文（2026-09-19 用户拍板）：两段之间用真元素画横线，
   不用「———」字符行 —— pre-wrap 容器里字符画线得手动凑长度，窗口一变就露馅。 */
.cardtext-rule { border: none; border-top: 1px solid var(--ink-4); margin: 12px 0; }
.cardtext-sub { color: var(--text-3); }
.variant-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--ink-4);
  font-size: 13px;
}
.variant-row:last-child { border-bottom: none; }
.variant-row .pick { margin-left: auto; }
/* 列表视图里的售完行**不去色**（2026-10-21 用户：「售完的卡不加特效蒙版，
   和有库存的卡一模一样」）—— 原来那条 `grayscale(1) brightness(.55)` 已删。
   行里唯一的差别只剩右侧动作（「售完」文字徽章 vs「选品相 →」按钮），那是能不能买。 */
/* 详情页挑品相 · 压缩芯片（2026-09-18 用户拍板）：挂在卡图下方左栏，
   替代右栏整行长条列表 —— 同编号品相间只有品相档在变，芯片印「品相名 + 价格」即可 */
.vchips-hd { font-size: 11px; letter-spacing: .06em; color: var(--text-3); margin-top: 16px; }
.vchips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.vchip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 13px; border-radius: 999px;
  background: var(--ink-2); border: 1px solid var(--ink-4);
  font-size: 12.5px; font-weight: 700; color: var(--text);
  text-decoration: none;
  transition: border-color .15s ease, transform .15s ease;
}
.vchip .vc-price { color: var(--gold-ink); font-weight: 800; }
.vchip:hover { border-color: var(--gold); transform: translateY(-1px); }
.vchip.cur { border-color: var(--gold); color: var(--gold-ink); cursor: default; }
.vchip.cur:hover { transform: none; }
.vchip.out { opacity: .4; cursor: not-allowed; }
.vchip.out:hover { border-color: var(--ink-4); transform: none; }
/* 详情页「携带构筑」已升级成卡组广场同款 .dk-card 方块（2026-09-20 用户拍板），
   原 .carry-* 行样式随旧列表一并删除 —— 死代码零容忍（README 铁律 #4）。 */
/* 卡库列表视图（#rList 里的 .variant-row）：窄屏必须允许换行 ——
   行内「库存 + 价格 + 起 + 收藏 + 按钮」这一块加起来约 255px，390px 屏下会把整行撑出 54px。
   把右侧那组换到第二行（仍右对齐），并允许徽章串内部折行；宽屏不受影响。 */
@media (max-width: 680px) {
  #rList .variant-row { flex-wrap: wrap; row-gap: 10px; }
  #rList .variant-row > span { flex-wrap: wrap; min-width: 0; }
  #rList .variant-row .pick { margin-left: auto; }
}

/* ==========================================================================
   9 · 购物车 / 结算
   ========================================================================== */
.cart { display: grid; grid-template-columns: minmax(0, 1fr) 336px; gap: 26px; align-items: start; }
.cart-line {
  display: grid; grid-template-columns: 62px minmax(0, 1fr) auto;
  gap: 14px; align-items: center;
  padding: 14px 0; border-bottom: 1px solid var(--ink-4);
}
.cart-line:last-child { border-bottom: none; }
.cart-thumb { border-radius: 6px; overflow: hidden; background: #0d0d0d; }
.sum { position: sticky; top: 86px; }
.sum-row {
  display: flex; justify-content: space-between; gap: 12px;
  font-size: 13px; color: var(--text-2); padding: 7px 0;
}
.sum-total {
  display: flex; justify-content: space-between; align-items: baseline;
  border-top: 1px solid var(--ink-4); margin-top: 8px; padding-top: 14px;
}
.sum-total .v { font-size: 28px; font-weight: 800; color: var(--gold-ink); }
.qty { display: inline-flex; align-items: center; }
.qty .n { min-width: 34px; text-align: center; font-weight: 700; font-size: 13.5px; }

/* ==========================================================================
   10 · 弹层
   ========================================================================== */
.mask {
  position: fixed; inset: 0; z-index: 100;
  /* 2026-09-21 拍板：去掉 backdrop-filter:blur —— 弹窗内容（卡图墙）滚动时
     整页模糊每帧重算，是滑动卡顿的大头；.72 深色遮罩本身已够用。 */
  background: rgba(10,10,10,.72);
  display: flex; align-items: center; justify-content: center; padding: 22px;
}
.modal {
  background: var(--ink-2); border: 1px solid var(--ink-4);
  border-radius: 12px; box-shadow: var(--shadow-3);
  width: min(560px, 100%); max-height: 88vh; overflow: auto;
  position: relative;
}
.modal.risk { border-color: var(--brick); }
.modal-hd { padding: 20px 22px 0; }
.modal-bd { padding: 14px 22px 4px; }
.modal-ft {
  display: flex; gap: 10px; justify-content: flex-end;
  padding: 18px 22px 22px;
}
.modal h3 { margin: 0 0 6px; font-size: 17px; font-weight: 800; }

/* 印张边框式收据（研究笔记 实验 05 · W5，最推荐落地的一项）*/
.receipt {
  background: var(--paper); color: #1A1A1A;
  border-radius: 6px; padding: 20px 18px 16px;
  font-size: 12.5px; line-height: 1.7;
  position: relative;
  box-shadow: var(--shadow-2);
}
.receipt::before {
  content: ""; position: absolute; inset: 8px;
  border: 1px dashed #C9BFA8; border-radius: 3px; pointer-events: none;
}
.receipt .rhd {
  display: flex; justify-content: space-between; align-items: flex-start;
  border-bottom: 1.5px solid #1A1A1A; padding-bottom: 10px; margin-bottom: 12px;
}
.receipt .rno { font-size: 11px; letter-spacing: .08em; }
.receipt table { width: 100%; border-collapse: collapse; margin: 10px 0; }
.receipt th, .receipt td { text-align: left; padding: 5px 0; font-weight: 400; }
.receipt th { font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: #6B655C;
  border-bottom: 1px solid #D8D2C4; }
.receipt td.num, .receipt th.num { text-align: right; }
.receipt .rtot { border-top: 1.5px solid #1A1A1A; font-weight: 800; font-size: 15px; }
.receipt .rft { margin-top: 14px; font-size: 10.5px; color: #6B655C; letter-spacing: .04em; }

/* ⚠️ 本文件已按主题拆成 5 段（2026-10-17）：本文件是第 1 段，
   后面依次是 brand-home / brand-member / brand-deck / brand-page。
   HTML 里的 5 个 <link> 顺序即层叠顺序，不要调换。 */

/* 危险确认弹窗的头部（2026-10-18）：红点图标 + 标题 + 说明。
   替代原来那条 45° 黄黑 hazard 警示带（.flag-danger）—— 那种「施工围挡」在
   一张 400px 宽的确认框上占掉 40px 且极度抢眼，危险语义靠图标和红按钮表达足够。 */
.risk-hd { display: flex; align-items: flex-start; gap: 12px; text-align: left; }
.risk-ic {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(229, 72, 77, .14); color: #ff8585;
  border: 1px solid rgba(229, 72, 77, .38);
  font: 800 17px/1 var(--font-sans, sans-serif);
}

/* 页脚「动效」开关（2026-10-24）：字号小、无边框，像一条脚注；
   点开有轻微下划线反馈，不抢视觉。 */
.footer-motion {
  margin-left: 10px;
  padding: 0 2px;
  font: inherit;
  font-size: 11px;
  color: var(--text-3);
  background: none;
  border: 0;
  border-bottom: 1px dashed rgba(255,255,255,.22);
  cursor: pointer;
  transition: color .16s ease, border-color .16s ease;
}
.footer-motion:hover { color: var(--gold-ink); border-bottom-color: var(--gold); }
.footer-motion[aria-pressed="true"] { color: var(--gold-ink); }

/* 页脚「动效」开关（2026-10-24）：字号小、无边框，像一条脚注；
   点开有轻微下划线反馈，不抢视觉。 */
.footer-motion {
  margin-left: 10px;
  padding: 0 2px;
  font: inherit;
  font-size: 11px;
  color: var(--text-3);
  background: none;
  border: 0;
  border-bottom: 1px dashed rgba(255,255,255,.22);
  cursor: pointer;
  transition: color .16s ease, border-color .16s ease;
}
.footer-motion:hover { color: var(--gold-ink); border-bottom-color: var(--gold); }
.footer-motion[aria-pressed="true"] { color: var(--gold-ink); }

/* ============================================================================
   购物车里的「商城商品」行（2026-10-25）
   ----------------------------------------------------------------------------
   商城购买改成先加车（店主：「商城购买行为也是要加入购物车」），
   购物车因此同时出现两类行：单卡（图 + 卡名 + 品相徽章）和商品（图 + 名 + 商品码）。
   两类共用 .cart-line 的栅格，这里只补商品特有的几处：无图占位、分区小标题、
   以及"本次会拆成 2 单"的提示条 —— 不提前说清楚，顾客收到两个单号会以为出错。
   ========================================================================== */
.cart-sec-h{
  margin:0 0 10px;font-size:13px;font-weight:800;letter-spacing:.04em;color:var(--text);
  display:flex;align-items:center;gap:8px;
}
.cart-sec-h .muted{font-weight:500;font-size:11.5px;color:var(--text-3);}
/* 无图商品：用底色 + 图标顶住，别让行高塌掉（.cart-thumb 是固定尺寸盒） */
.sp-ph{
  display:flex;align-items:center;justify-content:center;width:62px;height:62px;
  font-size:26px;border-radius:8px;background:var(--ink-3);color:var(--text-2);
}
/* 拆单提示：中性黄底，不是警告（它不是错，只是要提前知道） */
.sum-split{
  margin:10px 0 2px;padding:9px 11px;border-radius:9px;
  background:rgba(255,224,0,.14);border:1px solid rgba(160,130,20,.26);
  font-size:11.5px;line-height:1.6;color:var(--text-2);
}
.sum-split b{color:var(--text);}

/* 收据里的「商城商品 · 另开 N 单」小节：四列（码 / 名 / 金额 / 单号） */
.r-shop{
  margin:12px 0 0;padding:10px 12px;border-radius:9px;
  border:1px dashed var(--ink-4);background:var(--ink-3);
}
.r-shop-h{font-size:11.5px;font-weight:800;letter-spacing:.06em;color:var(--text-2);margin-bottom:8px;}
.r-shop-i{
  display:grid;grid-template-columns:78px minmax(0,1fr) 74px 132px;
  gap:8px;align-items:baseline;font-size:12.5px;padding:4px 0;
}
.r-shop-code{font-size:11px;color:var(--text-3);}
.r-shop-nm{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.r-shop-no{font-size:11px;color:var(--text-2);}
.r-shop-err{margin-top:6px;font-size:11.5px;color:#B4232A;font-weight:700;}
@media (max-width:560px){
  .r-shop-i{grid-template-columns:minmax(0,1fr) 72px;row-gap:2px;}
  .r-shop-code{grid-column:1 / -1;font-size:10.5px;}
  .r-shop-no{grid-column:1 / -1;}
}


/* ══════════════════════════════════════════════════════════════════════════
   卡库 2026-10-25 第三次改版：左栏筛选 → 「更多筛选」弹窗 + 一行 6 张
   ──────────────────────────────────────────────────────────────────────────
   店主原话：
     「把这一块删了」              → 左侧常驻筛选栏整块取消
     「再把这个删了」              → 网格 / 列表 切换取消
     「再加一个更多筛选按钮…点击会弹出一个包含这些功能的筛选窗口」
     「把这行字删了替换成搜索框」  → 计数行让位给搜索框
     「卡牌展示区域更改成一行展示 6 张」
   ⚠️ 筛选能力**一条没减**：整个面板（价位 + 系列/职业/字段/费用/类型/稀有度）
      搬进弹窗，DOM 原封不动 —— 芯片、折叠、URL 同步、重置角标全部沿用，
      所以 `.fgroup / .fopts / .fopt` 那些规则一条都不用改。
   ══════════════════════════════════════════════════════════════════════════ */

/* ① 结果区吃满整宽（左栏没了） */
.shop { padding-left: 0; }

/* ② 一行 6 张。**只作用于卡库结果网格**，且只在真桌面开：
      `.grid` 基类别处也用来做两栏说明网格（.grid.g-21 等），
      而 ≤900 的 3 列 / ≤680 的 2 列由 brand-home.css 里 `.grid` 的媒体查询负责 ——
      这里用 `#rGrid`（id 选择器）会盖掉它们，所以必须包在 min-width 里。 */
@media (min-width: 901px) {
  #rGrid.grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 14px; }
}

/* ③ 工具栏：搜索框 + 重置 + 更多筛选 ｜ 排序 */
.toolbar { gap: 10px; }
.toolbar .fq-row {
  flex: 1 1 240px; max-width: 360px; min-width: 200px;
  height: 38px;
}
.toolbar .fq-reset { flex: none; height: 38px; }
/* 网格/列表切换（店主 2026-10-25「再把这个删了」）：DOM 留着给 state.view 的绑定用，
   视觉上彻底消失 —— 用 `display:none` 而不是删节点。 */
.toolbar #viewSeg { display: none; }
.toolbar #sortSel { flex: none; height: 38px; }

/* 「更多筛选」按钮：和搜索框同高、同一族（同底色/描边/圆角） */
.btn-more {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  height: 38px; padding: 0 13px;
  border-radius: 10px; cursor: pointer; font: inherit;
  background: var(--ink-2); border: 1px solid var(--ink-4); color: var(--text-2);
  font-size: 12.5px; font-weight: 700; white-space: nowrap;
  transition: border-color .16s, background .16s, color .16s;
}
.btn-more svg { width: 15px; height: 15px; flex: none; }
.btn-more:hover { border-color: rgba(255, 224, 0, .5); background: var(--ink-3); color: var(--text); }
.btn-more.on, body.filters-open .btn-more { border-color: var(--gold); color: var(--gold-ink); background: rgba(255, 224, 0, .07); }
.btn-more-n {
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: 999px;
  background: var(--gold); color: var(--on-accent);
  font-size: 10.5px; font-style: normal; font-weight: 900; line-height: 17px; text-align: center;
}

/* ④ 桌面：筛选面板从「常驻左栏」变成「居中弹窗」
      —— 和手机上已有的形态统一（那边 ≤900 早就是模态了）。
      要点：默认 display:none；`body.filters-open` 时才铺满视口做遮罩层，
      `.filters-in` 居中成一枚 760 宽的卡片、内部自己滚。 */
@media (min-width: 901px) {
  .filters { display: none; }

  body.filters-open .filters {
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    position: fixed; inset: 0;
    left: 0; top: 0;
    width: auto; height: auto; max-height: none; max-width: none;
    padding: 26px;
    background: rgba(8, 8, 8, .64);
    -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
    z-index: 300;                    /* 高于顶栏(70)、高于页脚抽屉(80) */
  }
  body.filters-open .filters-in {
    position: relative;
    width: min(780px, 100%); max-width: 780px;
    max-height: 86vh; overflow-y: auto;
    border-radius: 18px;
    background: var(--ink-2); border: 1px solid var(--ink-4);
    box-shadow: 0 30px 70px -24px rgba(0, 0, 0, .85);
    /* 2026-10-26：右边从 24 收到 10 —— 右栏的滚动条原来离弹窗边 40px，
       像一条"悬在内容中间"的灰线（店主圈的就是它）。现在贴到 10px 以内。 */
    padding: 0 10px 18px 24px;
  }
  /* 弹窗头（「筛选」+ ✕）：桌面也显示 —— 它是这个弹窗唯一的关闭按钮。
     ≤900 有一段同名规则（brand-home.css），两边形态一致，这里给桌面补一份。 */
  body.filters-open .fmodal-head {
    display: flex; align-items: center; justify-content: space-between;
    position: sticky; top: 0; z-index: 2;
    /* 左右负边距要跟 `.filters-in` 的内边距对上（左 24 / 右 10），否则头部会歪 */
    margin: 0 -10px 0 -24px; padding: 15px 10px 12px 24px;
    background: var(--ink-2);
    border-bottom: 1px solid var(--ink-4);
    border-radius: 18px 18px 0 0;
  }
  body.filters-open .fmodal-head .t { font-size: 14px; font-weight: 800; color: var(--text); }
  body.filters-open .fmodal-x {
    width: 32px; height: 32px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    padding: 0; border: 1.5px solid var(--ink-4);
    background: var(--ink-3); color: var(--text-2);
    cursor: pointer; transition: .15s;
  }
  body.filters-open .fmodal-x:hover { color: var(--text); border-color: var(--text-3); }
  body.filters-open .fmodal-x svg { width: 13px; height: 13px; display: block; }

  /* ── 两栏（2026-10-25 第二次，店主给的是参考图里的"左侧列表 + 右侧详情"）──
     左栏 = 7 个选择项（价位 + 六维），右栏 = 当前那一项的**全部选项**。
     左栏只放标题行（`.fopts` 被 JS 搬进右栏，CSS 里也兜一层隐藏），
     所以 `#fgrid` 从"两列网格"退成一个普通的纵向列表。 */
  body.filters-open .filters-in {
    display: flex; flex-direction: column;
    overflow: hidden;                       /* 滚动交给右栏，外壳不动 */
    /* 🔴 2026-10-26 店主：「我的意思是一直保持这样的高度，不会因为点到其他地方
       就会更改高度」（对比图：系列 40+ 芯片撑到 700，职业 9 个缩到 360）。
       所以高度是**定值**、不是 `max-height`：两栏本来就该像一块固定窗，
       内容在右栏里滚。改窄改高只动这一处，左右两栏跟着一起变。 */
    height: min(720px, 86vh);
    /* 🔴 基础样式里有 `scrollbar-gutter: stable`（单栏时代为"切组不横跳"加的）。
       两栏模式下外壳根本不滚，那条只会白占 17px —— 右栏的滚动条因此离弹窗边
       还有 26px（店主圈的就是它）。这里收回。 */
    scrollbar-gutter: auto;
  }
  .fmodal-body { display: flex; flex: 1 1 auto; min-height: 0; }

  body.filters-open #fgrid.fg-inline {
    display: block;
    flex: 0 0 238px;
    overflow-y: auto;
    border-right: 1px solid var(--ink-4);
    padding: 6px 10px 10px 0;
  }
  /* 左栏里每组只剩一行标题：去掉原来的分隔线与上内边距 */
  body.filters-open #fgrid > .fgroup { border-top: 0; padding: 0; }
  body.filters-open #fgrid > #fRange { display: none; }   /* 价位只在右栏出现 */
  body.filters-open #fgrid .fgroup > .fopts { display: none; }

  /* 左栏每一项（含「价位」那颗按钮）统一成一行：图标 + 名称 + 当前值 + › */
  body.filters-open #fgrid .fhead,
  body.filters-open .fnav-price {
    display: flex; align-items: center; gap: 8px;
    width: 100%; padding: 9px 10px; margin: 1px 0;
    border-radius: 10px; border: 1px solid transparent;
    text-align: left; cursor: pointer; background: none;
    transition: background .15s, border-color .15s, color .15s;
  }
  body.filters-open #fgrid .fhead:hover,
  body.filters-open .fnav-price:hover { background: var(--ink-3); }
  /* 选中项：金线 + 淡金底 —— 一眼能看出"右栏现在显示的是哪一项" */
  body.filters-open #fgrid .fgroup.is-cur .fhead,
  body.filters-open .fnav-price.is-cur {
    background: rgba(255, 224, 0, .09);
    border-color: rgba(255, 224, 0, .45);
  }
  body.filters-open #fgrid .fhead .fico,
  body.filters-open .fnav-price .fico { width: 20px; height: 20px; border-radius: 6px; flex: none; }
  body.filters-open #fgrid .fhead .fico svg,
  body.filters-open .fnav-price .fico svg { width: 13px; height: 13px; }
  body.filters-open #fgrid .fhead .fmeta,
  body.filters-open .fnav-price .fmeta { flex: 1 1 auto; flex-direction: row; align-items: baseline; gap: 6px; min-width: 0; }
  body.filters-open #fgrid .fhead .fsum,
  body.filters-open .fnav-price .fsum { flex: 1 1 auto; text-align: right; font-size: 10.5px; }
  /* 折叠箭头 → 改成"进入右侧"的 › （这一栏没有折叠，别让箭头说谎） */
  body.filters-open #fgrid .fhead::after,
  body.filters-open .fnav-price::after {
    content: ""; flex: none; width: 6px; height: 6px; margin-left: 2px;
    border-top: 1.6px solid var(--text-3); border-right: 1.6px solid var(--text-3);
    border-bottom: 0;
    transform: rotate(45deg);
  }

  /* 右栏 */
  body.filters-open #fFilterPane {
    flex: 1 1 auto; min-width: 0; min-height: 0;
    overflow-y: auto;
    padding: 10px 4px 10px 20px;
    /* 2026-10-26：原来这里写 `max-height: 66vh` —— 那正是"弹窗忽高忽低"的来源
       （职业只有 9 个芯片时外壳被压到 360）。外壳已改成定高，右栏就该**撑满**，
       只在自己的框里滚。 */
    max-height: none;
    /* 滚动条槽位**常驻**：切到「费用」（无滚动）时不重排，
       行宽变了就会重新换行 —— 那正是"行高忽大忽小"的来源。 */
    scrollbar-gutter: stable;
    overscroll-behavior: contain;
  }
  /* 滚动条：8px 细轨 + 低对比拇指（全站默认 10px/--ink-4 在这块太抢眼） */
  body.filters-open #fFilterPane::-webkit-scrollbar { width: 8px; }
  body.filters-open #fFilterPane::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, .16); border-radius: 99px;
    border: 2px solid transparent; background-clip: content-box;
  }
  body.filters-open #fFilterPane::-webkit-scrollbar-thumb:hover {
    background: rgba(0, 0, 0, .32); background-clip: content-box;
  }
  html[data-theme="dark"] body.filters-open #fFilterPane::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, .16); background-clip: content-box;
  }
  html[data-theme="dark"] body.filters-open #fFilterPane::-webkit-scrollbar-thumb:hover {
    background: rgba(255, 255, 255, .3); background-clip: content-box;
  }
  body.filters-open #fFilterPane .fopts { display: flex; flex-wrap: wrap; gap: 7px; }
  /* 2026-10-26 店主：「筛选界面始终保持这样的行高」——
     改成**固定 34px**：长名字（公主连结Re:Dive）不许折成两行、带代码尾巴的不许比旁边高，
     行与行永远等距。超出用省略号（完整名字在 title 里）。 */
  body.filters-open #fFilterPane .fopt {
    width: auto; flex: 0 0 auto;
    height: 34px; padding: 0 11px;
    display: inline-flex; align-items: center;
    font-size: 12.5px; line-height: 1;
  }
  body.filters-open #fFilterPane .fopt .t {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* 价位在右栏里给足宽度（两个输入框并排，比原来的 40px 高小条好填） */
  body.filters-open #fFilterPane #fRange {
    display: flex; align-items: center; gap: 10px;
    margin: 0; height: 44px; max-width: 420px;
  }
  body.filters-open #fFilterPane #fRange .frange-in { height: 100%; }
}

/* ── 手机：两栏退化成"上方横向标签条 + 下方内容" ─────────────────────
   390 宽的屏放不下 238 的左栏 + 内容；横滑一行标签更接近它原本的形态。 */
@media (max-width: 900px) {
  .fmodal-body { display: flex; flex-direction: column; min-height: 0; }
  /* 2026-10-26：手机这一格的高度**本来就是恒定的** —— brand-home.css 里
     `.filters-in { flex: 1 1 auto }` 让它在 `.filters`（flex 列）里撑满整屏，
     换维度只会改右栏高度，外壳一直是整屏。这里只把结构显式写成"列 + 裁溢出"，
     与桌面同构（免得以后有人把 flex:1 去掉之后右栏不再自己滚）。 */
  body.filters-open .filters-in {
    display: flex; flex-direction: column;
    overflow: hidden;
  }
  #fgrid.fg-inline {
    display: flex; gap: 6px; align-items: center;
    overflow-x: auto; overflow-y: hidden;
    padding: 0 0 10px;
    border-bottom: 1px solid var(--ink-4);
    flex: none;
    scrollbar-width: none;
  }
  #fgrid.fg-inline::-webkit-scrollbar { display: none; }
  #fgrid.fg-inline > .fgroup { flex: none; width: auto; border: 0; padding: 0; }
  #fgrid.fg-inline > #fRange { display: none; }
  #fgrid.fg-inline .fgroup > .fopts { display: none; }
  .fnav-price, #fgrid.fg-inline .fhead {
    display: flex; align-items: center; gap: 6px; width: auto; white-space: nowrap;
    padding: 7px 11px; border-radius: 999px;
    border: 1px solid var(--ink-4); background: var(--ink-2);
    font-size: 12px; color: var(--text-2);
  }
  .fnav-price .fico, #fgrid.fg-inline .fhead .fico { display: none; }
  .fnav-price .fsum, #fgrid.fg-inline .fhead .fsum { display: none; }
  #fgrid.fg-inline .fhead::after, .fnav-price::after { content: none; }
  #fgrid.fg-inline .fgroup.is-cur .fhead,
  .fnav-price.is-cur { background: var(--gold); border-color: var(--gold); color: var(--on-accent); }
  #fFilterPane { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 12px 0 4px; }
  #fFilterPane #fRange { display: flex; height: 40px; margin: 0; }
}


/* ══════════════════════════════════════════════════════════════════════════
   「筛选卡库」两栏（2026-10-26 店主：「PC 的所有这个筛选页面都要换成这个类型」）
   ──────────────────────────────────────────────────────────────────────────
   原来的形态是一列可折叠的组（费用 / 稀有度 / 卡种 / 系列 / 种族），
   要筛「系列」得先展开它、再在一屏里往下找 —— 组一多就变成一条长卷。
   现在与卡库页「更多筛选」同构：左栏五个维度、右栏当前维度的全部选项。
   DOM 由 cardfilter.js 每次开窗现建（#cfMask / .cf2），这里只管长相。
   ══════════════════════════════════════════════════════════════════════════ */
.fmodal.cf2 {
  width: min(860px, 100%);
  /* 高度**固定**（不是 max-height）：费用只有 10 个芯片、种族 126 个，
     若让内容撑高，切换维度时弹窗会从 360 跳到 700 —— 每点一次换一次位置。
     两栏本来就该像一块固定窗，内容在里面滚。 */
  height: min(620px, 86vh);
  max-height: 86vh;
}
.cf2-hd {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
  /* 右 10 与 `.cf2-body` 的右边距对齐（2026-10-26：滚动条要贴到弹窗右边） */
  padding: 18px 10px 12px 24px;
}
.cf2-hd h3 { margin-bottom: 2px; }
.cf2-x {
  flex: none; width: 32px; height: 32px; margin-top: -2px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; padding: 0;
  border: 1.5px solid var(--ink-4); background: var(--ink-3); color: var(--text-2);
  cursor: pointer; transition: color .15s, border-color .15s;
}
.cf2-x:hover { color: var(--text); border-color: var(--text-3); }
.cf2-x svg { width: 13px; height: 13px; display: block; }

.cf2-body {
  display: flex; flex: 1 1 auto; min-height: 0;
  /* 右 10：右栏滚动条原来离弹窗边 25px，像悬在内容里的一条灰线 → 收到 10px 以内 */
  margin: 0 10px 0 24px;
  border-top: 1px solid var(--ink-4);
}
/* 左栏：五个维度。宽度固定，`i` 那句是"当前选了什么"（收起也能看见） */
.cf2-nav {
  flex: 0 0 210px; overflow-y: auto;
  padding: 10px 10px 10px 0; border-right: 1px solid var(--ink-4);
}
.cf2-it {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 9px 10px; margin: 1px 0;
  border: 1px solid transparent; border-radius: 10px; background: none;
  color: var(--text-2); font: inherit; text-align: left; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.cf2-it:hover { background: var(--ink-3); }
.cf2-it.is-cur {
  background: rgba(255, 224, 0, .09);
  border-color: rgba(255, 224, 0, .45);
  color: var(--text);
}
.cf2-ico {
  flex: none; width: 22px; height: 22px; border-radius: 6px;
  display: grid; place-items: center;
  background: var(--ink-3); color: var(--text-3);
}
.cf2-ico svg { width: 14px; height: 14px; }
.cf2-it.is-cur .cf2-ico { background: rgba(255, 224, 0, .16); color: var(--gold-ink); }
.cf2-meta { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cf2-meta b { font-size: 12.5px; font-weight: 800; color: inherit; }
.cf2-meta i {
  font-style: normal; font-size: 10.5px; color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cf2-it.has .cf2-meta i { color: var(--gold-ink); }

/* 右栏：当前维度的全部芯片（自己滚，弹窗本体不滚） */
.cf2-pane {
  flex: 1 1 auto; min-width: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 12px 4px 12px 20px;
  /* 槽位常驻：切到「费用」（10 个芯片、无滚动）时宽度不跳，行不会被重新折行 */
  scrollbar-gutter: stable;
}
/* 滚动条：8px 细轨 + 低对比拇指（全站 10px/--ink-4 在这块太显眼） */
.cf2-pane::-webkit-scrollbar { width: 8px; }
.cf2-pane::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, .16); border-radius: 99px;
  border: 2px solid transparent; background-clip: content-box;
}
.cf2-pane::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, .32); background-clip: content-box; }
html[data-theme="dark"] .cf2-pane::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .16); background-clip: content-box; }
html[data-theme="dark"] .cf2-pane::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, .3); background-clip: content-box; }
.cf2-cloud { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start; }
/* 系列重名时的弱化代码尾巴（2026-10-26）：中文名是主体，代码只用来区分
   同名的几盒（入门预组 / 联动预组）。别把它做成主色，否则又变回"看代码"。 */
.fopt .code {
  font-style: normal; font-size: 10px; font-weight: 700;
  color: var(--text-3); margin-left: 4px; letter-spacing: .02em;
}

/* ⚠️ `.fopts.scroll .fopt{width:100%}` 是旧"一行一条"的遗留 ——
   右栏用的是普通 div，但万一宿主把它换成 .fopts，这条也能兜住。 */
/* 固定行高 34px（2026-10-26 店主：「筛选界面始终保持这样的行高」）：
   长名字不许折两行、带代码尾巴的不许比旁边高 —— 行距永远一致。
   超长用省略号，完整名字在 title 里。 */
.cf2-cloud .fopt {
  width: auto; flex: 0 0 auto;
  height: 34px; padding: 0 11px;
  display: inline-flex; align-items: center;
  font-size: 12.5px; line-height: 1;
}
.cf2-cloud .fopt .t { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 系列的三节小标题（补充包 / 预组 / PR卡）占满一整行 */
.cf2-cloud .fsub {
  flex: 0 0 100%; margin: 12px 0 0;
  font-size: 10.5px; font-weight: 800; letter-spacing: .14em;
  color: var(--text-3);
}
.cf2-cloud .fsub:first-child { margin-top: 0; }

/* 手机（≤700）：两栏放不下，退化成「上方横向标签条 + 下方内容」——
   和卡库页筛选弹窗在窄屏的处理一致。 */
@media (max-width: 700px) {
  /* 手机上 620 的固定高度会在「费用」这种只有 10 个芯片的维度里留下半屏空白 →
     改按内容高（上限 88vh），只有右栏自己封顶滚动。PC 仍用固定高（切换不跳）。 */
  .fmodal.cf2 { height: auto; max-height: 88vh; }
  .cf2-body { flex: 0 1 auto; flex-direction: column; margin: 0 16px; }
  .cf2-pane { max-height: 52vh; }
  .cf2-nav {
    flex: none; display: flex; gap: 6px; align-items: center;
    overflow-x: auto; overflow-y: hidden;
    padding: 9px 0; border-right: 0; border-bottom: 1px solid var(--ink-4);
    scrollbar-width: none;
  }
  .cf2-nav::-webkit-scrollbar { display: none; }
  .cf2-it {
    width: auto; flex: none; padding: 6px 12px; border-radius: 999px;
    border: 1px solid var(--ink-4); background: var(--ink-2);
    font-size: 12px; white-space: nowrap;
  }
  .cf2-ico { display: none; }
  .cf2-meta i { display: none; }
  .cf2-it.is-cur { background: var(--gold); border-color: var(--gold); color: var(--on-accent); }
  .cf2-pane { padding: 12px 0 4px; }
}
