/* ============================================================================
 * 京璟供应链商城 · 前台样式表
 * ----------------------------------------------------------------------------
 * 规范来源：docs/DESIGN-mall.md（v1 · 2026-09-11）
 * 用法：mall.html 以 <link rel="stylesheet" href="css/mall.css?v=N"> 引入。
 *       ⚠ 本文件每改一次，mall.html 里的 ?v=N 必须 +1，否则生产用户一直吃浏览器缓存的旧版。
 *       故障不报错、页面看着几乎正常，肉眼冒烟发现不了 —— 上线后用 curl 核 md5。
 *
 * 三条铁律（改这个文件前先读）：
 *   1. --clay（赭红）只许出现在三处：价格数字 / 主按钮 / 当前位置指示条。
 *      其余一律 --ink 系 + --rule 细线。加新组件时先问：它是这三类吗？
 *   2. 所有出现在列上的数字走 var(--mono) + tabular-nums。小数点必须对齐。
 *   3. 层级靠三级纸（paper → card → paper-2），不靠给每块描边加投影。
 *
 * 字体：中文只用系统字，不引 webfont（中文字库几 MB，高频进站客户不值当）。
 *       IBM Plex 已自托管在 client/fonts/（拉丁+数字子集，5 支共 45KB），详见下一段。
 *
 * 对比度：所有文字 token 对其真实背景均已过 WCAG AA（小字 4.5:1 / 大字 3:1），
 *        2026-09-11 全量核过一轮，修了 --ink-3 / --gone / --on-clay 三项。
 *        新增颜色前请按「前景对它真正会坐的那个背景」算，别拿它不会出现的组合凑数。
 * ========================================================================== */

/* ── 自托管字体【已启用】· 拉丁+数字子集 ─────────────────────────────────
 *
 * 文件在 client/fonts/，IBM Plex v6.4.0，SIL OFL 1.1
 * 许可证原文 client/fonts/LICENSE-IBMPlex.txt —— OFL 要求许可证随字体一起分发，
 * 删字体可以，但别单独删许可证。
 *
 *   IBMPlexSans-Regular.woff2     9,992 B
 *   IBMPlexSans-Medium.woff2     10,324 B
 *   IBMPlexSans-SemiBold.woff2   10,420 B
 *   IBMPlexMono-Regular.woff2     7,448 B
 *   IBMPlexMono-SemiBold.woff2    7,544 B
 *   ── 五支合计 45,728 B（源 TTF 的 5%），加许可证整目录 60 KB
 *
 * unicode-range 锁死拉丁段：中文字符永远不会落到 Plex 上去等加载，
 * 首屏中文立即可读（系统字直出），拉丁与数字随后 swap 进来。
 *
 * 复现命令（换字重照抄，v6.4.0 是钉死的标签不是 master）：
 *   curl -sSLO https://raw.githubusercontent.com/IBM/plex/v6.4.0/IBM-Plex-Sans/fonts/complete/ttf/IBMPlexSans-Regular.ttf
 *   pip install fonttools brotli
 *   pyftsubset IBMPlexSans-Regular.ttf \
 *     --unicodes="U+0020-007F,U+00A5,U+2013-2014,U+2018-201D,U+2026" \
 *     --layout-features="kern,liga,tnum" \
 *     --flavor=woff2 --output-file=client/fonts/IBMPlexSans-Regular.woff2
 *   （Mono 两支的源路径是 IBM-Plex-Mono/fonts/complete/ttf/）
 *
 * ⚠️ 若哪天把字体文件删了，务必把下面整段 @font-face 一起注释掉 ——
 *    指向不存在文件的声明会让生产每次访问打 5 个 404。
 *    回落栈 SFMono-Regular / Menlo / Consolas 同样带表格数字，删了版式也不塌。
 * ────────────────────────────────────────────────────────────────────────── */
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;
  src:url('../fonts/IBMPlexSans-Regular.woff2') format('woff2');
  unicode-range:U+0020-007F,U+00A5,U+2013-2014,U+2018-201D,U+2026;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;
  src:url('../fonts/IBMPlexSans-Medium.woff2') format('woff2');
  unicode-range:U+0020-007F,U+00A5,U+2013-2014,U+2018-201D,U+2026;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;
  src:url('../fonts/IBMPlexSans-SemiBold.woff2') format('woff2');
  unicode-range:U+0020-007F,U+00A5,U+2013-2014,U+2018-201D,U+2026;
}
@font-face{
  font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('../fonts/IBMPlexMono-Regular.woff2') format('woff2');
  unicode-range:U+0020-007F,U+00A5,U+2013-2014,U+2018-201D,U+2026;
}
@font-face{
  font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;
  src:url('../fonts/IBMPlexMono-SemiBold.woff2') format('woff2');
  unicode-range:U+0020-007F,U+00A5,U+2013-2014,U+2018-201D,U+2026;
}

/* ── Token ──────────────────────────────────────────────────────────────── */
:root{
  /* 三级纸 */
  --paper:#F2EDE4;          /* 页面画布 */
  --paper-2:#E8E2D6;        /* 凹进一级：表头 / 图位 / 输入槽 */
  --card:#FFFCF7;           /* 抬起一级：卡片 / 面板 */
  /* 墨 */
  --ink:#24201B;
  --ink-2:#5E574C;
  --ink-3:#6C6453;   /* 2026-09-11 从 #918978 压暗：原值对纸/卡仅 3.39:1，货号·库存·克重都是小字，不达 AA */
  /* 线 */
  --rule:#DCD4C4;
  --rule-2:#C3B9A4;
  /* 唯一彩色口 */
  --clay:#BE4A23;
  --on-clay:#FFFFFF;        /* 赭红底上的字。浅色白字 5.01:1 达标 */
  --clay-deep:#8E3415;
  --clay-tint:#F7E3D8;
  /* 结构深色（不是强调色） */
  --slate:#2C3543;
  --on-slate:#E7E2D7;
  /* 语义 · 四种货态，低饱和，永远不和赭红抢 */
  --stock:#2C6A4E;    --stock-bg:#E2EEE7;
  --drop:#2A5885;     --drop-bg:#E2EAF3;
  --made:#7E5410;     --made-bg:#F4EAD6;
  --gone:#6B6456;     --gone-bg:#E7E2D8;   /* 2026-09-11 从 #857E70 压暗：原值在 gone-bg 上仅 3.12:1（.tag.s9 / .oos 都是小字） */
  --alert:#A3311F;    --alert-bg:#FAE8E4;
  /* 字 */
  --sans:'PingFang SC','Hiragino Sans GB','Microsoft YaHei','Noto Sans SC',sans-serif;
  --latin:'IBM Plex Sans',var(--sans);
  --mono:'IBM Plex Mono','SFMono-Regular',Menlo,Consolas,monospace;
  /* 形 */
  --r-sm:8px;   /* 图位 / 输入 / 徽章 */
  --r-md:12px;  /* 卡片 / 面板 */
  --r-lg:16px;  /* 弹窗 / 画廊 */

  /* 向后兼容别名：防止 mall.js 行内 style 引用旧变量名失效。
     2026-09-11 供应商城板块已把行内样式清到 19 处且全部走 token，
     确认无人引用这些旧名后即可整段删除。 */
  --brand:var(--clay);
  --brand-dark:var(--clay-deep);
  --brand-bg:var(--clay-tint);
  --bg:var(--paper);
  --text:var(--ink);
  --text-2:var(--ink-2);
  --text-3:var(--ink-3);
  --border:var(--rule);
  --green:var(--stock);
  --green-bg:var(--stock-bg);
  --amber:var(--made);
  --amber-bg:var(--made-bg);
  --blue:var(--drop);
  --blue-bg:var(--drop-bg);
  --red:var(--alert);
  --radius:var(--r-md);
}

