/* ============================================================
   UNITEX — OEM/ODM Underwear Sourcing Partner
   Design system: legacy black/white/orange, ink hairlines,
   stitch-dashed pills, editorial serif + mono spec labels.
   ============================================================ */

:root {
  --paper: #FFFFFF;
  --paper-2: #F7F6F3;
  --paper-3: #EFEDE7;
  --ink: #161412;
  --ink-2: #57524B;
  --ink-3: #8B857B;
  --line: #E4E1D9;
  --line-strong: #161412;
  --accent: #F28C28;
  --accent-deep: #D97706;
  --forest: #2F5D46;
  --gold: #C99A2C;
  --serif: "Fraunces", Georgia, "Times New Roman", serif;
  --sans: "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
  --max: 1240px;
  --pad: clamp(20px, 4vw, 56px);

  /* Astra-era mu-plugins (zz-a11y.php, unitex-colors.php in wp-content/mu-plugins)
     reference these two variables. This theme does not use them, but leaving them
     undefined would make any surviving rule that reads them resolve to nothing.
     They now point at the theme accent. */
  --ast-global-color-0: #D97706;
  --ast-global-color-1: #B45309;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--accent); color: #fff; }

img { max-width: 100%; height: auto; display: block; }

a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent-deep); }

.wrap { max-width: var(--max); margin: 0 auto; padding-left: var(--pad); padding-right: var(--pad); }

/* ---------- type ---------- */
h1, h2, h3, .serif { font-family: var(--serif); font-weight: 500; line-height: 1.08; letter-spacing: -0.01em; }
h1 { font-size: clamp(2.6rem, 6.2vw, 5.2rem); }
h2 { font-size: clamp(1.9rem, 3.6vw, 3rem); }
h3 { font-size: clamp(1.2rem, 2vw, 1.5rem); }
p.lede { font-size: clamp(1.05rem, 1.6vw, 1.25rem); line-height: 1.6; color: var(--ink-2); max-width: 62ch; }

.kicker {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-2);
  display: flex;
  align-items: center;
  gap: 12px;
}
.kicker::before { content: ""; width: 34px; height: 1px; background: var(--accent); display: inline-block; }

.mono { font-family: var(--mono); }

.idx {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--accent-deep);
  letter-spacing: 0.08em;
}

/* ---------- stitch pills & buttons ---------- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--ink-2);
  border-radius: 999px;
  padding: 7px 16px;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  background: transparent;
  transition: border-color .2s, color .2s, background .2s;
}
.pill:hover { border-color: var(--accent); color: var(--accent-deep); }
.pill.solid { background: var(--ink); color: var(--paper); border: 1px solid var(--paper); }
.pill.accent { border-color: var(--accent-deep); color: var(--accent-deep); }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 15px 28px;
  border-radius: 999px;
  border: 1px solid var(--ink);
  color: var(--ink);
  transition: all .2s ease;
  cursor: pointer;
  background: transparent;
}
.btn:hover { background: var(--ink); color: #fff; border-color: var(--ink); }
.btn.primary { background: var(--accent); border: 1px solid var(--accent-deep); color: #fff; }
.btn.primary:hover { background: var(--accent-deep); color: #fff; }
.btn.light { border-color: var(--paper); color: var(--paper); }
.btn.light:hover { background: var(--paper); color: var(--ink); }
.btn .arrow { transition: transform .2s; }
.btn:hover .arrow { transform: translateX(4px); }

/* ---------- header ---------- */
.site-head {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--ink);
  color: #fff;
  border-bottom: 1px solid var(--ink);
}
.head-in {
  display: flex;
  align-items: stretch;
  justify-content: space-between;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 0;
}
.brand .logo-img { height: 34px; width: auto; display: block; }
.brand:hover { opacity: .85; }
.nav { display: flex; align-items: stretch; }
.nav a {
  display: flex;
  align-items: center;
  padding: 0 18px;
  font-family: var(--mono);
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-left: 1px solid #2E2A25;
  color: #C9C4BB;
  transition: color .2s, background .2s;
}
.nav a:hover { color: var(--accent); background: #211D19; }
.nav a.active { color: var(--accent); box-shadow: inset 0 -2px 0 var(--accent); }
.head-cta { display: flex; align-items: center; padding-left: 18px; border-left: 1px solid #2E2A25; }
.head-cta .btn { padding: 11px 20px; font-size: 0.72rem; }

.burger { display: none; background: none; border: none; border-left: 1px solid #2E2A25; padding: 0 20px; cursor: pointer; }
.burger span { display: block; width: 24px; height: 2px; background: #fff; margin: 5px 0; transition: .25s; }

@media (max-width: 960px) {
  .nav, .head-cta { display: none; }
  .burger { display: block; }
  .nav.open {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: 100%; left: 0; right: 0;
    background: var(--ink);
    border-bottom: 1px solid #000;
  }
  .nav.open a { border-left: none; border-top: 1px solid #2E2A25; padding: 16px var(--pad); }
}

/* ---------- hero ----------
   2026-09-15 第三版（Will 两条反馈指向同一个根因）：
     · 「HOME 页那段白色框及其文字挡住了 banner 图 … 能调整一下位置或者以其他形式存在
        但是不影响页面视觉效果」
     · 「所有 banner 图，除了首页的，都是黑的，是不是你渲染的时候添加了黑色元素」
   白色岛压住图片、和黑色遮罩压住图片，是同一个问题的两种表现：**文字被叠在照片上**。
   照片要么为文字让路（压黑/加白框），要么文字就得让位。
   这一版让文字让位：hero 变成**左右分栏** —— 左边品牌墨色面板承载文字，
   右边照片 100% 原色，两者不重叠。首页与各级子页面统一用同一套版式。 */
.hero {
  position: relative;
  border-bottom: 1px solid var(--line-strong);
  overflow: hidden;
  display: block;
  min-height: clamp(420px, 42vw, 580px);
  background: var(--ink);
}
/* 照片用绝对定位放在右 56%。**不能让它参与行高计算** ——
   第一版把照片做成 grid item，结果照片的固有宽高比反过来决定了 hero 高度：
   首页实测被撑到 1152px、产品页（方图）807px。绝对定位后高度只由文字和
   min-height 决定，照片永远填满它那一栏。 */
.hero-photos {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  z-index: 0;
  display: flex;
}
.hero-photos .ph {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: none;
}
.hero-photos .ph.on { opacity: 1; }
.hero-photos img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* 首页这四条 banner 是**成品图**，左半边烘焙了 "Comfort Redefined" + UNI7EX 标志，
     人物在偏右处。右栏的可视窗口只有原图宽度的 ~60%，居中裁切会把那行字切成
     半截（"Comfort Rec…"）。把取景右移，整行烘焙文字被裁掉、人物居中。 */
  object-position: 76% center;
}
/* 首页原来那条 `to top` 全幅渐变（0.82 → 0.28 → 0.18）已取消 ——
   照片现在不与文字重叠，不需要压暗。 */
.hero-photos::after { content: none; }
.hero-island {
  position: relative;
  z-index: 2;
  
  border: 0;
  color: #fff;
  margin: 0;
  max-width: none;
  width: 100%;
  /* 2026-10-01：图片改全幅后，文字不再靠窄栏裁切，而是叠在左侧渐变遮罩上。
     遮罩同时盖住了 banner-1 左半边的烘焙品牌字与 banner-4 左下角的认证标。 */
  background: linear-gradient(90deg,
    rgba(11,11,11,.94) 0%,
    rgba(11,11,11,.88) 22%,
    rgba(11,11,11,.70) 34%,
    rgba(11,11,11,.38) 44%,
    rgba(11,11,11,.10) 52%,
    rgba(11,11,11,0) 58%);
  min-height: clamp(420px, 42vw, 580px);
  box-sizing: border-box;
  padding-top: clamp(34px, 4.5vw, 64px);
  padding-bottom: clamp(34px, 4.5vw, 64px);
  padding-right: clamp(20px, 2.5vw, 40px);
  /* 左内缩对齐站点的 1240px 版心：max(小屏内边距, (视口-版心)/2 + 内边距) */
  padding-left: max(var(--pad), calc((100vw - var(--max)) / 2 + var(--pad)));
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* 文字限宽在左半，避免遮罩右侧变透后文字压到模特身上 */
.hero-island > .kicker,
.hero-island > h1,
.hero-island > .lede,
.hero-island > .hero-actions,
.hero-island > .hero-certs { max-width: min(560px, 39vw); }

.hero-island h1 { margin: 18px 0 20px; font-size: clamp(1.6rem, 2.6vw, 2.6rem); }
.hero-island .lede { font-size: 0.95rem; }
.hero-island h1 em { font-style: italic; color: var(--accent); }
/* 墨色底上的胶囊：`.pill` 默认是墨色文字 + --ink-2 边框，在墨底上看不见 */
/* 深遮罩上的次级按钮（如 View Product Range）：原本按浅底设计的深色文字在遮罩上不可见 */
.hero-island .btn:not(.primary) { color: #fff; border-color: rgba(255,255,255,.6); }
.hero-island .btn:not(.primary):hover { border-color: var(--accent); color: var(--accent); }
.hero-island .pill { color: #fff; border-color: rgba(255,255,255,.55); }
.hero-island .pill:hover { border-color: var(--accent); color: var(--accent); }
.hero-island .kicker { color: #D8D3C9; }
.hero-island .lede { color: #E4E0D8; }
.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 28px; }
.hero-certs { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 26px; }

.hero-dots {
  position: absolute;
  right: var(--pad);
  bottom: 22px;
  z-index: 3;
  display: flex;
  gap: 10px;
}
.hero-dots button {
  width: 34px; height: 5px;
  border: none;
  background: rgba(255,255,255,.35);
  cursor: pointer;
  transition: background .3s;
  padding: 0;
}
.hero-dots button.on { background: var(--accent); }

.stat-row {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--line-strong);
  margin-top: clamp(24px, 5vh, 60px);
  background: var(--paper);
}
.stat {
  padding: 22px clamp(16px, 2.5vw, 36px);
  border-right: 1px solid var(--line-strong);
}
.stat:last-child { border-right: none; }
.stat b {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.8rem, 3.4vw, 2.8rem);
  display: block;
  line-height: 1;
}
.stat span {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-2);
}
@media (max-width: 720px) {
  .stat-row { grid-template-columns: 1fr 1fr; }
  .stat:nth-child(2) { border-right: none; }
  .stat:nth-child(1), .stat:nth-child(2) { border-bottom: 1px solid var(--line-strong); }
}

/* ---------- sections ---------- */
.section { border-bottom: 1px solid var(--line-strong); padding: clamp(56px, 9vw, 110px) 0; }
.section.tint { background: var(--paper-2); }
.section.ink { background: var(--ink); color: var(--paper); }
.section.ink .kicker { color: #A39D93; }
.section.ink p.lede { color: #C9C4BB; }

.sec-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 30px; margin-bottom: clamp(34px, 5vw, 60px); flex-wrap: wrap; }
.sec-head h2 { margin-top: 16px; max-width: 16ch; }
.sec-head .side { max-width: 40ch; color: var(--ink-2); font-size: 0.95rem; }

/* ---------- dense hairline catalog grid ---------- */
.cat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--line-strong);
  border-left: 1px solid var(--line-strong);
}
.cat-cell {
  border-right: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line-strong);
  padding: 22px;
  display: flex;
  flex-direction: column;
  min-height: 380px;
  position: relative;
  transition: background .25s;
}
.cat-cell:hover { background: var(--paper-2); }
.cat-cell .code {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  color: var(--ink-2);
  display: flex;
  justify-content: space-between;
}
.cat-cell h3 { margin: 14px 0 6px; }
.cat-cell .spec {
  font-family: var(--mono);
  font-size: 0.7rem;
  line-height: 1.8;
  color: var(--ink-2);
  letter-spacing: 0.02em;
}
.cat-cell .imgbox { margin-top: auto; padding-top: 20px; overflow: hidden; }
.cat-cell .imgbox img { width: 100%; aspect-ratio: 3/2; object-fit: cover; border: 1px solid var(--line-strong); }
.cat-cell .go {
  position: absolute;
  top: 20px; right: 20px;
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--accent-deep);
  opacity: 0;
  transform: translateX(-6px);
  transition: .25s;
}
.cat-cell:hover .go { opacity: 1; transform: none; }
.cat-cell.textual { justify-content: flex-start; background: var(--ink); color: var(--paper); }
.cat-cell.textual .code, .cat-cell.textual .spec { color: #A39D93; }
.cat-cell.textual:hover { background: #211D19; }
@media (max-width: 960px) { .cat-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { .cat-grid { grid-template-columns: 1fr; } .cat-cell { min-height: 0; } }

/* 2026-09-15（Will：「产品要 4 个一行、一页 5–6 行」）——
   产品网格（[unitex_product_grid] 输出的 .cat-grid.unitex-product-grid）
   原来是 3 列、约 218px 宽/格，男装品类页实测 169 个产品排成 57 行、
   整页 33903px 高。改为 4 列；配合 mu-plugin 新增的 per_page=24
   得到 4 列 × 6 行 = 24 个/页 + 分页。
   只作用于产品网格，不动分类总览页的 6 格 .cat-grid。 */
.cat-grid.unitex-product-grid { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1100px) { .cat-grid.unitex-product-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 860px) { .cat-grid.unitex-product-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .cat-grid.unitex-product-grid { grid-template-columns: 1fr; } }

/* 2026-09-15 —— 产品网格必须"撑破"正文栏。
   渲染实测（男装品类页）：网格在 `.wrap.prose.entry-content` 里，而那是一个
   为长文阅读收窄过的 767px 栏（左右各 56px padding）→ 4 列每列只有 **163px**，
   卡片标题被折成 "Breathabl / e"、"Cotton/Sp / andex" 这种断词，
   而且网格缩在页面中间、两侧留出大片空白。
   这里把网格从正文栏里横向撑出来，对齐 `.wrap` 的 1240px 版心。
   用负 margin + min() 计算，不用 100vw + transform —— 后者在窄视口会
   引入横向滚动条，也会新建包含块（本项目在吸顶/浮动组件上踩过一次）。 */
.prose .cat-grid.unitex-product-grid {
  width: calc(100vw - 2 * var(--pad));
  max-width: var(--max);
  margin-left: calc(50% - min(50vw - var(--pad), calc(var(--max) / 2)));
}
.prose .unitex-grid-count,
.prose .unitex-product-grid + .pager { max-width: var(--max); }
/* 分页与"第 N/M 页"计数行跟着网格一起撑出来，否则它们会缩在正文栏里、
   和上方的 4 列网格左右对不齐。 */
.prose > .unitex-product-grid + .pager,
.prose > .unitex-grid-count {
  width: calc(100vw - 2 * var(--pad));
  max-width: var(--max);
  margin-left: calc(50% - min(50vw - var(--pad), calc(var(--max) / 2)));
}

/* 产品分页的"第 N 页 / 共 M 页，本页显示第 a–b 个，共 C 个"计数行。
   它同时是给 AI 引擎的分页语义信号：让模型知道这是分部列举，
   而不是"这个品类只有 24 个产品"。 */
.unitex-grid-count {
  margin: 22px 0 0;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-align: center;
}
.unitex-product-grid + .pager { margin-top: 26px; justify-content: center; }

/* 2026-09-15 修（Will：文章页内容背景「白色 + 部分其他背景色」）——
   实测同一篇文章叠了三种奶白：.section 基色 #FFFDF6、
   `main > section:nth-of-type(even)` 交替出的 #FBF7EA、
   `.section.tint` 的 #F6F0DF，再往外是 body 的 #F1EADA。
   长文读起来像拼接色块（不是渲染坏了，是三条规则各自生效）。

   第一次尝试只写了 `.single-post main > section.section`，**没生效** ——
   交替规则是 `(0,4,2)`（三段 :not() 各算一个类），比它 `(0,2,1)` 高，
   于是"偶数段"仍是 #FBF7EA、只有 .tint 段变白，反而还是两种底色。
   这里把交替规则本身也按同样形状列进来（`.single-post` 前缀把特异性抬到 (0,5,3)），
   文章页与产品页正文统一成**单一阅读底**。 */
.single-post main > section:nth-of-type(even):not(.ink):not(.cta-band):not(.page-hero),
.single-post main > section.section,
.single-post main > section.section.tint,
.single-product main > section:nth-of-type(even):not(.ink):not(.cta-band):not(.page-hero),
.single-product main > section.section,
.single-product main > section.section.tint {
  background-color: var(--paper);
  background-image: var(--pat-cloud);
}

/* ---------- two-col ruled feature grid ---------- */
.rule-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--line-strong);
  border-left: 1px solid var(--line-strong);
}
.rule-cell {
  border-right: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line-strong);
  padding: clamp(26px, 3.5vw, 48px);
  display: block;
}
a.rule-cell:hover { background: var(--paper-2); }
.rule-cell .idx { display: block; margin-bottom: 18px; }
.rule-cell h3 { margin-bottom: 12px; }
.rule-cell p { color: var(--ink-2); font-size: 0.96rem; max-width: 52ch; }
/* factory-photograph cells (front-page #factory section, 2026-09-13) */
.rule-cell .imgbox { display: block; margin-bottom: 18px; overflow: hidden; }
.rule-cell .imgbox img {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  border: 1px solid var(--line-strong);
}
.rule-cell .detail {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed var(--ink-3);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--ink-2);
  line-height: 2;
}
.rule-cell .meta {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 14px;
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}
@media (max-width: 720px) { .rule-grid { grid-template-columns: 1fr; } }

/* ---------- process steps ---------- */
.steps { display: grid; grid-template-columns: repeat(6, 1fr); border-top: 1px solid var(--line-strong); border-left: 1px solid var(--line-strong); }
.step {
  border-right: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line-strong);
  padding: 22px 18px 26px;
  min-height: 190px;
  display: flex;
  flex-direction: column;
}
.step .idx { margin-bottom: 14px; }
.step h3 { font-size: 1.05rem; margin-bottom: 8px; }
.step p { font-size: 0.8rem; color: var(--ink-2); line-height: 1.55; }
.step .t { margin-top: auto; padding-top: 12px; font-family: var(--mono); font-size: 0.66rem; color: var(--accent-deep); letter-spacing: 0.1em; text-transform: uppercase; }
@media (max-width: 1000px) { .steps { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px) { .steps { grid-template-columns: 1fr 1fr; } }

/* ---------- cert stamps ---------- */
.stamps { display: flex; flex-wrap: wrap; gap: clamp(18px, 3vw, 40px); align-items: center; }
.stamp {
  width: 128px; height: 128px;
  border: 1.5px dashed var(--ink-2);
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4px;
  padding: 12px;
  font-family: var(--mono);
  transition: border-color .25s, transform .25s;
}
.stamp:hover { border-color: var(--accent); transform: rotate(-4deg); }
.stamp b { font-size: 0.82rem; letter-spacing: 0.06em; color: var(--ink); }
.stamp span { font-size: 0.58rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-2); line-height: 1.5; }
.stamp.green { border-color: var(--forest); }
.stamp.green b { color: var(--forest); }

