
.cs-vb__btns{display:none}
/* JS 就绪：出按钮、藏下拉（下拉仍在 DOM 里，WC 的 JS 照常读它） */
/* 🔴 2026-09-20 改「定宽按钮」。原因（实测）：原来是 flex + 内容宽度，
   按钮宽度随文字长短浮动 —— 同一页里 `Pre-Order` 114px、证书号 121px，
   第二个按钮的 x 位置于是取决于第一个按钮多宽 ⇒ 这就是买家看到的「位置随文字浮动」。
   改为 flex:0 0 auto + width:158px 后，每个按钮**定宽**，
   ⇒ 第 N 个按钮的坐标只由 (N-1) × (158 + 10) 决定，与任何文字长度无关。
   ⚠️ 试过 `display:grid` + `repeat(auto-fill,minmax(158px,1fr))`：**不可用** ——
   本控件落在 <td> 里，表格单元格是 shrink-to-fit 宽度，`1fr` 解析不出来会塌成 1 列，
   实测两个按钮被竖排换行（容器 w=158 h=102）。故仍用 flex，只把尺寸钉死。 */
.cs-vb.is-ready .cs-vb__btns{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:0 0 16px;min-height:46px}
.cs-vb.is-ready .cs-vb__select{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* ⚠️ 尺寸必须写死并显式 border-box：站内 CSS 里 `*{box-sizing}` 没统一，
   实测 content-box + min-height:46px ⇒ 实际外框 46+24(padding)+3(border)=73px，
   `<span>` 芯片因此比 `<button>` 高一截。写死 height:46px + border-box 后两者一致。
   宽度交给网格（width:100% 吃满列宽 + min-width:0 允许被列宽约束）。 */
.cs-vb__btn{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;appearance:none;-webkit-appearance:none;font-family:inherit;font-size:.9375rem;font-weight:600;line-height:1.2;flex:0 0 auto;width:158px;height:46px;min-height:46px;padding:0 16px;border:1.5px solid #d6d6db;border-radius:8px;background:#fff;color:#1b1b1f;cursor:pointer;text-decoration:none;text-align:center;transition:border-color .15s ease,background-color .15s ease,color .15s ease,box-shadow .15s ease}
/* 文字兜底：值再长也撑不破固定列宽（当前最长是 12 位证书号 ≈ 100px，用不到；防将来）
   `inline-flex` 容器上 text-overflow 不生效，所以真正截断的是这层块级 span。 */
.cs-vb__btn > .cs-vb__btn-t{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cs-vb__btn:hover{border-color:#8B1A1A;color:#8B1A1A}
.cs-vb__btn:focus-visible{outline:2px solid #8B1A1A;outline-offset:2px}
.cs-vb__btn.is-active{background:#8B1A1A;border-color:#8B1A1A;color:#fff;box-shadow:0 2px 8px rgba(139,26,26,.18)}
.cs-vb__btn.is-active:hover{color:#fff}
.cs-vb__btn--single{cursor:default}
.cs-vb__btn--single:hover{border-color:#8B1A1A;color:#fff}
/* 「Clear」是原生下拉的逃生口：一旦变成按钮，取值恒为其中一个按钮，
   清空只会把买家带进「Please choose an option」的死角 ⇒ 按钮就绪后隐藏它。
   ⚠️ 必须 !important：主题的 .woocommerce div.product form.cart .reset_variations
   选择器比本规则更具体，不加会被它按 display:inline 覆盖回来（实测踩过）。 */
.cs-vb.is-ready ~ .reset_variations{display:none!important}
/* 承接 <th class="label">Option</th>：`Option` 对买家没有信息量，且按钮自带语义。
   🔴 只对 `option` 用（由 data-cs-vb-hide 决定）—— Size / Shape 的表头必须留着，
      一个商品挂两行属性时，没有标题买家分不清哪组按钮是做什么的（2026-09-23）。 */
.cs-vb-rowhide > th.label{display:none}
/* ── 商品标题锁三行高度 ──────────────────────────────────────────────────
   实测（2026-09-20 新标题格式上线后）：
        `Pikachu — SV-P Promo World Championships (002/SV-P) · PSA 10 · 2025` = 3 行 / 105px
        `Umbreon — Gem Pack Vol.2 (CBB2C) · PSA 10 · 2025`                   = 1 行 / 35px
   ⇒ 下方变体按钮与加购按钮整块**上下位移 70px**。这是买家能直接看见的
     「标题一长、按钮就往下跑」。锁到 3 行后两种标题的下方位置一致。
   ⚠️ 不是锁 2 行：新格式本身就会占满 3 行（关键词段比旧格式长），锁 2 行等于没锁。
   `3lh` = 三倍当前行高（跟随主题字号，别写死 px）；不认 lh 单位的浏览器退回 105px。 */
body.single-product h1.wp-block-post-title{min-height:105px;min-height:3lh}
/* ── 列表页商品卡：同样锁三行 ────────────────────────────────────────────
   实测（/shop/ 第一排三张，2026-09-20）：
        Cleffa   标题 2 行 → 价格 y=776  Select-options y=811
        Pikachu  标题 3 行 → 价格 y=800  Select-options y=836
        Mew ex   标题 1 行 → 价格 y=751  Select-options y=786
   ⇒ 「Select-options」按钮上下浮动 **50px**，同一排卡片的价格/按钮参差不齐。
   锁三行后价格与按钮落在同一条水平线上。
   注意：卡片标题的字号比详情页 h1 小（medium font size），所以这里 3lh ≈ 75px，
   与详情页的 105px 不是一个值 —— 各自跟随自己的行高，都用 lh 单位即可。 */
li.product .wp-block-post-title,li.wc-block-product .wp-block-post-title{min-height:75px;min-height:3lh}
/* ── 列表页商品卡：价格与按钮**钉在卡片底边**（比锁标题行数更稳） ──────────
   🔴 2026-09-20 二稿。起因：对外标题改成 eBay 式后长度**暴涨且不可控**
      （`2025 Pokemon Simplified Chinese … #002/SV-P Pikachu PSA 10`，最长 91 字符），
      锁三行不够用了 —— 实测 86 字符的 `… Blade Awakening SAR Ciphermaniac's Codebreaking …`
      在 3 列布局下换到 **4 行**（标题框 h=99 而非 74）⇒ 同排按钮又被顶开 25px。
   ⇒ 改机制：标题是**外部数据**（PSA 系列名 + 卡号 + 角色名），长度永远不可控，
      所以不能靠"锁行数"这种对内容的假设。改为
        ① 卡片纵向 flex + `align-self:stretch`（同排卡片自动等高）；
        ② 价格块 `margin-top:auto` 吃满中间余量 ⇒ **价格与按钮永远贴底**，
           按钮紧跟价格，因而也永远在同一水平线。
      标题再长、再短都不影响下方控件的位置。

   ⚠️🔴 **别写 `height:100%`**（第一版就是这么写的，在商品页的 Related products 上失效）：
      那个区块的容器是 **`ul.is-flex-container`（display:flex）**，不是 grid。
      给 flex 子项指定非 `auto` 的 `height` 会**直接关掉 `align-self:stretch`**
      ⇒ `height:100%` 在容器高度 auto 时解析成 auto ⇒ 卡片回到内容高度、`margin-top:auto` 没有余量可吃。
      实测：Related products 五张卡按钮 y = 3607 / 3627 / 3647（差 40px）。
      `align-self:stretch` 对 grid（本就是默认）与 flex 行**都成立**，所以只用它。
   `ul[class*=…]` 是因为不同模板给的类名不同（`wc-block-product-template__responsive` /
   `wc-block-product-template`），父容器 display 也不一样（grid / flex）。 */
ul[class*="wc-block-product-template"] > li.wc-block-product,
ul.products > li.product{display:flex;flex-direction:column;align-self:stretch}
ul[class*="wc-block-product-template"] > li.wc-block-product > .wp-block-woocommerce-product-price,
ul.products > li.product > .price{margin-top:auto}
/* ── 小屏（≤480px）：选项按钮**每行两个**（🔴 长期规则，2026-09-24 第三十三轮）──────
   用户口径：「卡膜和卡夹均有两个选项（如 shape 有两个选项），当前手机端为一列纵向排布，
   过于空旷，请改为每行两列显示（即一行内并排两列）……此排版规则需长期执行。」

   🔴 为什么原来必塌成一列（2026-09-24 真机实测，不是推算）：
     视口 390px ⇒ `form.cart` 315px，但 `td.value` 只有 **230–240px**
     （`th.label` 那列吃掉约 75–80px），`.cs-vb__btns` 实测 **229–239px**；
     视口 360px ⇒ `.cs-vb__btns` 只剩 **209px**。
     而按钮是**定宽 140px** ⇒ 140 + 8 + 140 = 288px > 239px ⇒ `flex-wrap` 只能一行一个。
     （旧注释「两个 288px 仍能并排」是按 **480px 视口**算的，390/360 的真机根本不成立。）

   ⇒ 两件事一起做才叫「不空旷」：
     ① `th.label` 那列**折成一行**（标题在上、按钮在下）⇒ 按钮行宽度 209 → 285px+；
     ② 按钮改**可伸缩**：`flex:1 1 calc(50% - 4px)`（4px = gap 8px 的一半）
        ⇒ 每行**恰好两个**，随容器自适应，不写死像素。
     `min-width:0` 必须留：否则长文本（`Ultra (White)`）会把 flex 项撑过 50%。
     `padding:0 10px` 收窄内边距，保证 `Ultra (White)` 不被省略号截断。

   ⚠️🔴 把 `th.label` 改成 `block` 会**盖掉** `.cs-vb-rowhide > th.label{display:none}`
      （那条特异性更低）⇒ `option` 那一行（PSA 证书号）会在手机端冒出 "Option" 标题。
      所以在同一条媒体查询里用**更高特异性**压回去 —— 删掉下面那条就会复发。 */
@media (max-width:480px){
	form.cart .variations{width:100%}
	form.cart .variations tbody,form.cart .variations tr{display:block}
	/* 🔴 `width:100%` 不能省（写成 auto 会出事）：`td.value` 在 `table-cell` 下是
	   **shrink-to-fit**，一旦按钮改成可伸缩宽度，单元格会跟着按钮一起塌 ——
	   实测 PSA 的 `option` 行（表头被隐藏、只剩一个单元格）从 315px 塌到 **192px**，
	   每个按钮只剩 92px ⇒ 12 位证书号会被省略号截断（那是要报给客户的号，绝不能截）。
	   钉成 100% 后单元格宽度＝表单宽度，与按钮宽度脱钩。 */
	form.cart .variations th.label{display:block;width:100%;padding:0 0 6px;border:0;text-align:left}
	form.cart .variations td.value{display:block;width:100%;padding:0}
	form.cart .variations tr.cs-vb-rowhide > th.label{display:none}
	.cs-vb,.cs-vb__btns{width:100%}
	.cs-vb.is-ready .cs-vb__btns{gap:8px}
	.cs-vb__btn{width:auto;flex:1 1 calc(50% - 4px);min-width:0;padding:0 10px}
}
/* ── 商品页购买区：把「短描述」从价格与按钮之间挪到最后（紧邻详情区） ────────
   🔴 2026-09-21 用户（手机端）反馈：「中间简介放在详情页，不然看上去很不简洁」。
   DOM 实测（/product/pikachu-sv-p-promo-6020/）购买区右栏的**真实顺序**：
        h1.wp-block-post-title              「2025 Pokemon Simplified Chinese … PSA 10」
        .wp-block-woocommerce-product-price    「$121.13」
        .wp-block-post-excerpt              ← 【479 字简介】原来夹在这里
        .wp-block-add-to-cart-form          「Pre-Order / 136976020」
        .cs-ship-note                        配送说明
        .wp-block-woocommerce-product-meta   分类 / 标签
   ⇒ 价格与「立即购买」之间横着一整屏文字，手机端尤其难看。

   🔴 而且这段（post_excerpt 479 字）**是下方详情区的压缩重复**：
      `woocommerce-tabs` 的 Description 面板（post_content 3287 字）是它的**超集** ——
      同一批事实全都在里面（cert 号 / 15 business days / 2 business days / Gem Mint / 香港发货 / 全额退款），
      唯一独有的「Free US shipping over $50」在**顶部公告条**与按钮下方的 `cs-ship-note` 里也有。

   ⇒ 改法：右栏改纵向 flex，只把短描述推到最后（`order` 给大值；
      其余子元素默认 0 ⇒ 自然全排在它前面）。价格与按钮重新贴在一起，简介落到详情区正上方。

   ⚠️ 纯视觉重排：**不动 DOM、不改模板、不删内容**。想还原只需删掉下面两行。
   ⚠️ 用 `:has()` 定位「装着 h1 的那一栏」，比按 `.wp-block-column` 序号写死稳
      （模板一改序号就错；详情区的规格两栏也是 `wp-block-column`，不能误伤）。
      `:has()` 需 Safari 15.4+ / Chrome 105+。
   ⚠️ 若要彻底不显示这段（详情区已完整覆盖），把第 2 条改成
      `… > .wp-block-post-excerpt{display:none}` 即可。 */
body.single-product .wp-block-column:has(> h1.wp-block-post-title){display:flex;flex-direction:column}
body.single-product .wp-block-column:has(> h1.wp-block-post-title) > .wp-block-post-excerpt{order:9}