/* 深色 · 显式选择（<html data-theme="dark">）。下面还有一份跟随系统的 @media，
   两份 token 必须同步改 —— 改一处漏一处是这个文件最容易犯的错。 */
:root[data-theme="dark"]{
  --paper:#191612; --paper-2:#211D18; --card:#252118;
  --ink:#EFE9DC; --ink-2:#B5AD9C; --ink-3:#8F8777;
  --rule:#37312A; --rule-2:#4C4539;
  --clay:#E4703F; --on-clay:#2A1408; --clay-deep:#F4A583; --clay-tint:#3A1F14;
  --slate:#11151C; --on-slate:#E7E2D7;
  --stock:#6CC79B; --stock-bg:#13311F;
  --drop:#82B2E6;  --drop-bg:#122B44;
  --made:#E0AC5A;  --made-bg:#39280C;
  --gone:#948C7D;  --gone-bg:#2A251D;
  --alert:#EE8B79; --alert-bg:#3A1714;
}
/* 跟随系统深色：2026-09-11 放开。
   放开前提是「mall.js 行内 style 里硬编码颜色为零」—— 已实测：19 处行内 style，
   颜色全走 token，仅余 2 处动态色卡背景（.sku-sw / .dz-sw）必须留行内。
   守卫 :not([data-theme="light"]) 让显式选浅色能压过深色系统设置。 */
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
  --paper:#191612; --paper-2:#211D18; --card:#252118;
  --ink:#EFE9DC; --ink-2:#B5AD9C; --ink-3:#8F8777;
  --rule:#37312A; --rule-2:#4C4539;
  --clay:#E4703F; --on-clay:#2A1408; --clay-deep:#F4A583; --clay-tint:#3A1F14;
  --slate:#11151C; --on-slate:#E7E2D7;
  --stock:#6CC79B; --stock-bg:#13311F;
  --drop:#82B2E6;  --drop-bg:#122B44;
  --made:#E0AC5A;  --made-bg:#39280C;
  --gone:#948C7D;  --gone-bg:#2A251D;
  --alert:#EE8B79; --alert-bg:#3A1714;
}}

/* ── 基础 ───────────────────────────────────────────────────────────────── */
*{margin:0;padding:0;box-sizing:border-box}
body{
  font-family:var(--sans);font-size:14px;line-height:1.6;
  color:var(--ink);background:var(--paper);-webkit-font-smoothing:antialiased;
}
button{font-family:inherit;cursor:pointer}
input,textarea,select{font-family:inherit}
.hidden{display:none!important}
:focus-visible{outline:2px solid var(--clay);outline-offset:2px;border-radius:3px}
::selection{background:var(--clay-tint);color:var(--clay-deep)}
/* 所有数字：等宽 + 表格对齐。这是这门生意的排版声音。 */
.num,.pprice,.tp,.ck-total .amt,.qty-input,.sku-stock,.d-code,.pmeta,
.dz-code,.al-qin,.ocard-h .no,.ocard-h .time,.ocard-f .tt b,.dz-total b,
.m-total b,.oitem span:last-child,.tier .tq{
  font-family:var(--mono);font-variant-numeric:tabular-nums;
}

/* ── 登录页 ─────────────────────────────────────────────────────────────── */
/* 整页登录墙 #loginView 已于 2026-09-22 撤除（改为弹窗，见文末「游客预览」段），其样式同步删除 */
.login-card{
  width:100%;max-width:380px;background:var(--card);border:1px solid var(--rule);
  border-radius:var(--r-lg);padding:36px 32px;
}
.login-logo{
  width:52px;height:52px;border-radius:var(--r-md);background:var(--ink);color:var(--paper);
  display:flex;align-items:center;justify-content:center;font-size:26px;margin:0 auto 14px;
}
.login-card h1{font-size:20px;font-weight:600;text-align:center;margin-bottom:4px;letter-spacing:-.01em}
.login-card .sub{text-align:center;color:var(--ink-3);font-size:13px;margin-bottom:26px}
.field{margin-bottom:14px}
.field label{display:block;font-size:13px;color:var(--ink-2);margin-bottom:6px}
.field input{
  width:100%;height:42px;border:1px solid var(--rule-2);border-radius:var(--r-sm);
  padding:0 12px;font-size:14px;background:var(--paper-2);color:var(--ink);outline:none;
}
.field input:focus{border-color:var(--clay);background:var(--card)}
.login-err{color:var(--alert);font-size:13px;margin-bottom:10px;display:none}
/* 主按钮 —— 赭红三处之二 */
.btn-brand{
  width:100%;height:44px;background:var(--clay);color:var(--on-clay);border:none;
  border-radius:var(--r-sm);font-size:15px;font-weight:500;
}
.btn-brand:hover{background:var(--clay-deep)}
.btn-brand:disabled{opacity:.45;cursor:not-allowed}

/* ── 顶栏 ───────────────────────────────────────────────────────────────── */
header{background:var(--card);border-bottom:1px solid var(--rule);position:sticky;top:0;z-index:50}
.header-inner{
  max-width:1200px;margin:0 auto;padding:11px 16px;
  display:flex;align-items:center;gap:16px;flex-wrap:wrap;
}
.logo{display:flex;align-items:center;gap:9px;font-size:16px;font-weight:600;white-space:nowrap;letter-spacing:-.01em}
/* 品牌标（⑦ 2026-09-27，用户给的蓝底白 J，client/img/logo-mark.png 96px 方图）。
   图自带蓝底与圆角、背景透明 —— 不垫底色、不加 border-radius、不描边，垫了只会多出一圈边。
   flex:none 是必须的：.logo 是 flex 容器，不锁窄屏会被商号文字挤成椭圆。
   原 .logo-ico（墨底「晶」字）已随 mall.html 改版删除。 */
.logo-img{width:30px;height:30px;display:block;flex:none}
/* 搜索框：不再用赭红描边。赭红只留给搜索按钮里的字？—— 不，按钮也退成墨色，
   因为一屏只允许一个赭红主按钮，那个名额留给「立即下单」。 */
