/* vps-mall 前台样式 —— 从 prototype/front.html v10 拆出
   设计 token（颜色/圆角/阴影/字体/缓动）全部来自 tokens.css（唯一色源），
   本文件只保留页面级布局变量与组件样式。 */
:root{
  /* 页面宽度（后台「展示设置 → 页面宽度与顶部栏」可改；0/100% = 全宽铺满） */
  --page-w: 1620px;
  --page-pad: 20px;
  --top-w: var(--page-w);
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{font-family:var(--font);background:var(--bg);color:var(--text);font-size:14px;line-height:1.55;
  -webkit-font-smoothing:antialiased;text-wrap:pretty;overflow-x:hidden}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer;border:0;background:none;color:inherit}
input,select{font-family:inherit;color:inherit}
::selection{background:var(--brand-line)}
.num{font-family:var(--mono);font-feature-settings:"tnum" 1}

/* ============ 顶栏（背景整幅铺满，内容按 --top-w 对齐） ============ */
.topbar{
  position:sticky;top:0;z-index:60;
  height:62px;background:color-mix(in srgb,var(--surface) 90%,transparent);
  backdrop-filter:blur(14px) saturate(1.4);border-bottom:1px solid var(--border);
}
.topbar .tb-in{display:flex;align-items:center;gap:20px;height:100%;
  max-width:var(--top-w);margin:0 auto;padding:0 var(--page-pad)}
.brand{display:flex;align-items:center;gap:10px;flex:0 0 auto}
.logo{width:34px;height:34px;border-radius:9px;flex:0 0 auto;
  background:linear-gradient(150deg,var(--brand),var(--brand-ink));display:grid;place-items:center;color:#fff;box-shadow:var(--sh-2)}
.brand-name{font-weight:700;font-size:15.5px;letter-spacing:.2px;line-height:1.15}
.brand-sub{font-size:11px;color:var(--text-3);letter-spacing:.4px}
.mainnav{display:flex;align-items:center;gap:2px;margin-left:4px;flex:1 1 auto;min-width:0;overflow:auto;scrollbar-width:none}
.mainnav::-webkit-scrollbar{display:none}
.mainnav a{position:relative;padding:8px 13px;border-radius:var(--r-sm);font-size:13.5px;font-weight:500;
  color:var(--text-2);white-space:nowrap;transition:color .16s var(--ease),background .16s var(--ease)}
.mainnav a:hover{color:var(--text);background:var(--surface-2)}
.mainnav a.on{color:var(--brand-ink);background:var(--brand-soft);font-weight:600}
.topright{display:flex;align-items:center;gap:8px;flex:0 0 auto}
.seg{display:flex;background:var(--surface-2);border:1px solid var(--border);border-radius:8px;padding:2px}
.seg button{padding:4px 9px;border-radius:6px;font-size:12px;color:var(--text-2);font-weight:500;transition:all .15s var(--ease)}
.seg button.on{background:var(--surface);color:var(--text);box-shadow:var(--sh-1);font-weight:600}
.iconbtn{width:34px;height:34px;border-radius:9px;display:grid;place-items:center;color:var(--text-2);
  border:1px solid transparent;transition:all .15s var(--ease)}
.iconbtn:hover{background:var(--surface-2);color:var(--text);border-color:var(--border)}
.btn{display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 14px;border-radius:9px;font-size:13px;
  font-weight:600;transition:all .16s var(--ease);white-space:nowrap}
.btn-p{background:var(--brand);color:#fff;box-shadow:var(--sh-1)}
.btn-p:hover{filter:brightness(1.07);box-shadow:var(--sh-2)}
.btn-g{border:1px solid var(--border);color:var(--text-2);background:var(--surface)}
.btn-g:hover{border-color:var(--border-strong);color:var(--text)}

/* ============ 主题气泡（顶栏，任何人都可改，选择写本地缓存） ============ */
.themepop{position:fixed;top:70px;right:18px;z-index:150;width:318px;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--sh-4);padding:15px;
  display:none;flex-direction:column;gap:12px}
.themepop.on{display:flex;animation:pop .2s var(--ease)}
.tp-h{font-size:12px;font-weight:700;color:var(--text-2);letter-spacing:.3px}
.tp-row{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}
.tp-row button{display:flex;align-items:center;justify-content:center;gap:6px;height:36px;border-radius:9px;
  border:1px solid var(--border);background:var(--surface-2);font-size:12.5px;color:var(--text-2);font-weight:500;
  transition:all .15s var(--ease)}
.tp-row button:hover{border-color:var(--border-strong);color:var(--text)}
.tp-row button.on{background:var(--brand-soft);border-color:var(--brand-line);color:var(--brand-ink);font-weight:600}
.tp-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}
.tp-row5{grid-template-columns:repeat(5,1fr)}
.tp-row5 button{font-size:12px;padding:0 2px}
.tp-c{display:flex;align-items:center;gap:7px;height:36px;padding:0 9px;border-radius:9px;
  border:1px solid var(--border);background:var(--surface);font-size:12.5px;color:var(--text-2);transition:all .15s var(--ease)}
.tp-c:hover{border-color:var(--border-strong);color:var(--text)}
.tp-c.on{border-color:var(--brand);background:var(--brand-soft);color:var(--brand-ink);font-weight:600}
.tp-c i{width:12px;height:12px;border-radius:99px;display:block;flex:0 0 auto}
.tp-foot{font-size:11px;color:var(--text-3);border-top:1px solid var(--border);padding-top:10px;line-height:1.6}

/* ============ 布局 ============ */
.layout{display:grid;grid-template-columns:248px minmax(0,1fr);gap:20px;max-width:var(--page-w);margin:0 auto;
  padding:20px var(--page-pad) 64px}

/* ============ 侧边栏（每个栏目块一张独立卡片，块间分区块不堆叠） ============ */
.side{display:flex;flex-direction:column;gap:10px;align-self:start;position:static}
.side-body{display:flex;flex-direction:column;gap:10px;background:transparent;border:0;
  border-radius:0;box-shadow:none;padding:0}
.blk{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);
  box-shadow:var(--sh-1);overflow:hidden;padding:5px 5px 7px}
.blk-h{display:flex;align-items:center;gap:7px;padding:8px 8px 5px;font-size:11px;font-weight:700;
  letter-spacing:.5px;color:var(--text-3);text-transform:uppercase}
.blk-h .dot{width:5px;height:5px;border-radius:2px;background:var(--brand);flex:0 0 auto}
.blk-h .n{margin-left:auto;font-family:var(--mono);font-size:10.5px;color:var(--text-3);
  background:var(--surface-2);padding:0 5px;border-radius:5px;letter-spacing:0}
.blk-b{padding:0 2px 2px;position:relative}
/* 液态选中块：一块圆角墨迹在列内滑动，取代「每一项自己变底色」。
   点栏目时 .on 原地切换 + 墨迹 translateY/height 过渡 → 有连续的位移感，
   而不是整棵树重建后底色「啪」地跳过去。 */
.sb-ink{position:absolute;left:2px;right:2px;top:0;height:0;z-index:0;opacity:0;border-radius:7px;
  background:var(--brand-soft);border:1px solid var(--brand-line);pointer-events:none;
  transition:transform .34s var(--ease),height .34s var(--ease),opacity .2s var(--ease)}
.sb-ink.on{opacity:1}
.side-body .blk-b>.item{position:relative;z-index:1}
/* 选中项的底色交给墨迹（否则两块色叠在一起），文字仍由 .item.on 上色。
   hover 时也不给它盖一层 surface-2，否则墨迹会被 hover 底色吃掉。 */
.side-body .item.on,.side-body .item.on:hover{background:transparent}
.item{display:flex;align-items:center;gap:8px;padding:6px 7px;border-radius:7px;font-size:13px;
  color:var(--text-2);transition:all .14s var(--ease);cursor:pointer;min-width:0}
.item:hover{background:var(--surface-2);color:var(--text)}
.item.on{background:var(--brand-soft);color:var(--brand-ink);font-weight:600}
.item .ic{width:15px;height:15px;flex:0 0 auto;color:var(--text-3)}
.item.on .ic{color:var(--brand)}
.item .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.item.tool{cursor:pointer}
.item.tool .tail{display:inline-flex;color:var(--text-3);opacity:.55}
.item.tool:hover .tail{opacity:1;color:var(--brand-ink)}
.item .tail{font-size:11px;color:var(--text-3);font-family:var(--mono);flex:0 0 auto}
.item.soon{opacity:.62;cursor:default}
.item.soon:hover{background:transparent;color:var(--text-2)}
.item .soonTag{font-size:10px;padding:1px 5px;border-radius:4px;background:var(--warn-soft);color:var(--warn);font-weight:600}
/* 三级条目 */
.item.l3{padding-left:24px;font-size:12.5px}
.item.l3 .ic{width:12px;height:12px}
.l3wrap{position:relative;margin:2px 0 4px}
.l3wrap::before{content:"";position:absolute;left:15px;top:2px;bottom:4px;width:1px;background:var(--border)}
.chk{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:7px;font-size:13px;color:var(--text-2);
  cursor:pointer;transition:background .14s var(--ease)}
.chk:hover{background:var(--surface-2)}
.box{width:15px;height:15px;border-radius:4px;border:1.5px solid var(--border-strong);display:grid;place-items:center;
  flex:0 0 auto;transition:all .14s var(--ease)}
.chk.on .box{background:var(--brand);border-color:var(--brand);color:#fff}
.chk.on{color:var(--text);font-weight:500}
.box svg{opacity:0;transform:scale(.6);transition:all .14s var(--ease)}
.chk.on .box svg{opacity:1;transform:scale(1)}
.chk .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chk .tail{font-size:11px;color:var(--text-3);font-family:var(--mono)}

/* ============ 主区 ============ */
.main{min-width:0;display:flex;flex-direction:column;gap:13px}
.crumb{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--text-3);flex-wrap:wrap}
.crumb b{color:var(--text-2);font-weight:500}
.crumb .sep{opacity:.5;display:inline-flex}
.crumb b.now{color:var(--brand-ink);font-weight:600}
/* 面包屑每一级都是可点的「回到那一级」（最后一段为当前位置，渲染成 b.now 不可点）
   默认给一条浅虚线，明确表达"可点"；hover 才转成品牌色实线 + 浅底 */
.crumb .cbtn{font:inherit;color:var(--text-2);font-weight:500;cursor:pointer;background:none;border:0;
  padding:0;border-radius:5px;
  text-decoration:underline;text-decoration-style:dashed;text-decoration-color:var(--border-strong);
  text-underline-offset:3px;text-decoration-thickness:1px;
  transition:color .14s var(--ease),background .14s var(--ease)}
.crumb .cbtn:hover{color:var(--brand-ink);background:var(--brand-soft);
  text-decoration-style:solid;text-decoration-color:currentColor}
.crumb .cbtn:focus-visible{outline:2px solid var(--brand-line);outline-offset:1px}

.listhd{display:flex;align-items:flex-end;gap:12px;flex-wrap:wrap}
.listhd-a{margin-left:auto;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.listhd h1{margin:0;font-size:22px;font-weight:700;letter-spacing:-.3px}
.listhd .sub{font-size:12.5px;color:var(--text-3);margin-top:3px}
.listhd .sub b{font-family:var(--mono);color:var(--brand-ink);font-weight:600}

/* ============ 筛选面板（紧凑 · 控件宽度按内容自适应） ============ */
.filters{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);
  box-shadow:var(--sh-1);padding:12px 13px 11px;display:flex;flex-direction:column;gap:9px}
