/* ═══════════════════════════════════════════════════════════════
   faorbit — 样式表(还原自 Homepage v4 设计稿)
   ═══════════════════════════════════════════════════════════════ */

/* ── 基础 ─────────────────────────────────────────────────────── */
html { scroll-padding-top: 150px; }
html, body { margin: 0; padding: 0; }
body {
  background: #F4F7FC;
  color: #0C1626;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
  font-weight: 500;
  -webkit-font-smoothing: antialiased;
}
a { color: #1B6BFF; text-decoration: none; }
a:hover { color: #0A56C8; text-decoration: none; }
input { font-family: inherit; font-weight: 500; }
input::placeholder { color: rgba(30, 50, 80, .7); }
::selection { background: rgba(46, 124, 255, .25); }
*::-webkit-scrollbar { width: 6px; height: 6px; }
*::-webkit-scrollbar-thumb { background: rgba(13, 38, 90, .18); border-radius: 3px; }
*::-webkit-scrollbar-track { background: transparent; }
/* 字重也要继承:否则按钮掉回浏览器默认的 400,而本站字重只有 500/600/700 */
button { font-family: inherit; font-weight: inherit; }

/* 内置 ease 起手太软,由输入直接触发的位移(hover 抬升 / 按压 / 浮层进出 / 箭头翻转)
   一律换成这条强 ease-out:起步快,第一帧就动,而那一帧正是用户盯着的地方。
   **只管位移与进出**,颜色 / 边框 / 底色那批照旧用 ease —— 颜色变化本来就该软起软收,
   跟着一起换会让 hover 的底色显得抢在鼠标前面。
   --ease-in-out 只有一个用户:.nav-ind。它不是进出而是「已经在屏幕上的东西平移
   过去」,两头都该收着点,用进出那条强 ease-out 会一头撞过去再刹住。 */
:root {
  --ease-out: cubic-bezier(.23, 1, .32, 1);
  --ease-in-out: cubic-bezier(.77, 0, .175, 1);
}

@keyframes dotGlow { from { opacity: .5; } to { opacity: 1; } }
@keyframes adPop { from { opacity: 0; transform: translateY(16px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes adFade { from { opacity: 0; } to { opacity: 1; } }
/* 下拉 / 浮层的入场:从触发器那一侧长出来 —— 挂在按钮下方的往下落,坐在按钮
   上方的往上升。配合各自的 transform-origin(见文件末尾那节),看起来才是从
   按钮里展开,而不是凭空在中间放大。
   位移只有个位数 px:adPop 那 16px 是给屏幕正中的弹窗用的,套在 236 宽的下拉上
   会明显慢半拍(实测原先复用它是 .18s 走 16px)。 */
/* 角标数字变多时弹一下:加购除了右下角那条 toast 之外没有任何指示,而「东西进车了」
   该由车自己说。只在变多时放(见 js 的 syncCartBadge),删一行不庆祝。 */
@keyframes badgeBump { 0% { transform: scale(1); } 40% { transform: scale(1.28); } 100% { transform: scale(1); } }
@keyframes popDown { from { opacity: 0; transform: translateY(-4px) scale(.98); } to { opacity: 1; transform: none; } }
/* 坐在触发器**上方**的浮层用这一条(目前只有消息中心那颗「+」的附件菜单
   `.msg-up-pop`):方向与 popDown 相反,收起的 .is-out 也必须跟着反过来,
   见文件末尾那节。 */
@keyframes popUp { from { opacity: 0; transform: translateY(4px) scale(.98); } to { opacity: 1; transform: none; } }
/* 减弱动效 ≠ 全部砍成 0。会引起不适的是**位移与缩放**,颜色 / 底色 / 透明度的
   过渡反过来是在帮着说明「这里变了」,砍掉只会让界面变得生硬。所以这里不再压时长,
   改成把 transform 从每一条 transition 里摘出去 —— 位移瞬间到位、颜色照旧渐变。
   关键帧仍然整体停掉(popDown / adPop / 跑马灯都是纯位移)。

   这条一刀切的代价站内已经付过一次:.rl-ring 的转圈被压成 0 后停成一段静止圆弧,
   只好在文件末尾单给它补一条铺平的规则(那条仍然需要,这里停的还是 animation)。

   没有 transition 声明的元素不受影响 —— 它们的 transition-duration 本来就是 0,
   只改 property 什么也不会发生。伪元素要显式写(通配符 * 不匹配),这一点
   auth.css 那边早就踩过并记在注释里,两个文件的写法保持一致。

   已知的小代价:属性列表被换成 7 个,而各元素原本声明的时长只有一两个,CSS 会把
   时长列表循环着配过去,于是某条颜色过渡可能拿到原本给别的属性写的时长。站内所有
   时长都在 .14–.3s 之间,差的这几十毫秒看不出来,不值得为它逐条重写。 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0s !important;
    animation-iteration-count: 1 !important;
    transition-property: opacity, color, background-color, border-color, box-shadow, fill, stroke !important;
  }
}
@media (forced-colors: active) {
  a, button { forced-color-adjust: auto; }
  .pdp-stars { forced-color-adjust: none; }   /* 评分条需保留作者色才有意义 */
}

a:focus-visible, button:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }

.page { min-width: 1366px; background: #F4F7FC; }
.container { box-sizing: content-box; max-width: 1366px; margin-inline: auto; padding-inline: 32px; }

/* 视图切换:首页 / 分类页 / 商品详情页
   一律反向匹配,使每个视图块默认隐藏 —— 新增视图只需再加一行,
   不会像正向匹配那样在遇到未知 data-view 值时同时泄漏多个视图。 */
.page:not([data-view="home"]) .home-only      { display: none; }
.page:not([data-view="cat"])  .cat-view       { display: none; }
.page:not([data-view="offers"]) .offers-view  { display: none; }
.page:not([data-view="pdp"])  .pdp-view       { display: none; }
.page:not([data-view="checkout"]) .checkout-view { display: none; }
.page:not([data-view="partners"]) .partners-view { display: none; }
.page:not([data-view="info"]) .info-view      { display: none; }
.page:not([data-view="faq"])  .faq-view       { display: none; }
.page:not([data-view="search"]) .search-view  { display: none; }
.page[data-view="pdp"] .hide-on-pdp           { display: none; }
/* 个人中心:信任条那四项(即时交货 / 被百万用户信任 / 支付安全快捷 / 在线客服)让位
   (2026-08-04 按用户要求)—— 那四条是**售前**信号,而这一页是已进站用户看自己的
   资料,读完不改变任何下一步动作。**支付图标行留着**:它挂在 .pays-row 上不受这条
   影响,与详情页同形态(那里也是只收四项、留支付行)。整条 .trust-band 没有一起收,
   所以页脚之前仍有收尾带,不会出现内容直接顶到深色页脚。 */
.page[data-view="account"] .hide-on-account   { display: none; }
/* 顶部 banner 与热门商品:首页与分类页共用,内容不随分类变化 */
.page:not([data-view="home"]):not([data-view="cat"]) .home-cat-only { display: none; }
/* 报价页:左栏换成筛选栏,分类导航与精选分区让位 */
.page[data-view="offers"] .hide-on-offers     { display: none; }
/* 合作伙伴页:整页全宽,侧栏与商品尾部(精选分区 / 客户之声)一起让位 —— 页面
   讲的是伙伴而不是商品,留着商品栅格会让「广告位 → 标签 → 伙伴」这条线断掉 */
.page[data-view="partners"] .hide-on-partners  { display: none; }
/* 说明页:同合作伙伴页,分类侧栏与商品尾部(精选分区 / 客户之声)一起让位 ——
   本页讲规则而不是商品,留着栅格会把「导航 → 正文」这条阅读线打断。
   信任条保留(与合作伙伴页一致),它是全站页脚前的固定收尾。 */
/* 常见问题页(`#/faq`)与说明页是同一种东西(一列正文 + 折叠问答),所以**共用
   `hide-on-info` 这一个类**,不新造一个 `hide-on-faq` —— 那样每个挂载点都要再
   多摞一个类名,而两者对侧栏 / 精选分区 / 客户之声的取舍逐条相同(同 `hide-on-solo`
   把 9 个全宽页合成一个类那条)。信任条同样保留。 */
.page[data-view="info"] .hide-on-info,
.page[data-view="faq"] .hide-on-info          { display: none; }
/* 搜索结果页:分类侧栏保留(方便从搜索转去浏览),但精选分区与客户之声让位 ——
   搜索是目标明确的行为,结果下面接一片跟关键词无关的推荐会把命中稀释掉。
   顶部 banner / 热门商品(home-cat-only)与推广位(home-only)靠上面的反向匹配
   已经自动隐藏,不用在这里再列一次。 */
.page[data-view="search"] .hide-on-search     { display: none; }
/* 后来加的 10 个独立页,一律全宽 */
.page:not([data-view="game"])    .game-view    { display: none; }
.page:not([data-view="seller"])  .seller-view  { display: none; }
.page:not([data-view="apply"])   .apply-view   { display: none; }
.page:not([data-view="invite"])  .invite-view  { display: none; }
.page:not([data-view="affiliate"]) .aff-view   { display: none; }
.page:not([data-view="affapply"]) .aff-apply-view { display: none; }
.page:not([data-view="shop"])    .shop-view    { display: none; }
.page:not([data-view="cart"])    .cart-view    { display: none; }
.page:not([data-view="orders"])  .orders-view  { display: none; }
.page:not([data-view="messages"]) .messages-view { display: none; }
.page:not([data-view="account"]) .account-view { display: none; }
.page:not([data-view="done"])    .done-view    { display: none; }
/* 这 8 个页面对「侧栏 / 精选分区 / 客户之声」的取舍完全一致(全都不要),所以合成
   一个 hide-on-solo,而不是在每个挂载点上再摞 8 个 hide-on-*。新增全宽页只改这里。
   信任条保留 —— 与说明页一致,它是页脚前的固定收尾。
   游戏页在列:它自带品牌条 + 类型 tab 这一套导航,再摆一份类目侧栏就是两套并行的
   导航;精选分区与客户之声同报价页那条,讲的是别的商品,会把这一页的线打断。 */
.page[data-view="game"] .hide-on-solo,
.page[data-view="seller"] .hide-on-solo,
.page[data-view="apply"] .hide-on-solo,
.page[data-view="invite"] .hide-on-solo,
.page[data-view="affiliate"] .hide-on-solo,
.page[data-view="affapply"] .hide-on-solo,
.page[data-view="shop"] .hide-on-solo,
.page[data-view="cart"] .hide-on-solo,
.page[data-view="orders"] .hide-on-solo,
.page[data-view="messages"] .hide-on-solo,
.page[data-view="account"] .hide-on-solo,
.page[data-view="topup"] .hide-on-solo,
.page[data-view="done"] .hide-on-solo { display: none; }
/* 消息中心是全站唯一「整页只有一屏」的视图(两栏定高见 `.msg-wrap`,底边
   比视口低 4px),所以信任条与页脚整块让位(2026-08-04 按用户要求,不是漏写)——
   往下滚才看得见的那两块,在这一页读作「客服界面下面还坠着一截官网」。
   **信任条整条收掉,不是照个人中心只收四格**:那一页收四格留支付图标行,是因为
   它后面还接着深色页脚,需要一条收尾带;这一页页脚也没了,支付图标行单独留着
   就成了页面末尾一排没有上下文的品牌 logo。
   四条售前信号(即时交货 / 被百万用户信任 / 支付安全快捷 / 在线客服)在这一页尤其
   不成立:用户已经买完了,而「在线客服 10:00–23:00」那格指的就是他正在用的这一页。
   **代价是这一页没有通往 11 个说明页的入口**(页脚三列是全站唯一入口),这是用户
   明确接受的取舍;页头仍在,回首页与各类目照常。别为此在页内补第二个说明页入口。 */
.page[data-view="messages"] .hide-on-messages { display: none; }
/* 结算页强力精简:付款环节移除所有出口与竞争性强调色 */
.page[data-view="checkout"] .hide-on-checkout { display: none; }
.page[data-view="checkout"] .main-wrap        { padding-top: 24px; }
/* 视图容器的 tabindex="-1" 只是给 applyRoute 末尾那句 host.focus() 用的落点
   (无障碍:路由切换后让屏幕阅读器与键盘用户知道主内容换了),它们不是可交互
   控件,浏览器默认焦点环(outline-style:auto)套在整块内容外面纯属噪音。
   以前看不见是因为其余视图全靠鼠标点击进入、:focus-visible 判定不成立;
   搜索页是全站唯一用回车进入的,一进来整块结果就被框起来。
   容器**里面**的链接与按钮照常有自己的 focus-visible 描边。
   **这条有一个已知误伤面**:结算页支付宫格是 roving tabindex,未选中的 7 颗也带
   tabindex="-1",会被这里一并关掉 —— 所以 .co-pays 自带一条特异性更高的
   focus-visible(见 .co-pay 那组)。以后再写 roving tabindex 组件时照办,
   别指望这条放过它们。 */
[tabindex="-1"]:focus { outline: none; }
/* 下拉的自绘箭头:全站 select(报价页排序、入驻申请向导里的国籍 / 国家 / 区号 /
   收款货币 / 类型档位等)一律 appearance:none,原生箭头换成 SEL_CARET_SVG 这一枚。
   这条只管「压在框右端、点得穿」—— pointer-events:none 不能删,不然点箭头这一块
   打不开下拉;水平位置由各自的 .off-sort / .sl-sel 覆盖(两处框高与内边距不是一套)。 */
.sel-caret {
  position: absolute; top: 50%; margin-top: -3px; right: 12px;
  display: block; pointer-events: none; color: rgba(30, 50, 80, .45);
}

/* ── 顶部工具条 ───────────────────────────────────────────────── */
.topbar { height: 38px; background: #0D1B2A; }
.topbar-inner { height: 38px; display: flex; align-items: center; gap: 16px; }
.topbar-dot {
  width: 7px; height: 7px; border-radius: 50%; background: #34D399;
  box-shadow: 0 0 10px rgba(52, 211, 153, .9);
  animation: dotGlow 1.8s ease-in-out infinite alternate;
  flex: none;
}
.topbar-text { color: rgba(255, 255, 255, .75); font-size: 13px; line-height: 17px; }
.topbar-links { margin-left: auto; display: flex; align-items: center; gap: 20px; }
.topbar-links a { color: rgba(255, 255, 255, .6); font-size: 13px; line-height: 17px; }
.topbar-links a:hover { color: #ffffff; }
.topbar a:focus-visible, .topbar button:focus-visible { outline-color: #6FB0FF; }
/* 语言 / 货币入口(2026-08-03 从 .head-actions 挪来,让搜索框回到页面正中):
   外观照 .topbar-links a 那套,不是浅底那颗 .head-btn 白描边药丸 —— 36px 的药丸
   塞不进 38px 的顶栏,深底上白描边也读不出。下拉面板仍是 .head-pop 白卡。
   z-index 70 抬过 .site-head 的 60:面板往下落会盖到吸顶头部上,不抬的话
   上半截被头部的毛玻璃白底压住(.head-pick 自带 position:relative,挂这里就够)。 */
.topbar-pick { z-index: 70; }
.topbar-pick-btn {
  display: flex; align-items: center;
  padding: 0; border: none; background: transparent;
  color: rgba(255, 255, 255, .6); font-size: 13px; line-height: 17px;
  transition: color .2s ease;
}
.topbar-pick-btn:hover { color: #ffffff; }

/* ── 吸顶头部 ─────────────────────────────────────────────────── */
.site-head {
  position: sticky; top: 0; z-index: 60;
  background: rgba(255, 255, 255, .85);
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  border-bottom: 2px solid #1B6BFF;   /* 品牌色收边:把头部与内容区切开 */
}
/* 三列栅格而不是 flex + 绝对居中的搜索框:搜索框曾经是 absolute + left:50%,
   不占位,右侧 .head-actions 一变宽就从它身上压过去(加「ZH ｜ USD」那颗按钮后
   实测重叠 57px,搜索框右边框正好穿过它)。改成栅格后三块互相让位,
   以后往 .head-actions 加按钮也压不到搜索框。
   三个子项都写死 grid-column:结算页 .search 是 hidden 的,靠自动排流的话
   .head-actions 会滑进中间那格。
   第三列的 minmax(max-content, 1fr) 不能退成 1fr:1fr 的最小值是 min-content,
   而右侧按钮栏比左侧品牌区宽,分到的那份不够,栅格就去压缩它里面的按钮
   (实测两枚图标按钮的 36px 被压成 20px)。锁住下限后它按内容占宽,
   中列的搜索框相应左移几十 px —— 让位的代价,总比压瘪按钮或压住搜索框好。 */
.head-row {
  position: relative; height: 76px;
  display: grid; grid-template-columns: 1fr auto minmax(max-content, 1fr);
  align-items: center; gap: 24px;
}
.brand { grid-column: 1; justify-self: start; display: flex; align-items: center; gap: 12px; }
/* 2026-08-03 从 34 / 21 放大到 48 / 30(整体 ×1.41,mark:word 仍是设计稿的 1.6)。
   **这两个数要按「可见墨迹」算,不是盒子高**:logo-mark.png 512 见方里只有
   370×315 有像素,38.5% 是透明留白 —— 34px 的盒子看得见的图形只有 20.9px,
   在 76px 的页头里占 27.5%,这才是用户报「图标太小」的来源(盒子并不小)。
   放到 48 后可见墨迹 29.5px = 页头的 38.8%,落在 35–45% 这档:够分量又不顶满。
   wordmark.png 留白少(80.6% 实心),30px 盒子里可见 24.2px。
   上限是 336:页头栅格第一列的宽度(1366 下 = 内容 1302 − 两个 24 间距 − 搜索框 560
   − 第三列 358),brand 总宽超了才会把搜索框推离正中,当前 182 离得远。
   gap 保持 12:mark 右侧自带 14.3% 留白,放大后墨迹间距自己从 19 长到 22,
   再把 gap 一起放大就散了。 */
.brand-mark { height: 48px; width: auto; display: block; }
.brand-word { height: 30px; width: auto; display: block; }

/* position:relative + z-index 让 .search 成为层叠上下文,里面 .sg-pop 的 z-index
   出不了这层门。所以要压过导航条(.nav-tab / .nav-home 都是 z-index 1)得在这里抬,
   下拉自己抬没用。(旧版靠 transform: translateX(-50%) 建这个上下文,搜索框改成
   栅格中列后不再需要位移,但 z-index:10 这一条不能跟着去掉。) */
.search {
  grid-column: 2; position: relative; z-index: 10;
  width: 560px; height: 44px; box-sizing: border-box;
  background: rgba(13, 38, 90, .05);
  border: 1px solid rgba(13, 38, 90, .1);
  border-radius: 12px; padding: 0 14px;
  display: flex; align-items: center; gap: 10px;
  transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.search:focus-within {
  border-color: rgba(27, 107, 255, .6);
  box-shadow: 0 0 0 4px rgba(46, 124, 255, .14);
  background: #ffffff;
}
.search svg { flex: none; }
.search input {
  flex: 1; border: none; outline: none; background: transparent;
  font-size: 14px; line-height: 18px; color: #0C1626;
}
.search-kbd {
  flex: none; height: 22px; padding: 0 8px; border-radius: 6px;
  border: 1px solid rgba(13, 38, 90, .14);
  color: rgba(30, 50, 80, .45); font-size: 11px;
  display: flex; align-items: center; letter-spacing: .06em;
}
/* 清空按钮占的是快捷键提示那个位子(两者互斥),所以尺寸与它对齐,
   免得输入前后搜索框里的元素宽度一跳。 */
.search-clear {
  flex: none; width: 22px; height: 22px; padding: 0; border-radius: 50%;
  border: none; background: rgba(13, 38, 90, .08); color: rgba(30, 50, 80, .6);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background-color .2s ease, color .2s ease;
}
.search-clear:hover { background: rgba(13, 38, 90, .14); color: #0C1626; }
.search-clear:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.search-clear[hidden] { display: none; }

/* ── 搜索建议下拉 ──
   包含块是 .search 自己(它带 position:relative,别改回 static)。
   .site-head 的 z-index 60 让整个头部盖在正文之上,下拉跟着受益。
   但这里的 z-index 只在 .search 这个层叠上下文内部管事(它带 transform),
   压不到头部里的兄弟节点 —— 要压导航条请改 .search 的 z-index,不是这个数。 */
.sg-pop {
  position: absolute; top: calc(100% + 8px); left: 0; right: 0; z-index: 5;
  box-sizing: border-box; max-height: 464px; overflow-y: auto; padding: 6px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .1);
  border-radius: 14px; box-shadow: 0 22px 46px rgba(13, 38, 90, .16);
  /* 全站最高频的浮层,此前是唯一裸出现的一个 —— 低频的语言下拉反而有动画,
     优先级正好反了。.15s 而不是语言下拉的 .18s:它跟着输入焦点走,比点开一个
     菜单更需要立刻在位。 */
  transform-origin: top center;
  animation: popDown .15s var(--ease-out);
}
.sg-sec + .sg-sec { margin-top: 5px; padding-top: 5px; border-top: 1px solid rgba(13, 38, 90, .07); }
.sg-label {
  display: block; padding: 5px 10px 3px;
  font-size: 12px; letter-spacing: .06em; color: rgba(30, 50, 80, .7);
}
.sg-row {
  display: flex; align-items: center; gap: 10px;
  height: 46px; padding: 0 10px; border-radius: 10px;
}
/* 键盘高亮(.is-on)与 hover 同一个底色:两条路径选中同一行时看起来必须一样 */
.sg-row:hover, .sg-row.is-on { background: rgba(27, 107, 255, .08); }
.sg-ico {
  flex: none; width: 30px; height: 30px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
}
.sg-ico img { width: 18px; height: 18px; object-fit: contain; display: block; }
.sg-letter { font-size: 13px; font-weight: 700; color: #123A8F; }
.sg-ico-cat { background: rgba(27, 107, 255, .1); }
.sg-ico-cat svg { fill: #1B6BFF; display: block; }
.sg-name {
  flex: 1; min-width: 0; font-size: 14px; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sg-hit { font-style: normal; font-weight: 700; color: #1B6BFF; }
.sg-cat { flex: none; font-size: 12px; color: rgba(30, 50, 80, .7); }
.sg-price { flex: none; font-size: 14px; font-weight: 700; color: #0C1626; }
/* 吸在下拉底部而不是跟着列表滚:命中多时(8 条商品 + 分类行就已经 523 > 462)
   它会被挤到滚动区外,而它是通往结果页的主入口,默认看不见等于没有。
   底色必须不透明 —— 半透明会把底下滚过去的行透出来,所以 hover 用把
   rgba(27,107,255,.08) 在白底上压平后的等效色 #EDF3FF。 */
.sg-all {
  position: sticky; bottom: -6px; z-index: 1;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  height: 38px; border-radius: 10px; font-size: 13px; color: #1B6BFF;
  background: #ffffff; box-shadow: 0 -6px 8px -6px rgba(13, 38, 90, .1);
}
.sg-all:hover, .sg-all.is-on { background: #EDF3FF; }
.sg-empty { padding: 26px 0; text-align: center; font-size: 14px; color: rgba(30, 50, 80, .7); }

.head-actions { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: 10px; }
.head-btn {
  height: 36px; padding: 0 12px; border-radius: 10px;
  border: 1px solid rgba(13, 38, 90, .14);
  color: #23324A; font-size: 14px; font-weight: 500;
  display: flex; align-items: center; gap: 6px;
  transition: border-color .2s ease, color .2s ease;
}
.head-btn:hover { border-color: rgba(27, 107, 255, .55); color: #1B6BFF; }
.head-btn svg { flex: none; display: block; }
.head-btn-icon { width: 36px; padding: 0; justify-content: center; }
.head-btn-promo {
  padding: 0 14px;
  background: rgba(46, 124, 255, .09);
  border-color: rgba(46, 124, 255, .35);
  color: #1B5FE8; font-weight: 700; white-space: nowrap;
  transition: background-color .2s ease, border-color .2s ease;
}
.head-btn-promo:hover { background: rgba(46, 124, 255, .16); border-color: rgba(46, 124, 255, .6); color: #1B5FE8; }
/* 登录入口:文字比图标按钮宽,但不做成主色实心 —— 它与「推广合作」并排,
   两个都抢眼就等于都不显眼,而这一栏的主角是推广位。 */
.head-btn-auth { padding: 0 14px; white-space: nowrap; font-weight: 600; }
/* 详情页卖家条那两颗按钮(联系客服 / 进入店铺)也走 `.head-btn-promo`:
   2026-08-05 当天试过「客服浅蓝底 + 进店铺只描边」的主次分档(`.head-btn-line`),
   用户当场要求两颗颜色一样,那条已删净 —— 别再加回来。 */
/* 账户余额 / 充值入口。数字用 tabular-nums:余额一变(充值、下单扣款)宽度会跟着
   跳,而它右边紧挨着头像 —— 等宽数字下 $9.00 → $10.00 只长一位的宽度,不会整块抖。
   内边距比 `.head-btn-auth` 的 14 收到 10:这一栏已经排了五件东西,而每多 1px 都会
   把搜索框推离页面正中(见 `.head-row` 那条三列栅格的说明)。 */
.head-bal { padding: 0 10px; white-space: nowrap; font-weight: 600; font-variant-numeric: tabular-nums; }
.head-avatar {
  width: 36px; height: 36px; border-radius: 50%;
  background: linear-gradient(140deg, #2E7CFF, #8B5CFF);
  display: flex; align-items: center; justify-content: center; flex: none;
  box-shadow: 0 4px 14px rgba(46, 124, 255, .35);
}
/* display:flex 盖过浏览器默认的 [hidden]{display:none},未登录时得显式补一条 */
.head-avatar[hidden] { display: none; }

.nav-row { position: relative; height: 54px; display: flex; align-items: center; gap: 4px; }
/* 选中态标签页:只留上圆角、底边贴住 .site-head 的品牌色收边并与之同色,
   两者连成一体 —— 而不是一枚悬在行内的胶囊按钮。
   蓝底不长在 tab 上,而是这块独立的 .nav-ind,点另一个 tab 时它平移过去;
   tab 自身只过渡文字色。位置由 main.js 按 getBoundingClientRect 写在行内样式上。 */
.nav-ind {
  position: absolute; left: 0; bottom: 0; z-index: 0;
  width: 0; height: 40px; border-radius: 10px 10px 0 0;
  background: #1B6BFF;
  /* 全站唯一的「已经在屏幕上的东西平移过去」,所以用 --ease-in-out 而不是进出那条。
     width 跟着一起过渡是有意的:它是绝对定位的独立元素,改宽不牵连任何兄弟节点,
     而换成 scaleX 会把 10px 10px 0 0 的圆角横向压变形。 */
  transition: transform .22s var(--ease-in-out), width .22s var(--ease-in-out),
    opacity .2s ease;
}
.nav-ind.no-anim { transition: none; }   /* 首帧定位与横向滚动跟随:不要动画 */
/* 没有对应 tab 的页面(购物车 / 订单 / 说明页…)整块收掉。退场淡出、进场瞬时:
   进场那次由 no-anim 一并关掉 opacity 过渡,蓝底直接落在正确位置,
   不从上一页记住的坐标滑过来。 */
.nav-ind.is-off { opacity: 0; }
.nav-home {
  position: relative; z-index: 1;
  align-self: flex-end;
  height: 40px; padding: 0 22px; border-radius: 10px 10px 0 0;
  color: rgba(30, 50, 80, .8); font-size: 14px; font-weight: 700;
  display: flex; align-items: center;
  margin-right: 10px;
  transition: background-color .2s ease, color .2s ease;
}
.nav-home:hover { background: rgba(46, 124, 255, .09); color: #1B5FE8; }
.nav-home.is-on, .nav-home.is-on:hover,
.nav-tab.is-on, .nav-tab.is-on:hover { background: transparent; color: #ffffff; }
/* 与 .nav-home 同高同贴底,保证所有类目文字落在同一条基线上 */
.nav-tabs {
  min-width: 0; align-self: flex-end; display: flex; align-items: stretch; gap: 0;
  overflow-x: auto; scrollbar-width: none;
}
.nav-tabs::-webkit-scrollbar { display: none; }
.nav-tab {
  position: relative; z-index: 1;
  height: 40px; padding: 0 13px; border-radius: 10px 10px 0 0;
  color: rgba(30, 50, 80, .8); font-size: 14px; font-weight: 500;
  display: flex; align-items: center; gap: 6px; white-space: nowrap;
  transition: background-color .2s ease, color .2s ease;
}
.nav-tab:hover { background: rgba(46, 124, 255, .09); color: #1B5FE8; }
.nav-hot {
  padding: 1px 5px; border-radius: 5px;
  background: #FF3B3B; color: #ffffff;
  font-size: 10px; font-weight: 700; letter-spacing: .04em;
}

/* ── 主容器 ───────────────────────────────────────────────────── */
.main-wrap { padding-top: 22px; }
.layout { display: flex; gap: 16px; align-items: flex-start; margin-top: 16px; }
/* 那 16 是**给通栏 banner 与内容之间**留的,而 banner 只在首页与分类页出现
   (`home-cat-only`)。其余 12 个视图里 banner 是 display:none,这 16 就直接摞在
   `.main-wrap` 的 22 上,凑成 40px 的空白顶着一行 14px 的面包屑 —— 2026-08-03
   用户报的「上面空位太大了」先在游戏页出现,其实全站都是这一处。
   收掉之后每个视图的第一件东西一律落在导航条下方 **24**(2 + 22),口径统一。
   排除条件照抄上面 `home-cat-only` 那条反向匹配,两处要一起改。 */
.page:not([data-view="home"]):not([data-view="cat"]) .layout { margin-top: 0; }
.content { flex: 1; min-width: 0; }
.tail-spacer { height: 76px; }

/* ── 顶部通栏 Banner(广告位)──────────────────────────────────── */
.banner-link {
  display: block; border-radius: 16px; overflow: hidden;
  box-shadow: 0 10px 28px rgba(13, 38, 90, .1);
  transition: transform .15s var(--ease-out), box-shadow .15s ease;
}
.banner-link:hover { transform: translateY(-2px); box-shadow: 0 18px 40px rgba(13, 38, 90, .18); }
.banner-link:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 3px; }
.ad-banner {
  position: relative; height: 72px; box-sizing: border-box;
  display: flex; align-items: center; gap: 16px; padding: 0 28px;
  background:
    radial-gradient(620px 220px at 10% -20%, rgba(58, 90, 255, .5), transparent 62%),
    radial-gradient(520px 200px at 88% 120%, rgba(139, 60, 255, .42), transparent 60%),
    linear-gradient(120deg, #151233, #0B0F24 55%, #0A0E1E);
}
.ad-banner::before {
  content: ""; position: absolute; inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 32px 32px;
  mask-image: radial-gradient(700px 160px at 50% 0%, rgba(0, 0, 0, .8), transparent 80%);
  -webkit-mask-image: radial-gradient(700px 160px at 50% 0%, rgba(0, 0, 0, .8), transparent 80%);
}
.ad-banner > * { position: relative; }
.ad-banner-badge {
  flex: none; height: 22px; padding: 0 11px; border-radius: 999px;
  background: linear-gradient(135deg, #FFB020, #F0700C);
  color: #2A1600; font-size: 11px; font-weight: 700; letter-spacing: .08em;
  display: flex; align-items: center;
}
.ad-banner-title { font-size: 18px; font-weight: 700; color: #ffffff; white-space: nowrap; }
.ad-banner-sub {
  font-size: 14px; color: rgba(200, 215, 240, .65);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
/* ── 分类侧栏 ─────────────────────────────────────────────────── */
.sidebar {
  flex: none; width: 248px; box-sizing: border-box;
  background: #ffffff;
  border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  border-radius: 18px; padding: 10px;
  position: sticky; top: 146px;
  max-height: calc(100vh - 162px); overflow-y: auto;
}
.sidebar-head { display: flex; align-items: center; gap: 9px; padding: 8px 10px 14px; }
.sidebar-bar {
  width: 14px; height: 4px; border-radius: 2px;
  background: linear-gradient(120deg, #2E7CFF, #0E9FD8); flex: none;
}
.sidebar-title { font-size: 12px; font-weight: 700; letter-spacing: .1em; color: rgba(20, 35, 60, .55); }
.sidebar-count { margin-left: auto; font-size: 12px; color: rgba(30, 50, 80, .35); }
.sidebar-list { display: flex; flex-direction: column; gap: 3px; }

.cat-item {
  height: 48px; padding: 0 12px; border-radius: 12px;
  display: flex; align-items: center; gap: 12px;
  transition: background-color .2s ease, transform .2s var(--ease-out);
}
.cat-item:hover { background: rgba(27, 107, 255, .06); transform: translateX(2px); }
.cat-ico {
  flex: none; width: 34px; height: 34px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(27, 107, 255, .12); color: #1B6BFF;
}
.cat-ico svg { display: block; fill: currentColor; }
.cat-label {
  flex: 1; min-width: 0; font-size: 14px; font-weight: 500; color: #23324A;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cat-num { font-size: 12px; color: rgba(30, 50, 80, .7); flex: none; }
.cat-arrow { flex: none; }

.cat-item.is-active {
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8);
  box-shadow: 0 8px 20px rgba(37, 99, 235, .32), inset 0 1px 0 rgba(255, 255, 255, .22);
}
.cat-item.is-active:hover { transform: none; }
.cat-item.is-active .cat-ico { background: rgba(255, 255, 255, .22); color: #ffffff; }
.cat-item.is-active .cat-label { font-weight: 700; color: #ffffff; }
.cat-item.is-active .cat-num { color: rgba(255, 255, 255, .7); }

/* ── 首页推广位 ───────────────────────────────────────────────── */
/* stretch:让侧边两张自动填满主卡高度,尺寸只由 .promo-main 一处决定 */
.promo-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 14px; align-items: stretch; }
.promo-side { display: grid; grid-template-rows: 1fr 1fr; gap: 14px; }
.promo-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 14px; }

.promo-card {
  position: relative; display: block; border-radius: 16px; overflow: hidden;
  background: #ffffff; box-shadow: 0 8px 24px rgba(13, 38, 90, .07);
  transition: transform .15s var(--ease-out), box-shadow .15s ease;
}
.promo-card:hover { transform: translateY(-4px); box-shadow: 0 20px 44px rgba(13, 38, 90, .18); }
.promo-card:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 3px; }

/* 主推大卡 —— 高度是整块促销区的基准:416 + 14 + 201 = 631,
   与左侧 12 项分类栏(12×48 + 11×3 + 20 内边距 + 2 边框)等高对齐 */
.promo-main {
  height: 416px; box-sizing: border-box;
  background:
    radial-gradient(460px 320px at 88% 14%, rgba(139, 92, 255, .55), transparent 66%),
    linear-gradient(125deg, #1B5FE8, #2E7CFF 46%, #8B5CFF);
}
.pm-ring {
  position: absolute; right: -70px; bottom: -110px;
  width: 320px; height: 320px; border-radius: 50%;
  border: 44px solid rgba(255, 255, 255, .08);
}
.pm-logo {
  position: absolute; right: 38px; top: 56px;
  width: 168px; height: 168px; opacity: .2; display: block;
  filter: invert(1); /* jsdelivr 图标为黑色,反色成白色水印 */
}
.pm-body {
  position: relative; height: 100%; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: flex-start;
  padding: 38px 36px;
}
.pm-kicker {
  height: 24px; padding: 0 12px; border-radius: 999px;
  background: rgba(255, 255, 255, .14); border: 1px solid rgba(255, 255, 255, .22);
  color: rgba(255, 255, 255, .92); font-size: 11px; font-weight: 700; letter-spacing: .08em;
  display: flex; align-items: center;
}
.pm-title {
  margin-top: 22px; font-size: 37px; line-height: 45px; font-weight: 700; color: #ffffff;
  text-shadow: 0 2px 14px rgba(9, 22, 60, .35);
}
.pm-sub { margin-top: 12px; font-size: 14px; color: rgba(255, 255, 255, .78); }
.pm-foot { margin-top: auto; display: flex; align-items: center; gap: 18px; }
.pm-price { display: flex; align-items: baseline; gap: 3px; color: #ffffff; font-weight: 700; }
.pm-price i { font-style: normal; font-size: 16px; }
.pm-price { font-size: 33px; line-height: 37px; }
.pm-price u { text-decoration: none; font-size: 14px; font-weight: 500; color: rgba(255, 255, 255, .75); }
.pm-cta {
  height: 36px; padding: 0 20px; border-radius: 18px;
  background: #ffffff; color: #1B5FE8; font-size: 14px; font-weight: 700;
  display: flex; align-items: center;
  box-shadow: 0 10px 24px rgba(9, 22, 60, .3);
}

/* 迷你横卡 —— 五张同高 201:侧边两张由 grid 拉伸自动得出 (416-14)/2,
   底排三张显式对齐同一数值,整块促销区因此是均匀的模块网格 */
.promo-mini {
  height: 201px; box-sizing: border-box;
  display: flex; align-items: center; gap: 14px; padding: 0 26px;
}
.promo-side .promo-mini { height: auto; }
.promo-mini::before {
  content: ""; position: absolute; right: -26px; top: -28px;
  width: 124px; height: 124px; border-radius: 50%;
  background: rgba(255, 255, 255, .09);
}
.pmini-body { position: relative; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
.pmini-kicker { font-size: 11px; font-weight: 500; letter-spacing: .04em; color: rgba(255, 255, 255, .85); text-shadow: 0 1px 8px rgba(0, 0, 0, .3); white-space: nowrap; }
.pmini-title { font-size: 20px; line-height: 25px; font-weight: 700; color: #ffffff; text-shadow: 0 1px 8px rgba(0, 0, 0, .3); white-space: nowrap; }
.pmini-price { display: flex; align-items: baseline; gap: 2px; color: #ffffff; font-size: 25px; line-height: 29px; font-weight: 700; text-shadow: 0 1px 8px rgba(0, 0, 0, .3); }
.pmini-price i { font-style: normal; font-size: 14px; }
.pmini-price u { text-decoration: none; font-size: 13px; font-weight: 500; color: rgba(255, 255, 255, .85); margin-left: 2px; }
.pmini-logo {
  position: relative; margin-left: auto; flex: none;
  width: 30px; height: 30px; object-fit: contain; display: block;
  background: #ffffff; padding: 13px; border-radius: 15px;
  box-shadow: 0 10px 22px rgba(0, 0, 0, .22);
}
.pmini-logo-svg { box-sizing: content-box; }

.promo-netflix { background: linear-gradient(125deg, #3D060B, #8A0007 58%, #C00711); }
.promo-spotify { background: linear-gradient(125deg, #04340F, #07702F 58%, #12A544); }
.promo-itunes { background: linear-gradient(125deg, #0E2A5C, #21509E 58%, #3B7DD8); }
.promo-telegram { background: linear-gradient(125deg, #0A3A52, #1A82D4 58%, #2FBBEA); }
.promo-sim { background: linear-gradient(125deg, #45125E, #8B44F7 55%, #C43A24); }

/* ── 分类页视图 ───────────────────────────────────────────────── */
.cat-head-sub { font-size: 14px; line-height: 19px; color: rgba(30, 50, 80, .7); }
/* 商家数抬到墨色 + 700 —— 它是这页的事实。 */
.cat-head-sub b { font-weight: 700; color: #23324A; }

.prod-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }

/* 无展开条的分类,行高统一取「三排铺满 631 时的单排高」= (631 - 2×16) / 3 ≈ 200,
   比自然高 163 高 37px —— 这是卡片高度的上限,不随商品数变化:
     12 款 → 3 排 × 200 = 631,底部正好对齐左侧栏(631,同 .promo-main 那条等高关系,
             侧栏增删项要一起改)
     少于 9 款 → 排数少,栅格自然变矮、下方留白,卡片不会被拉成细长条
   刻意不用 min-height:631 + auto-rows:1fr —— 那会让 3 款商品的单排涨到 631 高。
   多出的 20px 全给渐变头 .fcard-top:不给 flex:1 的话 .feat-card 这个 flex column
   会把空档留在卡片底部,白边一条。
   注意这会让 .fcard-top 从 112 涨到 ~132,三排底部落到 788,矮窗口(< 800)
   一屏看不完第三排,是明确取舍,别当 bug 改回去。 */
.prod-grid-fill { grid-auto-rows: calc((631px - 2 * 16px) / 3); }
.prod-grid-fill .fcard-top { flex: 1; }

/* 有「查看更多」展开条时,栅格可用高度少 54 = 按钮 38(9 上下内边距 + 13/18 文字 + 2 边框)
   + margin-top 16,单排落到 (631 - 54 - 32) / 3 ≈ 182。
   旧版是「有展开条就不撑」,理由写的是那 54px 已经把差补上 —— 实测补不上:
   自然三排 521 + 54 = 575,离 631 差 56,按钮底部就悬在侧栏底部上方。
   展开后按钮消失,行高回到上面那条的 200,与展开前差 18px(旧版是差 37)。 */
.prod-grid-fill-more { grid-auto-rows: calc((631px - 54px - 2 * 16px) / 3); }

/* ── 搜索结果页 ──
   栅格刻意不用 .prod-grid-fill:那个 631 的 grid-auto-rows 是为「分类页三排
   对齐侧栏底部」设的,搜索命中只有一两条时会把卡片拉成半屏高的空壳。
   结果少时左侧栏比栅格高出一截,与报价页左栏同理,是预期的。 */
.sr-head { display: flex; align-items: baseline; gap: 10px; padding: 6px 2px 18px; }
.sr-head h1 { margin: 0; font-size: 30px; line-height: 38px; font-weight: 700; color: #0C1626; }
.sr-count { font-size: 14px; color: rgba(30, 50, 80, .7); }
.sr-cats { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 2px 18px; }
.sr-cat {
  height: 32px; padding: 0 13px; box-sizing: border-box;
  border-radius: 9px; border: 1px solid rgba(13, 38, 90, .12);
  display: flex; align-items: center; gap: 7px;
  font-size: 14px; color: #23324A;
  transition: border-color .2s ease, color .2s ease;
}
.sr-cat:hover { border-color: rgba(27, 107, 255, .55); color: #1B5FE8; }
.sr-cat svg { flex: none; fill: currentColor; display: block; }
.sr-cat i { font-style: normal; font-size: 12px; color: rgba(30, 50, 80, .7); }
.sr-empty { padding: 56px 0 40px; text-align: center; }
.sr-empty p { margin: 0 0 7px; font-size: 17px; line-height: 22px; font-weight: 700; color: #0C1626; }
.sr-empty span { font-size: 14px; color: rgba(30, 50, 80, .7); }
.sr-empty .sr-cats { justify-content: center; padding: 22px 0 0; }

/* 分类页栅格超过三排时的展开条 */
.more-btn {
  display: flex; align-items: center; justify-content: center;
  width: 100%; box-sizing: border-box; margin-top: 16px;
  padding: 9px 0; border-radius: 11px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .07);
  box-shadow: 0 6px 18px rgba(13, 38, 90, .06);
  font-family: inherit; font-size: 14px; font-weight: 600;
  color: rgba(30, 50, 80, .7); cursor: pointer;
  transition: color .25s ease, border-color .25s ease, box-shadow .25s ease;
}
.more-btn:hover {
  color: #1B6BFF; border-color: rgba(27, 107, 255, .45);
  box-shadow: 0 18px 40px rgba(13, 38, 90, .13);
}
.more-btn:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 3px; }
.prod-frame { flex: none; padding: 2px; border-radius: 17px; }
.prod-ico {
  width: 56px; height: 56px; border-radius: 15px;
  display: flex; align-items: center; justify-content: center;
}
.prod-ico img { width: 32px; height: 32px; object-fit: contain; display: block; }
.prod-letter { font-size: 17px; font-weight: 700; color: #123A8F; }
.prod-tag {
  align-self: flex-start; max-width: 100%; box-sizing: border-box;
  border-radius: 5px; padding: 2px 7px;
  background: rgba(13, 38, 90, .05); border: 1px solid rgba(13, 38, 90, .06);
  color: rgba(30, 50, 80, .7); font-size: 12px; line-height: 16px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 卖家行 —— 头像沿用 .review-avatar 的渐变约定,缩到 20px */
.prod-seller { display: flex; align-items: center; gap: 6px; min-width: 0; }
.prod-avatar {
  flex: none; width: 20px; height: 20px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #ffffff; font-size: 12px; font-weight: 700;
}
.prod-seller-name {
  min-width: 0; font-size: 13px; line-height: 17px; font-weight: 500;
  color: rgba(30, 50, 80, .7);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.prod-verify { flex: none; display: block; }

/* 徽章:自动发货是真实二值信号(约四分之一商品为人工代充),不是装饰 */
.prod-flag {
  box-sizing: border-box; border-radius: 5px; padding: 2px 7px;
  font-size: 12px; line-height: 16px; font-weight: 600;
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
}
.prod-flag svg { flex: none; display: block; }
.prod-flag-auto   { background: rgba(14, 125, 69, .09); border: 1px solid rgba(14, 125, 69, .18); color: #0E7D45; }
.prod-flag-manual { background: rgba(13, 38, 90, .05); border: 1px solid rgba(13, 38, 90, .06); color: rgba(30, 50, 80, .7); }
.price { display: flex; align-items: baseline; gap: 2px; }
.price-cur { font-size: 14px; font-weight: 700; color: #1B6BFF; }
/* 卡片价格统一 22/25:报价卡那轮校准定的就是这一档(= .fcard-foot),
   基准写在这里之后,各类卡片不必再各抄一条同样的覆盖。 */
.price-num { font-size: 22px; line-height: 25px; font-weight: 700; color: #0C1626; }
.price-from { font-size: 13px; color: rgba(30, 50, 80, .7); margin-left: 2px; }
/* ── 合作伙伴页 ───────────────────────────────────────────────────
   四块自上而下:广告位 → 章节头 → 标签栏 → 分段的伙伴栅格。广告卡直接复用
   首页推广位的表面 .promo-card(白底 + 16 圆角 + 悬浮抬升),这里只补几何与
   文字层级;章节头借精选分区的 .feat-title / .feat-rule 一套字号,标签的选中态
   复用侧栏 .cat-item.is-active 的渐变 + 蓝影,都不另造。 */
/* 42 张同规格白卡浮在纯平底色上会读成「没排完」,铺一层极淡的品牌径向晕染当衬底
   (配方与结算页 / .reviews-band / .footer::before 同族)。 */
.page[data-view="partners"] {
  background:
    radial-gradient(1120px 560px at 50% 120px, rgba(46, 124, 255, .07), transparent 62%),
    #F4F7FC;
}
/* 高度只由 .pa-main 一处说话:右侧两块靠 stretch 跟随(同 .promo-side 的做法),
   小卡因此恒为 (208-14)/2 = 97,改高度只改这一个数。 */
.pa-ads { display: grid; grid-template-columns: 1.7fr 1fr 1fr; gap: 14px; align-items: stretch; }
.pa-col { display: grid; grid-template-rows: 1fr 1fr; gap: 14px; }
.pa-main { height: 208px; }

.pa-card {
  box-sizing: border-box; padding: 0 26px;
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 10px;
}
/* 光环取 .pm-ring 的配方(圆 + 一圈很厚的半透明白描边),让大卡不只是一块渐变。
   尺寸按卡高等比缩过:.pm-ring 是 320 圆 / 44 描边配 416 高的主推卡,这里卡只有
   208 高,照抄那个尺寸弧线会横穿标题。z-index 分层也是必需的 —— 伪元素算最后一个
   子节点,不分层会盖在文字上。 */
.pa-main::after {
  content: ''; position: absolute; right: -56px; bottom: -84px; z-index: 0;
  width: 200px; height: 200px; border-radius: 50%;
  border: 30px solid rgba(255, 255, 255, .08); pointer-events: none;
}
.pa-card .pm-kicker { position: relative; z-index: 1; }
/* 铺真实广告图时整卡盖满,底下的渐变与文字都不再出现 */
.pad-img { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; object-fit: cover; display: block; }
.pad-title {
  position: relative; z-index: 1; font-size: 27px; line-height: 33px; font-weight: 700; color: #ffffff;
  text-shadow: 0 2px 14px rgba(9, 22, 60, .35);
}
.pad-sub { position: relative; z-index: 1; font-size: 14px; line-height: 18px; color: rgba(255, 255, 255, .78); }
.pad-cta {
  position: relative; z-index: 1; margin-top: 4px;
  height: 34px; padding: 0 15px; border-radius: 999px; box-sizing: border-box;
  display: inline-flex; align-items: center; gap: 7px;
  background: rgba(255, 255, 255, .16); border: 1px solid rgba(255, 255, 255, .34);
  color: #ffffff; font-size: 14px; font-weight: 700;
  transition: background .2s ease, border-color .2s ease;
}
.pa-card:hover .pad-cta { background: rgba(255, 255, 255, .26); border-color: rgba(255, 255, 255, .5); }
.pa-sm { padding: 0 20px; gap: 7px; }
.pa-sm .pad-title { font-size: 18px; line-height: 23px; }
.pa-sm .pad-sub { font-size: 13px; line-height: 17px; }

/* 章节头:与精选分区同一套字号,下面接同一条 .feat-rule —— 这页因此读作站内的
   一个分区而不是另一个站。左块两行,所以按 .reviews-head 那样底对齐。 */
.pa-head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 16px;
  margin-top: 40px;
}
.pa-title { margin: 0; font-size: 30px; line-height: 38px; font-weight: 700; color: #0C1626; }
.pa-sub { margin: 10px 0 0; font-size: 14px; color: rgba(30, 50, 80, .7); }
.pa-more {
  flex: none; display: inline-flex; align-items: center; gap: 7px;
  font-size: 14px; font-weight: 600; color: #1B6BFF;
}
.pa-more:hover { color: #0A56C8; }

.pa-tabs { display: flex; flex-wrap: wrap; gap: 8px; padding: 22px 0 0; }
.pa-tab {
  height: 34px; padding: 0 16px; border-radius: 999px; box-sizing: border-box;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .1);
  color: #23324A; font-size: 14px; font-weight: 500;
  display: inline-flex; align-items: center;
  transition: border-color .2s ease, color .2s ease, transform .2s var(--ease-out);
}
.pa-tab:hover { border-color: rgba(27, 107, 255, .55); color: #1B6BFF; transform: translateY(-1px); }
.pa-tab.is-active {
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8); border-color: transparent;
  color: #ffffff; font-weight: 700;
  box-shadow: 0 8px 20px rgba(37, 99, 235, .32), inset 0 1px 0 rgba(255, 255, 255, .22);
}
.pa-tab.is-active:hover { transform: none; }

/* 分段那一套(`.pa-sec` / `-head` / `-title` / `-num` / `-rule` / `-more`)2026-08-04
   照参考站整块删净,不是漏写 —— 见 js 里 renderPartnerGrid 那段。栅格的上边距
   由这里接住:旧版靠 `.pa-sec { margin-top: 26px }` 撑开,段落没了要写在栅格自己身上。 */

/* 三列(伙伴简介要两三行,四列会把行宽压到读不下去);min-height 116 让简介
   一行与三行的卡片同高,栅格不会长短不齐。
   列数与「每组 6 家」是一套:3 列 × 2 行正好排满,改任一边都会在右下角留缺口
   (「全部标签」下 42 家 = 3 × 14 行,同样排满)。
   `margin-top` 是旧版 `.pa-sec` 那 26 挪过来的:段落删掉后没人撑开标签行与栅格之间的空。 */
.pa-grid { margin-top: 26px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.pa-item {
  position: relative; overflow: hidden;
  box-sizing: border-box; min-height: 116px; padding: 20px 22px; border-radius: 14px;
  display: flex; align-items: center; gap: 16px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .07);
  box-shadow: 0 8px 24px rgba(13, 38, 90, .07);
  transition: transform .25s var(--ease-out), box-shadow .25s ease;
}
/* 伙伴卡是 <div> 而不是链接(站外品牌,站内没有落点,见 main.js 的 partnerCard)。
   所以这里不再给 hover 抬起与顶边展开 —— 抬起是「这张能点」的信号,挂在点不动的
   卡片上就是骗人。焦点环也一并去掉:div 不进 Tab 序列,那条规则永远不会命中。 */
/* 顶边渐变线常驻(原本是 hover 才从左展开)。白卡片密排仍然需要一条分隔的重音,
   但它不能再跟着鼠标走 —— 那是可点击的信号。 */
.pa-item::before {
  content: ''; position: absolute; left: 0; top: 0; width: 100%; height: 2px;
  background: linear-gradient(90deg, #2E7CFF, #8B5CFF);
}
.pa-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.pa-name { font-size: 16px; line-height: 20px; font-weight: 700; color: #0C1626; }
/* max-height 是 3 行的整数倍(3 × 20),跟着 line-height 走 —— 差一点就会把第 3 行切在半腰上 */
.pa-desc {
  font-size: 14px; line-height: 20px; max-height: 60px; overflow: hidden;
  color: rgba(30, 50, 80, .7); text-wrap: pretty;
}
.pa-logo {
  flex: none; width: 56px; height: 56px; border-radius: 15px; box-sizing: border-box;
  background: rgba(13, 38, 90, .04); border: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: center; justify-content: center;
}
.pa-logo img { width: 28px; height: 28px; object-fit: contain; display: block; }

/* ── 说明页(页脚三列)────────────────────────────────────────────
   单列正文,全宽,无左导航(2026-07-30 按用户要求移除,换页走页脚三列的链接)。
   正文面板是 .pdp-panel 的表面(白底 + 18 圆角 + 浅影),行宽放到 760 以内 ——
   条款读的是长句,行太长会跳行。
   本页为新代码,金额一律 $(USD)。 */
/* 常见问题页的面包屑与说明页同形(第二格是不可点的分组名「服务支持」) */
.info-view .crumb span,
.faq-view .crumb span { font-size: 14px; color: rgba(30, 50, 80, .7); }
.info-title { margin: 0; font-size: 30px; line-height: 38px; font-weight: 700; color: #0C1626; }
.info-lead {
  margin: 12px 0 0; max-width: 820px;
  font-size: 15px; line-height: 1.75; color: rgba(20, 35, 60, .7); text-wrap: pretty;
}
.info-panel {
  margin-top: 18px; box-sizing: border-box; padding: 30px 34px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05); border-radius: 18px;
}
.info-sec + .info-sec { margin-top: 26px; padding-top: 26px; border-top: 1px solid rgba(13, 38, 90, .07); }
.info-h { margin: 0 0 12px; font-size: 17px; line-height: 22px; font-weight: 700; color: #0C1626; }
.info-panel p, .info-panel li {
  font-size: 14px; line-height: 1.9; color: rgba(20, 35, 60, .8);
  text-wrap: pretty; max-width: 760px;
}
.info-panel p { margin: 0 0 14px; }
.info-panel ul { margin: 0; padding-left: 20px; }
.info-panel ol { margin: 0; padding-left: 22px; }
.info-panel ol li::marker { font-weight: 700; color: #1B5FE8; }
.info-panel li { margin-bottom: 4px; }
.info-panel li::marker { color: rgba(27, 107, 255, .45); }
.info-sec > :last-child { margin-bottom: 0; }

/* 卡片栅格:两列(卡里有 2–3 行说明,三列会把行宽压到读不下去);
   表面复用 .pa-item 的白卡观感,只有链接卡抬起,信息卡不动。 */
/* 跟着正文的 760 行宽收边:面板去掉左导航后是 1366 通宽,不限宽的话两列卡片
   会各拉到 642px、说明文字只占一行,右半边全空,和 760 的正文脊错开一大截。 */
.info-cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; max-width: 760px; }
.info-card {
  box-sizing: border-box; padding: 16px 18px; border-radius: 16px;
  display: flex; flex-direction: column; gap: 5px;
  background: rgba(13, 38, 90, .025); border: 1px solid rgba(13, 38, 90, .08);
}
.info-card.is-link { transition: transform .15s var(--ease-out), box-shadow .15s ease, border-color .2s ease; }
.info-card.is-link:hover {
  transform: translateY(-3px); border-color: rgba(46, 124, 255, .45);
  box-shadow: 0 16px 36px rgba(13, 38, 90, .1); background: #ffffff;
}
.info-card-name { font-size: 15px; line-height: 20px; font-weight: 700; color: #0C1626; }
.info-card-val { font-size: 14px; line-height: 19px; font-weight: 600; color: #1B5FE8; word-break: break-all; }
.info-card-sub { font-size: 14px; line-height: 20px; color: rgba(30, 50, 80, .7); text-wrap: pretty; }
.info-card-go {
  margin-top: 3px; display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; font-weight: 700; color: #1B6BFF;
}
.info-card-go svg { display: block; transition: transform .2s var(--ease-out); }
.info-card.is-link:hover .info-card-go svg { transform: translateX(3px); }

/* 折叠问答用原生 <details>:去掉默认三角,收起态只留问题行 */
/* 同样收进 760:不限宽的话行下划线拉满 1296,折叠箭头被推到面板最右端,
   与问题文字隔开一千多 px。分节线(.info-sec 之间那条)通宽是有意的,不要一起收。 */
.info-qa { border-bottom: 1px solid rgba(13, 38, 90, .07); max-width: 760px; }
.info-qa:last-child { border-bottom: none; }
.info-q {
  padding: 13px 0; cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 12px;
  font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626;
  transition: color .2s ease;
}
.info-q::-webkit-details-marker { display: none; }
.info-q:hover { color: #1B6BFF; }
.info-caret { margin-left: auto; flex: none; display: block; transition: transform .2s var(--ease-out); }
.info-qa[open] .info-caret { transform: rotate(180deg); }
.info-a { margin: 0 0 15px; padding-right: 24px; }
/* 展开 / 收起跟着箭头一起走 .2s(与报价页左栏那组折叠同一个数)。原来箭头转 .2s、
   答案 0ms 就蹦出来,是同一个动作的两种速度。
   全靠 ::details-content 做,**不接管 <details> 的开合** —— 拦 summary 的点击再
   自己 toggle open,就把原生白送的键盘操作、Ctrl+F 展开、无障碍语义一并接了过来,
   而这一段的价值只是那 200ms。渲染那边那句「折叠用原生 details:不需要事件处理」
   因此仍然成立,别为了动画去加 JS。
   两个细节:
   ① 0 → auto 默认不可插值,所以终点写 calc-size(auto, size)。也可以在 :root 开
      interpolate-size: allow-keywords,但那是全站开关,为一个组件不值得;
   ② content-visibility 必须带 allow-discrete 一起过渡 —— 不带的话收起瞬间内容
      直接不渲染,那 .2s 就成了一个空盒子在压扁。
   overflow:hidden 顺带建了 BFC,.info-a 的下外边距因此算进内容高、跟着一起收。 */
.info-qa::details-content {
  block-size: 0; overflow: hidden;
  transition: block-size .2s var(--ease-out), content-visibility .2s allow-discrete;
}
.info-qa[open]::details-content { block-size: calc-size(auto, size); }
/* 高度动画属于位移那一类,减弱动效时停掉。单写一条而不是并进文件顶部那个选择器组:
   ::details-content 万一在某个浏览器里不认,整组选择器会一起失效(逗号列表里有一个
   非法选择器就废掉整条),那条规则可比这个动画要紧。放在这里则最多是这一条被丢掉,
   而那时动画本来也不存在。 */
@media (prefers-reduced-motion: reduce) {
  .info-qa::details-content { transition: none; }
}

/* ── 商品报价页(多商家)────────────────────────────────────────
   左筛选栏没有卡片外壳(也不吸顶),直接坐在页底色上;组标签与 .co-label 同一套
   (14/20/600 近黑、无字距,见「组标签全站一个样」),勾选框复用 .co-check。
   报价卡的白底 + .08 边框 + 阴影与站内其它卡同一套 —— 曾经参照的那张中密度
   .prod-card 已于 2026-07-31 随「列表层一律用 featCard」删净,别再照它找。
   本页为新代码,金额一律 $(USD)。 */
.offers-view .crumb { padding-bottom: 4px; }
/* 左右不留内边距:这 2px 曾是全页唯一的缩进,让页头行里的商品图标(34)与 ‹返回 /
   排序(1332)各自偏离面包屑、左栏与报价栅格的 32 / 1334 那条脊 —— 读起来就是"没对齐"。 */
.off-head { display: flex; align-items: center; gap: 16px; padding: 6px 0 18px; }
.off-head h2 { margin: 0; font-size: 30px; line-height: 38px; font-weight: 700; color: #0C1626; }
.off-head-meta { min-width: 0; display: flex; flex-direction: column; gap: 8px; }
/* 页头是全页最大的品牌位,而 .prod-letter 的 17px 是照商品卡抄来的:56 的框里只占 39%
   高(有图的商品是 32/56 = 57%),字母型商品的图标因此显得发飘。框不动 —— 60 高正好
   与右侧「标题 34 + gap 8 + 副标 18」两行齐平,放大反而站不住。 */
.off-head .prod-letter { font-size: 22px; letter-spacing: .01em; }

/* 已选条件:横跨整行坐在栅格与左栏之上,所以两列一起下移、齐平不破。
   只在有条件时出现([hidden] 生效需要它自己不是 display:flex —— 这里靠
   下面那条显式规则兜住,同站内其它靠 hidden 切换的 flex 元素。 */
.off-chips {
  margin: 16px 0 0; display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
}
.off-chips[hidden] { display: none; }
.off-chips-label {
  font-size: 13px; font-weight: 700; color: rgba(30, 50, 80, .7);
}
.off-chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 10px; border-radius: 999px;
  background: rgba(27, 107, 255, .08); border: 1px solid rgba(27, 107, 255, .25);
  color: #1B5FE8; font-size: 13px; font-weight: 600; cursor: pointer;
  transition: background-color .2s ease, border-color .2s ease;
}
.off-chip:hover { background: rgba(27, 107, 255, .14); border-color: rgba(27, 107, 255, .5); }
.off-chip:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.off-chip svg { flex: none; display: block; opacity: .7; }
.off-chip-clear {
  height: 28px; padding: 0 4px; border: none; background: transparent;
  color: rgba(30, 50, 80, .7); font-size: 13px; font-weight: 600; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.off-chip-clear:hover { color: #1B5FE8; }
.off-chip-clear:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }

.off-main { display: flex; gap: 16px; align-items: flex-start; }
/* 左栏没有卡片外壳:透明底、无边框、无阴影,整条直接坐在页底色上,组与组之间
   只靠 .off-sec 那条淡分隔线断开。旧版是一张 960 高的白卡,那条竖直硬边界从页头
   一路划到页尾、把内容区切成两半 —— 用户报的「边界太清晰、有割裂感」就是它。
   参考站(GamsGo 报价页)同样是无壳左栏 + 浮起的白卡列表:轻的那边融进背景,
   重的那边才是主体。padding 右 16 是留给栅格的呼吸位(内容右缘 266 → 卡 298 共 32),
   左 0 让筛选组标题与面包屑 / 页头 h2 落在同一条 34 的左脊上。
   宽度仍是 248,所以 .off-list-wrap 的 298 与卡宽 357 一点没动、顶部齐平不破。 */
.off-rail {
  flex: none; width: 248px; box-sizing: border-box;
  padding: 0 16px 0 0;
}
/* 左栏不吸顶、不设自己的滚动条:全部筛选组默认展开,整条随页面一起滚。
   这三件事是一套的 —— 旧版 sticky + max-height + overflow-y:auto 里,
   单去掉内滚动条会让高于视口的左栏(影音 7 组 850px vs 视口约 736px)底部
   被永久钉在屏幕外、翻页也够不着,比有滚动条更糟。要缩短用组标题上的折叠箭头。 */
.off-sec + .off-sec { margin-top: 18px; padding-top: 18px; border-top: 1px solid rgba(13, 38, 90, .07); }
/* 组标题是小标题、不是 eyebrow 标签(2026-08-01 按用户「参考这个字体类型、间距和大小」,
   对的是 GamsGo 报价页左栏):14/20 的 600 近黑,没有字距。旧版是 12/16 的 700 灰字 +
   .1em 字距 —— 那套参数是给全大写英文标签用的,套在「卖家在线状态」这种中文上,
   字被字距推散、颜色又退到 55%,读起来是一行说明文字而不是一组筛选的名字。
   深色也是有意的:标题(近黑) > 选项(#23324A) > 计数(70%)三级,同参考站。 */
.off-label {
  display: block; font-size: 14px; line-height: 20px; font-weight: 600;
  color: #0C1626;
}
/* 勾选组的可折叠标题:整条是按钮,但视觉上与不可折叠的 .off-label 完全一致
   (同字号同字重同颜色),只在右端多一个箭头 —— 两种标题混排时不能有两种观感。
   箭头是 currentColor,所以颜色跟着这里走。 */
.off-head-btn {
  width: 100%; padding: 0; border: none; background: transparent; cursor: pointer;
  font-family: inherit; display: flex; align-items: center; gap: 8px;
  color: #0C1626;
}
.off-head-btn:hover { color: #1B5FE8; }
.off-head-btn:hover .off-label { color: inherit; }
.off-caret { margin-left: auto; flex: none; display: block; transition: transform .2s var(--ease-out); }
.off-sec.is-shut .off-caret { transform: rotate(-90deg); }
/* 折叠走 grid 的 1fr → 0fr,不再是 display:none —— 箭头滑 .2s 而行 0ms 就没了,
   是同一个动作的两种速度。左栏最高 1151(影音 8 组),收起一组页面跳得厉害,
   这 .2s 是给用户跟住位置用的。几何上有三处坑,改之前先看 .off-rows-in 那条注释。
   收完还要 visibility:hidden(延到动画走完再落),否则被压成 0 高的那些行
   还留在 Tab 序里 —— 剪掉看不见 ≠ 摸不到,这一条是 display:none 本来白送的。 */
.off-sec.is-shut .off-rows { grid-template-rows: 0fr; margin-top: 0; }
.off-sec.is-shut .off-rows-in { visibility: hidden; transition: visibility 0s .2s; }
.off-field {
  margin-top: 10px; height: 42px; box-sizing: border-box;
  background: rgba(13, 38, 90, .05);
  border: 1px solid rgba(13, 38, 90, .1);
  border-radius: 10px; padding: 0 11px;
  display: flex; align-items: center; gap: 8px;
  transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.off-field:focus-within {
  border-color: rgba(27, 107, 255, .6);
  box-shadow: 0 0 0 4px rgba(46, 124, 255, .14);
  background: #ffffff;
}
.off-field svg { flex: none; display: block; }
.off-field input {
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font-size: 14px; line-height: 18px; color: #0C1626;
}
.off-range { margin-top: 10px; display: flex; align-items: center; gap: 8px; }
.off-range .off-field { margin-top: 0; flex: 1; min-width: 0; padding: 0 10px; }
.off-range i { flex: none; font-style: normal; font-size: 13px; color: rgba(30, 50, 80, .35); }

/* 0fr 要压得下去,被压的必须是**单个**子元素、且它自己带 overflow:hidden
   与 min-height:0,所以这里多包了一层 .off-rows-in。两处几何都反直觉:

   ① 内层的 `padding: 6px` 与 `margin: -6px` 四边严格对消,一个数都不能单独动。
      要 padding 是因为 overflow:hidden 会剪掉两样东西:.off-row 的 hover 块
      左右各溢出的 6(见它自己的注释),和首行 / 末行 :focus-visible 那圈描边
      (2 描边 + 2 offset)。留出 6 的可视区,这两样就都落在自己的内边距里。
      而负外边距把这 12 又还回去,所以**展开时**外缘一点没变(行仍是 28–272、
      内容仍是 34–266)、**收起时**也不会留下 12px 的空壳 —— padding 是不跟着
      0fr 压缩的,只有这个对消能让残留归零(第一版写成 8/6 不对称,实测每个
      收起的组多出 8px)。
   ② 组的上间距 8 留在外层 .off-rows 的 margin 上,并且跟着一起过渡到 0。
      放进内层当 padding 同样会变成残留(理由同上);不过渡则是收起的瞬间
      先跳掉 8px 再开始压,一次折叠看得出两段。

   动这一块之后先量三个数:行的左右缘(28 / 272)、组间距(18)、
   收起前后左栏高度差(应当**正好**等于那几行的高度,多一点少一点都是残留)。 */
.off-rows {
  margin-top: 8px; display: grid; grid-template-rows: 1fr;
  transition: grid-template-rows .2s var(--ease-out), margin-top .2s var(--ease-out);
}
.off-rows-in {
  min-height: 0; overflow: hidden; visibility: visible;
  padding: 6px; margin: -6px;
  display: flex; flex-direction: column; gap: 1px;
}
/* hover 块靠负 margin 向两侧各伸出 6px,行内容因此严格落在 34–266 这条内容区里:
   勾选框与组标题、搜索框左缘齐,右端计数与搜索框右缘齐。直接写 padding 的话
   整行会比标题缩进 6px、计数又比搜索框短 6px,没有壳的左栏里一眼看得出。 */
.off-row {
  width: calc(100% + 12px); margin: 0 -6px; height: 32px; padding: 0 6px;
  box-sizing: border-box;
  border: none; border-radius: 8px; background: transparent; font-family: inherit;
  color: #23324A; font-size: 14px; font-weight: 500; cursor: pointer;
  display: flex; align-items: center; gap: 10px;
  transition: background-color .2s ease;
}
.off-row:hover { background: rgba(27, 107, 255, .06); }
/* 计数为 0 的行**与正常行一模一样,照给 hover 与手型**(2026-08-04 按用户要求;
   2026-08-03 的禁用态 `.off-row.is-void` 四条 CSS 与 js 里的 `disabled` 一并删净,
   不是漏写)。「这一档没货」改由行尾那个**空位**来说 —— 见 js 里 row() 那段。 */
.off-row .co-check { pointer-events: none; }
.off-row-label { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 计数比选项小一号,但 α 不跟着参考站压浅:.55 在页底色上只有 3.4:1,
   同报价卡已售那条(.45 判为读不出后提到 .7)。层级靠字号拉开就够。 */
.off-row i { margin-left: auto; font-style: normal; font-size: 13px; color: rgba(30, 50, 80, .7); }
.off-reset {
  margin-top: 18px; width: 100%; height: 40px; box-sizing: border-box;
  border: 1px solid rgba(13, 38, 90, .14); border-radius: 10px; background: #ffffff;
  font-family: inherit; color: #23324A; font-size: 14px; font-weight: 500; cursor: pointer;
  transition: border-color .2s ease, color .2s ease;
}
.off-reset:hover { border-color: rgba(27, 107, 255, .55); color: #1B6BFF; }

.off-list-wrap { flex: 1; min-width: 0; }
/* 工具栏坐在页头行右端而不是栅格上方:栅格顶因此与 .off-rail 顶齐平。
   margin-left:auto 推到最右,flex:none 保证长标题不会把它压扁。
   align-self 覆盖掉 .off-head 的 align-items:center —— 那条是给 60 方图与右侧两行文字
   用的,工具栏跟着一起居中的话中心线正好落进标题(242–280)与副标(288–306)之间那 8px
   缝里,与哪一行都不共基线,看着就是悬空。改成与 h2 共中心(244–278),仍在页头内容框
   242–306 内,所以页头高度不变、栅格顶的 324 不破。别改成与副标共线:那样底边到 314,
   会把页头撑到 332,齐平当场就没了。 */
.off-toolbar {
  margin-left: auto; align-self: flex-start; margin-top: 2px;
  flex: none; display: flex; align-items: center; gap: 12px;
}
.off-count { font-size: 14px; color: rgba(30, 50, 80, .7); text-align: right; }
/* 下拉自绘:appearance:none 去掉 Chrome 原生箭头,右侧 caret 复用左栏折叠那枚 —— 这是
   报价页唯一一个 select,留着原生外观就是全页唯一一个不属于站内那套表面的控件。
   宽度由最宽的选项(「价格最低」)决定、不随选中项变,所以换排序方式框不会跳。选项文案
   一律压到 4 字以内(2026-08-01):框里显示的「推荐」只有 28px,而框按最长的那条撑到
   128,右边空着一大片。评分 / 好评率 / 销量 去掉「最高」不丢信息 —— 这三项只有降序
   一个方向,同淘宝那排「综合 / 销量 / 价格」;价格两个方向都要,所以留着「最低 / 最高」。 */
.off-sort { position: relative; flex: none; display: flex; align-items: center; }
.off-sort select {
  appearance: none; -webkit-appearance: none;
  height: 34px; padding: 0 30px 0 12px; border-radius: 10px; box-sizing: border-box;
  border: 1px solid rgba(13, 38, 90, .14); background: #ffffff;
  font-family: inherit; font-size: 14px; font-weight: 500; color: #23324A; cursor: pointer;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.off-sort select:hover { border-color: rgba(27, 107, 255, .55); }
.off-sort select:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.off-sort .sel-caret { right: 11px; }

/* 3 列:92 件商品里 75 件正好 3 条报价(4 条的 10 件、2 条的 7 件),一排放完不用往下翻。
   4 列不做 —— 没有商品超过 4 条报价,而 246 宽的卡装不下卖家行(名字 + 认证 + 好评率)。
   卡上现在没有徽章行,标题下也没有文案行:标题 → 卖家 → 评分 → 价格四行到底。 */
.offer-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
/* 内边距 18 与站内其它卡对齐(.feat-card 的 .fcard-top 20/18、.sl-perk 22)——
   报价卡原本是全站唯一的 14,内容顶到边上,与相邻区块读起来不是一套 */
.offer-card {
  display: flex; flex-direction: column; box-sizing: border-box; padding: 18px;
  border-radius: 16px; background: #ffffff;
  border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  transition: transform .15s var(--ease-out), border-color .15s ease, box-shadow .15s ease;
}
.offer-card:hover {
  transform: translateY(-3px);
  border-color: rgba(27, 107, 255, .45);
  box-shadow: 0 18px 40px rgba(13, 38, 90, .13);
}
.offer-card:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 3px; }
/* 上半区:左边两级文字 + 右边一张方图。图是这张卡唯一的图形锚点,
   一排三张能凭它一眼认出是同一个商品的三家报价。 */
.offer-head { display: flex; align-items: flex-start; gap: 12px; }
.offer-head-txt { flex: 1; min-width: 0; }
.offer-thumb {
  flex: none; width: 62px; height: 62px; border-radius: 15px;
  display: flex; align-items: center; justify-content: center;
}
.offer-thumb img { width: 34px; height: 34px; object-fit: contain; display: block; }
.offer-letter { font-size: 18px; font-weight: 700; color: #123A8F; }
/* 档位是主标题:几条报价之间唯一可直接比的东西,一行放不下就截断 */
.offer-spec {
  display: block; font-size: 14px; line-height: 19px; font-weight: 700; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 商家自己写的标题退成灰色副标题,钉死两行 —— 长短不一时下面的卖家行才不会错开。
   `text-wrap: pretty` 与 .fcard-name / .pdp-title 同一条:不加会把最后一个字
   甩到第二行独占一行(实测「…长期稳 / 定」),三张卡并排时那个孤字最扎眼。 */
.offer-title {
  display: -webkit-box; margin-top: 5px; min-height: 36px;
  font-size: 13px; line-height: 18px; font-weight: 500; color: rgba(30, 50, 80, .7);
  -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; text-wrap: pretty;
}
.offer-seller { margin-top: 14px; display: flex; align-items: center; gap: 6px; }
/* 好评率贴右端(参考站同款:蓝色拇指 + 百分比 + 灰色评价数) */
.offer-like {
  margin-left: auto; display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; font-weight: 700; color: #1B6BFF; white-space: nowrap;
}
.offer-like svg { flex: none; display: block; }
.offer-like i { font-style: normal; font-weight: 500; color: rgba(30, 50, 80, .7); }
/* 本机商家的新报价:likes 为 null 时这一格印「新店」(见 offerCard)。
   退成中灰 600 —— 它是状态说明不是口碑数字,蓝色 700 会读成一个可点的东西。 */
.offer-like-new { color: rgba(30, 50, 80, .7); font-weight: 600; }
/* 价格行的右端配重:只有已售,同号同色,不与价格抢。
   α 从 .45 提到 .7:已售是排序下拉的键,「排序键必须在卡上看得见」这条
   规矩要成立,它得先读得出来(.45 在白底上只有 2.55:1)。字号与权重不动。 */
.offer-meta {
  margin-left: auto;
  font-size: 12px; line-height: 15px; color: rgba(30, 50, 80, .7); white-space: nowrap;
}
/* 与 .fcard-foot 同构:居中对齐、价格用站内卡片的 22 —— 26 是全站最大的卡片价格,
   比首页主推卡还大一档,单看没问题,和相邻区块摆一起就不是一套字号了。
   「选购」按参考站去掉:整张卡本来就是一个 <a>,hover 抬升已经说明它能点,
   右端让给评分与已售当配重。 */
.offer-foot {
  margin-top: auto; padding-top: 14px;
  border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: center;
}
.off-empty { grid-column: 1 / -1; padding: 56px 0; text-align: center; font-size: 14px; color: rgba(30, 50, 80, .7); }
.off-empty button {
  border: none; background: none; padding: 0; font-family: inherit;
  font-size: 14px; font-weight: 600; color: #1B5FE8; cursor: pointer;
}
.off-empty button:hover { color: #0A56C8; }

/* ── 热门商品(深色区)───────────────────────────────────────────
   面板左右必须落在 1366 脊线上 —— banner、侧栏+内容、精选网格全在这条
   线上,这块曾用 margin-inline:-32px 外扩,是全页唯一越过脊线的块,
   加上 0 圆角,读起来像贴上去的补丁。内容退让改由 .hot-inner 的内边距
   承担,别再把外扩加回来。
   圆角 + 柔光 + 落地投影:深浅交界要有过渡带,不能是一条死线;柔光把
   周围浅色底染上一点深块的颜色,与 .reviews-band 的品牌晕染同族。 */
.hot {
  position: relative; margin-top: 76px; overflow: hidden;
  border-radius: 24px;
  box-shadow:
    0 0 64px rgba(24, 22, 62, .22),
    0 28px 64px -16px rgba(24, 22, 62, .42),
    inset 0 1px 0 rgba(255, 255, 255, .10);
  background:
    radial-gradient(1000px 560px at 10% -10%, rgba(58, 90, 255, .38), transparent 60%),
    radial-gradient(820px 520px at 92% 8%, rgba(139, 60, 255, .32), transparent 58%),
    radial-gradient(900px 600px at 82% 105%, rgba(244, 63, 94, .28), transparent 60%),
    radial-gradient(700px 460px at 6% 100%, rgba(14, 159, 216, .22), transparent 58%),
    linear-gradient(165deg, #151233 0%, #0B0F24 48%, #0A0E1E 100%);
}
.hot-grid-lines {
  position: absolute; inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(900px 500px at 50% 0%, rgba(0, 0, 0, .85), transparent 78%);
  -webkit-mask-image: radial-gradient(900px 500px at 50% 0%, rgba(0, 0, 0, .85), transparent 78%);
}
.hot-orb { position: absolute; border-radius: 50%; filter: blur(10px); }
.hot-orb-blue {
  left: -120px; top: -160px; width: 420px; height: 420px;
  background: radial-gradient(circle, rgba(90, 120, 255, .35), transparent 70%);
}
.hot-orb-red {
  right: -140px; bottom: -180px; width: 460px; height: 460px;
  background: radial-gradient(circle, rgba(244, 63, 94, .28), transparent 70%);
}
/* 36px 横向内边距与 .ad-banner 同值 —— 全站两块深色面板共用一个退让量 */
.hot-inner { position: relative; padding: 56px 36px 62px; }
.hot-head { display: flex; align-items: flex-end; gap: 18px; flex-wrap: wrap; }
.hot-title { margin: 0; font-size: 30px; line-height: 36px; font-weight: 700; color: #ffffff; }
.hot-sub { margin-top: 9px; font-size: 14px; color: rgba(200, 215, 240, .58); }
.hot-tabs { margin-left: auto; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.hot-tab {
  height: 32px; padding: 0 16px; border-radius: 999px;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .16);
  color: rgba(206, 222, 248, .78); font-size: 13px; font-weight: 600;
  display: inline-flex; align-items: center;
  transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.hot-tab:hover { border-color: rgba(255, 255, 255, .45); color: #ffffff; background: rgba(255, 255, 255, .12); }
.hot-tab.is-active {
  background: #ffffff; border: none; color: #0B0F1A; font-weight: 700;
  box-shadow: 0 8px 18px rgba(0, 0, 0, .35);
}
.hot-tab.is-active:hover { color: #0B0F1A; }
.hot a:focus-visible { outline-color: #4D8BFF; outline-offset: 3px; }

.hot-list { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 30px; }
.hot-card {
  display: flex; flex-direction: column; border-radius: 14px; overflow: hidden;
  background: #ffffff; box-shadow: 0 16px 36px rgba(10, 8, 40, .42);
  transition: transform .15s var(--ease-out), box-shadow .15s ease;
}
.hot-card:hover { transform: translateY(-3px); box-shadow: 0 26px 54px rgba(10, 8, 40, .58); }
.hcard-top {
  position: relative; display: flex; align-items: center; gap: 14px;
  padding: 20px 18px; min-height: 134px; box-sizing: border-box;
}
.hcard-top::before {
  content: ""; position: absolute; right: -22px; top: -24px;
  width: 104px; height: 104px; border-radius: 50%;
  background: rgba(255, 255, 255, .09);
}
.hcard-rank {
  position: absolute; right: 14px; top: 14px; height: 20px; padding: 0 8px;
  border-radius: 999px; background: rgba(0, 0, 0, .28);
  color: rgba(255, 255, 255, .92); font-size: 10px; font-weight: 700; letter-spacing: .06em;
  display: flex; align-items: center;
}
.hcard-ico {
  position: relative; flex: none; width: 64px; height: 64px; border-radius: 16px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 22px rgba(0, 0, 0, .25);
}
.hcard-ico img { width: 34px; height: 34px; object-fit: contain; display: block; }
.hcard-letter { font-size: 17px; font-weight: 700; color: #123A8F; }
.hcard-meta { position: relative; min-width: 0; display: flex; flex-direction: column; gap: 9px; }
/* 两行封顶走 line-clamp 而不是光靠 max-height 裁:后者切在第三行上沿,页面上
   看不出还有没有下文(实测「Blox Fruits LVL 2800 · CYBORG V4 全套 · GOD HUMAN」
   正好三行,末尾那截被裁得干干净净)。市场型商品名是卖家自己挂上来的,长度不可控,
   这类会越来越多。max-height 一并留着 —— 几何不变,clamp 只是补上那个省略号。
   写法同 .offer-title / .sgc-title / .sgc-desc。 */
.hcard-name {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  font-size: 16px; line-height: 20px; max-height: 40px; overflow: hidden;
  font-weight: 700; color: #ffffff; text-shadow: 0 1px 8px rgba(0, 0, 0, .35); text-wrap: pretty;
}
.hcard-tag {
  align-self: flex-start; max-width: 100%; box-sizing: border-box;
  border-radius: 5px; padding: 2px 8px;
  background: rgba(0, 0, 0, .26); color: rgba(255, 255, 255, .9);
  font-size: 12px; line-height: 17px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hcard-foot { padding: 13px 18px; display: flex; align-items: center; background: #ffffff; }
.hcard-foot .prod-flag { margin-left: 10px; }
.hcard-sold { margin-left: auto; font-size: 12px; color: rgba(30, 50, 80, .7); white-space: nowrap; }

/* ── 精选分区 ─────────────────────────────────────────────────── */
.feat-sec { padding-top: 76px; }
.feat-head { display: flex; align-items: baseline; gap: 16px; }
.feat-title { margin: 0; font-size: 30px; line-height: 36px; font-weight: 700; color: #0C1626; }
.feat-more {
  margin-left: auto; display: inline-flex; align-items: center; gap: 7px;
  font-size: 14px; font-weight: 600; color: #1B6BFF;
}
.feat-more:hover { color: #0A56C8; }
.feat-rule {
  height: 1px; margin-top: 18px;
  background: linear-gradient(90deg, rgba(27, 107, 255, .3), rgba(13, 38, 90, .06) 40%, transparent);
}
.feat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 26px; }
.feat-card {
  display: flex; flex-direction: column; border-radius: 14px; overflow: hidden;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .07);
  box-shadow: 0 8px 24px rgba(13, 38, 90, .07);
  transition: transform .15s var(--ease-out), box-shadow .15s ease;
}
/* 抬 3 不抬 5:首页同屏 29 张、分类页一屏 12 张,密集栅格里 5px 的抬升鼠标一划
   就是一片起伏。大卡(推广位 4px / 通栏 2px)那边数量少、面积大,按各自的量不动 */
.feat-card:hover { transform: translateY(-3px); box-shadow: 0 22px 46px rgba(13, 38, 90, .16); }
.feat-card:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 3px; }
/* min-height 112:分类页三排 12 件要在一屏里看完(3 × 163 + 2 × 16 = 521),
   卡片再高一点第三排就会被吸顶头部压掉。名称占两行时内容高 65,
   加 20 上下内边距是 105 < 112,所以高度始终由 min-height 说话,不会顶开。 */
.fcard-top {
  position: relative; display: flex; align-items: center; gap: 14px;
  padding: 20px 18px; min-height: 112px; box-sizing: border-box;
}
.fcard-top::before {
  content: ""; position: absolute; right: -22px; top: -24px;
  width: 104px; height: 104px; border-radius: 50%;
  background: rgba(255, 255, 255, .09);
}
.fcard-ico {
  position: relative; flex: none; width: 62px; height: 62px; border-radius: 16px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 22px rgba(0, 0, 0, .2);
}
.fcard-ico img { width: 33px; height: 33px; object-fit: contain; display: block; }
.fcard-letter { font-size: 17px; font-weight: 700; color: #123A8F; }
.fcard-meta { position: relative; min-width: 0; display: flex; flex-direction: column; gap: 9px; }
/* 两行封顶同 .hcard-name(理由见那条) */
.fcard-name {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  font-size: 16px; line-height: 20px; max-height: 40px; overflow: hidden;
  font-weight: 700; color: #ffffff; text-shadow: 0 1px 8px rgba(0, 0, 0, .32); text-wrap: pretty;
}
.fcard-tag {
  align-self: flex-start; max-width: 100%; box-sizing: border-box;
  border-radius: 5px; padding: 2px 8px;
  background: rgba(0, 0, 0, .26); color: rgba(255, 255, 255, .9);
  /* 全站抬一档时这一行留在 11:12px 下最长的「平台账号 · CDK · 手游代充」在卡宽里放不下,
     ai / 影音 / 办公三个分类页实测各有 1–2 张卡被省略号切掉尾巴。它是卡上最次要的一行
     (类型标签,既不参与搜索也不是筛选项),不值得为它加宽卡片或缩短文案。 */
  font-size: 11px; line-height: 16px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fcard-foot { padding: 12px 18px; display: flex; align-items: center; background: #ffffff; }
.fcard-foot .prod-flag { margin-left: auto; }

/* ── 商品详情页 ───────────────────────────────────────────────── */
/* 面包屑 —— 9 个视图共用(首页与分类页没有)。
   左右不留内边距:这 2px 会让「首页」缩到 34,而同页的正文容器、左栏与栅格都在
   32 / 1334 —— 同 .off-head 那处,读起来就是"没对齐"。 */
.crumb { display: flex; align-items: baseline; gap: 8px; padding: 6px 0 18px; }
.crumb a { font-size: 14px; color: rgba(30, 50, 80, .7); transition: color .2s ease; }
.crumb a:hover { color: #1B5FE8; }
.crumb i { font-style: normal; font-size: 14px; color: rgba(30, 50, 80, .35); }
.crumb b { font-size: 14px; font-weight: 500; color: #23324A; }
/* 「返回对话」:只在从消息中心的 chip 点出来时由 syncCsBack 挂上(说明页 / 常见问题页 /
   订单查询页三处),平时这一行还是干净的三格面包屑。
   **几何与配色整套照 `.msg-link`** —— 去程点的就是那样一枚浅蓝 chip,回程长一个样
   才读得出是原路返回;这也是站内既有表面,没为它新造一种。
   `margin-left:auto` 推到行右端(左边三格是「我在哪」,右端是「回哪去」,两件事);
   面包屑是 baseline 对齐、chip 里的 svg 没有基线,所以单独 `align-self:center`
   (同 `.msg-faq-all` 那条)。箭头是 ARROW_SVG 翻转过来的,别再存一份左箭头常量。 */
.crumb-back {
  /* **上下负 4 是必须的**:chip 28 高、面包屑文字才 20,不吸收掉这 8px 的话
     `.crumb` 会从 44 涨到 52,同一个说明页「带 chip / 不带 chip」两次进来正文
     差 8px。负 margin 只让它在行内溢出、不参与撑高,实测两种态 crumb 恒为 44。 */
  margin: -4px 0 -4px auto; align-self: center;
  display: inline-flex; align-items: center; gap: 5px;
  height: 28px; padding: 0 12px; border-radius: 999px;
  background: rgba(46, 124, 255, .09); color: #1B5FE8;
  font-size: 13px; font-weight: 600;
  transition: background-color .2s var(--ease-out);
}
.crumb-back svg { transform: scaleX(-1); }
.crumb-back:hover { background: rgba(46, 124, 255, .17); color: #1B5FE8; }

/* 两栏:右栏定宽 380,左栏自适应(内容区 1102 → 左 706) */
.pdp-main { display: flex; gap: 16px; align-items: flex-start; }
.pdp-left { flex: 1; min-width: 0; }
/* 吸顶挂在这一层:sticky 的可滑动行程 = 父级高度 − 自身高度,而 .pdp-main 是
   align-items:flex-start,内层包装会被压到与内容等高、行程恒为 0。所以必须挂在
   .pdp-main 的直接 flex 子项上(同 .sidebar 的做法),挂 .pdp-rail-in 不生效。 */
.pdp-rail { flex: none; width: 380px; position: sticky; top: 146px; }

/* 头图 —— .hcard-top 的放大版,渐变同样由 p.grad 内联注入 */
.pdp-hero {
  position: relative; overflow: hidden; box-sizing: border-box;
  min-height: 240px; border-radius: 18px; padding: 34px;
  display: flex; align-items: center; gap: 24px;
  box-shadow: 0 10px 28px rgba(13, 38, 90, .1);
}
.pdp-hero::before {
  content: ""; position: absolute; right: -60px; top: -70px;
  width: 220px; height: 220px; border-radius: 50%;
  background: rgba(255, 255, 255, .09);
}
.pdp-hero > * { position: relative; }
.pdp-ico {
  flex: none; width: 96px; height: 96px; border-radius: 22px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 14px 30px rgba(0, 0, 0, .25);
}
.pdp-ico img { width: 51px; height: 51px; object-fit: contain; display: block; }
.pdp-letter { font-size: 26px; font-weight: 700; color: #123A8F; }

.pdp-id { min-width: 0; display: flex; flex-direction: column; }
.pdp-title {
  margin: 0; font-size: 28px; line-height: 34px; max-height: 68px; overflow: hidden;
  font-weight: 700; color: #ffffff; text-shadow: 0 1px 8px rgba(0, 0, 0, .35); text-wrap: pretty;
}
.pdp-flags { margin-top: 14px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pdp-badge {
  flex: none; height: 24px; padding: 0 12px; border-radius: 999px;
  background: linear-gradient(135deg, #FFB020, #F0700C);
  color: #2A1600; font-size: 11px; font-weight: 700; letter-spacing: .08em;
  display: flex; align-items: center;
}
.pdp-flag {
  flex: none; max-width: 100%; box-sizing: border-box;
  height: 24px; padding: 0 11px; border-radius: 999px;
  background: rgba(255, 255, 255, .14); border: 1px solid rgba(255, 255, 255, .22);
  color: rgba(255, 255, 255, .9); font-size: 12px; line-height: 17px;
  display: flex; align-items: center; gap: 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 这三条现在只服务店铺页头部(入驻 / 在售 / 响应率 / 评分):
   详情页头图那行同名的「已售 / 评价 / 评分」2026-07-31 去重删掉了,别跟着删这里。
   配色随之改成白底上的墨色 —— 原本是配深色头图的白字,而 .shop-head 是白卡,
   这四个数一直是白底白字看不见的(2026-07-31 顺手修) */
.pdp-stats { margin-top: 14px; display: flex; align-items: center; gap: 18px; }
.pdp-stat { font-size: 13px; color: rgba(30, 50, 80, .7); white-space: nowrap; }
.pdp-stat b { font-size: 14px; font-weight: 700; color: #23324A; }

/* 卖家条 —— 头图之后第一块白色表面,深浅对比本身就是分节 */
.pdp-seller {
  margin-top: 14px; box-sizing: border-box; min-height: 76px; padding: 18px 20px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05); border-radius: 16px;
  display: flex; align-items: center; gap: 14px;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.pdp-seller:hover { border-color: rgba(27, 107, 255, .35); box-shadow: 0 16px 36px rgba(13, 38, 90, .1); }
.pdp-shop { min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.pdp-shop-name { display: flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 700; color: #0C1626; }
.pdp-shop-name svg { flex: none; display: block; }
.pdp-shop-sub { font-size: 13px; color: rgba(30, 50, 80, .7); white-space: nowrap; }
.pdp-seller .pdp-rate { margin-left: auto; }
.pdp-seller .head-btn { flex: none; }

/* 星级(支持小数)—— 底层灰星,上层金星按像素宽度裁切 */
.pdp-rate { display: inline-flex; align-items: center; gap: 7px; }
.pdp-stars { position: relative; flex: none; display: inline-flex; gap: 3px; }
.pdp-stars svg { flex: none; display: block; }
.pdp-stars-on {
  position: absolute; left: 0; top: 0; overflow: hidden;
  display: flex; gap: 3px; white-space: nowrap;
}
.pdp-rate b { font-size: 14px; font-weight: 700; color: #0C1626; }

/* ── 充值页:面值栅格 + 同档卖家比价 ──────────────────────────────────
   只在 topup 类目出现(`rec.pricing.topup`)。章节头借 .feat-title 那套关系,
   卡片几何照 .fcard(圆角 16 / 内边距 14 / hover 抬 2),不自立一套。 */
.tp-faces, .tp-sellers { margin-top: 26px; }
.tp-head { display: flex; align-items: baseline; gap: 12px; }
.tp-title { margin: 0; font-size: 18px; line-height: 26px; font-weight: 700; color: #0C1626; }
.tp-sub { font-size: 13px; color: rgba(30, 50, 80, .7); }

/* 5 列 = 参考站的排布;卡宽由容器等分,不写死 —— 左栏 760 与全宽 1366 都要能装 */
.tp-grid { margin-top: 14px; display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; }
.tp-card {
  position: relative; box-sizing: border-box; padding: 10px 10px 12px; cursor: pointer;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .1); border-radius: 16px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  font-variant-numeric: tabular-nums;
  transition: border-color .2s ease, box-shadow .2s ease, transform .2s var(--ease-out);
}
.tp-card:hover { transform: translateY(-2px); border-color: rgba(27, 107, 255, .4); box-shadow: 0 14px 30px rgba(13, 38, 90, .1); }
/* 选中态是 2px 内描边而不是加粗边框:24 张卡并排时,1px→2px 的边框变化会让整行错位 */
.tp-card.is-active { border-color: #1B6BFF; box-shadow: 0 0 0 1px #1B6BFF, 0 14px 30px rgba(27, 107, 255, .16); }
.tp-off {
  position: absolute; top: 0; left: 0; z-index: 1;
  padding: 3px 8px; border-radius: 16px 0 10px 0;
  background: #0E7D45; color: #ffffff; font-size: 12px; line-height: 16px; font-weight: 700;
}
.tp-cover {
  width: 100%; aspect-ratio: 1 / 1; border-radius: 11px; margin-bottom: 8px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  color: #ffffff; text-shadow: 0 2px 10px rgba(0, 0, 0, .35);
}
.tp-cover-kind { font-size: 9px; font-weight: 700; letter-spacing: .18em; opacity: .8; }
/* 面值数字是这张卡唯一的识别物(没有商品图),所以给到 26 —— 与卡上其余字拉开两档 */
.tp-cover-num { font-size: 26px; line-height: 30px; font-weight: 700; }
.tp-cover-unit { font-size: 10px; font-weight: 600; opacity: .85; }
.tp-name { font-size: 13px; line-height: 18px; color: rgba(30, 50, 80, .7); }
.tp-price { font-size: 17px; line-height: 22px; font-weight: 700; color: #E2342E; }
.tp-was { font-size: 12px; color: rgba(30, 50, 80, .7); text-decoration: line-through; }

.tp-rows { margin-top: 14px; display: flex; flex-direction: column; gap: 10px; }
.tp-row {
  box-sizing: border-box; padding: 14px 18px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 14px;
  display: flex; align-items: center; gap: 14px;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.tp-row:hover { border-color: rgba(27, 107, 255, .3); box-shadow: 0 10px 24px rgba(13, 38, 90, .07); }
.tp-row-av { width: 38px; height: 38px; font-size: 14px; flex: none; }
.tp-row-who { display: flex; flex-direction: column; gap: 2px; min-width: 180px; }
.tp-row-name { font-size: 14px; font-weight: 700; color: #0C1626; display: flex; align-items: center; gap: 5px; }
.tp-row-rate { font-size: 12px; color: rgba(30, 50, 80, .7); }
/* 每列自带一行小标题:四家横排时,不标注就分不清 12min 和 $0.75 各是什么 */
.tp-row-col { display: flex; flex-direction: column; gap: 2px; min-width: 120px; font-variant-numeric: tabular-nums; }
.tp-row-col i { font-style: normal; font-size: 12px; color: rgba(30, 50, 80, .7); }
.tp-row-col b { font-size: 14px; font-weight: 700; color: #0C1626; }
.tp-row-col b.is-fast { color: #0E7D45; }
.tp-row-price { margin-left: auto; min-width: 150px; }
.tp-row-price b { font-size: 17px; color: #E2342E; }
.tp-row-cut { display: flex; align-items: center; gap: 7px; }
.tp-row-was { font-size: 12px; color: rgba(30, 50, 80, .7); text-decoration: line-through; }
.tp-row-off { font-size: 12px; font-weight: 700; color: #0E7D45; }
.tp-row-cta {
  flex: none; height: 36px; padding: 0 18px; border-radius: 10px;
  border: 1px solid rgba(27, 107, 255, .5); color: #1B6BFF;
  font-size: 14px; font-weight: 700; display: flex; align-items: center;
  transition: background-color .2s ease, color .2s ease;
}
.tp-row-cta:hover { background: #1B6BFF; color: #ffffff; }

/* 右栏的充值账号输入 */
.tp-uid { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; margin-bottom: 0; }
.tp-uid-in {
  box-sizing: border-box; width: 100%; height: 40px; padding: 0 12px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14); border-radius: 10px;
  font-size: 14px; color: #0C1626; outline: none;
}
.tp-uid-in:focus { border-color: rgba(27, 107, 255, .6); box-shadow: 0 0 0 3px rgba(46, 124, 255, .14); }
.tp-uid-in.is-bad { border-color: rgba(192, 38, 31, .7); box-shadow: 0 0 0 3px rgba(192, 38, 31, .12); }
.buy-was { font-size: 14px; color: rgba(30, 50, 80, .7); text-decoration: line-through; margin-left: 8px; }

/* 内容 tabs —— 形制取自 .nav-tab,选中态取自 .head-btn-promo */
.pdp-tabs { margin-top: 24px; display: flex; align-items: center; gap: 6px; }
.pdp-tab {
  height: 38px; padding: 0 16px; border-radius: 10px; box-sizing: border-box;
  background: transparent; border: 1px solid transparent; font-family: inherit;
  color: rgba(30, 50, 80, .75); font-size: 14px; font-weight: 500; cursor: pointer;
  display: flex; align-items: center; white-space: nowrap;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}
.pdp-tab:hover { background: rgba(13, 38, 90, .06); color: #0C1626; }
.pdp-tab.is-active {
  background: rgba(46, 124, 255, .09); border-color: rgba(46, 124, 255, .35);
  color: #1B5FE8; font-weight: 700;
}
.pdp-tab.is-active:hover { background: rgba(46, 124, 255, .16); border-color: rgba(46, 124, 255, .6); }

.pdp-panel {
  margin-top: 14px; box-sizing: border-box; padding: 28px 30px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05); border-radius: 18px;
}
.pdp-panel h3 { margin: 0 0 12px; font-size: 16px; font-weight: 700; color: #0C1626; }
.pdp-panel p, .pdp-panel li {
  font-size: 14px; line-height: 1.85; color: rgba(20, 35, 60, .8);
  text-wrap: pretty; max-width: 760px;
}
.pdp-panel p { margin: 0 0 16px; }
.pdp-panel ul, .pdp-panel ol { margin: 0; padding-left: 20px; }
.pdp-panel > :last-child { margin-bottom: 0; }
.pdp-panel section + section { margin-top: 24px; padding-top: 24px; border-top: 1px solid rgba(13, 38, 90, .07); }

/* 充值说明的四格(适用平台 / 适用区服 / 所需信息 / 充值结果)。
   两列而不是参考站那样四段纵向堆叠:每格只有一两条,堆起来要滚一屏才看完,
   而这四件是同时要核对的 —— 760 的行宽正好放下两列。 */
.tp-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 24px; max-width: 760px; }
.tp-fact h4 {
  margin: 0 0 6px; font-size: 14px; font-weight: 700; color: #0C1626;
}
.tp-fact ul { padding-left: 18px; }
.tp-fact li { font-size: 14px; line-height: 1.7; }

/* 购买前置声明:同 .pdp-panel 一族的白卡,但不加阴影 —— 它是补充说明,
   跟在正文面板后面再来一层浮起会喧宾夺主。 */
.pdp-terms {
  margin-top: 14px; box-sizing: border-box; padding: 20px 30px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
}
.pdp-terms h3 { margin: 0 0 10px; font-size: 15px; font-weight: 700; color: #0C1626; }
.pdp-terms p {
  margin: 0; font-size: 14px; line-height: 1.85; color: rgba(20, 35, 60, .75);
  text-wrap: pretty; max-width: 760px;
}
.pdp-terms a { color: #1B5FE8; font-weight: 600; }
.pdp-terms a:hover { text-decoration: underline; }

/* ── 购买面板:单价型与规格型共用同一骨架,差异只有 .buy-group ── */
/* 面板的纵向节奏是三档:20(卡内边距)/ 14(分节)/ 10(节内)。
   2026-08-03 从 22 / 18 / 12 收紧一档 —— 顶上多了「订单信息」一节之后,原来那套
   间距把面板撑到 471,价格被推到 152(面板的三分之一处)。分节那 14 是配着
   `.buy-rule` 那条线的:线本身已经在分隔,两侧不必再各留 18。 */
.pdp-buy {
  box-sizing: border-box; padding: 20px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 8px 24px rgba(13, 38, 90, .07); border-radius: 18px;
}
/* .pdp-rail-in 只做「购买面板 + 简版评价整块跟随」的包装,吸顶在 .pdp-rail 上
   (见那条注释):挂在这一层的话 flex-start 会把它压到零行程,永远不动。 */
.buy-head { display: flex; align-items: center; gap: 12px; }
.buy-kind { font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626; }

.buy-price { margin-top: 10px; }
.buy-price .price-cur { font-size: 16px; }
.buy-price .price-num { font-size: 36px; line-height: 40px; }
.buy-unit { font-size: 14px; font-weight: 500; color: rgba(30, 50, 80, .7); margin-left: 3px; }

.buy-meta { margin-top: 10px; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.buy-meta .prod-tag b { font-weight: 700; color: #23324A; }
.buy-rule { height: 1px; margin: 14px 0; background: rgba(13, 38, 90, .07); }

/* 规格组 —— 仅 spec 型商品渲染 */
.buy-group + .buy-group { margin-top: 16px; }
.buy-label { font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626; }
.buy-opts { margin-top: 9px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.buy-opt {
  height: 32px; padding: 0 12px; border-radius: 10px; box-sizing: border-box;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14); font-family: inherit;
  color: #23324A; font-size: 14px; font-weight: 500; cursor: pointer;
  display: flex; align-items: center;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}
.buy-opt:hover { border-color: rgba(27, 107, 255, .55); color: #1B6BFF; }
.buy-opt.is-active {
  background: rgba(46, 124, 255, .09); border-color: rgba(46, 124, 255, .35);
  color: #1B5FE8; font-weight: 700;
}
.buy-opt.is-active:hover { background: rgba(46, 124, 255, .16); border-color: rgba(46, 124, 255, .6); }
/* 与当前其它轴取值不相容:仍可点(会跳到该值的另一组合),但视觉降级 */
.buy-opt[data-soft] { color: rgba(30, 50, 80, .7); border-color: rgba(13, 38, 90, .07); }

/* 两行:标签与步进器并排(标签左、步进器靠 margin-left:auto 顶右),
   「可购 N – M」靠 flex-basis:100% 换到整行。理由见 buyPanelHtml 那段注释 ——
   区间挤在步进器左边时只有 168px,计量型的大数字装不下。 */
.buy-qty { margin-top: 14px; display: flex; flex-wrap: wrap; align-items: center; }
.buy-range { flex-basis: 100%; margin-top: 5px; font-size: 13px; color: rgba(30, 50, 80, .7); }
.buy-stepper {
  margin-left: auto; flex: none; height: 38px; box-sizing: border-box; overflow: hidden;
  border: 1px solid rgba(13, 38, 90, .14); border-radius: 10px;
  display: flex; align-items: center;
}
.buy-step {
  flex: none; width: 36px; height: 36px; padding: 0; font-family: inherit;
  background: transparent; border: none; cursor: pointer;
  color: #23324A; font-size: 15px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  /* transform 也要进过渡表:按压那下要瞬时(:active 里把时长压到 .1s),
     但松手回弹得有一小段,不然抬起来是「啪」的一跳 */
  transition: background-color .2s ease, color .2s ease, transform .2s var(--ease-out);
}
.buy-step:hover { background: rgba(27, 107, 255, .06); color: #1B6BFF; }
.buy-step[disabled], .buy-step[disabled]:hover { background: transparent; color: rgba(30, 50, 80, .55); cursor: not-allowed; }
.buy-num {
  flex: none; width: 66px; height: 36px; box-sizing: border-box;
  border-inline: 1px solid rgba(13, 38, 90, .1);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 700; color: #0C1626;
}

.buy-total {
  margin-top: 14px; padding-top: 14px;
  border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: baseline;
}
.buy-total-label { font-size: 14px; color: rgba(30, 50, 80, .7); }
.buy-total .price { margin-left: auto; }

/* CTA 排在保障说明之前:面板吸顶被裁时先丢文案,绝不能丢按钮 */
.buy-cta {
  width: 100%; height: 50px; box-sizing: border-box; padding: 0;
  border: none; border-radius: 12px; font-family: inherit;
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8);
  color: #ffffff; font-size: 16px; font-weight: 700; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  box-shadow: 0 6px 16px rgba(37, 99, 235, .26), inset 0 1px 0 rgba(255, 255, 255, .25);
  transition: transform .2s var(--ease-out), box-shadow .2s ease;
}
.buy-cta:hover { transform: translateY(-2px); box-shadow: 0 10px 22px rgba(37, 99, 235, .34), inset 0 1px 0 rgba(255, 255, 255, .25); }
.buy-cta svg { flex: none; display: block; }

/* ── 简版用户评价:购买面板下方,与它同宽同卡型 ────────────────
   正文截 2 行,长文全貌在首页「客户之声」 */
.pdp-rev {
  box-sizing: border-box; margin-top: 14px; padding: 18px 22px 20px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 8px 24px rgba(13, 38, 90, .07); border-radius: 18px;
}
.pdp-rev-head { display: flex; align-items: baseline; gap: 8px; }
/* 星条整体推到右端,数字与条数跟着它;svg 没有基线,baseline 会把它吊高,单独居中。 */
.pdp-rev-head .pdp-stars { margin-left: auto; align-self: center; }
.pdp-rev-score { font-size: 15px; font-weight: 700; color: #1B5FE8; }
.pdp-rev-count { font-size: 13px; color: rgba(30, 50, 80, .7); }
/* 空态那句(本机商家的新货,还没有评价)。13px 但 α 走 .7 —— 次要文字对比度下限
   那条在这里同样管着。 */
.pdp-rev-none { margin: 12px 0 0; font-size: 13px; line-height: 20px; color: rgba(30, 50, 80, .7); }
.pdp-rev-item { margin-top: 14px; padding-top: 14px; border-top: 1px solid rgba(13, 38, 90, .07); }
.pdp-rev-top { display: flex; align-items: center; gap: 9px; }
.pdp-rev-top .review-avatar { width: 26px; height: 26px; font-size: 12px; }
.pdp-rev-name {
  min-width: 0; font-size: 13px; font-weight: 700; color: #0C1626;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pdp-rev-text {
  margin: 8px 0 0; font-size: 14px; line-height: 1.7; color: rgba(20, 35, 60, .72);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}

/* ── 结算页 · 确认订单 ────────────────────────────────────────────
   排版契约:全页只有 8 种字体样式、6 档纵向间距(5/9/16/24/28/84)、
   2 档横向间距(12/16)。字距只出现在 .co-label 一种样式上。
   藏掉侧栏后内容区 1366,面板 760 居中,两侧各留 303 —— 44% 的空白
   是刻意不花掉的,这是本页「大气」的主要来源。 */
/* 两侧各 303px 的留白若是纯平底色,会读成「页面没排完」而不是「留白」。
   一层极淡的品牌径向晕染(取自 .reviews-band / .footer::before 的同族配方)
   把空白变成刻意的,同时给白面板一圈光晕。 */
.page[data-view="checkout"] {
  background:
    radial-gradient(920px 540px at 50% 130px, rgba(46, 124, 255, .07), transparent 62%),
    #F4F7FC;
}

/* 两栏:左栏保持原来的 760(面板内的排版契约一格不动),右栏取详情页同款
   380,gap 同 .pdp-main 的 16 —— 合计 1156,两侧留白从 303 收到 105。
   留白确实少了,但账目与付款动作必须自成一栏才不被表单节奏带着走。 */
.co-wrap { width: 1156px; margin-inline: auto; }
.co-cols { display: flex; gap: 16px; align-items: flex-start; }
.co-main { width: 760px; flex: none; }
/* 吸顶同 .pdp-rail:必须挂在 .co-cols / .cart-cols 的直接 flex 子项上,
   挂内层的 .co-sum 会被 flex-start 压到零行程。top 取页头高 + 14 呼吸,
   而结算页的页头没有类目 tab 条(78 而非 132),所以下面单独覆盖一次。 */
.co-side { width: 380px; flex: none; position: sticky; top: 146px; }
.page[data-view="checkout"] .co-side { top: 92px; }

.co-head { display: flex; align-items: baseline; gap: 16px; padding: 0 0 24px; }
.co-head h1 { margin: 0; font-size: 30px; line-height: 38px; font-weight: 700; color: #0C1626; }
.co-back { margin-left: auto; font-size: 14px; font-weight: 600; color: #1B6BFF; }
.co-back:hover { color: #0A56C8; }

/* 一个表面,不是若干:整单是一块面板 + 两条 1px 横线。
   与 .pdp-panel 同族,但不做 hover 抬起(内容面板不抬)。 */
.co-panel {
  box-sizing: border-box; padding: 28px 30px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05); border-radius: 18px;
}
.co-sec + .co-sec {
  margin-top: 24px; padding-top: 24px;
  border-top: 1px solid rgba(13, 38, 90, .07);
}

/* ── 账户充值页 #/topup(2026-08-06)──────────────────────────────
   三张独立白卡走 `.co-panel`,这里只管卡间距与这一页自己的几个控件。
   卡间距 16 = 两栏之间的 gap(`.co-cols`),纵横同一个数,不另取值。 */
.tu-card + .tu-card { margin-top: 16px; }
.tu-head { padding-block: 22px; }
.tu-title { margin: 0 0 4px; font-size: 24px; line-height: 32px; font-weight: 700; color: #0C1626; }
/* 面额按钮:5 列等宽。**不写死宽度** —— $1,000.00 比 $50.00 宽出一截,等分才能让
   五颗一样大(参考站也是等分的一行)。 */
.tu-amts { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; }
.tu-amt {
  height: 52px; box-sizing: border-box; padding: 0 6px; cursor: pointer;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14); border-radius: 12px;
  font-size: 16px; font-weight: 700; color: #23324A;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  transition: border-color .2s ease, background-color .2s ease, color .2s ease, transform .2s var(--ease-out);
}
.tu-amt:hover { border-color: rgba(27, 107, 255, .55); color: #1B6BFF; transform: translateY(-2px); }
/* 选中态走浅蓝底 + 蓝边,不做实心蓝:实心是主行动按钮那一档(右栏那颗「充值」),
   一排五颗选中一颗就变成整页最重的一块,会跟真正的 CTA 抢。 */
.tu-amt.is-active {
  background: rgba(46, 124, 255, .09); border-color: #1B6BFF; color: #1B5FE8;
}
.tu-custom { display: block; margin-top: 16px; }
.tu-custom-lab {
  display: block; margin-bottom: 8px;
  font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626;
}
/* 「最低 $10」跟在标签后面,退一档字重与颜色:它是对这一格的说明,不是标签本身。
   参考图这里用的是红色,站内不跟 —— 红的既有语义是「错误」,而填之前没人做错什么。 */
.tu-min { margin-left: 8px; font-size: 13px; font-weight: 500; font-style: normal; color: rgba(30, 50, 80, .6); }
/* 金额越界之后这一句才变红(填错了,红的既有语义在这一刻正好成立),同时文案由
   `tpMinText` 换成 tpTodo 那句 —— 上面那条注释说的是**常态**不用红,不是这一条的反例。
   `#C0261F` 是站内错误红(同 `.co-hint.is-bad`),不引入第二个红;字重跟着上到 600,
   13px 的说明字退回中灰时看得见、变红时要读得出。 */
.tu-min.is-bad { font-weight: 600; color: #C0261F; }
/* 带副行的支付格子(充值页每格的费率、结算页余额那格的当前余额)。
   **只作用于这两处,不改基类** —— `.co-pay` 还被结算页那 8 个卡类格子与入驻申请的
   收款宫格用着,把 height 改成 auto 会连它们一起松开。
   `.co-pays` 是 4 列 grid,行高由该行最高的项决定:充值页 8 格全带费率、整行一起变高;
   结算页余额那格是第 9 个、单独占第 3 行,所以前两行仍是 44。 */
.co-pay.is-bal, [data-paygrp="topup"] .co-pay {
  height: auto; min-height: 44px; padding: 9px 12px;
  flex-wrap: wrap; align-content: center;
}
/* 副行独占一行并与名字左对齐:30 是 `.co-pay-logo` 的宽、12 是 `.co-pay` 的 gap。
   `flex-basis:100%` 要配上面那条的 `flex-wrap:wrap` 才生效,两条是一套。 */
.co-pay-fee, .co-pay-bal {
  flex-basis: 100%; margin-left: 42px;
  font-size: 12px; line-height: 16px;
  font-variant-numeric: tabular-nums;
}
.co-pay-fee { color: rgba(30, 50, 80, .68); }
.tu-fee-note { margin: 6px 0 0; }
/* 金额框左边那个 $ 是**符号不是输入内容**:写在框里而不是 placeholder 里,
   填完之后它还得在(placeholder 一有输入就没了,金额会读作一个裸数字)。 */
.tu-field { gap: 6px; }
.tu-cur { flex: none; font-size: 14px; font-weight: 700; font-style: normal; color: rgba(30, 50, 80, .6); }
.tu-field input { font-variant-numeric: tabular-nums; }
/* 金额回显条。**没选金额时不是隐藏而是变淡**:整条消失会让下面的支付方式往上跳
   一格(实测 46px),而这一块正是用户点完面额要看的地方。 */
.tu-echo {
  margin-top: 16px; padding: 12px 14px; border-radius: 12px;
  background: rgba(46, 124, 255, .07); border: 1px solid rgba(46, 124, 255, .18);
  display: flex; align-items: center; gap: 8px;
  font-size: 14px; line-height: 20px; color: rgba(30, 50, 80, .7);
  opacity: .55; transition: opacity .2s ease;
}
.tu-echo.is-on { opacity: 1; }
.tu-echo svg { flex: none; display: block; color: #1B6BFF; }
.tu-echo b { font-size: 16px; font-weight: 700; color: #1B5FE8; font-variant-numeric: tabular-nums; }
/* 结算页支付宫格里余额那格的当前余额。12px 是徽章那一档,但**色值仍过 4.5:1** ——
   它是用来判断「够不够」的数,不是装饰(同消息中心那条对比度下限)。 */
.co-pay-bal { font-weight: 600; color: rgba(30, 50, 80, .72); }
/* 三个标签在同一 x 位置形成一条左脊。参数与报价页左栏 .off-label 一字不差 ——
   两处都是「一组东西的名字」,见 .off-label 那条注释。 */
.co-label {
  display: block; font-size: 14px; line-height: 20px; font-weight: 600;
  color: #0C1626;
}
.co-body { margin-top: 9px; }
.co-meta { font-size: 13px; line-height: 17px; color: rgba(30, 50, 80, .7); }

/* 商品行:恒定 60px 高,商品名 nowrap 保证下方节奏永不位移 */
/* 商品行做成一口「井」而不是浮在面板上的一行文字 —— 填充刻意与 .co-field
   取同一个 rgba(13,38,90,.05),于是面板里两个可读区块共用一套内嵌语言,
   是系统而非装饰。 */
.co-item {
  padding: 16px; border-radius: 12px;
  background: rgba(13, 38, 90, .05);
  display: flex; align-items: center; gap: 16px;
}
.co-item .prod-frame { flex: none; }
.co-item-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.co-item-name {
  font-size: 16px; font-weight: 700; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.co-item-qty { flex: none; font-size: 14px; font-weight: 700; color: rgba(30, 50, 80, .6); }

/* 徽章行落在「井」外面:井装的是买了什么,这行说的是谁发货、多快 —— 两件事 */
.co-item-flags { margin-top: 10px; display: flex; align-items: center; gap: 6px; }
.co-item-flags .prod-flag { flex: none; }
.prod-flag-shop { background: rgba(27, 107, 255, .08); border: 1px solid rgba(27, 107, 255, .16); color: #1B6BFF; }
.prod-flag-shop .prod-verify { margin-left: 1px; }

/* 输入框:.search 去掉绝对定位与定宽 */
.co-field {
  width: 100%; height: 44px; box-sizing: border-box;
  background: rgba(13, 38, 90, .05);
  border: 1px solid rgba(13, 38, 90, .1);
  border-radius: 12px; padding: 0 14px;
  display: flex; align-items: center; gap: 12px;
  transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.co-field:focus-within {
  border-color: rgba(27, 107, 255, .6);
  box-shadow: 0 0 0 4px rgba(46, 124, 255, .14);
  background: #ffffff;
}
.co-field svg { flex: none; display: block; }
.co-field input {
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font-size: 14px; line-height: 18px; color: #0C1626;
}
.co-hint { margin-top: 5px; }
/* 多件代充时一件一个账号框。组标题只写「充值账号」,是哪一件由 .co-uid-for 说 ——
   两个「请输入 Bigo ID」并排,不点名就分不清谁是谁。 */
.co-uid + .co-uid { margin-top: 14px; }
.co-uid-for {
  display: block; margin-bottom: 6px;
  font-size: 13px; font-weight: 600; color: rgba(20, 35, 60, .8);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 支付宫格:logo 用固定 30×18 盒子,否则 8 个标签会从 8 个不同的 x 开始 */
.co-pays { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.co-pay {
  height: 44px; padding: 0 12px; border-radius: 12px; box-sizing: border-box;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14);
  color: #23324A; font-size: 14px; font-weight: 500; cursor: pointer;
  display: flex; align-items: center; gap: 12px;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}
.co-pay:hover { border-color: rgba(27, 107, 255, .55); color: #1B6BFF; }
/* roving tabindex 的代价:未选中的 7 颗渲染 tabindex="-1",被文件顶部那条
   [tabindex="-1"]:focus 把焦点环一起关掉了(那条本来只想管视图容器)。而用方向键
   在组内换项正是这一组的键盘用法,看不见焦点落在哪就没法用;选中那颗因为是
   tabindex="0" 反而有环,同一组里两种表现。特异性 (0,3,0) 高过那条的 (0,2,0),
   所以不依赖谁写在后面。**加新的 roving tabindex 组件时照这条补一份。** */
.co-pays .co-pay:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.co-pay.is-active {
  background: rgba(46, 124, 255, .09); border-color: rgba(46, 124, 255, .35);
  color: #1B5FE8; font-weight: 700;
}
.co-pay.is-active:hover { background: rgba(46, 124, 255, .16); border-color: rgba(46, 124, 255, .6); }
.co-pay-logo {
  flex: none; width: 30px; height: 18px;
  display: flex; align-items: center; justify-content: center;
}
.co-pay-logo img {
  max-width: 30px; max-height: 18px; width: auto; height: auto;
  object-fit: contain; display: block; opacity: .85;
  transition: opacity .2s ease;
}
.co-pay:hover .co-pay-logo img, .co-pay.is-active .co-pay-logo img { opacity: 1; }
.co-pay-name { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* 条款:button[role=checkbox] 而非 label 包裹 —— 文字含链接,
   点文字必须打开条款而不是切换勾选 */
.co-agree { margin-top: 16px; display: flex; align-items: center; gap: 12px; }
.co-check {
  flex: none; width: 18px; height: 18px; padding: 0; box-sizing: border-box;
  border: 1px solid rgba(13, 38, 90, .24); border-radius: 5px;
  background: #ffffff; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background-color .2s ease, border-color .2s ease;
}
.co-check:hover { border-color: rgba(27, 107, 255, .55); }
/* 勾是从小长到满,不是淡进来:确认动作(结算勾条款、左栏勾筛选)纯淡入太温吞,
   而 .6 → 1 这一下就够读出「勾上了」。缩放起点不取 0 —— 见文件末尾按压那节,
   同样的理由:没有东西是从虚无里冒出来的。 */
.co-check svg {
  display: block; opacity: 0; transform: scale(.6);
  transition: opacity .14s var(--ease-out), transform .14s var(--ease-out);
}
.co-check.is-on {
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8); border-color: transparent;
}
.co-check.is-on svg { opacity: 1; transform: none; }
.co-agree .co-meta { min-width: 0; }
.co-agree a { font-weight: 600; }

/* 订单摘要卡:阴影用 .pdp-buy 那档(0 8px 24px .07)而非 .pdp-panel 的
   (0 6px 20px .05) —— 站内以此区分「内容面板」与「操作面板」,这里是后者。
   内边距 22 而非左栏的 30:380 宽的栏里 30 会把明细行挤成两截。 */
.co-sum {
  box-sizing: border-box; padding: 22px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 8px 24px rgba(13, 38, 90, .07); border-radius: 18px;
}
.co-sum-rows { margin-top: 14px; display: flex; flex-direction: column; gap: 10px; }
.co-sum-row { display: flex; align-items: baseline; gap: 12px; font-size: 14px; line-height: 19px; }
/* 优惠行没有折扣时靠 [hidden] 收起,但上面那句 display:flex 的权重压过了
   浏览器默认的 [hidden]{display:none},不补这条它会一直显示「优惠码 −$0」。 */
.co-sum-row[hidden] { display: none; }
.co-sum-row span { color: rgba(30, 50, 80, .6); }
.co-sum-row b { margin-left: auto; font-weight: 600; color: #23324A; }
.co-sum-row b.is-free { color: #0E7D45; }

/* 明细与应付之间那条线是全卡唯一的分隔:线以上是演算,线以下是答案 */
.co-sum-total {
  margin-top: 16px; padding-top: 16px;
  border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: baseline; gap: 12px;
}
.co-sum-total .price { margin-left: auto; }
.co-sum-total .price-cur { font-size: 16px; }
.co-sum-total .price-num { font-size: 34px; line-height: 38px; }

/* 灰按钮的解释:只在没就绪时占位,就绪后整块 hidden,不留空行 */
.co-todo {
  margin-top: 10px; font-size: 13px; line-height: 17px;
  color: #C2410C; text-align: center;
}
.co-safe {
  margin-top: 16px; padding-top: 14px;
  border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; flex-direction: column; gap: 8px;
}
.co-safe span {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; line-height: 17px; color: rgba(30, 50, 80, .7);
}
.co-safe svg { flex: none; display: block; }

.co-cta {
  margin-top: 16px; width: 100%; height: 50px; box-sizing: border-box;
  border: none; border-radius: 12px;
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8);
  color: #ffffff; font-size: 16px; font-weight: 700; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  box-shadow: 0 12px 30px rgba(37, 99, 235, .4), inset 0 1px 0 rgba(255, 255, 255, .25);
  transition: transform .2s var(--ease-out), box-shadow .2s ease, background-color .2s ease, color .2s ease;
}
.co-cta:hover { transform: translateY(-2px); box-shadow: 0 16px 38px rgba(37, 99, 235, .5), inset 0 1px 0 rgba(255, 255, 255, .25); }
.co-cta svg { flex: none; display: block; }
/* 禁用态只用既有 token:.06 是 ghost hover 填充,.55 是全站禁用态统一的字色
   (2026-08-03 从 .3 提上来 —— 旧值在这里只有 1.77:1,压根读不出写的是什么;
   四处禁用态 .cart-bulk / .co-cta / .buy-step / .msg-send 现在同为 .55,落在 3.1–3.3,
   既看得出是禁用、也读得出内容)。
   填写期间整页零个饱和元素,就绪瞬间出现一个 —— 按钮变蓝本身就是奖励。 */
.co-cta[disabled] {
  background: rgba(13, 38, 90, .06); color: rgba(30, 50, 80, .55);
  box-shadow: none; cursor: not-allowed;
}
.co-cta[disabled]:hover { transform: none; box-shadow: none; }
.co-cta[disabled] svg { display: none; }

/* ── 客户之声 ─────────────────────────────────────────────────── */
.reviews-band {
  position: relative; overflow: hidden;
  background: radial-gradient(760px 420px at 50% 0%, rgba(139, 92, 255, .07), transparent 65%);
}
/* 76 是首页区块间距的公用档(.hot / .feat-sec 同值)—— 原先 72/76/80/84
   四个值彼此差 4px,分不出层级,只让「新分区留多少」没有可抄的答案。 */
.reviews-band .container { padding-top: 76px; padding-bottom: 76px; }
.reviews-head { display: flex; align-items: flex-end; justify-content: space-between; }
.band-title { margin: 0; font-size: 30px; line-height: 36px; font-weight: 700; color: #0C1626; }
.reviews-sub { margin: 10px 0 0; font-size: 14px; color: rgba(30, 50, 80, .7); }
/* 跑马灯视口。--rv-w + --rv-gap 一格 396,一屏(1366)因此露出 3.4 张 ——
   半张卡卡在边上正是「这一条还能往下滚」的信号,别调成整数张。
   --rv-n(评价条数)由 renderReviews 写在行内,位移与时长都从它算:
   位移 = 一份的宽度,时长 = 每张卡 6.6s(≈60px/s,读得完又不显得停着)。
   6.6 与 396 是一对,改卡宽要一起改,不然速度会跟着卡宽变。
   overflow:hidden 会连垂直方向一起裁,而卡片 hover 抬 3px 还带阴影,所以上下
   各留 12 padding 再用负 margin 收回去(顶部 32 = 20 + 12,与原来 grid 的间距一致)。
   左右 mask 让卡片在容器边缘淡出,不然是一刀切断。 */
.reviews-marquee {
  --rv-w: 380px; --rv-gap: 16px;
  overflow: hidden;
  padding-block: 12px; margin: 20px 0 -12px;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 56px, #000 calc(100% - 56px), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 56px, #000 calc(100% - 56px), transparent);
}
.reviews-track {
  display: flex; align-items: stretch; gap: var(--rv-gap); width: max-content;
  animation: rvScroll calc(var(--rv-n) * 6.6s) linear infinite;
}
/* 停下来才读得完一条 —— 鼠标停在带子上就暂停,移开继续。 */
.reviews-marquee:hover .reviews-track { animation-play-state: paused; }
@keyframes rvScroll {
  to { transform: translateX(calc(var(--rv-n) * (var(--rv-w) + var(--rv-gap)) * -1)); }
}
/* 全局那条 reduce 规则只把时长压成 0,轨道会停在起点、后 7 条永远看不见。
   所以这里明确关掉动画、改成可手动横滑,并把只为循环存在的第二份收掉。 */
@media (prefers-reduced-motion: reduce) {
  .reviews-marquee { overflow-x: auto; }
  .reviews-track { animation: none; }
  .review-card[aria-hidden="true"] { display: none; }
}
.review-card {
  /* 本站没有全局 border-box,不写这条的话 26 的内边距会把 380 撑成 434,
     而动画位移按 --rv-w + --rv-gap 算 —— 差的那 54px 每卡累一次,一轮下来
     接缝错开 540px,循环处会当场跳一下。--rv-w 必须就是卡的外框宽。 */
  box-sizing: border-box; flex: none; width: var(--rv-w);
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  border-radius: 18px; padding: 26px;
  display: flex; flex-direction: column;
  transition: border-color .15s ease, transform .15s var(--ease-out), box-shadow .15s ease;
}
.review-card:hover {
  border-color: rgba(27, 107, 255, .35);
  transform: translateY(-3px);
  box-shadow: 0 16px 36px rgba(13, 38, 90, .1);
}
.review-quote {
  font-size: 52px; line-height: .6; font-weight: 700;
  color: rgba(27, 107, 255, .3); font-family: Georgia, serif;
}
.review-text {
  margin: 14px 0 0; font-size: 14px; line-height: 1.85;
  color: rgba(20, 35, 60, .8); text-wrap: pretty; flex: 1;
}
.review-foot {
  margin-top: 22px; padding-top: 18px;
  border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: center; gap: 11px;
}
.review-avatar {
  position: relative; overflow: hidden;
  width: 40px; height: 40px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  color: #ffffff; font-size: 14px; font-weight: 700;
}
/* 人像图盖满字母块;加载失败时 js 摘掉 img,字母自动露出来 */
.review-avatar-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.review-who { min-width: 0; }
.review-name { display: block; font-size: 14px; font-weight: 700; color: #0C1626; }
.review-date { display: block; margin-top: 2px; font-size: 13px; color: rgba(30, 50, 80, .7); }
.review-stars { margin-left: auto; display: flex; gap: 3px; }

/* ── 信任条 + 支付方式 ────────────────────────────────────────── */
.trust-band {
  background: linear-gradient(180deg, #F4F7FC, #EAF0F9);
  border-top: 1px solid rgba(13, 38, 90, .06);
}
.trust-band .container { padding-block: 40px; }
.trust-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; }
.trust-item { display: flex; align-items: center; gap: 14px; }
.trust-ico {
  flex: none; width: 42px; height: 42px; border-radius: 13px;
  background: linear-gradient(150deg, rgba(46, 124, 255, .13), rgba(139, 92, 255, .09));
  display: flex; align-items: center; justify-content: center;
}
.trust-text { min-width: 0; }
.trust-title { display: block; font-size: 14px; line-height: 19px; font-weight: 700; color: #0C1626; }
.trust-sub { display: block; margin-top: 3px; font-size: 13px; line-height: 18px; color: rgba(30, 50, 80, .7); }

.pays-row {
  margin-top: 34px; padding-top: 24px;
  border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: center; gap: 30px; flex-wrap: wrap; justify-content: center;
}
/* 藏掉 .trust-grid 的三个视图(报价页 / 详情页 / 个人中心)里,付款条是条内唯一一行,
   分隔线上面没东西可分隔 —— 留着就是一条悬空的横线,还白撑高 59px。
   **这几个选择器要跟着 `.trust-grid` 的 hide-on-* 名单一起改**:以后再有视图收掉
   那四项,这里漏补的症状就是页脚上方多一条无来由的线。
   (2026-08-06 补 offers:报价页与详情页是同一件商品的两层,形态本来就该一致。) */
.page[data-view="offers"] .pays-row,
.page[data-view="pdp"] .pays-row,
.page[data-view="account"] .pays-row { margin-top: 0; padding-top: 0; border-top: none; }
.pay-item {
  display: flex; align-items: center; opacity: .85;
  transition: opacity .25s ease, transform .2s var(--ease-out);
}
.pay-item:hover { opacity: 1; transform: translateY(-2px); }
.pay-item img { height: 19px; width: auto; display: block; object-fit: contain; }
.pay-item span { font-size: 14px; font-weight: 700; color: #23324A; white-space: nowrap; }

/* ── 页脚 ─────────────────────────────────────────────────────── */
.footer { position: relative; overflow: hidden; background: #0A1220; }
.footer::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(700px 320px at 8% 0%, rgba(46, 124, 255, .12), transparent 62%);
}
.footer-grid {
  position: relative; padding-block: 60px;
  display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 24px;
}
.footer-brand { display: flex; align-items: center; gap: 12px; }
.footer-mark { height: 32px; width: auto; display: block; }
.footer-word { height: 20px; width: auto; display: block; }
.footer-desc {
  margin: 20px 0 0; font-size: 14px; line-height: 1.8;
  color: rgba(255, 255, 255, .5); max-width: 300px;
}
.footer-social { display: flex; gap: 10px; margin-top: 24px; }
.footer-social a {
  width: 42px; height: 42px; border-radius: 12px;
  background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .12);
  display: flex; align-items: center; justify-content: center;
  transition: background-color .2s ease, border-color .2s ease;
}
.footer-social a:hover { background: linear-gradient(120deg, #2E7CFF, #1B5FE8); border-color: transparent; }
.footer-social a:focus-visible { outline-color: #6FB0FF; }
.footer-social img { width: 18px; height: 18px; display: block; opacity: .9; }
.footer-social .social-x img { width: 15px; height: 15px; }
.footer-note { font-size: 13px; color: rgba(255, 255, 255, .5); margin-top: 20px; }
/* 页脚是深底,700 留着 —— 同一个 600 在深底上比浅底看着细一档。字距按全站统一去掉。 */
.footer-col-title { font-size: 14px; font-weight: 700; color: rgba(255, 255, 255, .92); }
.footer-links { display: flex; flex-direction: column; gap: 14px; margin-top: 20px; }
.footer-links a { font-size: 14px; color: rgba(255, 255, 255, .55); }
.footer-links a:hover { color: #ffffff; }
.footer-links a:focus-visible { outline-color: #6FB0FF; }
.footer-bottom {
  position: relative;
  border-top: 1px solid rgba(255, 255, 255, .08); padding-block: 22px;
  display: flex; align-items: center; justify-content: space-between;
  font-size: 13px; color: rgba(255, 255, 255, .5);
}
.footer-domain { letter-spacing: .08em; }

/* ── 弹窗广告 ─────────────────────────────────────────────────── */
.ad-modal {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(13, 27, 42, .6);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  overflow-y: auto; padding: 32px;
  animation: adFade .2s ease-out;
}
.ad-modal[hidden] { display: none; }
.ad-modal-box {
  margin: auto; flex: none; position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 20px;
  animation: adPop .28s cubic-bezier(.2, .8, .3, 1);
}
.ad-poster {
  position: relative; overflow: hidden; box-sizing: border-box;
  width: min(420px, 74vw); height: min(520px, 56vh);
  display: flex; flex-direction: column; align-items: flex-start;
  padding: 40px 36px;
  border-radius: 22px;
  background:
    radial-gradient(420px 320px at 82% -6%, rgba(139, 92, 255, .5), transparent 64%),
    radial-gradient(360px 300px at 6% 104%, rgba(14, 159, 216, .3), transparent 60%),
    linear-gradient(160deg, #151233, #0B0F24 52%, #0A0E1E);
  border: 1px solid rgba(13, 38, 90, .1);
  box-shadow: 0 30px 80px rgba(6, 16, 40, .5);
}
.ad-poster-grid {
  position: absolute; inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 40px 40px;
  mask-image: radial-gradient(420px 360px at 50% 0%, rgba(0, 0, 0, .85), transparent 80%);
  -webkit-mask-image: radial-gradient(420px 360px at 50% 0%, rgba(0, 0, 0, .85), transparent 80%);
}
.ad-poster-orb {
  position: absolute; right: -90px; bottom: -120px;
  width: 300px; height: 300px; border-radius: 50%;
  border: 38px solid rgba(255, 255, 255, .07);
}
.ad-poster > span { position: relative; }
.ad-poster-badge {
  height: 26px; padding: 0 14px; border-radius: 999px;
  background: linear-gradient(135deg, #FFB020, #F0700C);
  color: #2A1600; font-size: 12px; font-weight: 700; letter-spacing: .1em;
  display: flex; align-items: center;
}
.ad-poster-title {
  margin-top: 26px; font-size: 40px; line-height: 1.2; font-weight: 700; color: #ffffff;
}
.ad-poster-title em {
  display: block; font-style: normal; font-size: 104px; line-height: 1.05; font-weight: 700;
  color: #ffffff; text-shadow: 0 0 44px rgba(77, 139, 255, .8);
}
.ad-poster-sub { margin-top: 16px; font-size: 14px; color: rgba(200, 215, 240, .7); }
.ad-poster-code {
  margin-top: auto; align-self: stretch;
  border: 1px dashed rgba(255, 255, 255, .32); border-radius: 12px;
  padding: 13px 18px;
  color: rgba(255, 255, 255, .82); font-size: 14px;
  display: flex; align-items: center; gap: 10px;
}
.ad-poster-code b { font-size: 16px; font-weight: 700; letter-spacing: .18em; color: #ffffff; }
.ad-modal-cta {
  height: 54px; padding: 0 46px; border-radius: 999px;
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8);
  color: #ffffff; font-size: 18px; font-weight: 700;
  display: flex; align-items: center;
  box-shadow: 0 14px 36px rgba(37, 99, 235, .5), inset 0 1px 0 rgba(255, 255, 255, .28);
  transition: transform .2s var(--ease-out);
}
.ad-modal-cta:hover { transform: translateY(-2px); color: #ffffff; }
.ad-modal-cta:focus-visible { outline: 2px solid #ffffff; outline-offset: 3px; }
.ad-modal-close {
  position: absolute; top: -14px; right: -14px; z-index: 1;
  background: #0D1B2A; width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .5);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; padding: 0;
  box-shadow: 0 8px 24px rgba(6, 16, 40, .5);
  transition: border-color .2s ease;
}
.ad-modal-close:hover { border-color: #ffffff; }
.ad-modal-close:focus-visible { outline: 2px solid #ffffff; outline-offset: 3px; }

/* ── Toast ────────────────────────────────────────────────────────
   固定在右下角。`bottom` 曾是 92,给底下那颗常驻的「在线客服」浮动按钮让位;
   2026-08-01 按钮删掉后落回 24(= right 的 24),不然右下角凭空空出 68px。 */
@keyframes toastIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.toast-host {
  position: fixed; right: 24px; bottom: 24px; z-index: 90;
  display: flex; flex-direction: column; align-items: flex-end; gap: 8px;
  pointer-events: none;
}
.toast {
  max-width: 340px; padding: 11px 16px; border-radius: 12px;
  background: rgba(13, 27, 42, .94); color: #ffffff;
  font-size: 14px; line-height: 20px; font-weight: 600;
  box-shadow: 0 14px 34px rgba(6, 16, 40, .34);
  animation: toastIn .2s var(--ease-out); transition: opacity .2s ease, transform .2s var(--ease-out);
}
/* 往下收,与入场的 translateY(10px) 同一条路 —— 原先是向上 -6px 退场,
   等于从下面进来又从上面出去,一条 toast 穿过了自己待的那块地方。
   进出同向,「往下滑掉」这个手势将来才解释得通。 */
.toast.is-out { opacity: 0; transform: translateY(10px); }

/* ── 首屏加载页 ────────────────────────────────────────────────────
   只盖首屏(标记默认带 is-on),站内跳转不显示 —— 理由见 main.js 那一段。
   出场瞬时(is-on 只切 display),退场才淡出(transition + .is-out),一头一尾
   刻意不对称:给 is-on 也配 opacity 淡入的话,那段时间里页面会从半透明的遮罩
   底下透出来,与「盖住白屏」正相反。底色同理取 body 的 #F4F7FC 实色。
   .is-out 必须一起关掉 pointer-events:它 opacity 已经是 0、看着已经没了,
   但 display 还是 flex,不关就白挡 .26s 的点击。
   z-index 100 高于 toast(90) 与客服按钮(70)。 */
@keyframes rlSpin { to { transform: rotate(360deg); } }
@keyframes rlPulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
.route-load {
  display: none;
  position: fixed; inset: 0; z-index: 100;
  flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  background: #F4F7FC;
}
.route-load.is-on { display: flex; }
.route-load.is-out { opacity: 0; pointer-events: none; transition: opacity .26s ease; }
.rl-badge { position: relative; display: grid; place-items: center; width: 68px; height: 68px; }
.rl-ring {
  position: absolute; inset: 0; border-radius: 50%;
  border: 3px solid rgba(27, 107, 255, .14); border-top-color: #1B6BFF;
  animation: rlSpin .72s linear infinite;
}
.rl-mark { width: 34px; height: 34px; object-fit: contain; }
.rl-text {
  margin: 0; font-size: 14px; line-height: 20px; font-weight: 600;
  color: rgba(30, 50, 80, .55); animation: rlPulse 1.2s ease-in-out infinite;
}
/* 全局那条 animation-duration:0 会让环停住,只亮一段的静止圆弧读不出「在加载」,
   所以停下来时把整圈铺平。收尾的淡出另由 main.js 的 reduceMo 直接跳过。 */
@media (prefers-reduced-motion: reduce) {
  .rl-ring { border-color: rgba(27, 107, 255, .45); }
}

/* ── 语言货币下拉(2026-08-03 挪去顶栏,外观覆盖见 .topbar-pick)+ 购物车角标 ── */
.head-pick { position: relative; flex: none; }
/* 按钮里没有箭头(2026-08-03 按用户要求删掉,连同 svg 的旋转过渡与 gap 一并删净,
   不是漏写):点它直接出选择面板。 */
.head-pick-btn { cursor: pointer; }
.head-pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 20;
  width: 236px; box-sizing: border-box; padding: 8px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .1); border-radius: 14px;
  box-shadow: 0 18px 48px rgba(13, 38, 90, .18);
  /* 挂在按钮右下角(top: 100%+8 / right: 0),所以从右上角展开、并且是往下落。
     原先复用 adPop 是从下方 16px 往上升 —— 方向与它挂的位置相反。 */
  transform-origin: top right;
  animation: popDown .15s var(--ease-out);
}
.head-pop-sec + .head-pop-sec { margin-top: 6px; padding-top: 8px; border-top: 1px solid rgba(13, 38, 90, .07); }
.head-pop-label {
  display: block; padding: 4px 10px 6px;
  font-size: 12px; font-weight: 700; color: rgba(30, 50, 80, .7); letter-spacing: .06em;
}
.head-pop-row {
  width: 100%; height: 34px; padding: 0 10px; border: none; border-radius: 9px;
  background: transparent; cursor: pointer; text-align: left;
  display: flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 600; color: #0C1626;
  transition: background-color .2s ease;
}
.head-pop-row:hover { background: rgba(46, 124, 255, .09); }
.head-pop-row svg { margin-left: auto; flex: none; display: block; }
/* 勾在浅底上要看得见:CHECK_SVG 是白描边,给它一枚蓝底 */
.head-pop-row.is-on svg {
  box-sizing: content-box; width: 10px; height: 10px; padding: 3px;
  border-radius: 50%; background: #1B6BFF;
}
/* `.head-pop-row.is-soon`(English 那行的禁用态)、`.head-pop-row i`(「开发中」角标)
   与 `.head-pop-note`(「暂不支持切换」那句)三条 2026-08-04 随「语言 / 币种改成真的
   能选」一并删净,**不是漏写** —— 两项都有多个可选值之后,这三样恒为假。 */
.head-cart { position: relative; }
.head-cart-num {
  position: absolute; top: -5px; right: -5px;
  min-width: 17px; height: 17px; box-sizing: border-box; padding: 0 4px;
  border-radius: 9px; background: #FF3B3B; color: #ffffff;
  font-size: 10px; font-weight: 700; line-height: 17px; text-align: center;
  box-shadow: 0 2px 6px rgba(255, 59, 59, .45);
}
.head-cart-num.is-bump { animation: badgeBump .28s var(--ease-out); }

/* ── 独立页通用件(购物车 / 订单 / 个人中心 / 商家入驻 / 店铺 / 支付结果)──
   页头、空态与主 CTA 三件在这六页里长一样,写一处。 */
/* `.solo-head` / `.solo-title` / `.solo-sub` 2026-08-06 一并删净,**不是漏写**:
   个人中心是最后一个页级标题的用户,那一页照参考站重做时把它去掉了(用户卡上就印着
   名字与邮箱,面包屑末格已经答过「这是哪」)。购物车 / 订单查询 / 消息中心早已各自
   删过一次。**CLAUDE.md 里那句「.solo-head / .solo-title 不能删,个人中心还在用」
   已失效** —— 真要再加页级标题,重写一条比复活这三条干净。 */
.solo-empty {
  margin-top: 18px; padding: 54px 30px; box-sizing: border-box;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
}
.solo-empty-lg { margin-top: 30px; padding: 80px 30px; }
.solo-empty p { margin: 0; font-size: 18px; font-weight: 700; color: #0C1626; }
.solo-empty span { font-size: 14px; line-height: 21px; color: rgba(30, 50, 80, .7); max-width: 460px; }
.solo-cta {
  margin-top: 10px; height: 44px; padding: 0 22px; border: none; border-radius: 12px; cursor: pointer;
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8);
  color: #ffffff; font-size: 14px; font-weight: 700; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 7px;
  box-shadow: 0 10px 26px rgba(37, 99, 235, .28);
  transition: transform .2s var(--ease-out), box-shadow .2s ease;
}
.solo-cta:hover { transform: translateY(-2px); color: #ffffff; box-shadow: 0 16px 34px rgba(37, 99, 235, .36); }
/* ARROW_SVG 是写死的品牌蓝,放在蓝底上会看不见 —— 描边改跟文字走 */
.solo-cta svg { flex: none; display: block; stroke: currentColor; transition: transform .2s var(--ease-out); }
.solo-cta:hover svg { transform: translateX(3px); }
.solo-cta-ghost {
  background: #ffffff; color: #1B5FE8;
  border: 1px solid rgba(46, 124, 255, .4); box-shadow: none;
}
.solo-cta-ghost:hover { background: rgba(46, 124, 255, .07); color: #1B5FE8; box-shadow: none; }

/* ── 购物车 ─────────────────────────────────────────────────────── */
.cart-cols { margin-top: 16px; display: flex; gap: 16px; align-items: flex-start; }
.cart-list {
  flex: 1; min-width: 0; box-sizing: border-box; padding: 6px 22px 12px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
}
/* 表头与数据行共用同一套列宽,改一处要改两处 —— 所以列宽写在这条共享选择器上。
   首列 28 是勾选框(18 的框 + 两侧各 5 的点击余量),表头那格坐着全选。
   小计列 124 是量出来的:`.cart-sum` 右对齐,装不下就往左侵占数量列,而金额一上
   四位数就装不下 —— $999.99 只要 85,`$1,234.56` 就要 101 > 96(2026-08-03 实测,
   旧值 96 是按三位数金额定的)。124 = 全站最宽的一条 `$42,048.00`(121)+ 3 余量;
   理论上界是 Crew AI 最贵规格 ×20 = $50,878.08,反而只要 117 —— 数字不等宽,
   位数相同宽度也能差 4px,所以别按位数推算,改价格体系(见「下一步」的汇率换算)
   后照这个方法重量一遍。
   加宽的 28 里有 12 是从单价列匀的(120 → 108,它最长的一条是金币的
   `$0.006 / Robux` 104,白占着 16 的余量),剩下 16 从 1fr 扣 —— 1366 下 1fr 因此
   是 302。这一步不是顺手优化:`.cart-name` 是 ellipsis,1fr 每窄一点就多截断几个
   商品名,单吃 28 会让截断从 4/133 涨到 7/133,匀完只涨到 5/133(多的那条是
   游戏专区那类超长描述名)。 */
.cart-head, .cart-row {
  display: grid; grid-template-columns: 28px 64px 1fr 108px 116px 124px 34px;
  align-items: center; gap: 14px;
}
/* 吸顶:满车 50 行有 6175px,表头不跟着走的话滚过第一屏就只剩四列没标题的数字,
   「$41.72」与「$41.72」分不出哪个是单价哪个是小计。top 与右栏摘要同一条基线(146),
   两边实测都停在 146。background 是必须的 —— 商品行从它底下穿过去,不铺底就叠字;
   z-index 挡的是 .cart-thumb 的 hover transform(有 transform 就自成层叠上下文,
   会画到未定位元素之上)。 */
.cart-head {
  position: sticky; top: 146px; z-index: 1; background: #ffffff;
  height: 42px; border-bottom: 1px solid rgba(13, 38, 90, .07);
  font-size: 13px; font-weight: 700; color: rgba(30, 50, 80, .7); letter-spacing: .04em;
}
/* 商品那格横跨缩略图与信息两列(2/4)。它同时装着「删除选中」——
   批量操作跟着吸顶的表头走,滚到第 40 行时还够得着。 */
.cart-head-name {
  grid-column: 2 / 4; display: flex; align-items: center; gap: 12px;
}
/* 勾选框:几何与配色全部来自 .co-check(结算页协议、报价页左栏筛选同一颗),
   这里只补 grid 里的居中。justify-self 而不是 margin auto —— 列宽 28 是死的。 */
.cart-pick { justify-self: center; }
/* 紧跟在「商品」右边,不用 margin-left:auto 推到列尾 —— 推到尾就只剩一个 gap(14)
   与「单价」相邻,两个都是灰色小字,一眼读成「删除选中3 单价」是一组。
   它和全选框本来就是一组批量操作,靠左成组才讲得通。 */
.cart-bulk {
  padding: 0; border: none; background: none; cursor: pointer;
  display: flex; align-items: center; gap: 5px;
  font-size: 13px; line-height: 17px; font-weight: 600; letter-spacing: 0;
  color: rgba(30, 50, 80, .7);
  transition: color .2s ease, opacity .2s ease;
}
.cart-bulk:hover { color: #C0261F; }
.cart-bulk i { font-style: normal; font-variant-numeric: tabular-nums; }
/* 一件没勾时留在原位置灰着,不 hidden:表头是吸顶的,一行元素忽有忽无会让
   下面 50 行整体跳一下(它自己是 flex 撑开的,收掉后商品标题会滑到右边)。 */
.cart-bulk[disabled] { cursor: default; color: rgba(30, 50, 80, .55); }
/* 未选中的行不另做淡化态:最左边那列勾选框是蓝底与空框的对比,竖着排 50 行
   扫一眼就分得出,整行再退一档是同一个值印第二遍。而真要淡,文字得压到
   .45 上下才看得出差别 —— 那是报价卡「已售」被从 .45 提回 .7 的老问题
   (白底 2.55:1,读不出)。 */
.cart-row { padding: 16px 0; border-bottom: 1px solid rgba(13, 38, 90, .06); }
.cart-row:last-child { border-bottom: none; }
.cart-thumb {
  width: 64px; height: 64px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
  transition: transform .2s var(--ease-out);
}
.cart-thumb:hover { transform: translateY(-2px); }
.cart-info { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.cart-name {
  font-size: 15px; font-weight: 700; color: #0C1626;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cart-name:hover { color: #1B6BFF; }
.cart-flags { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
/* 代充行的账号。比 .co-field 矮一档(34)也窄一档:它坐在商品名底下的信息列里,
   拿结算页那份 44 高的框会把行高顶到把缩略图挤扁。 */
.cart-uid { margin-top: 4px; display: flex; align-items: center; gap: 8px; }
.cart-uid > span {
  flex: none; font-size: 12px; font-weight: 600; color: rgba(30, 50, 80, .7);
}
.cart-uid input {
  flex: 1; min-width: 0; max-width: 240px; height: 34px; box-sizing: border-box;
  padding: 0 10px; border-radius: 10px;
  background: rgba(13, 38, 90, .05); border: 1px solid rgba(13, 38, 90, .1);
  outline: none; font-size: 13px; line-height: 17px; color: #0C1626;
  transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.cart-uid input:focus { border-color: rgba(27, 107, 255, .6); box-shadow: 0 0 0 3px rgba(46, 124, 255, .14); background: #ffffff; }
.cart-uid input.is-bad { border-color: rgba(192, 38, 31, .7); box-shadow: 0 0 0 3px rgba(192, 38, 31, .12); }
.cart-unit { font-size: 14px; font-weight: 600; color: rgba(20, 35, 60, .8); }
/* 数量列 116 宽,详情页那套 36+66+36 的步进器塞不进去,这里整体缩一档到 108 */
.cart-qty { display: flex; align-items: center; justify-content: center; }
.cart-qty .buy-stepper { margin: 0; height: 34px; }
.cart-qty .buy-step { width: 32px; height: 32px; font-size: 14px; }
.cart-qty .buy-num { width: 42px; height: 32px; font-size: 14px; }
.cart-sum { text-align: right; }
.cart-del {
  width: 34px; height: 34px; border-radius: 10px; padding: 0; cursor: pointer;
  background: transparent; border: 1px solid rgba(13, 38, 90, .1);
  color: rgba(30, 50, 80, .5);
  display: flex; align-items: center; justify-content: center;
  transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.cart-del:hover { border-color: rgba(255, 59, 59, .5); color: #C0261F; background: rgba(255, 59, 59, .06); }

/* ── 订单来源 tab(自营 / 市场卖家)与状态 pill ─────────────────────── */
/* tab 是 18/26,不是第二个 30px 标题 —— 页面已经有「消息中心」那一层面包屑,
   两层同级的粗黑字并排,眼睛不知道先读哪个。
   **形制是药丸分段控件,不是下划线文字 tab**(2026-08-03 按用户「这两个地方突出
   一下」改):旧版两个标签是裸字坐在一条通宽细线上,上面是面包屑、下面是两张白卡,
   整行读起来像一个小标题而不是一个能点的控件 —— 选中态那条 2px 蓝线是全行唯一
   的信号,在 1600 宽里细得几乎看不见。现在未选中是白底卡(与两栏同一套边框 .08
   + 阴影),选中是实心 `#1B6BFF` 白字,取的是导航条 `.nav-ind` 那套「站内选中即
   蓝底」的既有语义,不新造一种表面。
   **高度钉死 40**,与旧版那行(26 行高 + 12 下内边距 + 1 分隔线)等高 —— 两栏顶边
   那个 300 是量出来的常数,这行一变高 `.msg-wrap` 的 sticky/定高整套都要重算。 */
/* 8 而不是 24:页级标题删掉之后 tab 直接跟在面包屑下面,而 .crumb 自带 18 的
   下内边距 —— 再叠 24 就是 42 的空档,与「整体往上」正相反。 */
/* 来源 tab 走站内页级 tab 的既有语言:**文字色 + 3px 下划线**,与游戏专区的
   `.gm-tab` 同一套构造(底下那条 hairline 是轨道,`::after` 压在 -1px 上盖住它)。
   2026-08-03 从「实心蓝药丸」改回来 —— 那一版把一个来源筛选打扮成了主行动按钮:
   实心 #1B6BFF + 白字 18/700 + 常驻投影 `0 8px 18px/.28`,而站内用实心蓝的
   选中态(`.shop-sw` / `.shop-add` / `.msg-send`)**一律 14px、静止无投影**,
   同一页真正的主按钮「发送」还只是 14/700 零投影,层级整个是倒的。两个药丸各自
   还带投影(未选中 `0 6px 20px/.05`),读成两颗浮起的按钮而不是一个分段控件,
   底下再压一张大白卡,三层叠着。**别再改回实心填充。**
   字号从 18 落到 16、再落到 **15/600**(2026-08-05 第二次,照用户给的参考站排版):
   这一页按设计没有页级标题(同日删的),18/700 是整页最大的字,一个次要的分流器
   就顶替了标题的位置;落到 16 之后它与会话头店名**并列最大**,仍是个分流器压着
   正主。15 让字号谱回到「会话头店名 16 > 来源 tab 15 > 会话名 14」—— 人已经在
   哪条会话里,这一页最该先被读到的就是那个店名。
   **两档字重必须相等**(现在同为 600,曾同为 700),只换颜色 —— 改成 600/700 的话
   切一次 tab 两个标签的宽度都会变,整行跟着抖(`tabular-nums` 只管得住数字)。 */
/* tab 条是左栏卡的表头,坐在卡内最上面(2026-08-03 分三步改到位:左对齐 → 整行
   居中 → 对左栏居中 → 干脆收进卡里,用户要的是「合在一起、整体统一」)。
   **不再写宽度**:它现在是 `.msg-rail` 这个 flex column 的直接子项,宽度由卡撑满,
   `flex: none` 防止被后面的列表挤扁。分隔线跟卡内其它分隔线同色 `.07`(不是页面上
   那条 `.08`)—— 它已经在卡里了,得用卡自己的那套分隔。
   **两枚各占一半、撑满卡宽**(2026-08-03 按用户「这里可以宽一点」改):原先是
   `justify-content: center` + `gap: 26` 把两枚按各自文字宽度(122 / 96)缩在中间,
   两侧空 33、中间空 26,一条 310 宽的表头有三分之一是空的。改成 `.ord-tab { flex: 1 }`
   之后各占一半,文字在自己那半里居中,下划线也跟着铺满半幅 —— 这是分段 tab 的常规做法。
   (**上面那些 310 / 155 是 340 栏宽时的数**;2026-08-05 收窄到 260 后卡内 230、
   两枚各 **129**,文字 84 / 60 仍零截断 —— tab 不是收窄的瓶颈,店名才是,见 `.msg-rail`。)
   `.ord-tabs` 因此**不再需要 `justify-content` 与 `gap`**:没有富余空间可分配了。 */
.ord-tabs {
  flex: none; box-sizing: border-box;
  display: flex; align-items: stretch;
  border-bottom: 1px solid rgba(13, 38, 90, .07);
}
/* 39 + `.ord-tabs` 那条 1px 轨道 = 40,与旧药丸版同高,别为了凑整改成 38 或 40。
   这 40 现在是**左栏卡内表头的高度**:tab 收进卡里之后它不再占 `.msg-wrap` 之上的
   空间,`.msg-wrap` 顶边实测 **236**(同轮注释里出现过 300 与 252 两个旧数:300 是
   tab 还浮在两栏之上时的,252 是它刚收进卡、`.msg-wrap` 还留着 `margin-top: 16` 时的;
   那 16 已按「面包屑自带 18 下内边距、别把同一道间隔算两遍」删掉)。 */
.ord-tab {
  position: relative; flex: 1; min-width: 0;
  height: 39px; padding: 0; box-sizing: border-box;
  background: transparent; border: none; cursor: pointer; font-family: inherit;
  display: flex; align-items: center; justify-content: center; gap: 8px; white-space: nowrap;
  font-size: 15px; line-height: 22px; font-weight: 600;
  color: rgba(30, 50, 80, .72);
  transition: color .2s ease;
}
/* 下划线铺满自己那一半(两枚 `flex: 1`,各 155),切换时只是左右两半换亮,
   位置与长度都不动 —— 旧药丸版实测选中 168 / 未选中 139,那片蓝色连位置带体量跳 29px。 */
.ord-tab::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 3px;
  background: #1B6BFF; border-radius: 3px 3px 0 0;
  opacity: 0; transition: opacity .2s ease;
}
.ord-tab:hover { color: #0C1626; }
.ord-tab.is-active { color: #1B5FE8; }
.ord-tab.is-active::after { opacity: 1; }
/* 计数 chip(`.ord-tab-n`)2026-08-05 按用户要求**整枚删掉,不是漏写** —— 连同它的
   淡底选中态一起。tab 是分流器不是计数器,点进去列表自己就说清了有多少;那两条旧账
   (「(0) 读起来像这里什么都没有」与「min-width 24 防止 9→10 时下划线跳」)也随之作废。
   `.ord-tab` 上那个 `gap: 8px` 现在只剩一个子节点、不生效,留着是给以后可能回来的
   第二个元素 —— 想删也无害。

   左栏的「已发货 / 待发货」状态 pill 更早(2026-08-03)已整排删掉,`.msg-pills` /
   `.ord-pill` 两组 CSS 跟着删净 —— 理由见 js 里 ORD_TABS 上方那段。 */

/* ── 订单卡(订单查询 / 支付结果两处共用)──────────────────────────── */
/* 宽度交给左栏:搜索框是栏内唯一的输入,撑满 340 才与下面的会话行同一条左右脊。
   旧版钉死 420 是因为它坐在通宽的一行里,现在没有那一行了。 */
.ord-search {
  box-sizing: border-box; width: 100%; height: 42px; padding: 0 14px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .1); border-radius: 12px;
  display: flex; align-items: center; gap: 10px;
}
.ord-search:focus-within { border-color: rgba(27, 107, 255, .6); box-shadow: 0 0 0 4px rgba(46, 124, 255, .14); }
.ord-search svg { flex: none; }
.ord-search input {
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font-size: 14px; color: #0C1626;
}
/* ── 订单查询 · 整笔单列表(2026-08-03 从 IM 里拆出,IM 整体去了 #/messages)── */
.orders-wrap { max-width: 900px; margin-inline: auto; }
.ord-list-bar { margin-top: 4px; display: flex; align-items: center; gap: 14px; }
.ord-list-bar .ord-search { flex: none; width: 320px; }
.ord-msgs-link {
  margin-left: auto; flex: none; display: flex; align-items: center; gap: 5px;
  font-size: 14px; font-weight: 700; color: #1B5FE8;
}
.ord-list { margin-top: 16px; display: flex; flex-direction: column; gap: 16px; }
.ord-card {
  box-sizing: border-box; padding: 18px 22px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
}
/* 从结果页「查看订单详情」落过来的那笔单,参数照 .msg-ord.is-hit */
.ord-card.is-hit { border-color: #1B6BFF; box-shadow: 0 0 0 4px rgba(46, 124, 255, .14); }
.ord-top { display: flex; align-items: center; gap: 12px; padding-bottom: 14px; border-bottom: 1px solid rgba(13, 38, 90, .07); }
.ord-no { font-size: 15px; font-weight: 700; color: #0C1626; letter-spacing: .04em; }
/* 订单号那颗复制按钮:灰底灰字、hover 才转蓝 —— 每张卡都有它,常驻蓝字会连成
   一串,把卡密那颗真正要点的盖过去。紧跟订单号(负 margin 抵掉半格 gap)。 */
.ord-no-copy {
  margin-left: -5px; flex: none; height: 24px; padding: 0 9px; border-radius: 7px; cursor: pointer;
  background: rgba(13, 38, 90, .04); border: 1px solid rgba(13, 38, 90, .1);
  font-size: 12px; font-weight: 700; color: rgba(30, 50, 80, .72);
  transition: border-color .2s ease, background-color .2s ease, color .2s ease;
}
.ord-no-copy:hover { border-color: rgba(46, 124, 255, .5); background: rgba(46, 124, 255, .07); color: #1B5FE8; }
.ord-at { font-size: 13px; color: rgba(30, 50, 80, .7); }
.ord-status {
  margin-left: auto; padding: 4px 10px; border-radius: 7px;
  font-size: 13px; font-weight: 700;
}
/* 2026-08-04 按用户要求照参考站换配色:**已完成 = 中性灰,待发货 = 红**
   (旧版是绿 / 橙)。两者的几何与字重本来就同一套,这次把底色的透明度也统一到 **.08**
   —— 旧值是 `.1` 与 `.14`,同一列里两个标签的视觉重量不等,而它们是同一档东西。
   **红在站内的既有语义是「错误」**(`#C0261F` 只出现在删除 hover 与结算页的错误提示上),
   而「待发货」不是错误 —— 这一点跟用户确认过,是他明确选的配色,不是抄错了;
   所以沿用 `#C0261F` 而不是再引入第四个红,站内的红仍然只有这一个色标。
   两个字色都过 4.5:1(灰 `.8` 约 4.6、红约 6.6),13px 粗体读得清。 */
.ord-status.is-done { background: rgba(13, 38, 90, .08); color: rgba(30, 50, 80, .8); }
.ord-status.is-part { background: rgba(192, 38, 31, .08); color: #C0261F; }
.ord-item { padding: 12px 0 8px; display: flex; align-items: center; gap: 12px; }
.ord-thumb {
  width: 46px; height: 46px; border-radius: 12px; flex: none;
  display: flex; align-items: center; justify-content: center;
}
.ord-thumb-gone { background: rgba(13, 38, 90, .06); }
.ord-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.ord-name { font-size: 14px; font-weight: 700; color: #0C1626; }
/* .6 实测 3.79:1,14px 正文要 4.5(订单卡如今只在会话页,ord-* 子样式都归它) */
.ord-qty { font-size: 14px; color: rgba(30, 50, 80, .72); }
.ord-price { font-size: 15px; font-weight: 700; color: #0C1626; min-width: 74px; text-align: right; }
.ord-key {
  margin-bottom: 6px; padding: 11px 14px; border-radius: 12px;
  background: rgba(13, 38, 90, .03); border: 1px dashed rgba(13, 38, 90, .14);
  display: flex; align-items: center; gap: 10px;
}
.ord-key-label {
  padding: 3px 8px; border-radius: 6px; flex: none;
  background: rgba(46, 124, 255, .1); color: #1B5FE8; font-size: 12px; font-weight: 700;
}
.ord-key code {
  font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  font-size: 14px; font-weight: 700; letter-spacing: .1em; color: #0C1626;
}
.ord-key-wait span:not(.ord-key-label) { font-size: 13px; color: rgba(30, 50, 80, .7); }
.ord-copy {
  margin-left: auto; flex: none; height: 28px; padding: 0 12px; border-radius: 8px; cursor: pointer;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14);
  font-size: 13px; font-weight: 700; color: #1B5FE8;
  transition: border-color .2s ease, background-color .2s ease;
}
.ord-copy:hover { border-color: rgba(46, 124, 255, .6); background: rgba(46, 124, 255, .06); }
.ord-items { padding-top: 6px; }
/* 「全部复制」行:左右 14 照 .ord-key 的内边距,不补的话按钮右缘比上面每条
   卡密行的那颗多 14px,一列按钮就错开了(实测 1130 vs 1129 对齐)。 */
.ord-keys-all { margin-bottom: 6px; padding: 0 14px; display: flex; align-items: center; gap: 12px; }
.ord-foot {
  margin-top: 8px; padding-top: 13px; border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: center; gap: 12px;
}
.ord-disc { color: #0E7D45; }
/* 「联系卖家」:margin-left:auto 挂它身上把自己和实付一起推到右端,实付恒钉最右 */
/* 实付靠 auto 推到右段,按钮跟在它后面收在行尾 */
.ord-total { margin-left: auto; font-size: 14px; color: rgba(30, 50, 80, .7); display: flex; align-items: baseline; gap: 7px; }
/* 「联系卖家」**照 .shop-cs 逐条抄参数**(店铺页那颗「联系客服」):同一个动作 ——
   找这家商家的客服 —— 在站内就该是同一张脸,用户在店铺页见过,到订单卡上认得出。
   所以不自己调一档高度:36 比卡密行的「复制」(28)重一档是对的,它是卡片级的动作
   而不是行内的小工具,卡脚因此从 39 涨到 50,这是给它的位置付的钱。
   裸文字链那一版的问题是没有边界:左边是灰字 meta、右边是 22px 大金额,一条 13px
   的蓝字夹在中间既不像按钮也读不出层级。
   **按钮里不带箭头**(2026-08-03 按用户要求去掉,不是漏写):有了边框与底色,「这是
   个能点的东西」已经说清楚了,箭头是第二遍;.shop-cs 那颗带的是前置的客服图标、
   不是箭头,照它抄的是几何与配色,别顺手把图标或箭头补进来。 */
.ord-cs {
  flex: none; height: 36px; padding: 0 14px; border-radius: 10px; box-sizing: border-box;
  display: flex; align-items: center;
  background: #ffffff; border: 1px solid rgba(27, 107, 255, .35); color: #1B6BFF;
  font-size: 14px; font-weight: 600;
  transition: background-color .2s ease, border-color .2s ease;
}
.ord-cs:hover { background: rgba(46, 124, 255, .08); border-color: rgba(27, 107, 255, .55); }
.ord-cs:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
/* ── 卡脚那颗「评价」──
   **它整套穿的是 `.ord-cs`**(标记上两个类一起写),这里只补一件事:装图标要 flex。
   两颗并排的同档卡级动作长得一样才读得出是一组 —— 详情页卖家条那两颗拆过主次分档,
   当场被推翻(见 CLAUDE.md 那条)。所以别在这里覆盖高度、圆角或边框色。
   **2026-08-06 从商品行右端挪来**,那一版的 `.ord-rev-slot` 定宽占位与 28 高的小按钮
   **已整套删净,不是漏写**:位置进了卡脚,粒度就跟着变成整笔单,那个「三行金额
   右缘要对齐」的问题也随之不存在了。 */
.ord-rev-btn { cursor: pointer; }
/* 已评价的退成灰(边框一起退):蓝是站内「这里要你动手」的语义,而这件事已经做完了。
   **它仍然可点** —— 点开是只读的回看(2026-08-07 按用户「评价完可以点击显示评价
   内容」),所以 hover 照旧要有反馈;不能改与看不了是两回事。同日中间做过一版
   **点不动的静态标记 `.ord-rev-done`**(连同那枚金星与星数),**已删净,不是漏写**。
   **按钮上不印星星也不印星数**(同日按用户要求):那枚金星是这一行里最饱和的东西,
   而卡脚已经有实付金额与「联系卖家」在争,一个回看入口占不起。 */
.ord-rev-btn.is-done { border-color: rgba(13, 38, 90, .14); color: rgba(30, 50, 80, .72); }
.ord-rev-btn.is-done:hover { background: rgba(13, 38, 90, .04); border-color: rgba(13, 38, 90, .22); }
/* ── 支付结果页 ──────────────────────────────────────────────────── */
.done-wrap { max-width: 900px; margin-inline: auto; }
.done-hero {
  margin-top: 24px; padding: 44px 40px; box-sizing: border-box; text-align: center;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 22px;
  box-shadow: 0 10px 30px rgba(13, 38, 90, .07);
  display: flex; flex-direction: column; align-items: center;
}
.done-tick {
  width: 62px; height: 62px; border-radius: 50%;
  background: linear-gradient(135deg, #34D399, #0E7D45);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 12px 30px rgba(14, 125, 69, .34);
  animation: adPop .35s var(--ease-out);
}
.done-title { margin: 18px 0 0; font-size: 30px; line-height: 38px; font-weight: 700; color: #0C1626; }
.done-sub { margin: 10px 0 0; font-size: 14px; line-height: 21px; color: rgba(30, 50, 80, .7); }
.done-sub b { color: #0C1626; letter-spacing: .04em; }
.done-note { margin: 6px 0 0; font-size: 14px; line-height: 21px; color: rgba(30, 50, 80, .7); max-width: 560px; }
.done-acts { margin-top: 20px; display: flex; gap: 10px; }

/* ── 订单页的会话两栏(左会话列表 / 右对话)────────────────────────── */
/* **两栏定高、填满视口剩余高度,左右等高、各自内滚** —— 这是全站唯一一处,
   IM 该是一屏应用而不是一篇随页面滚的长文(2026-08-03 按用户「最好占满一个页面」)。
   316 = 两栏顶边 300 + 底部呼吸位 16。**300 是量出来的**(面包屑 192 + 44 高,
   ord-tabs 244 + 40 高,再加 16 上边距),`.messages-view` 上面任何一块的间距一变
   都要重量这个数。它只跟宽度定死的页级 chrome 有关,与视口高度无关。

   本页当天早些时候先走过一版「两栏都不定高、页面整体滚动」,理由是 1440×720 下
   定高会让对话区只剩 280、卡密被切一半。**那一版的病根不是定高,是当时两栏上面
   还堆着页级标题(chrome 417)**;标题删掉之后 chrome 落到 300,720 视口下两栏
   仍有 404、对话区 265,放得下一张订单卡。所以定高回来了 —— 但**改这里之前
   照旧要在 720 高的窗口上量一遍**,那条教训本身没过期。

   `min-height: 320` 兜的是更矮的窗口:低于它就不再压缩,宁可溢出一点也不让
   对话区塌到不可用(旧版那个 420 定得太高才会在 720 上溢出 67)。

   **240 = 300 − 76 + 16**(2026-08-03 按用户「这里可以再往下」从 316 改过来):
   316 那个数只在 scrollY=0 时成立 —— 面包屑 44 + tab 条 40 连同间距共 154px
   一滚就进了吸顶头部,两栏跟着往上走,底下当场空出 154 + 16 = 170。加高的这
   76 就是尾部呼吸位 `.tail-spacer` 的高度(它仍留着,见下面 sticky 那条),
   滚动后的空隙因此从 170 收到 94。**代价是 scrollY=0 时两栏底边比视口低 60**,
   发送框要往下滚一小段才看得见 —— 这是用户明确接受的取舍。想连那 94 也去掉
   得再加 154(总计 `calc(100vh - 162px)`),那样落地时发送框会低到折叠线下
   138,没走这条。

   `position: sticky` 的可滑动行程 = 两栏底边到 `.messages-view` 底边的距离,
   也就是 `.tail-spacer` 那 76 —— 所以 scroll 154~230 这一段两栏钉在 146 不动,
   过了才继续往上滚去露页脚。**这也是不能把 tail-spacer 删掉换成加高 76 的原因**:
   删了行程归零,sticky 写了也不生效(同 `.pdp-rail` 那条)。 */
/* **上边距是 0,不是 16**(2026-08-03 按用户「这上面有点空」改):`.crumb` 自带
   `padding-bottom: 18`,那就是面包屑与正文之间的那道间隔,再加一层 margin 等于把
   同一道间隔算两遍。站内实测的通例正是 0 —— 报价页 / 合作伙伴 / 说明页的第一块
   都紧贴着 crumb 的内边距开始,隔壁 `#/orders` 是 4;`#/cart` 与个人中心那 18 是
   `.solo-head` 自己的,而这一页没有页级标题。改完导航条到卡片这一带从 84 收到 68,
   其中 24 是全站统一的「第一件东西落在导航条下方 24」,动不得。 */
/* **2026-08-05:面包屑挪回两栏之上,常数跟着加回 240**(= 顶边 236 + 底部留 4)。
   沿革是「240 → 196 → 240」:2026-08-04 收进卡里省掉那 44px 的 chrome,顶边上到 192;
   2026-08-05 用户看过卡内的两种排法(一行 / 两行)都说不好看,挪回卡外,顶边落回 236。
   **这两个数是一套的**:上面任何一块的间距一变,就要重量顶边再改这个常数,
   不改的话底边会离视口底差出同样的量(实测漏改时底边缩到视口上方 48)。
   **卡内面包屑那套 `.msg-crumb*` 已整块删净,不是漏写** —— 卡里放不下它:一行排开
   右边空 53%,堆两行又与紧挨的 tab 条叠成两层标题。别照 08-04 / 08-05 那两版记录
   再做回去。 */
.msg-wrap {
  display: flex; gap: 16px;
  position: sticky; top: 146px;
  height: calc(100vh - 240px); min-height: 320px;
}

.msg-rail, .msg-main {
  box-sizing: border-box;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  display: flex; flex-direction: column; overflow: hidden;
}
/* 左栏不再 sticky:两栏已经等高且都在视口内,sticky 的可滑动行程恒为 0,写了也
   不生效(同 `.pdp-rail` 那条)。会话列表改成在白卡内部自己滚 —— 比 sticky 更强,
   长对话时左栏连滚都不用滚就整列在眼前。 */
/* **宽度 260,2026-08-05 从 340 收窄**(用户报「自营只有一个对话窗口,左边太空了」)。
   这一列天生装不满:自营 tab 恒定只有 1 条会话(67px),而列表区在 1440×900 下是
   548 —— 空 481px(88%);市场卖家 2 条也才 134,空 414。收窄不改变空白**率**
   (列表区高度由两栏定高决定,与宽度无关),但把空白面积压掉 24%,省下的 80 归对话区。
   **260 是量出来的下界,别再往下收**:最长店名「faorbit 官方自营」14/600 实测 107px,
   而会话行留给店名的可用宽 = 栏宽 − 2 边框 − 16 列表内边距 − 24 行内边距 − 40 头像
   − 10 gap − 8 gap − 35 时间列;260 下得 125(余 18),**240 只有 105,当场截断**。
   换 logo 或加长商家名后照这个式子重算。tab 与面包屑不是瓶颈(两枚 tab 文字
   84 / 60,各分 129;面包屑「首页 › 消息中心」零截断)。
   **会话行的行高 67 一并不动**:收紧头像与内边距只会让列表内容更矮、空白更多,
   与这次要解决的问题正相反。 */
.msg-rail { width: 260px; flex: none; }
.msg-main { flex: 1; min-width: 0; }

.msg-filters {
  flex: none; padding: 14px; border-bottom: 1px solid rgba(13, 38, 90, .07);
  display: flex; flex-direction: column; gap: 10px;
}
/* flex:1 + 内滚:会话再多也只在白卡内部滚,左栏底边永远与对话区齐平。
   **内边距 7 不是 8**(2026-08-05):面包屑挪回卡外之后,两栏矮了 44 而卡内只少了
   43 —— 净差 1px,1366×720 的自营 tab 会为这 1px 挂一条滚动条(列表 367 装 368)。
   会话行自己带 12 的内边距,这一层只是列表与卡壁之间的呼吸位,7 与 8 视觉无差别。
   **这一档一个像素的富余都没有**,加 FAQ 条目或改这里的内边距前照判据重量:
   自营 tab + 1366×720 下 `scrollHeight` 不得超过 `clientHeight`。 */
.msg-convs { flex: 1; overflow-y: auto; padding: 7px; }
.msg-none { margin: 0; padding: 26px 14px; text-align: center; font-size: 13px; line-height: 19px; color: rgba(30, 50, 80, .7); }

.msg-conv {
  box-sizing: border-box; width: 100%; padding: 12px; cursor: pointer;
  border: none; border-radius: 12px; background: none; text-align: left;
  display: flex; align-items: center; gap: 10px;
  transition: background-color .2s var(--ease-out);
}
/* **hover 是中性灰,选中才是蓝**(2026-08-05 照参考站改):旧版两态同为
   `rgba(46,124,255,.07 / .12)` —— 同一个色相只差 5 点透明度,鼠标扫过一条没选中的
   会话时它看着已经半选中了,而左栏同时只有一条是真选中的,这个歧义正好落在
   最要紧的那一列上。蓝留给「这条是当前会话」一件事,hover 只负责说「指到这了」。 */
.msg-conv:hover { background: rgba(13, 38, 90, .04); }
.msg-conv.is-active { background: rgba(46, 124, 255, .12); }
.msg-conv.is-active:hover { background: rgba(46, 124, 255, .12); }
.msg-conv-av { width: 40px; height: 40px; font-size: 15px; }
.msg-conv-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.msg-conv-top { display: flex; align-items: baseline; gap: 8px; }
/* 店名与摘要都单行截断:两行摘要会让每条会话高矮不一,一眼数不清左栏有几条 */
.msg-conv-name {
  flex: 1; min-width: 0; font-size: 14px; font-weight: 600; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 今天只印 hh:mm、今年只印 MM-DD:整串 2026-07-31 是 10 个字符,在 340 的栏里
   直接吃掉店名的位置(而年份对「哪条最近」这个问题没有信息量)。 */
/* 次要文字的浅度有下限:12–13px 正文要 4.5:1。旧的 .5 / .62 实测只有
   **2.51 / 3.47**,与报价卡「已售」当年从 .45 提到 .7 是同一个老问题 ——
   层级靠字号与字重拉开就够,不必再把颜色压到读不出。 */
.msg-conv-at { flex: none; font-size: 12px; color: rgba(30, 50, 80, .72); font-variant-numeric: tabular-nums; }
.msg-conv-sub {
  font-size: 13px; line-height: 19px; color: rgba(30, 50, 80, .75);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 会话列表底下的「常见问题」(2026-08-05 加,理由与「点一条 = 发出去」的取舍见
   js 里 `faqHtml` 那段)。**左内边距 12,与 `.msg-conv` 的一致** —— 两块都坐在
   `.msg-convs` 的 8 内边距里,文字左缘因此同为 20,不然这一块会比上面的会话行缩进。
   分隔线跟着内边距走、不用负 margin 拉通宽:它分的是列表里的两块内容,不是卡片的
   两个区。 */
/* **上边距 0,不是 10**:分隔线上方那点空隙由会话行自己的 12 内边距顶着,而这 10 是
   720 视口下的救命钱 —— 那一档列表区只有 368,一条会话 67 + 这一块 285 恰好 368,
   多 10 就要为「1 条会话 + 6 颗按钮」挂一条滚动条,在 260 的窄栏里格外显眼。
   加条目或改内边距后照这个数重量(判据:自营 tab + 1366×720 下 `scrollHeight`
   不得超过 `clientHeight`)。 */
.msg-faq { padding: 14px 12px 0; border-top: 1px solid rgba(13, 38, 90, .07); }
/* 组标签那一档:14/20 的 600 近黑、无字距(同 `.off-label` / `.co-label`)。
   `flex` 是为了把「全部」推到行右端 —— 它挂在标题行上而不是独占一行,理由见
   `faqHtml`(独占一行要多 29px,而 1366×720 那档一点富余都没有)。 */
.msg-faq-t {
  margin: 0 0 10px; display: flex; align-items: baseline; gap: 8px;
  font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626;
}
/* 借客服回复里那枚 `.msg-link` 的浅蓝底 + 13/600 蓝字 —— 两者是同一件事的两个方向
   (那是客服递过来的落点,这是我递过去的问题),不新造一种表面。
   **圆角 10 不是 12**:这一页只有三档(壳 18 / 面 12 / 小方块与图标 10),这几颗比
   会话行小一档,落在最末那档;别在这一层引入第四个值。
   **形态是整行按钮不是横排 chip**:260 的窄栏里横排会按字数断成长短不一的几行,
   而这 6 条是一份可以竖着扫的清单。
   **不进文件末尾那份 `:active` 按压名单**:同 `.msg-conv` 那条,它 hover 只换底色,
   而按下去的回执是「一条消息当场发了出去」,比缩一下明确得多。 */
/* **它是 button 不是 `<a>`**(2026-08-05 定稿,点一条把这句话发进右边的对话,人不
   离开这一页;中途做过一版跳 `#/faq/<id>` 的 `<a>`,已按用户要求改回,见 `faqHtml`)。
   字体与字重由全局那条 `button { font-family: inherit; font-weight: inherit }` 兜住,
   这里只需要按下去像一行清单:`display:block` + `width:100%` + 左对齐。 */
.msg-faq-q {
  display: block; box-sizing: border-box; width: 100%;
  padding: 8px 12px; border: none; border-radius: 10px; cursor: pointer;
  background: rgba(46, 124, 255, .09); color: #1B5FE8; text-align: left;
  font-size: 13px; line-height: 19px; font-weight: 600;
  transition: background-color .2s var(--ease-out);
}
.msg-faq-q + .msg-faq-q { margin-top: 6px; }
.msg-faq-q:hover { background: rgba(46, 124, 255, .17); }
/* 「全部」:通往正主的出口,坐在标题行右端。**不套那六条的浅蓝底** —— 底色是
   「这是一条问题」的标记,给它套上就成了第七条问题。13px 比标题小一档,是次要出口。
   `margin-left:auto` 把它推到行尾;svg 没有基线,标题行是 baseline 对齐,所以这里
   单独用 flex + center 把箭头与文字对上。 */
.msg-faq-all {
  margin-left: auto; align-self: center;
  display: flex; align-items: center; gap: 3px;
  font-size: 13px; line-height: 19px; font-weight: 600; color: #1B5FE8;
}
.msg-faq-all:hover { text-decoration: underline; color: #1B5FE8; }

/* **这一条与 `.msg-foot` 是这一页仅有的两块 chrome,几何按「尽量少占」定**
   (2026-08-04 按用户「上面和下面这两个地方减少占画面比例」改)。收成单行之后
   高度**由头像撑着、不由文字**:店名那行只有 22 高,44 的头像连内边距共 71px,
   在 720 视口下占对话栏的 **14.8%**,而它一共只印一个店名。头像收到 34、内边距
   13 → 10 之后是 **55**(10 + 34 + 10 + 1 边框),省下的 16 全部归对话区。
   **别再把头像放回 44** —— 这一行不是「挑卖家」的场合(那是店铺页与报价卡),
   人已经在这条会话里,头像只是认一下这是谁,34 与左栏会话行的 40 同一个量级。 */
.msg-head {
  flex: none; padding: 10px 20px; border-bottom: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: center; gap: 12px;
}
/* 字号跟着圆一起收:16 是配 44 的,放进 34 的圆里首字母会顶到边 */
.msg-head-av { width: 34px; height: 34px; font-size: 14px; }
/* 店名与「买过几件」竖排成一列(副标 2026-08-04 恢复):flex:1 + min-width:0 移到
   这层壳上,两行各自省略号,长店名不会把「进店逛逛」挤出去。 */
.msg-head-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.msg-head-name {
  min-width: 0; font-size: 16px; font-weight: 600; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 13px 次要文字的对比度下限 4.5:1,同 `.msg-conv-sub` 那条,别再往浅了压 */
.msg-head-sub {
  font-size: 13px; line-height: 18px; color: rgba(30, 50, 80, .75);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.msg-head-shop { flex: none; display: flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 700; color: #1B5FE8; }
.msg-head-shop:hover { text-decoration: underline; }

/* 对话区压一层比页底更深的灰蓝:气泡是白的,底色只比页底深一级(#F7F9FD vs #F4F7FC)
   时,白气泡全靠一条 .08 的描边硬撑,读起来是「一片白上画了几个框」而不是
   「几块牌子摆在台面上」。台面压深之后描边才退成收边而不是唯一的分界。 */
/* flex:1 + 内滚:两栏定高之后,消息区吃掉头尾之外的全部高度,输入框因此恒贴在
   白卡底边、永远够得着。`min-height` 不再需要(高度由 flex 分配,塌不下去)。 */
/* 台面 `#F7F8FA`(2026-08-05 按用户要求照参考站改,旧值 `#EDF1F8`)。旧的那档比页底
   深一档、还带蓝调,把对话区做成了整页最重的一块;新的这档只比白低 3 点明度、不带
   色相,气泡与卡片浮在上面。**与上面气泡去描边是一套的**:台面浅到这一档,白气泡
   才只需要一层贴边投影;哪天台面改回深蓝灰,描边要跟着回来,否则气泡会糊进底色。
   我 2026-08-05 早些时候按自己的判断否决过这一改(怕退回「一片白上画了几个框」),
   用户看了参考站后明确要这一套 —— **别照那条旧记录改回去**。 */
.msg-body { flex: 1; overflow-y: auto; padding: 20px 22px; background: #F7F8FA; }
.msg-empty { margin: auto; }

/* 间距写 margin-top 不写 bottom:分组要收的是「这一条与上一条之间」,而 CSS
   看不到下一个兄弟,只有把间距挂在后一条身上才管得住。 */
.msg-row { display: flex; align-items: flex-end; gap: 8px; margin-top: 18px; }
.msg-body > :first-child { margin-top: 0; }
.msg-row.is-me { flex-direction: row-reverse; }
/* 同一侧连着说的收到 6:一串自己的话之间留 16 会读成三件不相干的事 */
.msg-row.is-cont { margin-top: 6px; }
.msg-bubble {
  max-width: 560px; box-sizing: border-box; padding: 12px 14px;
  /* 四角一律 12,与输入框 / 发送 / 会话行同档(2026-08-04 分两步定:先撤掉 5px 的
     指向尖角,用户仍说不舒服,量完全页才发现真正的病灶是 14 与 12 的**近似撞档**)。
     判据是量出来的:这一页的「面」层元素共 10 类(气泡 / 订单卡 / 引用卡 / 选单浮层
     / 会话行 / 搜索框 / 输入框 / 发送 / 订单按钮 / 卡密块),原先 4 类写 14、6 类写 12
     —— 差 2px 在同屏相邻(气泡就压在输入框正上方)时读不出是两档,只读得出「没对齐」。
     全站 12 也是主导值(31 处 vs 14 的 15 处)。收完这一页只剩三档:壳 18 / 面 12 /
     小方块与图标 10。**别再往这一层引入第四个值。** */
  border-radius: 12px;
  /* **没有描边,只有一层贴边投影**(2026-08-05 按用户要求照参考站改;旧值是
     `1px rgba(13,38,90,.07)` + 同一层投影)。描边 + 投影两样一起用是这一栏「重」的
     来源 —— 一条边把气泡钉在台面上,投影又要把它托起来,两个相反的说法叠在同一个
     元素上。参考站只留投影。**它跟下面 `.msg-body` 的近白台面是一套**:台面浅到
     那一档,白气泡才需要投影来分离;台面若改回深蓝灰,描边就得跟着回来。 */
  background: #ffffff; border: 1px solid transparent;
  box-shadow: 0 1px 2px rgba(13, 38, 90, .06);
  /* **行高 25 = 14 × 1.79,不是正文那档 1.5**(2026-08-05 照参考站改,旧值 21)。
     气泡里是**连续的口语句子**,一条客服回复常有三四行(实测「这个问题自动应答
     答不了……」那条在 560 里就是 3 行),1.5 的行距在这种成段短文里读起来是挤的;
     而站内 14/21 那档配的是卡片上的单行字段与两行 clamp,不是同一种东西。
     气泡是 `max-width` 由内容撑的,加行高只让它自己长高,不影响任何对齐。 */
  font-size: 14px; line-height: 25px; color: #0C1626;
  text-wrap: pretty;
}
.msg-row.is-me .msg-bubble {
  background: #1B6BFF; border-color: #1B6BFF; color: #ffffff;
  /* 投影从 `0 2px 10px/.22` 收到贴边的一层(2026-08-05 照参考站):10px 的扩散在
     一串连发的气泡上会糊成一片蓝雾,而气泡本来就靠满色与台面分开、不需要再浮起来。
     白气泡那边本来就是 `0 1px 2px/.05`,收完两侧才是同一种分量。 */
  box-shadow: 0 1px 3px rgba(27, 107, 255, .18);
}
/* 订单卡自己带底与边框,气泡退成纯容器 */
/* **行高要复位回 21**(2026-08-05 随气泡抬到 25 时补):卡里是「单号 / 商品名 /
   数量 / 卡密」这类**单行字段**,不是成段的口语句子,那 25 的依据在这里不成立;
   而 `.ord-no` / `.ord-name` / `.ord-qty` 都没写自己的行高,不复位就会整张卡被
   撑高(720 视口下订单卡本来就是刚好完整可见的 183)。加新的卡型消息时照此办理。 */
.msg-bubble.is-card { max-width: none; padding: 0; background: none; border: none; box-shadow: none; line-height: 21px; }
.msg-at { flex: none; display: flex; align-items: center; gap: 6px; font-size: 12px; color: rgba(30, 50, 80, .72); font-variant-numeric: tabular-nums; }

/* 日期分隔条。有了它,每条气泡就只需要印 hh:mm —— 同一天里把日期重复十几遍,
   而真正会被问起的「这是哪天的事」反倒要一条条比对。 */
.msg-day { margin-top: 20px; display: flex; justify-content: center; }
.msg-day span {
  padding: 3px 11px; border-radius: 999px;
  background: rgba(13, 38, 90, .06); color: rgba(30, 50, 80, .75);
  font-size: 12px; line-height: 16px;
}

/* 新消息的入场:只给**追加**的那一条(msgAppend 挂 is-new),不给整屏重渲染。
   换会话是一天里要做几十次的动作,让十几条气泡每次都飞一遍就是纯噪点;
   而发出去的那一条不带任何进入过程,看着像页面自己刷新了一下。
   位移只有 6px 且没有 to 帧 —— 减弱动效把 animation-duration 压成 0 时,
   元素直接落在自然状态上,不需要另写一份。 */
@keyframes msgIn { from { opacity: 0; transform: translateY(6px); } }
.msg-row.is-new { animation: msgIn .2s var(--ease-out); }
/* 回复里的落点是**动作**,不是正文里的引用链接,所以走 chip 而不是竖排文字链:
   竖排两条蓝字读起来像气泡正文的一部分,而它们是「点这里去解决」。
   chip 借的是站内已有的 .off-chip 那套圆角浅底,不新造一种表面。 */
.msg-links { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; }
.msg-link {
  display: inline-flex; align-items: center; gap: 5px;
  height: 28px; padding: 0 12px; border-radius: 999px;
  background: rgba(46, 124, 255, .09); color: #1B5FE8;
  /* 700 → 600(2026-08-04):它坐在气泡正文(14/400)下面,700 的蓝字比它引用的
     那段话还重,读起来是气泡的标题而不是「点这里去解决」。 */
  font-size: 13px; font-weight: 600;
  transition: background-color .2s var(--ease-out);
}
.msg-link:hover { background: rgba(46, 124, 255, .17); }

.msg-typing { display: flex; align-items: center; gap: 5px; padding: 15px; }
.msg-typing i { width: 6px; height: 6px; border-radius: 50%; background: rgba(30, 50, 80, .38); animation: msgDot 1s infinite ease-in-out; }
.msg-typing i:nth-child(2) { animation-delay: .15s; }
.msg-typing i:nth-child(3) { animation-delay: .3s; }
@keyframes msgDot {
  0%, 60%, 100% { opacity: .3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* 订单卡消息。宽度与文字气泡的上限**对齐到同一个 560**:它是本页的主角
   (用户来这一页十有八九就是为了卡上那串卡密),按 440 缩着摆在 1010 宽的对话区里,
   右边空一大片、卡密那行还得折;对齐之后左侧所有内容共用一条右缘。 */
/* 四角 12,同 `.msg-bubble`(2026-08-04 分两步:先撤 5px 尖角,再把整层从 14 收到 12,
   理由见 `.msg-bubble` 那段的量化判据)。 */
.msg-ord {
  box-sizing: border-box; width: 560px; padding: 13px 16px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .07); border-radius: 12px;
  box-shadow: 0 1px 2px rgba(13, 38, 90, .05);
  transition: border-color .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
/* 搜到的那一张:左栏搜索命中订单号时高亮并滚进视野,否则一条会话里十几张卡
   全长一个样,搜完还得自己一张张找。 */
.msg-ord.is-hit { border-color: #1B6BFF; box-shadow: 0 0 0 4px rgba(46, 124, 255, .14); }
.msg-ord-top { display: flex; align-items: center; gap: 10px; padding-bottom: 9px; border-bottom: 1px solid rgba(13, 38, 90, .07); }
.msg-ord .ord-item { padding: 11px 0 7px; }
.msg-ord .ord-key { margin-bottom: 0; }

/* 上下内边距 12 → 9(2026-08-04,同 `.msg-head` 那条):高 67 → **61**。
   **控件高 42 不动** —— 站内输入框基线是 42(`.off-field`)与 46(`.shop-q`),
   单给这一处改成 38 就是全站最矮的一个,而省下的只有 4px;这一块能收的本来就是
   内边距,42 的框贴着白卡底边留 9 已经够了。 */
.msg-foot { flex: none; padding: 9px 16px; border-top: 1px solid rgba(13, 38, 90, .07); display: flex; gap: 10px; }
.msg-input {
  flex: 1; min-width: 0; box-sizing: border-box; height: 42px; padding: 0 14px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .12); border-radius: 12px; outline: none;
  font-size: 14px; color: #0C1626;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.msg-input:focus { border-color: rgba(27, 107, 255, .6); box-shadow: 0 0 0 4px rgba(46, 124, 255, .14); }
.msg-send {
  flex: none; height: 42px; padding: 0 22px; border: none; border-radius: 12px; cursor: pointer;
  background: #1B6BFF; color: #ffffff; font-size: 14px; font-weight: 700;
  transition: background-color .2s var(--ease-out), transform .2s var(--ease-out);
}
.msg-send:hover { background: #1558D6; }
/* 空输入时真禁用,不是只让它点不出效果:一颗满色的主按钮点下去什么也不发生,
   用户第一反应是发送坏了,而不是「我还没打字」。 */
.msg-send:disabled { background: rgba(13, 38, 90, .1); color: rgba(30, 50, 80, .55); cursor: not-allowed; }
.msg-send:disabled:hover { background: rgba(13, 38, 90, .1); }

/* ── 上传入口(输入栏左侧的「+」)────────────────────────────────
   按钮坐在输入框左边、与它同高:它和输入框是同一件事的两种说法(「我要附一样
   东西上来」/「我要说的是这句话」),分成上下两行反而读不出这层关系。 */
/* 输入栏左侧的工具按钮。**「订单」「商品」两颗选择器 2026-08-05 已整块删掉**
   (按用户要求,不是漏写;理由见 js/main.js 里原址那段注释:进客服的两条路现在
   都自带上下文,不必再指一遍),`.msg-pick*` / `.pick-*` 两组 CSS 一并删净。
   换上来的是**上传入口**,沿用这一档控件的表面参数。
   **2026-08-05 晚些时候又从「图片」「文件」两颗药丸收成一颗 42 见方的「+」**
   (按用户要求):两颗带图标带文字的药丸横占 152px,而附件是这一页的次要入口
   (主动作是打字与发送),那 110px 该还给输入框;两类的名字挪进展开的菜单里
   说,accept 仍是各是各的(见 js 里 msgUploadHtml 那段)。
   `position: relative` 是菜单的定位基准,别删。 */
.msg-up { flex: none; position: relative; }
.msg-tool {
  width: 42px; height: 42px; border-radius: 12px; cursor: pointer;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .12);
  display: flex; align-items: center; justify-content: center;
  color: rgba(30, 50, 80, .78);
  transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.msg-tool:hover { border-color: rgba(27, 107, 255, .5); color: #1B5FE8; background: rgba(46, 124, 255, .05); }
/* 菜单开着时按钮要看得出是它开的(2026-08-05 照参考站补;此前开合之间按钮一个像素
   都不变)。加号转 45° 变成叉,一下说清「现在是开的」与「再点就关」——
   底色变化只能说前一半。转的是 svg 不是按钮,按钮上还有边框与底色要保持不动。 */
.msg-tool svg { transition: transform .2s var(--ease-out); }
.msg-tool.is-open { border-color: rgba(27, 107, 255, .5); color: #1B5FE8; background: rgba(46, 124, 255, .09); }
.msg-tool.is-open svg { transform: rotate(45deg); }

/* 菜单坐在按钮**上方**(输入栏贴着卡底,往下没有地方),所以入场是 popUp、
   收起的 .is-out 要跟着反过来(见文件末尾那节)。表面参数照 .head-pop 那张白卡,
   不新造一种。 */
.msg-up-pop {
  position: absolute; left: 0; bottom: calc(100% + 8px); z-index: 5;
  /* **`width: max-content` 是必须的**:absolute 元素按 shrink-to-fit 算宽,上限是
     包含块 —— 而包含块 `.msg-up` 只有 42px(那颗方按钮),所以菜单会一路被压到
     `min-width` 那 140 上、内容自己折行。行里只有「图片」两个字时正好看不出来,
     2026-08-05 补上格式小字后当场折成四行(实测)。 */
  width: max-content; min-width: 140px; padding: 6px; box-sizing: border-box;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .1); border-radius: 12px;
  box-shadow: 0 14px 34px rgba(13, 38, 90, .14);
  display: flex; flex-direction: column; gap: 2px;
  animation: popUp .15s var(--ease-out);
}
/* [hidden] 配 display:flex 藏不掉(同 .co-sum-row 那几处) */
.msg-up-pop[hidden] { display: none; }
/* 行的几何与字重照顶栏下拉的 `.head-pop-row` 一个字不改(34 / 9 / 14/600):
   站内的「浮层里的一行可点选项」就这一种长相,单给这里取一个中间值(做过一版
   36 / 8)就是往这一层引入第四档表面 —— 同这一页圆角那条。 */
.msg-up-row {
  width: 100%; height: 34px; padding: 0 10px; border: none; border-radius: 9px; cursor: pointer;
  background: transparent; display: flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 600; color: #0C1626; text-align: left;
  transition: background-color .2s ease, color .2s ease;
}
.msg-up-row:hover { background: rgba(46, 124, 255, .09); color: #1B5FE8; }
.msg-up-row svg { flex: none; display: block; }
/* 主标签与格式小字**并排、基线对齐**,不是堆成两行 —— 并排不占额外高度,所以
   上面那条「行高照 .head-pop-row 的 34 一个字不改」没被破(实测仍是 34);
   堆两行就要放到 44,那就是往这一层引入第四档表面了。 */
.msg-up-text { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 6px; }
/* 11px 是徽章那一档的字号(全站抬一档时明确不抬的两类之一),这里同理:它是括号里的
   补充,压到 11 才不会跟 14/600 的标签抢。色值仍要过 4.5:1 —— 参考站那个 #c2c6cc
   在白底上只有 2.1,照抄就是一行看不清的说明。 */
.msg-up-text em {
  font-style: normal; font-size: 11px; font-weight: 500;
  color: rgba(30, 50, 80, .62);
}
.msg-up-row:hover .msg-up-text em { color: rgba(27, 95, 232, .75); }

/* ── 附件气泡(图片 / 文件)────────────────────────────────────────
   **没有后端,所以这里不演上传进度**:图片压成一张缩略图存本机,文件只存名称与
   大小(见 js 里 msgSendFile 那段)。
   图片直接铺一张图、不再套文件名那一行 —— 它自己就是内容;`.msg-bubble.is-card`
   已经把气泡的内边距去掉了,所以图片的圆角要自己写(12,同这一页那三档里的「面」)。 */
/* **图片自己定尺寸,别写 `width: 100%`**:气泡是收缩包裹的(`max-width` 而不是
   `width`),百分比在这里没有基准可算,量出来的宽度是 0 —— 症状是图片发出去了、
   气泡里却什么都看不见。所以走 `max-width` + `height: auto`,横图按 320 收、
   竖图按 260 高收,两条一起才挡得住细长图。 */
.msg-file-img { display: block; }
.msg-file-img img {
  display: block; max-width: 320px; max-height: 260px; height: auto; border-radius: 12px;
  background: rgba(13, 38, 90, .06);
}
/* 文件(与压不出缩略图的图片)走横条卡:图标 + 名称 + 大小。宽度跟着 `.msg-ref`
   那张引用卡的 340 走 —— 同一侧发出去的东西宽度不一致,读起来是两套。
   **没有「下载」按钮**:站内没有后端,那颗按钮点下去什么都不会发生。 */
.msg-file {
  display: flex; align-items: center; gap: 11px;
  box-sizing: border-box; width: 340px; max-width: 100%; padding: 11px 13px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 12px;
  box-shadow: 0 1px 2px rgba(13, 38, 90, .05);
}
.msg-file-ico {
  flex: none; width: 38px; height: 38px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(46, 124, 255, .1); color: #1B5FE8;
}
.msg-file-ico svg { display: block; width: 18px; height: 18px; }
.msg-file-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.msg-file-name {
  font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 12px 次要文字的对比度下限是 4.5:1(这一页那条),别再往浅了压 */
.msg-file-size { font-size: 12px; line-height: 16px; color: rgba(30, 50, 80, .72); }

/* ── 引用的那一单(我发出去的订单卡)────────────────────────────────
   比历史里那张 `.msg-ord` 窄、也不带卡密:它回答的是「我说的是哪一单」,
   卡密在上面那张历史卡里已经印过一次了。
   圆角同 `.msg-ord` 一律 12(2026-08-04):它是同一个东西的另一侧,只改左边那张
   会造出「历史卡一种角、引用卡另一种」的新不一致。 */
.msg-ref {
  display: block; box-sizing: border-box; width: 340px; padding: 11px 13px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 12px;
  box-shadow: 0 1px 2px rgba(13, 38, 90, .05);
}
.msg-ref-cap {
  display: block; margin-bottom: 8px; padding-bottom: 8px;
  border-bottom: 1px solid rgba(13, 38, 90, .07);
  font-size: 12px; line-height: 16px; font-weight: 700; color: #1B5FE8;
}
.msg-ref-row { display: flex; align-items: center; gap: 10px; }
.msg-ref-thumb {
  width: 38px; height: 38px; border-radius: 10px; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: rgba(13, 38, 90, .06);
}
.msg-ref-thumb .prod-ico { width: 38px; height: 38px; border-radius: 10px; }
.msg-ref-thumb .prod-ico img { width: 22px; height: 22px; }
.msg-ref-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.msg-ref-name {
  font-size: 14px; font-weight: 700; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.msg-ref-meta {
  font-size: 12px; line-height: 17px; color: rgba(30, 50, 80, .72);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 「立即发货」这一档给绿,与比价行 `.tp-row-col b.is-fast` 和结算页「免费」同一个
   #0E7D45 —— 站内绿的既有语义就是「快 / 免费」。**其余三档不给颜色**:20 分钟 / 1 小时 /
   12 小时都是常规时效,四档都染绿等于都不跳。不复用 `.is-fast` 是因为那条选择器
   带着 `.tp-row-col b` 祖先,不通用。 */
.msg-ref-fast { color: #0E7D45; font-weight: 600; }
.msg-ref-price { flex: none; font-size: 14px; font-weight: 700; color: #0C1626; }

/* ── 个人中心 ────────────────────────────────────────────────────────
   2026-08-06 照用户给的参考站(HUOAD 用户页)重做:用户卡 → 5 格分段 tab →
   面板。**2026-08-03 那版「收成单分区、限宽 760」被整体推翻** —— `.acct-wrap`
   随之删净(不是漏写),旧注释里那句「资料页是读的东西所以限宽」不再成立:
   这一页现在装的是三张并排的统计卡与订单列表,760 里塞不下。
   **整页全宽**(个人中心本来就在 `hide-on-solo` 名单里,没有侧栏)。

   **只借版式不借橙色**:参考站主色是橙,站内一律 `#1B6BFF`(同招商页那条)。
   **这一页没有任何动作或控件是红的**(2026-08-10):「删除账户」那一行已整行删掉,
   而「退出登录」挪进「账户安全」那一列之后**不染红** —— 红的语义是错误 / 破坏性,
   退出只是清掉「这个人是谁」那三样,数据一条不动。旧注释里「这两个动作照参考站
   留红」已失效。**仅剩的 `#C0261F` 是 `.acct-req` 那两颗必填星号**(表单惯例,
   不是动作标记),别拿它推翻这条,也别为了「清零」去改星号的颜色。

   纵向节奏三档:分区之间 **14**、卡内头部到内容 **14**、卡内小节 **18**
   (同店铺页那条,别往这一层引入第四个数)。 */
.acct-hero {
  box-sizing: border-box; padding: 20px 22px; display: flex; align-items: center; gap: 16px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
}
/* 首字母头像是**正圆**,同店铺页那颗:圆角方块那套形状在站内是**商品**图标
   (`.fcard-ico` / `.sgc-ico`)的,一页里两种东西不该同形。 */
.acct-ava {
  flex: none; width: 64px; height: 64px; border-radius: 50%;
  background: linear-gradient(140deg, #2E7CFF, #8B5CFF);
  display: flex; align-items: center; justify-content: center;
  color: #ffffff; font-size: 26px; font-weight: 700;
}
.acct-hero-body { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.acct-hero-name {
  font-size: 20px; line-height: 28px; font-weight: 700; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.acct-hero-mail {
  display: flex; align-items: center; gap: 7px; min-width: 0;
  font-size: 14px; line-height: 20px; color: rgba(30, 50, 80, .7);
}
.acct-hero-mail svg { flex: none; display: block; }
/* **用户卡右端没有按钮**:「退出登录」2026-08-07 按用户要求挪进了「设置 · 账户安全」
   那一列,`.acct-out` 那颗药丸的整组 CSS 一并删净,不是漏写。08-06 反过来挪过一次
   (从设置挪到这张卡上),别照那条记录再做回去。 */

/* 分段 tab:灰底容器 + 白色选中片,5 格等分铺满(参考站就是这个控件)。
   **站内那几套下划线 tab(`.ord-tabs` / `.gm-tab` / `.shop-tab`)管的是页级 / 列表级
   导航,这一条是「同一块内容的五个面」**,语义不同才另给一种形态;而它 5 格等分、
   填充率恒 100%,所以店铺页那次「文件夹标签填充率只有 16%」的病在这里不成立,
   也不是消息中心被否掉的那种**实心蓝**主按钮态。 */
.acct-tabs {
  margin-top: 14px; box-sizing: border-box; padding: 5px;
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px;
  background: rgba(13, 38, 90, .05); border-radius: 14px;
}
.acct-tab {
  height: 44px; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 7px;
  background: transparent; border: none; border-radius: 10px; cursor: pointer;
  font-family: inherit; font-size: 14px; font-weight: 600; color: rgba(30, 50, 80, .72);
  transition: background-color .2s ease, color .2s ease, box-shadow .2s ease;
}
.acct-tab svg { flex: none; display: block; }
.acct-tab:hover { color: #0C1626; }
/* 两档字重都是 600,只靠底片 + 文字色区分 —— 600/700 的话切一次 tab 每格的文字宽度
   都变,五格跟着抖(同 `.ord-tab` / `.shop-tab` 那条)。 */
.acct-tab.is-on {
  background: #ffffff; color: #0C1626;
  box-shadow: 0 2px 6px rgba(13, 38, 90, .08);
}
.acct-panel { margin-top: 14px; }
/* 换 tab 时整块淡入(同店铺页 `.is-swap`):五屏的形态差得远(统计卡 ↔ 列表 ↔ 表单),
   不给过渡就读作「页面闪了一下」。减弱动效由顶部那条全局规则停掉关键帧。 */
.acct-panel.is-swap { animation: acctSwap .16s var(--ease-out); }
@keyframes acctSwap { from { opacity: 0; } }

.acct-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.acct-stat {
  box-sizing: border-box; padding: 20px; display: flex; flex-direction: column; gap: 10px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
}
.acct-stat-top { display: flex; align-items: center; gap: 10px; }
.acct-stat-k { font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626; }
/* 右上角那枚图标是**蓝**不是参考站的橙,而且只描边不加底盘:它是一个说明性的
   小标记,给它一块底色就会在三张卡上排成一行最响的东西(同店铺页评价那次
   「先把标记本身做足,别急着加背景板」的反面 —— 这里本来就不需要被扫读)。 */
.acct-stat-ico { margin-left: auto; flex: none; display: flex; color: #1B6BFF; }
.acct-stat-v { font-size: 30px; line-height: 38px; font-weight: 700; color: #0C1626; }
.acct-stat-sub { font-size: 13px; line-height: 19px; color: rgba(30, 50, 80, .7); }
.acct-stat-cta {
  align-self: flex-start; height: 36px; padding: 0 18px;
  display: inline-flex; align-items: center; border-radius: 10px;
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8);
  color: #ffffff; font-size: 14px; font-weight: 700;
  box-shadow: 0 8px 18px rgba(37, 99, 235, .24);
  transition: transform .15s var(--ease-out), box-shadow .2s ease;
}
.acct-stat-cta:hover { transform: translateY(-2px); color: #ffffff; box-shadow: 0 12px 24px rgba(37, 99, 235, .32); }

.acct-card {
  margin-top: 14px; box-sizing: border-box; padding: 22px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
}
/* 面板里第一张卡紧贴 tab 条,那 14 已经由 `.acct-panel` 的 margin 给过了 */
.acct-panel > .acct-card:first-child, .acct-stats + .acct-card { margin-top: 14px; }
.acct-panel > .acct-card:first-child { margin-top: 0; }
/* 卡头**只有标题**(2026-08-10):`.acct-sec-head` 外壳与 `.acct-sec-sub` 一并删净,
   不是漏写 —— 那六条副标里五条与标题逐字同义,理由与先例见 `acctSecHead` 上方。
   14 的间距因此挪到标题自己身上。 */
.acct-sec-title { margin: 0 0 14px; font-size: 18px; line-height: 26px; font-weight: 700; color: #0C1626; }
.acct-sub-title { margin: 18px 0 12px; font-size: 15px; line-height: 22px; font-weight: 700; color: #0C1626; }

/* 订单简行。逐条 hairline 分隔(同店铺页评价列表),首条不画线 —— 上面就是章节头。 */
.acct-ords { display: flex; flex-direction: column; }
.acct-ord {
  padding: 13px 0; display: flex; align-items: center; gap: 14px;
  border-top: 1px solid rgba(13, 38, 90, .07);
  transition: background-color .15s ease;
}
.acct-ords .acct-ord:first-child { border-top: none; }
.acct-ord:hover { background: rgba(46, 124, 255, .04); }
.acct-ord-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.acct-ord-no { font-size: 14px; line-height: 20px; font-weight: 700; color: #0C1626; }
.acct-ord-name {
  font-size: 13px; line-height: 19px; color: rgba(30, 50, 80, .7);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* **右端三列各自定宽,一列都不能跟着内容走**(2026-08-10 修)。病根是 `.ord-status`:
   药丸宽度跟着文字变(「已完成」59 / 「部分待发货」85),它顶在行尾又是 `flex:none`,
   于是把前面的时间与金额一起往左推 —— 实测同一列里时间右缘 1128 / 1102 / 1128、
   金额右缘 1238 / 1212 / 1238,**每碰到一笔待发货的单,上下两列就错开 26px**。
   所以药丸单独包一个定宽的槽、在槽内右对齐(药丸本身仍按文字收缩 —— 给它写
   `min-width` 会把「已完成」那颗拉宽,标签的宽度该跟着字走)。
   三个数都是**在本页量出来的**,别按字符数推算(第一版按比例推出 118,实测要 124.9,
   当场把时间折成两行):128 = 去掉秒的 `2026-08-07 09:32` 等宽下 124.9 + 余量;
   112 = 七位数金额 `$2,543,904.00` 109.2 + 余量(实际最长的 `$42,048.00` 只要 86);
   88 = 「部分待发货」85 + 3。
   `tabular-nums` 是配套的:这两列竖着排,比例数字会让同格式的时间彼此差几 px;
   代价是时间宽了 8(116.9 → 124.9),已经算进上面那个 128。 */
.acct-ord-at {
  flex: none; width: 128px; text-align: right; font-variant-numeric: tabular-nums;
  font-size: 13px; color: rgba(30, 50, 80, .7);
}
.acct-ord-sum {
  flex: none; min-width: 112px; text-align: right; font-variant-numeric: tabular-nums;
  font-size: 15px; font-weight: 700; color: #0C1626;
}
.acct-ord-st { flex: none; width: 88px; display: flex; justify-content: flex-end; }
/* `.ord-status` 自带 `margin-left:auto`(订单卡那边靠它推到行尾),这里由槽定位,
   不复位的话它会在槽内把自己再推一次(结果相同但意图不清)。 */
.acct-ord .ord-status { margin-left: 0; flex: none; }
.acct-more {
  margin-top: 14px; display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; font-weight: 600; color: #1B5FE8;
}
.acct-more:hover { color: #1246B8; }
.acct-more svg { flex: none; display: block; transition: transform .2s var(--ease-out); }
.acct-more:hover svg { transform: translateX(3px); }

.acct-empty {
  padding: 34px 20px 30px; display: flex; flex-direction: column; align-items: center; gap: 8px;
  text-align: center;
}
.acct-empty-art { display: block; margin-bottom: 4px; }
.acct-empty p { margin: 0; font-size: 15px; line-height: 22px; font-weight: 600; color: #0C1626; }
.acct-empty span { font-size: 13px; line-height: 19px; color: rgba(30, 50, 80, .7); max-width: 420px; }

/* 余额大卡:参考站是橙色实心,这里换站内品牌蓝渐变(同 `.solo-cta` / `.promo-main`)。
   按钮必须白底蓝字 —— 蓝底上再放一颗蓝按钮就看不见了。 */
/* **横向排、按钮推到右端**(2026-08-10):竖排那版三样东西(标签 52 / 数字 100 /
   按钮 68)全挤在左侧,而卡宽 1256 —— 一整块高饱和的品牌蓝,91% 的面积是空的。
   同报价卡「每行都要有右端信息」那条(用户当年报的「不协调」,主因就是全部左对齐、
   卡片右半边整片空着)。卡高跟着从 157 落到 107。 */
.acct-bal {
  box-sizing: border-box; padding: 20px 22px; border-radius: 14px;
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8);
  display: flex; align-items: center; gap: 16px;
}
.acct-bal-body { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
/* **纯白,别压成半透明**:白 `.82` 在渐变最亮那端(`#2E7CFF`)只有 **3.09**,而
   13px 的次要文字下限是 4.5(同消息中心那轮体检)。纯白也才 3.86 —— 那是站内在
   蓝渐变上放白字的既有水平(`.solo-cta` 同值),这里不引入比它更差的一档。
   与下面那个 34px 大数字的层级靠**字号**拉开,不靠把颜色洗淡(同报价卡「已售」
   当年从 .45 提回 .7 那条)。 */
.acct-bal-k { font-size: 13px; line-height: 19px; color: #ffffff; }
.acct-bal-v { font-size: 34px; line-height: 42px; font-weight: 700; color: #ffffff; }
.acct-bal-cta {
  margin-left: auto; flex: none; height: 38px; padding: 0 20px;
  display: inline-flex; align-items: center; border-radius: 10px;
  background: #ffffff; color: #1B5FE8; font-size: 14px; font-weight: 700;
  transition: transform .15s var(--ease-out);
}
.acct-bal-cta:hover { transform: translateY(-2px); color: #1B5FE8; }

/* 设置那一屏的输入框。几何与 `.acct-field-v` / `.acct-sel` 严格同参(44 高、12 圆角、
   14px):三样东西在同一张卡上下摆着,差一点就读成没对齐。 */
.acct-in {
  box-sizing: border-box; width: 100%; height: 44px; padding: 0 14px;
  border-radius: 12px; border: 1px solid rgba(13, 38, 90, .12); background: #fff;
  font-family: inherit; font-size: 14px; font-weight: 500; color: #0C1626;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.acct-in::placeholder { color: rgba(30, 50, 80, .45); }
.acct-in:hover { border-color: rgba(46, 124, 255, .45); }
.acct-in:focus-visible {
  outline: none; border-color: #1B6BFF; box-shadow: 0 0 0 3px rgba(46, 124, 255, .16);
}
.acct-req { margin-right: 4px; font-style: normal; color: #C0261F; }
.acct-phone { display: flex; align-items: center; gap: 10px; }
.acct-phone .acct-in { flex: 1; min-width: 0; }
.acct-save {
  margin-top: 18px; height: 44px; padding: 0 22px; border: none; border-radius: 12px; cursor: pointer;
  background: linear-gradient(120deg, #2E7CFF, #1B5FE8);
  font-family: inherit; color: #ffffff; font-size: 14px; font-weight: 700;
  box-shadow: 0 10px 26px rgba(37, 99, 235, .28);
  transition: transform .15s var(--ease-out), box-shadow .2s ease;
}
.acct-save:hover { transform: translateY(-2px); box-shadow: 0 16px 34px rgba(37, 99, 235, .36); }

.acct-sec-rows { display: flex; flex-direction: column; gap: 10px; }
.acct-sec-row {
  box-sizing: border-box; width: 100%; height: 48px; padding: 0 16px;
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .12); border-radius: 12px;
  font-family: inherit; font-size: 14px; font-weight: 600; color: #0C1626;
  transition: background-color .2s ease, border-color .2s ease;
}
.acct-sec-row i { flex: none; display: flex; color: rgba(30, 50, 80, .7); }
.acct-sec-row:hover { background: rgba(46, 124, 255, .04); border-color: rgba(46, 124, 255, .35); }
/* `.is-danger` 三条已随「删除账户」那一行删净,不是漏写(2026-08-10,见 ACCT_SEC_ROWS)。 */

/* 未登录的登录引导。整块居中一张卡,不渲染 tab 与统计卡 —— 那些数字不是这台
   浏览器的真实状态、只是还没登录(理由与头像未登录时收起来同一条)。 */
.acct-gate {
  margin-top: 0; box-sizing: border-box; padding: 64px 30px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center;
}
.acct-gate-ico {
  width: 56px; height: 56px; margin-bottom: 4px; border-radius: 50%;
  background: rgba(46, 124, 255, .1);
  display: flex; align-items: center; justify-content: center;
}
.acct-gate-title { margin: 0; font-size: 22px; line-height: 30px; font-weight: 700; color: #0C1626; }
.acct-gate-sub {
  margin: 0; max-width: 460px; font-size: 14px; line-height: 21px;
  color: rgba(30, 50, 80, .7); text-wrap: pretty;
}
/* 两列,**每一格都是半列**(2026-08-10):个人信息那三格原先全写 `-wide` 通宽,把两列
   栅格整个废掉了 —— 名称 / 邮箱 / 手机都是短值,而通宽是 1256。`.acct-field-wide`
   与 `acctFieldHtml` 的 `o.wide` 分支因此一并删净,不是漏写;真需要通宽格(多行简介
   那类)时照 `.slw-grid` 那边加。取舍理由见 `acctSettingsHtml` 上方。 */
.acct-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.acct-field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.acct-field-k { font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626; }
/* 只读框的样子(参考站的邮箱那格也是灰底只读)。**现在只剩邮箱一格在用** —— 它是
   登录时系统自动匹配的,本来就不该让人点进去打字,所以是带边框的静态块而不是禁用的
   输入框;名称与手机是真的能填,走 `.acct-in`(白底、同参数)。
   **「退出登录」现在是这一屏「账户安全」那一列的一行**(`.acct-sec-row`,2026-08-07
   从用户卡挪回来的;08-06 曾从这里挪出去过)—— 它没有自己的一套样式,别再给它加。 */
.acct-field-v {
  box-sizing: border-box; min-height: 44px; padding: 11px 14px; border-radius: 12px;
  background: rgba(13, 38, 90, .03); border: 1px solid rgba(13, 38, 90, .08);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 14px; line-height: 20px; color: rgba(30, 50, 80, .78);
}
/* 语言 / 币种的下拉。**几何与 `.acct-field-v` 严格同参**(44 高、12 圆角、14px):
   两张卡在同一页上下摆着,只读框与下拉差一点就读成没对齐。区别只在**可交互的信号**:
   白底(只读那格是灰底)+ 自绘 caret + hover / focus 亮蓝边。
   caret 的 `right` 走 `.sel-caret` 基础规则的 12,不覆盖 —— 这个框的内边距 14 与它
   本来就配得上,不像 `.off-sort` / `.sl-sel` 那两处要各自挪。 */
.acct-sel { position: relative; display: block; }
.acct-sel select {
  box-sizing: border-box; width: 100%; height: 44px; padding: 0 34px 0 14px;
  border-radius: 12px; border: 1px solid rgba(13, 38, 90, .12); background: #fff;
  /* 字重 **500**,不是 600(2026-08-04 按用户给的参考图改):站内**控件里的文字**
     一律 14/500 —— 报价页排序下拉 `.off-sort select`、搜索框 `.off-field input`、
     入驻表单输入框都是,同一张卡里的只读值 `.acct-field-v` 也是 500。写 600 让这两个
     下拉成了全站唯一的半粗控件,而且与紧挨着的标签(`.acct-field-k` 14/600 近黑)
     同号同重同色、层级读不出来。**600 是「组标签」那一档的字重**(见「组标签全站
     一个样」那条),控件文字不该借它。 */
  font-family: inherit; font-size: 14px; font-weight: 500; color: #0C1626;
  cursor: pointer; appearance: none; -webkit-appearance: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.acct-sel select:hover { border-color: rgba(46, 124, 255, .45); }
.acct-sel select:focus-visible {
  outline: none; border-color: #1B6BFF; box-shadow: 0 0 0 3px rgba(46, 124, 255, .16);
}
/* `.acct-card-cta` / `.acct-card-note` 2026-08-04 已删(「登录 / 注册」按钮与那句
   「本站没有后端…」的说明)。**它们承担的两件事 2026-08-06 各自有了新落点**:
   登录入口在 `.acct-gate`(未登录时整页就是它),而「换设备查不到」写进了订单 tab
   的空态与 gate 的副标。别再把它们加回来。 */

/* ── 店铺页 ─────────────────────────────────────────────────────────
   2026-08-03 照参考站(huoad 商家店铺页)重做:hero → 悬浮名片 → 章节头 →
   店内搜索 → 分类/排序/视图切换 → 商品区。
   参考站那张真人插画站内没有素材,换成商家自己的品牌渐变(tintA→tintB,与头像、
   报价卡上的卖家头像同源)+ 一枚首字母水印,不引入外部图片。 */
/* 2026-08-04 按用户给的新参考站收窄:那一页的名片几乎顶着页头,上面只露出一条很浅的
   带子。**hero 高 120、名片往上叠 84,可见的只有 36** —— 高饱和的品牌渐变露 36px
   读作一条彩色顶饰,露 136px 才是「一张大 banner」。两个数是一套的,改一个要跟着改另一个。
   **首字母水印跟着删掉,不是漏写**:104px 的字在 36 高的带子里只露得出上沿一截。 */
.shop-hero {
  position: relative; overflow: hidden;
  height: 120px; border-radius: 18px;
}
/* 装饰圆:同 .fcard-top::before 那一套(白 .09 的大圆),不另造一种表面 */
.shop-hero::before, .shop-hero::after {
  content: ""; position: absolute; border-radius: 50%;
  background: rgba(255, 255, 255, .1);
}
/* 两枚圆都落在可见的那 36 里,别照 hero 的整高摆 —— 摆在下半截等于没画 */
.shop-hero::before { width: 300px; height: 300px; right: 150px; top: -276px; }
.shop-hero::after  { width: 190px; height: 190px; right: -46px; top: -166px; }
/* position:relative 是必需的 —— 不写就被 hero 的装饰圆盖住(伪元素算最后一个子节点) */
.shop-card {
  position: relative; margin: -84px 0 0; padding: 22px 24px; box-sizing: border-box;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 18px;
  box-shadow: 0 10px 30px rgba(13, 38, 90, .07);
  display: flex; align-items: flex-start; gap: 20px;
}
/* 圆形而不是圆角方 —— 参考站的店铺头像是正圆,而站内圆角方块那套是**商品**图标
   (`.fcard-ico` / `.sgc-ico`)的形状,同一页两种东西不该同形。 */
.shop-logo {
  flex: none; width: 104px; height: 104px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 40px; font-weight: 700; color: #ffffff;
  box-shadow: 0 10px 24px rgba(13, 38, 90, .18);
}
.shop-body { flex: 1; min-width: 0; }
.shop-top { display: flex; align-items: flex-start; gap: 20px; }
.shop-id { flex: 1; min-width: 0; }
.shop-name {
  margin: 0; font-size: 24px; line-height: 30px; font-weight: 700; color: #0C1626;
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
}
.shop-name .prod-verify { width: 15px; height: 15px; }
/* 店名旁的响应率 pill。照参考站那枚蓝色圆角标,但**用站内蓝**(同「只借版式不借红色」)。
   `margin-left: 4` 是把它与认证盾拉开 —— 盾贴着店名读作店名的一部分,pill 是另一件事。 */
.shop-live {
  margin-left: 4px; padding: 3px 10px; border-radius: 999px;
  display: inline-flex; align-items: center; gap: 5px;
  background: rgba(46, 124, 255, .1); color: #1552CC;
  font-size: 13px; line-height: 18px; font-weight: 600;
}
.shop-live svg { flex: none; display: block; }
.shop-since {
  margin: 10px 0 0; font-size: 14px; line-height: 20px; color: rgba(30, 50, 80, .7);
}
.shop-since b { font-weight: 600; color: #0C1626; }
/* 反馈行:标签灰、数值蓝(照参考站,那两个百分比就是蓝的)。两组之间 32 的间距 ——
   28 以下两组会读成一组四个数。 */
.shop-feed {
  margin: 10px 0 0; display: flex; flex-wrap: wrap; gap: 8px 32px;
  font-size: 14px; line-height: 20px; color: rgba(30, 50, 80, .7);
}
.shop-feed span { display: inline-flex; align-items: baseline; gap: 8px; }
.shop-feed b { font-size: 15px; font-weight: 700; color: #1552CC; }
.shop-feed i { font-style: normal; color: #1552CC; }
.shop-acts { flex: none; display: flex; align-items: center; gap: 12px; }
/* 售前客服。**蓝色实心**(2026-08-03 按用户「显眼一些」从白底蓝边改过来)。
   几何与配色照站内已有的同尺寸主按钮 `.shop-add`(商品行的「加入购物车」),
   不自立一套;只多一层常态阴影 —— 它是这一页页头唯一的行动按钮,而 `.shop-add`
   在列表里每行一个,常态就带阴影会把整页顶得发飘。
   原先做成次级是怕它和 `.shop-add` 互相抢,实际两者一个在页头、一个在列表里,
   语境不同;用户要的是这颗被一眼看见,那条顾虑让位。
   **`color` 必须显式写死** —— 全局的 `a` / `a:hover` 规则会把它拉回蓝字。 */
.shop-cs {
  flex: none; height: 36px; padding: 0 14px; border-radius: 10px; box-sizing: border-box;
  display: flex; align-items: center; gap: 6px;
  background: #1B6BFF; border: 1px solid #1B6BFF; color: #ffffff;
  font-size: 14px; font-weight: 600;
  box-shadow: 0 4px 12px rgba(27, 107, 255, .24);
  transition: background-color .2s ease, box-shadow .2s ease;
}
.shop-cs:hover { background: #0A56C8; border-color: #0A56C8; color: #ffffff; box-shadow: 0 8px 18px rgba(27, 107, 255, .32); }
.shop-cs:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.shop-cs svg { flex: none; display: block; }
/* 分享:36 见方的图标按钮,与参考站同一个位置(名片右上角最外侧)。
   点开的是「分享店铺」弹窗(.sh-modal),不是「点一下悄悄复制」—— 后者当天做过一版,
   一枚看不懂的图标配一句 toast,被删了。 */
.shop-share {
  flex: none; width: 36px; height: 36px; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14); border-radius: 10px;
  color: rgba(30, 50, 80, .62);
  transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.shop-share:hover { border-color: rgba(27, 107, 255, .5); color: #1B5FE8; background: rgba(46, 124, 255, .06); }
.shop-share:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
/* ── 店内的商品区 ── */
/* 分区间距 30(2026-08-04 从 24 拉开):名片 / 商品 / 评价是三个平级分区,而分区**内部**
   的头到卡是 14 —— 24 : 14 分不出层次,三块读起来是连着的一长条。 */
.shop-sec { margin-top: 30px; }
/* 章节头不挂图标(见 js 里那段),所以这里不再需要 flex 与 svg 两条 —— h2 的左缘
   因此落回 34,与下面的 chips、白卡同一条左脊。 */
.shop-sec-head h2 { margin: 0; font-size: 20px; line-height: 26px; font-weight: 700; color: #0C1626; }

/* ── 分类 tab(2026-08-04 第三版,前两版都推翻了)────────────────────
   **形态是「文字 + 3px 蓝下划线」,坐在商品白卡内部当表头** —— 与消息中心 `.ord-tabs`
   同一套构造(一条 hairline 轨道 + `::after` 压在 `bottom:-1px` 上盖住它)。
   前两版都是**文件夹标签**(未选中灰底、选中白底凸起、下沿伸进白卡),连着改了两轮
   用户仍说不好,诊断下来是形态本身在本站的数据上不成立:文件夹标签要读作一排标签,
   得让标签把整条带子填住,而实测 10 家店的填充率是
   **16% / 15% / 16% / 25% / 25% / 33% / 42% / 60% / 65% / 119%** —— 一半的店不到 30%,
   居中之后就是一条空带子上贴着一个白色小方块,那个白块反而成了整屏最突兀的东西。
   第二版加的那条灰带也没救回来:`#EBEFF6` 与页底 `#F4F7FC` 只差 (9,8,6),
   肉眼几乎不可辨,「带子」根本没读出来是带子。
   **下划线式不需要铺满**:线只跟着自己那一格走,2 格与 14 格一样成立;
   而且它是站内既有的 tab 语言(`.ord-tabs` / `.gm-tab` / `.pdp-tab` 全是这一套),
   文件夹标签是给这一页新造的第二套表面。**别再改回去。** */
.shop-tabs-wrap {
  /* 负 margin 把轨道撑到卡片边缘,分隔线因此是通宽的;padding 再把 tab 收回内容区 */
  margin: 0 -20px 18px; padding: 0 20px;
  border-bottom: 1px solid rgba(13, 38, 90, .07);
}
/* **放不下就换行,不横向滚**(2026-08-04 按用户要求从横滚改过来)。14 个类目的
   自营店实测溢出只有 32px —— 为这 32px 保留一套「隐滚动条 + 右端渐隐 + scroll 监听」
   等于让右边那几格躲在屏幕外,而换行之后 13 个类目一眼全在。跟着删净的是
   `syncShopMore` / `.is-more` / `.shop-tabs-wrap::after` 那条渐隐与 scroll 监听
   (见 js 里那段注释),**不是漏写** —— wrap 之后永不溢出,它们恒为假。
   `justify-content` 因此也从 `safe center` 退回裸 `center`:那个 `safe` 兜的正是
   「溢出时别把左端推出滚动区」,现在没有溢出可兜了。
   **行距 0、列距 26**:tab 自己高 46(文字 22 + 上下各 12),两行贴着排视觉间距就是
   24,够了;写成 `gap: 26px` 会把行距也设成 26,两行之间空出 70,读成两条不相干的带子。
   列距 26 是量出来的 —— 下划线只有本格那么宽,格与格贴太近时两条线会读成一条断线。 */
.shop-tabs {
  display: flex; align-items: stretch; justify-content: center;
  flex-wrap: wrap; gap: 0 26px;
}
/* **真换行了才左对齐**(`.is-wrap` 由 js 量高度后挂,见 syncShopWrap)。居中的
   孤格是舞台中央的独角戏 —— faorbit 断成 13 + 1,末位的「游戏专区」两侧各空 590,
   反而成了整条最显眼的一格;左对齐后它读作上一行的续行。**只动 justify-content,
   不动 flex-wrap** —— 换不换行是宽度说了算,这个类只管对齐,所以量高度时不会
   自己影响自己(没有反馈循环)。 */
.shop-tabs.is-wrap { justify-content: flex-start; }
/* **两档字重都是 600**,只靠文字色与下划线区分选中(同 `.ord-tab` 那条):
   改成 600/700 的话切一次 tab 每一格的宽度都会变,整行跟着抖。 */
.shop-tab {
  position: relative; flex: none;
  height: 46px; padding: 0; box-sizing: border-box; cursor: pointer;
  display: flex; align-items: center;
  background: transparent; border: none; font-family: inherit;
  font-size: 15px; line-height: 22px; font-weight: 600; color: rgba(30, 50, 80, .72);
  white-space: nowrap;
  transition: color .2s ease;
}
/* 下划线压在 `bottom:-1px` 上盖住 wrap 那条轨道 —— 不压的话线与轨道会叠成 4px */
.shop-tab::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 3px;
  background: #1B6BFF; border-radius: 3px 3px 0 0;
  opacity: 0; transition: opacity .2s ease;
}
/* **tab 上不印件数**(2026-08-04 按用户要求整个删掉,`.shop-tab i` 那组规则一并
   删净,不是漏写;此前还走过「带括号 → 裸数字」一轮)。栅格上方「N 个商品」那行
   仍在,件数没有丢出口。 */
.shop-tab:hover { color: #0C1626; }
.shop-tab.is-on { color: #1B5FE8; }
.shop-tab.is-on::after { opacity: 1; }
.shop-tab:focus-visible { outline: 2px solid #1B6BFF; outline-offset: -2px; }

/* 商品白卡:tab 表头 + 工具行 + 计数 + 商品栅格全装在里面。**上内边距只有 2** ——
   tab 自己 46 高,卡片顶部再留 20 会把表头压得离上边框太远(同 `.ord-tabs` 那条)。 */
.shop-panel {
  margin-top: 14px; padding: 2px 20px 20px; box-sizing: border-box;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  border-radius: 18px;
  box-shadow: 0 10px 30px rgba(13, 38, 90, .05);
}
.shop-tools { display: flex; align-items: center; gap: 12px; }
/* 店内搜索框。**底色是浅蓝,不是灰也不是白**(2026-08-03 用户报
   「不是很显眼」后连改两版才定的,三版都实测过):
   ① 初版照报价页左栏 `.off-field` 抄的灰底 `rgba(13,38,90,.05)`,压在 `#F4F7FC` 页底上
      算出来是 `rgb(232,237,244)` —— 与页底只差 12/10/8,通宽 1300 摊开就是一条几乎
      看不见的浅带子。左栏那个框只有 248 宽、四周有筛选行陪着,同一套参数在那里成立、
      在这里不成立。
   ② 换成白底 + 卡片阴影能看出边界了,但它上面是店铺名片、下面是商品行,**全是白卡** ——
      它成了三层白里最矮最空的一条,仍然不跳。
   ③ 浅蓝底走的是**色相差**而不是明度差,一眼就从两张白卡之间分离出来,而蓝在站内的
      既有语义正是「这里能动」。所以不再叠阴影 —— 分离已经由颜色完成,两种手法叠加
      会让它比商品行还重,而它只是个筛选控件。
   加高加大图标也是同一件事的一部分:46 高、18 图标、15px 文字,比 `.off-field` 整体重一档。
   2026-08-04 从通宽收成 `flex: 1` 坐在工具行里(参考站的搜索框只占小半行,右边跟着
   排序下拉)。**浅蓝底留着** —— 它现在压在 `.shop-panel` 那张白卡上,与白底的
   明度差比压在页底上时更小,那点色相差是它还能被看见的全部依据。 */
.shop-q {
  flex: 1; min-width: 0; height: 46px; box-sizing: border-box;
  background: rgba(46, 124, 255, .06);
  border: 1px solid rgba(27, 107, 255, .22); border-radius: 12px; padding: 0 16px;
  display: flex; align-items: center; gap: 11px;
  transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.shop-q:hover { border-color: rgba(27, 107, 255, .4); }
.shop-q:focus-within {
  border-color: rgba(27, 107, 255, .6);
  box-shadow: 0 0 0 4px rgba(46, 124, 255, .14);
  background: #ffffff;
}
/* FIND_SVG 是全站共用的 14px / 灰 `.5` 描边,在这个框里太轻。就地放大到 18 并
   **染成站内蓝** —— 蓝在站内的既有语义就是「这里能动」,而这一格是工具行里唯一
   能打字的地方。presentation attribute 的优先级低于 CSS,所以 stroke 覆盖得动。 */
.shop-q svg { flex: none; display: block; width: 18px; height: 18px; stroke: #1B6BFF; }
.shop-q input {
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font-size: 15px; line-height: 20px; color: #0C1626;
}
/* 比全局的 `.4` 深一档:这条占位符还兼着「把空框填住」的活(见 renderShopView 里
   那句注释),太浅就白写了。不再往深走 —— 到 `.72` 才够 4.5:1,而那个重量读起来
   已经像框里本来就有内容。 */
.shop-q input::placeholder { color: rgba(30, 50, 80, .7); }
/* 排序下拉**整套跟着搜索框走**,不只是同高(2026-08-04):此前它是白底灰边、搜索框是
   浅蓝底蓝边,两个同高同排的平级控件长得完全不一样,读不出是一组。它俩回答的是同一个
   问题(「筛这批商品」),右端的视图切换回答的是另一个(「怎么看」)—— 表面上的这条界线
   正好落在语义的界线上,所以视图切换保持白底,不跟着一起浅蓝。 */
/* 宽度按最长选项算,不留富余(2026-08-05 从 150 收到 108,用户报「这个框可以收窄一些」):
   108 = 最长的「价格最低」15px 实测 60 + 左内边距 12 + 右内边距 34(让 caret) + 边框 2,
   与不写宽度时的自动宽度**恰好相等** —— 旧的 150 是凭手感取的,里面有 42px 是空的,
   而它右边紧挨着视图切换、左边是撑满剩余空间的搜索框,那片空白读作两个控件没对齐。
   写 min-width 而不是 width:选项以后变长会自己撑开,不会截断;加选项前照
   「文字 + 内边距 42 + 边框 2 就是框宽」重量一遍(同 `.off-sort` 那条)。 */
.shop-tools .off-sort select {
  min-width: 108px; height: 46px; padding-right: 34px;
  background: rgba(46, 124, 255, .06); border-color: rgba(27, 107, 255, .22);
  font-size: 15px; color: #0C1626;
}
.shop-tools .off-sort select:hover { border-color: rgba(27, 107, 255, .4); }
/* 计数独占一行、左对齐坐在栅格上方(参考站的「11 个商品」就在这个位置)。
   **不再推到工具行右端** —— 那一行现在被搜索框撑满,右端归视图切换。 */
.shop-count { margin: 16px 0 0; font-size: 14px; color: rgba(30, 50, 80, .7); }
.shop-switch {
  flex: none; display: flex; height: 46px; box-sizing: border-box;
  border: 1px solid rgba(13, 38, 90, .14); border-radius: 12px; overflow: hidden;
  background: #ffffff;
}
.shop-sw {
  width: 44px; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: none; color: rgba(30, 50, 80, .55);
  transition: background-color .2s ease, color .2s ease;
}
.shop-sw + .shop-sw { border-left: 1px solid rgba(13, 38, 90, .14); }
.shop-sw:hover { background: rgba(46, 124, 255, .08); color: #1B5FE8; }
.shop-sw.is-on, .shop-sw.is-on:hover { background: #1B6BFF; color: #ffffff; }
.shop-sw:focus-visible { outline: 2px solid #1B6BFF; outline-offset: -2px; }

/* 两种形态共用同一个容器 id(#shopList),上边距写在两个类上,切换时不跳。
   **换分类 / 换排序 / 换视图时整块淡入(`.is-swap`),搜索时不淡** —— 换视图是
   形态突变(行 ↔ 卡)、换分类可能从 113 张跳到 9 张,不给过渡就读作「页面闪了一下」;
   而搜索是**每敲一个字符**触发一次重画,那是上百次/天的频率,加动画只会让打字发黏
   (同「动效频次」那条:100+ 次/天的动作一律不动画)。
   关键帧**只写 from**:减弱动效把 duration 压成 0 时元素直接落在自然状态。 */
@keyframes shopSwap { from { opacity: 0; transform: translateY(4px); } }
.shop-list.is-swap, .shop-grid.is-swap, .shop-empty.is-swap {
  animation: shopSwap .16s var(--ease-out);
}
.shop-list { margin-top: 12px; display: flex; flex-direction: column; gap: 12px; }
/* 4 列(参考站也是 4 列)。**不复用 `.prod-grid`** —— 那个是页面级栅格,列宽按
   1302 的内容区算;这里的卡片坐在 `.shop-panel` 里,左右各被吃掉 20 的内边距。 */
.shop-grid {
  margin-top: 12px; display: grid; gap: 14px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
/* 分页条(2026-08-04 加,照参考站摆在商品区右下角)。**空的时候不占位** ——
   一条结果都没有时 js 渲染空串(空态卡底下不该挂翻页器),`:empty` 把上边距一并
   收掉,否则那张卡下面会平白多出一段。**只有一页时照样渲染,整条 disabled**,
   见 js 里 shopPagerHtml 那段。
   按钮的白底 / .14 边框 / 圆角 12 与同页的 `.shop-switch` 同参数,选中态照站内
   既有语言走实心蓝(参考站那颗当前页是白底方框,但站内一律蓝)。 */
.shop-pager { margin-top: 20px; display: flex; justify-content: flex-end; }
.shop-pager:empty { margin-top: 0; }
.shop-pager-in { display: flex; align-items: center; gap: 8px; }
.shop-pg {
  min-width: 38px; height: 38px; padding: 0 12px; box-sizing: border-box; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14); border-radius: 12px;
  font-family: inherit; font-size: 14px; font-weight: 600; color: rgba(30, 50, 80, .72);
  font-variant-numeric: tabular-nums; white-space: nowrap;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}
.shop-pg:hover { background: rgba(46, 124, 255, .08); border-color: rgba(46, 124, 255, .35); color: #1B5FE8; }
.shop-pg.is-on, .shop-pg.is-on:hover {
  background: #1B6BFF; border-color: #1B6BFF; color: #ffffff;
}
/* 首末页的那颗保持在原位、只退成灰 —— 藏起来的话整条会左右跳一格宽。
   单页时三颗全在这一档(见 js 里 `solo`),hover 也不亮:`:disabled` 排在
   `:hover` 之后,同特异性靠顺序取胜,**别把它挪到上面去**。 */
.shop-pg:disabled { cursor: default; color: rgba(30, 50, 80, .32); background: #ffffff; border-color: rgba(13, 38, 90, .08); }
.shop-pg:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }

/* ── 全部评价(2026-08-04 照参考站加)───────────────────────────────
   数据是 `CATALOG.shopReviewsOf` 派生的成交反馈(见 catalog.js 7.6)。
   骨架:章节头 → 三枚筛选 chip → 一张白卡(逐条 hairline 分隔 + 卡脚的注与分页)。
   **chip 不做成商品区那样的下划线 tab**:那一条是页级分区导航,这三枚是列表内的
   筛选按钮,层级不同、形态不同才对;药丸的选中态也**不用实心蓝** —— 实心是主按钮
   那一档(`.shop-cs` / `.shop-add`),一个筛选控件占不起。 */
/* 上边距 10(从 14 收):标题与它的三枚筛选是同一个「头部」,该靠在一起;头部与白卡
   之间那 14 由 `.shop-panel` 自己的 margin-top 给,与商品区「章节头 → 白卡」的 14
   是同一个数 —— 层次因此是 30(分区) > 14(头到卡) > 10(头部内)。 */
.srev-chips { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 10px; }
.srev-chip {
  height: 38px; padding: 0 16px; box-sizing: border-box; cursor: pointer;
  display: flex; align-items: center; gap: 7px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14); border-radius: 999px;
  font-family: inherit; font-size: 14px; font-weight: 600; color: rgba(30, 50, 80, .72);
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}
.srev-chip i { font-style: normal; font-size: 13px; font-weight: 600; color: rgba(30, 50, 80, .55); }
.srev-chip:hover { border-color: rgba(46, 124, 255, .4); color: #1B5FE8; }
.srev-chip.is-on, .srev-chip.is-on:hover {
  background: rgba(46, 124, 255, .1); border-color: rgba(27, 107, 255, .4); color: #1552CC;
}
.srev-chip.is-on i { color: #1552CC; }
.srev-chip:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }

/* 评价区的白卡上下内边距收到 4:它没有商品区那样的 tab 表头,逐条自带 18 的上下内边距,
   卡片再留 20 就成了首条评价上方一片空白。 */
.shop-rev-panel { padding: 4px 20px; }
.srev-list.is-swap { animation: shopSwap .16s var(--ease-out); }
.srev + .srev { border-top: 1px solid rgba(13, 38, 90, .07); }
/* 上下 13(原先 18):这一条装的是「谁 + 买了什么 + 什么时候 + 一句短评」,四个短值,
   条内两行只隔 5、条与条却隔 36,读起来是一条条飘着的字。收到 13 之后条高 84 → 70,
   一屏从 8 条变 10 条(= 正好一页),竖向的节奏也从 1:4.5 收到 1:5.2 之内。 */
.srev { padding: 13px 0; }
/* 头行:图标 + 名字 …… 右端时间。时间靠 `margin-left:auto` 推到右缘。
   **商品名 2026-08-04 按用户要求整个不展示了**(`.srev-prod` / `.srev-sep` 两条 CSS
   与那两个节点一并删净,不是漏写):它是个裸值,600 条里有 109 条(18.2%)一个中文字
   都没有(Trae Pro / Quillbot / Financial times …),孤零零挨在用户名后面读不出是什么
   —— 用户当场问的就是「这是什么」。数据层的 `r.product` 留着没动。 */
.srev-head { display: flex; align-items: center; gap: 8px; }
/* **好差评的图标是 16px 的裸拇指,没有底盘**(2026-08-04 照用户给的参考图定稿;
   当天先做过一版「12px 图标 + 20px 淡底圆盘」,**已整体推翻,别再做回去**)。
   要解决的问题一直是同一个:实测 10 家店每家都是 60 条里 57–58 好评、2–3 差评,
   而原先 12px 的细拇指在 13px 名字旁边只是一粒色点,那一两条差评扫过去根本不会停
   —— 可它恰恰是这一列唯一值得被看见的东西(三枚筛选 chip 筛的就是它)。
   **圆盘那版是走错方向**:它想用淡底给标记一个固定 footprint,实际效果相反 ——
   12px 的图标被 20px 的盘子一衬更显小,而 `.12` 的淡底自己对白卡只有 1.16 的对比度,
   等于给一个本来就弱的标记又套了层雾。**真正该做的是把标记本身做饱满** ——
   放到 16px + 厚实字形(见 js 里 THUMB_SVG 那段描边),红蓝两枚各自就够跳,
   实测这样比套圆盘时**更**显眼,盘子因此没有存在的理由了。
   红色沿用 `THUMB_DOWN_SVG` 已有的 `#E1473D`,不引入新色标;它也刻意不是站内的
   错误红 `#C0261F`(差评是负面反馈,不是错误状态)。
   **16 这个尺寸只作用于这一列**(常量本身是 12,给 `.offer-like` 那种跟文字同排的
   行内符号用):这里的拇指是要竖着扫一列的标记,不是跟在数字后面的注脚。 */
.srev-ico { flex: none; display: flex; }
.srev-ico svg { display: block; width: 16px; height: 16px; }
/* 本机写的那条印的是五颗星(见 js 里 `shopRevRow`),复用首页「客户之声」那枚
   `reviewStars` —— 但它带着两个只在那边成立的默认值,都要在这里撤掉:
   ① **`margin-left:auto`**(在那边是靠右挂的),不撤的话这里会被推到行尾去,
      和同样带 auto 的 `.srev-at` 平分空间,整行当场散开;
   ② **svg 是 inline 的**,底下留着基线降部,星条盒子会比五颗星本身高出几 px。
      `display:block` 之后它正好等于星高 13(实测)。
   **别指望这条能把行高拉平**:带「我的评价」的行实测仍比派生行高 3px,那是 21 高的
   `.srev-mine` 标签撑的(两档那版就如此),与星条无关 —— 一列里 70/72/75 的抖动本来
   就有(文案长短),不是没对齐。 */
.srev .review-stars { margin-left: 0; flex: none; }
.srev .review-stars svg { display: block; }
/* 名字退成 13/600 中灰:它与时间同属「这条是谁在什么时候留的」那一档,正文才是
   主体(见下)。原先 14/700 近黑,与正文同号同色,一条里两个重点。 */
.srev-who { flex: none; font-size: 13px; font-weight: 600; color: rgba(30, 50, 80, .78); }
/* 本机写的那条挂一枚「我的评价」(2026-08-06 加评价功能时):这一列的名字全是脱敏
   前缀,自己那条的 `me***` 混在 `mar***` / `San***` 里认不出来,而「刚写完能不能
   在店铺页看见自己那条」正是这个功能要闭上的环。
   **标签而不是给整行换底色**:换底色会让它读成一条被平台特别对待的评价,而它跟
   旁边那些是同一档东西。配色照 `.ord-key-label`(浅蓝底蓝字),不新造一种标签。 */
.srev-mine {
  flex: none; padding: 2px 7px; border-radius: 6px;
  background: rgba(46, 124, 255, .1); color: #1B5FE8; font-size: 12px; font-weight: 700;
}
.srev-at {
  flex: none; margin-left: auto; padding-left: 12px;
  font-size: 13px; color: rgba(30, 50, 80, .55); font-variant-numeric: tabular-nums;
}
/* 正文缩进 20 对齐名字(图标 12 + gap 8):不缩的话它顶在图标下方,读起来像是图标的说明 */
/* 正文比头行**重一档**(近黑 + 15px):一条评价里最要紧的是「说了什么」,而头行的
   名字是 14/700 近黑 —— 不抬的话「谁说的」压过了「说了什么」,层级是反的。
   上边距 5(原先 8):头行与正文是同一条评价的两半,靠得住才不会被条间的 26 拆开。 */
.srev-text {
  margin: 5px 0 0 20px; font-size: 15px; line-height: 22px; color: #0C1626;
  text-wrap: pretty;
}
.srev-list.is-void { padding: 40px 0; text-align: center; }
.srev-list.is-void p { margin: 0; font-size: 14px; color: rgba(30, 50, 80, .7); }
/* 卡脚:左边那句注,右边分页。**注必须在** —— 列表只有 6 页而名片上写着三万多条反馈,
   不说明「仅展示最近 60 条」两个数就当场对不上(同「对外宣称的数字必须能被站内
   自己的数据兑现」)。`align-items:center` 让单行的注与 38 高的分页按钮对齐。 */
.srev-foot {
  padding: 18px 0 20px; border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: center; gap: 20px;
}
.srev-note { margin: 0; flex: 1; min-width: 0; font-size: 13px; color: rgba(30, 50, 80, .7); }
/* 分页在卡脚里,自己那条 margin-top 由 flex 布局接管 */
.srev-foot .shop-pager { margin-top: 0; flex: none; }

/* ── 店内商品卡 ──────────────────────────────────────────────────
   2026-08-04 照参考站新做,替掉原来那张 `featCard`(见 js 里 shopCard 那段注释)。
   骨架:上半区左文右图 → 分隔线 → 价格与发货时效。卡高由文字侧定(标题 20 +
   描述 3×18 = 74),62 的方图顶不到它,所以三张并排时高度靠 `min-height` 钉住。 */
.shop-gcard {
  display: flex; flex-direction: column; gap: 12px;
  padding: 16px; box-sizing: border-box; border-radius: 14px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .09);
  box-shadow: 0 4px 14px rgba(13, 38, 90, .04);
  /* .15s 是站内卡片 hover 的统一时长(`.feat-card` / `.offer-card` / `.promo-card`
     全是这个数),这张卡原先写的 .2s 是全站唯一 */
  transition: transform .15s var(--ease-out), border-color .15s ease, box-shadow .15s ease;
}
.shop-gcard:hover {
  transform: translateY(-3px);
  border-color: rgba(27, 107, 255, .3); box-shadow: 0 14px 30px rgba(13, 38, 90, .1);
}
.shop-gcard:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.sgc-head { display: flex; align-items: flex-start; gap: 12px; }
.sgc-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
/* 档位串,粗体。与报价卡的 `.offer-spec` 同一个角色,但**这里钉两行、不是一行省略号** ——
   报价页是 3 列、`.offer-spec` 实测零截断,这一页 4 列只剩 213 可用,而最长的档位串
   要 238(「标准 · 1 个月 · 完全访问 · 移动端 + 电脑」),一行省略实测 65 件里切掉 12 件(18%)。
   两行钉死(2 × 20 = 40)后零截断,长短不一时下面的描述行也不会错开。
   加属性或改列数后照这个方法重量(渲染后比 `scrollHeight > clientHeight`)。 */
.sgc-title {
  font-size: 14px; line-height: 20px; font-weight: 700; color: #0C1626;
  min-height: 40px; text-wrap: pretty;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
/* 商家自己那句文案,钉死 3 行(3 × 18 = 54)—— 长短不一时下面的价格行才不会错开。
   `text-wrap: pretty` 同 `.offer-title` / `.fcard-name`:不加会把末字甩成孤字。 */
.sgc-desc {
  font-size: 13px; line-height: 18px; color: rgba(30, 50, 80, .7);
  min-height: 54px; text-wrap: pretty;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
/* **白底卡里的方图不挂投影**(2026-08-04 修)。站内同位置的 `.offer-thumb`(报价卡右上
   那张 62 方图)本来就没有阴影;有阴影的是 `.fcard-ico`,而它坐在**彩色渐变**的
   `.fcard-top` 上 —— 那里的投影是把图标从底色里托起来。抄到白底上就成了
   `0 8px 18px rgba(0,0,0,.16)`:比卡片自己的 `.04` 重四倍,一排卡看过去,
   图标读作贴在卡上的贴纸,而不是卡的一部分。 */
.sgc-ico {
  flex: none; width: 62px; height: 62px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
}
.sgc-ico img { width: 32px; height: 32px; object-fit: contain; display: block; }
.sgc-letter { font-size: 17px; font-weight: 700; color: #123A8F; }
.sgc-foot {
  padding-top: 12px; border-top: 1px solid rgba(13, 38, 90, .07);
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
/* 行:方图 + 标题两行 + 右端价格与 CTA。**hover 不做位移** —— 行内右端坐着一颗
   真按钮,整行抬起会跟按钮自己的按压打架;换边框与阴影已经说明这一行能点。 */
.shop-row {
  box-sizing: border-box; padding: 18px; border-radius: 16px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  display: flex; align-items: center; gap: 16px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.shop-row:hover { border-color: rgba(27, 107, 255, .3); box-shadow: 0 12px 30px rgba(13, 38, 90, .1); }
.shop-row-main { flex: 1; min-width: 0; display: flex; align-items: center; gap: 16px; }
.shop-row-main:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 3px; border-radius: 12px; }
/* 同 `.sgc-ico`:白底行里的方图不挂投影 */
.shop-row-ico {
  flex: none; width: 62px; height: 62px; border-radius: 16px;
  display: flex; align-items: center; justify-content: center;
}
.shop-row-ico img { width: 32px; height: 32px; object-fit: contain; display: block; }
.shop-row-letter { font-size: 17px; font-weight: 700; color: #123A8F; }
.shop-row-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.shop-row-title {
  font-size: 14px; line-height: 20px; font-weight: 700; color: #0C1626;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.shop-row-meta {
  font-size: 13px; line-height: 18px; color: rgba(30, 50, 80, .7);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.shop-row-buy { flex: none; display: flex; align-items: center; gap: 16px; }
.shop-add {
  flex: none; height: 36px; padding: 0 16px; border-radius: 10px; cursor: pointer;
  display: flex; align-items: center; gap: 4px;
  background: #1B6BFF; border: 1px solid #1B6BFF; color: #ffffff;
  font-size: 14px; font-weight: 600;
  transition: background-color .2s ease, box-shadow .2s ease;
}
.shop-add:hover { background: #0A56C8; box-shadow: 0 8px 18px rgba(27, 107, 255, .28); }
.shop-add:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
/* 代充类没有加购(必须先填账号),换成去详情页的次级按钮 —— 同一格位置、次一档权重 */
.shop-add.is-ghost { background: #ffffff; border-color: rgba(27, 107, 255, .35); color: #1B6BFF; }
.shop-add.is-ghost:hover { background: rgba(46, 124, 255, .08); box-shadow: none; }
.shop-add.is-ghost svg { flex: none; display: block; }
/* 空态坐在 `.shop-panel` 那张白卡**里面**,所以底色不能再是白的(2026-08-04):
   白底白卡叠白底空态,那 54 的内边距读不出是一块独立的东西。 */
.shop-empty {
  margin-top: 12px; padding: 46px 30px; border-radius: 14px;
  background: rgba(13, 38, 90, .03); border: 1px solid rgba(13, 38, 90, .07);
  display: flex; flex-direction: column; align-items: center; gap: 14px;
}
.shop-empty p { margin: 0; font-size: 16px; font-weight: 700; color: #0C1626; }

/* ── 分享店铺弹窗 ──────────────────────────────────────────────────
   遮罩照弹窗广告 `.ad-modal` 那套(同一个 z-index 80、同一层毛玻璃),卡片则照站内
   白卡。**不复用 `.ad-modal` 的 DOM** —— 那是写死在 index.html 里的广告海报,
   内容与形状都不是这回事;共用的只有表面参数与文件末尾那条 `.is-out` 收起动画。 */
.sh-modal {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(13, 27, 42, .6);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  display: flex; align-items: center; justify-content: center; padding: 32px;
  animation: adFade .2s ease-out;
}
/* 浏览器默认的 [hidden]{display:none} 权重低于上面那条 display:flex,藏不掉,
   必须显式补一条(同 .co-sum-row / .auth-tabs 那几处) */
.sh-modal[hidden] { display: none; }
.sh-box {
  width: 480px; max-width: 100%; box-sizing: border-box; padding: 20px 24px 24px;
  background: #ffffff; border-radius: 18px;
  box-shadow: 0 30px 80px rgba(6, 16, 40, .3);
  animation: adPop .28s cubic-bezier(.2, .8, .3, 1);
}
.sh-head { display: flex; align-items: center; margin-bottom: 18px; }
.sh-title {
  display: flex; align-items: center; gap: 8px;
  font-size: 16px; line-height: 22px; font-weight: 700; color: #0C1626;
}
.sh-title svg { flex: none; display: block; }
.sh-close {
  margin-left: auto; flex: none; width: 30px; height: 30px; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: none; border-radius: 8px;
  color: rgba(30, 50, 80, .55);
  transition: background-color .2s ease, color .2s ease;
}
.sh-close:hover { background: rgba(13, 38, 90, .06); color: #0C1626; }
.sh-close:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
/* 字段标签走站内那套组标签参数(14/20 的 600 近黑、无字距),不照参考站的 13px 灰 */
.sh-label { display: block; margin: 0 0 8px; font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626; }
.sh-label-2 { margin-top: 20px; }
.sh-link-row { display: flex; align-items: center; gap: 10px; }
/* 只读:这一格是给人看和复制的,不是给人改的。改了也不会让链接变成另一家店。 */
#shLink {
  flex: 1; min-width: 0; box-sizing: border-box; height: 44px; padding: 0 14px;
  background: rgba(13, 38, 90, .05);
  border: 1px solid rgba(13, 38, 90, .1); border-radius: 10px;
  font-size: 13px; color: rgba(30, 50, 80, .8);
  text-overflow: ellipsis;
}
#shLink:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.sh-copy {
  flex: none; width: 44px; height: 44px; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14); border-radius: 10px;
  color: rgba(30, 50, 80, .62);
  transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.sh-copy:hover { border-color: rgba(27, 107, 255, .5); color: #1B5FE8; background: rgba(46, 124, 255, .06); }
.sh-copy:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.sh-ways { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.sh-way {
  height: 46px; box-sizing: border-box; border-radius: 10px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14);
  font-size: 14px; font-weight: 600; color: #0C1626;
  transition: border-color .2s ease, background-color .2s ease;
}
.sh-way:hover { border-color: rgba(27, 107, 255, .45); background: rgba(46, 124, 255, .06); color: #0C1626; }
.sh-way:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.sh-way img { width: 16px; height: 16px; object-fit: contain; display: block; flex: none; }

/* ── 评价弹窗 ────────────────────────────────────────────────────
   外壳整套复用 `.sh-modal` / `.sh-box`(遮罩、进出动画、480 宽、Esc 与点遮罩关闭
   全都跟着来),这里只写它自己那四块:评的是哪一件、好评 / 差评两颗、正文框、页脚。
   **纵向节奏就两档:14(节内)/ 18(分节)** —— 同购买面板那条,别再引入第三个数。 */
.rev-item {
  margin-bottom: 18px; padding: 12px 14px; border-radius: 12px;
  background: rgba(13, 38, 90, .03); border: 1px solid rgba(13, 38, 90, .07);
  display: flex; flex-direction: column; gap: 3px;
}
.rev-item b { font-size: 14px; font-weight: 700; color: #0C1626; }
/* ── 五颗星(2026-08-06 按用户要求,从 👍 / 👎 两颗药丸改过来,那两条 `.rev-picks`
   / `.rev-pick` 已整套删净,不是漏写)──
   **星条与档位话同排**:那句「很差 … 非常满意」是这把尺子的刻度,分成两行会让人
   先打完分再读到它。 */
.rev-rate { margin-top: 10px; display: flex; align-items: center; gap: 14px; }
.rev-stars { display: flex; align-items: center; gap: 2px; }
/* **靶子按 38 见方给(实测),不是按星本身的 24** —— 星是个尖角图形,按边界算的
   可点面积只有视觉面积的一半上下;38 与站内可点控件的下限档齐平(`.buy-step` 36
   见方那一类)。`padding` 撑出来而不是写死宽高:改星号尺寸时不必两处一起调。 */
.rev-star {
  padding: 8px; border: none; background: none; cursor: pointer; line-height: 0;
  color: rgba(13, 38, 90, .18);
  transition: color .12s var(--ease-out), transform .12s var(--ease-out);
}
.rev-star svg { display: block; }
/* 点亮走 `is-on`(js 逐颗加,hover 预览与真实选中共用一条画法):**CSS 那个
   `row-reverse` + `~` 的老技巧没用** —— 它要把 DOM 倒着写,读屏用户听到的就成了
   「五星、四星、三星…」。金色沿用站内唯一的星色 `#F5A623`,不另取一个。 */
.rev-star.is-on { color: #F5A623; }
.rev-star:hover { transform: scale(1.12); }
/* 只读态(回看评过的那一单,`revStarsHtml` 那时输出的是 span):**把 cursor 与 hover
   放大一起撤掉** —— 一排会跟着鼠标动的星星摆在一个改不了的东西上,就是在请人去点它。 */
.rev-stars.is-view .rev-star { cursor: default; }
.rev-stars.is-view .rev-star:hover { transform: none; }
.rev-star:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; border-radius: 6px; }
/* 档位话:14/600 近黑,与它左边那五颗星同一档分量(它就是那五颗星的读数)。
   **没打分时整句留空**(2026-08-07 按用户要求;旧的占位提示「点星星打分」与配它的
   `.rev-word.is-void` 一并删净,不是漏写)—— 五颗空星自己就在说该点它。 */
.rev-word { font-size: 14px; font-weight: 600; color: #0C1626; }
/* 「选填」跟在标签后面:不写的话空着交上去像是漏填,而这一格本来就可以空 */
.rev-opt { margin-left: 6px; font-size: 13px; font-weight: 500; color: rgba(30, 50, 80, .55); }
.rev-text {
  box-sizing: border-box; width: 100%; padding: 11px 14px; border-radius: 12px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .14);
  font-family: inherit; font-size: 14px; line-height: 21px; font-weight: 500; color: #0C1626;
  resize: none; transition: border-color .2s ease, box-shadow .2s ease;
}
.rev-text::placeholder { color: rgba(30, 50, 80, .5); }
.rev-text:focus { outline: none; border-color: rgba(27, 107, 255, .6); box-shadow: 0 0 0 4px rgba(46, 124, 255, .14); }
.rev-foot { margin-top: 14px; display: flex; align-items: center; gap: 12px; }
.rev-count { font-size: 13px; color: rgba(30, 50, 80, .55); font-variant-numeric: tabular-nums; }
/* 「发布后不可修改」**紧贴按钮**,不跟左端的计数并排:它说的是这颗按钮的后果,
   离它越近越像是在说它(`margin-left:auto` 因此挂在这一句上,不在 `.rev-send` 上)。
   同为 13px 但比计数深一档(.7 vs .55):计数是可以不读的,这一句不是 —— .55 在白底
   只有 3.3:1,同「12–13px 次要文字 ≥ 4.5:1」那条。 */
.rev-once { margin-left: auto; font-size: 13px; color: rgba(30, 50, 80, .7); }
/* ── 只读态:写过的那句话 + 什么时候发的 ──
   正文按气泡那一档给行高(它是**一段口语**,不是卡片上的单行字段,同 `.msg-bubble`
   25/14 那条),15px 近黑比它上面那行标签重一档 —— 这一屏最要紧的就是「我说了什么」。
   时间那行 13px 灰,把「不可修改」一并说了:表单态那句提示在这个态里已经收起来了,
   而回看的人正是最想改的人。 */
.rev-view-text {
  margin: 0; padding: 12px 14px; border-radius: 12px;
  background: rgba(13, 38, 90, .03); border: 1px solid rgba(13, 38, 90, .07);
  font-size: 15px; line-height: 24px; font-weight: 500; color: #0C1626;
  overflow-wrap: anywhere;
}
.rev-view-at { margin: 12px 0 0; font-size: 13px; color: rgba(30, 50, 80, .7); }
/* 没写正文时那一节整块收掉,这一行就直接接在星条下面 —— 那时用分节的 20
   (= `.sh-label-2`),不是节内的 12。 */
#revViewBody[hidden] + .rev-view-at { margin-top: 20px; }
/* 主行动按钮,参数照 `.msg-send`(站内 42 高那一档的实心蓝):同一种分量的按钮
   在站内就该是同一张脸。 */
.rev-send {
  flex: none; height: 42px; padding: 0 22px; border: none;
  border-radius: 12px; cursor: pointer;
  background: #1B6BFF; color: #ffffff; font-size: 14px; font-weight: 700;
  transition: background-color .2s var(--ease-out), transform .2s var(--ease-out);
}
.rev-send:hover { background: #1558D6; }
.rev-send:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
/* 没打星时真禁用(照 `.msg-send:disabled` 那条):一颗满色的主按钮点下去什么也不
   发生,用户第一反应是发布坏了,而不是「我还没打分」。星数是这张表唯一的必填项 ——
   正文写着「选填」,所以灰的只可能是因为它。 */
.rev-send:disabled { background: rgba(13, 38, 90, .1); color: rgba(30, 50, 80, .55); cursor: not-allowed; }
.rev-send:disabled:hover { background: rgba(13, 38, 90, .1); }

/* ── 商家入驻页 ──────────────────────────────────────────────────── */
.sl-hero {
  position: relative; overflow: hidden;
  margin-top: 18px; padding: 46px 48px; box-sizing: border-box; border-radius: 22px;
  background: linear-gradient(125deg, #0E2A5C, #1B5FE8 58%, #2E7CFF);
  box-shadow: 0 18px 44px rgba(13, 38, 90, .22);
  /* 左文案 + 右示意卡。参考稿的 hero 是通栏 + 底部弧形切口,这里保持圆角卡:
     全站的大色块(推广位主卡 / banner / 通栏 CTA)都是圆角卡,单给这一页开个弧形
     切口就是自立一套 —— 同报价卡那条,单看没问题、和相邻区块摆一起就不是一套。 */
  display: grid; grid-template-columns: 1fr 400px; gap: 48px; align-items: center;
}
.sl-hero > * { position: relative; z-index: 1; }
/* Hero 右侧示意卡 —— 纯装饰,标记见 slHeroArt() */
.sl-art {
  box-sizing: border-box; padding: 18px 20px 16px; border-radius: 16px;
  background: rgba(255, 255, 255, .97);
  box-shadow: 0 18px 40px rgba(6, 20, 60, .3);
}
.sl-art-top { display: flex; align-items: center; justify-content: space-between; }
.sl-art-t { font-size: 14px; font-weight: 700; color: rgba(30, 50, 80, .72); }
.sl-art-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #1B6BFF; box-shadow: 0 0 0 4px rgba(46, 124, 255, .14);
}
.sl-art-svg { display: block; width: 100%; height: 108px; margin-top: 14px; }
.sl-art-foot {
  margin-top: 14px; padding-top: 13px; border-top: 1px solid rgba(13, 38, 90, .08);
  display: flex; gap: 28px;
}
.sl-art-cell { display: flex; flex-direction: column; gap: 2px; }
.sl-art-cell b { font-size: 12px; font-weight: 700; color: rgba(30, 50, 80, .7); }
.sl-art-cell i { font-style: normal; font-size: 14px; font-weight: 700; color: #0C1626; }
.sl-orb {
  position: absolute; right: -70px; top: -90px; z-index: 0;
  width: 300px; height: 300px; border-radius: 50%;
  border: 40px solid rgba(255, 255, 255, .09);
}
/* .pm-kicker 是 display:flex,在推广位里靠父级的 align-items:flex-start 收住宽度;
   这里的父级是块级容器,不改成 inline-flex 它会拉成一条通栏的横杠。 */
.sl-hero .pm-kicker { display: inline-flex; }
.sl-title { margin: 12px 0 0; font-size: 40px; line-height: 50px; font-weight: 700; color: #ffffff; }
.sl-sub {
  margin: 14px 0 0; max-width: 620px;
  font-size: 15px; line-height: 1.75; color: rgba(219, 232, 255, .82); text-wrap: pretty;
}
.sl-hero-acts { margin-top: 22px; display: flex; gap: 10px; }
.sl-hero-acts .solo-cta { background: #ffffff; color: #1B5FE8; box-shadow: 0 10px 26px rgba(6, 20, 60, .3); }
.sl-hero-acts .solo-cta:hover { color: #1B5FE8; }
.sl-hero-acts .solo-cta-ghost {
  background: rgba(255, 255, 255, .1); color: #ffffff; border-color: rgba(255, 255, 255, .42);
}
.sl-hero-acts .solo-cta-ghost:hover { background: rgba(255, 255, 255, .2); color: #ffffff; }
.sl-stats { margin-top: 14px; display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.sl-stat {
  box-sizing: border-box; padding: 20px 22px; border-radius: 16px; text-align: center;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
}
.sl-stat-num { display: block; font-size: 30px; line-height: 38px; font-weight: 700; color: #1B5FE8; }
.sl-stat-label { display: block; margin-top: 2px; font-size: 14px; font-weight: 600; color: rgba(30, 50, 80, .7); }
.sl-stat-note {
  display: block; margin-top: 9px; padding-top: 9px; border-top: 1px solid rgba(13, 38, 90, .07);
  font-size: 13px; line-height: 1.6; color: rgba(30, 50, 80, .7); text-wrap: pretty;
}
.sl-sec { margin-top: 34px; }
.sl-sec .feat-head { align-items: baseline; }

/* 招募类目宫格。10 个开放类目排 5×2,卡片是真链接(落到类目页)—— 点不动的卡
   在这一页尤其刺眼,它整块都在喊「来上货」。 */
/* 6 列:类目数在变(11 项排 6+5,留一个空位是最少的)。改列数前先数一遍 CATS ——
   5 列会排成 5/5/1,最后一行孤零零一张卡。 */
.sl-wants { margin-top: 22px; display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px; }
.sl-want {
  box-sizing: border-box; padding: 20px 18px; border-radius: 16px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  display: flex; flex-direction: column; gap: 7px; text-decoration: none;
  transition: transform .15s var(--ease-out), box-shadow .15s ease, border-color .2s ease;
}
.sl-want:hover {
  transform: translateY(-3px); border-color: rgba(46, 124, 255, .4);
  box-shadow: 0 16px 36px rgba(13, 38, 90, .13);
}
.sl-want-ico {
  width: 44px; height: 44px; border-radius: 13px; background: rgba(46, 124, 255, .1);
  display: flex; align-items: center; justify-content: center;
}
.sl-want-name { font-size: 15px; line-height: 21px; font-weight: 700; color: #0C1626; }

/* 通栏 CTA。中段的企业位与页尾的收口位共用,页尾那条多一层点阵(.sl-band-end)。 */
.sl-band {
  position: relative; overflow: hidden;
  margin-top: 34px; padding: 34px 40px; box-sizing: border-box; border-radius: 22px;
  background: linear-gradient(115deg, #1B5FE8, #2E7CFF 74%);
  box-shadow: 0 16px 38px rgba(13, 38, 90, .2);
  display: flex; align-items: center; gap: 32px;
}
.sl-band-copy { position: relative; z-index: 1; flex: 1; min-width: 0; }
.sl-band-title { margin: 0; font-size: 26px; line-height: 34px; font-weight: 700; color: #ffffff; }
.sl-band-sub {
  margin: 8px 0 0; max-width: 760px;
  font-size: 14px; line-height: 1.7; color: rgba(219, 232, 255, .86); text-wrap: pretty;
}
.sl-band-cta {
  position: relative; z-index: 1; flex: none;
  background: #ffffff; color: #1B5FE8; box-shadow: 0 10px 26px rgba(6, 20, 60, .28);
}
.sl-band-cta:hover { color: #1B5FE8; }
/* 点阵只铺右半边(mask 渐显),对应参考稿收口 banner 上那张点阵地图 */
.sl-band-end::after {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background-image: radial-gradient(rgba(255, 255, 255, .34) 1.8px, transparent 1.8px);
  background-size: 14px 14px;
  -webkit-mask-image: linear-gradient(100deg, transparent 44%, #000 82%);
  mask-image: linear-gradient(100deg, transparent 44%, #000 82%);
}

/* 卖家案例轮播。三列:引号 / 内容 / 导航(圆点竖排 + 上下箭头,同参考稿)。
   引言长短不一,卡高靠 .sl-case-body 的 min-height 钉住 —— 不钉的话换一条
   下面整页会往上跳。 */
.sl-case {
  position: relative; margin-top: 22px; padding: 28px 32px; box-sizing: border-box; border-radius: 18px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  display: grid; grid-template-columns: 40px 1fr 44px; gap: 24px; align-items: start;
}
.sl-case-mark { font-size: 58px; line-height: 46px; font-weight: 700; color: rgba(46, 124, 255, .22); }
.sl-case-body { min-height: 115px; }
.sl-case-who { display: flex; align-items: center; gap: 11px; }
.sl-case-avatar { width: 44px; height: 44px; font-size: 17px; flex: none; }
.sl-case-name { display: flex; align-items: center; gap: 6px; font-size: 16px; font-weight: 700; color: #0C1626; }
.sl-case-meta { font-size: 13px; font-weight: 600; color: rgba(30, 50, 80, .7); }
.sl-case-metric {
  padding: 4px 10px; border-radius: 8px; background: rgba(46, 124, 255, .1);
  font-size: 13px; font-weight: 700; color: #1B5FE8;
}
.sl-case-who .head-btn { margin-left: auto; }
/* 限宽 880:不限的话中间列有 1170,一行能排 78 个字 —— 读到行尾要找下一行的行首。
   三条引言在这个宽度下都是整 2 行,卡高也就跟着稳住了。 */
.sl-case-q {
  margin: 15px 0 0; max-width: 880px; font-size: 15px; line-height: 1.85;
  color: rgba(20, 35, 60, .82); text-wrap: pretty;
}
/* 导航整列垂直居中:卡是 align-items:start(引号要贴顶),不单独居中的话
   圆点会顶在商家行那一行、下面空一截。 */
.sl-case-nav { align-self: center; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.sl-case-dots { display: flex; flex-direction: column; gap: 7px; }
.sl-case-dot {
  width: 7px; height: 7px; padding: 0; border: none; border-radius: 50%;
  background: rgba(13, 38, 90, .16); cursor: pointer; transition: background .2s ease;
}
.sl-case-dot.is-on { background: #1B6BFF; }
.sl-case-arw {
  width: 34px; height: 34px; padding: 0; border-radius: 50%; cursor: pointer;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .12); color: rgba(30, 50, 80, .6);
  display: flex; align-items: center; justify-content: center;
  transition: border-color .2s ease, color .2s ease;
}
.sl-case-arw:hover { border-color: rgba(27, 107, 255, .55); color: #1B6BFF; }

/* 提现渠道行。品牌与图标同源 SELLER_PAYOUTS,规则不在这里复述(指回费率表)。 */
.sl-payout {
  padding: 34px 40px; box-sizing: border-box; border-radius: 22px; text-align: center;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
}
.sl-payout-h { margin: 0; font-size: 22px; line-height: 28px; font-weight: 700; color: #0C1626; }
.sl-payout-sub {
  margin: 8px auto 0; max-width: 640px;
  font-size: 14px; line-height: 1.7; color: rgba(30, 50, 80, .7);
}
.sl-payout-row { margin-top: 26px; display: flex; align-items: center; justify-content: center; gap: 46px; }
.sl-payout-item { display: flex; align-items: center; gap: 9px; }
.sl-payout-item img { width: 26px; height: 26px; object-fit: contain; display: block; }
.sl-payout-item b { font-size: 15px; font-weight: 700; color: rgba(20, 35, 60, .78); }
.sl-perks { margin-top: 22px; display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.sl-perk {
  box-sizing: border-box; padding: 22px; border-radius: 16px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  display: flex; flex-direction: column; gap: 8px;
  transition: transform .15s var(--ease-out), box-shadow .15s ease, border-color .2s ease;
}
.sl-perk:hover {
  transform: translateY(-3px); border-color: rgba(46, 124, 255, .4);
  box-shadow: 0 16px 36px rgba(13, 38, 90, .13);
}
.sl-perk-ico {
  width: 42px; height: 42px; border-radius: 12px; background: rgba(46, 124, 255, .1);
  display: flex; align-items: center; justify-content: center;
}
.sl-perk-title { font-size: 16px; line-height: 22px; font-weight: 700; color: #0C1626; }
.sl-perk-sub { font-size: 14px; line-height: 1.7; color: rgba(30, 50, 80, .7); text-wrap: pretty; }
.sl-steps {
  margin: 22px 0 0; padding: 0; list-style: none;
  counter-reset: slstep;
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px;
}
.sl-step {
  position: relative; box-sizing: border-box; padding: 44px 18px 20px; border-radius: 16px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  display: flex; flex-direction: column; gap: 6px;
  counter-increment: slstep;
}
/* 序号由 counter 生成,文案里不写「1.」—— 同说明页那条规矩 */
.sl-step::before {
  content: counter(slstep);
  position: absolute; top: 18px; left: 18px;
  width: 26px; height: 26px; border-radius: 8px;
  background: #1B6BFF; color: #ffffff;
  font-size: 14px; font-weight: 700; line-height: 27px; text-align: center;
}
.sl-step-t { font-size: 15px; font-weight: 700; color: #0C1626; }
.sl-step-d { font-size: 14px; line-height: 1.7; color: rgba(30, 50, 80, .7); text-wrap: pretty; }
/* 资质与费率:两列等宽,align-items:start 让两块各按自己的内容收高 —— 两列条目数
   不等时(需求 4 条 / 费率 4 行,行高不同)拉伸对齐会在短的那块底部留一片空白。 */
.sl-two { margin-top: 22px; display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
.sl-box {
  box-sizing: border-box; padding: 24px 26px; border-radius: 18px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
}
.sl-box-h { margin: 0 0 14px; font-size: 17px; line-height: 22px; font-weight: 700; color: #0C1626; }
.sl-need { margin: 0; padding-left: 20px; }
.sl-need li { margin-bottom: 8px; font-size: 14px; line-height: 1.75; color: rgba(20, 35, 60, .8); text-wrap: pretty; }
.sl-need li::marker { color: rgba(27, 107, 255, .45); }
.sl-fee-row {
  padding: 11px 0; border-bottom: 1px solid rgba(13, 38, 90, .06);
  display: flex; align-items: baseline; gap: 14px;
}
.sl-fee-row:last-child { border-bottom: none; }
.sl-fee-row span { width: 96px; flex: none; font-size: 14px; font-weight: 700; color: rgba(30, 50, 80, .72); }
.sl-fee-row b { flex: 1; font-size: 14px; line-height: 1.65; font-weight: 600; color: #0C1626; }
/* 字段样式在申请向导(#/seller/apply)里复用 —— 招商页那张行内表单已经整段搬去
   向导,所以外壳 .sl-form 与 .sl-submit 一并删净,留下的是字段本身。 */
.sl-field { display: block; }
.sl-field-wide { grid-column: 1 / -1; }
/* :first-child 是必需的 —— 两个下拉字段里还有第二个 span(.sl-sel 那层 caret 壳),
   不限定的话它会拿到标签的 margin-bottom 与字号,字段底下平白多出 6px。 */
.sl-field > span:first-child {
  display: block; margin-bottom: 6px;
  font-size: 14px; font-weight: 700; color: rgba(30, 50, 80, .75);
}
.sl-field input, .sl-field select, .sl-field textarea {
  box-sizing: border-box; width: 100%; padding: 11px 13px;
  border: 1px solid rgba(13, 38, 90, .12); border-radius: 11px;
  background: rgba(13, 38, 90, .025);
  font-family: inherit; font-size: 14px; font-weight: 500; color: #0C1626;
  outline: none; resize: vertical;
  transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.sl-field input:focus, .sl-field select:focus, .sl-field textarea:focus {
  border-color: rgba(27, 107, 255, .6); background: #ffffff;
  box-shadow: 0 0 0 3px rgba(46, 124, 255, .14);
}
/* 下拉的 caret 壳:select 仍是 width:100%,字段宽度与上面几个 input 一致。
   这两条必须排在上面那组共用规则之后 —— 特异性相同,padding 简写会盖掉 padding-right。 */
.sl-sel { position: relative; display: block; }
.sl-field select { appearance: none; -webkit-appearance: none; padding-right: 34px; }
.sl-sel .sel-caret { right: 13px; }
.sl-faq {
  margin-top: 22px; box-sizing: border-box; padding: 6px 28px; border-radius: 18px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05);
  max-width: 860px;
}
.sl-faq .info-qa { max-width: none; }

/* ── 推荐有礼 #/invite ─────────────────────────────────────────────
   整页的骨架借招商页(`.sl-hero` / `.sl-steps` / `.sl-perks` / `.sl-band` / `.sl-faq`)——
   两者是同一种东西(一张全宽的招募着陆页),单给这一页另造一套表面就是自立一套。
   下面这几条只是它自己的那张链接面板,以及三步卡的列数。 */
/* `.sl-steps` 写死 5 列(招商页 5 步),三步的页面不覆盖的话会缩在左边、右侧空两格。
   **列数跟着步数走,别去改基类**;`.sl-steps-3` 与 `.sl-perks-3` 由推荐有礼页与
   推广合作页共用(三步流程 / 六张卡排两行)。 */
.sl-steps-3 { grid-template-columns: repeat(3, 1fr); }
.sl-perks-3 { grid-template-columns: repeat(3, 1fr); }
/* 面板坐在 hero 的第二列(400px)里,外壳是 `.sl-art`,这里只补内边距与内部间距:
   `.sl-art` 那套 18/20 是配一张 108 高的示意图的,装不下「标签 + 链接行 + 标签 +
   三个分享按钮 + 脚注」五行。 */
.inv-panel { padding: 22px 22px 20px; }
.inv-panel .sh-label-2 { margin-top: 18px; }
/* 只读链接框。几何与配色照分享弹窗那一格(#shLink):同样是「给人看和复制的链接」,
   两处长得不一样才是问题。那一条是 id 选择器、只作用于弹窗里那一个 input。 */
.inv-link {
  flex: 1; min-width: 0; box-sizing: border-box; height: 44px; padding: 0 14px;
  background: rgba(13, 38, 90, .05);
  border: 1px solid rgba(13, 38, 90, .1); border-radius: 10px;
  font-size: 13px; color: rgba(30, 50, 80, .8);
  text-overflow: ellipsis;
}
.inv-link:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
/* 脚注:推荐码 + 绑定的邮箱。12px 次要文字的对比度下限仍是 4.5:1(同消息中心那条),
   所以 `.7` 不再往浅压。 */
.inv-code {
  margin: 16px 0 0; padding-top: 13px; border-top: 1px solid rgba(13, 38, 90, .08);
  font-size: 12px; line-height: 18px; color: rgba(30, 50, 80, .7);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.inv-code b { font-weight: 700; color: #0C1626; }
/* 未登录态:一段说明 + 一颗登录按钮。说明文字用 13/1.7,比 `.sl-sub` 小一档 ——
   它坐在 356 宽的卡里,不是 hero 那半边的通栏。 */
.inv-note { margin: 0; font-size: 13px; line-height: 1.7; color: rgba(30, 50, 80, .7); text-wrap: pretty; }
.inv-cta { margin-top: 16px; }

/* ── 推广合作 #/affiliate + #/affiliate/apply ──────────────────────
   着陆页整块借招商页的组件(见 renderAffiliateView),申请表借入驻向导那套字段样式,
   所以这里只剩一条:表单卡的上边距(`.sl-box` 只有内边距,没有 margin-top)。
   **页头副标 `.aff-sub` 2026-08-05 按用户要求删掉,那条 CSS 一并删净,不是漏写** ——
   它写的「三件事:渠道是什么、有多少人看、打算怎么推」正是下面七个字段自己在说的,
   而「1–2 个工作日内给结果」在着陆页流程第 1 步与成功页各写过一次。 */
.aff-form { margin-top: 22px; }

/* ── 入驻申请向导 #/seller/apply ───────────────────────────────────
   一屏一问,6 步。页头居中是照参考站,站内也已有先例 —— 支付结果页 .done-hero
   同样居中,两页都是「流程的一个节点」而不是可以接着逛的列表。
   卡宽 860 沿用招商页表单与 FAQ 的既有宽度,不另立一个数。 */
.slw-wrap { max-width: 860px; margin-inline: auto; }
.slw-head { margin-top: 26px; text-align: center; }
.slw-head-row { display: flex; align-items: center; justify-content: center; gap: 9px; }
/* SHIELD_SVG 是 12×12 的认证盾(给报价卡用的),这里靠 viewBox 放大复用,
   不另抄一份 path */
.slw-head-row .prod-verify { width: 22px; height: 22px; }
.slw-title { margin: 0; font-size: 30px; line-height: 38px; font-weight: 700; color: #0C1626; }
.slw-step { margin: 7px 0 0; font-size: 14px; font-weight: 600; color: rgba(30, 50, 80, .7); }
.slw-card {
  position: relative; margin-top: 20px; box-sizing: border-box; padding: 36px 40px 34px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08); border-radius: 22px;
  box-shadow: 0 10px 30px rgba(13, 38, 90, .07); overflow: hidden;
}
/* 进度条压在卡片上沿:参考站就是这个位置。宽度由步数算,不写死每一步的百分比 */
.slw-bar { position: absolute; left: 0; right: 0; top: 0; height: 4px; background: rgba(13, 38, 90, .06); }
.slw-bar i { display: block; height: 100%; background: linear-gradient(90deg, #2E7CFF, #1B5FE8); transition: width .3s ease; }
.slw-q { margin: 0 0 22px; text-align: center; font-size: 20px; line-height: 28px; font-weight: 700; color: #0C1626; }

/* 单选 / 多选:用真的 input 而不是自绘 button —— required 与选中态交给浏览器,
   才不用再维护一份 JS state(同 auth 页「校验走原生」那条)。appearance:none
   把外观收回站内这套表面,同报价页排序下拉那次改法。 */
.slw-opts { display: flex; flex-direction: column; }
.slw-opt {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 11px 13px; border-radius: 12px; cursor: pointer;
  transition: background-color .2s ease;
}
.slw-opt:hover { background: rgba(46, 124, 255, .05); }
/* 第 6 步的协议勾选(.slw-agree)也走这一套 —— 漏掉它的话,整页就剩它一个是
   Chrome 原生控件(实测 13px 灰框),同报价页排序下拉那条 */
.slw-opt input, .slw-agree input {
  appearance: none; -webkit-appearance: none; flex: none; margin: 1px 0 0;
  width: 18px; height: 18px; box-sizing: border-box;
  border: 1.5px solid rgba(13, 38, 90, .24); background: #ffffff; cursor: pointer;
  transition: background-color .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.slw-opt input[type="radio"] { border-radius: 50%; }
.slw-opt input[type="checkbox"], .slw-agree input { border-radius: 5px; }
.slw-opt:hover input, .slw-agree:hover input { border-color: rgba(27, 107, 255, .55); }
.slw-opt input:checked, .slw-agree input:checked { border-color: #1B6BFF; background-color: #1B6BFF; }
/* 圆点用 inset 阴影而不是伪元素:input 上的 ::after 不是标准行为 */
.slw-opt input[type="radio"]:checked { box-shadow: inset 0 0 0 3.5px #ffffff; }
.slw-opt input[type="checkbox"]:checked, .slw-agree input:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 6.2 4.6 9 10 3.4'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: center; background-size: 11px 11px;
}
.slw-opt-txt { min-width: 0; }
.slw-opt-t { font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626; }
.slw-opt-d { display: block; margin-top: 2px; font-size: 13px; line-height: 19px; color: rgba(30, 50, 80, .7); text-wrap: pretty; }
/* 条件字段:勾了才出现。缩进对齐上面那行的文字,才看得出是它的下一层 */
.slw-when { margin: -2px 0 8px; padding-left: 43px; }

/* ── 推广申请表「你在哪里推」的多选网格(2026-08-06)──
   **基类 .slw-opt 一个字没动**,这里只加排列与品牌图标 —— 同 .sl-steps-3 /
   .sl-perks-3 那条:列数是修饰,别改基类(向导那 11 个类别仍是竖排一列)。
   4 列是量出来的:网格可用 806,4 列每格 195.5;而最宽的一项「Instagram」需要
   左右内边距 26 + 勾选框 18 + gap 12 + 图标 22 + gap 12 + 文字 68 = 158,余 37.5。
   **5 列每格只有 154.8,差 3.2 就会折行** —— 富余只有一格的量,加平台或改文案后
   照这个式子重量(判据是 .slw-opt-t 的高度还是不是 17,折行即 34)。 */
.slw-opts-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2px 8px; }
/* 每格只有一行文字(没有 .slw-opt-d),所以垂直居中;基类那 1px 的 input 上边距
   是配两行文字的,这里要复位,不然勾选框比图标高一格。 */
.slw-opts-grid .slw-opt { align-items: center; padding: 9px 13px; }
.slw-opts-grid .slw-opt input { margin-top: 0; }
/* 条件输入框通栏:它答的是上一行那个勾选,缩在 1/4 格里连站点地址都放不下。
   左内边距 13 对齐的是**勾选框**而不是文字 —— 单列那套缩进 43 是为了看出层级,
   而通栏之后左边是整片空白,缩进 43 只会让它比同栏其它字段短一截。 */
.slw-opts-grid .slw-when { grid-column: 1 / -1; margin: 0 0 8px; padding-left: 13px; }
.slw-opt-ico { flex: none; display: block; }
/* 「(多选)」跟在标签后面,是对这一组怎么答的说明,不是标签的一部分,所以退一档 */
.aff-multi { margin-left: 6px; font-size: 13px; font-weight: 500; font-style: normal; color: rgba(30, 50, 80, .6); }
.aff-where { margin-bottom: 20px; }

/* 提示条(第 3 步那句核验说明)。蓝底与站内其它「说明性」底色同一套 */
.slw-note {
  margin-bottom: 18px; padding: 13px 15px; border-radius: 12px;
  background: rgba(46, 124, 255, .07); border: 1px solid rgba(46, 124, 255, .18);
  display: flex; align-items: flex-start; gap: 10px;
}
.slw-note svg { flex: none; margin-top: 1px; }
.slw-note p { margin: 0; font-size: 14px; line-height: 21px; color: rgba(20, 35, 60, .82); text-wrap: pretty; }

.slw-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 18px; }
/* 字段按自身高度排,不跟着同排最高的那格拉伸 —— 拉伸的话,同排邻居多一行说明文字
   就会把这一格的 label 盒撑高,而字数计数是贴着盒底定位的,当场掉到输入框外面
   (实测店铺简介的「0 / 120」被 店铺名称 的说明推低 24px)。 */
.slw-grid > * { align-self: start; }
/* 第 3 步是「选项 + 字段」两段,中间要断开;其余步骤只有其中一种,不受影响 */
.slw-opts + .slw-grid { margin-top: 20px; }
/* 标签文字。有些格子(电话、收款渠道)不是一个 label 包一个控件的形状,
   套不上 .sl-field > span:first-child,所以另给一个类,声明与它保持一致。 */
.slw-lab {
  display: block; margin-bottom: 6px;
  font-size: 14px; font-weight: 700; color: rgba(30, 50, 80, .75);
}
/* 分组线:详细信息那一步里「本人 / 住址 / 联系方式」三段,不分段就是一片 12 个格子 */
.slw-rule { grid-column: 1 / -1; height: 1px; margin: 4px 0 0; background: rgba(13, 38, 90, .07); }
.slw-req {
  display: inline-block; width: 5px; height: 5px; margin-left: 3px; vertical-align: 2px;
  border-radius: 50%; background: #E5484D;
}
.slw-hint { margin: 6px 0 0; font-size: 13px; line-height: 19px; color: rgba(30, 50, 80, .7); }
/* 不可逆的选择用琥珀色 —— 它是提醒不是错误,借红色(#C0261F 在站内只表示错误
   与危险操作)会读成「这里填错了」 */
.slw-warn { margin: 6px 0 0; font-size: 13px; line-height: 19px; color: #B45309; }

/* 字数计数贴在输入框右侧内缘,同参考站 */
.slw-cw { position: relative; }
.slw-cw input, .slw-cw textarea { padding-right: 62px; }
.slw-cnt {
  position: absolute; right: 12px; bottom: 11px;
  font-size: 13px; font-weight: 600; color: rgba(30, 50, 80, .7); pointer-events: none;
}

/* 区号 + 号码:两格并排。**唯一使用者是推广申请表**(`#/affiliate/apply`)——
   入驻向导第 3 步 2026-08-06 换成店铺信息后不再收电话,跟着删净的是 .slw-code /
   .slw-code-btn 那对「验证码 + 获取代码」,不是漏写。 */
.slw-phone { display: flex; gap: 8px; }
.slw-phone .dial-pick { flex: none; }
.slw-phone input { flex: 1; min-width: 0; }

/* ── 区号选择器 ──────────────────────────────────────────────────────────
   **收起只印区号(窄按钮),展开才带国家名** —— 原生 select 这两条只能满足一条,
   所以这一格是站内唯一一个自绘的表单控件(值走它里面那格 hidden input)。
   按钮的几何照 .sl-field 那套输入框(41 高 / 11 圆角 / 同边框同底色),面板与行照
   顶栏下拉 .head-pop / .head-pop-row(14 圆角 / 34 行高 / 9 / 14/600),两边都不新
   取值 —— 它同时坐在这两套表面中间,自立第三套就会两头都不像。 */
.dial-pick { position: relative; display: block; }
.dial-btn {
  position: relative; box-sizing: border-box; width: 84px; height: 41px;
  display: flex; align-items: center; padding: 0 13px; cursor: pointer;
  border: 1px solid rgba(13, 38, 90, .12); border-radius: 11px;
  background: rgba(13, 38, 90, .025);
  font-family: inherit; font-size: 14px; font-weight: 500; color: #0C1626;
  transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.dial-btn:hover { border-color: rgba(13, 38, 90, .22); }
/* 焦点环照 .sl-field input:focus,键盘走到这一格与走到号码框长得一样 */
.dial-btn:focus-visible {
  outline: none; border-color: rgba(27, 107, 255, .6); background: #ffffff;
  box-shadow: 0 0 0 3px rgba(46, 124, 255, .14);
}
/* 面板比按钮宽得多,**必须写 width: max-content**:absolute 元素按 shrink-to-fit 算宽、
   上限是包含块,而包含块 .dial-pick 只有 84 —— 不写的话每一行都会折成两行
   (同 .msg-up-pop 那条)。35 行装不下一屏,所以自己滚。 */
.dial-pop {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 20;
  width: max-content; max-height: 288px; overflow-y: auto;
  box-sizing: border-box; padding: 8px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .1); border-radius: 14px;
  box-shadow: 0 18px 48px rgba(13, 38, 90, .18);
  transform-origin: top left;
  animation: popDown .15s var(--ease-out);
}
.dial-row {
  width: 100%; height: 34px; padding: 0 10px; border: none; border-radius: 9px;
  background: transparent; cursor: pointer; text-align: left;
  display: flex; align-items: center; gap: 10px;
  font-family: inherit; font-size: 14px; font-weight: 600; color: #0C1626;
  transition: background-color .2s ease;
}
/* 区号列定宽,国家名才对得成一列(最宽的读数是 +966) */
.dial-row b { flex: none; min-width: 40px; font-weight: 600; color: rgba(30, 50, 80, .6); }
.dial-row:hover { background: rgba(46, 124, 255, .09); }
.dial-row.is-on { color: #1B5FE8; }
.dial-row.is-on b { color: #1B5FE8; }
.dial-row svg { margin-left: auto; flex: none; display: block; }
.dial-row.is-on svg {
  box-sizing: content-box; width: 10px; height: 10px; padding: 3px;
  border-radius: 50%; background: #1B6BFF;
}

/* 上传框。原生 file input 铺满整块并透明化,点哪儿都能选,同时保留原生 required
   与键盘可达 —— 换成 button + click() 转发就得自己补这两件事 */
.slw-file {
  position: relative; box-sizing: border-box; min-height: 74px; padding: 14px 16px;
  border: 1.5px dashed rgba(13, 38, 90, .18); border-radius: 12px;
  background: rgba(13, 38, 90, .02); cursor: pointer;
  display: flex; align-items: center; gap: 12px;
  transition: background-color .2s ease, border-color .2s ease;
}
.slw-file:hover { border-color: rgba(27, 107, 255, .5); background: rgba(46, 124, 255, .04); }
.slw-file input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.slw-file svg { flex: none; }
.slw-file-txt { min-width: 0; }
.slw-file-t { display: block; font-size: 14px; font-weight: 700; color: #0C1626; }
.slw-file-n {
  display: block; margin-top: 3px; font-size: 13px; line-height: 19px; color: rgba(30, 50, 80, .7);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.slw-file.is-on { border-style: solid; border-color: rgba(27, 107, 255, .45); background: rgba(46, 124, 255, .05); }
.slw-file.is-on .slw-file-n { color: #1B5FE8; font-weight: 600; }
/* 店铺头像:62 方图 + 「选择图片」按钮,占半格(2026-08-06 用户在三个形态里选的)。
   **不是 .slw-file 那种通宽虚线框** —— 那一版被否决:删掉副文案之后,780 宽的框里
   只有左边 200 有东西,那圈框等于把右边的空白圈起来强调了一遍。现在它与同屏其它字段
   同构(标签在上、控件在下),右边的空白读作栅格留白,没有框去圈它。 */
.slw-ava-row { display: flex; align-items: center; gap: 12px; }
/* 62 / radius 15 照站内既有的方图(.offer-thumb / .sgc-ico),不自取一个尺寸。
   box-sizing 不能省:空态那圈 1.5px 虚线走 content-box 会把方块撑到 65,行跟着高 3px ——
   选完头像下半屏当场跳一下(同气泡 border 写 transparent 那条)。 */
.slw-ava {
  box-sizing: border-box; flex: none; width: 62px; height: 62px;
  border-radius: 15px; object-fit: cover;
}
.slw-ava.is-empty { border: 1.5px dashed rgba(27, 107, 255, .4); background: rgba(46, 124, 255, .07); }
/* 按钮几何照同屏输入框(高 42 / radius 11),配色照 .head-btn-promo 那档浅蓝 ——
   **不用实心蓝**:那是主行动按钮那一档,一个上传控件占不起(同详情页卖家条那条)。
   hover 只换底色不位移,所以按文件末尾那节的收录判据**不进按压名单**。 */
.slw-ava-btn {
  position: relative; flex: none; box-sizing: border-box; height: 42px; padding: 0 18px;
  display: inline-flex; align-items: center; border-radius: 11px;
  border: 1px solid rgba(46, 124, 255, .35); background: rgba(46, 124, 255, .09);
  color: #1B5FE8; font-size: 14px; font-weight: 700; white-space: nowrap; cursor: pointer;
  transition: background-color .2s ease, border-color .2s ease;
}
/* 整格是一个 <label>,点方图与标签同样会触发,所以 hover 挂在整行上 */
.slw-ava-row:hover .slw-ava-btn { background: rgba(46, 124, 255, .16); border-color: rgba(46, 124, 255, .6); }
/* file input 铺满按钮并透明化(同 .slw-file 那条):**不能换成 display:none** ——
   它是必填的,不可聚焦的控件会让 Chrome 拒绝提交并报 "not focusable"。
   选择器写足 (0,2,1) 压过 `.sl-field input` 那组的 width:100% + padding + 灰底,
   **不依赖谁写在后面**(同 .sl-sel caret 那条踩过的顺序坑)。 */
.sl-field .slw-ava-btn input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  padding: 0; border: none; background: none; opacity: 0; cursor: pointer;
}

/* 收款宫格复用结算页的 .co-pays / .co-pay:同一套表面,不为这一页另画一版。
   选中态仍走 is-active 类(由 JS 同步),里面那个 radio 只负责取值与原生校验。 */
.slw-pays { grid-template-columns: repeat(3, 1fr); }
.slw-pays .co-pay { position: relative; }
.slw-pays .co-pay input { position: absolute; inset: 0; margin: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }

/* 确认页摘要。每组右端的「修改」跳回对应那一步 —— 走到第 6 步才发现第 1 步选错,
   没有这条出口就只能一路后退。
   **排布是两级堆叠:上行「组名 + 修改」,下行值**(2026-08-07 按用户「信息排版需要
   继续优化」从「标签 | 值 | 修改」三列改过来,理由与实测见 `slwSumRow` 那段注释 ——
   一句话:值列 626 宽而五条值没有一条把它占满,三列中间空掉一大片)。 */
.slw-sum { border-top: 1px solid rgba(13, 38, 90, .07); }
.slw-sum-row { padding: 14px 2px 16px; border-bottom: 1px solid rgba(13, 38, 90, .06); }
.slw-sum-top { display: flex; align-items: baseline; gap: 12px; }
/* 组名走站内组标签那一档(14/20 的 600 近黑、无字距):它是这一组的名字。
   `flex:1` 把「修改」顶到右端 —— 不写 `margin-left:auto` 是因为组名本来就该占满
   这一行,长组名时才不会与按钮挤在一起。 */
.slw-sum-k {
  flex: 1; min-width: 0; font-size: 14px; line-height: 20px;
  font-weight: 600; color: #0C1626;
}
/* 字段两列,与第 3 / 4 / 5 步表单的 `.slw-grid` 同一种排布(那边是 `1fr 1fr` + 14/16
   的 gap)——摘要因此读起来是同一份表的只读视图。长值(主营商品 120 字)占整行。 */
.slw-sum-grid { margin-top: 10px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px 20px; }
.slw-sum-f { min-width: 0; }
.slw-sum-f-wide { grid-column: 1 / -1; }
/* 字段名 13 灰在上、值 14 近黑在下(同个人中心 `.acct-field` 那对只读键值)。
   **值不加粗到 700**:字段名已经把它标出来了,一屏十几个 700 的值反而没有重点。 */
.slw-sum-fk { display: block; font-size: 13px; line-height: 18px; color: rgba(30, 50, 80, .7); }
.slw-sum-fv {
  display: block; margin-top: 2px; font-size: 14px; line-height: 21px;
  font-weight: 600; color: #0C1626; text-wrap: pretty; overflow-wrap: anywhere;
}
/* 「修改」与组名同号(13):它是这一组的附属动作,比组名重的话五颗蓝字会连成
   整屏最抢眼的一列。 */
.slw-edit {
  flex: none; padding: 0; border: none; background: none; cursor: pointer;
  font-family: inherit; font-size: 13px; font-weight: 600; color: #1B6BFF;
}
.slw-edit:hover { text-decoration: underline; }
.slw-agree { margin-top: 20px; display: flex; align-items: flex-start; gap: 12px; }
.slw-agree .slw-opt-t { font-weight: 500; color: rgba(20, 35, 60, .82); }
.slw-agree a { font-weight: 600; }

/* 两颗按钮居中并排,同参考站。min-width 让「后退 / 下一个」两颗等宽 —— 字数不同,
   不定宽的话中线会偏 */
.slw-acts { margin-top: 22px; display: flex; justify-content: center; gap: 14px; }
.slw-acts .solo-cta { margin-top: 0; min-width: 172px; justify-content: center; }

/* ── 详情页:购买 + 加购两个 CTA ────────────────────────────────── */
/* 上边距挂在行上而不是 .buy-cta 上:挂在按钮上时,同排的 .buy-cart 没有这段
   外边距又被 stretch 拉高,实测 66px vs 50px、顶边高出 16px */
.buy-acts { margin-top: 14px; display: flex; align-items: center; gap: 10px; }
.buy-acts .buy-cta { flex: 1; min-width: 0; }
.buy-cart {
  width: 50px; height: 50px; box-sizing: border-box; flex: none;
  border-radius: 12px; cursor: pointer; padding: 0;
  background: rgba(46, 124, 255, .06); border: 1px solid rgba(46, 124, 255, .28); color: #1B5FE8;
  display: flex; align-items: center; justify-content: center;
  transition: background-color .2s ease, border-color .2s ease, transform .2s var(--ease-out);
}
.buy-cart:hover { background: rgba(46, 124, 255, .12); border-color: rgba(46, 124, 255, .55); transform: translateY(-2px); }
/* ── 结算页:优惠码 ──────────────────────────────────────────────── */
/* 只做大写化,**不加字距** —— 结算页的排版契约是「字距只出现在 .co-label 一种样式上」
   (见 README「结算页的排版契约」)。uppercase 已经足够说明这格填的是码。 */
/* 优惠码坐在订单摘要卡里、明细与分隔线之间。只留 14 的间距、**不加第二条分隔线** ——
   「明细与应付之间那条线是全卡唯一的分隔」那条契约还在,再画一条就把演算区切成两截。
   核验通过时提示行 hidden,卡片跟着矮 22px,与总额变小是同一次反馈。 */
/* 2026-08-06 收成折叠(按用户要求,照参考站 GamsGo 结算页那块):没有码的人不必一直
   看着一个填不上的空框,收起态整块只占一行。
   折叠复用说明页那套原生 <details> + ::details-content(见 .info-qa),**同样不接管开合** ——
   理由与那一处逐字相同,别为这 200ms 的动画去加 JS。箭头也直接复用 .info-caret,
   但它的 [open] 旋转规则挂在 .info-qa 上,这里得自己补一条。
   **代价是「新人首单可用 NEWBIE5」那句提示进了折叠层**:首页弹窗广告与新手教程仍在喊
   这个码,所以它没有变成"页面上找不到"—— 这是折叠本身的取舍,不是漏写。 */
/* 左右各外扩 6:::details-content 的 overflow:hidden 按**这一层**的宽度裁剪,而
   .co-field:focus-within 那圈 4px 外发光是往外长的 —— 不把裁剪边界撑开,一聚焦
   左右两侧就各被切掉一刀(上下不会,那边有 padding 顶着)。撑开之后再靠 summary 与
   .co-code-body 各自的水平 padding 6 把内容收回 334 的右脊上,所以看得见的位置一点没变。
   **别改成给 .co-code-body 加 padding + 负 margin 对消**(报价页左栏 .off-rows-in 那套):
   那样内容位置虽对,裁剪边界却仍是原宽,光晕照剪不误 —— 两处要解决的不是同一个问题。 */
.co-code { margin: 14px -6px 0; }
.co-code-q {
  padding: 0 6px; cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 12px;
  font-size: 14px; line-height: 20px; font-weight: 600; color: #0C1626;
  transition: color .2s ease;
}
.co-code-q::-webkit-details-marker { display: none; }
.co-code-q:hover { color: #1B6BFF; }
.co-code[open] .info-caret { transform: rotate(180deg); }
/* 上 10 是标题到输入框的间距,水平 6 把内容从外扩的那 12 里收回原位。
   **一律用 padding、不用垂直 margin**:margin 会与 ::details-content 的边界折叠,
   收起态就压不到 0。下边留 0,所以提示行底边就是折叠内容的底边。 */
.co-code-body { padding: 10px 6px 0; }
.co-code::details-content {
  block-size: 0; overflow: hidden;
  transition: block-size .2s var(--ease-out), content-visibility .2s allow-discrete;
}
.co-code[open]::details-content { block-size: calc-size(auto, size); }
/* 单写一条、不并进文件顶部那个选择器组,理由同 .info-qa 那处 */
@media (prefers-reduced-motion: reduce) {
  .co-code::details-content { transition: none; }
}
.co-field-code input { text-transform: uppercase; }
.co-hint.is-bad { color: #C0261F; }
.co-item + .co-item-flags + .co-body { margin-top: 14px; padding-top: 14px; border-top: 1px solid rgba(13, 38, 90, .06); }
.co-item-price { margin-left: auto; font-size: 14px; font-weight: 700; color: #0C1626; }

/* ═══════════════════════════════════════════════════════════════
   按压反馈 + 浮层收起
   **必须留在文件末尾**:每条 :active 都和对应的 :hover 同特异性(都是 0,2,0),
   同分靠顺序取胜 —— 写在前面会被 hover 那句的位移整条盖掉,症状是按下去毫无反应。
   ═══════════════════════════════════════════════════════════════ */

/* ── 按压 ──
   凡是 hover 会抬起的元素,按下去就得落回并轻微缩小:抬起是「这张能点」的邀请,
   按压是「点到了」的回执,只给前半句的话点下去像点在一张图片上。
   收录标准是「能点 + hover 会动」两条都满足 —— .pay-item / .sl-perk 也会抬起,
   但它们是 <div>、没有落点,给点不动的东西加按压反馈只会更像骗人。
   时长压到 .1s:按压是这一整套里唯一必须瞬时的东西,松手回弹走各自的基准时长,
   一头快一头缓,手感上才是「按下去」而不是「弹一下」。
   幅度分两档:卡片面积大,缩 .985 边框就已经明显动了;按钮小,要 .97 才读得出。 */
.banner-link:active, .promo-card:active, .feat-card:active, .hot-card:active,
.offer-card:active, .info-card.is-link:active, .cart-thumb:active,
.sl-want:active, .tp-card:active, .shop-gcard:active {
  transform: translateY(0) scale(.985);
  transition-duration: .1s;
}
.buy-cta:active, .co-cta:active, .solo-cta:active, .buy-cart:active,
.ad-modal-cta:active, .pa-tab:active,
.msg-send:active:not(:disabled), .shop-add:active, .shop-cs:active,
.shop-share:active, .sh-copy:active, .sh-way:active, .ord-cs:active, .rev-send:active {
  transform: translateY(0) scale(.97);
  transition-duration: .1s;
}
/* 会话行与状态 pill **不进这份名单**:按上面那条收录标准,它们 hover 只换底色、
   不抬起,而按下去的回执是选中态本身(整行变蓝底 / pill 变蓝框)—— 那比缩一下
   更明确也更持久。给它们再加一层按压就是在站内立第二套约定。 */
/* 步进器缩得比别的按钮狠:它是全站重复点击最多的控件,而 36px 见方的小按钮
   scale(.97) 只差 1px,基本看不出来 */
.buy-step:active { transform: scale(.9); transition-duration: .1s; }

/* ── 浮层收起 ──
   入场有动画、出场 hidden=true 瞬间消失是反的。收尾复用 toast 与 .route-load
   那套 .is-out + setTimeout,不新造机制;JS 的 POP_OUT 必须与这里的 .14s 对齐,
   短了会把浮层在淡出中途抽走。
   收的方向一律是入场的逆向,也就是**收回触发器那一侧**:挂在按钮下方的往上收
   (popDown 的逆向)。这样开关同一个浮层看着才是一件东西在原地进出,而不是两件
   东西穿过屏幕。改入场关键帧时这条要跟着改,方向一旦对不上就是「弹出来又从
   另一头飞走」。坐在按钮**上方**的浮层现在是附件菜单(`.msg-up-pop`,配 popUp
   的逆向),所以它单列一条、方向与上面那两个相反。 */
.sg-pop, .head-pop, .msg-up-pop, .dial-pop {
  transition: opacity .14s var(--ease-out), transform .14s var(--ease-out);
}
.sg-pop.is-out, .head-pop.is-out, .dial-pop.is-out { opacity: 0; transform: translateY(-4px) scale(.98); }
.msg-up-pop.is-out { opacity: 0; transform: translateY(4px) scale(.98); }
/* 遮罩淡出时必须一起关掉点击:它 opacity 已经是 0、看着已经没了,
   但 display 还是 flex,不关就白挡 .16s(同 .route-load.is-out 那条) */
.ad-modal, .sh-modal { transition: opacity .16s var(--ease-out); }
.ad-modal.is-out, .sh-modal.is-out { opacity: 0; pointer-events: none; }
.ad-modal.is-out .ad-modal-box,
.sh-modal.is-out .sh-box { transform: translateY(6px) scale(.98); transition: transform .16s var(--ease-out); }

/* ══════════════════════════════════════════════════════════════════════
   游戏专区(#/g/<game>/<kind>)
   页头是「品牌 + 类型 tab」一条:这一层的导航就是它,所以 hide-on-solo 里
   把类目侧栏收掉了(两套并行的导航比没有导航更难用)。
   下面三种版式全部复用既有组件,这里只写这一层外壳自己的几条。
   ══════════════════════════════════════════════════════════════════════ */
/* 三列栅格而不是「品牌 + margin-left:auto 的 tab 条」:后者会把 tab 顶到最右边,
   离品牌一整屏远,读起来像页头右上角的功能区而不是这一层的主导航(2026-08-03
   用户指出「放在中间,显眼一点」)。三列 `1fr auto 1fr` 让中列落在整条的正中,
   第三列空着只为占位。**三个子项都写死 `grid-column`** —— 同 `.head-row` 那条:
   靠自动排流的话,以后往右列加东西(比如换游戏的下拉)会把 tab 挤出中间那格。 */
.gm-head {
  height: 76px; margin-bottom: 4px;
  border-bottom: 1px solid rgba(13, 38, 90, .08);
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 16px;
}
.gm-brand { grid-column: 1; min-width: 0; display: flex; align-items: center; gap: 12px; }
/* 与 .prod-frame 同一套:2px 的渐变描边 + 内层白底方图,游戏图标与商品图标
   因此是同一种物件,只是尺寸小一档(44 对 56)。 */
.gm-logo { flex: none; padding: 2px; border-radius: 14px; }
.gm-ico {
  width: 44px; height: 44px; border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
}
.gm-ico img { width: 26px; height: 26px; object-fit: contain; display: block; }
.gm-letter { font-size: 16px; font-weight: 700; color: #123A8F; }
.gm-name { font-size: 22px; line-height: 28px; font-weight: 700; color: #0C1626; }

/* tab 用下划线而不是站内那种蓝底药丸:它贴着 .gm-head 的下边框,是「这一条线上
   现在停在哪一格」,与顶部导航那块会平移的蓝底不是一回事(那块跨的是整站类目)。
   ::after 压在边框上(bottom:-1px),选中时才显形 —— 用 border-bottom 切换的话
   未选中的 tab 会矮 2px,一排 tab 的基线就参差了。 */
/* 这一条是游戏专区唯一的导航,所以字号比站内其它 tab 重一档(15/600 对
   `.pdp-tab` 的 14/500):它要在整页里第一眼被看见,而不是等人找。 */
.gm-tabs { grid-column: 2; align-self: stretch; display: flex; align-items: stretch; }
.gm-tab {
  position: relative; padding: 0 20px; display: flex; align-items: center;
  font-size: 15px; font-weight: 600; color: rgba(30, 50, 80, .78);
  white-space: nowrap; transition: color .2s ease;
}
.gm-tab::after {
  content: ""; position: absolute; left: 20px; right: 20px; bottom: -1px; height: 3px;
  background: #1B6BFF; border-radius: 3px 3px 0 0;
  opacity: 0; transition: opacity .2s ease;
}
.gm-tab:hover { color: #0C1626; }
.gm-tab.is-on { color: #1B5FE8; font-weight: 700; }
.gm-tab.is-on::after { opacity: 1; }
.gm-tab:focus-visible { outline: 2px solid #1B6BFF; outline-offset: -4px; border-radius: 8px; }

/* 计数 + 排序:横跨整行坐在 .off-main 之上,与已选条件 chips 同一个理由 ——
   放进右列会把栅格压下去,第一排卡片与左栏顶部的齐平就破了。
   计数在这一页靠左(参考站也是「413 找到的物品」在列表左上角):它是这一页的
   主语,而报价页那处是副语(页头已经写过商家数),所以那边靠右。 */
.gm-bar { min-height: 34px; display: flex; align-items: center; gap: 12px; }
.gm-bar .off-count { margin-right: auto; text-align: left; }
.gm-bar .off-sort { margin-left: auto; }

/* 可键入的数量框(计量型专用,见 buyPanelHtml 的 typable)。
   宽度按**全站最大的那个上限**定,不是按某一款游戏:92 是照 Robux 的 200,000(7 字符)
   量的,而艾尔登法环的卢恩上限是 100,000,000 —— 11 个字符实测 93px,在 92 的框里
   (内边距 0、内容区 90)当场被切,加到最大量就读不出自己买了多少。106 = 93 + 两侧
   各 6.5 余量。**加新的计量型商品时要拿它的 max 重量一遍这个数。** */
.buy-num-in {
  display: block; width: 106px; height: 36px; box-sizing: border-box;
  padding: 0; text-align: center; background: transparent;
  font-family: inherit; font-size: 15px; font-weight: 700; color: #0C1626;
  border-block: none; border-radius: 0;
}
.buy-num-in:focus-visible { outline: 2px solid #1B6BFF; outline-offset: -2px; }

/* 比价行里单价后面那个「/ Robux」:面值型没有它(那一列是整档的实付价),
   计量型必须有 —— 光一个 $0.006 说不清是一件多少钱还是一千个多少钱。 */
.tp-row-per { font-size: 12px; font-weight: 500; color: rgba(30, 50, 80, .7); }

/* 通往游戏专区的横幅(只挂在被引用的那件充值商品上,见 main.js 的 gmXlinkHtml)。
   卡片参数照站内其它卡:白底 + .08 描边 + 阴影 + 16 圆角,hover 抬 1px ——
   它是能点的,而站内「能点的卡 hover 会抬起」是一条一贯的信号。 */
.gm-xlink {
  margin: 16px 0 0; box-sizing: border-box; min-height: 62px; padding: 12px 18px;
  background: #ffffff; border: 1px solid rgba(13, 38, 90, .08);
  box-shadow: 0 6px 20px rgba(13, 38, 90, .05); border-radius: 16px;
  display: flex; align-items: center; gap: 14px;
  transition: border-color .2s ease, box-shadow .2s ease, transform .2s var(--ease-out);
}
.gm-xlink:hover {
  border-color: rgba(27, 107, 255, .35);
  box-shadow: 0 16px 36px rgba(13, 38, 90, .1);
  transform: translateY(-1px);
}
.gm-xlink:focus-visible { outline: 2px solid #1B6BFF; outline-offset: 2px; }
.gm-xlink-logo { flex: none; padding: 2px; border-radius: 12px; }
.gm-xlink-ico {
  width: 34px; height: 34px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.gm-xlink-ico img { width: 20px; height: 20px; object-fit: contain; display: block; }
.gm-xlink-letter { font-size: 13px; font-weight: 700; color: #123A8F; }
.gm-xlink-txt { min-width: 0; display: flex; align-items: baseline; gap: 10px; }
.gm-xlink-txt b { font-size: 15px; font-weight: 700; color: #0C1626; }
/* 「还有 游戏账号 · 礼品卡 …」是这条横幅的正文,不是角标,所以走 13 不压到 12 以下 */
.gm-xlink-txt i {
  font-style: normal; font-size: 13px; line-height: 19px;
  color: rgba(30, 50, 80, .7);
}
.gm-xlink-go {
  margin-left: auto; flex: none; display: flex; align-items: center; gap: 6px;
  font-size: 14px; font-weight: 700; color: #1B6BFF;
}

/* 品牌条贴着导航条,当成同一条带子读(2026-08-03 按用户「上面空位太大了」改;
   参考站的品牌条同样是紧贴页头的)。往上拉的 22 = `.main-wrap` 的 padding-top
   —— 其余视图留着这 22 给面包屑呼吸,而这两个页面的第一件东西是一条 76 高的
   实心导航,贴着导航条读成同一条带子才对。(`.layout` 原来还有 16,已按上面那条
   在非首页 / 分类页的视图里收掉,所以这里只需抵消 22。)
   **改上面任何一个数都要重算这里**,量的是 `.gm-head` 顶与导航条底的距离(应为 2)。
   两处都写:游戏页(`.game-view`)与游戏商品的详情页(`.pdp-view`,那里品牌条同样
   是第一个子节点),否则从专区点进一件物品,那条会往下跳 38px。
   `:first-child` 是必需的 —— 详情页只有游戏商品才顶着品牌条,其余商品第一个
   子节点是面包屑,那 38 得留着。 */
.game-view > .gm-head:first-child,
.pdp-view > .gm-head:first-child { margin-top: -22px; }

/* 游戏卡页脚右端那枚计数。借 .prod-flag 的药丸底，但它自带绿/橙的发货语义色，
   这里换成中性蓝灰 —— 「3 种买法」不是发货方式，不该染成「自动发货」那个绿。 */
.gcard-n {
  background: rgba(27, 107, 255, .08); border-color: rgba(27, 107, 255, .16);
  color: #1B5FE8;
}
/* 只有一种买法的游戏不渲染 tab 条(见 gmHeadHtml)。品牌条退成两列，
   否则空着的中列会把品牌推离左脊。 */
.gm-head.is-solo { grid-template-columns: auto 1fr; }