.searchbar{
  flex:1;min-width:200px;display:flex;align-items:center;
  border:1px solid var(--rule-2);border-radius:var(--r-sm);overflow:hidden;background:var(--paper-2);
}
.searchbar:focus-within{border-color:var(--ink-3);background:var(--card)}
.searchbar input{flex:1;border:none;outline:none;padding:9px 14px;font-size:13px;min-width:0;background:transparent;color:var(--ink)}
.searchbar button{background:var(--ink);color:var(--paper);border:none;padding:9px 22px;font-size:13px;font-weight:500}
.searchbar button:hover{background:var(--ink-2)}
.header-links{display:flex;align-items:center;gap:16px;font-size:13px;color:var(--ink-2);white-space:nowrap}
.header-links a{cursor:pointer;text-decoration:none;color:var(--ink-2)}
.header-links a:hover{color:var(--ink)}
.header-links .me{color:var(--ink);font-weight:500}

/* ── 类目导航 —— 当前位置指示条是赭红三处之三 ──────────────────────────── */
nav.cats{background:var(--card);border-bottom:1px solid var(--rule)}
.cats-inner{
  max-width:1200px;margin:0 auto;padding:0 16px;display:flex;gap:2px;
  overflow-x:auto;scrollbar-width:none;
}
.cats-inner::-webkit-scrollbar{display:none}
.cat-item{
  padding:11px 14px;font-size:13.5px;color:var(--ink-2);cursor:pointer;
  border-bottom:2px solid transparent;white-space:nowrap;
}
.cat-item:hover{color:var(--ink)}
.cat-item.active{color:var(--ink);font-weight:600;border-bottom-color:var(--clay)}

/* ── 主体 ───────────────────────────────────────────────────────────────── */
main{max-width:1200px;margin:0 auto;padding:16px 16px 60px}
.banner{
  background:var(--paper-2);color:var(--ink-2);border-radius:var(--r-md);
  padding:11px 16px;font-size:13px;margin-bottom:16px;border:1px solid var(--rule);
}

/* ── 商品网格 ───────────────────────────────────────────────────────────── */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px}
.pcard{
  background:var(--card);border:1px solid var(--rule);border-radius:var(--r-md);
  overflow:hidden;cursor:pointer;transition:border-color .16s,transform .16s;
}
/* hover 不加阴影，只上浮 + 提线 */
.pcard:hover{border-color:var(--rule-2);transform:translateY(-2px)}
.pimg{
  width:100%;aspect-ratio:3/4;background:var(--paper-2);
  display:flex;align-items:center;justify-content:center;color:var(--ink-3);font-size:30px;overflow:hidden;
}
.pimg img{width:100%;height:100%;object-fit:cover;display:block}
.pbody{padding:9px 11px 11px;border-top:1px solid var(--rule)}
/* 行高固定 —— 整排卡片的价格行必须落在同一基线 */
.pname{
  font-size:12.5px;line-height:1.5;height:3em;overflow:hidden;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;color:var(--ink);
}
/* 价格 —— 赭红三处之一 */
.pprice{margin-top:7px;color:var(--clay);font-size:18px;font-weight:600;line-height:1.1}
.pprice small{font-size:10.5px;color:var(--ink-3);font-weight:400;margin-left:4px}
.pmeta{
  margin-top:6px;padding-top:6px;border-top:1px dashed var(--rule);
  font-size:10.5px;color:var(--ink-3);display:flex;justify-content:space-between;gap:6px;
}
.empty{text-align:center;color:var(--ink-3);padding:60px 0}
.loading{text-align:center;color:var(--ink-3);padding:50px 0}

/* ── 详情 ───────────────────────────────────────────────────────────────── */
.back{
  display:inline-flex;align-items:center;gap:5px;color:var(--ink-2);font-size:13px;
  cursor:pointer;margin-bottom:12px;background:none;border:none;
}
.back:hover{color:var(--ink)}
.detail{
  background:var(--card);border:1px solid var(--rule);border-radius:var(--r-md);
  padding:20px;display:flex;gap:24px;flex-wrap:wrap;
}
.d-imgs{width:330px;flex:none}
.d-main{
  width:100%;aspect-ratio:3/4;border-radius:var(--r-sm);background:var(--paper-2);
  display:flex;align-items:center;justify-content:center;color:var(--ink-3);font-size:44px;overflow:hidden;
}
.d-main img{width:100%;height:100%;object-fit:cover;display:block}
.d-thumbs{display:flex;gap:6px;margin-top:8px;flex-wrap:wrap}
.d-thumb{
  width:56px;height:56px;border-radius:var(--r-sm);background:var(--paper-2);
  border:2px solid transparent;overflow:hidden;cursor:pointer;
}
.d-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.d-thumb.active{border-color:var(--clay)}
.d-info{flex:1;min-width:300px}
.d-name{font-size:17px;font-weight:600;line-height:1.55;letter-spacing:-.01em;text-wrap:balance}
.d-code{font-size:12px;color:var(--ink-3);margin-top:5px;letter-spacing:.02em}

/* ── 价格阶梯 —— 批发站的主角 ───────────────────────────────────────────── */
/* 表达的是「进度」不是「三个选项」：当前档底条 + 下一档提示（.min-hint） */
.tiers{
  display:flex;gap:0;margin:16px 0 12px;flex-wrap:nowrap;overflow-x:auto;
  border:1px solid var(--rule);border-radius:var(--r-sm);
}
.tier{
  flex:1;min-width:96px;border:none;border-right:1px solid var(--rule);
  padding:10px 12px;text-align:left;background:var(--paper);position:relative;
  transition:background .18s;
}
.tier:last-child{border-right:none}
.tier.active{background:var(--card)}
/* 当前档指示条 —— 赭红三处之三 */
.tier.active::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;background:var(--clay)}
.tier .tp{font-size:22px;font-weight:600;line-height:1.1;color:var(--ink-3)}
.tier.active .tp{color:var(--clay)}
.tier .tq{font-size:11px;color:var(--ink-3);margin-top:3px}
.tier.active .tq{color:var(--ink-2)}

/* ── 单价块（⑩ 2026-09-27）—— 取代上面那条阶梯条 ──────────────────────
 * 用户 2026-09-27 定：价格按客户等级走，**每级一个价、不分件数**（起批量一款一个、不随等级）。
 * 详情页因此不再有「档」这个概念，`.tiers/.tier` 那一套随之退役 —— 但**先留着不删**：
 * 供应商城的 mall.js 换 DOM 上线之前，线上页面还在用它。等 ⑧+⑩ 上线确认后再单独删一批。
 * 没有档就没有「当前档」，所以不带 `.tier.active::after` 那条 3px 赭红底条；
 * 赭红只落在价格数字本身（三个名额里的「价格数字」那一个）。
 * 用户同时定「前台不显示等级」：这里不出现「一级价」之类字样，只给客户属于他的那一个价。 */
.price-block{
  display:flex;align-items:baseline;gap:7px;flex-wrap:wrap;
  margin:16px 0 12px;padding:12px 14px;
  background:var(--paper);border:1px solid var(--rule);border-radius:var(--r-sm);
}
.pb-amt{
  font-family:var(--mono);font-variant-numeric:tabular-nums;
  font-size:26px;font-weight:600;line-height:1.1;color:var(--clay);
}
.pb-unit{font-size:12px;color:var(--ink-3)}
/* 游客态：整块变成一个可点、可 Tab 的登录入口，行为与观感沿用原 .tier.active[data-login]。
   焦点环靠全局 :focus-visible（本块的 8px 圆角写在全局那条之后，所以聚焦时不会被压成 3px）。
   遮罩值不是价格数字 → 不给赭红，与 .ck-total .amt[data-masked]、.sz-p[data-masked] 同口径。 */