.f-r1,.f-r2,.f-r3{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.f-r2,.f-r3{padding-top:9px;border-top:1px solid var(--border)}
.fgrp{display:flex;align-items:center;gap:7px;flex-wrap:wrap;min-width:0}
.fdiv{width:1px;height:20px;background:var(--border);flex:0 0 auto;margin:0 2px}
.fend{margin-left:auto;display:flex;align-items:center;gap:7px}
.search{display:flex;align-items:center;gap:8px;height:36px;padding:0 11px;flex:1 1 240px;max-width:440px;
  border:1px solid var(--border);border-radius:9px;background:var(--surface-2);transition:all .15s var(--ease)}
.search:focus-within{border-color:var(--brand);background:var(--surface);box-shadow:0 0 0 3px var(--brand-soft)}
.search input{flex:1;border:0;outline:0;background:none;font-size:13.5px;min-width:0}
.search input::placeholder{color:var(--text-3)}
.kwclr{display:none;width:18px;height:18px;border-radius:5px;place-items:center;color:var(--text-3);flex:0 0 auto}
.search.has .kwclr{display:grid}
.kwclr:hover{background:var(--surface-3);color:var(--text)}
.mode{display:inline-flex;background:var(--surface-2);border:1px solid var(--border);border-radius:9px;padding:3px;flex:0 0 auto}
.mode button{padding:5px 12px;border-radius:7px;font-size:12.5px;color:var(--text-2);font-weight:600;
  display:inline-flex;align-items:center;gap:5px;transition:all .15s var(--ease)}
.mode button.on{background:var(--brand);color:#fff}
.morebtn{display:none;align-items:center;gap:5px;height:36px;padding:0 12px;border-radius:9px;
  border:1px solid var(--border);background:var(--surface-2);font-size:12.5px;font-weight:600;color:var(--text-2)}
/* 数值字段：标签内联 + 单位后缀，宽度由内容决定 */
.nf{display:inline-flex;align-items:center;gap:5px;height:32px;padding:0 10px;border:1px solid var(--border);
  border-radius:9px;background:var(--surface-2);transition:all .15s var(--ease);cursor:text}
.nf:hover{border-color:var(--border-strong)}
.nf:focus-within{border-color:var(--brand);background:var(--surface);box-shadow:0 0 0 3px var(--brand-soft)}
.nf .lb{font-size:11.5px;color:var(--text-3);white-space:nowrap}
.nf .op{font-family:var(--mono);font-size:12px;color:var(--brand-ink);font-weight:600}
.nf input{width:44px;border:0;outline:0;background:none;font-family:var(--mono);font-size:13px;text-align:right}
.nf input::placeholder{color:var(--text-3)}
.nf .un{font-size:11px;color:var(--text-3);white-space:nowrap}
.dirbtn{height:32px;padding:0 12px;border:1px solid var(--border);border-radius:9px;background:var(--surface-2);
  font-size:13px;font-weight:600;color:var(--text-2);display:inline-flex;align-items:center;gap:6px;
  transition:all .15s var(--ease);white-space:nowrap}
.dirbtn:hover{border-color:var(--border-strong);color:var(--text)}
.resetbtn{height:32px;padding:0 12px;border-radius:9px;font-size:13px;font-weight:600;color:var(--text-2);
  display:inline-flex;align-items:center;gap:6px;transition:all .15s var(--ease);white-space:nowrap}
.resetbtn:hover{color:var(--brand-ink);background:var(--brand-soft)}

/* 已选条件 chips */
.chips{display:none;align-items:center;gap:6px;flex-wrap:wrap;padding-top:9px;border-top:1px solid var(--border)}
.chips.on{display:flex}
.chips .clb{font-size:11.5px;color:var(--text-3)}
.chip{display:inline-flex;align-items:center;gap:5px;height:26px;padding:0 9px;border-radius:7px;
  background:var(--surface-2);border:1px solid var(--border);font-size:12px;color:var(--text-2);white-space:nowrap}
.chip:hover{border-color:var(--brand-line);color:var(--brand-ink)}
.chip .cx{display:inline-flex;color:var(--text-3)}
.chip:hover .cx{color:var(--brand-ink)}
.chip.clr{background:transparent;border-style:dashed;color:var(--text-3)}
.chip.clr:hover{color:var(--up);border-color:var(--up)}

/* 通用下拉（地区含二级城市 / 库存 / 排序 / 币种） */
.dd{position:relative}
.dd-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 10px;border:1px solid var(--border);
  border-radius:9px;background:var(--surface-2);font-size:13px;color:var(--text-2);transition:all .15s var(--ease)}
.dd-btn:hover{border-color:var(--border-strong)}
.dd-btn .lb{font-size:11.5px;color:var(--text-3);white-space:nowrap}
.dd-btn .vl{font-weight:600;color:var(--text);white-space:nowrap}
.dd-btn .vl.def{font-weight:400;color:var(--text-3)}
.dd.on .dd-btn,.dd.open .dd-btn{border-color:var(--brand);background:var(--surface)}
.dd-ar{display:inline-flex;color:var(--text-3);transition:transform .18s var(--ease)}
.dd.open .dd-ar{transform:rotate(180deg)}
.dd-pop{position:absolute;z-index:48;top:calc(100% + 6px);left:0;min-width:100%;width:max-content;
  max-width:min(300px,86vw);background:var(--surface);border:1px solid var(--border);border-radius:12px;
  box-shadow:var(--sh-3);padding:5px;display:none}
.dd.open .dd-pop{display:block;animation:pop .16s var(--ease)}
.dd-opt{position:relative;display:flex;align-items:center;gap:8px;height:33px;padding:0 10px;border-radius:8px;
  font-size:13px;color:var(--text-2);cursor:pointer;white-space:nowrap;transition:background .14s var(--ease)}
.dd-opt:hover{background:var(--surface-2);color:var(--text)}
.dd-opt.on{background:var(--brand-soft);color:var(--brand-ink);font-weight:600}
.dd-opt.has-sub.open{background:var(--surface-2)}
.dd-opt .nm{flex:1;min-width:36px;overflow:hidden;text-overflow:ellipsis}
.dd-opt .cn{font-family:var(--mono);font-size:11px;color:var(--text-3)}
.dd-opt.on .cn{color:var(--brand-ink)}
.dd-opt .ar{display:inline-flex;color:var(--text-3)}
.dd-sub{position:absolute;left:calc(100% + 4px);top:-5px;min-width:148px;background:var(--surface);
  border:1px solid var(--border);border-radius:12px;box-shadow:var(--sh-3);padding:5px;display:none}
.dd-opt.has-sub:hover>.dd-sub,.dd-opt.has-sub.open>.dd-sub{display:block;animation:pop .14s var(--ease)}

/* 下拉多选（线路 / 退款政策） */
.msel{position:relative;min-width:0}
.msel-btn{display:flex;align-items:center;gap:7px;height:32px;padding:0 10px;border:1px solid var(--border);
  border-radius:9px;background:var(--surface-2);font-size:13px;color:var(--text-2);width:100%;min-width:0;
  transition:all .15s var(--ease)}
.msel-btn:hover{border-color:var(--border-strong);color:var(--text)}
.msel.open .msel-btn,.msel.on .msel-btn{border-color:var(--brand);background:var(--surface)}
.msel-btn .lb{font-size:11.5px;color:var(--text-3);white-space:nowrap;flex:0 0 auto}
.msel.open .msel-btn .lb{color:var(--text-2)}
.msel-tx{flex:1;min-width:0;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.msel-tx.has{color:var(--text);font-weight:600}
.msel-bdg{font-family:var(--mono);font-size:10.5px;background:var(--brand);color:#fff;border-radius:5px;padding:1px 5px;flex:0 0 auto}
.msel-ar{flex:0 0 auto;color:var(--text-3);display:inline-flex;transition:transform .18s var(--ease)}
.msel.open .msel-ar{transform:rotate(180deg)}
.msel-pop{position:absolute;z-index:45;top:calc(100% + 6px);left:0;width:max(100%,210px);max-height:264px;overflow:auto;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r);box-shadow:var(--sh-3);padding:6px;display:none}
.msel.open .msel-pop{display:block;animation:pop .16s var(--ease)}
.msel-opt{display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:7px;font-size:13px;color:var(--text-2);
  cursor:pointer;transition:background .14s var(--ease)}
.msel-opt:hover{background:var(--surface-2);color:var(--text)}
.msel-opt.on{color:var(--text);font-weight:500}
.msel-opt .nm{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.msel-opt .tail{font-size:11px;color:var(--text-3);font-family:var(--mono)}
.msel-opt .box svg{opacity:0;transform:scale(.6);transition:all .14s var(--ease)}
.msel-opt.on .box{background:var(--brand);border-color:var(--brand);color:#fff}
.msel-opt.on .box svg{opacity:1;transform:scale(1)}
.msel-foot{display:flex;gap:6px;border-top:1px solid var(--border);margin-top:5px;padding-top:6px}
.msel-foot button{flex:1;height:28px;border-radius:7px;font-size:12px;font-weight:600;color:var(--text-2);background:var(--surface-2)}
.msel-foot button:hover{color:var(--brand-ink);background:var(--brand-soft)}

/* ============ 列表工具条 / 页脚 ============ */
.toolbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.toolbar .sp{flex:1}
.pp{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--text-3)}
.pp select{height:30px;padding:0 7px;border:1px solid var(--border);border-radius:8px;background:var(--surface);
  font-size:12.5px;outline:0;cursor:pointer}
.viewseg{display:flex;background:var(--surface-2);border:1px solid var(--border);border-radius:8px;padding:2px}
.viewseg button{width:28px;height:26px;border-radius:6px;display:grid;place-items:center;color:var(--text-3)}
.viewseg button.on{background:var(--surface);color:var(--brand-ink);box-shadow:var(--sh-1)}
.listfoot{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding-top:2px}
.listfoot .ri{font-size:12.5px;color:var(--text-3)}

/* ============ 卡片网格 ============ */
.grid{display:grid;gap:14px}
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--sh-1);
  padding:15px 16px;display:flex;flex-direction:column;gap:12px;cursor:default;position:relative;overflow:hidden;
  min-width:0;transition:box-shadow .2s var(--ease),border-color .2s var(--ease)}
.card::before{content:"";position:absolute;inset:0;border-radius:inherit;padding:2px;pointer-events:none;
  background:linear-gradient(105deg,var(--brand) 0%,var(--brand) 5%,transparent 18%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask-composite:exclude;
  opacity:0;transition:opacity .22s var(--ease)}
.card:hover{box-shadow:var(--sh-2);border-color:var(--border-strong)}
.card:hover::before{opacity:1}
.card.out{opacity:.62}
.c-name{margin:0;font-size:15px;font-weight:600;letter-spacing:-.15px;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:41px}
.c-chips{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.pill{display:inline-flex;align-items:center;gap:5px;height:26px;padding:0 10px;border-radius:99px;
  border:1px solid var(--border);background:var(--surface);font-size:11.5px;color:var(--text-2);white-space:nowrap}
.pill svg{color:var(--brand)}
.badge{display:inline-flex;align-items:center;gap:4px;height:22px;padding:0 9px;border-radius:99px;
  font-size:11.5px;font-weight:600;white-space:nowrap;letter-spacing:.2px}
.b-in{background:color-mix(in srgb,var(--down) 11%,transparent);color:var(--down)}
.b-low{background:var(--warn-soft);color:var(--warn)}
.b-out{background:color-mix(in srgb,var(--up) 11%,transparent);color:var(--up)}

.specgrid{display:grid;grid-template-columns:1fr 1fr;gap:9px 12px}
.spg{display:flex;gap:8px;align-items:flex-start;min-width:0}
.spg .i{flex:0 0 auto;color:var(--text-3);margin-top:1px}
.spg .k{font-size:11px;color:var(--text-3);line-height:1.25}
.spg .v{font-family:var(--mono);font-size:13px;font-weight:500;margin-top:1px;white-space:normal;word-break:break-word}
.promo{display:flex;align-items:center;gap:6px;font-size:11.5px;padding:6px 9px;border-radius:7px;
  background:var(--warn-soft);color:var(--warn);font-weight:500}
.c-foot{display:flex;align-items:flex-end;justify-content:space-between;gap:10px;
  border-top:1px solid var(--border);padding-top:14px;margin-top:auto}
.price{display:flex;align-items:baseline;gap:2px;min-width:0}
.price .cur{font-size:15px;font-weight:600;color:var(--text)}
.price .v{font-family:var(--mono);font-size:24px;font-weight:600;letter-spacing:-1px;color:var(--text)}
.price .per{font-size:11.5px;color:var(--text-3);margin-left:3px}
.agent-hint{font-size:10.5px;color:var(--text-3);margin-top:2px}
/* 按钮统一走主色（此前是近黑色，与蓝色主色不搭） */
.btn-detail{height:36px;padding:0 16px;border-radius:9px;background:var(--brand);color:#fff;
  font-size:13px;font-weight:600;display:inline-flex;align-items:center;gap:6px;transition:all .16s var(--ease);
  box-shadow:var(--sh-1);flex:0 0 auto}
.btn-detail:hover{filter:brightness(1.08);box-shadow:var(--sh-2)}
.btn-detail svg{color:#fff}

/* 列表视图：完整显示，不截断 */
.grid.list{grid-template-columns:1fr!important}
.grid.list .card{flex-direction:row;align-items:center;gap:16px;padding:14px 16px;flex-wrap:wrap}
.grid.list .c-name{min-height:0;-webkit-line-clamp:unset;display:block;overflow:visible;
  flex:0 1 230px;font-size:14.5px}
.grid.list .c-chips{flex:0 0 auto}
.grid.list .specgrid{grid-template-columns:repeat(4,minmax(96px,1fr));flex:1 1 420px;gap:8px 14px}
.grid.list .c-foot{border-top:0;padding-top:0;margin-top:0;flex:0 0 auto}   /* 列表视图本来就不要分隔线 */
.grid.list .promo{display:none}
.grid.list .spg .v{font-size:12.5px}
@media(max-width:1180px){.grid.list .specgrid{grid-template-columns:repeat(2,minmax(96px,1fr));flex:1 1 100%}
  .grid.list .c-name{flex:1 1 100%}}

/* ============ 分页 ============ */
.pager{display:flex;align-items:center;justify-content:flex-end;gap:6px;flex:1 1 auto;flex-wrap:wrap}
.pager button{min-width:34px;height:34px;padding:0 10px;border-radius:9px;border:1px solid var(--border);
  background:var(--surface);font-size:13px;color:var(--text-2);font-family:var(--mono);transition:all .15s var(--ease)}
.pager button:hover:not(:disabled){border-color:var(--border-strong);color:var(--text)}
.pager button.on{background:var(--brand);border-color:var(--brand);color:#fff;font-weight:600}
.pager button:disabled{opacity:.4;cursor:not-allowed}
.pager .dots{color:var(--text-3);padding:0 2px}

/* ============ 详情弹窗 ============ */
.mask{position:fixed;inset:0;z-index:120;background:rgba(10,12,18,.5);backdrop-filter:blur(3px);
  display:none;align-items:center;justify-content:center;padding:20px}
.mask.on{display:flex}
.modal{width:min(840px,100%);max-height:90vh;max-height:90dvh;display:flex;flex-direction:column;
  overflow:hidden;background:var(--surface);border-radius:var(--r-xl);
  box-shadow:var(--sh-4);border:1px solid var(--border)}
/* ⚠️ 弹窗结构：头/尾固定、内容区滚动（选配机型内容再长，标题和底部按钮也始终在屏幕内）。
   dvh 兜底 vh（部分浏览器 vh 含浏览器外壳，弹窗会顶出屏幕四角 —— 用户实测截图）。
   同时 overflow:hidden 让圆角真正裁到内容 —— 之前登录弹窗（.narrow overflow:visible）
   被内部块的背景盖住圆角，看着是直角（用户点名「都是要圆角的」）。 */
@keyframes pop{from{opacity:0;transform:translateY(14px) scale(.98)}to{opacity:1;transform:none}}
/* 详情弹窗 · 胶囊式开合：打开时从点击处「扩展放大」（--ox/--oy 由 openModal 按点击坐标写入，
   不传坐标默认中心），关闭时向同一原点「收回」（.bye 播完才摘 .on）。 */
.mask.on .modal{animation:mCapIn .3s cubic-bezier(.2,1.28,.34,1) both;transform-origin:var(--ox,50%) var(--oy,50%)}
@keyframes mCapIn{from{opacity:0;transform:scale(.52)}to{opacity:1;transform:scale(1)}}
/* ⚠️ 必须三态（.mask.on.bye）压过动效层的 `.mask.on{animation:vbFadeIn}`，否则收回时遮罩不淡出 */
.mask.on.bye{animation:vbFadeOut .2s var(--ease) both}
.mask.bye .modal{animation:mCapOut .18s var(--ease) both;transform-origin:var(--ox,50%) var(--oy,50%)}
@keyframes mCapOut{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.68)}}
@keyframes vbFadeOut{from{opacity:1}to{opacity:0}}
.m-hd{display:flex;align-items:flex-start;gap:12px;padding:20px 22px 16px;border-bottom:1px solid var(--border);
  flex:0 0 auto;background:var(--surface);z-index:3}
.m-hd h2{margin:0;font-size:19px;font-weight:700;letter-spacing:-.2px}
.m-hd .sub{font-size:12.5px;color:var(--text-3);margin-top:7px;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.m-bd{flex:1 1 auto;min-height:0;overflow:auto;padding:18px 22px;display:flex;flex-direction:column;gap:18px}
.sec-h{font-size:12px;font-weight:700;color:var(--text-3);letter-spacing:.7px;text-transform:uppercase;
  display:flex;align-items:center;gap:8px;margin-bottom:10px}
.sec-h::after{content:"";flex:1;height:1px;background:var(--border)}
.sec-h .aux{order:3;font-size:11.5px;letter-spacing:0;text-transform:none;color:var(--text-3);font-weight:500}
/* 规格 8 宫格：含带宽 / IP 数量 / 防御 */
.spec6{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.spec{background:var(--surface-2);border-radius:9px;padding:8px 11px;min-width:0}
.spec .k{font-size:11px;color:var(--text-3);letter-spacing:.2px;display:flex;align-items:center;gap:5px}
.spec .k svg{color:var(--text-3)}
.spec .v{font-family:var(--mono);font-size:14px;font-weight:500;margin-top:3px;white-space:normal;word-break:break-word}
.spec .v em{font-style:normal;color:var(--text-3);font-size:11px}
/* CPU 型号后缀（上游「配置：1核 1G/2G AMD7k62」里的 AMD7k62）：同格内弱化显示，不占新行 */
.spec .v .cmu{font-family:var(--font);font-size:11px;color:var(--text-3);font-weight:400;margin-left:4px;white-space:normal;word-break:break-word}
.note{display:flex;gap:10px;padding:13px 15px;border-radius:var(--r);background:var(--surface-2);
  border:1px solid var(--border);font-size:13px;color:var(--text-2);line-height:1.7}
.note .ic{color:var(--brand);flex:0 0 auto;margin-top:2px}
.note b{color:var(--text)}
.note .fee{color:var(--up);font-weight:600}

/* 安装系统：品牌彩色图标 · 单行紧凑（原来 3 行大卡片太占地方） */
.osgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px}
.os{display:flex;align-items:center;gap:6px;height:36px;padding:0 8px;border-radius:9px;min-width:0;
  border:1px solid color-mix(in srgb,var(--osc,var(--border)) 26%,var(--border));
  background:color-mix(in srgb,var(--osc,var(--surface)) 8%,var(--surface))}
.os .oi{flex:0 0 auto;display:flex;align-items:center;justify-content:center;width:16px;height:16px;line-height:0}
.os .oi svg{display:block}
.os .onm{font-size:12px;font-weight:600;white-space:nowrap;flex:0 0 auto}
.os .ov{margin-left:auto;flex:0 1 auto;min-width:0;font-size:10px;color:var(--text-3);
  font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:right}
.os.off{background:var(--surface-2);border-style:dashed;border-color:var(--border)}
.os.off .oi,.os.off .onm,.os.off .ov{opacity:.52}
.os.off .oi svg{filter:grayscale(1)}
.os.off .onm{font-weight:500;color:var(--text-3)}
.ostip{font-size:11.5px;color:var(--text-3);margin-top:9px;display:flex;gap:6px;align-items:flex-start;line-height:1.6}
/* 系统清单未公开（上游整组售罄、抓不到）：改用一块浅底提示替代 15 个灰格子 */
.ostip.osunk{margin-top:0;padding:10px 12px;border:1px dashed var(--border-strong);border-radius:10px;
  background:var(--surface-2);color:var(--text-2)}
.ostip.osunk .ic{color:var(--text-3);flex:0 0 auto;margin-top:1px}
.osrow.osnone{color:var(--text-3)}
.osrow.osnone .n{font-weight:400}

/* 价格方案 */
.tiertabs{display:inline-flex;background:var(--surface-2);border:1px solid var(--border);border-radius:9px;
  padding:3px;gap:2px;margin-bottom:10px}
.tiertabs button{padding:6px 14px;border-radius:7px;font-size:12.5px;color:var(--text-2);font-weight:500}
.tiertabs button.on{background:var(--brand);color:#fff;font-weight:600}
.tiers{display:grid;grid-template-columns:1fr 1fr;gap:11px}
/* 未登录代理时详情只渲染「普通售价」一档 —— 不做价格卡，压成一条信息行。
   （此前给一个半宽的大空框放一个数字，用户两轮反馈「太大 / 不和谐」。） */
.tiersolo{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;padding:12px 14px;
  border:1px solid var(--border);border-radius:var(--r);background:var(--surface-2)}
.tiersolo .tk{font-size:11.5px;color:var(--text-3);font-weight:600;letter-spacing:.3px}
.tiersolo .tv{font-family:var(--mono);font-size:22px;font-weight:600;color:var(--brand-ink);letter-spacing:-.3px}
.tiersolo .tv small{font-size:12px;color:var(--text-3);font-weight:400}
.tiersolo .tn{font-size:11.5px;color:var(--text-3);margin-left:auto}
/* 「同档更划算」侧边气泡的样式已随功能一起下线（2026-10-16） */
.tier{border:1px solid var(--border);border-radius:var(--r);
  transition:all .16s var(--ease);position:relative}
.tier.on{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
.tier .tk{font-size:11.5px;color:var(--text-3);font-weight:600;letter-spacing:.3px;display:flex;align-items:center;gap:6px}
.tier .tv{font-family:var(--mono);font-size:24px;font-weight:600;color:var(--brand-ink);margin-top:5px}
.tier .tv small{font-size:12px;color:var(--text-3);font-weight:400}
.tier .tn{font-size:11.5px;color:var(--text-3);margin-top:4px}
.tier.locked{background:var(--surface-2);border-style:dashed}
.tier.locked .tv{color:var(--text-3);letter-spacing:2px;font-size:21px}
.tier.locked .tk{color:var(--text-3)}
.tier .lock{color:var(--text-3)}
.desc{font-size:13px;color:var(--text-2);line-height:1.8}
.desc .row{display:flex;gap:10px;padding:6px 0;border-bottom:1px dashed var(--border)}
.desc .row:last-child{border-bottom:0}
.desc .row .k{width:96px;flex:0 0 auto;color:var(--text-3);font-size:12.5px}
.m-ft{display:flex;align-items:center;gap:10px;padding:14px 22px;border-top:1px solid var(--border);
  background:var(--surface-2);flex:0 0 auto;flex-wrap:wrap}
.m-ft .sp{flex:1}

/* ============ 代理登录弹窗（取代浏览器原生 prompt） ============ */
/* ⚠️ 不能 overflow:visible —— 内部块的背景会盖住弹窗圆角，四角看着是直角 */
.modal.narrow{width:min(400px,100%);max-height:none}
/* 详情弹窗的 .m-hd/.m-ft 带分隔线和灰底，登录框内容少，去掉它们更干净 */
.m-hd.lg{padding:20px 22px 0;border-bottom:0}
.m-hd.lg h2{font-size:17px}
.m-ft.lg{padding:4px 22px 18px;border-top:0;background:var(--surface);position:static}
.lg-bd{padding:16px 22px 0;display:flex;flex-direction:column;gap:7px}
.lg-lb{font-size:12.5px;font-weight:600;color:var(--text-2)}
.lg-in{width:100%;height:42px;padding:0 13px;border-radius:10px;border:1px solid var(--border);
  background:var(--surface-2);font-size:14px;color:var(--text);letter-spacing:.12em;
  transition:border-color .15s var(--ease),box-shadow .15s var(--ease),background .15s var(--ease)}
.lg-in::placeholder{letter-spacing:0;color:var(--text-3);font-size:13px}
.lg-in:focus{outline:0;border-color:var(--brand-line);background:var(--surface);
  box-shadow:0 0 0 3px var(--brand-soft)}
.lg-in.bad{border-color:var(--up);box-shadow:0 0 0 3px color-mix(in srgb,var(--up) 14%,transparent)}
.lg-err{min-height:17px;font-size:11.5px;color:var(--up);line-height:1.5}

/* ============ 筛选：流量「不限」切换 ============ */
.nf .unlim{height:22px;padding:0 8px;border-radius:6px;border:1px dashed var(--border-strong);flex:0 0 auto;
  font-size:11px;color:var(--text-3);font-weight:600;white-space:nowrap;transition:all .15s var(--ease)}
.nf .unlim:hover{color:var(--text);border-color:var(--text-3)}
.nf.unlim .unlim{background:var(--brand);border-color:var(--brand);border-style:solid;color:#fff}
.nf.unlim .op,.nf.unlim input,.nf.unlim .un{opacity:.3;pointer-events:none}

/* ============ 侧边栏：二级折叠箭头（三级默认折叠） ============ */
.item .cw{flex:0 0 auto;width:15px;height:15px;display:inline-flex;align-items:center;justify-content:center;
  color:var(--text-3);border-radius:4px;transition:transform .16s var(--ease),color .15s var(--ease)}
.item .cw:hover{color:var(--brand-ink);background:var(--surface-3)}
.item.exp .cw{transform:rotate(90deg)}
.item.exp{color:var(--text)}
.l3wrap[hidden]{display:none}

/* ============ 详情：可选配置（配置器） ============ */
.cfgr{display:grid;grid-template-columns:104px minmax(0,1fr);gap:12px;padding:13px 0;
  border-bottom:1px dashed var(--border)}
.cfgr:last-child{border-bottom:0;padding-bottom:2px}
.cfgr>.k{font-size:12.5px;color:var(--text-3);font-weight:600;padding-top:8px}
.cfgr>.ov{min-width:0;display:flex;flex-direction:column;gap:7px}
.cchips{display:flex;flex-wrap:wrap;gap:8px}
.cchip{display:inline-flex;align-items:center;gap:7px;height:34px;padding:0 12px;border:1px solid var(--border);
  border-radius:9px;background:var(--surface);font-size:12.5px;color:var(--text-2);font-weight:500;
  transition:all .15s var(--ease);text-align:left}
.cchip:hover{border-color:var(--border-strong);color:var(--text)}
.cchip .sb{font-size:10.5px;color:var(--text-3);font-family:var(--mono)}
.cchip .ad{font-size:11px;font-family:var(--mono);font-weight:600;color:var(--brand-ink);background:var(--brand-soft);
  padding:1px 6px;border-radius:5px}
.cchip .ad.free{color:var(--text-3);background:var(--surface-2);font-weight:500}
.cchip.on{border-color:var(--brand);background:var(--brand-soft);color:var(--brand-ink);font-weight:600}
.cchip.on .sb{color:var(--brand-ink);opacity:.8}
.cchip.on .ad{background:var(--brand);color:#fff}
.cchip.on .ad.free{background:transparent;color:var(--brand-ink);opacity:.8}
.cchip .oi{display:inline-flex;align-items:center;line-height:0}
.cchip.on .oi{color:var(--brand)}

/* ============ 详情：「型号」清单改 V10 风格规格表 ============
   26 款整机摊成芯片墙要两屏高、两列错落没法横向比较；表格按 CPU 核数 → 内存 →
   带宽升序，表头吸顶 + 超高滚动，弹窗高度不再被机型条数撑长。 */
.cfmwrap{border:1px solid var(--border);border-radius:var(--r);background:var(--surface);
  overflow:auto;max-height:312px;overscroll-behavior:contain}
.cfm{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}
.cfm thead th{position:sticky;top:0;z-index:2;height:31px;padding:0 9px;background:var(--surface-2);
  font-size:11px;font-weight:600;color:var(--text-3);text-align:left;white-space:nowrap;
  border-bottom:1px solid var(--border)}
.cfm tbody td{height:37px;padding:0 9px;font-size:12.5px;color:var(--text-2);
  border-bottom:1px dashed var(--border);vertical-align:middle;min-width:0}
.cfm tbody tr:last-child td{border-bottom:0}
.cfm .ck{width:32px;padding:0;text-align:center}
.cfm .cc{width:58px}.cfm .cm{width:64px}.cfm .cd{width:118px}.cfm .cb{width:62px}
.cfm .cp{width:92px;text-align:right}
.cfm td.cp b{font-family:var(--mono);font-size:12.5px;font-weight:600;color:var(--text)}
.cfm td.cp b.ask{font-family:var(--font);font-size:11px;color:var(--brand-ink);
  background:var(--brand-soft);padding:1px 7px;border-radius:5px}
.cfm .na{font-style:normal;color:var(--text-3);font-family:var(--font)}
.cfm-r{cursor:pointer;transition:background .14s var(--ease)}
.cfm-r:hover td{background:var(--surface-2)}
.cfm-r.on td{background:var(--brand-soft)}
.cfm td.cn .nm{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  vertical-align:bottom;font-weight:600;color:var(--text)}
.cfm td.cn .tg{display:inline-block;margin-left:6px;padding:1px 6px;border-radius:5px;
  font-size:10.5px;font-weight:600;color:var(--brand-ink);background:var(--brand-soft)}
.cfm-r.on td.cn .tg{background:var(--brand);color:#fff}
.cfm td.cn .nt{margin-left:6px;font-size:10.5px;color:var(--text-3)}
.cfm td.cn .mb{display:none}
.cfm .rd{display:inline-block;width:14px;height:14px;border-radius:50%;vertical-align:middle;
  border:1.5px solid var(--border-strong);background:var(--surface);transition:all .14s var(--ease)}
.cfm-r:hover .rd{border-color:var(--brand)}
.cfm-r.on .rd{border-color:var(--brand);background:var(--brand);box-shadow:inset 0 0 0 3.5px var(--surface)}
/* 窄屏：CPU/内存/硬盘/带宽四列挤不下 → 折叠进型号格下的副行（一行说全） */
@media (max-width:640px){
  .cfm .cc,.cfm .cm,.cfm .cd,.cfm .cb{display:none}
  .cfm tbody td{height:auto;padding:8px 9px}
  .cfm td.cn .mb{display:block;margin-top:2px;font-size:11px;color:var(--text-3);
    white-space:normal;overflow-wrap:anywhere}
  .cfm td.cn .nm{white-space:normal;overflow-wrap:anywhere}
  .cfm .cp{width:84px}
  .cfm thead th{height:28px}
}
.cfhint{font-size:11px;color:var(--text-3);line-height:1.5}
.cfhint b{font-family:var(--mono);color:var(--brand-ink)}
.slrow{display:flex;align-items:center;gap:13px;min-width:0}
.slrow input[type=range]{flex:1 1 auto;min-width:80px;height:4px;-webkit-appearance:none;appearance:none;
  border-radius:99px;background:linear-gradient(90deg,var(--brand) var(--p,0%),var(--surface-3) var(--p,0%));
  outline:0;cursor:pointer}
.slrow input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:15px;height:15px;border-radius:50%;
  background:var(--surface);border:2px solid var(--brand);box-shadow:var(--sh-1);cursor:grab}
.numst{display:inline-flex;align-items:center;border:1px solid var(--border);border-radius:8px;
  background:var(--surface-2);overflow:hidden;flex:0 0 auto}
.numst button{width:26px;height:30px;display:grid;place-items:center;color:var(--text-2);font-size:14px}
.numst button:hover{background:var(--surface-3);color:var(--text)}
.numst input{width:50px;height:30px;border:0;border-left:1px solid var(--border);border-right:1px solid var(--border);
  background:var(--surface);text-align:center;font-family:var(--mono);font-size:12.5px;outline:0}
.numst .un{padding:0 8px;font-size:11px;color:var(--text-3);white-space:nowrap}
.osver{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.osver select{height:32px;padding:0 9px;border:1px solid var(--border);border-radius:8px;background:var(--surface-2);
  font-size:12.5px;outline:0;cursor:pointer}

/* ============ 详情：配置明细与价格 ============ */
.cfs{border:1px solid var(--border);border-radius:var(--r);overflow:hidden;background:var(--surface)}
.cfs .cfr{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 26px;padding:12px 15px}
.cfs .r{display:flex;align-items:center;gap:9px;padding:6.5px 0;border-bottom:1px dashed var(--border);min-width:0}
.cfs .r .k{font-size:11.5px;color:var(--text-3);width:60px;flex:0 0 auto}
.cfs .r .n{flex:1 1 auto;min-width:0;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cfs .r b{flex:0 0 auto;font-family:var(--mono);font-size:12px;font-weight:600}
.cfs .r b.ad{color:var(--brand-ink)}
.cfs .r b.free{color:var(--text-3);font-weight:400}
.cfs .cft{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));border-top:1px solid var(--border);
  background:var(--surface-2)}
.cfs .cft>div{padding:10px 14px;border-right:1px solid var(--border);display:flex;flex-direction:column;gap:2px;min-width:0}
.cfs .cft>div:last-child{border-right:0}
.cfs .cft .k{font-size:11px;color:var(--text-3)}
.cfs .cft b{font-family:var(--mono);font-size:17px;font-weight:600}
.cfs .cft b small{font-size:11px;color:var(--text-3);font-weight:400}
.cfs .cft .d b{color:var(--text-2)}
.cfs .cft .t b{color:var(--brand-ink);font-size:19px}
.cfs .cft .a b{color:var(--text-2);font-size:15px}
/* 弹窗底部实时合计 */
.m-sum{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap;flex:0 0 auto;margin-right:2px}
.m-sum .k{font-size:11.5px;color:var(--text-3)}
.m-sum .v{font-family:var(--mono);font-size:20px;font-weight:700;color:var(--brand-ink);letter-spacing:-.3px}
.m-sum .per{font-size:11.5px;color:var(--text-3)}
.m-sum .ag{font-size:11px;color:var(--text-3);background:var(--surface);border:1px solid var(--border);
  padding:1px 7px;border-radius:6px;font-family:var(--mono)}
/* 卡片上的「可选配」标记 */
.badge.b-opt{background:var(--brand-soft);color:var(--brand-ink)}

/* ============ 机型对比 PK：卡片勾选（放在卡片右上角 · 商品名右侧留位避免压字） ============ */
.card .pk{position:absolute;top:12px;right:12px;z-index:3;width:19px;height:19px;border-radius:6px;
  border:1.5px solid var(--border-strong);background:var(--surface);
  display:flex;align-items:center;justify-content:center;padding:0;line-height:0;
  color:#fff;opacity:.55;transition:all .16s var(--ease)}
.card .pk svg{display:block;flex:0 0 auto}
.card:hover .pk{opacity:1;border-color:var(--brand)}
.card .pk:hover{border-color:var(--brand);background:var(--brand-soft)}
.card.pk-on{border-color:var(--brand-line);box-shadow:0 0 0 2px var(--brand-soft),var(--sh-2)}
.card.pk-on .pk,.card.pk-on:hover .pk{opacity:1;background:var(--brand);border-color:var(--brand);color:#fff}
.card .c-name{padding-right:26px}
@media (hover:none){.card .pk{opacity:1}}
/* 列表视图：勾选框留在行首左侧（与卡片内容垂直居中），网格视图才是右上角 */
.grid.list .card{padding-left:54px;padding-right:16px}
.grid.list .c-foot{align-items:center}
.grid.list .card .pk{top:50%;margin-top:-9.5px;left:15px;right:auto}
.grid.list .c-name{padding-left:0;padding-right:0}
/* 工具条上的对比入口 */
.cmpbtn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 11px;border-radius:9px;
  border:1px solid var(--border);background:var(--surface);font-size:12.5px;font-weight:600;color:var(--text-3);
  transition:all .16s var(--ease)}
.cmpbtn svg{color:var(--text-3)}
.cmpbtn:hover{border-color:var(--border-strong);color:var(--text)}
.cmpbtn.on{border-color:var(--brand-line);background:var(--brand-soft);color:var(--brand-ink)}
.cmpbtn.on svg{color:var(--brand-ink)}
.cmpbtn b{min-width:18px;height:18px;padding:0 5px;border-radius:99px;background:var(--surface-3);color:var(--text-3);
  font-family:var(--mono);font-size:11px;font-weight:600;display:inline-flex;align-items:center;justify-content:center}
.cmpbtn.on b{background:var(--brand);color:#fff}

/* ============ 机型对比 PK：底部浮动栏 ============ */
.pkbar{position:fixed;left:0;right:0;bottom:0;z-index:110;display:flex;justify-content:center;
  padding:0 var(--page-pad);pointer-events:none;
  transform:translateY(120%);transition:transform .26s var(--ease)}
.pkbar.on{transform:none}
.pkbar-in{pointer-events:auto;width:100%;max-width:var(--page-w);display:flex;align-items:center;gap:12px;
  background:var(--surface);border:1px solid var(--border);border-bottom:0;border-radius:16px 16px 0 0;
  box-shadow:0 -12px 40px rgba(16,20,32,.16);padding:10px 14px;flex-wrap:wrap}
[data-theme="dark"] .pkbar-in{box-shadow:0 -12px 40px rgba(0,0,0,.6)}
.pk-h{display:flex;align-items:center;gap:7px;font-size:12.5px;font-weight:600;color:var(--text);flex:0 0 auto}
.pk-h .ic{color:var(--brand);display:inline-flex}
.pk-h b{font-family:var(--mono);font-size:13px;color:var(--brand-ink)}
.pk-h .mx{font-size:11px;color:var(--text-3);font-family:var(--mono)}
.pk-list{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.pk-chip{display:inline-flex;align-items:center;gap:7px;height:30px;padding:0 6px 0 10px;border-radius:9px;
  border:1px solid var(--border);background:var(--surface-2);max-width:230px;animation:pop .2s var(--ease)}
.pk-chip .nm{font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.pk-chip .pr{font-family:var(--mono);font-size:11.5px;font-weight:600;color:var(--brand-ink);flex:0 0 auto}
.pk-chip .x{width:19px;height:19px;border-radius:6px;display:grid;place-items:center;color:var(--text-3);flex:0 0 auto}
.pk-chip .x:hover{background:color-mix(in srgb,var(--up) 12%,transparent);color:var(--up)}
.pk-slot{display:inline-flex;align-items:center;gap:5px;height:30px;padding:0 11px;border-radius:9px;
  border:1px dashed var(--border-strong);color:var(--text-3);font-size:11.5px;white-space:nowrap}
.pk-acts{flex:0 0 auto;display:flex;align-items:center;gap:8px;margin-left:auto}
.pk-clr{height:32px;padding:0 12px;border-radius:9px;font-size:12.5px;font-weight:600;color:var(--text-3)}
.pk-clr:hover{color:var(--up);background:color-mix(in srgb,var(--up) 10%,transparent)}
.pkbar .btn.dim{opacity:.5}                    /* 第 27 轮：替代原来的 inline opacity:.5（少了 2 款时变暗，但仍可点、会给出提示） */
body.pk{padding-bottom:92px}
body.pk .toast{bottom:118px}

/* ============ 机型对比 PK：对比弹窗 ============ */
.cmp-mask{position:fixed;inset:0;z-index:130;background:rgba(10,12,18,.52);backdrop-filter:blur(3px);
  display:none;align-items:center;justify-content:center;padding:20px}
.cmp-mask.on{display:flex}
.cmp-modal{width:min(1120px,100%);height:88vh;height:88dvh;max-height:880px;display:flex;flex-direction:column;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--r-xl);box-shadow:var(--sh-4);overflow:hidden;animation:pop .26s var(--ease)}
.cmp-hd{display:flex;align-items:center;gap:12px;padding:16px 20px;border-bottom:1px solid var(--border);flex:0 0 auto}
.cmp-hd h2{margin:0;font-size:17px;font-weight:700;letter-spacing:-.2px;display:flex;align-items:center;gap:9px}
.cmp-hd h2 .ic{color:var(--brand)}
.cmp-hd .cnt{font-size:11.5px;font-weight:600;color:var(--brand-ink);background:var(--brand-soft);
  padding:2px 8px;border-radius:99px;font-family:var(--mono)}
.cmp-hd .acts{margin-left:auto;display:flex;align-items:center;gap:8px}
.cmp-hd .hint{font-size:11.5px;color:var(--text-3);margin-right:4px}
.cmp-bd{flex:1 1 auto;overflow:auto;padding:0 0 4px;scrollbar-gutter:stable;transition:opacity .16s var(--ease)}
.cmp-bd.switching{opacity:0}
.cmp-bd.cmp-in{animation:vbFadeIn .22s var(--ease)}
/* 页签切换的等待层：旋转环 + 穿梭进度条，~0.6s，让用户愿意等 */
.cmp-wait{min-height:300px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:13px;
  animation:vbFadeIn .16s var(--ease)}
.cw-ring{width:30px;height:30px;border-radius:50%;border:3px solid var(--brand-soft);border-top-color:var(--brand);
  animation:cwSpin .7s linear infinite}
@keyframes cwSpin{to{transform:rotate(360deg)}}
.cw-tx{font-size:12.5px;color:var(--text-3);font-weight:500}
.cw-bar{width:170px;height:3px;border-radius:99px;background:var(--surface-3);overflow:hidden}
.cw-bar i{display:block;height:100%;width:38%;border-radius:99px;background:var(--brand);
  animation:cwSlide .9s var(--ease) infinite alternate}
@keyframes cwSlide{from{transform:translateX(-30%)}to{transform:translateX(240%)}}
.cmp-t{border-collapse:separate;border-spacing:0;width:100%;min-width:660px}
.cmp-t th,.cmp-t td{padding:10px 14px;text-align:left;vertical-align:middle;border-bottom:1px solid var(--border)}
/* 左列（对比项）吸顶：文字居中（两侧留出星标栏，且左右等宽 → 真正居中） */
.cmp-t .rk,.cmp-t .lk{width:140px;min-width:140px;position:sticky;left:0;z-index:2;background:var(--surface);
  font-size:12px;font-weight:600;color:var(--text-2);box-shadow:1px 0 0 var(--border)}
.cmp-t .rk{text-align:center;padding-left:26px!important;padding-right:26px!important}
.cmp-t .lk{font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:var(--text-3);text-align:center;
  border-bottom:1px solid var(--border-strong)}
/* 表头：机型列 */
.cmp-t thead th.cm{background:var(--surface);position:sticky;top:0;z-index:3;border-bottom:1px solid var(--border-strong);
  padding:13px 14px;min-width:196px;box-shadow:0 1px 0 var(--border)}
.cmp-t thead th.lk{z-index:4;top:0;padding:13px 14px}
.cmh{display:flex;flex-direction:column;gap:7px;position:relative;padding:0 20px;
  align-items:center;text-align:center}
.cmh .nm{font-size:13px;font-weight:600;line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;min-height:36px}
.cmh .pr{font-family:var(--mono);font-size:16px;font-weight:700;color:var(--brand-ink);letter-spacing:-.4px;line-height:1.2}
.cmh .pr small{font-size:11px;color:var(--text-3);font-weight:400;letter-spacing:0}
.cmh .rmv{position:absolute;top:-3px;right:-3px;width:20px;height:20px;border-radius:6px;display:grid;place-items:center;
  color:var(--text-3);background:transparent;opacity:.55;transition:all .14s var(--ease)}
.cmp-t th.cm:hover .cmh .rmv{opacity:1}
.cmh .rmv:hover{background:color-mix(in srgb,var(--up) 12%,transparent);color:var(--up)}
.cmh .det{align-self:center;height:23px;padding:0 8px;border-radius:6px;font-size:11px;font-weight:600;
  border:1px solid var(--border);background:var(--surface);color:var(--text-3);
  display:inline-flex;align-items:center;gap:4px;transition:all .14s var(--ease)}
.cmh .det:hover{border-color:var(--brand-line);background:var(--brand-soft);color:var(--brand-ink)}
/* 分组行 */
.cmp-t tr.grp th{background:var(--surface-2);font-size:11px;font-weight:700;color:var(--text-3);
  letter-spacing:.5px;text-transform:uppercase;padding:7px 14px;border-bottom:1px solid var(--border)}
.cmp-t tr.grp td{background:var(--surface-2);border-bottom:1px solid var(--border)}
.cmp-t tr.grp th{position:sticky;left:0;z-index:2;box-shadow:1px 0 0 var(--border)}
/* 分组行也要保住列间虚线，否则竖虚线会在「价格与库存 / 计算与存储 / 网络与机房」这里断掉 */
.cmp-t tr.grp td.grc+td.grc{border-left:1px dashed var(--border-strong)}
/* 数据行 */
.cmp-t tr.diff .rk{color:var(--text);font-weight:700}
.cmp-t tr.diff .rk .dot{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--brand);
  margin-left:7px;vertical-align:middle}
.cmp-t tr.same .cv{color:var(--text-3)}
.cmp-t tr.diff .cv{background:color-mix(in srgb,var(--brand-soft) 55%,transparent)}
/* 列与列之间：虚线分隔 + 奇偶列明暗层次（配置对比/明细表格一眼看出「这列属于谁」） */
.cmp-t thead th.cm+th.cm,.cmp-t tbody td.cv+td.cv{border-left:1px dashed var(--border-strong)}
.cmp-t thead th.cm:nth-of-type(even){background:color-mix(in srgb,var(--surface-2) 62%,var(--surface))}
.cmp-t tbody tr.same td.cv:nth-of-type(even){background:color-mix(in srgb,var(--surface-2) 55%,transparent)}
.cmp-t tbody tr.grp td:nth-of-type(even){background:color-mix(in srgb,var(--surface-2) 70%,var(--surface))}
.cmp-t .cv{font-size:12.5px;line-height:1.45;position:relative;text-align:center}
/* 两台机型对比时每列都很宽：标签列与数值列一律居中，内容不再贴左边留一大片空白 */
.cmp-t .cv .sub{display:block}
.cmp-t tbody tr.grp td{text-align:left}
.cmp-t .cv .tv{font-family:var(--mono);font-size:12.5px;display:inline-block}
.cmp-t .cv .sub{display:block;font-size:10.5px;color:var(--text-3);margin-top:3px;font-family:var(--mono)}
.cmp-t .cv.best .tv,.cmp-t .cv.best .osrow{font-weight:700;color:var(--brand-ink)}
.cmp-t .cv .bst{display:inline-flex;align-items:center;gap:3px;margin-left:7px;padding:1px 7px;border-radius:99px;
  background:var(--brand);color:#fff;font-size:10.5px;font-weight:600;white-space:nowrap;vertical-align:middle}
.cmp-t .cv.badge-in .tv{color:var(--down)}
.cmp-t .cv.badge-low .tv{color:var(--warn)}
.cmp-t .cv.badge-out .tv{color:var(--up)}
.osrow{display:inline-flex;align-items:center;gap:3px;flex-wrap:nowrap;max-width:100%}
.osrow svg{color:var(--text-2)}
.osrow .n{font-size:10.5px;color:var(--text-3);font-family:var(--mono);margin-left:2px;white-space:nowrap}
.osrow .more{font-size:10px;font-family:var(--mono);color:var(--text-3);background:var(--surface-2);
  border:1px solid var(--border);border-radius:5px;padding:0 3px;white-space:nowrap}
.cmp-ft{flex:0 0 auto;display:flex;align-items:center;gap:10px;padding:12px 20px;border-top:1px solid var(--border);
  background:var(--surface-2);flex-wrap:wrap}
.cmp-ft .tip{font-size:11.5px;color:var(--text-3);display:flex;align-items:center;gap:6px}
.cmp-ft .sp{flex:1}
.cmp-empty{padding:56px 20px;text-align:center;color:var(--text-3);font-size:13px}
.btn-sm{height:32px!important;padding:0 13px!important;font-size:12.5px!important}
/* ============ 机型对比 PK：工具栏 / 视图 / 关注项 / 场景评分 ============ */
.cmp-bar{flex:0 0 auto;display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:9px 20px;border-bottom:1px solid var(--border);background:var(--surface-2)}
.cmp-tabs{display:flex;gap:3px;background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:3px}
.cmp-tabs button{height:28px;padding:0 12px;border-radius:8px;font-size:12.5px;font-weight:600;color:var(--text-3);
  display:inline-flex;align-items:center;gap:6px;transition:all .14s var(--ease)}
.cmp-tabs button:hover{color:var(--text)}
.cmp-tabs button.on{background:var(--brand-soft);color:var(--brand-ink)}
.cmp-tabs button svg{color:currentColor}
.cmp-flt{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.cfbtn{display:inline-flex;align-items:center;gap:6px;height:30px;padding:0 10px;border-radius:9px;
  border:1px solid var(--border);background:var(--surface);font-size:12.5px;font-weight:600;color:var(--text-3);
  transition:all .14s var(--ease)}
.cfbtn:hover{border-color:var(--border-strong);color:var(--text)}
.cfbtn svg{color:var(--text-3)}
.cfbtn .n{font-family:var(--mono);font-size:11px;padding:1px 5px;border-radius:99px;background:var(--surface-3);color:var(--text-3)}
.cfbtn.on{border-color:var(--brand-line);background:var(--brand-soft);color:var(--brand-ink)}
.cfbtn.on svg{color:var(--brand-ink)}
.cfbtn.on .n{background:var(--brand);color:#fff}
.cfbtn .cv{display:inline-flex;align-items:center;margin-left:-1px;opacity:.75}
.cfbtn.on .cv{opacity:1}
.cfbtn.ghost{border-style:dashed}
.cmp-watch{flex:0 0 auto;padding:12px 20px;border-bottom:1px solid var(--border);background:var(--surface-2)}
.cmp-watch.hide{display:none}
.cmp-watch .wh{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:9px}
.cmp-watch .wh b{font-size:12.5px}
.cmp-watch .wg{display:flex;flex-wrap:wrap;gap:6px}
.cmp-watch .wc{display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 10px;border-radius:8px;
  border:1px solid var(--border);background:var(--surface);font-size:12px;color:var(--text-2);cursor:pointer;
  transition:all .14s var(--ease)}
.cmp-watch .wc i{width:14px;height:14px;border-radius:4px;border:1.5px solid var(--border-strong);
  display:grid;place-items:center;color:#fff;flex:0 0 auto}
.cmp-watch .wc.on{border-color:var(--brand-line);background:var(--brand-soft);color:var(--brand-ink);font-weight:600}
.cmp-watch .wc.on i{background:var(--brand);border-color:var(--brand)}
.cfbtn-mini{height:26px;padding:0 10px;border-radius:7px;font-size:11.5px;font-weight:600;color:var(--text-3);
  border:1px solid var(--border);background:var(--surface);transition:all .14s var(--ease)}
.cfbtn-mini:hover{color:var(--brand-ink);border-color:var(--brand-line)}
/* 行首关注星标：常显（原来是 opacity:0，用户反馈「五角星太小 / 看不见」） */
.rk .star{position:absolute;right:0;top:50%;transform:translateY(-50%);width:26px;height:26px;border-radius:8px;
  display:grid;place-items:center;color:var(--text-3);opacity:.55;transition:all .14s var(--ease)}
.cmp-t tbody tr:hover .rk .star{opacity:1}
.rk .star:hover{opacity:1;background:var(--brand-soft);color:var(--brand-ink);transform:translateY(-50%) scale(1.06)}
.rk .star.on{opacity:1;color:var(--warn)}
.rk .star.on svg{filter:drop-shadow(0 1px 1px color-mix(in srgb,var(--warn) 45%,transparent))}
/* 综合对比：场景矩阵 + 结论卡 */
.scn{padding:16px 20px 6px;display:flex;flex-direction:column;gap:14px}
.scn-lead{display:flex;align-items:flex-start;gap:9px;padding:12px 14px;border-radius:12px;
  background:var(--brand-soft);border:1px solid var(--brand-line);color:var(--brand-ink);font-size:12.5px;line-height:1.7}
.scn-lead .ic{flex:0 0 auto;margin-top:1px;display:inline-flex}
.scn-lead b{font-family:var(--font)}
/* 综合对比表格：定宽铺满（原 min-width:640px 在 4 款对比时会横向滚动 → 用户要求「要显示完整」） */
.scn-t{width:100%;table-layout:fixed;border-collapse:separate;border-spacing:0}
.scn-t thead th.sc,.scn-t tbody td.sc{width:196px}
.scn-t th,.scn-t td{padding:9px 11px;border-bottom:1px solid var(--border);text-align:left;vertical-align:middle}
.scn-t thead th{font-size:11px;letter-spacing:.5px;text-transform:uppercase;color:var(--text-3);
  border-bottom:1px solid var(--border-strong);white-space:normal;position:sticky;top:0;background:var(--surface);z-index:2}
.scn-t thead th.sn{font-size:12.5px;letter-spacing:0;text-transform:none;color:var(--text-2);font-weight:700;
  overflow-wrap:anywhere}
.scn-t thead th.sn .w{font-family:var(--mono);font-size:10.5px;color:var(--text-3);font-weight:400;margin-top:2px}
.scn-t tbody tr:hover td{background:color-mix(in srgb,var(--brand-soft) 50%,transparent)}
.scn-t .sc{white-space:normal}
.scn-t .sc .nm{font-size:12.5px;font-weight:600}
.scn-t .sc .w{font-size:10.5px;color:var(--text-3);font-family:var(--mono);margin-top:2px;line-height:1.5}
.scn-t .cell{min-width:0}
/* 列间虚线：表头 + 每一行都带 → 从头到尾一条连续竖虚线（三台对比时一眼看清哪列属于谁） */
.scn-t thead th.sn,.scn-t tbody td.cell{border-left:1px dashed var(--border-strong)}
.scnb{display:flex;align-items:center;gap:6px;min-width:0}
.scnb .bar{flex:1 1 auto;min-width:26px;max-width:74px;height:7px;border-radius:99px;background:var(--surface-3);
  overflow:hidden}
.scnb .bar i{display:block;height:100%;border-radius:99px;background:linear-gradient(90deg,var(--brand),var(--brand-ink))}
.scnb .v{font-family:var(--mono);font-size:11.5px;color:var(--text-2);width:22px;text-align:right;flex:0 0 auto}
.scnb.top .v{color:var(--brand-ink);font-weight:700}
.scnb .pick{display:inline-flex;align-items:center;gap:3px;height:18px;padding:0 7px;border-radius:99px;
  background:var(--brand);color:#fff;font-size:10px;font-weight:700;white-space:nowrap}
.scn-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(292px,1fr));gap:11px}
.scn-card{border:1px solid var(--border);border-radius:12px;padding:12px 13px;background:var(--surface)}
.scn-card .ch{display:flex;align-items:center;gap:8px;margin-bottom:7px}
.scn-card .ch b{font-size:13px}
.scn-card .ch .ic{color:var(--brand);display:inline-flex}
.scn-card .win{font-size:12.5px;color:var(--text-2);line-height:1.6}
.scn-card .win b{color:var(--brand-ink)}
.scn-card .tags{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}
.scn-card .tags .tg{font-size:10.5px;font-family:var(--mono);color:var(--text-2);background:var(--surface-2);
  border:1px solid var(--border);border-radius:6px;padding:2px 7px}
.scn-note{font-size:11.5px;color:var(--text-3);line-height:1.75;padding:0 0 8px}
/* 配置对比：胜负 / 总分汇总条 */
.spc-sum{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:11px 20px;border-bottom:1px solid var(--border);
  background:var(--surface-2);font-size:12px;color:var(--text-2)}
.spc-sum .pill{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 10px;border-radius:99px;
  background:var(--surface);border:1px solid var(--border);font-size:12px;white-space:nowrap}
.spc-sum .pill b{font-family:var(--mono);color:var(--brand-ink)}

.empty{padding:60px;text-align:center;color:var(--text-3);border:1px dashed var(--border-strong);
  border-radius:var(--r-lg);background:var(--surface)}

/* toast */
.toast{position:fixed;left:50%;bottom:34px;transform:translate(-50%,20px);z-index:300;background:var(--text);
  color:var(--bg);font-size:13px;font-weight:500;padding:10px 18px;border-radius:10px;box-shadow:var(--sh-3);
  opacity:0;pointer-events:none;transition:all .22s var(--ease)}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* ============ 移动端抽屉 ============ */
.sidehd{display:none;align-items:center;justify-content:space-between;padding:0 2px 4px}
.sidehd b{font-size:14px;letter-spacing:.2px}
.mobfilter{display:none;align-items:center;gap:7px;height:36px;padding:0 13px;border-radius:9px;
  border:1px solid var(--border);background:var(--surface);font-size:13px;font-weight:600;color:var(--text-2)}
.mobfilter:hover{border-color:var(--border-strong);color:var(--text)}
.drawer-mask{display:none;position:fixed;inset:0;background:rgba(10,12,18,.45);z-index:120;backdrop-filter:blur(2px)}
.drawer-mask.on{display:block}

/* ============ 自适应 ============ */
@media (min-width:1181px){
  .side{position:sticky;top:78px;max-height:calc(100vh - 96px);overflow:auto;scrollbar-width:thin}
}
@media (max-width:1180px){
  .layout{grid-template-columns:1fr;gap:14px}
  .side-body{background:transparent;border:0;box-shadow:none;padding:0;flex-direction:row;flex-wrap:wrap;gap:10px}
  .side-body>.blk{flex:1 1 240px;min-width:0;background:var(--surface);border:1px solid var(--border);
    border-radius:var(--r);box-shadow:var(--sh-1);overflow:hidden;padding:0;margin:0}
  .side-body>.blk .blk-h{padding:9px 11px 8px}
  .side-body>.blk .blk-b{padding:0 5px 7px}
  .mainnav{gap:0}
}
@media (max-width:860px){
  .topbar{height:auto}
  .topbar .tb-in{height:auto;padding:9px 14px;flex-wrap:wrap;gap:10px}
  .brand{flex:1 1 auto}
  .mainnav{order:3;flex:1 1 100%;margin-left:0;padding-bottom:2px}
  .side{position:fixed;left:0;top:0;bottom:0;width:min(330px,88vw);z-index:130;
    background:var(--surface);border-right:1px solid var(--border);box-shadow:var(--sh-4);
    padding:14px;overflow:auto;transform:translateX(-102%);transition:transform .24s var(--ease);border-radius:0;
    max-height:none}
  .side.on{transform:none}
  .side-body{flex-direction:column;flex-wrap:nowrap;gap:0;background:transparent;border:0;box-shadow:none;padding:0}
  .side-body>.blk{flex:0 0 auto;width:100%;background:none;border:0;box-shadow:none;border-radius:0;padding:0;overflow:visible}
  .side-body>.blk+.blk{border-top:1px solid var(--border);padding-top:4px}   /* 抽屉里退回细分隔线 */
  .sidehd{display:flex}
  .mobfilter{display:inline-flex}
  .morebtn{display:inline-flex}
  #moreIc{transition:transform .2s var(--ease)}
  #moreIc.up{transform:rotate(180deg)}
  .layout{padding:14px 14px 56px}
  /* 更多筛选：默认收起数值区与线路/退款 */
  .filters:not(.adv) .m-extra,.filters:not(.adv) .f-r2{display:none}
  .f-r1 .search{flex:1 1 100%;max-width:none}
  .f-r1 .mode{margin-left:auto}
  .f-r2,.f-r3{gap:7px}
  .f-r3{gap:7px}
  .fdiv{display:none}
  .nf input{width:50px}
  .listhd{align-items:flex-start}
  .listhd-a{margin-left:0;width:100%}
  .dd-pop{max-width:calc(100vw - 30px)}
  .dd-opt{flex-wrap:wrap;height:auto;min-height:32px;padding:6px 10px}
  .dd-sub{position:static;left:auto;top:auto;flex:1 1 100%;min-width:0;border:0;box-shadow:none;
    background:transparent;padding:2px 0 2px 10px;animation:none}
  .listfoot .pager{justify-content:center}
  .spec6{grid-template-columns:repeat(2,1fr)}
  /* 未登录的单价格条在窄屏：口径说明换行到下一行，不要挤在价格右边 */
  .tiers,.tiers.solo{grid-template-columns:1fr}
  .tiersolo{flex-wrap:wrap;gap:4px 10px}
  .tiersolo .tn{margin-left:0;flex:1 1 100%}
  .cfgr{grid-template-columns:1fr;gap:7px;padding:11px 0}
  .cfgr>.k{padding-top:0}
  .cfs .cfr{grid-template-columns:1fr;gap:0}
  .cfs .cft{grid-template-columns:1fr 1fr}
  .cfs .cft>div:nth-child(-n+2){border-bottom:1px solid var(--border)}
  .m-sum{width:100%;margin-bottom:2px}
  /* 对比：底部栏与弹窗在窄屏收紧 */
  .card .pk{opacity:1}
  .pkbar{padding:0 10px}
  .pkbar-in{border-radius:14px 14px 0 0;padding:9px 11px;gap:9px}
  .pk-list{order:3;flex:1 1 100%;flex-wrap:nowrap;overflow-x:auto;padding-bottom:2px}
  .pk-chip{max-width:190px}
  .pk-acts{margin-left:auto}
  .cmp-t .rk,.cmp-t .lk{width:112px;min-width:112px;font-size:11.5px}
  .cmp-t .rk{padding-left:18px!important;padding-right:24px!important}
  .cmp-t .lk{padding:9px 10px}
  .rk .star{width:22px;height:22px;right:-2px}
  .cmp-t thead th.cm{min-width:168px;padding:11px 10px}
  .cmp-t th,.cmp-t td{padding:9px 10px}
  /* 综合对比：窄屏改回自适应 + 横向滚动（定宽铺满会把每列压到看不清） */
  .scn-t{table-layout:auto;min-width:600px}
  .scn-t thead th.sc,.scn-t tbody td.sc{width:auto;min-width:150px}
  .scn-t .cell{min-width:132px}
  .scnb .bar{width:56px;flex:0 0 auto;max-width:56px}
  .cmp-modal{height:94vh;height:94dvh;max-height:none;border-radius:var(--r-lg)}
  .crumb{display:none}
  .themepop{left:12px;right:12px;width:auto}
}
@media (max-width:640px){
  /* ================= 移动端自适应（统一在这里收口） =================
     问题：390px 宽时卡片两列只有 ~170px，规格值疯狂折行、价格「¥17 / 月付」折成三行、
     顶部栏 + 筛选栏占掉半屏 —— 看着就是「乱」。
     做法：窄屏强制一列（JS applyGrid）＋ 字体降一档 ＋ 顶部栏压扁 ＋ 筛选行改成可横滑的一条。 */
  /* ⚠️ 顶部栏在手机上本来就是两行（品牌行 + 导航行，见 ≤860px 的 .tb-in{flex-wrap:wrap}），
     所以这里**只能给 auto 高度**：写死 52px 会让内容溢出、盖住下面的标题（踩过）。 */
  .topbar{height:auto}
  .topbar .tb-in{gap:8px;padding:8px 12px}
  .logo{width:28px;height:28px;border-radius:8px}
  .brand-name{font-size:14px}
  .brand-sub{display:none}                 /* 副标题在手机上只会挤掉导航 */
  .mainnav a{font-size:13px;padding:6px 9px}
  .page-hd h1{font-size:19px}
  .page-hd .sub{font-size:12px}

  .filters{padding:10px;gap:7px;border-radius:12px}
  .search{flex:1 1 100%;max-width:none;height:34px}
  .f-r2,.f-r3{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding-bottom:2px}
  .f-r2::-webkit-scrollbar,.f-r3::-webkit-scrollbar{display:none}
  .f-r2>*,.f-r3>*{flex:0 0 auto}
  .fend{margin-left:0}
  .nf{height:30px;padding:0 8px}
  .mode button{padding:4px 9px;font-size:12px}

  .grid{gap:11px}
  .grid>.card{padding:12px;gap:9px}
  .c-name{font-size:13.5px;line-height:1.35}
  .c-chips{gap:5px}
  .c-foot{flex-wrap:nowrap;gap:8px}
  .c-foot .price{white-space:nowrap}
  .price .v{font-size:19px}
  .price .u{font-size:11px}
  .btn-detail{height:30px;padding:0 11px;font-size:12px}

  .side{gap:9px;padding:12px}
  .card{padding:13px;gap:11px;border-radius:12px}
  .c-name{font-size:14px;min-height:38px}
  .specgrid{gap:10px 8px}
  .spg{gap:7px}
  .spg .k{font-size:10.5px}
  .spg .v{font-size:12px}
  .spec{padding:7px 9px}
  .price .v{font-size:20px}
  .btn-detail{height:32px;padding:0 12px;font-size:12.5px}
  .osgrid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .m-bd{padding:14px}
  .m-hd{padding:15px 14px 13px}
  .m-ft{padding:12px 14px}
  .mask{padding:0;align-items:flex-end}
  .modal{max-height:94vh;max-height:94dvh;border-radius:var(--r-xl) var(--r-xl) 0 0;width:100%}
  .cmp-mask{padding:0;align-items:flex-end}
  .cmp-modal{width:100%;max-height:94vh;border-radius:var(--r-xl) var(--r-xl) 0 0}
  .cmp-hd{padding:13px 14px}
  .cmp-hd .hint{display:none}
  .cmp-ft{padding:10px 14px}
  body.pk{padding-bottom:118px}

  /* ---- 可配机型的配置器：手机上「标签 + 控件」必须竖排（原来两列会把滑块挤成一条缝） ---- */
  .cfgr{grid-template-columns:1fr;gap:7px;padding:11px 0}
  .cfgr>.k{padding-top:0;font-size:12px}
  .cfgr>.ov{width:100%}
  .cchips{gap:6px}
  .cchip{height:33px;padding:0 10px;font-size:12.5px;gap:5px}
  .cchip .oi svg{width:13px;height:13px}
  .slrow{flex-direction:column;align-items:stretch;gap:9px}
  .slrow input[type=range]{width:100%;flex:0 0 auto}
  .numst{align-self:flex-end}
  .osver{flex-direction:column;align-items:stretch;gap:8px}
  .osver select{width:100%;height:36px}
  /* 详情底部按钮：手机上分两行，主操作整行 */
  .m-ft{flex-wrap:wrap;gap:8px;padding:11px 14px}
  .m-ft .sp{display:none}
  .m-ft .m-sum{flex:1 1 100%;font-size:12.5px}
  .m-ft .btn{flex:1 1 auto;justify-content:center}
  /* 对比表在手机上本来就能横滑，这里只把「配置明细」压紧一点 */
  .cfsum{padding:12px 13px}
  .cfsum .kv{gap:6px}
}
@media (max-width:860px) and (min-width:641px){
  /* 平板：配置器标签栏收窄，别把控件挤没 */
  .cfgr{grid-template-columns:88px minmax(0,1fr);gap:10px}
  .cchip{height:32px;padding:0 10px;font-size:12.5px}
}
@media (max-width:400px){
  .specgrid{grid-template-columns:1fr 1fr}
  .spec6{grid-template-columns:1fr 1fr}
}

/* ============================================================
   动效层（前台）—— 全站「点击感」集中在这里，不要散进各个组件
   ------------------------------------------------------------
   原则：
   · 只动 transform / opacity，不动 width/height/margin（不触发重排、不抖）
   · 时长档位：按压 90ms · hover 150ms · 入场 200~260ms · 错峰步长 18ms
   · 缓动统一用 --ease（tokens.css 是唯一来源，别写字面量曲线）
   · 收尾的 prefers-reduced-motion 兜底：系统关动画时全部退化成「直接到位」
   ⚠️ admin.css 有一份同源副本（同名 vb* 关键帧），改这里必须同步改那边。
   ============================================================ */
@keyframes vbRise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes vbSlideL{from{opacity:0;transform:translateX(-9px)}to{opacity:1;transform:none}}
@keyframes vbFadeIn{from{opacity:0}to{opacity:1}}

/* ---- 1. 商品卡片错峰入场 ----
   渲染时给每张卡片写 style="--vb-i:序号"，逐张晚 18ms 出现（第 12 张之后不再往后堆，
   否则 24 张的最后一只要等 0.43s 才出来，反而像卡了）。 */
@keyframes vbCard{from{opacity:0;transform:translateY(10px) scale(.985)}to{opacity:1;transform:none}}
.grid>.card{animation:vbCard .26s var(--ease) both;
  animation-delay:calc(min(var(--vb-i,0),12) * 18ms)}
/* 翻页 / 筛选时卡片被整块替换 → 动画会重播；列表视图同理 */
.grid.list>.card{animation-name:vbSlideL}
/* 侧边栏点栏目（renderLight 的轻量路径）：结果区只做一次**快速整体淡入**，
   不重播 12 张的错峰入场 —— 错峰本来是为「首屏/翻页」设计的，用在点栏目上会让
   整片结果区像被重新加载了一遍（用户原话「点一下就像刷新」）。
   ⚠️ 必须写在这两条之后：选择器权重与 .grid.list 相同，靠源码顺序取胜。 */
.grid.soft>.card{animation:vbFadeIn .16s var(--ease) both;animation-delay:0ms}
.grid.soft.list>.card{animation-name:vbFadeIn}

/* ---- 2. 卡片 hover 抬起 / 按下回弹（原来只有阴影变化，手感偏「平」） ---- */
.card{transition:box-shadow .2s var(--ease),border-color .2s var(--ease),transform .18s var(--ease)}
.card:hover{transform:translateY(-2px)}
.card:active{transform:translateY(0) scale(.997);transition-duration:.09s}

/* ---- 3. 按钮 / 图标按钮的按压反馈：向下 1px + 轻微收缩，松开回弹 ---- */
.btn:active,.iconbtn:active,.btn-detail:active,.pager button:not(:disabled):active{
  transform:translateY(1px) scale(.985);transition-duration:.09s}
.btn-detail{transition:filter .16s var(--ease),box-shadow .16s var(--ease),transform .12s var(--ease)}
.pager button{transition:background .15s var(--ease),color .15s var(--ease),transform .12s var(--ease)}

/* ---- 4. 侧边栏：二级展开 / 收起时三级从左侧「滑」出来，而不是硬切 ----
   [hidden] 一去掉元素就 display 回来，CSS 动画会重新起跑。
   ⚠️ 但动画必须挂在 `.run` 上（由 sideL2Open()/replay() 显式加）：否则
      renderSide() 重建整棵树时，所有已经展开的分组都会**跟着重播一遍**动画 ——
      用户看到的就是「点一下栏目像刷新了一次」。 */
.l3wrap.run:not([hidden]){animation:vbSlideL .18s var(--ease) both}
.l3wrap.run:not([hidden])>.item:nth-child(1){animation-delay:0ms}
.l3wrap.run:not([hidden])>.item:nth-child(2){animation-delay:14ms}
.l3wrap.run:not([hidden])>.item:nth-child(3){animation-delay:28ms}
.l3wrap.run:not([hidden])>.item:nth-child(n+4){animation-delay:42ms}
.l3wrap.run:not([hidden])>.item{animation:vbSlideL .18s var(--ease) both}
/* 栏目标题左边那个小方点：选中的栏目带一点呼吸感 */
.item{transition:background .15s var(--ease),color .15s var(--ease),transform .12s var(--ease)}
.item:active{transform:scale(.985)}

/* ---- 5. 遮罩淡入 + 弹窗由下浮起（.modal 的 pop 保留，遮罩补一层淡入） ---- */
.mask.on{animation:vbFadeIn .16s var(--ease)}
.cmp-mask.on{animation:vbFadeIn .16s var(--ease)}

/* ---- 6. 价格档位切换：两个价框切换时数值不硬跳 ---- */
.tier .tv{transition:color .18s var(--ease)}
.tiertabs button{transition:background .18s var(--ease),color .18s var(--ease)}
.tier.on .tv{animation:vbFadeIn .2s var(--ease)}

/* ---- 7. 可装系统芯片：hover 微微浮起，让「能点的地方」有回应 ---- */
.os{transition:box-shadow .16s var(--ease),border-color .16s var(--ease),transform .14s var(--ease)}
.os:not(.off):hover{transform:translateY(-1px);box-shadow:var(--sh-1)}

/* ---- 8. 系统关动画：全部退化为「直接到位」（无障碍要求，也是低端机省电开关） ---- */
@media (prefers-reduced-motion:reduce){
  .grid>.card,.l3wrap:not([hidden]),.l3wrap:not([hidden])>.item,.tier.on .tv,
  .mask.on,.mask.on .modal,.mask.bye,.mask.bye .modal,.cmp-mask.on{animation:none!important}
  .card:hover,.card:active,.btn:active,.iconbtn:active,.btn-detail:active,
  .os:not(.off):hover,.item:active{transform:none!important}
}

/* ============================================================
   移动端「app 化」收口（第十五轮追加）
   ------------------------------------------------------------
   用户要求：① 详情要从下往上滑出、像原生 app；② 461px 以上用两列（一列太空）；
             ③ 工具条 UI 统一（等高、横滑有暗示）；④ 两列时卡片要紧凑不折行。
   ============================================================ */
@media (max-width:860px){
  /* ① 底部抽屉：滑入滑出 + 抓手 + 安全区 */
  .mask{padding:0;align-items:flex-end}
  .modal{position:relative;width:100%;max-height:92dvh;border-radius:20px 20px 0 0;
    padding-bottom:env(safe-area-inset-bottom,0);
    box-shadow:0 -20px 44px -20px rgba(0,0,0,.45)}
  .mask.on .modal{animation:vbSheetIn .3s cubic-bezier(.22,1,.36,1) both!important;transform-origin:50% 100%}
  .mask.bye .modal,.mask.on.bye .modal{animation:vbSheetOut .2s cubic-bezier(.4,0,1,1) both!important}
  .modal::before{content:"";position:absolute;top:7px;left:50%;width:40px;height:4px;margin-left:-20px;
    border-radius:3px;background:var(--border-strong);opacity:.9;pointer-events:none}
  .m-hd{padding-top:20px}
  .cmp-mask{padding:0;align-items:flex-end}
  .cmp-modal{width:100%;max-height:92dvh;border-radius:20px 20px 0 0;position:relative}
  .cmp-modal::before{content:"";position:absolute;top:7px;left:50%;width:40px;height:4px;margin-left:-20px;
    border-radius:3px;background:var(--border-strong);opacity:.9;pointer-events:none}

  /* ③ 工具条：控件等高、均匀分布；芯片行横滑并给出右侧渐隐暗示 */
  .f-r1{gap:7px}
  .f-r1>.btn,.f-r1>.mode,.f-r1>.mobfilter,.f-r1>.selbtn{height:34px}
  .fend{margin-left:0;gap:7px;flex-wrap:wrap}
  .f-r2,.f-r3{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;
    -webkit-overflow-scrolling:touch;
    -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 20px),transparent);
    mask-image:linear-gradient(90deg,#000 calc(100% - 20px),transparent)}
  .f-r2::-webkit-scrollbar,.f-r3::-webkit-scrollbar{display:none}
  .f-r2>*,.f-r3>*{flex:0 0 auto}
  .filters{padding:11px;gap:8px}
}
@keyframes vbSheetIn{from{transform:translateY(100%)}to{transform:translateY(0)}}
@keyframes vbSheetOut{from{transform:translateY(0)}to{transform:translateY(100%)}}

@media (max-width:560px){
  /* ④ 两列时的紧凑卡片：字号与间距一起降，长值不许把卡片撑成三行 */
  .grid{gap:10px}
  .grid>.card{padding:11px;gap:8px;border-radius:12px}
  .c-name{font-size:13px;line-height:1.32}
  .c-chips{gap:4px}
  .c-chips>*{height:22px;font-size:10.5px;padding:0 7px}
  .specgrid{grid-template-columns:1fr 1fr;gap:7px 8px}
  .spg{gap:5px}
  .spg .k{font-size:10px}
  .spg .v{font-size:11.5px;line-height:1.3}
  .c-foot{gap:6px;flex-wrap:nowrap}
  .c-foot .price{white-space:nowrap}
  .price{flex-wrap:nowrap}
  .price .v{font-size:17px;letter-spacing:-.5px}
  .price .u{font-size:10px}
  .btn-detail{height:28px;padding:0 9px;font-size:11.5px;gap:4px}
}

@media (max-width:560px){
  /* 两列时个别值很长（"1个ivp4+1个ipv6"、"SK Broadband 广播IP"）会把卡片撑高、行列参差 →
     统一最多 2 行 + 允许断词，卡片高度就齐了。 */
  .spg .v{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
    overflow-wrap:anywhere;min-height:0}
}

/* ============================================================
   移动端顶栏 = app 样式：左汉堡 / 中间 logo / 右侧操作 + 下方栏目条
   ============================================================ */
.navbtn{display:none;width:38px;height:38px;flex:0 0 auto;border-radius:10px;border:1px solid transparent;
  background:none;color:var(--text);align-items:center;justify-content:center;cursor:pointer}
.navbtn:active{background:var(--surface-2)}
@media (max-width:860px){
  .tb-in{position:relative;align-items:center;row-gap:8px}
  .navbtn{display:inline-flex;order:1}
  .brand{order:2;flex:1 1 auto;justify-content:center;margin-right:38px}  /* 右侧留出汉堡同宽，视觉真正居中 */
  .brand-sub{display:none}
  .topright{order:4;flex:1 1 100%;justify-content:center;gap:8px;flex-wrap:wrap}
  .mainnav{order:3;flex:1 1 100%;justify-content:center}
  .brand .logo{width:28px;height:28px}
  .brand-name{font-size:15px}
}
@media (max-width:640px){
  .topright .btn{height:32px;padding:0 11px;font-size:12.5px}
}

/* ============================================================
   移动端筛选区：从「客户的视角」重排（第十七轮追加）
   ------------------------------------------------------------
   问题（用户截图）：搜索、大于/精确、更多筛选、地区/库存/排序/币种 挤成四行、右边还被切掉，
   看着既不协调也不好点。客户真正要的是：搜一下 → 选地区 → 看库存 → 排序。
   做法：搜索独占一行（38px 好点）；四个筛选做成 2×2 等宽网格（每个整行宽，好点、对齐）；
         「大于/精确」这种进阶开关收进「更多筛选」那一行，不再抢位置。
   ============================================================ */
@media (max-width:860px){
  .filters{padding:12px 12px 10px;gap:10px;border-radius:14px}
  .search{flex:1 1 100%;max-width:none;height:38px;border-radius:10px;font-size:14px}
  .search input{font-size:14px}

  /* 第二行：只留「更多筛选」这类进阶入口，右对齐，不与搜索抢宽度 */
  .f-r2{border-top:0;padding-top:0;justify-content:flex-end;gap:8px;flex-wrap:wrap}
  .f-r2 .mode{order:2}
  .f-r2 .morebtn{order:1;height:34px}

  /* 四个筛选：2×2 等宽网格（原来是横滑，右边被切掉） */
  .f-r3{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;
    border-top:1px solid var(--border);padding-top:10px;
    overflow:visible;-webkit-mask-image:none;mask-image:none}
  .f-r3>*{width:100%;min-width:0;justify-content:space-between}
  .f-r3 .fdiv{display:none}

  /* 工具条第一行：四个控件等分，点起来不费劲 */
  .f-r1{gap:8px}
  .f-r1>.mobfilter,.f-r1>.fgrp{flex:1 1 0;min-width:0}
  .f-r1 .mobfilter{justify-content:center;height:36px;border-radius:10px}
  .fend{margin-left:0;gap:8px}

  /* 一级栏目头做成可点的行（原来点了没反应，客户以为「回到首页」） */
  .blk-h{cursor:pointer;border-radius:9px}
  .blk-h:active{background:var(--surface-2)}
}

@media (max-width:860px){
  /* .fend 里装着「排序 + 币种 + 升序 + 重置筛选」一整组：让它跨两列、内部再排成 2 列，
     这样整块筛选区就是一个干净的 2 列网格（原来它是单个格子，把右侧撑得参差不齐）。 */
  .f-r3>.fend{grid-column:1/-1;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0;width:100%}
  .f-r3>.fend>*{width:100%;min-width:0;justify-content:space-between}
  .f-r3>.fdiv{display:none!important}
}

@media (max-width:860px){
  /* 网格里若有个别零宽元素占位，会让第一行左边空一格 —— dense 让它自动补位 */
  .f-r3{grid-auto-flow:row dense}
  .f-r3>.fgrp,.f-r3>.nf,.f-r3>.msel{grid-column:auto}
}

/* ============================================================
   移动端筛选区：**结构性重排**（不再打补丁）
   ------------------------------------------------------------
   网格：搜索独占一行 → [地区|库存] / [排序|币种] / [升序|重置]；
   「大于/精确」这种进阶开关收进「更多筛选」，不跟主流程抢位置。
   ============================================================ */
@media (max-width:860px){
  .f-r3{display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:8px;
    border-top:1px solid var(--border);padding-top:10px;overflow:visible!important;
    -webkit-mask-image:none!important;mask-image:none!important}
  .f-r3>*{width:100%;min-width:0;flex:initial}
  .f-r3>.fdiv{display:none!important}
  .f-r3>.fend{grid-column:1 / -1;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  .f-r3>.fend>*{width:100%;justify-content:center}
  .fcell,.fcell>*{display:block;width:100%;min-width:0}
  .fcell .msel,.fcell .mselbtn,.fcell button{width:100%;justify-content:space-between}

  /* 主流程：搜索整行 + 「更多筛选」右对齐；进阶模式开关只在展开后出现 */
  .f-r1{flex-wrap:wrap;gap:8px}
  .f-r1 .search{flex:1 1 100%;max-width:none}
  .f-r1 .morebtn{margin-left:auto;height:34px}
  .f-r1 .mode{display:none}
  .filters.adv .f-r1 .mode{display:inline-flex;margin-left:auto}
}

/* 一级栏目头：有二级时可折叠（点它只展开/收起，不进入） */
.blk-h{display:flex;align-items:center;gap:8px}
.blk-h[data-cat]{cursor:pointer;border-radius:9px;padding-left:4px;padding-right:4px;margin-left:-4px;margin-right:-4px}
.blk-h[data-cat]:active{background:var(--surface-2)}
.blk-h[data-cat]::after{content:"";width:7px;height:7px;margin-left:auto;flex:0 0 auto;
  border-right:1.6px solid var(--text-3);border-bottom:1.6px solid var(--text-3);
  transform:rotate(45deg) translateY(-2px);transition:transform .2s var(--ease);opacity:.7}
.blk-h[data-cat].col::after{transform:rotate(-45deg) translateY(-1px)}
.blk-b.hide{display:none}
@media (max-width:860px){
  /* 移动端一级栏目头做厚一点，手指好点 */
  .blk-h[data-cat]{min-height:40px}
}

/* ============================================================
   移动端「更多筛选」展开后的数值条件：也做成 2 列整齐网格
   ------------------------------------------------------------
   用户截图：CPU/内存/硬盘/流量/价格 五个 .nf 是 inline-flex 自适应宽度，
   换行后长短不一、右侧对齐乱七八糟 —— 这里统一成整格宽的「标签 + ≥ + 输入 + 单位」。
   ============================================================ */
@media (max-width:860px){
  .f-r2{display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;
    padding-top:10px;border-top:1px solid var(--border)}
  .f-r2>*{width:100%;min-width:0}
  .nf{display:flex;align-items:center;gap:6px;width:100%;height:38px;padding:0 10px;border-radius:10px}
  .nf .lb{flex:0 0 auto;font-size:12px;color:var(--text-2);white-space:nowrap}
  .nf .op{flex:0 0 auto;font-size:12px}
  .nf input{flex:1 1 auto;min-width:0;width:100%;text-align:right;font-size:13.5px}
  .nf .un{flex:0 0 auto;font-size:11.5px;color:var(--text-3);white-space:nowrap}
  .nf .unlim{flex:0 0 auto;height:22px;padding:0 6px;font-size:11px;white-space:nowrap}
}

@media (max-width:860px){
  /* 流量那格多一个「不限流量」按钮，184px 塞不下 → 让它跨两列 */
  .f-r2>#nfTraffic{grid-column:1 / -1}
  .f-r2>#nfTraffic input{max-width:120px}
}

/* 卡片「补满」：同一行的卡片等高，价格/按钮那一行钉在底部 —— 规格少的卡片不再空一截 */
.grid{align-items:stretch}
.grid>.card{height:100%}
.card>.c-foot{margin-top:auto}
.specgrid{align-content:start}
.l3wrap .item.l3.all{color:var(--text-2)}
.l3wrap .item.l3.all .nm{font-weight:600}

/* 一级栏目头：去掉展开/收起的小三角，也不做折叠（用户要求这四项常开） */
.blk-h[data-cat]::after{display:none!important}
.blk-h[data-cat]{cursor:default}
.blk-b.hide{display:block!important}

/* 卡片「补满」第二版：让规格网格**吃掉剩余高度并均匀铺开** ——
   上一版把价格行钉底、规格挤在顶部，中间就露出一块空白（用户：留空多难看啊）。 */
.grid>.card>.specgrid{flex:1 1 auto;align-content:space-between}

/* ============================================================
   侧边抽屉必须**撑满整屏高度**（用户：这个侧边栏就不能做整齐布满吗？）
   —— 内容少的时候抽屉只到一半、下面露出背后的页面，非常不整齐。
   ============================================================ */
@media (max-width:860px){
  .side{top:0!important;bottom:0!important;height:100dvh!important;max-height:100dvh!important;
    display:flex;flex-direction:column;overflow-y:auto;overscroll-behavior:contain;
    padding-bottom:calc(20px + env(safe-area-inset-bottom,0px))}
  .side-body{flex:1 1 auto;display:flex;flex-direction:column}
  /* 内容不足时，把「待上架/暂无商品」这类尾巴推到底部，整屏看起来是满的 */
  .side-body>.blk:last-child{margin-bottom:auto}
  #sideClose{margin-left:auto}
  .sidehd{position:sticky;top:0;z-index:3;background:var(--surface);
    padding-bottom:10px;margin-bottom:2px;border-bottom:1px solid var(--border)}
}

/* ============================================================
   移动端筛选区：统一节奏 + 紧密内联（第二十五轮）
   ------------------------------------------------------------
   用户原话：「一看就知道这网站很差劲，搜索布局都布局不好」。
   对着截图核过 DOM 与计算样式，病根是四条：
     ① .nf input 是 flex:1 + text-align:right —— 输入框把整格吃掉、占位符「不限」被顶到最右，
        看着就像「CPU ≥」和「不限 核」被 space-between 拉开，操作符和值彻底脱节；
     ② .mode 与 .morebtn 都写了 margin-left:auto —— 两个 auto 平分剩余空间，
        「大于/精确」于是悬在第二行中间偏右，跟「更多筛选」对不齐；
     ③ #nfTraffic 跨两列 —— 中间白白空掉一大片，「不限 GB」被推到最远；
     ④ 控件高度 30/32/34/36 四档、圆角 8/9/10 三档、字号 11.5~14 五种 —— 没有节奏，看着就廉价。
   这一版：
     · 整个筛选区一套刻度：控件 38px 高 / 10px 圆角 / 13~13.5px 字 / 12px 内边距 / 8px 间距；
     · 数值格 = 标签(46px 定宽) · 操作符 · 输入(占满中段·左对齐·白底内嵌) · 单位(右对齐、定宽)，
       五行的标签左缘、操作符、输入框左缘、单位右缘全部对齐；
     · 流量格不再跨列；「不限流量」用 flex order 挪到行尾当小开关（**只改视觉顺序，DOM 一动不动**）；
     · 数值区收进「更多筛选」（不展开不占地方），展开后才出现「大于/精确」，且与「更多筛选」同排右对齐；
     · 工具条 4 个控件排成 2×2 等高网格（原来「视图切换」被挤到第二行单独一个，重心全散）。
   ⚠️ 全部规则只在 @media (max-width:860px) 内 —— 桌面端（≥861px）一个像素都不动。
   ============================================================ */
@media (max-width:860px){
  /* 统一刻度：本块内所有控件都从这里取值，以后改一处全变。
     ⚠️ 变量必须挂在 .filters 和 .listhd-a **两个**作用域上：工具条是 .filters 的兄弟节点，
        只写在 .filters 上的话 var() 取不到值 → height/radius 会整条失效（踩过）。 */
  .filters,.listhd-a{--c-h:38px;--c-r:10px;--c-fs:13.5px;--c-pad:12px;--c-gap:8px}
  .filters{padding:12px;gap:10px;border-radius:14px}

  /* ---- 1. 工具条：4 个控件 2×2 等高网格，四角对齐 ---- */
  .listhd-a{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));align-items:stretch;
    gap:var(--c-gap);width:100%;margin-left:0}
  .listhd-a>*{width:100%;min-width:0}
  .mobfilter,.cmpbtn{height:var(--c-h);padding:0 var(--c-pad);border-radius:var(--c-r);
    justify-content:center;font-size:var(--c-fs)}
  .pp{height:var(--c-h);padding:0 var(--c-pad);border:1px solid var(--border);border-radius:var(--c-r);
    background:var(--surface);display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:var(--c-fs)}
  .pp select{height:auto;padding:0;border:0;border-radius:0;background:transparent;
    font-size:var(--c-fs);font-weight:600;color:var(--text);flex:0 1 auto;max-width:64%}
  .viewseg{height:var(--c-h);width:100%;padding:3px;border-radius:var(--c-r)}
  .viewseg button{flex:1 1 0;width:auto;height:30px;border-radius:8px}

  /* ---- 2. 第一行：搜索独占一行；「更多筛选」贴右；「大于/精确」只在展开后出现且与它同排右对齐 ---- */
  .f-r1{gap:var(--c-gap)}
  .f-r1 .search{flex:1 1 100%;max-width:none;height:var(--c-h);padding:0 var(--c-pad);border-radius:var(--c-r)}
  .f-r1 .search input{font-size:14px}
  .f-r1 .morebtn{margin-left:auto;height:var(--c-h);padding:0 14px;border-radius:var(--c-r);
    font-size:13px;background:var(--surface-2)}
  .f-r1 .mode{display:none}
  /* 展开后：由 .mode 吃掉左侧剩余空间 → 「大于/精确」和「更多筛选」肩并肩右对齐（不再各占一头） */
  .filters.adv .f-r1 .mode{display:inline-flex;margin-left:auto;height:var(--c-h);padding:3px;border-radius:var(--c-r)}
  .filters.adv .f-r1 .morebtn{margin-left:0}
  .filters.adv .f-r1 .mode button{height:30px;padding:0 12px;border-radius:8px;font-size:13px}

  /* ---- 3. 数值条件：一行一格，标签·操作符·输入·单位 左边缘全部对齐 ---- */
  .f-r2{display:grid!important;grid-template-columns:1fr!important;gap:var(--c-gap)!important;
    overflow:visible!important;-webkit-mask-image:none!important;mask-image:none!important}
  .filters:not(.adv) .f-r2{display:none!important}      /* 收进「更多筛选」，默认不占地方 */
  .f-r2>*{width:100%;min-width:0;flex:initial}
  .f-r2>#nfTraffic{grid-column:auto!important}          /* 流量格不再跨两列 */
  .nf{display:flex;align-items:center;justify-content:flex-start;gap:8px;width:100%;min-width:0;
    height:var(--c-h);padding:0 var(--c-pad);border-radius:var(--c-r)}
  .nf .lb{flex:0 0 46px;font-size:13px;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .nf .op{flex:0 0 14px;text-align:center;font-size:13px}
  .nf input{flex:1 1 auto;min-width:80px;width:auto;height:28px;padding:0 10px;text-align:left;
    font-size:13.5px;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:var(--text)}
  .nf input:focus{border-color:var(--brand)}
  .nf .un{flex:0 0 26px;text-align:right;font-size:12px}
  .nf .unlim{order:1;flex:0 0 auto;height:26px;padding:0 10px;border-radius:8px;font-size:12px}

  /* ---- 4. 四个下拉 + 线路/退款：仍是 2 列网格，改成等高、等宽、四角对齐 ---- */
  .f-r3 .dd-btn,.f-r3 .msel-btn{display:flex;width:100%;height:var(--c-h);padding:0 var(--c-pad);
    border-radius:var(--c-r);gap:8px}
  .f-r3 .dd-btn .lb,.f-r3 .msel-btn .lb{flex:0 0 auto}
  .f-r3 .dd-btn .vl{margin-left:auto;min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:13px}
  .f-r3 .msel-tx{text-align:right;font-size:13px}
  .f-r3>.fend{gap:var(--c-gap)}
  .dirbtn,.resetbtn{height:var(--c-h);padding:0 var(--c-pad);border-radius:var(--c-r);font-size:var(--c-fs)}
}

/* 「更多筛选」开合的稳定性 + 明确的收起入口
   用户反馈：展开后再点收不回去。实测 390/430/479 三种宽度下 .adv 都能正常来回切，
   但手机上行宽/字体差异会让这一行换行、按钮换位 → 用户第二次点在原位置就落空了。
   所以：① 这一行**强制不换行**、按钮尺寸固定；② 展开区底部给一个整行的「收起筛选」。 */
@media (max-width:860px){
  .f-r1{flex-wrap:nowrap!important;align-items:center}
  .f-r1 .search{flex:1 1 auto;min-width:0}
  .f-r1 .mode,.f-r1 .morebtn{flex:0 0 auto}
  .morecollapse{display:none;width:100%;height:38px;margin-top:2px;border-radius:10px;
    border:1px dashed var(--border-strong);background:var(--surface-2);color:var(--text-2);
    font-size:13px;font-weight:600}
  .filters.adv .morecollapse{display:block}
  .formore:active,.morecollapse:active{background:var(--surface-3)}
}

/* ============================================================
   第 27 轮：移动端触摸目标与交互适配（2026-10-17）
   ------------------------------------------------------------
   背景：用户明确「移动端要像 App、不能有 BUG、UI 与功能适配都要好」，
        且「桌面端保持原样，一个像素都不许动」。
   原则：① 本块所有规则一律包在 @media (max-width:860px) 内；
        ② 能用「扩大热区」解决的不改视觉尺寸，避免布局连锁反应；
        ③ 每条都按 430×932 在 CDP 上实测（详见 reports/第二十七轮）。
   覆盖的实测问题：
     1. 卡片右上角勾选框 19×19 —— 手机上几乎点不中（对比入口就废了）；
     2. 「查看详情」被压到 28px 高，不到手指的一半；
     3. 分页按钮 34×34，翻页要戳好几次；
     4. 筛选项下拉从按钮下方展开、面板可到 430px，按钮在页面下半部时选项被切到屏幕外；
     5. 详情弹窗底部按钮 34px、系统/CPU 芯片 33px，都低于 44px 的触摸下限；
     6. 主题面板在手机上还显示「页面宽度与顶栏」—— 桌面端专属设置，手机上改了没任何效果；
     7. 顶栏四个控件 29~34px 高，四种高度不成套。
   ============================================================ */
@media (max-width:860px){
  /* ---- 1. 卡片勾选框：视觉 24px，热区 44px（::after 吃点击，DOM 不动） ---- */
  .card .pk{width:24px;height:24px;border-radius:7px;top:10px;right:10px}
  .card .pk::after{content:"";position:absolute;inset:-10px}
  .card .pk svg{width:13px;height:13px}
  .grid.list .card .pk{left:12px;right:auto;margin-top:-12px}

  /* ---- 2. 「查看详情」：手机上它才是卡片的主操作，放大到 38px ---- */
  .card .btn-detail{height:38px;padding:0 13px;font-size:12.5px;border-radius:10px}
  .card .c-foot{gap:8px}

  /* ---- 3. 分页：40px 方按钮 + 更大间距 ---- */
  .pager{gap:8px}
  .pager button{min-width:40px;height:40px;font-size:13px}

  /* ---- 4. 筛选项下拉：不越出视口（.up 由 fitDrop() 动态加，见 front.js） ---- */
  .dd-pop{overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
  .dd.up .dd-pop{top:auto;bottom:calc(100% + 6px);animation:vbPopUp .16s var(--ease)}
  @keyframes vbPopUp{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}

  /* ---- 5. 详情弹窗：底部按钮 44px、芯片 40px ---- */
  .m-ft .btn{min-height:44px;font-size:13.5px;border-radius:11px}
  .cchip{height:40px;padding:0 12px;font-size:13px}
  .cchip .oi svg{width:14px;height:14px}
  .m-hd .iconbtn{width:40px;height:40px}

  /* ---- 6. 对比浮条：按钮 38px，去掉机型 chip 的 19px 小叉 ---- */
  .pk-clr{height:38px;padding:0 14px;font-size:13px}
  .pkbar .btn{min-height:38px;padding:0 16px;font-size:13px}
  .pk-slot{height:34px;font-size:12.5px}
  .pk-chip{height:34px}
  .pk-chip .x{position:relative;width:24px;height:24px}
  .pk-chip .x::after{content:"";position:absolute;inset:-8px}

  /* ---- 7. 主题面板：贴上顶栏下沿（否则它会把顶栏那排按钮整个盖住，连"再点一次关闭"都做不到） ---- */
  #tpWTitle,#tpWidth,#tpTop{display:none!important}
  /* 顶栏是两行（栏目条 + 操作区），实测高 145px；面板原来写死 top:70px（桌面端顶栏只有 62px 所以没事），
     在手机上正好把主题按钮压在底下 → 移动端下移到顶栏下方。 */
  .themepop{top:152px;max-height:calc(100dvh - 168px);overflow-y:auto;overscroll-behavior:contain}
  .tp-row button,.tp-c{height:40px}

  /* ---- 8. 顶栏：四种高度（29/31/32/34）统一到 38/40 ---- */
  #navBtn{width:40px;height:40px}
  .iconbtn{width:38px;height:38px}
  #loginBtn{height:38px;padding:0 14px;font-size:13px}
  #langSeg,#curSeg{height:38px;padding:3px;border-radius:11px}
  #langSeg button,#curSeg button{height:30px;border-radius:9px}
}

/* ============================================================
   第 28 轮：移动端头部「控件面」统一（2026-10-17）
   ------------------------------------------------------------
   用户反馈：首页上半屏「这里不好看」。
   诊断（抓的是计算样式，不是感觉）—— 同一屏里出现了 **三套控件面** 交错：
     · 白底 + 边框  ：登录 / 分类与筛选 / 对比 / 每页
     · 灰底 + 边框  ：简繁、币种段、视图切换、搜索框、更多筛选、地区/库存/排序/币种、升序
     · 透明 + 无边框：重置筛选、主题按钮
   圆角还分了 9/10/11 三档；段控件的选中块是「白底叠白底」（只有 0.05 的阴影），
   基本看不出选中。整块于是就"糊"在一起，读不出层级。

   改法（**只动 ≤860px，桌面端一个像素不动**）：
     ① 控件面统一成「白底 + 1px 边框 + 10px 圆角」——一屏只有一种控件面；
     ② 段控件（简繁 / 币种 / 视图）的选中块改**主色浅底 + 主色字**，白胶囊里一眼可见；
     ③ 筛选区容器由白改浅灰（--surface-2）——原来白卡片里放白控件，只能靠描边硬撑；
     ④ 「对比」「主题」补齐边框、统一文字色，不再和旁边的控件一个深一个浅；
     ⑤ 「每页」内容居中；清空按钮 18px → 44px 热区。
   ============================================================ */
@media (max-width:860px){
  /* ① 一屏只有一种控件面：白底 + 边框 + 10px 圆角 */
  #loginBtn,#themeBtn,.seg,.viewseg,.pp,.search,.morebtn,.dd-btn,.dirbtn,.resetbtn,.nf{
    background:var(--surface);border:1px solid var(--border);border-radius:10px}
  .resetbtn,#themeBtn{border:1px solid var(--border)}      /* 这两个原来完全没有边框 */
  /* ⚠️ 这两处必须提到「和前一块同等/更高优先级」才盖得住：
     · #langSeg/#curSeg 上一轮是用 **ID 选择器**写的圆角 11px，.seg 这种类名压不过它；
     · 「更多筛选」上一轮写的是 `.f-r1 .morebtn{background:var(--surface-2)}`，权重也更高。 */
  #langSeg,#curSeg{border-radius:10px}
  .filters .f-r1 .morebtn{background:var(--surface);color:var(--text-2)}
  .dirbtn,.resetbtn{color:var(--text-2);font-weight:600}
  .dd-btn{color:var(--text-2)}
  .dirbtn:active,.resetbtn:active,.morebtn:active,.dd-btn:active{background:var(--surface-2)}

  /* ② 段控件选中块：主色浅底 + 主色字（原来是白底叠白底，等于没有选中态） */
  .seg button,.viewseg button{border-radius:8px}
  .seg button.on,.viewseg button.on{
    background:var(--brand-soft);color:var(--brand-ink);box-shadow:none;font-weight:600}

  /* ③ 筛选区：容器浅灰、里面全白 —— 层级一眼分明 */
  .filters{background:var(--surface-2)}
  .filters .nf input{background:var(--surface-2);border-color:var(--border)}
  .filters .nf input:focus{border-color:var(--brand)}
  .morecollapse{background:var(--surface);border-color:var(--border-strong);color:var(--text-2)}

  /* ③-b 「已选择」的下拉（如币种）原来是**饱和主色边框**，在满屏白控件里最跳的那一个就是它。
     改成浅主色描边 + 主色字：一样能看出"已选"，但不再抢内容区的注意力。 */
  .filters .dd.on .dd-btn{border-color:var(--brand-line);background:var(--surface)}
  .filters .dd.on .dd-btn .vl{color:var(--brand-ink)}

  /* ④ 「对比」和「分类与筛选」拉齐：文字同色、徽标加深 */
  .cmpbtn,.cmpbtn svg{color:var(--text-2)}
  .cmpbtn b{background:var(--surface-3);color:var(--text-2)}
  .cmpbtn.on,.cmpbtn.on svg{color:var(--brand-ink)}
  .cmpbtn.on b{background:var(--brand);color:#fff}

  /* ⑤ 「每页」居中；搜索框的清空按钮 18px → 44px 热区 */
  .pp{justify-content:center;gap:8px}
  .pp select{text-align:center}
  .search .kwclr{position:relative;width:22px;height:22px}
  .search .kwclr::after{content:"";position:absolute;inset:-11px}
}

/* ============================================================
   第 30 轮：英文显示 / 卡片标题与图标 / 代理登录弹窗（2026-10-17）
   ------------------------------------------------------------
   用户反馈四条（都带截图）：
     ① 英文模式下侧边栏文案被 ellipsis 切掉 ——「显示不完全」；
     ② 卡片标题被折成两行 ——「要一行显示最好，分行不好看」；
     ③ 卡片右上角勾选框 +「查看详情」的箭头图标太大（第 27 轮放大过，这次回调）；
     ④ 移动端代理登录是贴底抽屉，要**居中弹窗**；弹窗里那行说明文字不要显示。
   全部只在 ≤860px 生效，桌面端一个像素不动。
   （英文文案本身的翻译问题在 front.js 里修：新增 TERM_EN 显示层映射 + 币种选项 i18n。）
   ============================================================ */
@media (max-width:860px){
  /* ① 侧边栏条目：允许两行 —— 英文名（"Kingdom of the Netherlands E5 Native IP"）一行放不下 */
  .side-body .item{padding:7px 7px}
  .side-body .item .nm{white-space:normal;display:-webkit-box;-webkit-line-clamp:2;
    -webkit-box-orient:vertical;line-height:1.35}

  /* ② 卡片标题：中文最多 2 行（全量 1044 条中文标题实测最长 1.78 行 → 2 行 100% 不截断）；
     英文标题天然长（全量实测最长 3.2 行）→ 单给 4 行，宁可换行也不许省略号吃掉。 */
  .grid:not(.list) .card .c-name{-webkit-line-clamp:2;min-height:0}
  html[lang="en"] .grid:not(.list) .card .c-name{-webkit-line-clamp:4}

  /* ③ 图标回调：勾选框 24→20（**热区仍保持 44px**），「查看详情」箭头 14→12 */
  .card .pk{width:20px;height:20px}
  .card .pk::after{inset:-12px}
  .card .pk svg{width:12px;height:12px}
  .grid.list .card .pk{margin-top:-10px}
  .card .btn-detail svg{width:12px;height:12px}

  /* ④ 代理登录：居中弹窗（原来跟详情共用一套「贴底抽屉」，用户要的是弹窗样式） */
  #lgMask{align-items:center;padding:0 18px}
  #lgMask .modal{width:100%;max-width:400px;max-height:none;border-radius:var(--r-xl)}
  #lgModal .sub{display:none}      /* 那行「登录后可见代理专属价与退款政策」，用户要求不显示 */
}
@media (max-width:560px){
  /* ②-补 让标题真正回到一行（390/412/430 三种机型实测）：
     .c-name 的 clientWidth 含 padding-right:26px（给勾选框留位），真实可用宽只有 126px（390 机型）/
     146px（430 机型），而「【精品】fx香港3区-2核2G」这类中文标题 13px 要 156px → 必然折两行。
     四招各拿一点：卡片内边距 11→10、网格间距 10→8、标题右留白 26→22、字号 13→12.5。
     430 机型可用宽 146→153px，标题需求 156→150px → 回到一行。 */
  .grid{gap:8px}
  .grid>.card{padding:10px}
  .grid:not(.list) .card .c-name{font-size:12.5px;line-height:1.36;padding-right:22px}

  /* ③-补 规格值 2 行 → 4 行：实测只有 3 种长值会被切掉
     （"SK Broadband 广播IP"、"2000 Mbps 2000G 流量" 各 4 行，"1个ipv4+1个ipv6" 3 行）。
     宁可某一行高一点，也不能把「广播IP」整段吃掉。
     overflow-wrap 从 anywhere 改回 break-word：anywhere 会把 "Broadband" 拆成 "Broadba/nd"。 */
  .spg .v{-webkit-line-clamp:4;word-break:normal;overflow-wrap:break-word}
}

/* ============================================================
   第 31 轮：数值条件排成 2×2 + 「每页」整颗药丸可点（2026-10-17）
   ------------------------------------------------------------
   用户两条（都带截图）：
     ① 「这样排序吧，流量最底下长的，其他的变成 2*2 的样式，这样会看好些」
        —— 现在 5 个数值条件竖着排 5 行（第 25 轮为了「五行左右边缘全对齐」写死了单列 1fr，
           且被本文件更靠后的 ≤860px 块用 !important 钉住）。改成
           [CPU][内存] / [硬盘][价格] / 流量整行 —— 3 行，短一截、成组更清楚。
           顺序用 order 调（DOM 一动不动）：流量 order:2、收起按钮 order:3。
     ② 「这里有问题，没下拉选项」
        —— 实测：药丸 .pp 是 193×38，里面原生 #ppSel 只有 83×19（只占药丸高的 50%），
           上下各 9/10px 命中 SPAN.pp，点上去毫无反应；直接可点面积只占 **24%**，
           用户点药丸的上下半边自然「没下拉选项」。
           修法：select 撑满药丸高度 + 吃掉「每页」右侧全部宽度 → 132×36、可点率 **69%**，
           剩下的「每页」文字区由整颗药丸的点击兜住。
           （第 32 轮用户又提「我不要系统的这个，我要用你自己写的下拉」→ 手机端已换成
             站内自研的 .dd-pop 面板，见下面 ② 的 .pp.dd 一段；原生 select 只在桌面端用。）
   ============================================================ */
@media (max-width:860px){
  /* ---- ① 数值条件：2×2 网格 + 流量整行垫底 ---- */
  .f-r2{grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:8px!important}
  .f-r2>#nfTraffic{grid-column:1 / -1!important;order:2}
  .f-r2>.morecollapse{grid-column:1 / -1!important;order:3}

  /* 半格宽（实测 422px 机型约 180px）塞不下原来的 46px 定宽标签 + 80px 最小输入框：
     左右内边距各收 2px、标签改 34px 定宽（"内存" 13px 实测 26px）、间距 8→6，
     输入框仍有 ~78px（占位符 "不限" 13.5px 只要 27px）。 */
  .f-r2 .nf{gap:6px;padding:0 10px}
  .f-r2 .nf .lb{flex:0 0 34px}
  .f-r2 .nf .op{flex:0 0 10px}
  .f-r2 .nf input{min-width:0}
  .f-r2 .nf .un{flex:0 0 18px;font-size:11.5px}
  html[lang="en"] .f-r2 .nf .lb{flex:0 0 52px}   /* Memory / Traffic / Price 更长 */

  /* ---- ② 「每页」：整颗药丸都是热区 + 自研下拉（第 31 轮修热区，第 32 轮换组件） ---- */
  .pp{cursor:pointer}
  .pp>#ppTx{flex:0 0 auto;pointer-events:none}
  /* 自研下拉模式：front.js 的 renderPp() 在 ≤860px 时给 .pp 挂上 .dd，
     原生 select 收进 DOM 只是不让点（值照常回填），药丸本体就是按钮，
     选项走站内统一的 .dd-pop 面板 —— 和「地区 / 库存 / 排序 / 币种」一模一样。 */
  .pp.dd{position:relative;justify-content:flex-start;padding:0 var(--c-pad);gap:8px}
  .pp.dd>#ppSel{display:none}
  .pp.dd>#ppVl{flex:0 1 auto;min-width:0;margin-left:auto;font-size:var(--c-fs);font-weight:600;
    color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none}
  .pp.dd>#ppAr{flex:0 0 auto;pointer-events:none}
  .pp.dd.open{border-color:var(--brand)}
  /* 兜底：万一 renderPp() 没跑到（.pp 上没有 .dd），原生 select 仍是「撑满药丸高」的满热区版 */
  .pp:not(.dd) select{flex:1 1 auto;max-width:none;width:auto;height:100%;padding:0;border:0;
    border-radius:0;background:transparent;text-align:center;font-size:var(--c-fs);font-weight:600;
    color:var(--text);cursor:pointer}
  .pp:not(.dd) select:focus{outline:0}
  .pp:not(.dd):focus-within{border-color:var(--brand)}    /* 展开时边框变色，明确「这是个下拉」 */
}
/* 窄屏（≤400px，实测 360px 机型）半格只有 150px：上面的 34px 标签 + 10px 内边距会
   把输入框压到 47px，占位符「不限」（13.5px 需 27px）正好被切掉 → 再收一档。
   实测 360px 下输入框回到 61px（中文，内宽 47）/ 43px（英文，内宽 29），占位符与数字都放得下。 */
@media (max-width:400px){
  .f-r2{gap:6px!important}
  .f-r2 .nf{gap:5px;padding:0 8px}
  .f-r2 .nf .lb{flex:0 0 28px;font-size:12.5px}
  .f-r2 .nf .op{flex:0 0 10px}
  .f-r2 .nf input{padding:0 6px}
  html[lang="en"] .f-r2 .nf .lb{flex:0 0 46px}

  /* 「每页」窄屏：英文「Per page + Auto（8）+ ⌄」实测要 148px，而 360 机型药丸内宽只有 136px
     → 值被切到 46px（"Auto（…"）。内边距 12→8、间距 8→4、字号 13.5→12、箭头 14→12 之后
     实测 360/390 中英都能完整放下（英文需 135px / 有 146px）。 */
  .pp.dd{padding:0 8px;gap:4px}
  .pp.dd>#ppTx,.pp.dd>#ppVl{font-size:12px}
  .pp.dd>#ppAr svg{width:12px;height:12px}
}

/* ============================================================
   第 33 轮：桌面端「显示完整」—— 栏目名 / 商品名，简、繁、英三语（2026-10-17）
   ------------------------------------------------------------
   用户原话：「web端也要显示完整，还有商品名称；英文繁体简体都要做好适配显示」
   ⚠️ 本轮**解除**了此前「web 端不要做调整」的约束 —— 桌面端必须改。
   但移动端（≤860px）的成果一个像素都不能动：本块全部包在 @media (min-width:861px) 里，
   第 27~32 轮的移动端规则一律不受影响（回归时用「基线 CSS 交换」复验）。

   —— 先量后改（无头 Chrome 全量实测：1046 条商品名 + 153 条侧栏条目，zh/tw/en × 1440/1280/1680）——

   ① 卡片商品名 .c-name 桌面写死 -webkit-line-clamp:2，实测被切条数：
        zh@1440   0 条（最长 2 行）        zh@1280   2 条（最长 3 行）
        tw@1440   0 条（最长 2 行）        zh@1024   0 条（最长 2 行）
        en@1680   8 条（最长 3 行）        en@1440 113 条（最长 3 行）
        en@1280 480 条超过 2 行，其中 38 条要 4 行（最长 "Hong Kong Premium CN2 8-core 16GB 75Mbps restricted data"）
      → 桌面端直接**不限行**。卡片是 flex 列 + .c-foot{margin-top:auto}，
        标题变长只会把同排卡片整体撑高，页脚仍然齐底，不会出现参差。

   ② 侧边栏 .item .nm 桌面是 nowrap + ellipsis，实测被切条数：
        zh/tw  三级 4 / 141 条（最长需 169px，可用 155px）
        en     三级 129 / 141 条 + 二级 5 / 9 条
               （最长 "Channel 15 · Hong Kong Optimized High Defence Cloud" 需 394px，可用 155px，超出 239px）
      → 允许折行且不限行；英文再把侧栏 248→320px，让绝大多数落回 1~2 行
        （320px 下实测：1 行 56 条 / 2 行 97 条，只有 2 条要 3 行）。

   ③ 对比表表头的商品名 .cmh .nm 同样 clamp:2 → 一并放开（对比页每一行都是商品名，一个都不能切）。

   ④ 对比托盘 .pk-chip .nm 是 nowrap + ellipsis，英文实测可用 145px / 需 368px → 3 个 chip 全被吃掉。
      → 桌面端允许折行，chip 改 auto 高（最低 30px）+ 300px 上限宽。
   ============================================================ */
@media (min-width:861px){
  /* ① 卡片商品名：完整显示，不截断 */
  .c-name{display:block;-webkit-line-clamp:unset;-webkit-box-orient:horizontal;
    overflow:visible;overflow-wrap:break-word}

  /* ③ 对比表头商品名：同上 */
  .cmh .nm{display:block;-webkit-line-clamp:unset;-webkit-box-orient:horizontal;
    overflow:visible;overflow-wrap:break-word}

  /* ② 侧边栏栏目名：折行 + 不限行
     ⚠️ 这里踩过一个坑：先写成 display:-webkit-box + -webkit-line-clamp:2，
        但 .nm 是 flex item，display 会被 blockify 成 flow-root；Chrome 的新版 line-clamp
        在 flow-root 上**照样生效** → 实测仍有 2 条（1440/1280）/ 9 条（900）三级栏目
        被裁成 2 行（scrollHeight 51px vs clientHeight 34px）。
        既然用户要「显示完整」，侧栏也不再限行 —— 宁可某一条高一点，也不吃掉栏目名。 */
  .side-body .item .nm{white-space:normal;line-height:1.35;overflow-wrap:break-word;
    display:block;-webkit-line-clamp:unset;overflow:visible;text-overflow:clip}

  /* ④ 对比托盘 chip 里的商品名：英文实测可用 145px / 需 368px（"South Korea Triple Network
        Optimized Lightweight 1 Core 1G"），3 个 chip 全被省略号吃掉 → 桌面端允许折行。
       chip 从固定 30px 高改成 auto（最低 30px）、上限 300px 宽，名称折完仍是一枚小胶囊；
       .pk-list 本来就有 flex-wrap，最多把托盘挤高一行。 */
  .pk-chip{height:auto;min-height:30px;max-width:300px;padding:4px 6px 4px 10px}
  .pk-chip .nm{white-space:normal;line-height:1.3;overflow-wrap:break-word;overflow:visible;text-overflow:clip}
}
/* 英文侧栏加宽 248 → 320px。
   只在 ≥1181px 加宽：≤1180px 时 .layout 已是单列、侧栏转成横排卡片（见第 862 行），
   那档实测可用宽 226~240px、0 被切，不用管。
   代价是主区让出 72px：1440 视口下卡片仍是 4 列、单卡 269 → 251px，没有掉列。 */
@media (min-width:1181px){
  html[lang="en"] .layout{grid-template-columns:320px minmax(0,1fr)}
}

/* ============================================================
   第 34 轮：桌面端去掉「收起筛选」按钮（2026-10-17）
   ------------------------------------------------------------
   用户原话：「web端不要这个」（截图上红框圈的就是 .f-r2 末尾那颗「收起筛选」）。

   查明原因：.morecollapse 只有 @media (max-width:860px) 里的规则
        （默认 display:none，.filters.adv 时 display:block），
       桌面端一条规则都没有 → 落回浏览器默认 button 样式，
       所以才会以一个灰底小方块突兀地贴在「价格」筛选框右边。
       它本来就是移动端「更多筛选」展开后的收起入口；
       而桌面端 .morebtn（右上角那颗「更多筛选」）本身是 display:none、筛选全展开，
       **桌面根本不存在「收起」这个概念** —— 这颗按钮在桌面纯属漏网。

   改动：桌面端直接不显示。DOM 保留不动 —— front.js:2608 的 onclick 绑定照旧有效
        （手机端 390/430 都还在用），只是桌面看不见它。
   安全性：.f-r2 是 flex + wrap，子项 .nf 是 inline-flex 内容宽度（没有 flex:1），
        少这一颗按钮不会让其它 5 个筛选框变宽，也不会改变换行位置。
   ============================================================ */
@media (min-width:861px){
  .f-r2>.morecollapse{display:none}
}