/* stamps on dark sections */
.section.ink .stamp { border-color: #6E675C; }
.section.ink .stamp b { color: var(--paper); }
.section.ink .stamp span { color: #A39D93; }
.section.ink .stamp.green { border-color: #5E8A70; }
.section.ink .stamp.green b { color: #8FBCA0; }
.section.ink .stamp:hover { border-color: var(--accent); }

/* ---------- spec table ---------- */
.spec-table { width: 100%; border-collapse: collapse; border-top: 1px solid var(--line-strong); }
.spec-table th, .spec-table td {
  text-align: left;
  padding: 15px 18px;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
  font-size: 0.92rem;
}
.spec-table th {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-2);
  font-weight: 500;
  width: 220px;
  white-space: nowrap;
}
.spec-table td { color: var(--ink); }
.spec-table td .mono { font-size: 0.8rem; color: var(--ink-2); }
@media (max-width: 620px) { .spec-table th { width: 130px; } .spec-table th, .spec-table td { padding: 12px 10px; } }

/* ---------- faq ---------- */
.faq-item { border-bottom: 1px solid var(--line); }
.faq-item:first-of-type { border-top: 1px solid var(--line-strong); }
.faq-q {
  width: 100%;
  background: none;
  border: none;
  text-align: left;
  padding: 22px 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  cursor: pointer;
  font-family: var(--serif);
  font-size: clamp(1.05rem, 1.8vw, 1.3rem);
  color: var(--ink);
  font-weight: 500;
}
.faq-q:hover { color: var(--accent-deep); }
.faq-q .pm { font-family: var(--mono); font-size: 1.1rem; color: var(--accent-deep); flex: none; transition: transform .25s; }
.faq-item.open .faq-q .pm { transform: rotate(45deg); }
.faq-a { max-height: 0; overflow: hidden; transition: max-height .35s ease; }
.faq-a .inner { padding: 0 0 24px; color: var(--ink-2); max-width: 72ch; font-size: 0.96rem; }
.faq-a .inner p + p { margin-top: 10px; }

/* ---------- article / prose ---------- */
.prose { max-width: 76ch; }
.prose p { margin-bottom: 18px; color: var(--ink-2); }
.prose p strong, .prose li strong { color: var(--ink); }
.prose h2 { margin: 44px 0 18px; font-size: clamp(1.5rem, 2.6vw, 2rem); }
.prose h3 { margin: 32px 0 12px; }
.prose ul, .prose ol { margin: 0 0 18px 22px; color: var(--ink-2); }
.prose li { margin-bottom: 8px; }
.prose table { width: 100%; border-collapse: collapse; margin: 24px 0 30px; font-size: 0.9rem; }
.prose th, .prose td { border: 1px solid var(--line); padding: 12px 14px; text-align: left; vertical-align: top; }
/* 2026-09-15 修（Will：「FOUND 和 PRODUCT MODEL 为什么有空白框？」）——
   原选择器是 `.prose thead th, .prose tr:first-child th`。后半句本意是
   "没有 thead 的表用第一行当表头"，但这些核心表格块（About 的 Company Facts /
   Production 表）用的是**逐行 `<th scope="row">`**：第一行既是数据行、也被算成表头，
   于是只有第一行拿到 --paper-2 灰底 + 大写等宽，看起来就是一个跟其它行不一样的
   "空框"（Will 说的 FOUNDED / PRODUCTION MODEL 那两格）。
   只保留真正的 `thead th`；逐行表头一律同款，表格恢复整齐。 */
.prose thead th { background: var(--paper-2); font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); }
.prose blockquote {
  border-left: 2px solid var(--accent);
  padding: 6px 0 6px 22px;
  margin: 26px 0;
  font-family: var(--serif);
  font-size: 1.2rem;
  color: var(--ink);
  font-style: italic;
}
.byline { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.1em; color: var(--ink-2); text-transform: uppercase; display: flex; gap: 18px; flex-wrap: wrap; margin: 18px 0 34px; }

/* ---------- breadcrumbs ---------- */
.crumbs {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 14px 0 0;
  max-width: var(--max);
  margin: 0 auto;
  padding-left: var(--pad);
  padding-right: var(--pad);
}
.crumbs a { color: var(--ink-2); }
.crumbs a:hover { color: var(--accent-deep); }
.crumbs .sep { margin: 0 8px; color: var(--ink-3); }

/* ---------- 无素材页面的品牌版面（2026-09-15 加）----------
   起因：无特色图的页面只输出一个标题，观感像"未完成的文档页"（实测二级分类、
   国别页、工具页、关于、资源中心共 7 页）。hero 素材要等摄影，故先给站内品牌版面：
   顶部一道琥珀规则 + 极淡暖色渐变 + 复用首页的认证徽标行。
   刻意保持克制 —— 只用一个强调色、一个规则、一组既有 pill，不引入新视觉语言。 */
.page-hero.brand {
  background:
    linear-gradient(180deg, rgba(242,140,40,.075) 0%, rgba(242,140,40,0) 58%),
    var(--paper);
}
.page-hero.brand::before {
  content: "";
  position: absolute;
  left: var(--pad);
  top: 0;
  width: 148px;
  height: 4px;
  background: var(--accent);
}
.page-hero.brand .hero-certs { margin-top: 22px; }
/* 2026-09-15（Will：「应该分别用橙色框不然不显眼」）——
   原来沿用 --ink-2 灰边（实测 rgb(87,82,75)），在奶白底上几乎看不出是"框"。
   改用设计系统的强调橙。深橙 --accent-deep 在 #FFFDF6 上对比度约 3.6:1，
   比 --accent（约 2.3:1）更适合做 1px 细边框的可见性；文字仍用 --ink 保证读得清。 */
.page-hero.brand .hero-certs .pill {
  border-color: var(--accent-deep);
  color: var(--ink);
  background: rgba(242,140,40,.07);
}

/* ---------- page hero (sub pages) ---------- */
.page-hero { border-bottom: 1px solid var(--line-strong); padding: clamp(48px, 7vw, 88px) 0 clamp(40px, 5vw, 64px); position: relative; overflow: hidden; }
/* 2026-09-15 修：非 banner 的 hero 完全由内容撑高，实测在 288–527px 间乱跳
   （About 页只有 288px，一个词）。给一个下限把区间收敛，但不强行拉齐（避免大片空白）。 */
.page-hero:not(.banner) { min-height: clamp(300px, 30vw, 420px); }
.page-hero h1 { margin: 18px 0 20px; max-width: 20ch; }
.page-hero h1 em { font-style: italic; color: var(--accent-deep); }
.page-hero .lede { margin-bottom: 8px; }

/* banner variant with photo —— 2026-09-15 第三版：照片与文字**不再重叠** */
.page-hero.banner {
  position: relative;
  min-height: clamp(360px, 38vw, 500px);
  display: block;
  padding: 0;
  background: var(--ink);
}
/* 绝对定位在右 56% —— 理由同 .hero-photos：不让照片的宽高比决定 hero 高度
   （否则 600×600 的产品方图会把 hero 撑成 806px 高）。 */
.page-hero.banner > img.bg {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 56%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.page-hero.banner .scrim {
  position: absolute;
  inset: 0;
  /* 2026-09-15 第三次标定（Will：「所有 banner 图片页是黑黑暗暗的」）——
     过程与取舍记录在这里，因为这里有过两次失败的方向：

     第 1 版（原版）：`to top` 单渐变，整幅压暗。
     第 2 版：左偏 0.80 + 下偏 0.80 双重全幅渐变 → 合成后左下 0.96、
             右半仍有 0.38–0.83，H1 区对比度 14.3–19.8:1（阈值的 5–6 倍），
             照片被压成黑块 —— Will 看到的就是这个。
     第 3 版（本版）：先把压暗范围收到左侧。**但渲染实测暴露了真正的约束**：
             H1 的盒子宽 930px（= 页面宽度的 75%，x 从 156 到 1086），
             所以只要白字要读得清，就必然有 3/4 幅宽需要压暗 ——
             单纯调系数不可能既亮又可读。
     因此本版同时做两件事：
       (a) 把 banner 里 H1 的最大宽度收到 min(46%, 600px)、字号从
           clamp(2.7rem,5.6vw,4.6rem) 收到 clamp(1.9rem,3.2vw,2.95rem)，
           让文字块退到左侧 46% 以内（原先 74px 的 H1 压在照片上本来也过大）；
       (b) 遮罩只覆盖左侧这条文字带，到 86% 处完全归零 ——
           右侧 14% 与顶部全程是原片。
     系数按像素反推（工具 _import385/tools/calib_hero_scrim.py）：
     先量"关掉遮罩时 H1 区原始照片亮度 P98"（最坏页 product = 1.00，
     womens 0.888、pajamas 0.912、kids 0.819、mens 0.577），
     再由 对比度 = 1.05 / (L*(1-a) + 0.05) 反推。文字右边界落在 ~52% 处，
     该处 a≈0.75 → 最坏页 L=0.25 → 3.5:1（H1 是 46px 粗体，WCAG 大文本阈 3:1）；
     文字左边界 a≈0.84 → 最坏页 5.0:1。lede 另由 text-shadow 兜底。 */
  /* 2026-09-15 第四版（Will：「把给有照片的地方因为显现字而加的黑罩全都取消」）——
     上面那两组深色渐变的**声明本身**也一并删除，只留这条 display:none 的记录。
     原因：只写 display:none 的话，深色叠层的定义还留在文件里，将来任何人
     删掉一行就可能把它放出来；"全都取消"应该是文件里根本没有这个黑罩。
     hero 早就改成了左右分栏（文字在左侧墨色面板、照片在右侧原色），
     遮罩在结构上已无必要 —— 这一条现在只是防回退的保险。 */
  display: none;
}
.page-hero.banner .wrap {
  position: relative;
  z-index: 2;
  width: 44%;
  min-height: clamp(360px, 38vw, 500px);
  box-sizing: border-box;
  max-width: none;
  margin: 0;
  padding-top: clamp(32px, 4vw, 54px);
  padding-bottom: clamp(32px, 4vw, 54px);
  padding-right: clamp(20px, 2.5vw, 40px);
  /* 与站点 1240px 版心左对齐（见 .hero-island 同一条注释） */
  padding-left: max(var(--pad), calc((100vw - var(--max)) / 2 + var(--pad)));
  color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* 文字宽度现在由左栏约束，不再需要按百分比收窄 */
.page-hero.banner .wrap > * { max-width: 100%; }
.page-hero.banner h1 { color: #fff; }
.page-hero.banner h1 em { color: var(--accent); }
.page-hero.banner .kicker { color: #D8D3C9; }
.page-hero.banner p.lede { color: #E4E0D8; }
.page-hero.banner .pill { color: #fff; border-color: rgba(255,255,255,.55); }
.page-hero.banner .pill:hover { border-color: var(--accent); color: var(--accent); }
.page-hero.banner .byline { color: #C9C4BB; }

/* 2026-09-15：分栏版式在窄屏改成上下堆叠 —— 照片在上、文字面板在下，
   两者仍然不重叠。断点取 1024px：再窄左栏文字只剩 ~355px，标题会被折得太碎。
   照片仍是绝对定位，所以文字面板要用 margin-top 让出照片的高度。 */
/* 2026-10-01：桌面态把 hero 盒子设成图片原始比例（1920×1071）。
   原来盒子比例 ≈1.92、图片 1.79，object-fit:cover 必然裁掉图片上下 —— 客户与 Will 都指出"图片不完整"。
   比例一致后 cover 等于不裁切，也不会出现留白。 */
@media (min-width: 1025px) {
  .hero { aspect-ratio: 1920 / 1071; }
  .hero-photos { height: 100%; }
  .hero-island { min-height: 0; padding-top: clamp(28px, 3.6vw, 52px); padding-bottom: clamp(28px, 3.6vw, 52px); }
}

@media (max-width: 1024px) {
  .page-hero.banner > img.bg,
  .hero-photos {
    left: 0;
    right: 0;
    width: 100%;
    height: clamp(196px, 33vw, 300px);
    bottom: auto;
  }
  .page-hero.banner .wrap,
  .hero-island {
    width: 100%;
    min-height: 0;
    margin-top: clamp(196px, 33vw, 300px);
    padding-left: var(--pad);
    padding-right: var(--pad);
  }
  .page-hero.banner .wrap { padding-top: clamp(26px, 4.5vw, 44px); padding-bottom: clamp(26px, 4.5vw, 44px); }
  .hero-island { padding-top: clamp(26px, 5vw, 44px); padding-bottom: clamp(26px, 5vw, 44px); }
  /* 首页轮播圆点：堆叠后 bottom:22px 会压到文字面板上，改挂到照片下沿 */
  .hero-dots { bottom: auto; top: calc(clamp(196px, 33vw, 300px) - 20px); }

  /* 2026-09-15 —— 竖构图 hero 在横条窗口里会被裁掉头（文章 #5398 实测提出）。
     该断点照片是整幅宽的横条 clamp(196px,33vw,300px)：
     768px 下窗口 **768×253 = 3.03:1**，而竖图是 900×1200（0.75:1），
     cover 后只保留原图高度的 ~25%。默认居中落在第 452–748 行，
     而三个人的头在 165–334 行 —— 正好全被裁掉。
     取景上移到 12% 即可：第 108–405 行，三个头都回到画面内。
     实测过的对照（768px）：默认 452–748 / center top 0–297 / center 12% 108–405。
     **只作用于竖图** `.tall`：横构图的 banner（1920×1072，主体居中）
     若一起上移，反而会把主体顶出画面。 */
  .page-hero.banner > img.bg.tall { object-position: center 12%; }
}

/* ---------- split media+text ---------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(30px, 5vw, 72px); align-items: center; }
.split.rev > .media { order: 2; }
.split .media img { border: 1px solid var(--line-strong); width: 100%; }
.split .media .cap { font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); margin-top: 10px; }
@media (max-width: 860px) { .split { grid-template-columns: 1fr; } .split.rev > .media { order: 0; } }

/* ---------- image strip ---------- */
.strip3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; border: 1px solid var(--line-strong); }
.strip3 figure { border-right: 1px solid var(--line-strong); }
.strip3 figure:last-child { border-right: none; }
.strip3 img { width: 100%; aspect-ratio: 3/2; object-fit: cover; }
.strip3 figcaption { font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); padding: 12px 14px; border-top: 1px solid var(--line); }
@media (max-width: 720px) { .strip3 { grid-template-columns: 1fr; } .strip3 figure { border-right: none; border-bottom: 1px solid var(--line-strong); } }

/* ---------- market list ---------- */
.markets { columns: 3; column-gap: 40px; font-family: var(--mono); font-size: 0.8rem; line-height: 2.3; color: var(--ink-2); }
.markets li { list-style: none; border-bottom: 1px dashed var(--line); padding-left: 0; break-inside: avoid; }
.markets li::before { content: "→ "; color: var(--accent-deep); }
@media (max-width: 720px) { .markets { columns: 2; } }

/* ---------- CTA band ---------- */
.cta-band { text-align: left; }
.cta-band .wrap { display: flex; justify-content: space-between; align-items: center; gap: 40px; flex-wrap: wrap; }
.cta-band h2 { max-width: 20ch; }
.cta-band .contact-lines { font-family: var(--mono); font-size: 0.78rem; line-height: 2.2; color: #A39D93; letter-spacing: 0.04em; }
.cta-band .contact-lines a { color: var(--paper); border-bottom: 1px dashed #6E675C; }
.cta-band .contact-lines a:hover { color: var(--accent); }

/* ---------- contact form ---------- */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; border: 1px solid var(--line-strong); }
.field { border-bottom: 1px solid var(--line); border-right: 1px solid var(--line); padding: 18px 20px; }
.field.full { grid-column: 1 / -1; }
.field label { display: block; font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-2); margin-bottom: 8px; }
.field input, .field select, .field textarea {
  width: 100%;
  background: transparent;
  border: none;
  outline: none;
  font-family: var(--sans);
  font-size: 1rem;
  color: var(--ink);
  padding: 4px 0;
}
.field textarea { min-height: 110px; resize: vertical; }
.field:focus-within { background: var(--paper-2); box-shadow: inset 0 0 0 1px var(--accent); }
@media (max-width: 620px) { .form-grid { grid-template-columns: 1fr; } }

/* ---------- footer ---------- */
.site-foot { background: var(--ink); color: #C9C4BB; }
.foot-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1.2fr;
  gap: clamp(28px, 4vw, 60px);
  padding: clamp(50px, 7vw, 84px) 0 44px;
}
.foot-grid h4 { font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.2em; text-transform: uppercase; color: #8B857B; margin-bottom: 18px; font-weight: 500; }
.foot-grid ul { list-style: none; }
.foot-grid li { margin-bottom: 10px; font-size: 0.9rem; }
.foot-grid a:hover { color: var(--accent); }
.foot-brand p { font-size: 0.9rem; max-width: 38ch; margin: 14px 0 20px; line-height: 1.7; }
.foot-certs { display: flex; gap: 8px; flex-wrap: wrap; }
.foot-certs .pill { border-color: #57524B; color: #C9C4BB; font-size: 0.62rem; padding: 5px 12px; }
.foot-contact { font-family: var(--mono); font-size: 0.76rem; line-height: 2.1; letter-spacing: 0.03em; }
.foot-contact a { color: var(--paper); border-bottom: 1px dashed #57524B; }
.foot-contact a:hover { color: var(--accent); }
.foot-bottom {
  border-top: 1px solid #2E2A25;
  padding: 22px 0 26px;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #8B857B;
}
@media (max-width: 900px) { .foot-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .foot-grid { grid-template-columns: 1fr; } }

/* ---------- misc ---------- */
.note { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-3); letter-spacing: 0.04em; margin-top: 14px; }
.tagrow { display: flex; flex-wrap: wrap; gap: 8px; }
.hr-dash { border: none; border-top: 1px dashed var(--ink-3); margin: 40px 0; }
.skip { position: absolute; left: -9999px; top: 0; background: var(--accent); color: #fff; padding: 10px 18px; z-index: 200; font-family: var(--mono); font-size: 0.75rem; }
.skip:focus { left: 0; }

/* ============================================================
   V3 additions: grand header, textured background,
   floating contact dock, VIP video page
   ============================================================ */

/* ---------- textured background (kept ultra-subtle) ---------- */
:root {
  /* 祥云纹 (auspicious cloud scrolls) + 太阳神鸟 (sun-bird medallion) — warm ivory, low contrast */
  --pat-cloud: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' viewBox='0 0 180 180'%3E%3Cg fill='none' stroke='%23B98A2F' stroke-opacity='0.10' stroke-width='1.3' stroke-linecap='round'%3E%3Cpath d='M30 44c-8 0-12 5-12 10s4 9 9 9 8-4 8-8m-1-2c0-6 5-10 11-10s10 4 10 9c0 6-5 9-10 9'/%3E%3Cpath d='M63 54h34M70 61h22'/%3E%3Cpath d='M128 124c-8 0-12 5-12 10s4 9 9 9 8-4 8-8m-1-2c0-6 5-10 11-10s10 4 10 9c0 6-5 9-10 9'/%3E%3Cpath d='M161 134h-34M154 141h-22'/%3E%3C/g%3E%3Cg fill='none' stroke='%23161412' stroke-opacity='0.055' stroke-width='1.2'%3E%3Ccircle cx='135' cy='40' r='13'/%3E%3Ccircle cx='135' cy='40' r='7'/%3E%3Cpath d='M135 22v5M135 53v5M117 40h5M148 40h5M122 27l3.5 3.5M144.5 49.5L148 53M148 27l-3.5 3.5M125.5 49.5L122 53'/%3E%3Cpath d='M146 31c5-4 12-4 15 1-4-1-7 0-9 3 3-1 6 1 7 4-5 1-11-2-13-8z'/%3E%3C/g%3E%3Cg fill='none' stroke='%23161412' stroke-opacity='0.05' stroke-width='1.2'%3E%3Ccircle cx='42' cy='128' r='13'/%3E%3Ccircle cx='42' cy='128' r='7'/%3E%3Cpath d='M42 110v5M42 141v5M24 128h5M55 128h5M29 115l3.5 3.5M51.5 137.5L55 141M55 115l-3.5 3.5M32.5 137.5L29 141'/%3E%3Cpath d='M32 119c-5-4-12-4-15 1 4-1 7 0 9 3-3-1-6 1-7 4 5 1 11-2 13-8z'/%3E%3C/g%3E%3C/svg%3E");
  --pat-cloud-strong: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' viewBox='0 0 180 180'%3E%3Cg fill='none' stroke='%23B98A2F' stroke-opacity='0.15' stroke-width='1.3' stroke-linecap='round'%3E%3Cpath d='M30 44c-8 0-12 5-12 10s4 9 9 9 8-4 8-8m-1-2c0-6 5-10 11-10s10 4 10 9c0 6-5 9-10 9'/%3E%3Cpath d='M63 54h34M70 61h22'/%3E%3Cpath d='M128 124c-8 0-12 5-12 10s4 9 9 9 8-4 8-8m-1-2c0-6 5-10 11-10s10 4 10 9c0 6-5 9-10 9'/%3E%3Cpath d='M161 134h-34M154 141h-22'/%3E%3C/g%3E%3Cg fill='none' stroke='%23161412' stroke-opacity='0.08' stroke-width='1.2'%3E%3Ccircle cx='135' cy='40' r='13'/%3E%3Ccircle cx='135' cy='40' r='7'/%3E%3Cpath d='M135 22v5M135 53v5M117 40h5M148 40h5M122 27l3.5 3.5M144.5 49.5L148 53M148 27l-3.5 3.5M125.5 49.5L122 53'/%3E%3Cpath d='M146 31c5-4 12-4 15 1-4-1-7 0-9 3 3-1 6 1 7 4-5 1-11-2-13-8z'/%3E%3C/g%3E%3Cg fill='none' stroke='%23161412' stroke-opacity='0.07' stroke-width='1.2'%3E%3Ccircle cx='42' cy='128' r='13'/%3E%3Ccircle cx='42' cy='128' r='7'/%3E%3Cpath d='M42 110v5M42 141v5M24 128h5M55 128h5M29 115l3.5 3.5M51.5 137.5L55 141M55 115l-3.5 3.5M32.5 137.5L29 141'/%3E%3Cpath d='M32 119c-5-4-12-4-15 1 4-1 7 0 9 3-3-1-6 1-7 4 5 1 11-2 13-8z'/%3E%3C/g%3E%3C/svg%3E");
  --pat-cloud-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' viewBox='0 0 180 180'%3E%3Cg fill='none' stroke='%23F28C28' stroke-opacity='0.08' stroke-width='1.3' stroke-linecap='round'%3E%3Cpath d='M30 44c-8 0-12 5-12 10s4 9 9 9 8-4 8-8m-1-2c0-6 5-10 11-10s10 4 10 9c0 6-5 9-10 9'/%3E%3Cpath d='M63 54h34M70 61h22'/%3E%3Cpath d='M128 124c-8 0-12 5-12 10s4 9 9 9 8-4 8-8m-1-2c0-6 5-10 11-10s10 4 10 9c0 6-5 9-10 9'/%3E%3Cpath d='M161 134h-34M154 141h-22'/%3E%3C/g%3E%3Cg fill='none' stroke='%23FFFFFF' stroke-opacity='0.05' stroke-width='1.2'%3E%3Ccircle cx='135' cy='40' r='13'/%3E%3Ccircle cx='135' cy='40' r='7'/%3E%3Cpath d='M135 22v5M135 53v5M117 40h5M148 40h5'/%3E%3Ccircle cx='42' cy='128' r='13'/%3E%3Ccircle cx='42' cy='128' r='7'/%3E%3Cpath d='M42 110v5M42 141v5M24 128h5M55 128h5'/%3E%3C/g%3E%3C/svg%3E");
}
body {
  background-color: #F1EADA;
  background-image: var(--pat-cloud);
  background-size: 180px 180px;
}
/* Chinese-pattern paper surfaces — pattern lives INSIDE sections,
   contrast kept low so text stays perfectly readable */
.section, .page-hero:not(.banner) {
  background-color: #FFFDF6;
  background-image: var(--pat-cloud);
}
.section.tint {
  background-color: #F6F0DF;
  background-image: var(--pat-cloud-strong);
}
.section.ink { background-image: var(--pat-cloud-dark); }
main > section:nth-of-type(even):not(.ink):not(.cta-band):not(.page-hero) {
  background-color: #FBF7EA;
  background-image: var(--pat-cloud);
}
/* 2026-09-15 修 —— 吸顶页头从来没生效过。
   `.site-head` 原来也在这个 `position: relative` 列表里，而这条规则位于
   第 131 行 `.site-head { position: sticky }` 之后、特异性同为 (0,1,0)，
   于是 sticky 被就地覆盖。渲染实测：computed position = "relative"，
   滚到 y=1800 时页头 top = -1742（跟着滚走了）。
   Will 的反馈「鼠标下拉的时候，抬头要保持不动，不然客人无法点击下一级子页」
   正是这个。这里把 .site-head 摘出去，让 sticky 生效。 */
.stat-row, .hero-island, .section, .page-hero, .site-foot, .crumbs {
  position: relative;
}

/* ---------- grand header ---------- */
.topbar {
  background: #0B0A08;
  color: #8B857B;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.topbar .wrap {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  padding-top: 8px;
  padding-bottom: 8px;
}
.topbar a { color: #C9C4BB; }
.topbar a:hover { color: var(--accent); }
.topbar .tb-right { display: flex; gap: 22px; align-items: center; }
/* 2026-09-15 修：实测 WhatsApp 号码折成两行（+86 186 / 5081 3853）。
   ⚠ 但 nowrap 不能无条件加：首版直接写在基础规则上，导致 **移动端横向滚动**
     （实测 scrollWidth 404 > clientWidth 390，11 个页面全部溢出 14px）——
     已由 capture_site.py 的横滚断言当场抓出。故只在 ≥961px（.tb-left 隐藏的同一断点）生效。 */
@media (min-width: 961px) {
  .topbar .tb-right, .topbar .tb-right > * { white-space: nowrap; }
}
.topbar .vip-link { color: var(--accent); }
.topbar .vip-link:hover { color: #FFB35C; }
@media (max-width: 720px) {
  .topbar .tb-left { display: none; }
  .topbar .wrap { justify-content: center; }
}

.site-head { border-bottom: none; }
.head-in { position: relative; }
.brand { padding: 20px 0; }
.brand .logo-img { height: 44px; }
.head-rule {
  height: 3px;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent) 18%, #2E2A25 18%, #2E2A25 100%);
}
@media (max-width: 960px) { .brand .logo-img { height: 34px; } }

/* ---------- floating contact dock ---------- */
.float-dock {
  position: fixed;
  right: 18px;
  bottom: 22px;
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-end;
}
.float-dock .fd-btn {
  width: 52px; height: 52px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ink);
  color: #fff;
  border: 1px solid #000;
  box-shadow: 0 6px 18px rgba(0,0,0,.28);
  transition: transform .2s, background .2s;
  position: relative;
}
.float-dock .fd-btn:hover { transform: translateY(-3px); }
.float-dock .fd-btn svg { width: 24px; height: 24px; }
.float-dock .fd-btn.wa { background: #1FA855; border-color: #178A45; }
.float-dock .fd-btn.inquiry { background: var(--forest); border-color: #244936; }
.float-dock .fd-btn.mail { background: var(--accent); border-color: var(--accent-deep); }
.float-dock .fd-btn.main-toggle { background: var(--ink); }
.float-dock .fd-label {
  position: absolute;
  right: 62px;
  top: 50%;
  transform: translateY(-50%);
  background: var(--ink);
  color: #fff;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: 4px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s;
}
.float-dock .fd-btn:hover .fd-label { opacity: 1; }
.float-dock .fd-collapse {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-end;
}
@media (max-width: 620px) {
  .float-dock { right: 12px; bottom: 14px; }
  .float-dock .fd-btn { width: 46px; height: 46px; }
}

/* ---------- VIP video page ---------- */
.vip-gate {
  max-width: 520px;
  margin: clamp(40px, 8vh, 90px) auto;
  background: #fff;
  border: 1px solid var(--line-strong);
  padding: clamp(30px, 5vw, 54px);
  text-align: center;
}
.vip-gate .lock {
  width: 64px; height: 64px;
  margin: 0 auto 22px;
  border: 1.5px dashed var(--accent-deep);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.vip-gate .lock svg { width: 26px; height: 26px; }
.vip-gate input {
  width: 100%;
  text-align: center;
  font-family: var(--mono);
  font-size: 1.3rem;
  letter-spacing: 0.5em;
  padding: 16px;
  border: 1px solid var(--line-strong);
  background: var(--paper-2);
  outline: none;
  margin: 22px 0 14px;
  text-transform: uppercase;
}
.vip-gate input:focus { box-shadow: inset 0 0 0 1px var(--accent); background: #fff; }
.vip-gate .err { color: #C0392B; font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.08em; min-height: 20px; }
.vip-gate .hint { font-family: var(--mono); font-size: 0.66rem; color: var(--ink-3); letter-spacing: 0.08em; margin-top: 18px; line-height: 2; }
.vip-videos { display: none; }
.reel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 0;
  border-top: 1px solid var(--line-strong);
  border-left: 1px solid var(--line-strong);
}
.reel-cell {
  border-right: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line-strong);
  background: #0E0C0A;
  display: flex;
  flex-direction: column;
}
.reel-cell video { width: 100%; aspect-ratio: 9/14; object-fit: cover; background: #000; display: block; }
.reel-cell .reel-cap {
  background: #fff;
  padding: 14px 16px;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  border-top: 1px solid var(--line-strong);
  display: flex;
  justify-content: space-between;
  gap: 10px;
}
.reel-upload {
  border: 1.5px dashed var(--ink-2);
  padding: clamp(24px, 4vw, 44px);
  text-align: center;
  background: #fff;
}
.reel-upload input[type=file] { display: none; }
.reel-upload .file-name { font-family: var(--mono); font-size: 0.72rem; color: var(--ink-2); margin-top: 12px; }
.reel-empty { text-align: center; padding: clamp(40px, 7vw, 80px) 20px; color: var(--ink-2); font-family: var(--mono); font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase; line-height: 2.4; }

/* ============================================================
   V4: grander header, bigger type, VIP nav entry
   ============================================================ */
.topbar { font-size: 0.72rem; font-weight: 500; }
.topbar .wrap { padding-top: 10px; padding-bottom: 10px; }

.brand { padding: 22px 0; gap: 16px; }
.brand .logo-img { height: 52px; }
.brand-tag {
  font-family: var(--mono);
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #C9C4BB;
  line-height: 1.7;
  border-left: 1px solid #2E2A25;
  padding-left: 16px;
  white-space: nowrap;
  flex: none;
}
.brand { flex: none; }
.nav { flex: none; }

/* 2026-09-13 — the header must never widen the document.
   The design was drawn for 新站2's six top-level items; the live site's menu
   has eighteen, which made the nav bar 1069 px wide and pushed the sticky
   header 239 px past a 1440 px viewport on every page. The nav now shrinks and
   scrolls horizontally instead of forcing a horizontal scrollbar on the page,
   and .head-in may wrap if the brand and the call-to-action still collide.
   The curated seven-item menu (see setup_header_menu.py) is the intended fix;
   this is the safety net for any menu an editor assigns later. */
.head-in { flex-wrap: wrap; row-gap: 4px; }
.nav {
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.nav::-webkit-scrollbar { display: none; }
.nav a { flex: 0 0 auto; white-space: nowrap; }
/* 2026-09-15：桌面端放开 .nav 的横向裁剪，否则悬停下拉子菜单会被 overflow 裁掉
   （子菜单是 .nav-item 的绝对定位后代）。菜单已收敛为 6 项，桌面宽度足够；
   窄一点的桌面同时收紧 padding，给「品牌 + 6 项 + CTA」留出余量。 */
@media (min-width: 961px) {
  .nav { overflow: visible; }
}
@media (max-width: 1560px) { .brand-tag { display: none; } }
@media (max-width: 960px) { .brand .logo-img { height: 40px; } .brand { padding: 16px 0; } }

.nav a {
  padding: 0 22px;
  font-size: 0.84rem;
  letter-spacing: 0.16em;
  font-weight: 500;
}
/* 2026-09-15 —— 菜单加为 7 项（新增 HOME）后的宽度收口。
   品牌 201 + 菜单 811 + CTA 190 = 1202px，超过 1240 版心的可用宽 1128px，
   `.head-in` 于是换行、GET A QUOTE 被挤到第二行（实测 .site-head 从 ~60px 变成 154px）。
   这条必须放在上面那个 `.nav a { padding: 0 22px }` **之后** ——
   我第一版把它写在文件更靠前的位置，特异性相同、被这条覆盖，改了个寂寞
   （实测 items_sum 仍是 811、head_h 仍是 154，才发现没生效）。 */
@media (min-width: 961px) {
  .nav a { padding: 0 11px; letter-spacing: 0.10em; font-size: 0.78rem; }
  .head-cta .btn { padding: 12px 18px; }
}
/* 1024–1100px 这一段的可用宽只剩 ~942px（版心被视口掐住、内边距 4vw），
   11px 内边距下的 7 项（586px）+ 品牌 201 + CTA 190 = 977px 仍会换行
   （实测 1024px 时 real_rows=2、页头 154px）。这一段再收紧一档。 */
@media (min-width: 961px) and (max-width: 1100px) {
  .nav a { padding: 0 8px; font-size: 0.72rem; letter-spacing: 0.06em; }
  .head-cta .btn { padding: 11px 14px; font-size: 0.7rem; }
}
.nav a.nav-vip {
  color: var(--accent);
  border-left: 1px solid #2E2A25;
  position: relative;
}
.nav a.nav-vip:hover, .nav a.nav-vip.active { color: #FFB35C; background: #211D19; }
.nav a.nav-vip::before {
  content: "";
  position: absolute;
  left: 50%; top: 12px;
  transform: translateX(-50%);
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
  animation: vippulse 2.2s ease-in-out infinite;
}
@keyframes vippulse { 0%,100% { opacity: .35; } 50% { opacity: 1; } }
@media (max-width: 960px) { .nav a.nav-vip::before { display: none; } }

.head-cta .btn { padding: 14px 24px; font-size: 0.78rem; font-weight: 500; }

/* page hero type a touch grander */
.page-hero h1 { font-size: clamp(2.7rem, 5.6vw, 4.6rem); }
/* 2026-09-15：banner 变体分栏后，文字栏只有 44% 宽，H1 相应收小
   （非 banner 的浅底 hero 保持原来的大字号）。 */
.page-hero.banner h1 { font-size: clamp(1.55rem, 2.35vw, 2.35rem); }
/* 分栏版式下文字不再压在照片上，光晕只留一点点，避免白字边缘发糊 */
.page-hero.banner h1 {
  text-shadow: 0 1px 2px rgba(11,10,8,.35);
}
.page-hero.banner .kicker,
.page-hero.banner p.lede,
.page-hero.banner .hero-certs .pill {
  text-shadow: 0 1px 3px rgba(11,10,8,.82), 0 0 12px rgba(11,10,8,.55);
}
.page-hero.banner .lede { max-width: 64ch; }

/* ---------- decorative Chinese fret divider band ---------- */
.fret-band {
  height: 14px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='14' viewBox='0 0 28 14'%3E%3Cg fill='none' stroke='%23F28C28' stroke-opacity='0.85' stroke-width='1.3'%3E%3Cpath d='M2 2h10v10H7V7h5'/%3E%3Cpath d='M16 12h10V2h-5v5h5'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 28px 14px;
  background-repeat: repeat-x;
  background-position: center;
  opacity: .8;
}
.fret-band.on-dark { background-color: transparent; }

/* keep text-bearing surfaces extra clean: tables, forms, faq, prose */
.spec-table, .form-grid, .faq-list { background: rgba(255,255,255,.72); }
.prose { background: transparent; }
.cat-grid, .rule-grid, .steps { background: rgba(255,255,255,.55); }

/* FAQ group heading */
.faq-group{font-size:15px;font-weight:600;letter-spacing:.02em;margin:34px 0 14px;padding-bottom:8px;border-bottom:1px solid rgba(0,0,0,.12)}


/* wide tables scroll horizontally on narrow screens — page itself never overflows */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 720px) {
  .table-wrap { margin: 0 -2px; }
}

/* ---------- resource cards ---------- */
.resource-grid { display:grid; gap:20px; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); margin-top:28px; }
.resource-card { border:1px solid var(--line-strong); border-radius:14px; padding:22px; background:#fff; display:flex; flex-direction:column; gap:10px; }
.resource-card h3 { margin:0; font-size:1.05rem; }
.resource-card p { margin:0; color:var(--ink-2); }
.resource-meta { font-family:var(--mono,monospace); font-size:.78rem; letter-spacing:.02em; text-transform:uppercase; color:var(--ink-2); }
.resource-card .btn { align-self:flex-start; margin-top:auto; }
@media (max-width:640px){ .resource-grid { grid-template-columns:1fr; } }

/* ============================================================
   === NEW IN THIS THEME (WordPress port) — everything below is
   === NOT present in 新站2's style.css and was added only where
   === WordPress structure / the GEO blocks require it.
   === Tokens, type scale, hairlines and the orange accent are
   === reused verbatim; no new colours or fonts are introduced.
   ============================================================ */

/* ---------- text wordmark used when no custom logo is uploaded ---------- */
.brand-mark {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.7rem;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
}
.site-foot .brand-mark { font-size: 1.35rem; }
@media (max-width: 960px) { .brand-mark { font-size: 1.3rem; } }

/* ---------- custom logo: UNITEX wordmark morphs into "WELCOME" ----------
   2026-09-13 (Will): hovering the masthead logo must dissolve the UNITEX wordmark
   into particles that re-form as WELCOME, then morph back on mouse-out.

   Source of truth (found after my first attempt was wrong): the effect is NOT in
   `site-static` — that build renders a plain <img class="logo-img"> with no
   treatment at all. It lives in the K3 **app** line, and the exact numbers below
   are copied from it:
     · app/public/assets/css/style.css:1125-1134  (.logo-dissolve rules)
     · app/public/assets/js/main.js:323-495      (the particle morph IIFE)
     · app/public/about.html                     (<span class="logo-dissolve"> wrapper)
   Requirement: the <img> must be wrapped in .logo-dissolve and keep the
   `logo-img` class — the script looks for `.logo-dissolve img.logo-img`, samples
   it into a dot grid (GAP = 2 css px), and pairs every logo dot with a dot of the
   WELCOME wordmark rendered at Inter 800 with 0.14em tracking. The wordmark takes
   the average colour of the logo's own opaque pixels.

   Asset: logo_white.png (mean opaque RGB 254/222/181) — masthead and footer both
   sit on --ink #161412, where the black variant (92/58/16) would land near 1.6:1.
 */
.logo-dissolve { position: relative; display: inline-block; line-height: 0; }
.logo-dissolve img.logo-img { display: block; transition: opacity .18s; }
.logo-dissolve canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  opacity: 0;
}
.logo-dissolve.dissolving img.logo-img { opacity: 0; }
.logo-dissolve.dissolving canvas { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  /* The morph is decorative; the wordmark must stay legible either way. */
  .logo-dissolve canvas { display: none; }
}

/* ---------- photo frame + UNITEX watermark on CLEAN photographs ----------
   2026-09-13 (Will): article photos should read like the 聚米旧站 — every photo
   carries a frame and a UNITEX watermark. Reference spec:
   04_GEO与内容/配图模板/聚米文章配图模板_20260912/聚米文章配图修复报告_20260912.md —
   orange #FA9B10 box (5/7/7/39 px on 600×600) plus a black UNITEX wordmark at
   (9,16), and its hard-won lesson is that a second, CSS-applied frame turns a
   5 px edge into a 14 px double frame.

   THE OPT-IN CLASS IS THE POINT. This block must never fire on an image that
   already carries baked branding. On this site that is not hypothetical: the
   category cards on /en/ and the whole [unitex_product_grid] catalogue on the
   product pages wrap 600×600 product photographs that ALREADY have the 聚米
   orange frame and white watermark burned in (measured on UT-GSB0001.jpg /
   sportbra.jpg: edge pixels (254,148,12) (252,150,6) …, bottom band 6 px of
   (252,161,28)). Those photographs are emitted as a bare `<span class="imgbox">`
   by a mu-plugin this theme does not own, so a `.imgbox::after` rule framed and
   watermarked them a second time and darkened them by roughly 70 %.
   Therefore the frame is driven by `.utx-brand`, which only the theme's own
   card helpers add, and only after the source photograph passed the
   "is it already branded?" pre-check (图片层_20260913/precheck_pool.py).
   `is-branded` remains as an explicit belt-and-braces opt-out.

   Frame colour: this theme's own hairline (--line-strong #161412), not 聚米's
   orange box — every other image on this design system is framed with
   --line-strong, and the orange is reserved for accents (header rule, kickers).

   Watermark: white wordmark over a graduated dark corner scrim, not the
   reference's black wordmark. Measured over the pool of clean photographs, the
   top-left watermark region runs from luminance 0.04 to 0.66; a black wordmark
   with no scrim clears 4.5:1 on only 19 of 28 and falls to 1.62:1 on the
   darkest, while the white wordmark over a scrim held at 80 % across the whole
   watermark box clears 5.6:1 on the worst (lightest) photograph. */
.imgbox,
.showcase-thumb {
  position: relative;
  display: block;
}
.imgbox.utx-brand,
.showcase-thumb { overflow: hidden; }
.rule-cell .imgbox.utx-brand > img,
.imgbox.utx-brand > img,
.showcase-thumb > img {
  border: 2px solid var(--line-strong);
}
.imgbox.utx-brand::after,
.showcase-thumb::after {
  content: "";
  position: absolute;
  /* 2026-09-15 第四次修（Will：「UNITEX 的水印还是正常的水印，浅的淡色的，
     不能影响视觉效果」）——
     这个水印的演进：整幅深色渐变 → 角上深色底板 → 黑色实心 logo → 本版淡水印。
     前两版是"为了让白水印看得见"而加黑罩（已按要求取消）；第三版换黑色实心
     logo 又太重，像在照片上贴了标签。本版做成**真正的淡水印**：
     黑色 logo + 低不透明度，在浅色工厂照上呈现为淡灰字标 ——
     是水印，但不和画面抢注意力。
     注：这批工厂照以浅色为主，所以用深色淡水印；若以后换成深色照片，
     把 url 换回 unitex-logo-white.png 并把 opacity 提到 ~0.5 即可。 */
  left: 0;
  top: 0;
  width: 42%;
  height: 32%;
  pointer-events: none;
  background-image: url("../img/unitex-logo-black.png");
  background-repeat: no-repeat;
  background-position: 12px 10px;
  background-size: 44% auto;
  /* 不透明度 0.45 是**实测挑出来的**，不是拍的：把同一张工厂照在
     0.26 / 0.35 / 0.45 / 0.55 / 0.70 / 1.0 六档各渲染一遍、做成对照拼版
     （99_临时/shots/watermark_sweep.png）之后判断 ——
       0.26 在照片上几乎看不见（水印失去意义）
       0.35 勉强可见
       0.45 一眼认得出是水印、而且仍是半透明的淡灰标   ← 采用
       0.55 偏显眼   0.70 开始抢画面   1.0 像照片上贴了标签（被否掉的那版） */
  opacity: .45;
}
/* Explicit opt-out for photographs that already carry a baked frame + watermark. */
.imgbox.is-branded > img,
.imgbox.is-branded.utx-brand > img { border: 0; }
.imgbox.is-branded::after { content: none; }
@media (max-width: 720px) {
  .imgbox.utx-brand::after,
  .showcase-thumb::after { background-position: 10px 9px; background-size: 40% auto; }
}

/* A three-column variant of the hairline grid, used only by the front page's
   factory-photograph section (2026-09-13). Twelve photographs at two columns
   would have made the section six 430 px-tall rows; at three columns it is four
   rows and still reads as a wall of evidence. */
.rule-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 960px) { .rule-grid.cols-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 720px) { .rule-grid.cols-3 { grid-template-columns: 1fr; } }

/* 2026-09-15：工厂照片区下方的 "View the product gallery →" CTA
   —— 补回首页 post_content 里那条从未渲染的链接（见 front-page.php 的注释）。 */
.gallery-cta { text-align: center; margin-top: clamp(26px, 3.5vw, 40px); }

/* ---------- GEO: company entity anchor block (.entity-block) ---------- */
.entity-block {
  border-top: 1px solid var(--line-strong);
  padding-top: clamp(24px, 3vw, 34px);
  margin: clamp(30px, 4vw, 46px) 0;
}
.entity-block > h2 { margin: 14px 0 20px; font-size: clamp(1.6rem, 3vw, 2.3rem); }
.entity-block .spec-table caption, .spec-table caption {
  caption-side: top;
  text-align: left;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.9;
  padding-bottom: 12px;
}

/* ---------- GEO: keep the FAQ button's text node identical to schema name ---------- */
/* The "+" is drawn by CSS so the visible question text (and its textContent)
   matches FAQPage.name byte for byte; the base rotate-on-open transform still
   applies to .pm. */
.faq-q .pm::before { content: "+"; }

/* ---------- navigation: highlight the current item ---------- */
.nav a.current-menu-item,
.nav a.current_page_item,
.nav a.current-menu-parent,
.nav a.current_page_parent,
/* 2026-09-15 修：缺 `*-ancestor` —— 品类页（如 /oem-products/mens-underwear/）
   实测拿的是 `current-page-ancestor`，而这里没列它，导致 **品类页导航完全没有当前态**
   （视觉审阅也独立指出"一级品类页六个导航项全同色"）。补上祖先类，
   让"所在栏目"被高亮；产品页那处误标由 body.single-product 规则单独抑制。 */
.nav a.current-menu-ancestor,
.nav a.current-page-ancestor,
.nav a.active { color: var(--accent); box-shadow: inset 0 -2px 0 var(--accent); }

/* 2026-09-15 修：产品页误把 INSIGHTS 高亮为当前态。
   实测成因：WP 给 Insights 菜单项加了 `current_page_parent`（文章页这样标是对的，
   但 **product 这种非层级 CPT 也被标**，而当前页并不属于该栏目）。
   按页面类型抑制，而不是删掉整条规则 —— 删了会让文章页丢掉正确的高亮。 */
body.single-product .nav a.current_page_parent {
  color: inherit;
  box-shadow: none;
}

/* ---------- 一级导航的悬停下拉子菜单（2026-09-15，Will 要求）----------
   起因：Will 反馈「鼠标放上去 PRODUCT 就会出现子一级」（对标聚米站点）。
   实测成因有两处，缺一不可：
     ① Walker 以 `depth => 1` 调用，子项**根本没被输出**（只有 6 个平级项）；
     ② `.nav` 带 `overflow-x: auto`，而 overflow 一个轴非 visible 时另一个轴
        会计算成 auto —— 绝对定位的下拉会被裁掉，所以必须先放开 overflow。
   实现：`ul`-less 的既有结构保留，深度 0 且带子项的条目由 Walker 包一层
   `.nav-item.has-sub`，子项放进 `.submenu`。 */
.nav-item { position: relative; display: flex; align-items: stretch; }
.nav-item > a { height: 100%; }
.nav-item.has-sub > a::after {
  content: "";
  width: 0; height: 0;
  margin-left: 8px;
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  border-top: 4px solid currentColor;
  opacity: .75;
}
.submenu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 140;
  min-width: 268px;
  padding: 8px 0;
  background: var(--ink);
  border: 1px solid #2E2A25;
  border-top: 2px solid var(--accent);
  box-shadow: 0 22px 44px rgba(11,10,8,.38);
  display: none;
}
.nav-item.has-sub:hover > .submenu,
.nav-item.has-sub:focus-within > .submenu { display: block; }
.submenu a {
  display: block;
  padding: 11px 18px;
  border-left: 0;
  font-size: 0.76rem;
  letter-spacing: 0.12em;
  white-space: nowrap;
  color: #C9C4BB;
}
.submenu a:hover { background: #211D19; color: var(--accent); }
@media (max-width: 960px) {
  /* 移动端走 .nav.open 的堆叠菜单，下拉容器改为常显的缩进列表 */
  .nav-item { display: block; }
  .submenu {
    position: static;
    display: block;
    min-width: 0;
    border: 0;
    border-left: 1px solid #2E2A25;
    box-shadow: none;
    padding: 0 0 6px 14px;
  }
  .nav-item.has-sub > a::after { display: none; }
}

/* ---------- GEO: answer-first block (.answer) ---------- */
.geo-answer-slot { padding-top: clamp(30px, 4.5vw, 52px); }
.answer {
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--accent);
  background: #fff;
  padding: clamp(20px, 3vw, 30px) clamp(20px, 3vw, 32px);
  margin: 0 0 clamp(28px, 4vw, 42px);
  max-width: 76ch;
}
.answer .a-label {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-2);
  display: flex;
  align-items: center;
  gap: 10px;
}
.answer .a-label::before { content: ""; width: 20px; height: 1px; background: var(--accent); display: inline-block; }
.answer p {
  font-family: var(--serif);
  font-size: clamp(1.05rem, 1.6vw, 1.22rem);
  line-height: 1.6;
  color: var(--ink);
  margin: 14px 0 0;
}
.answer .a-entity {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.8;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px dashed var(--line);
}

/* ---------- GEO: key takeaways / checklist / sources ---------- */
.takeaways {
  border-top: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line-strong);
  padding: clamp(18px, 2.6vw, 26px) 0;
  margin: 0 0 clamp(28px, 4vw, 42px);
  max-width: 76ch;
}
.takeaways h2, .takeaways h3 { font-size: clamp(1.05rem, 1.8vw, 1.3rem); margin-bottom: 14px; }
.takeaways ul { list-style: none; margin: 0; }
.takeaways li { position: relative; padding-left: 24px; margin-bottom: 10px; color: var(--ink-2); font-size: 0.96rem; }
.takeaways li::before { content: "\2192"; position: absolute; left: 0; color: var(--accent-deep); font-family: var(--mono); }
.takeaways .t-entity, .checklist .c-entity {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-top: 12px;
}

.checklist { list-style: none; margin: 0 0 24px; }
.checklist li { position: relative; padding-left: 30px; margin-bottom: 10px; }
.checklist li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.35em;
  width: 13px; height: 13px;
  border: 1px solid var(--ink-2);
}

.sources {
  border-top: 1px dashed var(--ink-3);
  margin-top: clamp(34px, 5vw, 56px);
  padding-top: 18px;
  max-width: 76ch;
}
.sources h2, .sources h3 {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-2);
  font-weight: 500;
  margin: 0 0 12px;
}
.sources ol, .sources ul { margin: 0 0 0 20px; color: var(--ink-2); font-size: 0.86rem; }
.sources li { margin-bottom: 8px; }
.sources li .src-url { font-family: var(--mono); font-size: 0.7rem; word-break: break-word; color: var(--ink-3); }

/* ---------- GEO: numeric comparison table (.data-table) ---------- */
.data-table {
  width: 100%;
  border-collapse: collapse;
  border-top: 1px solid var(--line-strong);
  margin: 0 0 clamp(24px, 3vw, 34px);
  font-size: 0.9rem;
}
.data-table caption {
  caption-side: top;
  text-align: left;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.9;
  padding: 0 0 10px;
}
.data-table th, .data-table td {
  text-align: left;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.data-table thead th {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
  font-weight: 500;
  background: var(--paper-2);
  white-space: nowrap;
}
.data-table tbody th { font-family: var(--mono); font-size: 0.72rem; font-weight: 500; color: var(--ink-2); }
.data-table tfoot td {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  background: var(--paper-2);
  line-height: 1.9;
}
/* tables scroll inside .table-wrap instead of stretching the page on 390px screens;
   no forced min-width, so a narrow table still fits without a pointless scrollbar */
.data-table caption { min-width: 0; }

/* ---------- GEO: entity line / byline ---------- */
.entity-line {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.9;
  border-top: 1px dashed var(--ink-3);
  padding-top: 10px;
  margin-top: 18px;
}
.geo-updated { color: var(--ink-3); }

/* ---------- single post: prev/next + pagination ---------- */
.post-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--line-strong);
  border-left: 1px solid var(--line-strong);
  margin-top: clamp(34px, 5vw, 54px);
}
.post-nav a {
  border-right: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line-strong);
  padding: 20px 22px;
  display: block;
}
.post-nav a:hover { background: var(--paper-2); }
.post-nav .pn-label {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: block;
  margin-bottom: 8px;
}
@media (max-width: 620px) { .post-nav { grid-template-columns: 1fr; } }

.pager {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: clamp(34px, 5vw, 54px);
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.pager .page-numbers {
  border: 1px solid var(--ink-2);
  border-radius: 999px;
  padding: 8px 15px;
  color: var(--ink);
}
.pager .page-numbers.current { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.pager a.page-numbers:hover { border-color: var(--accent); color: var(--accent-deep); }

/* ---------- search form (404 / no-results) ---------- */
.search-form { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 20px; max-width: 520px; }
.search-form input[type="search"] {
  flex: 1 1 220px;
  min-width: 0;
  border: 1px solid var(--line-strong);
  background: #fff;
  padding: 13px 16px;
  font-family: var(--sans);
  font-size: 1rem;
  color: var(--ink);
  outline: none;
}
.search-form input[type="search"]:focus { box-shadow: inset 0 0 0 1px var(--accent); }
.search-form .search-submit {
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 14px 24px;
  border-radius: 999px;
  /* 2026-09-15 修：按钮用虚线描边会被欧美买家读成"占位/线框稿"，改实线。 */
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background .2s, color .2s;
}
.search-form .search-submit:hover { background: var(--ink); color: #fff; }

/* ---------- clear the fixed float-dock (>=90px, 110px on mobile) ---------- */
.unitex-float-dock main { padding-bottom: 90px; }
@media (max-width: 620px) { .unitex-float-dock main { padding-bottom: 110px; } }

/* ---------- WordPress core classes ---------- */
.screen-reader-text {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.screen-reader-text:focus {
  position: static !important;
  width: auto; height: auto;
  clip: auto;
  clip-path: none;
  padding: 10px 18px;
  background: var(--accent);
  color: #fff;
  font-family: var(--mono);
  font-size: 0.75rem;
  z-index: 200;
}
.alignleft { float: left; margin: 0 24px 18px 0; }
.alignright { float: right; margin: 0 0 18px 24px; }
.aligncenter { display: block; margin-left: auto; margin-right: auto; }
.wp-caption { max-width: 100%; }
.wp-caption-text, .gallery-caption {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-top: 8px;
}
.wp-block-image img, .prose img { border: 1px solid var(--line-strong); }
.sticky .rule-cell { background: var(--paper-2); }
embed, iframe, object, video { max-width: 100%; }
.prose > *:first-child { margin-top: 0; }
.prose .table-wrap { margin: 24px 0 30px; }
.prose .table-wrap > table { margin: 0; }
.prose h2:first-of-type { margin-top: 0; }
/* long unbroken strings (URLs, SKUs, emails) must not push the page wide */
.prose p, .prose li, .answer p, .entity-line, .foot-contact { overflow-wrap: break-word; }

/* ---------- comments (theme had no comments.php before 2026-09-13) ---------- */
.comments-area { max-width: 76ch; }
.comments-title, .comment-reply-title {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.3rem, 2.4vw, 1.7rem);
  margin: 0 0 18px;
}
.comment-list { list-style: none; margin: 0 0 32px; padding: 0; }
.comment-list ol.children { list-style: none; margin: 0; padding-left: 22px; }
.comment-list li.comment { border-top: 1px solid var(--line); padding: 18px 0; }
.comment-list .comment-body { font-size: 0.95rem; color: var(--ink-2); }
.comment-list .comment-meta {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 8px;
}
.comment-list .comment-author img { border: 1px solid var(--line-strong); border-radius: 50%; }
.comment-notes, .comments-closed, .logged-in-as {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--ink-3);
}
.comment-form p { margin: 0 0 14px; }
.comment-form label {
  display: block;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 6px;
}
.comment-form input[type="text"],
.comment-form input[type="email"],
.comment-form input[type="url"],
.comment-form textarea {
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  font: inherit;
  color: var(--ink);
}
.comment-form .form-submit { margin-top: 18px; }
.comments-area .comment-navigation a,
.comments-area .pagination a { color: var(--accent-deep); text-decoration: underline; }

/* ---------- duplicate floating controls (unitex-floating-bar.php) ----------
   The mu-plugin renders a second floating contact stack. On desktop it sits at
   mid-right and the theme dock at bottom-right, but at 390 px it becomes a
   full-width bottom bar at z-index 9999 that overlaps the theme dock
   (measured: bar 0-390 x 800-844 vs dock 332-378 x 784-830). The theme dock
   now carries WhatsApp, e-mail and a Quick-inquiry button wired to the plugin's
   own modal, so the stack itself is hidden and only one control remains.
   Specificity (1,2,0) + !important beats the plugin's
   `#unitex-floating-bar.unitex-floating-bar` rule (1,1,0). The modal
   (#inquiry-modal) and its script are deliberately left visible. */
body #unitex-floating-bar.unitex-floating-bar { display: none !important; }

/* ---------- footer cookie-settings control (bound by zz-consent.php) ---------- */
/* zz-a11y.php forces `.site-footer a { color:#c2410c !important }` — a fix for
   Astra's footer, which is light. This footer is dark (#161412), where that
   orange lands at roughly 3:1. Re-assert the design system with a more specific
   !important rule; the accessible fix for body copy still applies through
   .entry-content. */
body .site-foot a,
body .site-foot a:visited { color: inherit !important; }
body .site-foot a:hover { color: var(--accent) !important; }
body .site-foot a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.site-foot .unitex-cookie-settings { color: inherit; }
.site-foot .unitex-cookie-settings:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- figure / gallery blocks inside article bodies ---------- */
.prose figure { margin: 26px 0; }
.prose figcaption, .prose .wp-element-caption {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-top: 8px;
}

/* ---------- product catalog: product CPT + [unitex_product_grid] ----------
   Appended 2026-09-13 (DSH). Reuses the design system's .cat-grid / .cat-cell
   catalog cells verbatim — no new colours, fonts or card styles. Only three
   things are added: (1) overflow hardening so a long SKU or category label can
   never widen a grid track, (2) the lead-in note, (3) the single-product layout. */
.unitex-product-note {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin: -10px 0 28px;
}
.unitex-product-grid { margin-top: 28px; }
/* hardening: mono .code is a flex row of two spans; keep it wrap-safe */
.cat-cell .code { flex-wrap: wrap; gap: 4px 14px; min-width: 0; }
.cat-cell .code > span { min-width: 0; overflow-wrap: anywhere; }
.cat-cell h3, .cat-cell .spec { overflow-wrap: anywhere; }

/* single product entry */
.unitex-product-detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(26px, 4vw, 56px);
  align-items: start;
}
.unitex-product-media {
  margin: 0;
  border: 1px solid var(--line-strong);
  background: var(--paper-2);
}
.unitex-product-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
.unitex-product-body { max-width: 68ch; }
.unitex-product-body > h2:first-of-type { margin-top: 0; }
@media (max-width: 860px) {
  .unitex-product-detail { grid-template-columns: minmax(0, 1fr); }
}


/* ---------- contact page (page-contact-us.php) — 新站2 contact.html ----------
   2026-09-13. The page body is a two-column split: the inquiry form on the
   left, the direct-contact block on the right. It is rendered by
   page-contact-us.php outside `.prose`, because `.prose` caps its column at
   76ch (line 496) and the two columns would collapse into a narrow stack.

   `.contact-split` / `.rule-grid` are the additional CSS classes on the
   wrapping core/group blocks, so every rule below is scoped to this page and
   to nothing else.

   Those two groups carry `"layout":{"type":"flex"}`. That is deliberate and is
   only about the wrapper: WordPress's `wp_restore_group_inner_container()`
   re-inserts a `<div class="wp-block-group__inner-container">` inside every
   core/group block in a theme without theme.json, and that extra wrapper would
   sit between the group and its columns, so the design system's
   `.split` / `.rule-grid` grids would have a single child and collapse.
   `layout.type` of `flex` (or `grid`) is excluded from that shim, so these two
   wrappers render as plain single-purpose divs and the grids below work.
   The flex layout support also adds `is-layout-flex` to these wrappers, and
   WordPress's global stylesheet sets the display with `body .is-layout-flex
   { display: flex }` — specificity (0,1,1), which outranks a plain
   `.contact-split` (0,1,0) whatever the file order. `.wp-block-group
   .contact-split` below is (0,2,0): it wins on weight alone, without depending
   on this stylesheet being loaded after the global styles. (That order is not
   guaranteed — mu-plugins/zz-inline-css-file.php can move the `global-styles`
   inline CSS into an external file enqueued after this one.) */
.wp-block-group.contact-split {
  --wp--style--block-gap: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(30px, 5vw, 72px);
  align-items: start;
}
.contact-split .kicker { margin: 0; }
.contact-split h2 {
  margin: 14px 0 26px;
  font-size: clamp(1.6rem, 3vw, 2.2rem);
}
@media (max-width: 860px) {
  .wp-block-group.contact-split { grid-template-columns: 1fr; }
}

/* the form column: `[contact-form-7 id="4037"]` renders its own
   .contact-form-wrapper / .form-row / .form-input markup, and the design system
   has no rules for any of those classes — inside a half-width column the
   controls would keep the browser's default `size="40"` width. Style them with
   the tokens the rest of the system uses; the form markup itself is untouched. */
.contact-split .wpcf7-form .form-row { margin-bottom: 16px; }
.contact-split .wpcf7-form .form-row label {
  display: block;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin-bottom: 8px;
}
.contact-split .wpcf7-form .form-input {
  width: 100%;
  max-width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
  font: inherit;
  font-size: 1rem; /* >=16px: iOS does not zoom the viewport on focus */
  color: var(--ink);
}
.contact-split .wpcf7-form textarea.form-input { min-height: 110px; resize: vertical; }
.contact-split .wpcf7-form .form-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.contact-split .wpcf7-form .form-submit input,
.contact-split .wpcf7-form input[type="submit"] {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 15px 28px;
  border-radius: 999px;
  /* 2026-09-15 修：实心按钮再套虚线边自相矛盾，改实线。 */
  border: 1px solid var(--accent-deep);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  transition: all .2s ease;
}
.contact-split .wpcf7-form .form-submit input:hover { background: var(--accent-deep); color: #fff; }
.contact-split .wpcf7-form p { margin-bottom: 14px; }
.contact-split .wpcf7-form small { color: var(--ink-2); }
.contact-split .wpcf7-response-output { margin: 14px 0 0; }

/* The verification block is a wp:html block whose markup is frozen: the four
   ids (captcha-input-x / captcha-correct-x / captcha-display-x /
   captcha-error-x) are the interface of mu-plugins/captcha-footer-js.php, and
   that script also toggles #captcha-error-x through inline `style.display`, so
   no rule below may set `display` on it. Only colours are pulled back onto the
   design tokens; the inline Astra-era greys (#F5F7FA / #E5E7EB / #1F2937) need
   !important to be overridden. */
.contact-split .math-captcha {
  background: var(--paper-2) !important;
  border-color: var(--line-strong) !important;
}
.contact-split .math-captcha #captcha-display-x { background: var(--ink) !important; }
.contact-split .math-captcha #captcha-input-x { border-color: var(--line-strong) !important; }

/* right column: the contact table + the two ruled cards */
.contact-split .table-wrap { margin: 0; }
.contact-split .wp-block-table { margin: 0; }
.contact-split .wp-block-table > table { margin: 0; width: 100%; }
.contact-split .wp-block-table figcaption { margin-top: 8px; }
.contact-split .rule-grid {
  margin-top: 34px;
  border-left: none;
  --wp--style--block-gap: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
}
/* The contact table is a core/table block, so its label column is <td><strong>
   rather than the <th scope="row"> that 新站2 writes by hand — a <th> inside
   <tbody> written into the block comment is re-serialised by the table block's
   own save() and risks a "block contains unexpected content" prompt for the
   editor. Give the first cell of each row the .spec-table th treatment instead,
   so the rendered table matches the design system without touching the block. */
.contact-split .wp-block-table.spec-table td:first-child {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-2);
  font-weight: 500;
  width: 220px;
}
@media (max-width: 620px) {
  .contact-split .wp-block-table.spec-table td:first-child { width: 130px; }
}
.contact-split .rule-grid .rule-cell { border-left: 1px solid var(--line-strong); }
.contact-split .rule-cell .idx { margin: 0 0 18px; }
@media (max-width: 720px) {
  .contact-split .rule-grid { grid-template-columns: 1fr; }
}

/* The two editorial blocks in the body carry the `.prose` class themselves
   and are authored with the `.contact-intro` / `.contact-resources` additional
   classes, so the spacing below is keyed to those class names rather than to a
   site-wide `.entry-content > .prose` selector — a bare `.prose` group added to
   some future page must not inherit a 44px gap from the contact page. */
.entry-content > .contact-intro { margin-top: 0; }
.entry-content > .contact-resources { margin-top: 44px; }
/* the closing confidentiality note is a bare paragraph, not a `.prose` group,
   so it needs the reading-measure paragraph spacing that `.prose p` used to
   give it when the body was rendered inside `.wrap.prose`. */
.entry-content > .unitex-confidential-note { margin-top: 18px; color: var(--ink-2); }

/* ---------- contact page: the app-line build's Direct Channels band ----------
   2026-09-13. The app-line build (app/public/contact.html) opens the body with
   `<section class="section tint">` holding a `.sec-head` and a `.rule-grid` of
   four `.rule-cell` cards (CH-01…CH-04), and only then the inquiry split. This
   page renders the same markup as blocks; because the body is no longer
   pre-wrapped, the band is a genuine full-width block and needs no bleed hacks.

   Two things the nesting changes, both fixed below:
     · `main > section:nth-of-type(even)` paints this page's content section
       cream (#FBF7EA + cloud). A #F6F0DF band inside it would be invisible, so
       the contact body is reset to the page ground colour — which is what the
       app build has, the band sitting directly on the page.
     · The band's own `.section` padding would stack with the enclosing
       section's, so it is trimmed to a band-sized rhythm. */
body.page-id-2767 main > section.contact-body { background-color: var(--paper); background-image: none; }
body.page-id-2767 .entry-content > .section.tint {
  padding-top: clamp(30px, 4vw, 52px);
  padding-bottom: clamp(30px, 4vw, 52px);
}
.contact-channels .sec-head { margin-bottom: clamp(26px, 3.6vw, 44px); }
.contact-channels .table-wrap { margin-top: clamp(30px, 4.5vw, 52px); }
/* the inquiry split follows the band; in the app build the two are sibling
   <section> elements and get that separation from the section rhythm. */
.contact-split { margin-top: clamp(36px, 5.5vw, 72px); }
/* the "two things worth knowing" cards are a single-column rule grid */
.contact-split .rule-grid.contact-tips { grid-template-columns: 1fr; }


/* ---------- product catalog: product CPT + [unitex_product_grid] ----------
   Appended 2026-09-13 (DSH). Reuses the design system's .cat-grid / .cat-cell
   catalog cells verbatim — no new colours, fonts or card styles. Only three
   things are added: (1) overflow hardening so a long SKU or category label can
   never widen a grid track, (2) the lead-in note, (3) the single-product layout. */
.unitex-product-note {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin: -10px 0 28px;
}
.unitex-product-grid { margin-top: 28px; }
/* hardening: mono .code is a flex row of two spans; keep it wrap-safe */
.cat-cell .code { flex-wrap: wrap; gap: 4px 14px; min-width: 0; }
.cat-cell .code > span { min-width: 0; overflow-wrap: anywhere; }
.cat-cell h3, .cat-cell .spec { overflow-wrap: anywhere; }

/* single product entry */
.unitex-product-detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(26px, 4vw, 56px);
  align-items: start;
}
.unitex-product-media {
  margin: 0;
  border: 1px solid var(--line-strong);
  background: var(--paper-2);
}
.unitex-product-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
.unitex-product-body { max-width: 68ch; }
.unitex-product-body > h2:first-of-type { margin-top: 0; }
@media (max-width: 860px) {
  .unitex-product-detail { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================
   /en/oem-products/ hub — restored from 新站2 site-static/products.html
   (appended 2026-09-13, second pass). The card grid itself reuses the
   design system's .cat-grid / .cat-cell verbatim; only the "what every
   order includes" band and the core/table block's .spec-table treatment
   are new here.
   ============================================================ */
.unitex-hub-grid { margin-top: 0; }

/* ---------- "what every Unitex order includes" band ---------- */
.entry-content > .unitex-order-band {
  background: var(--paper-2);
  border: 1px solid var(--line-strong);
  padding: clamp(26px, 3.5vw, 46px);
  margin: clamp(36px, 5vw, 62px) 0;
}
.entry-content > .unitex-order-band > .wp-block-heading:first-child { margin-top: 0; }
.entry-content > .unitex-order-band > :last-child { margin-bottom: 0; }
.unitex-order-cta { margin: clamp(26px, 3.5vw, 40px) 0 0; }

/* ---------- core/table block carrying .spec-table ----------
   The theme already does exactly this for its contact page (`contact-split`,
   see style.css ~1686): a `<th>` inside <tbody> would be re-serialised by the
   table block's own save() and can raise "block contains unexpected content",
   so the label column is a <td> that is given the .spec-table th treatment. */
.entry-content .wp-block-table.spec-table { margin: 0; }
.entry-content .wp-block-table.spec-table table {
  width: 100%;
  border-collapse: collapse;
  margin: 0;
  border-top: 1px solid var(--line-strong);
  font-size: 0.92rem;
}
.entry-content .wp-block-table.spec-table td {
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 15px 18px;
  text-align: left;
  vertical-align: top;
  color: var(--ink);
}
.entry-content .wp-block-table.spec-table td:first-child {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-2);
  font-weight: 500;
  width: 220px;
  white-space: nowrap;
}
.entry-content .wp-block-table.spec-table td .mono { font-size: 0.8rem; color: var(--ink-2); }
@media (max-width: 620px) {
  .entry-content .wp-block-table.spec-table td { padding: 12px 10px; }
  .entry-content .wp-block-table.spec-table td:first-child { width: 130px; white-space: normal; }
}

/* ============================================================
   /en/our-process-quality-control/ (2766) — K3「Capabilities」页复刻
   Appended 2026-09-13 (DSH). 参照（一手 artifact，不是对它的描述）:
     迁移资料/Kimi_Agent_B2B内裤站建设/_对齐_20260913/…/app/oem-odm-process.html
     …/app/assets/css/style.css
   用 app 线：其文案是已整改版（sourcing partner）；app-static 线页脚/描述仍是
   "manufacturer" 旧文本。app/ 与 app-static/ 的 assets/css/style.css 逐字节相同。

   逐 class 比对结果（参照 <main> 共 36 个 class → grep 本文件）:
     33 个：规则体完全一致，或已被本主题完整覆盖（另有扩展）
      3 个：缺失 —— .plus-flex / .plus-copy / .step p(字号行高)
   下面第 1 段按参照原文补这 3 条；第 2 段解决结构差异：
   参照页的 .section 是整幅色带，而 page.php 把 the_content() 放进
   <div class="wrap prose entry-content">（.prose 有 max-width:76ch）。
   全部 scope 到 body.page-id-2766，不影响任何其它页面。
   ============================================================ */

/* ---------- 1) 参照有、本主题缺的规则（逐字照抄参照 CSS 第 1193–1199 行） ---------- */
.plus-flex { display: flex; gap: 32px; align-items: flex-start; margin-top: 20px; }
.plus-flex figure { flex: 0 0 300px; }
.plus-flex img { width: 100%; aspect-ratio: 3/4; object-fit: cover; display: block; border: 1px solid var(--line); background: #f4f2ec; }
.plus-flex figcaption { font-size: 12px; color: var(--ink-3); padding-top: 7px; font-family: var(--mono); }
.plus-copy { flex: 1; min-width: 0; }
.plus-copy p { font-size: 1.02rem; line-height: 1.6; color: var(--ink-2); margin: 0 0 16px; }
@media (max-width: 720px) { .plus-flex { flex-direction: column; } .plus-flex figure { flex: 1 1 auto; max-width: 360px; } }

/* ---------- 2) 2766：让复刻区块跳出 .prose 阅读栏 ----------
   子元素用 100vw + 左右负边距即可跳出父级 max-width，父级一行都不用改。
   负边距按父级内容盒算：calc(50% - 50vw)，父级 .wrap 是 margin:auto 居中的，故左右对称。 */
body.page-id-2766 .utx-k3 > .section {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}
/* 参照页用 `main > section:nth-of-type(even):not(.ink):not(.cta-band):not(.page-hero)`
   做浅色交替；我们的 section 不在 main 下，位置选择器失效，故按同一条设计系统
   规则显式给底色（参照 1440px 实测：#FBF7EA / #F6F0DF / ink 深色）。 */
body.page-id-2766 .utx-k3 > .section:not(.tint):not(.ink) {
  background-color: #FBF7EA;
  background-image: var(--pat-cloud);
}
body.page-id-2766 .utx-k3 > .section.tint {
  background-color: #F6F0DF;
  background-image: var(--pat-cloud-strong);
}
body.page-id-2766 .utx-k3 > .section.ink { background-image: var(--pat-cloud-dark); }

/* .step p 本主题是 0.8rem/1.55，参照是 0.92rem/1.6 —— 只在 2766 采用参照值 */
body.page-id-2766 .utx-k3 .step p { font-size: 0.92rem; color: var(--ink-2); line-height: 1.6; }

/* 参照页的 .spec-table 不在 .prose 里；我们这里在，必须抵消 .prose table/th/td 的串味。
   选择器特异性 (0,3,1) > .prose th (0,1,1)，与书写顺序无关。 */
body.page-id-2766 .utx-k3 .spec-table { margin: 0; }
body.page-id-2766 .utx-k3 .spec-table th,
body.page-id-2766 .utx-k3 .spec-table td {
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 15px 18px;
}
body.page-id-2766 .utx-k3 .spec-table tr:first-child th {
  background: transparent;
  letter-spacing: 0.16em;
}
body.page-id-2766 .utx-k3 .plus-flex img { border: 1px solid var(--line); }
@media (max-width: 620px) {
  body.page-id-2766 .utx-k3 .spec-table th { width: 130px; white-space: normal; }
  body.page-id-2766 .utx-k3 .spec-table th,
  body.page-id-2766 .utx-k3 .spec-table td { padding: 12px 10px; }
}

/* ---------- 3) 2766 K3 复刻：还原设计系统基础排版（第 2 次追加, 2026-09-13） ----------
   原因：参照页的 <main> 不在 .prose 里；page.php 把 the_content() 放进
   <div class="wrap prose entry-content">，于是 .prose 的 h2/h3/p/li/figcaption
   规则串进了复刻区块。下面每一条的值都不是猜的 —— 是用 k3_style_diff.py 对
   「参照 file:// 页」与「生产页」逐元素 getComputedStyle 对照量出来的
   （量到的差异：sec-head h2 48px/16px/0 vs 32px/0/18px、cta-band h2 48px/0/0
   vs 32px/0/18px、step h3 0/8px vs 32px/12px、step p 0 vs 18px、
   kicker/cap/side 0 vs 18px、plus-copy li 0 vs 8px、
   plus-flex figcaption 0/normal/none vs 8px/1.2px/uppercase、plus-copy ul 少 22px）。
   每条都带 .utx-k3 前缀，(0,3,2) 特异性高于 .prose X (0,1,1)，
   且只覆盖量到差异的属性，不动 .plus-copy p / .split h2 等参照本来就有值的组件规则。 */

body.page-id-2766 .utx-k3 .sec-head h2,
body.page-id-2766 .utx-k3 .cta-band h2 { font-size: clamp(1.9rem, 3.6vw, 3rem); }
body.page-id-2766 .utx-k3 .sec-head h2 { margin-top: 16px; margin-bottom: 0; }
body.page-id-2766 .utx-k3 .cta-band h2 { margin-top: 0; margin-bottom: 0; }

body.page-id-2766 .utx-k3 .step h3 { margin-top: 0; margin-bottom: 8px; }
body.page-id-2766 .utx-k3 .step p { margin-top: 0; margin-bottom: 0; }

body.page-id-2766 .utx-k3 .kicker,
body.page-id-2766 .utx-k3 .media .cap,
body.page-id-2766 .utx-k3 .sec-head .side { margin-bottom: 0; }

body.page-id-2766 .utx-k3 .plus-copy li { margin-bottom: 0; color: inherit; }
body.page-id-2766 .utx-k3 .plus-copy ul { margin: 0; }

body.page-id-2766 .utx-k3 .plus-flex figcaption {
  margin-top: 0;
  letter-spacing: normal;
  text-transform: none;
}

/* ---------- 3b) 2766 K3 复刻：.plus-copy 列表颜色（第 3 次追加, 2026-09-13） ----------
   量到 .plus-copy li 的颜色仍是 rgb(87,82,75)（--ink-2），而参照是 rgb(22,20,18)（--ink）。
   根因：颜色并不在 .prose li 上，而在 `.prose ul, .prose ol { color: var(--ink-2) }`
   —— li 是从 ul 继承来的，所以必须把 color 设在 ul 上（设在 li 上无效）。 */
body.page-id-2766 .utx-k3 .plus-copy ul { color: inherit; }

/* ---------- 3c) 2766 K3 复刻：表格包装层与按钮段落（第 4 次追加, 2026-09-13） ----------
   量到两处残余差异（ref vs prod 逐子元素 getComputedStyle）：
   1) 参考页里 <table class="spec-table"> 是直接子元素；生产页被 WordPress 包了一层
      <div class="table-wrap">，而 `.prose .table-wrap { margin: 24px 0 30px }` 会带来
      24/30px 外边距（section[3] 实测高出 26px）。
   2) 规格表后的按钮段落 <p style="margin-top:26px"> 在参照里 margin-bottom=0，
      生产页被 `.prose p { margin-bottom: 18px }` 加了 18px。
   两条都只作用在 .utx-k3 内，且不碰 .plus-copy p（参照本来就 16px）与 .split .prose p。 */
body.page-id-2766 .utx-k3 .table-wrap { margin: 0; }
body.page-id-2766 .utx-k3 .split > div > p,
body.page-id-2766 .utx-k3 .cta-band p { margin-bottom: 0; }

/* ---------- 3d) 2766 K3 复刻：整幅色带的横向兜底（第 5 次追加, 2026-09-13） ----------
   复刻块用 `width: 100vw` 跳出 .prose 阅读栏。100vw 在**有经典（非 overlay）滚动条**
   的浏览器里 = clientWidth + 滚动条宽度，因此比 body 内容盒宽出约 15px，
   在 Windows/Linux Chrome、Firefox 上会出现横向滚动条。
   ⚠️ 本机 headless Chromium 不带经典滚动条（clientWidth == innerWidth），
      所以三视口实测 overflow=0 **覆盖不到这个场景** —— 这条是按标准行为补的兜底，
      不是在无头环境里"测出来"的。
   `overflow-x: clip`（不是 hidden）不创建滚动容器，因此不会破坏页面内的
   position: sticky / fixed 元素；它在 body 宽度处裁掉最多一条滚动条的背景宽度，
   视觉上不可见。旧 Safari(<16) 不支持 clip，会退回到"出现横向滚动条"，
   即与不加这条时的行为一致，不会更差。 */
body.page-id-2766 { overflow-x: clip; }


/* ============================================================
   APPEND 2026-09-14 (DSH) —— 从预发合并「新站2 产品呈现体系」那一整块。
   背景：生产与预发的 style.css **双向漂移**（生产多 2 块共 109 行、预发多这 1 块 162 行，
   且没有 replace 块）。按 README「CSS 只追加」的纪律，**不覆盖、不重排**，
   只把预发独有的这块追加到末尾，生产原有的块原位保留。
   逐块证据：见 /root/backups/prod-385-*/css-merge-report.txt
   ============================================================
}



/* ============================================================
   UNITEX — product presentation: 新站2 (K3 app) production-sample gallery
   + product detail page.  DSH 2026-09-13.  APPEND-ONLY.

   Provenance of every rule below:
   · `.prod-gallery` / `.prod-card` / `.prod-thumbs` / `.prod-thumbs img` /
     `.prod-card figcaption` are copied VERBATIM from the reference
     design system `app-static/assets/css/style.css`
     (block `/* ---------- production sample gallery ---------- */`, lines 1006-1026).
   · `.prod-thumbs.cols-1/2/3` are copied verbatim from the same file (lines 1038-1040).
   · `cols-4` is USED by the reference HTML but DEFINED NOWHERE in the reference CSS
     (verified: `grep -c 'cols-4' style.css` = 0), so it silently falls back to the
     `.prod-thumbs` default of 4 columns. It is written out explicitly here, together
     with cols-5/6, so a 5- or 6-image product does not silently inherit 4 columns.
   · The reference has NO clickable product card (its cards are inert), so the
     whole-card link uses the design system's own precedent for a clickable ruled
     cell: `a.rule-cell:hover { background: var(--paper-2) }` (reference line 358).
     Nothing new is invented — no new colours, fonts, radii or shadows.
   ============================================================ */

/* ---------- production sample gallery (verbatim from 新站2) ---------- */
.prod-gallery {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
}
.prod-card {
  background: #fff; margin: 0; padding: 14px 14px 12px;
  display: flex; flex-direction: column; gap: 10px;
}
.prod-thumbs {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px;
}
.prod-thumbs img {
  width: 100%; aspect-ratio: 1; object-fit: cover; display: block;
  background: #f4f2ec; border: 1px solid var(--line);
}
.prod-card figcaption {
  font-size: 12.5px; line-height: 1.35; color: var(--ink-2);
  font-weight: 500; letter-spacing: .01em;
}

.prod-thumbs.cols-1 { grid-template-columns: 1fr; }
.prod-thumbs.cols-2 { grid-template-columns: repeat(2, 1fr); }
.prod-thumbs.cols-3 { grid-template-columns: repeat(3, 1fr); }
.prod-thumbs.cols-4 { grid-template-columns: repeat(4, 1fr); }
.prod-thumbs.cols-5 { grid-template-columns: repeat(5, 1fr); }
.prod-thumbs.cols-6 { grid-template-columns: repeat(6, 1fr); }

/* ---------- whole-card link (precedent: a.rule-cell:hover) ----------
   `.prod-gallery` draws its hairlines with `gap:1px; background:var(--line)`.
   The reference never puts anything but a `<figure class="prod-card">` in a
   grid cell, so the cell's own background is never visible. Wrapping the card
   in an `<a>` makes the ANCHOR the grid cell; if the anchor had no background
   the 1px gaps would still read as hairlines but any sub-pixel gap between the
   anchor box and the figure (line-height, flex margins) would flash the
   `var(--line)` colour as a dark band. So the anchor is given the same #fff as
   the card. This changes no reference value — it only stops a new element from
   exposing the grid's background. */
.prod-gallery > a.prod-card-link {
  display: block; color: inherit; min-width: 0; background: #fff;
  transition: background .25s;
}
.prod-gallery > a.prod-card-link > .prod-card { height: 100%; }
a.prod-card-link:hover { background: var(--paper-2); }
a.prod-card-link:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: -2px; }
.prod-gallery.is-compact { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

/* The reference defines NO responsive rule for `.prod-thumbs` at all (its only
   .prod-* rules are lines 1007-1040). On a 390px viewport `.prod-gallery`
   collapses to one ~300px column while 4 thumbnails stay 4-across, i.e. ~65px
   squares. These two rules only ever apply below the reference's own narrowest
   layout, so they cannot change any desktop rendering. */
@media (max-width: 620px) {
  .prod-gallery { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
  .prod-gallery.is-compact { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
  .prod-thumbs.cols-4, .prod-thumbs.cols-5, .prod-thumbs.cols-6 { grid-template-columns: repeat(3, 1fr); }
}

/* ============================================================
   Product detail page (`product` CPT, single-product.php)
   Built only from the design system's own primitives: `.page-hero.banner`,
   `.section`, `.section.tint`, `.wrap`, `.split`, `.kicker`, `.sec-head`,
   `.spec-table`, `.rule-grid` / `.rule-cell`, `.prod-gallery`, `.note`.
   Only the CSS-only image galley below is new.
   ============================================================ */

/* ---------- CSS-only product image gallery ----------
   No JavaScript, no library. A radio group holds the state; `:checked` shows
   the matching stage image and marks the matching thumbnail. Keyboard users
   reach the radios with Tab and switch with the arrow keys, which is the
   native behaviour of a radio group. Rule count is bounded by MAX_IMAGES (8)
   in single-product.php, and the radios are rendered in the same order as the
   stage images, which is what makes the `nth-of-type` pairing correct. */
.pd-gallery { margin: 0; }
.pd-gallery > input { position: absolute; opacity: 0; pointer-events: none; width: 1px; height: 1px; }
.pd-stage { border: 1px solid var(--line-strong); background: #f4f2ec; overflow: hidden; }
.pd-stage img {
  display: none; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover;
}
.pd-gallery > input:nth-of-type(1):checked ~ .pd-stage > img:nth-child(1),
.pd-gallery > input:nth-of-type(2):checked ~ .pd-stage > img:nth-child(2),
.pd-gallery > input:nth-of-type(3):checked ~ .pd-stage > img:nth-child(3),
.pd-gallery > input:nth-of-type(4):checked ~ .pd-stage > img:nth-child(4),
.pd-gallery > input:nth-of-type(5):checked ~ .pd-stage > img:nth-child(5),
.pd-gallery > input:nth-of-type(6):checked ~ .pd-stage > img:nth-child(6),
.pd-gallery > input:nth-of-type(7):checked ~ .pd-stage > img:nth-child(7),
.pd-gallery > input:nth-of-type(8):checked ~ .pd-stage > img:nth-child(8) { display: block; }

.pd-thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); gap: 8px; margin-top: 10px; }
.pd-thumbs > label { display: block; cursor: pointer; margin: 0; }
.pd-thumbs > label > img {
  width: 100%; aspect-ratio: 1; object-fit: cover; display: block;
  background: #f4f2ec; border: 1px solid var(--line); transition: border-color .2s;
}
.pd-thumbs > label:hover > img { border-color: var(--ink-2); }
.pd-gallery > input:nth-of-type(1):checked ~ .pd-thumbs > label:nth-child(1) > img,
.pd-gallery > input:nth-of-type(2):checked ~ .pd-thumbs > label:nth-child(2) > img,
.pd-gallery > input:nth-of-type(3):checked ~ .pd-thumbs > label:nth-child(3) > img,
.pd-gallery > input:nth-of-type(4):checked ~ .pd-thumbs > label:nth-child(4) > img,
.pd-gallery > input:nth-of-type(5):checked ~ .pd-thumbs > label:nth-child(5) > img,
.pd-gallery > input:nth-of-type(6):checked ~ .pd-thumbs > label:nth-child(6) > img,
.pd-gallery > input:nth-of-type(7):checked ~ .pd-thumbs > label:nth-child(7) > img,
.pd-gallery > input:nth-of-type(8):checked ~ .pd-thumbs > label:nth-child(8) > img { border-color: var(--line-strong); border-width: 2px; }
.pd-gallery > input:focus-visible:nth-of-type(1) ~ .pd-thumbs > label:nth-child(1) > img,
.pd-gallery > input:focus-visible:nth-of-type(2) ~ .pd-thumbs > label:nth-child(2) > img,
.pd-gallery > input:focus-visible:nth-of-type(3) ~ .pd-thumbs > label:nth-child(3) > img,
.pd-gallery > input:focus-visible:nth-of-type(4) ~ .pd-thumbs > label:nth-child(4) > img,
.pd-gallery > input:focus-visible:nth-of-type(5) ~ .pd-thumbs > label:nth-child(5) > img,
.pd-gallery > input:focus-visible:nth-of-type(6) ~ .pd-thumbs > label:nth-child(6) > img,
.pd-gallery > input:focus-visible:nth-of-type(7) ~ .pd-thumbs > label:nth-child(7) > img,
.pd-gallery > input:focus-visible:nth-of-type(8) ~ .pd-thumbs > label:nth-child(8) > img { outline: 2px solid var(--accent-deep); outline-offset: 2px; }

/* single-image product: no radio group, no thumb strip */
.pd-single { border: 1px solid var(--line-strong); background: #f4f2ec; }
.pd-single img { width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; }

/* ---------- detail-page furniture ---------- */
.pd-lede-facts { margin-top: 18px; }
.pd-section-flush { padding-top: 0; }
.pd-ref {
  font-family: var(--mono); font-size: 0.68rem; line-height: 1.7; letter-spacing: 0.03em;
  color: var(--ink-3); border-top: 1px dashed var(--ink-3); padding-top: 12px; margin-top: 26px;
  overflow-wrap: anywhere;
}
.pd-ref strong { color: var(--ink-2); font-weight: 500; }
.pd-body { max-width: 72ch; }
.pd-body > h2:first-child, .pd-body > h3:first-child { margin-top: 0; }
.pd-body p, .pd-body li { color: var(--ink); }
.pd-body ul { margin: 0 0 18px 20px; }
.pd-body li { margin-bottom: 7px; }
.pd-cta-row { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 30px; }
.pd-hint {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-3); margin-top: 10px;
}

@media (max-width: 860px) {
  .pd-stage img, .pd-single img { aspect-ratio: 3 / 2; }