.price-block[data-login]{background:var(--paper-2);cursor:pointer;transition:background .18s}
.price-block[data-login]:hover{background:var(--card)}
.pb-amt[data-masked]{color:var(--ink-3);letter-spacing:.12em}
.pb-hint{font-size:12px;color:var(--ink-2)}
.price-block[data-login]:hover .pb-hint{color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.service{font-size:12px;color:var(--ink-2);margin-bottom:14px}
.d-desc{font-size:13px;color:var(--ink-2);margin-top:14px;white-space:pre-wrap}
.d-detail{
  background:var(--card);border:1px solid var(--rule);border-radius:var(--r-md);
  padding:20px;margin-top:16px;
}
.d-detail-t{
  font-size:14px;font-weight:600;margin-bottom:12px;padding-bottom:10px;
  border-bottom:1px solid var(--rule);
}
.d-detail img{display:block;width:100%;max-width:750px;margin:0 auto;border-radius:var(--r-sm)}

/* ── 码单式 SKU 矩阵 ────────────────────────────────────────────────────── */
/* 它取代的是仓库那张纸质码单，就按码单排。窄屏横向滚动，绝不折行。 */
.sku-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table.sku{width:100%;border-collapse:collapse;font-size:13px;min-width:460px}
table.sku th{
  font-family:var(--mono);font-weight:500;color:var(--ink-3);font-size:11.5px;
  padding:9px 6px;border-bottom:1px solid var(--rule-2);text-align:center;background:var(--paper-2);
}
table.sku th:first-child{text-align:left;padding-left:10px;min-width:100px;font-family:var(--sans)}
table.sku td{padding:7px 6px;border-bottom:1px solid var(--rule);text-align:center;vertical-align:middle}
table.sku td:first-child{text-align:left;padding-left:10px;font-size:12.5px}
/* 库存状态用格子底色表达，不写字。需 mall.js 给 td 加 .low / .out —— 见交接单 */
table.sku td.low{background:var(--made-bg)}
table.sku td.out{background:var(--gone-bg)}
.sku-stock{display:block;font-size:10px;color:var(--ink-3);margin-top:2px}
td.low .sku-stock{color:var(--made)}
.qty-input{
  width:54px;height:31px;border:1px solid var(--rule-2);border-radius:6px;
  text-align:center;font-size:13px;outline:none;background:var(--card);color:var(--ink);
}
.qty-input:focus{border-color:var(--clay)}
.qty-input:disabled{background:var(--paper-2);color:var(--ink-3);cursor:not-allowed}
.oos{font-size:11px;color:var(--gone)}
/* 色卡方块 —— 颜色列用，需 mall.js 输出 <i class="sku-sw" style="background:…"> */
.sku-sw{
  display:inline-block;width:13px;height:13px;border-radius:3px;
  border:1px solid rgba(0,0,0,.18);margin-right:7px;vertical-align:-2px;flex:none;
}

/* ── 结算栏 ─────────────────────────────────────────────────────────────── */
.checkout{
  position:sticky;bottom:0;background:var(--card);border-top:1px solid var(--rule);
  margin:16px -20px -20px;padding:13px 20px;
  border-radius:0 0 var(--r-md) var(--r-md);
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
}
.ck-sum{font-size:13px;color:var(--ink-2)}
.ck-sum b{color:var(--ink);font-weight:600}
.ck-total{margin-left:auto;font-size:13px;color:var(--ink-2)}
.ck-total .amt{font-size:22px;font-weight:600;color:var(--clay);margin-left:5px}
/* 主按钮 —— 一屏最多一个 */
.btn-order{
  background:var(--clay);color:var(--on-clay);border:none;border-radius:var(--r-sm);
  padding:11px 26px;font-size:14px;font-weight:500;
}
.btn-order:hover{background:var(--clay-deep)}
.btn-order:disabled{opacity:.45;cursor:not-allowed}
/* 下一档提示：「再拿 N 件降到 ¥X」/「还差 N 件起批」 */
.min-hint{width:100%;font-size:12px;color:var(--ink-2)}
/* ⑩ 2026-09-27：阶梯条退役后这行只剩「N 件起批，还差 M 件」一种文案，`b` 里包的是**件数不是价格**，
   按铁律 1 收回赭红改墨色。⚠ 与供应商城 mall.js 的 ⑧+⑩ 同批上线；万一拆批，
   旧文案「再拿 N 件降到 ¥X」里的价格会短暂失去赭红（只是弱一点，不影响可读）。 */
.min-hint b{font-family:var(--mono);color:var(--ink);font-weight:600}

/* ── 我的订单 ───────────────────────────────────────────────────────────── */
.ocard{
  background:var(--card);border-radius:var(--r-md);border:1px solid var(--rule);
  margin-bottom:12px;overflow:hidden;
}
.ocard-h{
  display:flex;align-items:center;gap:12px;padding:10px 14px;
  border-bottom:1px solid var(--rule);background:var(--paper-2);font-size:13px;flex-wrap:wrap;
}
.ocard-h .no{font-weight:600;color:var(--ink)}
.ocard-h .time{color:var(--ink-3);font-size:11.5px}
/* 货态徽章 —— 低饱和，永远不和价格抢 */
.tag{font-size:11.5px;line-height:1;padding:4px 9px;border-radius:5px;font-weight:500;white-space:nowrap}
.tag.s0{background:var(--made-bg);color:var(--made)}      /* 待确认 / 待配货 */
.tag.s1{background:var(--drop-bg);color:var(--drop)}      /* 待发货 */
.tag.s2{background:var(--stock-bg);color:var(--stock)}    /* 已发货 / 完成 */
.tag.s3{background:var(--gone-bg);color:var(--ink-2)}     /* 已完成归档 */
.tag.s9{background:var(--gone-bg);color:var(--gone)}      /* 已取消 */
.ocard-items{padding:6px 14px}
.oitem{display:flex;justify-content:space-between;gap:10px;padding:6px 0;font-size:13px}
.oitem .n{color:var(--ink-2)}
.ocard-f{
  display:flex;align-items:center;gap:12px;padding:10px 14px;
  border-top:1px solid var(--rule);font-size:13px;
}
.ocard-f .tt{margin-left:auto}
.ocard-f .tt b{color:var(--clay);font-size:17px;font-weight:600}
/* 次要操作：描边，不是赭红 */
.btn-ghost{
  background:var(--card);border:1px solid var(--rule-2);border-radius:var(--r-sm);
  padding:7px 14px;font-size:12.5px;color:var(--ink-2);
}
.btn-ghost:hover{border-color:var(--ink-3);color:var(--ink)}

/* ── 弹窗 / 提示 ────────────────────────────────────────────────────────── */
.modal-mask{
  position:fixed;inset:0;background:rgba(36,32,27,.5);z-index:100;
  display:flex;align-items:center;justify-content:center;padding:16px;
}
.modal{
  background:var(--card);border-radius:var(--r-lg);width:100%;max-width:440px;
  max-height:80vh;overflow:auto;padding:22px;border:1px solid var(--rule);
}
.modal h3{font-size:16px;font-weight:600;margin-bottom:14px}
.modal .m-items{font-size:13px;color:var(--ink-2);max-height:220px;overflow:auto;margin-bottom:10px}
.modal .m-row{display:flex;justify-content:space-between;gap:10px;padding:5px 0}
.modal textarea{
  width:100%;border:1px solid var(--rule-2);border-radius:var(--r-sm);padding:9px 11px;
  font-size:13px;resize:vertical;min-height:58px;outline:none;background:var(--paper-2);color:var(--ink);
}
.modal textarea:focus{border-color:var(--clay);background:var(--card)}
.modal .m-total{text-align:right;font-size:14px;margin:12px 0}
.modal .m-total b{color:var(--clay);font-size:19px;font-weight:600}
.modal .m-btns{display:flex;gap:10px}
.modal .m-btns button{flex:1;height:42px;border-radius:var(--r-sm);font-size:14px}
.m-cancel{background:var(--paper-2);border:1px solid var(--rule);color:var(--ink-2)}
.m-cancel:hover{border-color:var(--rule-2);color:var(--ink)}
#toast{
  position:fixed;top:72px;left:50%;transform:translateX(-50%);z-index:200;
  background:var(--ink);color:var(--paper);padding:11px 20px;border-radius:var(--r-sm);
  font-size:13px;display:none;max-width:86vw;
}

/* ── 在线定制设计器 ─────────────────────────────────────────────────────── */
.dz{background:var(--card);border:1px solid var(--rule);border-radius:var(--r-md);padding:18px}
.dz-main{display:flex;gap:20px;flex-wrap:wrap}
.dz-left{width:300px;flex:none}
/* 正反面切换：分段控件，选中态用墨块不用赭红（它不是「当前位置」是「视角切换」） */
.seg{
  display:flex;width:168px;margin:0 auto 10px;border:1px solid var(--rule-2);
  border-radius:var(--r-sm);overflow:hidden;font-size:13px;
}
.seg button{flex:1;border:none;background:var(--card);color:var(--ink-2);padding:7px 0;cursor:pointer}
.seg button.on{background:var(--ink);color:var(--paper)}
.stage{
  position:relative;width:300px;height:360px;background:var(--paper-2);
  border-radius:var(--r-md);overflow:hidden;touch-action:none;
}
.stage-base{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none}
.stage-zone{
  position:absolute;border:1.5px dashed var(--rule-2);border-radius:4px;
  pointer-events:none;transition:all .16s;
}
.stage-ov{position:absolute;cursor:grab;user-select:none;touch-action:none;display:none}
.stage-ov img{width:100%;display:block;pointer-events:none;border:1px solid var(--clay)}
.stage-ph{position:absolute;left:0;right:0;top:46%;text-align:center;font-size:12px;color:var(--ink-3)}
.dz-right{flex:1;min-width:260px}
.dz-name{font-size:15px;font-weight:600;line-height:1.5}
.dz-code{font-size:12px;color:var(--ink-3);margin:4px 0 14px}
.dz-lb{font-size:12px;color:var(--ink-3);margin:14px 0 7px;font-weight:500}
.dz-chips{display:flex;gap:7px;flex-wrap:wrap}
.dz-chip{
  border:1px solid var(--rule-2);border-radius:var(--r-sm);padding:5px 12px;font-size:12px;
  color:var(--ink-2);cursor:pointer;background:var(--card);display:flex;align-items:center;gap:6px;
}
.dz-chip:hover{border-color:var(--ink-3)}
.dz-chip.on{border-color:var(--ink);background:var(--ink);color:var(--paper)}
.dz-sw{width:13px;height:13px;border-radius:3px;border:1px solid rgba(0,0,0,.18);flex:none}
.dz-up{
  display:flex;align-items:center;justify-content:center;gap:7px;
  border:1px dashed var(--rule-2);color:var(--ink-2);border-radius:var(--r-sm);
  padding:11px;font-size:12.5px;cursor:pointer;background:var(--paper-2);
}
.dz-up:hover{border-color:var(--ink-3);color:var(--ink)}
.dz-ctl .r{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--ink-2);margin:9px 0}
.dz-ctl .r label{width:34px;flex:none}
.dz-ctl input[type=range]{flex:1;accent-color:var(--ink)}
.dz-ctl .r b{width:46px;text-align:right;color:var(--ink);font-family:var(--mono);font-variant-numeric:tabular-nums}
.sizemtx{width:100%;border-collapse:collapse;font-size:12px}
.sizemtx th{
  font-family:var(--mono);font-weight:500;color:var(--ink-3);font-size:11px;
  padding:6px 3px;text-align:center;border-bottom:1px solid var(--rule-2);background:var(--paper-2);
}
.sizemtx td{padding:6px 3px;text-align:center}
.sizemtx input{
  width:48px;height:29px;border:1px solid var(--rule-2);border-radius:6px;text-align:center;
  font-family:var(--mono);font-size:12px;font-variant-numeric:tabular-nums;outline:none;
  background:var(--card);color:var(--ink);
}
.sizemtx input:focus{border-color:var(--clay)}
.dz-dots{font-size:12px;color:var(--ink-2);margin-top:8px}
.dz-dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--rule-2);margin:0 4px 0 10px}
.dz-dot.f{background:var(--stock)}
.dz-foot{
  margin-top:16px;border-top:1px solid var(--rule);padding-top:14px;
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
}
.dz-total{margin-left:auto;font-size:13px;color:var(--ink-2)}
.dz-total b{font-size:20px;color:var(--clay);font-weight:600;margin-left:5px}

/* ── 配货代发 ───────────────────────────────────────────────────────────── */
.al{background:var(--card);border:1px solid var(--rule);border-radius:var(--r-md);padding:16px}
.al h3{font-size:15px;font-weight:600;margin-bottom:4px}
.al .sub{font-size:12px;color:var(--ink-3);margin-bottom:14px}
.altb{width:100%;border-collapse:collapse;font-size:13px}
.altb th{
  font-weight:500;color:var(--ink-3);font-size:11.5px;text-align:left;
  padding:8px;border-bottom:1px solid var(--rule-2);background:var(--paper-2);
}
.altb td{padding:8px;border-bottom:1px solid var(--rule)}
.al-form{background:var(--paper-2);border-radius:var(--r-sm);padding:13px;margin:14px 0}
.al-form .row{display:flex;gap:9px;flex-wrap:wrap;align-items:center;margin-bottom:9px;font-size:12px}
.al-form select,.al-form input[type=text]{
  height:33px;border:1px solid var(--rule-2);border-radius:6px;padding:0 10px;
  font-size:12px;outline:none;background:var(--card);color:var(--ink);
}
.al-form select:focus,.al-form input:focus{border-color:var(--clay)}
.al-lbl{
  display:inline-flex;align-items:center;gap:6px;border:1px dashed var(--rule-2);
  color:var(--ink-2);border-radius:6px;padding:7px 11px;font-size:12px;cursor:pointer;
}
.al-lbl:hover{border-color:var(--ink-3);color:var(--ink)}
.al-lbl.done{border-style:solid;border-color:var(--stock);color:var(--stock);background:var(--stock-bg)}
.al-qin{
  width:46px;height:29px;border:1px solid var(--rule-2);border-radius:6px;text-align:center;
  font-size:12px;outline:none;background:var(--card);color:var(--ink);
}
.al-qin:focus{border-color:var(--clay)}
.al-hint{font-size:11px;color:var(--made)}
.sub-card{border:1px solid var(--rule);border-radius:var(--r-sm);padding:10px 12px;margin-bottom:8px;font-size:12px}
.sub-card .h{display:flex;gap:8px;align-items:center;margin-bottom:5px}
.plat-tag{font-size:11px;padding:3px 8px;border-radius:5px;background:var(--drop-bg);color:var(--drop)}
.btn-add{
  background:var(--ink);color:var(--paper);border:none;border-radius:6px;
  padding:8px 16px;font-size:12px;cursor:pointer;
}
.btn-add:hover{background:var(--ink-2)}
.btn-add:disabled{opacity:.45;cursor:not-allowed}
.link-del{color:var(--alert);font-size:12px;cursor:pointer;margin-left:auto}
.link-view{color:var(--ink-2);font-size:12px;cursor:pointer;text-decoration:underline}
.link-view:hover{color:var(--ink)}

/* ============================================================================
 * 接线补充规则（2026-09-11，配合供应商城板块删除 mall.js 行内 style）
 * 每条对应一处曾经的行内样式；删行内值前这些必须先在这里存在。
 * 位置必须在上面各分区之后、@media 之前 —— .sub-head / .sub-empty 与 `.al .sub`
 * 同特异度（0,2,0），靠源码顺序取胜。
 * ========================================================================== */

/* 确认弹窗：单价行（说明性文字，不是价格，不吃赭红） */
.modal .m-row.m-row-unit{font-size:13px;color:var(--ink-2)}
.modal .m-btns{margin-top:12px}

/* 定制设计器：备注框 + 件数 */
textarea.dz-remark{
  width:100%;margin-top:10px;padding:8px;font-size:12px;outline:none;
  border:1px solid var(--rule-2);border-radius:var(--r-sm);
  background:var(--card);color:var(--ink);resize:vertical;
}
textarea.dz-remark:focus{border-color:var(--clay)}
/* 件数是数量不是金额 —— 不该继承 .dz-total b 的赭红 20px */
.dz-total b.dz-qty{font-size:14px;color:var(--ink);font-weight:500}

/* 订单项：定制效果图缩略 */
.oitem.oitem-top{align-items:flex-start}
.oitem .eff-row{display:inline-flex;margin-top:5px}
.oitem img.eff-thumb{
  width:48px;height:58px;object-fit:cover;border-radius:6px;
  border:1px solid var(--rule);margin-right:6px;
}

/* 配货代发：剩余件数（原为赭红，按「赭红只三处」改墨色） */
.altb b.al-rem{color:var(--ink)}
.altb b.al-rem.done{color:var(--ink-3)}
.al-form .al-title{font-weight:500;margin-bottom:8px}
.altb.altb-sub{margin:6px 0}
/* 提示条两态：警示走 made（未开通平台），完成走 stock（已配货完毕） */
.al-form.al-form-msg{text-align:center}
.al-form.al-form-msg.is-warn{color:var(--made)}
.al-form.al-form-msg.is-done{color:var(--stock)}

/* 子单卡内文案层级：note 统一收到 ink-3（三级说明），items 用 ink-2 */
.sub-note{font-size:11px;color:var(--ink-3)}
.sub-items{color:var(--ink-2)}
.al .sub.sub-empty{text-align:center;padding:16px 0}
.al .sub.sub-head{margin:12px 0 6px}

/* ============================================================================
 * 游客预览（2026-09-22，配合供应商城板块「游客可逛、下单才弹登录」）
 * 三处选择器都用【特异度】压过基础规则，而不是靠源码顺序 —— 这段挪到哪都成立。
 * ========================================================================== */

/* ① 登录弹窗「先逛逛」：第三级纯文字按钮。它是退出口，不能和「登录」抢；
   原先吃 .m-cancel 默认样式 → 42×20px、离主按钮 1px，触控目标不达标。 */
.login-card button.login-cancel{
  display:block;width:100%;height:44px;margin-top:8px;
  background:transparent;border:none;border-radius:var(--r-sm);
  color:var(--ink-2);font-size:14px;
}
.login-card button.login-cancel:hover{color:var(--ink);background:transparent;border:none}

/* ② 卡片关价链接「登录查看批发价」：墨色下划线，不用赭红。
   理由：一屏 6 张卡 = 6 个链接，用赭红就是 6 个强调色，违反「一屏最多一个主按钮」。
   字重 500 而非继承 .pprice 的 600 —— 600 是价格数字的字重，链接不冒充价格。
   行高由 .pprice 的 18px×1.1 支撑，整排卡片价格行/规格行基线不变。 */
.pprice a.link-view{
  font-family:var(--sans);font-size:12.5px;font-weight:500;color:var(--ink);
  text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;
}
.pprice a.link-view:hover{color:var(--ink);text-decoration-thickness:2px}

/* ③ 详情关价档位：锁定格。去掉赭红 —— 遮罩价「¥ ···」不是价格数字，
   锁定格也不是「当前位置」，两处原先都越界。改为凹进纸 + 可点提示。
   ⚠ 键盘可达需 markup 配合：该 div 要加 tabindex="0" role="button" 并响应 Enter/Space。 */
.tier.active[data-login]{background:var(--paper-2);cursor:pointer}
.tier.active[data-login]::after{display:none}
.tier.active[data-login] .tp{color:var(--ink-3);letter-spacing:.12em}
.tier.active[data-login] .tq{color:var(--ink-2)}
.tier.active[data-login]:hover{background:var(--card)}
.tier.active[data-login]:hover .tq{color:var(--ink);text-decoration:underline;text-underline-offset:3px}

/* ④ 遮罩合计「¥ ···」（详情结算栏 #ckAmt、定制器 #dzAmt）：同③，遮罩值不是价格数字，不用赭红。
   这两处 mall.js 只改 textContent，CSS 无法按内容选中 → 约定 markup 钩子 data-masked：
   写入 '¥ ···' 时 el.dataset.masked=''，写回真金额时 delete el.dataset.masked。
   钩子未加之前本条完全不生效、零副作用。字号不变，避免遮罩↔真值切换时布局跳动。 */
.ck-total .amt[data-masked],
.dz-total b[data-masked]{color:var(--ink-3);letter-spacing:.12em}

/* ============================================================================
 * 批次④（2026-09-22）：码单颜色选项图 + 游客态顶栏「登录」主按钮
 * 同样全部靠特异度取胜，不依赖源码顺序。
 * ========================================================================== */

/* ⑤ 顶栏「登录」主按钮：仅游客态列表页（mall.js 在其它视图自动摘掉 class）。
   列表页没有别的赭红按钮，符合「一屏最多一个主按钮」；详情页已有「登录后下单」，那里不加。 */
.header-links a.nav-login-primary{
  display:inline-flex;align-items:center;height:34px;padding:0 16px;
  background:var(--clay);color:var(--on-clay);border-radius:var(--r-sm);font-weight:500;
}
.header-links a.nav-login-primary:hover{background:var(--clay-deep);color:var(--on-clay)}

/* ⑥ 码单颜色列：去掉浏览器原生按钮外观（原为灰底 + 2px 凸起边框 + 黑字）。
   选择器用 .sku-color 而不是 button.sku-color —— 无图颜色若改成不可点的 <span>，样式照样成立。 */
table.sku .sku-color{
  display:inline-flex;align-items:center;gap:8px;
  margin-left:-4px;padding:4px 8px 4px 4px;          /* 负边距抵掉内边距，色卡仍与表头「颜色」左对齐 */
  background:transparent;border:none;border-radius:var(--r-sm);
  font:inherit;color:var(--ink);text-align:left;cursor:pointer;
}
table.sku .sku-color:hover{background:var(--paper-2)}
/* 无图颜色：点了不切图，不给「可点」暗示 */
table.sku .sku-color[data-noimg]{cursor:default}
table.sku .sku-color[data-noimg]:hover{background:transparent}

/* 色卡图与回落方块同为 24×24：原来方块 13px、图 24px，有图行与无图行高差 2px（66 vs 64）。
   13px 的图案（碎花、条纹）认不出来，所以是方块放大，而不是图缩小。 */
table.sku .sku-color .sku-sw-img{
  display:block;flex:none;width:24px;height:24px;object-fit:cover;
  border:1px solid var(--rule);border-radius:4px;background:var(--paper-2);
}
table.sku .sku-color .sku-sw{flex:none;width:24px;height:24px;margin:0;border-radius:4px;vertical-align:middle}

/* 当前选中的颜色：赭红第三类「当前选中态」。只描色卡，不加粗名字 ——
   加粗会让首列变宽，选一次颜色整张码单横向跳一下。 */
table.sku .sku-color[aria-pressed="true"] .sku-sw-img,
table.sku .sku-color[aria-pressed="true"] .sku-sw{outline:2px solid var(--clay);outline-offset:1px}

@media (max-width:640px){
  .header-links a.nav-login-primary{height:40px}      /* 触控 */
}

/* ── 动效降级 ───────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important}
  .pcard:hover{transform:none}
}

/* ── 响应式 ─────────────────────────────────────────────────────────────── */
@media (max-width:900px){
  .d-imgs{width:100%}
  .grid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}
  .dz-left,.stage{width:100%}
}
@media (max-width:640px){
  .header-inner{gap:10px;padding:10px 14px}
  main{padding:12px 14px 72px}
  .grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  .detail{padding:16px}
  .checkout{margin:14px -16px -16px;padding:12px 16px}
  /* 触控目标 ≥44 */
  .btn-order,.btn-brand{min-height:44px}
  .qty-input,.al-qin,.sizemtx input{height:38px}
  .tier{min-width:88px}
  .cat-item{padding:13px 14px}
}

/* ============================================================================
 * 字体子集生成（拉丁+数字，每字重约 10–15KB）
 *   pip install fonttools brotli
 *   下载 IBM Plex（SIL OFL 1.1）：https://github.com/IBM/plex/releases
 *   pyftsubset IBMPlexSans-Regular.ttf \
 *     --unicodes="U+0020-007F,U+00A5,U+2013-2014,U+2018-201D,U+2026" \
 *     --flavor=woff2 --output-file=client/fonts/IBMPlexSans-Regular.woff2
 *   其余四个字重同法（Sans Medium/SemiBold、Mono Regular/SemiBold）。
 *
 * 字体文件未到位时本表仍可用：回落到系统等宽字（SFMono-Regular / Menlo /
 * Consolas），这些字体同样有表格数字，价格小数点照样对齐，只是字形不同。
 * ========================================================================== */

/* ============================================================================
 * 批次⑧（2026-09-27）：阿里巴巴式选项 —— 颜色芯片 + 尺码行（取代码单矩阵表）
 * ----------------------------------------------------------------------------
 * 用户 2026-09-27：「选项改成跟阿里巴巴的选项一样的风格」。
 * 取 1688 的**信息结构**（颜色一排可换行的芯片、尺码一行一条带步进器），不取它的配色：
 * 1688 通篇橙，本站只有三个赭红名额（价格数字 / 主按钮 / 当前选中态，见文件头铁律 1）。
 * 这里只花掉「当前选中」那一个（选中的颜色芯片），价格与按钮的名额留给阶梯条与「立即下单」。
 * 尺码行的 .sz-p 走墨色而不是赭红：本站单价来自阶梯价（按总件数走档），每一行是**同一个数**，
 * 一列重复的赭红只是噪音不是信息。要 1688 那种橙价，把 .sz-p 的 color 换成 var(--clay) 即可，
 * 一行改动，其余不动。
 * 手机端收益：矩阵表那条横向滚动没有了。
 *
 * DOM 由 mall.js 出（契约见 docs/UI交接-商城选项阿里style-20260927.md）。
 * 本段全部靠特异度取胜，不依赖源码顺序；.tiers 阶梯条与 .checkout 结算栏结构不变。
 * ========================================================================== */

.opt{margin:16px 0}
.opt-h{font-size:12px;color:var(--ink-3);display:flex;align-items:baseline;gap:8px;margin-bottom:9px}
.opt-cur{font-size:13px;font-weight:500;color:var(--ink)}

/* ── 颜色：一排可换行的芯片，左 40×40 选项图 + 右颜色名 ─────────────────── */
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{
  display:inline-flex;align-items:center;gap:9px;text-align:left;cursor:pointer;
  padding:5px 12px 5px 5px;min-height:44px;          /* 44 = 触控下限，桌面同高不另写一套 */
  background:var(--card);border:1px solid var(--rule-2);border-radius:var(--r-sm);
  font:inherit;font-size:13px;color:var(--ink);
}
.chip:hover{border-color:var(--ink-3)}
/* 选中态 —— 赭红第三类。用 border + inset 阴影凑够 2px，**不用 outline**：
   outline 要留给 :focus-visible，两者抢同一个属性时，键盘用户看不出焦点落在哪一片。 */
.chip[aria-checked="true"]{border-color:var(--clay);box-shadow:inset 0 0 0 1px var(--clay)}
.chip[aria-checked="true"] .chip-n{font-weight:500}
/* 缺货色：灰掉但仍读得清（禁用态 1.4.3 豁免，这里仍给 --ink-3 而不是更淡） */
.chip:disabled,.chip[aria-disabled="true"]{
  background:var(--paper-2);border-color:var(--rule);color:var(--ink-3);cursor:not-allowed;
}
.chip:disabled:hover,.chip[aria-disabled="true"]:hover{border-color:var(--rule)}
/* 整色缺货**但仍可选中**（供应商城 2026-09-27 定：选中后整列显示「缺货」，让客人看得到有哪些码）。
   于是「灰态」和「选中态」会同时挂在同一片上，而上面那条 [aria-disabled] 的 border-color
   会把选中的赭红边吃掉、只剩 1px inset 的半圈——实测 border 变成 --rule 灰、shadow 还是赭红，
   选中态明显变弱，偏偏这正是最需要看清的一种（客人选中了一个卖完的颜色）。
   这里把赭红边补回来：(0,3,0) 压过那条 (0,2,0)，并写在 :hover 那条之后压住同分的它。
   底色仍然保持灰：它确实缺货，这一点不因为被选中而消失。 */
.chip[aria-disabled="true"][aria-checked="true"],
.chip[aria-disabled="true"][aria-checked="true"]:hover{border-color:var(--clay)}
/* 光标不能撒谎：真 disabled 的点不动，aria-disabled 的仍可点。两条同为 (0,2,0)，靠源序分先后。 */
.chip[aria-disabled="true"]{cursor:pointer}
.chip:disabled{cursor:not-allowed}
.chip:disabled .chip-img,.chip[aria-disabled="true"] .chip-img{opacity:.55}
/* 有图与无图同位同尺寸：无图给纯色块（动态色仍走行内 style，与 .sku-sw / .dz-sw 同例） */
.chip-img,.chip-sw{
  display:block;flex:none;width:40px;height:40px;border-radius:6px;
  border:1px solid var(--rule);background:var(--paper-2);
}
.chip-img{object-fit:cover}
.chip-n{white-space:nowrap}
/* 该色已填件数角标。
   ⚠ 别给它写裸 display：markup 用 hidden 属性控制显隐，写了就把浏览器的 [hidden]{display:none}
   覆盖掉，0 件时角标会一直挂着。要写就写在 :not([hidden]) 上，像下面这样。 */
.chip-q:not([hidden]){
  display:inline-block;min-width:18px;padding:0 5px;border-radius:9px;
  background:var(--ink);color:var(--paper);
  font-family:var(--mono);font-variant-numeric:tabular-nums;
  font-size:11px;font-weight:600;line-height:18px;text-align:center;
}

/* ── 尺码：一行一个码，码名 | 单价 | 库存 | 步进器 ───────────────────────
   码名与单价给最小宽度，库存因此每行都从同一个 x 开始，一列看下来数字是对齐的（铁律 2）。
   用 flex-wrap 而不是四列网格：窄到挤不下时，步进器**整件**掉到第二行并仍然贴右，
   不用猜断点，也不会出现「库存 / 1000」这种数字被折断的行（数字宁可换行整件、绝不断开或省略）。 */
.szl{border-top:1px solid var(--rule)}
.szr{
  display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;
  min-height:48px;padding:6px 10px;border-bottom:1px solid var(--rule);
}
.sz-n{flex:none;min-width:36px;font-size:13px;font-weight:500;color:var(--ink)}
/* ⚠ `.sz-p`（尺码行单价）在 2026-09-27 定稿的 DOM 里**已经不出现了** —— 每款每级只有一个价，
   一整列重复的同一个数是噪音，供应商城采纳后从 mall.js 去掉了（交接单 §3.3）。
   规则先留着不删，和 `.tiers` / `table.sku` 一起进上线后的那批清理；
   万一以后真按码定价，DOM 把它加回来样式就还在。 */
.sz-p,.sz-s{font-family:var(--mono);font-variant-numeric:tabular-nums;white-space:nowrap}
.sz-p{flex:none;min-width:56px;font-size:13px;color:var(--ink)}
.sz-s{flex:none;font-size:11.5px;color:var(--ink-3)}
/* 少量 / 缺货：沿用码单那套语义底色，不新造颜色 */
.szr.low{background:var(--made-bg)}
.szr.low .sz-s{color:var(--made)}
.szr.out{background:var(--gone-bg)}
.szr.out .sz-n,.szr.out .sz-p,.szr.out .sz-s{color:var(--gone)}
.szr .stp,.szr .oos{margin-left:auto}   /* 贴右；折行后在自己那一行里仍然贴右。缺货行第四件是 <span class="oos">缺货</span>，不是步进器 */
/* 游客关价：与 .ck-total .amt[data-masked] 同口径 —— 遮罩值不是价格数字，不给赭红；
   字号不变，避免登录前后整列行高跳动。 */
.sz-p[data-masked]{color:var(--ink-3);letter-spacing:.12em}

/* ── 步进器：− / 输入 / + 三件一体 ─────────────────────────────────────
   **不写 overflow:hidden** —— 它会把 :focus-visible 那圈 offset 2px 的外框剪掉，
   键盘用户就看不见焦点在哪；圆角改由首尾两个按钮各自承担。 */
.stp{display:inline-flex;align-items:center;background:var(--card);border:1px solid var(--rule-2);border-radius:6px}
.stp button{
  flex:none;width:32px;height:32px;border:none;background:transparent;
  color:var(--ink-2);font-size:16px;line-height:1;cursor:pointer;
}
.stp .stp-m{border-radius:5px 0 0 5px}
.stp .stp-p{border-radius:0 5px 5px 0}
.stp button:hover:not(:disabled){background:var(--paper-2);color:var(--ink)}
.stp button:disabled{color:var(--ink-3);cursor:not-allowed}
.stp .qty-input{
  width:46px;height:32px;border:none;border-radius:0;background:transparent;
  border-left:1px solid var(--rule-2);border-right:1px solid var(--rule-2);
  font-family:var(--mono);font-variant-numeric:tabular-nums;
}
.stp .qty-input:disabled{background:var(--paper-2)}
.stp .qty-input:focus{border-color:var(--rule-2)}   /* 压掉 .qty-input:focus 的赭红换边框：组内焦点改由下面那圈环表达 */
.stp :focus-visible{outline-offset:-2px}            /* 环收进组内，不压到相邻按钮 */
/* ⚠ 这一条不能省：.qty-input 自己带 outline:none（第 362 行附近），特异度与全局 :focus-visible 相同
   且写在它后面 —— 键盘焦点落进数字框时会**一点提示都没有**（原样式靠 :focus 换边框色补偿，
   而组内边框被我去掉了）。2026-09-27 用真实 Tab 测出来的，别按"看起来多余"删掉。
   (0,2,1) 压过 .qty-input (0,1,0)。 */
.stp .qty-input:focus-visible{outline:2px solid var(--clay);outline-offset:-2px}
/* 数字框的上下小箭头去掉：一格一格点比拖箭头准，箭头还要吃掉本来就窄的输入区 */
.stp .qty-input::-webkit-outer-spin-button,
.stp .qty-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.stp .qty-input[type=number]{-moz-appearance:textfield;appearance:textfield}

@media (max-width:640px){
  .chip{padding:5px 10px 5px 5px;gap:8px}
  .szr{gap:6px 8px;padding:8px 4px}
  /* 触控：38 高。这里必须显式写 —— 上面那个 640 媒体块里的 .qty-input{height:38px}
     特异度只有 (0,1,0)，压不过 .stp .qty-input (0,2,0)。 */
  .stp button{width:38px;height:38px}
  .stp .qty-input{width:44px;height:38px}
}
