/* hilaldecor - palette B, Royal Midnight.
 * All direction-dependent properties use CSS logical properties
 * (margin-inline / inset-block / border-block), so adding dir="rtl" mirrors the
 * layout with no rewrite. */
/* ── 品牌衬线字体（2026-10-21 引进，先只在 About 页试用）───────────────
   为什么自托管：站内 `_headers` 给 /*.woff2 设了 immutable 长缓存，
   引 Google Fonts CDN 会多一个第三方域名（也违背 CSP img/font 白名单思路）。
   文件名带 v1 —— 换字体就换文件名，避免 immutable 缓存钉死旧字体。
   unicode-range 只覆盖拉丁：中文/阿拉伯文继续走系统字体，不会拉到空字形。 */
@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-latin-v1.woff2") format("woff2");
  font-weight: 400 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* 显示字体（标题用）。2026-10-21 老板定稿：Fraunces（对比 Playfair 后选它）。
     ⛔ 换字只改这一处；正文( --font-body )仍走系统无衬线，长文可读性优先。 */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --navy: #0B1B3A;
  --navy-2: #122A55;
  --gold: #D4AF37;
  --gold-lt: #E8D28A;
  --gold-hero: #F5E6B8;  /* 首页 hero 标题里的金色 **专用**（2026-10-08）：
                          * 遮罩调浅到 0.58 后，--gold-lt #E8D28A 在白字旁边
                          * 亮度掉一档、对比只有约 3:1（不达 AA）。
                          * 这是**深色底上的文字色**（H 45° 保持品牌金调、明度提到近白），
                          * 只给 `.hero h1 em` 用；其他深色区仍用 --gold-lt（那里底更深，够用）。 */
  --gold-dk: #8A6E15;
  --body: #3A4356;
  --paper: #FFFFFF;
  --paper-2: #F6F7FA;
  --line: #DDE1E9;

  /* ── 语义色（2026-09-24 令牌化）────────────────────────────────
   * 这些值此前在样式里**硬编码 60+ 处**，改一次主题要全文替换。
   * 现在只在这里定义一次，其余地方一律 var()。
   * 命名规则：on-dark-* = 深色底上的文字；ink-* = 浅色底上的文字层级。 */
  --on-dark-1: #C9D3E4;   /* 深色底 · 正文 */
  --on-dark-2: #9FB0C9;   /* 深色底 · 次要文字 */
  --on-dark-3: #BFCBE0;   /* 深色底 · 描述文字 */
  --ink-2: #5A6376;       /* 浅色底 · 次要正文 */
  --ink-3: #666F80;       /* 浅色底 · 提示/弱化文字（原 #7A8398 对比度仅 3.80:1，WCAG AA 要求 4.5:1 → 调深到 5.06:1；用于面包屑/SKU/卡片副标题等 8 处小字） */
  --on-gold: #1A1405;     /* 金色底 · 文字（CTA 按钮） */
  --danger: #C0392B;      /* 错误态 */

  /* ── 产品卡标签（2026-09-25）───────────────────────────────
   * S2 要求颜色一律走令牌。对比度实测 6.95:1（WCAG AA 需 4.5:1）。 */
  --gold-tint: #FFF9E6;   /* 标签底 */
  --gold-line: #E3CE86;   /* 标签描边 */
  --gold-ink: #6B5310;    /* 标签文字 */

  /* ── 圆角（2026-09-25 收敛）───────────────────────────────────────
   * 此前混用 10 个值：2 / 6 / 8 / 10 / 12 / 14 / 16 / 20 / 100px / 50%。
   * 同一类元素（都是卡片）在不同页面圆角不同 —— 这是"各页各做"的直接来源。
   * 现在只有 4 个令牌；S11 闸门盯着，写别的值会报错。
   * 唯一例外：气泡尾巴（12px 12px 12px 4px），是形状不是漂移。 */
  --r-sm: 8px;        /* 小件：标签 / 按钮 / 输入框 / 缩略图 / 小面板 */
  --r-md: 12px;       /* 卡片 / 面板 / 图片块 / 深色带 */
  --r-pill: 100px;    /* 胶囊：副标题标签 / 圆形角标 / 浮动条按钮 */

  /* ── 垂直节奏（2026-09-25 统一）──────────────────────────────────
   * 此前散在 28/30/34/36/40/44/48/64/72/96/104 十一个值上，
   * 同一层级的留白在不同页面不一样 —— 这是"页面看着松紧不一"的主因。
   * ⛔ hero 卡片（.ab-hero）**不跟着放大** —— 老板 09-25 明确说过
   *    "hero 太大"，它的内距有自己的档位。 */
  --sp-section: 96px;  /* 板块之间（.ab-sec / .pd 底） */
  --sp-block: 56px;    /* 板块内的子块（.grp / 正文段） */
  --sp-body: 48px;     /* 正文区顶部（.pd） */
  --sp-gap: 40px;      /* 标题与内容之间 */
  --sp-tight: 24px;    /* 次级间隔 / 深色带头部内距 */

  /* 产品卡固定行高（见下方 .pcard-name / -pack 的说明）
     ⛔ 2026-09-25 删掉 --pcard-tag-row：标签行已从卡片上移除（只产品页显示标签），
        固定行高随之下线 —— 留着就是"声明了没人用"的死令牌。 */
}

* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  color: var(--body); background: var(--paper); line-height: 1.65;
  /* 2026-10-15 老板「全站字太小，现代浏览风格就是图多字大」⇒ 基准 16 → 17px。
     这是**继承型**文字的底噪（导航 .94rem 卡片标题等显式字号不受影响），
     组件字号由 :root 的 --ab-fs-* 统一放大。 */
  font-size: 1.06rem;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
h1, h2, h3, h4 { color: var(--navy); font-weight: 700; }
h1 { font-size: 2.2rem; line-height: 1.22; }
/* 2026-09-24 按老板要求放宽到 1660（参照 islamicwallartstore 的 .page-width）。
   ⚠️ 本文件里 .wrap 定义了两次（见下方「共享组件」段），改宽度要两处一起改。 */
.wrap { max-inline-size: 1660px; margin-inline: auto; padding-inline: 24px; }

/* header */
.hd { position: sticky; inset-block-start: 0; z-index: 50; background: var(--navy); border-block-end: 2px solid var(--gold); }
.hd nav { display: flex; gap: 28px; font-size: .94rem; align-items: center; }
.hd nav a { color: var(--on-dark-1); padding-block: 6px; border-block-end: 2px solid transparent; transition: .18s; }
.hd nav a:hover { color: var(--paper); border-block-end-color: var(--gold); }

/* ── Products 下拉（2026-10-21 老板：「Products 加下拉，直接列出 9 个分类」）──
   为什么之前没有：点 Products 直达 /products/（按标签筛选的浏览页），9 个分类页
   只有页脚有入口 → 买家想看"灯笼"得先进目录页再点左栏。
   实现只用 CSS（hover + focus-within），不引 JS：
     · ≥901px 悬停/聚焦展开；
     · 641–900px 不展开（触屏没有 hover），点 Products 进目录页走左栏；
     · ≤640px 抽屉里平铺展开（见该断点的覆盖规则）。
   ⚠️ 不要给这里加 transition/animation 之外的花活，页头全站 528 页共用。 */
.nav-drop { position: relative; display: flex; align-items: center; }
/* ⛔ 2026-10-21 修「Products 比别的导航项高一截」：
   包了一层 div 之后，里面的 <a> 仍是 **inline** 级，行盒会多出一截 leading；
   而同级其他 <a> 是 flex item（被块化）—— 两者盒高算法不同，肉眼就是一高一低。
   `.nav-drop` 自己也做 flex，里面的 <a> 一样被块化，高度就跟兄弟项完全一致。 */
.nav-drop-m {
  /* ⛔ 2026-10-21 修「鼠标移到 Products，来不及选就消失」——
     原写法 `inset-block-start: calc(100% + 10px)` 在触发项和面板之间留出 10px **空隙**，
     指针穿过空隙时 `.nav-drop:hover` 立刻失效 → 面板关闭，根本够不到里面的菜单项。
     现在面板顶端贴住触发项（`100%`），视觉上的 16px 间距改由**面板自己的上内距**提供 ——
     内距属于面板，指针停在那里仍然算 hover，不会掉出。
     ⛔ 以后任何 hover 展开的浮层，都不许用「位移」制造间距，只能用自己的 padding。 */
  position: absolute; inset-block-start: 100%; inset-inline-start: -16px;
  min-inline-size: 236px; padding: 16px 8px 8px; display: none; z-index: 60;
  background: var(--navy-2); border: 1px solid rgba(255, 255, 255, .16);
  border-radius: var(--r-md); box-shadow: 0 20px 44px rgba(0, 0, 0, .38);
}
.nav-drop:hover .nav-drop-m, .nav-drop:focus-within .nav-drop-m { display: block; }
.nav-drop-m a {
  display: block; padding: 9px 12px; border: 0; border-radius: var(--r-sm);
  font-size: .92rem; color: var(--on-dark-1);
}
.nav-drop-m a:hover { background: rgba(255, 255, 255, .08); color: var(--paper); border: 0; }
/* 策展位（HOT / NEW）+ All collections 自成一组，与 7 个真实品类之间一道细分隔。
   ⛔ 不要用 `.nd-cur:first-of-type` —— 面板里第一个 <a> 是品类链接，
      那个选择器永远匹配不到，分隔线会整条消失（2026-10-21 实测踩到）。 */
.nav-drop-m .nd-cur-wrap {
  margin-block-start: 6px; padding-block-start: 6px;
  border-block-start: 1px solid rgba(255, 255, 255, .14);
}
.nav-drop-m .nd-all { color: var(--gold-lt); }

/* Mobile menu.
 * The nav used to be hidden below the breakpoint, which left phones with no
 * navigation at all. It now collapses into a toggle plus dropdown panel driven
 * by assets/site.js. */
/* Toggle button for the mobile nav panel.
 * 外观定义集中在基础层，媒体查询里只切换 display —— 与首页写法一致。
 * （此前外观写在 640 断点里，同一组件的定义散落两处，改的时候容易漏。） */
.nav-toggle {
  display: none;
  align-items: center; justify-content: center;
  inline-size: 44px; block-size: 44px; flex: none;
  background: transparent; border: 1px solid rgba(255, 255, 255, .30); border-radius: var(--r-sm);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.nav-bars, .nav-bars::before, .nav-bars::after {
  display: block; inline-size: 20px; block-size: 2px; border-radius: var(--r-pill);
  background: var(--paper); transition: transform .18s ease, background .18s ease;
}
.nav-bars { position: relative; }
.nav-bars::before, .nav-bars::after { content: ""; position: absolute; inset-inline-start: 0; }
.nav-bars::before { inset-block-start: -6px; }
.nav-bars::after  { inset-block-start: 6px; }
/* toggle bars become an X when open */
.nav-open .nav-bars { background: transparent; }
.nav-open .nav-bars::before { transform: translateY(6px) rotate(45deg); }
.nav-open .nav-bars::after  { transform: translateY(-6px) rotate(-45deg); }

/* CTA inside the panel, small screens only.
 * The header button and the toggle cannot share one row at 390px - the toggle
 * gets pushed past the right edge - so the CTA moves into the panel. */
.nav-cta { display: none; }

/* breadcrumbs */
/* 面包屑条 —— 全站唯一位置：紧跟页头、hero 之前。
   老板 2026-09-25 指出「面包屑和 hero 合并后，和页头是不是也糊成一块了」：
   页头与 hero 卡片（.ab-hero）同为 var(--navy) 系，中间只隔 2px 金线。
   这条浅底细条本身就成了**页头（深）与 hero（深）之间的分隔层**，问题消解。 */
.crumbs { background: var(--paper); border-block-end: 1px solid var(--line); }
.crumbs-in {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  max-inline-size: 1660px; margin-inline: auto; padding: 11px 24px;
  font-size: .8rem; color: var(--ink-3);
}
.crumbs a { color: var(--gold-dk); }
.crumbs span { color: var(--body); }
.crumbs i { display: block; inline-size: 14px; block-size: 1px; background: currentColor; opacity: .5; }

/* product page */
.pd { padding-block: var(--sp-body) var(--sp-section); }

/* 分类页正文区间距（2026-09-25 二次修正）
   ⛔ 原先分类页是**三段**：`.cat-hero` 段 → `.subnav` 段 → `.wrap.pd.cat-body` 段，
      每段落白各算各的，`hero → 产品` 与 `subnav → 产品` 都退化成 0 ——
      这就是老板看到的「部分列表页依然和产品行紧贴着」。
      现在整页是**单个 `.wrap.pd` 段**，段内间距由下面这几条统一控制，
      不再需要 `.cat-body` 这类"补丁式"类。 */
/* 列宽必须与主图宽度一致（2026-09-25）：
   旧版媒体列 1.15fr 约 800px 而主图封顶 520px -> 图右侧多出约 280px 空白，
   加上 gap 看起来就是「图和说明之间空一大块」。现在列宽 = 主图宽。 */
.pd-grid { display: grid; grid-template-columns: minmax(0, 620px) minmax(0, 1fr);
  gap: 44px; align-items: start; }
.pd-info { max-inline-size: 760px; }
/* ── 产品媒体区（2026-09-25 照成熟方案重做）────────────────────────────
   老板反馈：「缩略图太大，描述文字被挤到缩略图下面去了」。
   旧版是 2×2 等大图（第一张跨两列）→ 整块高度约 1.4 屏。
   成熟方案（参照站 islamicwallartstore / Shopify Impulse 实测）：
     `.product__thumbs--beside{flex:0 0 60px}` —— **1 张大主图 + 一排小缩略图**。
   我们取 76px：比 60 略大，兼顾触摸目标（DESIGN-SPEC S6 要求 ≥44px），
   但远小于旧版的半宽（1660 容器下约 400px）。主图封顶 520px，避免高屏占满。
   ⛔ 缩略图是 <button>（媒体区不在 <a> 内，可以用 button）。 */
.pd-media { min-inline-size: 0; }
.pd-media-main { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden;
  background: var(--paper-2); max-inline-size: 620px; }
.pd-media-main img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; }
.pd-thumbs { display: flex; flex-wrap: wrap; gap: 10px; margin-block-start: 10px; }
.pd-thumb { inline-size: 76px; block-size: 76px; padding: 0; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--paper-2);
  cursor: pointer; }
.pd-thumb img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.pd-thumb[aria-current="true"] { border-color: var(--gold);
  box-shadow: inset 0 0 0 1px var(--gold); }

/* ── 现货块（老板要求经常强调「12 个起 / 可混批 / 随时问现货」）────────
   ⛔ 文案不得声称"有货"：AGENTS.md §2 明确「不公开库存、只在询盘时确认」。 */
.pd-stock { background: var(--gold-tint); border: 1px solid var(--gold-line);
  border-radius: var(--r-md); padding: 16px 18px; margin-block: 16px 20px; }
.pd-stock h2 { font-size: 1rem; margin: 0 0 6px; }
.pd-stock p { font-size: .9rem; color: var(--ink-2); margin: 0 0 6px; }
.pd-stock .hdi-add { max-inline-size: none; margin-block-start: 10px; }

/* ── 装柜计算块（数据早就算得出来，此前只藏在 FAQ 里）──────────────── */
.pd-load { background: var(--paper-2); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 20px 22px; margin-block-start: 28px; }
.pd-load h2 { font-size: 1.15rem; margin-block-end: 4px; }
.pd-load-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px; margin-block-start: 14px; }
.pd-load-cell { background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 14px; }
.pd-load-cell b { display: block; font-size: 1.15rem; color: var(--navy); font-weight: 500; }
.pd-load-cell span { font-size: .78rem; color: var(--ink-3); }

/* ── 相关产品（解「357 个产品页只有 1 条入链」）────────────────────── */
.pd-related { border-block-start: 1px solid var(--line); margin-block-start: var(--sp-block);
  padding-block-start: 26px; }
.pd-info h1 { font-size: 1.75rem; }
.pd-sku { font-size: .84rem; color: var(--ink-3); margin-block: 6px 20px; }
table.spec { width: 100%; border-collapse: collapse; margin-block-end: 20px; font-size: .92rem; }
table.spec th, table.spec td { text-align: start; padding: 10px 12px; border-block-end: 1px solid var(--line); }
table.spec th { color: var(--ink-2); font-weight: 500; inline-size: 38%; background: var(--paper-2); }
.pd-note { font-size: .9rem; color: var(--ink-2); margin-block-end: 18px; }
.pd-body { margin-block-start: 40px; max-inline-size: 74ch; }
.pd-body p { margin-block-end: 14px; }
.pd-rfq { margin-block-start: 44px; background: var(--paper-2); border: 1px solid var(--line); border-radius: var(--r-md); padding: 34px 32px; }
.pd-rfq h2 { font-size: 1.3rem; margin-block-end: 10px; }
.pd-rfq p { margin-block-end: 14px; max-inline-size: 62ch; }
/* 同款其他货号（变体块）—— 2026-10-15 SEO 审计后新增。
   锚文本是各自的消歧词（300cm / 1.65m / #641183），所以是**真链接**不是装饰。 */
.pd-variants { margin-block-end: 18px; padding: 13px 14px;
  background: var(--paper-2); border: 1px solid var(--line); border-radius: var(--r-sm); }
.pd-variants-h { font-size: .84rem; font-weight: 700; color: var(--ink-2); margin-block-end: 9px; }
.pd-variants-list { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.pd-variants-list a { display: inline-block; padding: 4px 11px; font-size: .85rem;
  color: var(--ink-2); background: var(--paper); border: 1px solid var(--line);
  border-radius: 999px; text-decoration: none; }
.pd-variants-list a:hover { color: var(--gold-dk); border-color: var(--gold); }

.pd-dl { margin-block-end: 16px; }
.pd-dl a { color: var(--gold-dk); font-weight: 600; font-size: .93rem; border-block-end: 1px solid var(--gold); padding-block-end: 2px; }
.pd-dl a:hover { color: var(--navy); }

/* 采购指南入口（2026-10-15 SEO 审计新增）：
   把博客文章接进产品页 / 分类页的内链网 —— 此前文章只有 2–4 条入链。 */
.pg-guides { margin-block-start: 42px; max-inline-size: 82ch;
  padding: 22px 24px; background: var(--paper-2);
  border: 1px solid var(--line); border-radius: var(--r-md); }
.pg-guides h2 { font-size: 1.15rem; margin-block-end: 12px; }
.pg-guides ul { list-style: none; padding: 0; margin: 0; }
.pg-guides li + li { margin-block-start: 11px; }
.pg-guides li a { font-weight: 600; color: var(--gold-dk); }
.pg-guides li span { display: block; font-size: .88rem; color: var(--ink-2);
  margin-block-start: 2px; }
.pg-guides-more { margin-block-start: 13px; font-size: .9rem; }
.pg-guides-more a { color: var(--gold-dk); font-weight: 600; }

/* FAQ accordion, shared by category and product pages */
.cat-faq { margin-block-start: 42px; max-inline-size: 82ch; }
.cat-faq h2 { font-size: 1.25rem; margin-block-end: 10px; }
/* ── FAQ（2026-10-21 定稿 = 卡片式，老板选的 B）─────────────────────
   同一份 `<details class="faq">` 标记，509 个页面共用（contact + 分类页）。
   样式要义：卡片分隔、右侧 +/− 指示（展开转 45° 成 ×）、展开时左侧金条、hover 变金。
   ⛔ 之前做过 ?faq=b/c 三版对比开关，老板定了 B 之后已删除 —— 不要再加回来，
      一个组件只留一套样式，否则「哪套是线上」又要靠记忆。 */
.faq { border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--paper-2); margin-block-end: 8px; }
.faq summary { display: flex; align-items: baseline; gap: 14px; justify-content: space-between;
  cursor: pointer; list-style: none; padding: 12px 14px;
  font-size: 1.02rem; font-weight: 600; color: var(--navy); transition: color .16s ease; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: ""; flex: 0 0 auto; inline-size: 13px; block-size: 13px;
  margin-block-start: .28em; color: var(--gold-dk); transition: transform .2s ease;
  background:
    linear-gradient(currentColor, currentColor) center / 13px 1.5px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.5px 13px no-repeat; }
.faq[open] > summary::after { transform: rotate(45deg); }
.faq summary:hover { color: var(--gold-dk); }
.faq summary:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.faq p { padding: 0 14px 14px; color: var(--body); font-size: .96rem;
  line-height: 1.7; max-inline-size: 78ch; }
.faq[open] { border-color: var(--gold-line); box-shadow: inset 3px 0 0 0 var(--gold); }

/* contact 侧栏的样品间照片 */
.ct-room { margin: 0; }
.ct-room img { inline-size: 100%; block-size: auto; display: block;
  border-radius: var(--r-md); border: 1px solid var(--line); }
.ct-room figcaption { margin-block-start: 8px; font-size: var(--ab-fs-sm); color: var(--ink-3); }

/* buying guide (category pages) */
.cat-guide { background: var(--paper-2); border: 1px solid var(--line); border-inline-start: 3px solid var(--gold); border-radius: var(--r-md); padding: 20px 22px; margin-block: 20px 30px; max-inline-size: 82ch; }

/* category page */
.cat-intro { margin-block: 12px 6px; max-inline-size: 70ch; }
h1 .ar { font-size: 1.1rem; color: var(--gold-dk); margin-inline-start: 10px; }
.pgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }

/* ── 产品卡（2026-09-25 三次收敛：改成 catalogue 目录页骨架）──────────────
   老板从三档对照测试页里选了 **③**：骨架照 /catalog/ 的 `.cat` / `.cat-dl`
   （图 → 名称 2 行 → 一行元信息 → 通栏按钮），但**图保持 1:1 方图不裁** ——
   我们的产品图都是 1200×1200，灯笼/挂饰是竖长商品，5:3 会把挂绳或底部裁掉。
   信息量与上一版**完全一样**（名称 · SKU · MOQ · pcs/ctn · m³ · 加询盘），
   只是 SKU 从单独一行并进元信息行，省掉一行高度。
   ⛔ 卡整体是 <a>，卡内交互只能是 role="button" 的 span（HTML 不允许 a 里嵌 button）。
   ⚠️ 字号下限 .75rem（DESIGN-SPEC S4）；元信息行 .8rem。 */
.pcard { display: flex; flex-direction: column; border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden; background: var(--paper); transition: .18s; }
.pcard:hover { border-color: var(--gold); }
/* ⛔ 2026-10-08 老板定案：「**产品图进详情**，鼠标移到产品图上时**弹出的按钮进购物车**」。
   这是第三版结构，前两版都反着做，写在这里防止后人再改回去：
     2026-09-28 版：图片区=加车按钮、文字区=进详情（老板当时要"点图加车"）
     2026-10-08 版：**图片区=进详情的 <a>**、图上浮出的 <button> =加车 ← 现在这个
   为什么翻过来：符合电商通用直觉 —— 图就是"看详情"的入口；
   加车是**次要动作**，藏进悬停弹出的按钮里，不抢图的视觉。
   ⚠️ 两个入口都得在，且**指向要分清**：
      图片区 <a> → /product/SKU/  （主路径，点图就走）
      加车 <button.pcard-add> → 由 inquiry.js 捕获阶段接管，不跳页（见 build_pages.py 注释） */
.pcard-img { position: relative; display: block; inline-size: 100%;
  margin: 0; padding: 0; border: 0; cursor: pointer; overflow: hidden;
  background: var(--paper-2); font: inherit; }
/* ⛔⛔ 2026-10-08 撤掉：这里曾加过「悬停时图片 scale(1.055) 推近」。
   老板原话：「**图片不用加浮起效果，我说的是其实是 Hover 出浮动按钮**」。
   我把他说的「hover 出浮动图片」误读成"图片浮起"，做了一版又被撤。
   ⇒ 记在这里防回改：**图片本身不做任何悬停动画**，悬停反馈只有两样 ——
     ① 图上浮出加车按钮（`.pcard-add`，见下）
     ② 文字区边框变金 + 名称下划线变金
   为什么"图片别动"是对的（不只是老板偏好）：产品图本身是信息主体，
   缩放会让买家在对比同款不同色时看到**不一致的画面比例**，
   而这站的卖点正是"图 + 装箱数据"一起看。图不动，眼睛才能安稳比对。
   ⚠️ 别因为"hover 没反馈显得干"就再加回来 —— 按钮浮出已经是足够强的反馈。 */
.pcard-img img { aspect-ratio: 1; object-fit: cover; width: 100%; display: block; }
.pcard-count { position: absolute; inset-block-end: 8px; inset-inline-end: 8px;
  background: var(--navy); color: var(--paper); font-size: .75rem; padding: 2px 8px;
  border-radius: var(--r-pill); transition: opacity .18s; }
/* ⛔⛔ 2026-10-08 删除：这里原本有**第二份** `.pcard-tag`（`inset-inline-start:8px`
   + navy），与新定义（`inset-inline-end:8px`）**并存**。CSS 层叠会**合并不同属性**
   ⇒ 左右各 8px ⇒ 角标被拉到通栏（线上实测宽 251.8px / 图片区 267.8px）。
   老板看到的「HOT, NEW 的标准太大太丑」根因就是这条，**不是审美问题**。
   全站 `.pcard-tag` 只允许存在**一处**定义（在文件下方 Products 段），别再复制。 */
/* 图上「加入询盘车」按钮 —— 交互上是老板要的「鼠标移到产品图上时弹出的按钮」，
   尺寸上是老板要的「原来那个大一点的」。
   ⛔ 尺寸改过一轮，别再缩回去（2026-10-08 老板：「add to inquiry 按钮我更喜欢
      原来那个大一点的」）：
        第一版 通栏大条（padding 9×12、字号 .82rem、整条贴满图片宽）← 老板喜欢的
        第二版 左下角小胶囊（padding 8×13、字号 .78rem）         ← 老板嫌小
        现在   **通栏大条 + 再放大一档**（padding 14、字号 .84rem）
      判定依据是"看得见 + 好点"：胶囊在 259px 宽的卡上只有约 110px 宽，
      字小、目标窄；通栏条宽 259px、高 45px，一眼就是按钮。
      同时 **45px ≥ DESIGN-SPEC S6 的 44px 触摸目标下限**（胶囊版只有 28px 高，
      其实是不达标的 —— 这是"大一点"背后的硬理由，不是纯审美）。
   ✅ 保留了前一轮定下的两件事，别一起改掉：
      · 平时收起、悬停/聚焦才升起（`opacity:0` + `pointer-events:none`）
      · 图片区仍是进详情的 <a>，加车是这个浮层按钮（不是"点图加车"）
   键盘可达：:focus-within 也要弹出（Tab 到它时必须可见，否则键盘用户没法加车）。 */
.pcard-add { position: absolute; inset-inline: 0; inset-block-end: 0;
  display: block; inline-size: 100%;
  /* 14px 纵向内边距 + .84rem/1.3 行高 ≈ 45.5px 高，压住 44px 触摸目标下限 */
  padding: 14px 16px; border: 0; border-radius: 0; text-align: center;
  font-family: inherit; font-size: .84rem; font-weight: 700; line-height: 1.3;
  background: var(--gold); color: var(--on-gold); cursor: pointer;
  /* 平时**完全收起**：opacity 0 + 沉到框外 + pointer-events none。
     加 pointer-events:none 是必须的 —— 否则它虽然看不见，仍会吃掉
     图片底部那一条的点击，那一块就点不进详情。 */
  opacity: 0; transform: translateY(100%); pointer-events: none;
  transition: opacity .18s, transform .18s; }
/* 悬停图片 → 按钮弹出。两个触发条件都要（缺一不可）：
   · :hover       —— 鼠标用户
   · :focus-within—— **键盘用户**：Tab 焦点落到 `.pcard-add` 上时它必须可见，
                     否则键盘党永远按不到一个看不见的按钮（DESIGN-SPEC 无障碍要求）。
     ⚠️ 用 :focus-within（父元素）而不是 :focus-visible（自身）：
        按钮 opacity:0 时**仍可被 Tab 聚焦**，:focus-visible 也能触发，
        但 once 焦点离开就收起会闪；:focus-within 让"焦点在图片区内"整段期间都保持可见，更稳。 */
/* 按钮文案的内层 span —— inquiry.js 只换它的文字（见 syncCards）。
   单独给类名是为了让 JS 有个**不受外层样式改动影响**的稳定锚点：
   哪天按钮外层再加图标/包裹元素，JS 也不会误伤。 */
.pcard-add-lbl { display: block; white-space: nowrap; }
.pcard-img:hover .pcard-add,
.pcard-img:focus-within .pcard-add { opacity: 1; transform: none; pointer-events: auto; }
/* 「N photos」在按钮弹出时让开 —— 通栏条贴满整个底部，必然盖住右下角的它 */
.pcard-img:hover .pcard-count,
.pcard-img:focus-within .pcard-count { opacity: 0; }
/* 已加入询盘车：按钮**常显**并换深蓝底金字（与金色形成"已选"的区分，
   且不依赖色相本身传递状态 —— 文案同时变成 ✓ 见 inquiry.js）
   ⚠️ 常显时也必须加 pointer-events:auto，否则用户没法再点一次取消。
   ⛔⛔ 选择器必须是 `.pcard-add.hdi-on`（**同一个元素**），不能写成
      `.pcard-img.hdi-on .pcard-add` —— 后者要求 hdi-on 在**父级 <a>** 上，
      而 inquiry.js 的 syncCards() 是 `btns[i].classList.toggle('hdi-on')`，
      btns = `[data-hdi-add]` = **按钮自己** ⇒ 那个选择器一个元素都匹配不到，
      按钮永远不显示（2026-10-08 实测：class 加上了、但 opacity 仍是 0）。
      来历：卡片结构还是「图片区=button」时，hdi-on 确实落在 .pcard-img 上，
      所以当年 `.pcard-img.hdi-on` 是对的；2026-10-08 结构翻转成
      「图片区=<a> + 内嵌 button」后，hdi-on 的落点跟着移到了按钮上，
      这个选择器当时**忘了同步改**。改结构时务必回头扫一遍所有依赖它的选择器。 */
.pcard-add.hdi-on { opacity: 1; transform: none; pointer-events: auto;
  background: var(--navy); color: var(--gold-lt); }
/* 通栏按钮常显时会盖住右下角「N photos」—— 靠 DOM 顺序（button 在 badge 之后）
   本来就压在上面，这里再显式声明一次，不依赖绘制顺序这个隐性前提。
   用 :has() 是因为 hdi-on 在子按钮上，父级只能反向选择。 */
.pcard-img:has(.pcard-add.hdi-on) .pcard-count { opacity: 0; }
/* 文字区：名称仍保留"能点"的视觉信号（图片区现在本身是链接，文字区同样是 <a>） */
.pcard-txt { display: flex; flex-direction: column; flex: 1; padding: 14px 16px 16px; }
.pcard-name {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: .96rem; color: var(--navy); font-weight: 600;
  line-height: 1.35;
  min-block-size: calc(2 * 1.35em);
  /* ① 常显细下划线：不能只在 hover 时出现 —— 那样等于对首访者没有提示。
     颜色用 --line（浅灰蓝），是"能点"的语义提示而非强调，不抢标题的视觉重量。 */
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: text-decoration-color .18s, color .18s;
}
.pcard-txt:hover .pcard-name, .pcard-txt:focus-visible .pcard-name {
  color: var(--gold-dk); text-decoration-color: var(--gold); }
/* ② ⛔ 2026-10-08 删除：这里原本是文字区底部的「View details →」常显提示
   （`.pcard-more`，全套 5 条规则）。老板：「view detail 是浪费空间」。
   删的理由不只是"重复"，还有一条硬的：它占掉 **一行固定高度**，
   让每张卡都白高一截 —— 而卡片的四行变异源（名称长短 / 装箱缺失 / 角标）
   好不容易才靠 `min-block-size` 压平，多一行等于把这份稳定让出去。
   现在文字区 <a> 本身仍进详情（语义没丢），图片区也是 <a>，两个入口都在。 */
/* 标签 chips —— **只有产品页用**（老板 2026-09-25：「除了产品页，其他地方不用显示标签」）。
   ⛔ 列表页卡片不再有标签行：卡片的四行变异源（标题长短 / 标签个数 / 装箱缺失 / 按钮）
      少了最不可控的那个 —— 标签个数实测是 1/2/3 个，卡片高度根本压不住。
   ⛔ 类名此前叫 `.pcard-tags`/`.pcard-tag`（卡上的标签），沿用会让"卡上有标签"的
      印象留在代码里，所以改名 `.pd-chips`/`.pd-chip`，一并去掉固定行高。 */
.pd-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-block-end: 16px; }
.pd-chip { display: inline-block; font-size: .8rem; font-weight: 500;
  background: var(--gold-tint); border: 1px solid var(--gold-line);
  color: var(--gold-ink); padding: 2px 9px; border-radius: var(--r-sm); }
/* 元信息行：SKU · MOQ · pcs/ctn · m³。数字加粗 —— 装箱数据是本站最硬的差异化点，
   一屏里扫过去要能直接看到「这一箱装多少」。
   ⚠️ 下边距 2026-10-08 从 14px 收到 0：那 14px 原本是和下面「View details →」拉开距离用的，
   那行删掉后若留着，卡底就成了 14 + 16(pcard-txt 内边距) = 30px 的死白 —— 比左右 16px 明显空。
   现在只留 `.pcard-txt` 的 16px 内边距，四边一致。 */
.pcard-meta { display: block; font-size: .8rem; color: var(--ink-2); line-height: 1.5;
  margin-block: 6px 0; }
.pcard-meta b { display: inline; font-weight: 500; color: var(--navy); }
/* ⛔ 2026-09-28 删除：这里原本是卡片底部的通栏按钮 `.pcard-txt .hdi-add`
   （深蓝底+金字，负外边距贴卡边）。老板：「产品卡片不要按钮，点图直接进询盘车」
   → 加车动作已移到**图片区**（见上方 `.pcard-img` / `.pcard-add`）。
   `.hdi-add` 的基样式仍保留 —— **产品页信息列**还在用它（那个是带文字的实心按钮，
   位置和语义都与卡片不同）。 */

/* ── 分类页 hero：**已并入 .ab-hero**（老板 2026-09-25：不要单独一套，
      都统一成 About 那样）。
      ⛔ 原先这里有一整套 `.cat-hero*`（通栏深色带 + 4:3 配图 + KPI 行）——
         它是「全站唯一一个长得不一样的 hero」，已整体删除。
         现在分类页 hero 就是 `.ab-hero`（同一个组件、同一个槽位顺序），
         页面差异只允许出现在「数值」上，不允许出现在结构上。 */

/* hero 内的「关键数字」行。固定 3 格 —— 此前格子数随页面在 3/4 之间变，
   同一排数字在有的页是 4 个、有的页是 3 个，视觉上就不成一套。
   ⛔ 新增 KPI 前先想清楚：每页都必须有值，否则回落到格子数不一。 */
.cat-facts { display: flex; flex-wrap: wrap; gap: 12px 34px; margin-block-start: 20px;
  padding-block-start: 16px; border-block-start: 1px solid rgba(255, 255, 255, .16); }
.cat-facts b { display: block; font-size: 1.15rem; color: var(--gold-lt); font-weight: 500; }
.cat-facts span { font-size: .76rem; color: var(--on-dark-2); }

/* ── 卖点行：**在 hero 卡片内**（老板 2026-09-25：不要单独一条，融合进 hero）*/
.cat-sell { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-block-start: 16px;
  padding-block-start: 14px; border-block-start: 1px solid rgba(255, 255, 255, .16);
  font-size: .84rem; color: var(--on-dark-1); }
.cat-sell b { color: var(--gold-lt); font-weight: 500; }
.cat-sell span::before { content: "◆"; color: var(--gold); font-size: .75rem;
  margin-inline-end: 6px; }

/* ── 子分组锚点导航（只在分组启用的分类页出现）
   ⚠️ 2026-09-25 它从"hero 之后的独立通栏"变成"hero 卡片之后的同栏条"，
      因为整页改成**单个 .wrap.pd 段**（原来 hero / 导航 / 商品在三段里，
      段与段之间的留白各算各的 —— 这就是老板看到「部分列表页和产品行紧贴着」的根因）。 */
.subnav { position: sticky; inset-block-start: 0; z-index: 5; background: rgba(255,255,255,.97);
  border-block: 1px solid var(--line); padding-block: 10px; margin-block-end: var(--sp-gap); }
.subnav-in { display: flex; gap: 8px; overflow-x: auto; }
.subnav a { font-size: .86rem; border: 1px solid var(--line); border-radius: var(--r-pill);
  padding: 7px 15px; white-space: nowrap; color: var(--ink-2); }
.subnav a:hover { border-color: var(--gold); color: var(--navy); }
/* 当前所在项（2026-09-26 加）。原先只有 collections 的**页内锚点**用 .subnav，
   没有"当前在哪一页"的概念；博客分类条是**跨页导航**，必须能看出当前项。
   深底反白，与全站 CTA 的 navy 底一致。 */
.subnav a[aria-current="page"] { background: var(--navy); border-color: var(--navy);
  color: var(--paper); }

/* ── Contact 页（2026-10-21 排版重做）────────────────────────────────
   原来：导语 →「How to reach us」一整条色带 →「送询价」色带 →「要写什么」色带
        → FAQ → CTA，五段纵向堆叠，表单被压到第三屏。
   现在：导语 → 表单（左）+ 侧栏（右：直达渠道 + 报价要素）→ FAQ → CTA。
   表单提到首屏附近，渠道与要素就在旁边，少两次滚动。 */
/* 表单上方的说明：图标 + 两行文字，讲清「购物车询盘」与「表单询盘」是两条路 */
.ct-cart-note { margin-block-end: 20px; display: grid; grid-template-columns: 20px 1fr;
  gap: 10px; align-items: start; font-size: var(--ab-fs-sm); color: var(--ink-2); line-height: 1.65; }
.ct-cart-note svg { inline-size: 20px; block-size: 20px; color: var(--gold-dk); margin-block-start: 1px; }
.ct-cart-note b { color: var(--navy); }
.ct-cart-note a { color: var(--gold-dk); font-weight: 600; white-space: nowrap; }
/* 侧栏：图标 + 联系方式（无说明文字） */
.ct-list--icon li { display: grid; grid-template-columns: 18px 1fr; gap: 10px;
  align-items: center; padding-inline-start: 0; }
.ct-list--icon li::before { content: none; }
.ct-list--icon svg { inline-size: 18px; block-size: 18px; color: var(--gold-dk); }
.ct-list--icon a { font-size: var(--ab-fs-body); }
.ct-grid {
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 48px; align-items: start;
}
.ct-aside { display: grid; gap: 30px; }
.ct-block { border-block-start: 2px solid var(--gold); padding-block-start: 16px; }
.ct-block h3 { font-size: var(--ab-fs-lead); margin-block-end: 12px; }
.ct-list { list-style: none; display: grid; gap: 10px;
  font-size: var(--ab-fs-sm); color: var(--body); line-height: 1.7; }
.ct-list li { position: relative; padding-inline-start: 18px; }
.ct-list li::before { content: ""; position: absolute; inset-inline-start: 0;
  inset-block-start: .72em; inline-size: 8px; block-size: 1px; background: var(--gold); }
.ct-list a { color: var(--gold-dk); font-weight: 600; }
.ct-note { margin-block-start: 14px; font-size: var(--ab-fs-sm); color: var(--ink-3); line-height: 1.7; }
.ct-note a { color: var(--gold-dk); }
@media (max-width: 900px) {
  .ct-grid { grid-template-columns: 1fr; gap: 34px; }
}

/* ── 商品分组 ────────────────────────────────────────────────────────── */
.grp { padding-block-start: var(--sp-block); }
/* `.blk` = .wrap.pd 段里的普通子块（hero 之后的正文）。
   ⛔ 为什么需要它：hero 与正文必须在**同一段**里（否则两段各带留白，中间空 144px）。
      所以正文块改用 .blk 承载段内间距，而不是自带 .wrap.pd。 */
.blk { padding-block-start: var(--sp-block); }
/* hero / 子导航后面的第一块不再重复加段间距（hero 自己已有 margin-bottom）*/
.ab-hero + .grp, .subnav + .grp, .ab-hero + .pgrid, .ab-hero + .blk { padding-block-start: 0; }
/* ⛔ 2026-09-28：hero 通栏后独立成段，紧跟的内容段要压掉上留白 ——
   否则 hero 底部 38px + .pd 的上留白会叠成一大块空白。
   （旧结构里 hero 与正文同属一个 .wrap.pd，靠段内间距控制，不存在这个问题。） */
.ab-hero + .wrap.pd { padding-block-start: 0; }
.grp-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-block-end: 14px; }
.grp-head .sec-h2--sub, .grp-head h2 { font-size: 1.5rem; letter-spacing: -0.012em; margin: 0; }
.grp-head span { font-size: .82rem; color: var(--ink-3); }

@media (max-width: 900px) {
  .sec-h2 { font-size: 2.2rem; }
  .subnav { position: static; }
  .pd-media-main { max-inline-size: none; }
  .pd-load-grid { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .sec-h2 { font-size: 1.8rem; }
  .sec-kicker i { inline-size: 22px; }
  .cat-facts { gap: 10px 24px; }
}

/* footer */
.ft { background: var(--navy); color: var(--on-dark-2); padding-block: 46px 34px; font-size: .88rem; border-block-start: 2px solid var(--gold); }
.ft-note { max-inline-size: 36ch; }

/* Category card grid.
 * Must stay identical to the .cats / .cat rules inlined in index.html:
 * change one, change both. */
.cat {
  display: block; background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden; transition: .18s;
}
/* Full-width download button pinned to the bottom of each card.
 * Negative margin cancels the .cat-txt padding so the button reaches the card
 * edge and inherits its radius through .cat's overflow:hidden. */
.cat .cat-dl {
  display: block; margin-block: 12px -16px; margin-inline: -16px;
  padding: 11px 16px; text-align: center;
  background: var(--navy); color: var(--gold-lt);
  font-size: .86rem; font-weight: 600;
  border-block-start: 1px solid var(--line);
}
.cat:hover .cat-dl { background: var(--gold); color: var(--on-gold); }
/* Arrow drawn in CSS so it can flip under RTL (a literal &rsaquo; would not mirror) */
.cat .cat-dl::after { content: " \203A"; }              /* › */
[dir="rtl"] .cat .cat-dl::after { content: " \2039"; }  /* ‹ */

@media (max-width: 900px) {
  .pd-grid { grid-template-columns: 1fr; gap: 26px; }
  h1 { font-size: 1.55rem; }
}

/* Products 下拉：≤900px 关掉 hover/focus 展开 —— 触屏没有 hover，展开态点不到。
   （≤640px 走抽屉平铺，见下方 640 断点里的覆盖，那里再把 display 改回 block）
   ⛔ 断点只能用标准集 640/768/900/1024 —— 曾写 641px 被 S3 拦下。 */
@media (max-width: 900px) {
  .nav-drop:hover .nav-drop-m,
  .nav-drop:focus-within .nav-drop-m { display: none; }
}

@media (max-width: 640px) {
  /* On small screens the header keeps only the logo and the toggle; the CTA
   moves into the panel, otherwise the toggle is pushed off-screen (390px) */
  .hd-cta, .hd-slogan { display: none; }
  .hd-in { gap: 10px; }
  .logo { font-size: 1rem; }
  /* 导航折叠成下拉面板。
     断点统一为 640px —— 此前这里在 860px 而首页在 640px，同一台平板
     在首页与子页会看到不同形态的导航（2026-09-24 统一）。 */
  .nav-toggle { display: inline-flex; }
  .hd nav {
    display: none;
    position: absolute; inset-block-start: 100%; inset-inline: 0;
    flex-direction: column; gap: 0;
    background: var(--navy); border-block-start: 1px solid rgba(255, 255, 255, .12);
    padding: 4px 24px 12px; box-shadow: 0 14px 28px rgba(0, 0, 0, .28);
  }
  .hd nav a {
    display: block; padding-block: 13px; font-size: 1rem; color: var(--paper);
    border-block-end: 1px solid rgba(255, 255, 255, .10);
  }
  .hd nav a:last-child { border-block-end: 0; }
  /* 抽屉里的分类子项：平铺、缩进、字号小一档；不再用绝对定位面板 */
  .nav-drop { position: static; display: block; }
  .nav-drop-m {
    position: static; display: block; min-inline-size: 0; padding: 0 0 4px 14px;
    background: none; border: 0; border-radius: 0; box-shadow: none;
  }
  .nav-drop-m a { padding-block: 9px; font-size: .92rem; color: var(--on-dark-2); }
  /* 抽屉里必须压过 ≤900px 的 display:none（同特异性、后出现者胜） */
  .nav-drop:hover .nav-drop-m,
  .nav-drop:focus-within .nav-drop-m { display: block; }
  .nav-drop-m .nd-cur-wrap { margin-block-start: 0; padding-block-start: 0; border-block-start: 0; }
  .nav-drop-m .nd-all { margin-block-start: 0; border-block-start: 0; padding-block-start: 9px; }
  .hd.nav-open nav { display: flex; }
  /* CTA inside the panel: visible only while the menu is open */
  .hd.nav-open .nav-cta {
    display: block; margin-block: 12px 6px; padding-block: 13px;
    text-align: center; background: var(--gold); color: var(--on-gold);
    font-weight: 600; border-radius: var(--r-sm);
  }
}

@media (max-width: 640px) {
  .cats { grid-template-columns: repeat(2, 1fr); gap: 10px; }
}

/* Inquiry cart - independent of the catalogue PDFs.
 * All logical properties, so RTL mirrors automatically. */
.hdi-add {
  display: block; width: 100%; margin-block-start: 8px;
  padding: 7px 10px; text-align: center; cursor: pointer;
  font-size: .78rem; font-weight: 600; border-radius: var(--r-sm);
  background: var(--paper-2); color: var(--navy);
  border: 1px solid var(--line); transition: .15s;
}
.hdi-add:hover { border-color: var(--gold); background: var(--paper); }
.hdi-add.hdi-on { background: var(--navy); color: var(--gold-lt); border-color: var(--navy); }
.pd-info .hdi-add { max-inline-size: 260px; margin-block: 14px 4px; font-size: .86rem; padding: 10px 16px; }

/* floating bar, bottom right */
.hdi-bar {
  position: fixed; inset-block-end: 22px; inset-inline-end: 22px; z-index: 60;
  display: none; align-items: center; gap: 14px;
  background: var(--navy); color: var(--paper); border-radius: var(--r-pill);
  padding: 10px 12px 10px 20px; box-shadow: 0 8px 26px rgba(11,27,58,.32);
  border: 1px solid rgba(212,175,55,.45);
}
.hdi-bar--on { display: flex; }
.hdi-bar-txt { font-size: .88rem; color: var(--on-dark-1); }
.hdi-bar-txt b { color: var(--gold-lt); font-size: 1rem; }
.hdi-bar-btn {
  cursor: pointer; border: 0; border-radius: var(--r-pill);
  background: var(--gold); color: var(--on-gold);
  font-weight: 600; font-size: .86rem; padding: 9px 18px;
}
.hdi-bar-btn:hover { background: var(--gold-lt); }

/* cart panel */
.hdi-modal {
  position: fixed; inset: 0; z-index: 70; display: none;
  background: rgba(11,27,58,.55); padding: 20px;
  overflow-y: auto;
}
.hdi-modal--on { display: block; }
.hdi-box {
  max-inline-size: 880px; margin: 4vh auto; background: var(--paper);
  border-radius: var(--r-md); overflow: hidden; box-shadow: 0 20px 60px rgba(11,27,58,.35);
}
.hdi-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; background: var(--navy); color: var(--paper);
}
.hdi-head b { font-size: 1.05rem; color: var(--gold-lt); }
.hdi-x { cursor: pointer; border: 0; background: transparent; color: var(--on-dark-1); font-size: 1.6rem; line-height: 1; }
.hdi-x:hover { color: var(--paper); }
.hdi-body { display: grid; grid-template-columns: minmax(0,1.15fr) minmax(0,1fr); gap: 0; }
.hdi-items { padding: 6px 18px 18px; max-block-size: 62vh; overflow-y: auto; }
.hdi-row { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-block-end: 1px solid var(--line); }
.hdi-row img { width: 52px; aspect-ratio: 1; object-fit: cover; border-radius: var(--r-sm); border: 1px solid var(--line); }
.hdi-row-t { flex: 1; min-inline-size: 0; }
.hdi-row-t b { display: block; font-size: .9rem; color: var(--navy); }
.hdi-row-t span { font-size: .78rem; color: var(--ink-3); }
.hdi-qty { width: 68px; padding: 6px 8px; border: 1px solid var(--line); border-radius: var(--r-sm); font-size: .84rem; text-align: center; }
.hdi-rm { cursor: pointer; border: 0; background: transparent; color: var(--on-dark-2); font-size: 1.2rem; padding: 0 4px; }
.hdi-rm:hover { color: var(--danger); }
.hdi-empty { padding: 40px 18px; color: var(--ink-3); text-align: center; font-size: .92rem; }

.hdi-form { padding: 18px 20px 22px; background: var(--paper-2); border-inline-start: 1px solid var(--line); }
.hdi-form h4 { font-size: .95rem; color: var(--navy); margin-block-end: 12px; }
.hdi-form label { display: block; font-size: .8rem; color: var(--ink-2); margin-block-end: 10px; }
.hdi-form input, .hdi-form textarea {
  display: block; width: 100%; margin-block-start: 4px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm); font: inherit; font-size: .88rem;
}
.hdi-req { color: var(--danger); }
.hdi-hint { font-size: .76rem; color: var(--ink-3); margin-block: 6px 12px; line-height: 1.5; }
.hdi-err { font-size: .82rem; color: var(--danger); margin-block-end: 10px; }
.hdi-send {
  display: block; width: 100%; cursor: pointer; border: 0; border-radius: var(--r-sm);
  background: var(--navy); color: var(--gold-lt);
  font-weight: 600; font-size: .92rem; padding: 12px 16px;
}
.hdi-send:hover:not(:disabled) { background: var(--gold); color: var(--on-gold); }
.hdi-send:disabled { opacity: .5; cursor: not-allowed; }
.hdi-done { padding: 40px 28px; text-align: center; }
.hdi-tick {
  width: 54px; height: 54px; margin: 0 auto 14px; border-radius: 50%;
  background: var(--navy); color: var(--gold-lt); font-size: 1.7rem; line-height: 54px;
}
.hdi-done h3 { color: var(--navy); font-size: 1.2rem; margin-block-end: 8px; }
.hdi-done p { color: var(--body); font-size: .92rem; max-inline-size: 46ch; margin: 0 auto 20px; }
.hdi-done .hdi-send { max-inline-size: 260px; margin-inline: auto; }

/* toast */
.hdi-toast {
  position: fixed; inset-block-end: 92px; inset-inline-end: 22px; z-index: 80;
  background: var(--navy); color: var(--paper); font-size: .85rem;
  padding: 10px 16px; border-radius: var(--r-sm); box-shadow: 0 6px 20px rgba(11,27,58,.3);
  opacity: 1; transition: opacity .4s;
}
.hdi-toast--out { opacity: 0; }

/* Standalone enquiry form — the /contact/ page.
   Same visual language as the cart panel (.hdi-form): 1px --line border, 6px radius,
   same type sizes. It exists as its own block only because the panel's rules carry
   a tinted surface and an inline-start divider that belong to the panel, not a form.
   Registered in DESIGN-SPEC §3 — reuse this, do not build a third form. */
.form-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px 22px; max-inline-size: 720px;
}
.form-grid .form-full { grid-column: 1 / -1; }
.form label { display: block; font-size: .8rem; color: var(--ink-2); }
.form input, .form textarea {
  display: block; inline-size: 100%; min-block-size: 44px; margin-block-start: 4px;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-sm);
  font: inherit; font-size: .9rem; background: var(--paper); color: var(--navy);
}
.form textarea { min-block-size: 132px; resize: vertical; }
.form input:focus-visible, .form textarea:focus-visible {
  outline: 2px solid var(--gold); outline-offset: 1px; border-color: var(--gold);
}
.form .req { color: var(--danger); }
.form-attached {
  font-size: .82rem; color: var(--ink-2); background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 10px 14px;
  margin-block-end: 16px; max-inline-size: 720px;
}
.form-hint { font-size: .8rem; color: var(--ink-3); margin-block: 14px 6px; }
.form-err { font-size: .85rem; color: var(--danger); margin-block: 8px 0; }
.form-send { margin-block-start: 18px; }
.form-done { text-align: center; padding-block: 8px; }
.form-done h3 { color: var(--navy); font-size: 1.2rem; margin-block-end: 8px; }
.form-done p { color: var(--body); max-inline-size: 52ch; margin-inline: auto; margin-block-end: 8px; }

@media (max-width: 768px) {
  .form-grid { grid-template-columns: 1fr; gap: 14px; }
}

/* Blog: article typography + index cards.
   Body copy is capped at 72ch — the same measure as .ab-note, so the reading
   rhythm matches the other inner pages. Tables keep horizontal rules only
   (no vertical grid), same convention as the catalogue documents.
   Type steps reuse existing ones: 2rem/1.75rem/1.25rem/1rem/.875rem/.75rem. */
/* 文章栏：整条内容（标题·导语·正文·CTA）居中成一条栏。
   ⛔ 2026-10-16 老板实测指出「博文偏左、只用一半屏幕」：
      外层 .wrap 是 1660px 居中，而 .post-body 只有 72ch 且**没有 margin-inline:auto**
      ⇒ 整块贴在左边，宽屏右侧空掉近一半。
   ⛔ 栏宽放在 .post 这一层（不放在 .post-body）：标题/导语/正文才会同一条左边缘，
      只给正文居中会出现「标题靠左、正文居中」的错位。 */
.post { max-inline-size: 80ch; margin-inline: auto; }
.post-h1 {
  font-size: var(--ab-fs-sec); font-weight: 600; line-height: 1.15;
  letter-spacing: -.02em; color: var(--navy);
  max-inline-size: 26ch; margin-block-end: 10px;
}
.post-meta { display: block; font-size: var(--ab-fs-sm); color: var(--ink-3); margin-block-end: 4px; }
p.post-meta { margin-block: 0 26px; }
.post-lede {
  font-size: var(--ab-fs-lead); font-weight: 600; line-height: 1.6;
  color: var(--navy); max-inline-size: 74ch; margin-block-end: 26px;
}
/* ⛔ 62ch → 74ch（2026-10-16）：导语比正文窄 18ch 时，80ch 的栏里看起来像没排齐；
   层次靠字号与字重（--ab-fs-lead + 600）体现，不用靠缩短宽度。 */
/* 跟随 .post 栏宽（80ch）：不要再另写一个更窄的值，否则段落/表格右边缘会比
   标题短一截，看起来像没排齐。 */
.post-body { max-inline-size: 80ch; margin-inline: auto; }
.post-body h2 {
  margin-block: 40px 14px; font-size: 1.75rem; font-weight: 600;
  line-height: 1.2; letter-spacing: -.02em; color: var(--navy);
}
.post-body h3 { margin-block: 26px 10px; font-size: 1.05rem; font-weight: 600; color: var(--navy); }
.post-body p { margin-block-end: 16px; line-height: 1.75; color: var(--body); }
.post-body ul, .post-body ol { margin: 0 0 16px 1.15em; color: var(--body); line-height: 1.7; }
.post-body li { margin-block-end: 7px; }
.post-body strong { color: var(--navy); }
.post-body a { color: var(--gold-dk); text-decoration: underline; text-underline-offset: 2px; }
.post-body table {
  inline-size: 100%; border-collapse: collapse;
  margin-block: 18px 24px; font-size: var(--ab-fs-sm);
}
.post-body th, .post-body td {
  text-align: start; padding: 10px 12px;
  border-block-end: 1px solid var(--line); vertical-align: top;
}
.post-body th { color: var(--navy); border-block-end: 2px solid var(--navy); font-weight: 600; }
.post-body tr:last-child td { border-block-end: 0; }
.post-note {
  font-size: var(--ab-fs-sm); color: var(--ink-2); background: var(--paper-2);
  border-inline-start: 3px solid var(--line); border-radius: var(--r-sm);
  padding: 12px 16px; margin-block: 26px 0;
}
.post-cta { margin-block-start: 34px; }
/* ── 博客：杂志式卡片网格（2026-09-25，老板给了参照站后重做）───────────────
   替代旧的 .post-card（无封面、纯文字、按分类分组）。
   卡内容：封面 → 分类标签 → 标题 → 摘要 → 日期。
   ⛔ 封面用 aspect-ratio 预留比例，故 <img> 不需要 width/height 属性
      （audit_site 认这条 —— 项目已有 3 处以上 aspect-ratio，判据降级为提示）。
   ⚠️ 用 17/9 而不是常见 16/9：我们的产品图是 1200×1200 方图，
      16/9 裁切会把上下切掉一大块。
   ⚠️ 300px 下限用 min(300px, 100%) 包一层 —— 否则 320px 视口下
      （可用宽 272px）栅格会横向溢出。 */
.bl-grid { display: grid; gap: 26px;
  grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); }
.bl-card { display: flex; flex-direction: column; border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden; background: var(--paper); transition: .18s; }
.bl-card:hover { border-color: var(--gold); transform: translateY(-2px); }
/* ⚠️ 2026-09-26：`.bl-card` 从整卡 <a> 改成 <article>（对齐 islamicwallartstore
   的真实 DOM），因此下面这些子元素各自成了独立的 <a>/<h2><a>，需要自己清掉链接下划线。 */
.bl-cover { display: block; aspect-ratio: 17 / 9; background: var(--paper-2); overflow: hidden; }
.bl-cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
.bl-body { display: flex; flex-direction: column; flex: 1; padding: 16px 18px 18px; }
.bl-tag { align-self: flex-start; font-size: .8rem; font-weight: 500;
  background: var(--gold-tint); border: 1px solid var(--gold-line);
  color: var(--gold-ink); padding: 2px 9px; border-radius: var(--r-sm);
  text-decoration: none; }
.bl-tag:hover { border-color: var(--gold-dk); }
.bl-card h2 { font-size: 1.12rem; line-height: 1.34; margin-block: 11px 9px; }
.bl-card h2 a { color: var(--navy); text-decoration: none; }
.bl-card h2 a:hover { color: var(--gold-dk); }
.bl-body p { font-size: .92rem; line-height: 1.6; color: var(--ink-2);
  margin-block-end: 14px; }
/* 日期贴底 —— 同一行卡片高度不一时，日期仍对齐 */
.bl-body .post-meta { margin-block-start: auto; }
@media (max-width: 640px) {
  .post-body table { font-size: .8rem; }
  .post-body th, .post-body td { padding: 8px; }
}

@media (max-width: 768px) {
  .hdi-body { grid-template-columns: 1fr; }
  .hdi-items { max-block-size: none; }
  .hdi-form { border-inline-start: 0; border-block-start: 1px solid var(--line); }
  .hdi-bar { inset-block-end: 12px; inset-inline: 12px; justify-content: space-between; }
}

/* save-list button: secondary action, kept visually distinct from Send inquiry */
.hdi-save {
  display: block; width: 100%; margin-block-start: 8px; cursor: pointer;
  background: transparent; color: var(--navy);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-weight: 600; font-size: .88rem; padding: 10px 16px;
}
.hdi-save:hover:not(:disabled) { border-color: var(--gold); background: var(--paper); }
.hdi-save:disabled { opacity: .5; cursor: not-allowed; }
.hdi-hint--sm { font-size: .75rem; margin-block: 8px 0; }

/* About page type scale */
/* 字号基线 —— 2026-10-15 老板：「现代浏览风格就是图多字大」，全站放大（先在 About 试过一轮）。
   ⛔ 这些 token 被 ab-* 组件与内容页组件读取；改基准值 = 全站一起变，别在页面里单独覆盖。
   移动端回退见文件下方的 @media（同一批 token）。 */
:root {
  --ab-fs-hero: 3.5rem;    /* 56 — 页面主标题 */
  --ab-fs-sec: 2.5rem;     /* 40 — 次级大标题 / CTA 标题 */
  --ab-fs-lead: 1.5rem;    /* 24 — 导语 / 卡片标题 / hero 副标题 */
  --ab-fs-body: 1.12rem;   /* 17.9 — 正文 */
  --ab-fs-sm: 1rem;        /* 16 — 卡片正文 / 图注 / 小字 */
  --ab-fs-tiny: .85rem;    /* 13.6 — 微标签 */
  --ab-ink-2: #6E7686;
}

/* About page one-off palette — the WhatsApp mock conversation and the two
   near-black surfaces. These are NOT brand colours: the WhatsApp greens cannot
   be substituted, so they are grouped into their own :root block instead of
   being scattered inline.
   2026-09-24: tokenised. They used to be hardcoded and were let through by an
   allow-list inside the design checker — an allow-list is a hole in the gate:
   change the value and nothing notices any more. No allow-list now. */
:root {
  --wa-panel: #EFE7DE;    /* WhatsApp chat background */
  --wa-header: #075E54;   /* WhatsApp header green  */
  --wa-accent: #25D366;   /* WhatsApp send button   */
  --wa-bubble: #DCF8C6;   /* inbound message bubble */
  --wa-meta: #5D7A66;     /* timestamp / meta text  */
  --ab-faint: #C9CFDA;    /* separator dot          */
  --ab-ink-1: #101418;    /* mock-screen near-black */
}

/* About page.
 * All logical properties, so RTL mirrors automatically.
 * Copy lives in build_pages.render_about(). */
/* Intro: two columns, copy plus the home hero image */
.ab-intro {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 34px;
  /* ⛔ 2026-10-20 老板：「文字的上端没有和右边图片对齐，文字和 hero 贴得太近」。
     ① align-items 原为 center —— 文字块比图矮时被垂直居中，顶端自然落低一截。
        改为 start：两栏顶端齐平（图有 aspect-ratio，不靠拉伸对齐）。
     ② `.ab-hero + .wrap.pd { padding-block-start: 0 }` 会把本段首元素的上留白
        压成 0；hero 现在只剩「小标签 + H1 + 副标题」以后更矮，正文直接贴住金线。
        这里补回 --sp-gap（40px），叠上 hero 自带的 38px 底距 ≈ 78px，
        与下方 .ab-sec 的 96px 板块间距同一个量级，不会打架。 */
  align-items: start;
  padding-block-start: var(--sp-gap);
}
.ab-intro-t { min-inline-size: 0; font-size: var(--ab-fs-body); line-height: 1.75; color: var(--body); }
/* ⛔ 2026-10-20：全站 `* { margin: 0 }` 重置后，本块内 4 段正文会粘成一坨
   （此前没人补段间距）。补 14px，与站内 `.flow-step p + p` 同一量级。 */
.ab-intro-t p + p { margin-block-start: 14px; }
.ab-intro-img {
  width: 100%; aspect-ratio: 4/3; object-fit: cover;
  border-radius: var(--r-md); border: 1px solid var(--line);
}

/* In-house lines: three real product shots (not factory interiors) */
.ab-made { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }

/* Buyer quotes styled to look like a real mail client and chat app rather than
   generic quote cards */
.ab-quotes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; align-items: start; }
.ab-quote {
  margin: 0; border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--line); background: var(--paper);
  box-shadow: 0 2px 10px rgba(11,27,58,.06);
}

/* email: dark app bar, sender row, body */
.ab-quote--mail .ab-quote-head {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 16px; background: var(--paper-2);
  border-block-end: 1px solid var(--line);
  font-size: var(--ab-fs-sm); color: var(--ink-2);
}
.ab-quote--mail .ab-quote-head::before {
  content: "✉"; flex: none; width: 26px; height: 26px; border-radius: 50%;
  background: var(--navy); color: var(--gold-lt);
  font-size: var(--ab-fs-tiny); line-height: 26px; text-align: center;
}
.ab-quote--mail blockquote {
  margin: 0; padding: 18px 20px 6px;
  font-size: var(--ab-fs-body); line-height: 1.7; color: var(--body);
}

/* chat app: green header, cream background, green bubble, timestamp and ticks */
.ab-quote--wa { background: var(--wa-panel); }
.ab-quote--wa .ab-quote-head {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 16px; background: var(--wa-header); color: var(--paper);
  font-size: var(--ab-fs-sm); font-weight: 600;
}
.ab-quote--wa .ab-quote-head::before {
  content: ""; flex: none; width: 22px; height: 22px; border-radius: 50%;
  background: var(--wa-accent);
  background-image: radial-gradient(circle at 50% 38%, var(--paper) 22%, transparent 23%),
                    radial-gradient(ellipse at 50% 95%, var(--paper) 42%, transparent 43%);
}
.ab-quote--wa blockquote {
  position: relative; margin: 16px 16px 6px; padding: 11px 14px 22px;
  background: var(--wa-bubble); border-radius: var(--r-md) var(--r-md) var(--r-md) 4px;
  font-size: var(--ab-fs-body); line-height: 1.6; color: var(--ab-ink-1);
  box-shadow: 0 1px 1px rgba(0,0,0,.08);
}
.ab-quote--wa blockquote::after {   /* timestamp and read ticks */
  content: "07:42  ✓✓"; position: absolute;
  inset-block-end: 6px; inset-inline-end: 12px;
  font-size: var(--ab-fs-tiny); color: var(--wa-meta);
}

.ab-quote figcaption {
  padding: 8px 16px 16px; font-size: var(--ab-fs-sm); color: var(--ab-ink-2);
}
.ab-quote--wa figcaption { padding-block-start: 0; }
.ab-quote figcaption b { color: var(--navy); font-weight: 600; }
.ab-lead { font-size: var(--ab-fs-lead); color: var(--navy); font-weight: 600; line-height: 1.6; }
.ab-punch {
  margin-block-start: 22px; padding: 16px 20px;
  background: var(--paper-2); border-inline-start: 3px solid var(--gold);
  border-radius: var(--r-sm); color: var(--navy); font-weight: 600;
}
/* Section headings: large size, tight leading, negative letter-spacing.
 * Without the negative tracking they do not separate from the body copy and
 * the page reads as one flat block. */
/* ── 板块标题（2026-09-25 全站唯一来源）──────────────────────────────
 * 借鉴的骨架：副标题两侧短线 + 更大的主标题 + 说明段。
 * ⛔ 每个板块标题都必须由生成器的 `sec_head()` 产出，不要在各页面手写 HTML ——
 *    S12 闸门会检查 HTML 里不存在手写的 .sec-h2。
 * ⛔ kicker 只允许写「页面上已经存在的标签」（页面名 / 分类名 / 板块所属层），
 *    它是**标签**不是新写的营销话。 */
.sec-head { margin-block: 0 var(--sp-gap); }
.sec-h2, .sec-h2--sub, .ab-cta h2, .grp-head h2,
.hero h1, .ab-hero h1,
.pd-info h1, .post-h1, .bl-card h2 { font-family: var(--font-display); }
/* ⛔ 2026-10-21：板块标题「居中」的**唯一合法写法**。
   用于 about 这种「居中标题 + 卡片网格」的展示页（老板 2026-10-15 定）。
   以前是 `.pg-about .sec-head{text-align:center}` —— 页面级补丁，
   与列表/正文的左对齐打架，也让「到底哪一页居中」只藏在 CSS 深处。
   现在由构建器给 About 的 `.sec-head` 加 `--mid` 修饰类；页面 CSS 不再碰对齐。
   ⚠️ 与 `.sec-head--center`（首页那套 1.65rem 大写）**不是一回事**，别合并。 */
.sec-head--mid { text-align: center; }
.sec-head--mid .sec-lead { margin-inline: auto; }
.sec-kicker { display: flex; align-items: center; gap: 11px; margin-block-end: 13px; }
.sec-kicker i { display: block; inline-size: 32px; block-size: 2px; background: var(--gold); }
.sec-kicker b {
  font-size: .8rem; font-weight: 600; letter-spacing: .11em;
  text-transform: uppercase; color: var(--gold-dk);
}
.sec-h2 {
  font-size: 3rem; font-weight: 600; line-height: 1.14;
  letter-spacing: -0.03em; color: var(--navy); margin: 0;
}
.sec-lead {
  font-size: 1.2rem; color: var(--ink-2); line-height: 1.72;
  max-inline-size: 66ch; margin-block-start: 12px;
}
/* Sections are separated by full-bleed background bands, not short dividers */
.ab-note { max-inline-size: 72ch; color: var(--body); margin-block-end: 22px; line-height: 1.7; }
.ab-sub {
  margin-block: 24px 12px; font-size: var(--ab-fs-tiny); color: var(--ab-ink-2);
  letter-spacing: .1em; text-transform: uppercase;
}

/* Consolidation cards - the core argument of this page */
.ab-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 24px; }
.ab-card {
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 28px 30px;
}
.ab-card h3 { font-size: var(--ab-fs-lead); color: var(--navy); margin-block-end: 8px; line-height: 1.45; }
.ab-card p { font-size: var(--ab-fs-sm); color: var(--body); line-height: 1.66; }

/* dark hero, matching the home and catalogue pages */
.ab-hero {
  /* ⛔ 2026-09-28 重做：从「.wrap 内的圆角卡片」改为**通栏深色 hero**（与首页 .hero 同一视觉语言）。
     背景：老板 2026-09-24 曾否掉通栏（「圆角贴到屏幕边，看起来像个大横幅」），
       2026-09-28 又要求「其他页 hero 做成和首页一样」→ 意图已变，按新指令做。
     当初两个顾虑的解法：
       ① 圆角贴屏幕边 → 通栏**不要圆角**，问题自然消失；
       ② 像空横幅 → 加深色背景图（不是纯色块）+ 压低高度 + 内容紧凑，不像空横幅。
     ⚠️ 结构随之改变：本类现在应当**包住 `.wrap`**（不是被 .wrap 包住），
       即 `<section class="ab-hero"><div class="ab-hero-bg"></div><div class="wrap">…</div></section>`。
       面包屑也从 hero 外**移入** hero 内（老板 2026-09-28 要求）。 */
  position: relative; overflow: hidden;
  background: var(--navy); color: var(--paper);
  /* 高度明显低于首页（首页 .hero 是 96/104）—— 老板明确要求「不要和首页那么高」 */
  padding-block: 42px 38px;
  /* 一条金线分隔（页面顶部有页头的 2px 金线；这里是 hero 与下方内容区的分隔） */
  border-block-end: 2px solid var(--gold);
  margin-block: 0;
}
.ab-hero-bg { position: absolute; inset: 0; z-index: 0; }
.ab-hero-bg img { width: 100%; height: 100%; object-fit: cover; object-position: center 42%; }
/* 遮罩比首页更深一档：内页 hero 更矮，可容纳的渐变空间更少，需要更实的底 */
/* ⛔ 2026-10-21 老板：「about / wholesale / story 的 hero 背景图太看不清，遮罩做渐变参考首页」。
   原写法是 90deg、.96 → .62，整幅压在 60% 以上，照片等于没了。
   现在照抄首页 `.hero-bg::after` 的曲线（100deg，左端 .88 保白字对比度 ≈12:1，
   向右降到 .30 让画面透出来）—— 两处曲线必须保持一致，改一处记得同步另一处。 */
.ab-hero-bg::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg,
    rgba(11,27,58,.88) 0%,
    rgba(11,27,58,.84) 34%,
    rgba(11,27,58,.70) 52%,
    rgba(11,27,58,.46) 72%,
    rgba(11,27,58,.30) 100%); }
.ab-hero > .wrap { position: relative; z-index: 1; }

/* 面包屑移入 hero 后的深色底样式（原本是全宽浅底细条，在 hero 里要反过来） */
.ab-hero .crumbs { background: transparent; border: 0; margin-block-end: 18px; }
.ab-hero .crumbs-in { padding: 0; max-inline-size: none; color: var(--on-dark-2); }
.ab-hero .crumbs a { color: var(--gold-lt); }
.ab-hero .crumbs span { color: var(--on-dark-1); }
.ab-hero .crumbs i { opacity: .55; }

.ab-kicker {
  display: inline-block; font-size: var(--ab-fs-tiny); letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold-lt); border: 1px solid rgba(232,210,138,.45);
  padding: 3px 11px; border-radius: var(--r-pill);
}
.ab-hero h1 { font-size: var(--ab-fs-hero); color: var(--paper); margin-block: 14px 10px;
  font-family: var(--font-display); }
.ab-hero-sub { font-size: var(--ab-fs-lead); color: var(--on-dark-1); max-inline-size: 62ch; line-height: 1.6; }
.ab-hero-btn { margin-block: 22px 0; }

/* card icons */
.ab-icon { display: block; inline-size: 32px; block-size: 32px; margin-block-end: 16px; color: var(--gold); }
.ab-icon svg { inline-size: 100%; block-size: 100%; display: block; }

/* closing dark CTA band */
.ab-cta {
  display: flex; align-items: center; justify-content: space-between; gap: 26px;
  flex-wrap: wrap; background: var(--navy); color: var(--paper);
  border-radius: var(--r-md); padding: 28px 30px; margin-block: 46px 18px;
  border-inline-start: 3px solid var(--gold);
}
.ab-cta-t { flex: 1 1 40ch; min-inline-size: 0; }
.ab-cta h2 { color: var(--gold-lt); font-size: var(--ab-fs-sec); margin-block-end: 8px; }
.ab-cta p { color: var(--on-dark-1); font-size: var(--ab-fs-body); margin-block-end: 6px; }
.ab-cta-line { font-size: var(--ab-fs-sm); color: var(--on-dark-2); }

/* Certificate wall (2026-10-15 boss redesign #2/#3/#4): one wall, one badge per
   certificate, **4 per row × 2 rows** for the current 8. Each badge carries its
   own text — category tag, name, issuer/scope, reference — so the old
   collapsed one-line summary (.ab-wall-note) is gone.
   Sizes are the boss' call: 「每个证书配文字，图再大一点」⇒ 轨道 232px、证书图 300px 高。
   ⛔ 固定列宽 + justify-content:center —— 用 1fr 的 auto-fill 时，少数的徽章
   会被推到最左边（不在容器里居中）。4 个一行：4×232 + 3×20 = 988 ≤ 1024。 */
.ab-wall {
  list-style: none; padding: 0;
  margin: 26px auto 0; max-inline-size: 1024px;
  display: grid; grid-template-columns: repeat(auto-fit, 232px);
  justify-content: center;
  gap: 20px;
}
.ab-badge {
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  padding: 14px 14px 18px; text-align: center;
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-md);
}
.ab-badge img, .ab-wall-noimg {
  inline-size: 100%; block-size: 300px; object-fit: contain;
  border-radius: var(--r-sm); background: var(--paper);
  border: 1px solid var(--line);
}
.ab-wall-noimg {
  display: flex; align-items: center; justify-content: center;
  color: var(--ab-ink-2); background: var(--paper-2);
}
.ab-wall-noimg svg { inline-size: 40px; block-size: 40px; }
.ab-badge-tag {
  font-size: var(--ab-fs-tiny); font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--gold-dk);
}
.ab-badge b {
  color: var(--navy); font-size: 1.1rem; font-weight: 700; line-height: 1.3;
}
.ab-badge-sub { font-size: var(--ab-fs-sm); color: var(--body); line-height: 1.5; }
.ab-badge em {
  font-size: var(--ab-fs-tiny); color: var(--ab-ink-2);
  font-style: normal; line-height: 1.55;
}

/* trade fairs and product shots */
.shots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.shot { margin: 0; }
.shot img { width: 100%; aspect-ratio: 4/3; object-fit: cover; border-radius: var(--r-md); border: 1px solid var(--line); }
.shot figcaption { font-size: var(--ab-fs-sm); color: var(--ab-ink-2); margin-block-start: 8px; }
.shot figcaption strong { color: var(--navy); }

.ab-browse { font-size: var(--ab-fs-sm); color: var(--body); }
.ab-browse a { color: var(--gold-dk); }
.ab-browse a::after { content: " · "; color: var(--ab-faint); }
.ab-browse a:last-child::after { content: ""; }

/* Responsive breakpoints.
 * The previous breakpoint fired on partly sized windows and dropped the image
 * grid to a single column. The image grid now never goes below two columns. */
@media (max-width: 1024px) {
  .ab-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 768px) {
  .ab-intro { grid-template-columns: 1fr; gap: 22px; }
  .ab-quotes { grid-template-columns: 1fr; }
  .ab-wall { grid-template-columns: repeat(auto-fit, 208px); gap: 16px; }
  .ab-badge img, .ab-wall-noimg { block-size: 250px; }
  .ab-made, .shots { grid-template-columns: repeat(2, minmax(0, 1fr)); }  /* two columns, never a single oversized image */
  .ab-hero { padding: 26px 22px; }
  .ab-hero h1 { font-size: var(--ab-fs-sec); }
  .ab-cta { padding: 24px 22px; }
}
@media (max-width: 640px) {
  .ab-grid { grid-template-columns: 1fr; }        /* cards: single column on narrow screens */
  .ab-made, .shots { gap: 10px; }                 /* images stay two-up, spacing tightens */
}

/* background bands give each section an edge */
/* Full-bleed background bands.
 * The section sits outside .wrap and .ab-in constrains the content width. */
/* The band is already full width; content width comes from .ab-in. */
.ab-sec { padding-block: var(--sp-section); }
/* 2026-10-21：hero 之后若紧跟一条 `.ab-sec` 色带（contact 的表单段），
   上内距吃满 96px 会显得离 hero 很远。站内既有规定是「hero 之后第一块 = --sp-gap」
   （见 about 的 .ab-intro / .ab-lead）。这里把它统一。 */
.ab-hero + .ab-sec { padding-block-start: var(--sp-gap); }
.ab-sec + .ab-sec { margin-block-start: 0; }
.ab-in {
  max-inline-size: 1660px; margin-inline: auto; padding-inline: 24px;
}
.ab-sec > .ab-in > .sec-head { margin-block: 0 var(--sp-gap); }

/* Three-band alternation using the same tokens as the home page:
   paper / paper-2 / navy */
.ab-band--plain { background: var(--paper); }
.ab-band--tint  { background: var(--paper-2); }
.ab-band--dark  { background: var(--navy); }
.ab-band--dark .sec-h2 { color: var(--paper); }
.ab-band--dark .sec-lead { color: var(--on-dark-1); }
.ab-band--dark .sec-kicker b { color: var(--gold-lt); }
.ab-band--dark .sec-kicker i { background: var(--gold-lt); }
.ab-band--dark .ab-note { color: var(--on-dark-1); }
.ab-band--dark .ab-sub { color: var(--on-dark-2); }
.ab-band--dark .ab-badge {
  background: rgba(255, 255, 255, .96);   /* badges keep a white surface on the dark band */
  border-color: rgba(255, 255, 255, .18);
}

/* ── About page-level overrides (hook: <body class="pg-about">) ──────────
 * 2026-10-15 boss: 字号已于当日**提到 :root 基准**（全站生效），
 * 这里只剩 About 专属的排版：去掉 kicker 标签、板块标题居中。 */
/* ⛔ 2026-10-21 清欠（S11 上线后照出来的第一批）：
   `.pg-about .ab-sub` 的三处声明是**死样式** —— About 页那个大号白字副标题
   早在 hero 改版时就没了（全站 `ab-sub` 只剩分类页的回链与 wholesale 的小标题）。
   `.pg-about .sec-head{text-align:center}` 则换成组件变体 `.sec-head--mid`（见下），
   页面级覆盖只留「隐藏 kicker」和「网格列数」两类**布局/可见性**的。
   证据：改前 guard 基线 527 页；改后 S11 应报 0 处。 */
/* 2026-10-21 字体定稿：Fraunces 已进 :root，页面级试用覆盖已删除。 */
.pg-about .sec-kicker { display: none; }   /* 「About Hala Deco」这句标签整条拿掉 */
/* Why us：固定 4 卡 = 2×2（auto-fill 会排出 3+1 孤卡） */
.pg-about .ab-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* 全站字号：窄屏回退（token 一改，所有读 var(--ab-fs-*) 的组件一起缩放） */
@media (max-width: 900px) {
  :root { --ab-fs-hero: 2.7rem; --ab-fs-sec: 2rem; --ab-fs-lead: 1.3rem; }
}
@media (max-width: 640px) {
  :root { --ab-fs-hero: 2.2rem; --ab-fs-body: 1.06rem; }
  .pg-about .ab-grid { grid-template-columns: 1fr; }
  /* 手机：证书墙两枚一行（160×2 + 12 = 332 ≤ 342 可排宽） */
  .ab-wall { grid-template-columns: repeat(auto-fit, 160px); gap: 12px; }
  .ab-badge img, .ab-wall-noimg { block-size: 200px; }
}

/* ── 版面构件：流程图 / 对比表 / 装箱示意图（2026-10-15 老板要求图示化）──────
 * 全部是 HTML/CSS + 内联 SVG —— 文字仍是真文本，SEO 与读屏都拿得到。
 * 老板同日要求：区块对称、大致均匀 ⇒ 网格列数与卡片数配成 6 / 2 / 6 / 6。 */
/* 流程节点图：编号圆点 + 贯穿连接线，3 列 × 2 行 */
.flow {
  list-style: none; padding: 0; margin: 30px auto 0;
  max-inline-size: 1080px;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
}
.flow-step {
  position: relative; text-align: center;
  padding: 34px 22px 30px;
}
.flow-step::before {                     /* 连接线：两端各留半格，形成连续路径 */
  content: ""; position: absolute; inset-block-start: 55px;
  inset-inline: 0; block-size: 1px; background: var(--line);
}
.flow-step:nth-child(3n + 1)::before { inset-inline-start: 50%; }
.flow-step:nth-child(3n)::before { inset-inline-end: 50%; }
.flow-n {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 44px; block-size: 44px; border-radius: 50%;
  background: var(--paper); border: 1px solid var(--gold);
  color: var(--navy); font-weight: 700; font-size: 1.05rem;
}
.flow-step h3 {
  position: relative; z-index: 1;
  margin-block: 16px 10px; font-size: 1.15rem; color: var(--navy);
}
.flow-step p { font-size: var(--ab-fs-sm); color: var(--body); line-height: 1.7; }
.flow-step p + p { margin-block-start: 8px; }

/* 双路线对比：等宽两列 + 中间分隔线（对称） */
.route-cmp {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 26px auto 0; max-inline-size: 1080px;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden;
}
.route-col { padding: 28px 28px 30px; }
.route-col + .route-col { border-inline-start: 1px solid var(--line); }
.route-kpi {
  display: block; font-size: 2.4rem; font-weight: 700; line-height: 1.1;
  color: var(--gold-dk);
}
.route-col h3 { margin-block: 6px 14px; font-size: 1.25rem; color: var(--navy); }
.route-col ul { list-style: none; padding: 0; }
.route-col li {
  position: relative; padding-inline-start: 22px;
  font-size: var(--ab-fs-sm); color: var(--body); line-height: 1.65;
}
.route-col li + li { margin-block-start: 10px; }
.route-col li::before {
  content: ""; position: absolute; inset-inline-start: 2px; inset-block-start: 9px;
  inline-size: 8px; block-size: 8px; border-radius: 50%; background: var(--gold);
}

/* 装箱规格示意图：左图右表（示意 + 数据，两栏等宽观感） */
.spec-split {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 32px; align-items: center;
  max-inline-size: 1080px; margin: 30px auto 0;
  padding: 26px 28px; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-md);
}
.spec-svg { inline-size: 100%; block-size: auto; }
.spec-list h3 { font-size: 1.15rem; color: var(--navy); margin-block-end: 12px; }
.spec-list ul { list-style: none; padding: 0; }
.spec-list li {
  position: relative; padding-inline-start: 22px;
  font-size: var(--ab-fs-sm); color: var(--body); line-height: 1.65;
}
.spec-list li + li { margin-block-start: 9px; }
.spec-list li::before {
  content: ""; position: absolute; inset-inline-start: 2px; inset-block-start: 9px;
  inline-size: 8px; block-size: 8px; border-radius: 50%; background: var(--gold);
}
.spec-note {
  margin-block-start: 14px; font-size: var(--ab-fs-sm);
  color: var(--ab-ink-2); line-height: 1.7;
}

/* ── Wholesale 页级覆盖（钩子 <body class="pg-wholesale">，2026-10-15）──────
 * 老板：标题居中、区块对称均匀。 */
/* ⛔ 2026-10-21 收敛（老板：「What we need to quote 下面有的文字左对齐，有的中间对齐，
   像学生交作业」）。
   原先这里有 3 条把 `.sec-head` / `.sec-lead` / `.ab-note` **推成居中**，而列表、
   表格、正文段落全是左对齐 —— 于是同一段里出现
   「居中标题 → 左对齐列表 → 居中说明 → 左对齐正文」四种节奏，看起来就是没排版。
   wholesale 是**条款/流程型长文页**，通篇左对齐才成体系；居中的板块标题只留给
   about 那种「居中标题 + 卡片网格」的展示页。
   ⛔ 这也是 DESIGN-SPEC 铁律 #3「不许某个页面单独改样式」的反面教材：
      页面级覆盖只允许改**布局**（列数/宽度/间距），不许改文字对齐与字号 —— 已加 S11 闸门。 */
.pg-wholesale .sec-kicker { display: none; }   /* 重复 8 次的「Wholesale terms」标签整条拿掉 */
/* 六卡网格 = 3×2（auto-fill 在 1392 下会排成 4+2，不匀 —— 老板要求对称） */
.ab-grid--6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1024px) {
  .ab-grid--6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .flow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .flow-step::before { display: none; }
}
@media (max-width: 768px) {
  .route-cmp { grid-template-columns: 1fr; }
  .route-col + .route-col {
    border-inline-start: 0; border-block-start: 1px solid var(--line);
  }
  .spec-split { grid-template-columns: 1fr; gap: 20px; padding: 20px; }
}
@media (max-width: 640px) {
  .flow { grid-template-columns: 1fr; }
  .ab-grid--6 { grid-template-columns: 1fr; }
}
.ab-card-h { display: flex; align-items: center; gap: 12px; margin-block-end: 12px; }
.ab-card-h .ab-icon { margin-block-end: 0; inline-size: 26px; block-size: 26px; flex: none; }
.ab-card-h h3 { margin-block-end: 0; }


@media (max-width: 640px) {
  .ab-sec { padding-block: 48px; }
}

/* ==========================================================================
   HOME PAGE BLOCK
   首页专属区块（hero / why / trust / certs / compliance / facts / cta）
   以及共享组件（.btn / .logo / .cat / .hd-in …）的规范定义。

   2026-09-24 架构统一：此前首页样式全部内联在 index.html 的 <style> 里，
   与本站其它 512 页各存一份 → 改一次要改两处。现已合并到本文件，
   **全站只有这一份样式表**：改这里，首页与所有子页同时生效。
   ⚠️ 修改后必须同步更新首页 <link> 的 ?v= 版本号（build_pages.py 自动做）。
   ========================================================================== */

html { scroll-behavior: smooth; }

/* 无障碍：键盘用户跳过导航直达正文（WCAG 2.4.1 Bypass Blocks，A 级）。
   ⛔ 不能用 display:none —— 那样键盘也拿不到焦点，等于没做。
   平时移到视口外，仅在 Tab 聚焦时滑入。 */
.skip-link {
  position: absolute; inset-block-start: -100px; inset-inline-start: 12px; z-index: 100;
  background: var(--gold); color: var(--on-gold); border-end-end-radius: 6px;
  padding: 11px 20px; font-size: .92rem; font-weight: 600; text-decoration: none;
}
.skip-link:focus { inset-block-start: 0; }
/* Prose width cap (2026-09-24). The container is now 1660px; without this, body copy
   would run to ~200 characters per line, which is harder to read than before.
   ~74ch keeps lines in the comfortable 45–75 character band. */
/* ⛔ 2026-10-16：`.post-body > *` 已从这条 74ch 里**移除** —— 栏宽已由 `.post`（80ch）
   统一管住，再在子级写 74ch 会让段落比标题/表格窄 6ch，右边缘参差不齐。
   其余条目（.ab-in / .wrap / .pd-info）保持原样。 */
.ab-in > p, .ab-in > ul, .ab-in > ol,
.wrap > p, .pd-info > p, .pd-info > ul { max-inline-size: 74ch; }

/* ⛔ 豁免（2026-09-28）：上面那条是给**正文段落**防超长行用的，
   但 `.ab-in > ul` 也命中了**网格组件** —— `.ab-wall` 本身就是个 <ul>
   （2026-10-15 前叫 .ab-certs / .ab-certrows），被压到 74ch（≈638px）会在宽容器里缩成窄条。
   ⇒ 网格/图墙类组件一律不受正文限宽约束。新增此类组件时记得加进来。
   ⛔ 2026-10-15 实测踩坑：`.ab-wall` **不能**列进这张表 —— 这条规则的选择器
      `.ab-in > ul.ab-wall` 比 `.ab-wall{max-inline-size:1024px}` 更具体，
      `max-inline-size: none` 会把墙的宽度上限顶掉 → 排成 5 个一行（老板要 4 个一行）。 */
.ab-in > ul.ab-quotes,
.ab-in > ul.shots,
.ab-in > ul.cats,
.ab-in > ul.ab-made { max-inline-size: none; }

/* 证书墙 / 流程图：同样豁免 74ch，但**保留自己的宽度上限** */
.ab-in > ul.ab-wall { max-inline-size: 1024px; }
/* ⛔ 2026-10-15 实测：`.flow` 是 <ol>，`.ab-in > ol` 的 74ch（0,1,1）比 `.flow`（0,1,0）
   更具体 ⇒ 流程图被压成 676px、三列挤成 225px 一列高的窄条。必须单独给宽度。 */
.ab-in > ol.flow { max-inline-size: 1080px; }

.wrap{max-width:1660px;margin-inline:auto;padding-inline:24px}

.hd-in{display:flex;align-items:center;justify-content:space-between;block-size:70px;gap:24px}
.logo{display:flex;align-items:center;gap:11px;font-weight:700;font-size:1.15rem;color:var(--paper);letter-spacing:.02em}
/* Brand mark — real logo image (a transparent PNG). Until 2026-09-24 this was
   drawn in CSS (gold ring + navy dot); the designer's mark replaced it.
   Logical properties so RTL mirrors it; object-fit keeps the aspect ratio. */
.logo .mark{inline-size:30px;block-size:30px;flex:none;object-fit:contain}
.hd-cta{background:var(--gold);color:var(--on-gold);font-weight:600;font-size:.9rem;padding:10px 20px;border-radius: var(--r-sm);white-space:nowrap}
.hd-cta:hover{background:var(--gold-lt)}
/* Logo + the Wholesale link as one group (2026-09-24).
   Without this wrapper the header's space-between spreads every child out and the
   link drifts into the middle instead of sitting beside the logo. */
/* ⛔ 2026-09-28：原本是 `align-items:baseline` —— 实测 slogan 的垂直中心比 logo **低 10px**，
   比导航/CTA 低 7px，正是老板说的「这个位置很古怪，和谁都不对齐」。
   原因：logo 里有 30px 高的图片，baseline 对齐会把文字基线对齐，而图片底边坐在基线上
   → 整个 logo 偏上、slogan 相对偏下。
   ⇒ 改 center：让 slogan 与 logo 视觉居中，整体与导航/CTA 同一水平线。 */
.hd-brand{display:flex;align-items:center;gap:12px;min-inline-size:0}
/* Secondary header link — sits beside the logo, not next to the gold CTA.
   .btn-ghost is built for light backgrounds and is unreadable on the navy header,
   so this is a small token-based text link instead. */
.hd-slogan{color:var(--on-dark-1);font-size:.85rem;white-space:nowrap}
.hd-slogan:hover{color:var(--paper)}

/* Mobile menu. Below 640px the nav collapses into a dropdown panel; opening and
   closing is driven by site.js toggling .nav-open on the header. */
/* CTA inside the panel: small screens only (the header one is hidden below 640px) */

.hero{background:var(--navy);color:var(--paper);padding-block:96px 104px;position:relative;overflow:hidden}
/* Hero background image plus a dark overlay that keeps the text contrast.
   ⛔ 2026-09-28 二次修正（老板：「字看不清，是因为遮罩和那几个字的颜色很接近」）。
      老板的诊断**实测成立**：lead 原用 #DCE4F0（H=216°），遮罩后背景 H=219° ——
      **色相差只有 2°，完全同色系**；而遮罩越深背景饱和度越高（S 0.31→0.55）反而更像。
      ⇒ 真问题不是亮度对比（原 8.51:1 早已达标），是**色相撞车**。
      修法：① lead 改 `var(--paper)` 纯白（S=0，不参与色相比，色相差 142°，对比 8.12:1）
            ② 遮罩 0.82 → **0.72**（老板要的「调浅」）—— 工厂实景更可见（这是核心卖点），
               且白色对比仍有 8.12:1，远超 AA 的 4.5:1。
      ⚠️ 那张图是"自有工厂"的视觉证据，**不能换**；只能调遮罩与文字色。 */
.hero-bg{position:absolute;inset:0;z-index:0}
.hero-bg img{width:100%;height:100%;object-fit:cover;object-position:center}
/* ⛔ 2026-10-08 三次修正（老板：「遮罩太暗」+「Ramadan & Eid Decorations 几乎看不见」）。
   老板要"调浅"，但遮罩深度有**硬下限**，不能凭感觉浅 —— 下面是实测推演：
     底色 = navy·α + 照片色·(1-α)（普通 alpha 合成），相对亮度按 WCAG 2.1 公式。
     ⛔ 采样必须用**真实 banner**（`_tools` 拉不了，直接从线上取 /img/brand/1.banner.jpg，
       2550×1200），取文字实际所在的**左侧 45%** 区域，对**最亮像素**算最坏情况：
       α=0.58 → 白 5.30:1  金 4.26:1   ← 金字不达 AA，不能用
       α=0.62 → 白 5.96:1  金 4.79:1   ← 两项双过 AA  ← **取这个**
       α=0.68 → 白 7.05:1  金 5.67:1
       α=0.72 → 白 8.00:1  金 6.43:1   ← 原值（老板嫌太暗）
     取 **0.62**：比原 0.72 浅了一档（照片透出来），白字/金字双双过 AA。
     ⚠️ 别再往浅调：金字是短板（α=0.58 时先掉线），而
       「Straight from the Factory」正是老板说"几乎看不见"的那半句，
       更浅等于把问题原样还给他。
     ⛔ 另一条实测教训：**不要在"没有 img/ 的本地站"上测 hero 对比度** ——
       本站 `/img/*` 走 R2 代理、`img/` 已被 .gitignore（见 functions/img/[[path]].js），
       本地构建产物天然没有图 → 截图里 hero 只剩深蓝底 + alt 文本，
       量的全是"没有照片"的假数据（2026-10-08 第一版就这么白测了一轮）。
       要验必须在**线上站**量，或把真图拉下来本地拼一个带图的环境。
   真问题是**标题字身太薄**（原 h1 只有 0.28 的淡阴影，遮罩一浅就被照片亮部吃掉），
   所以同时给标题一套**发光式描边**（见下方 .hero h1，全 0 偏移）。 */
/* ⛔ 2026-10-08 定稿：**横向渐变遮罩**，不是纯色平铺。
   ⚠️ 先说清楚：老板报的「遮罩太暗 + 字几乎看不见」是**两个独立问题**，
      上一版把这俩当成一个（以为字看不清是因为遮罩太深）→ 连改三版都没解决。
      真正的重因是**字色**：h1 的全局规则（本文件第 72 行
      `h1,h2,h3,h4{color:var(--navy)}`）让标题渲染成 **navy 深蓝**，
      而 `.hero h1` 从来没覆盖过 color ⇒ 深蓝字压在深蓝遮罩上，
      对比实测 **1.27~1.53:1**（等于看不见）。修法见下方 `.hero h1{color}`。
      遮罩深是**次要**因素 —— 单独调它治不了这个病。
   遮罩本身为什么用渐变：
     这张 banner（2550×1200 义乌车间实景）是**亮底照片**，文字落区
     （左 46% × 纵 10–80%）亮度中位数 (143,111,64)、75 分位 (167,153,127)。
     平铺遮罩在这张图上无解 —— 浅了字糊、深了照片死（老板嫌 0.72 就太暗）。
     所以把"深"只压在**文字占的左半**：左端 α=0.88（白字 ≈12.6:1，稳），
     向右线性降到 0.30（车间实景透亮可见）。
     ⚠️ 左端 0.88 更不更"暗"不看数字看观感：右半几乎全透，整屏比原来那层
       均匀 0.72 更透气；深色只压在文字背后，不牺牲画面信息。 */
.hero-bg::after{content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,
    rgba(11,27,58,.88) 0%,
    rgba(11,27,58,.84) 34%,
    rgba(11,27,58,.70) 52%,
    rgba(11,27,58,.46) 72%,
    rgba(11,27,58,.30) 100%)}
/* Hero 内文字提亮：局部覆盖，不动全局变量（其他页还在用 --on-dark-3） */
.hero p.lead{color:var(--paper);text-shadow:0 1px 3px rgba(0,0,0,.35)}
.hero>.wrap{position:relative;z-index:1}
.hero::before{content:"";position:absolute;inset-block-start:-100px;inset-inline-end:-100px;width:360px;height:360px;border:1.5px solid rgba(212,175,55,.28);border-radius:50%}
.hero::after{content:"";position:absolute;inset-block-start:20px;inset-inline-end:30px;width:200px;height:200px;border:1.5px solid rgba(212,175,55,.16);border-radius:50%}
.hero .wrap{position:relative;z-index:1}
.eyebrow{display:inline-block;font-size:.78rem;letter-spacing:.16em;text-transform:uppercase;color:var(--gold-lt);border:1px solid rgba(232,210,138,.4);padding:5px 14px;border-radius: var(--r-pill);margin-block-end:22px}
/* ⛔ `color:var(--paper)` 这一项**是整个问题真正的修复**，删了标题就会变回深蓝看不见。
   本文件第 72 行有全局 `h1,h2,h3,h4{color:var(--navy)}` —— 它比 `.hero`（父元素）的
   `color:var(--paper)` **更具体**，所以标题一直渲染成 navy 深蓝；
   而深蓝字压在深蓝遮罩上对比仅 1.27~1.53:1（实测），这就是老板说
   「Ramadan & Eid Decorations 几乎看不见」的根因 —— 跟遮罩深浅无关。
   ⚠️ 别用 `.hero{color:...}` 那条来"覆盖"：它管不了 h1（子元素显式设了 color）。
   ⚠️ `.hero h1 em` 的 --gold-hero 同理，必须自带 color（下面那条已带）。 */
.hero h1{color:var(--paper);font-size:2.75rem;line-height:1.18;font-weight:700;max-inline-size:20ch;letter-spacing:-.01em}
/* ⛔ 标题描边 —— 全部用 **0 偏移** 的发光圈（2026-10-08 实测教训）。
   第一版这里写的是 `0 1px 2px` + 四向 ±1px 偏移，**方向错了**：
   带偏移的阴影会落在**字身**上（1px 字重下字身几乎全被覆盖），
   渲染出来白字变成 (79,84,82) 的灰字 —— 比改之前更看不清。
   实测截图取样（h1 第一行最亮像素仅 79,84,82）后改成纯发光圈：
   四向 0 偏移只往外扩、不侵入字身，白字仍是 255 白，外圈压住照片。
   近黑 + 微透明，不做大 blur（blur 大了会糊成一团灰雾，反而不锐）。 */
.hero h1{text-shadow:0 0 1px rgba(0,0,0,.95),0 0 2px rgba(0,0,0,.8),
  0 0 6px rgba(0,0,0,.6),0 0 14px rgba(0,0,0,.35)}
/* `<em>`「Straight from the Factory」——把品牌金提到近白一档（H 仍是 45°），
   并共用 h1 的暗描边。原 --gold-lt #E8D28A 在浅遮罩上对比只有约 3:1，不达标；
   --gold-hero #F5E6B8 在 α=0.68 时 4.79:1，过 AA。 */
.hero h1 em{color:var(--gold-hero);font-style:normal;
  text-shadow:inherit}
.hero p.lead{margin-block-start:20px;font-size:1.08rem;max-inline-size:62ch;color:var(--on-dark-3)}
.hero-cta{display:flex;gap:14px;margin-block-start:34px;flex-wrap:wrap}
.btn{display:inline-block;padding:14px 30px;border-radius: var(--r-sm);font-weight:600;font-size:.96rem;transition:.18s;border:2px solid transparent}
/* 用 <button class="btn"> 时浏览器默认样式会插一脚（字体/光标/居中）——
   只补这几项，让按钮与 <a class="btn"> 看起来一致。 */
button.btn { font-family: inherit; line-height: inherit; cursor: pointer; text-align: center; }
.btn-gold{background:var(--gold);color:var(--on-gold)}
.btn-gold:hover{background:var(--gold-lt)}
.btn-ghost{border-color:rgba(255,255,255,.45);color:var(--paper)}
.btn-ghost:hover{border-color:var(--gold-lt);color:var(--gold-lt)}
.facts{display:flex;gap:48px;margin-block-start:48px;padding-block-start:28px;border-block-start:1px solid rgba(255,255,255,.15);flex-wrap:wrap}
.fact b{display:block;font-size:1.6rem;color:var(--gold-lt);font-weight:700;line-height:1.2}
.fact span{font-size:.85rem;color:var(--on-dark-2)}

.home section{padding-block:72px}
.sec-head{margin-block-end:40px}
/* ⛔⛔ 2026-10-15 修正（老板第二轮「字号放大到全站」时抓到）：
   这里原本写死 `font-size:1.75rem`，而 `.sec-head h2`（0,1,1）比 `.sec-h2`（0,1,0）
   **更具体** ⇒ 全站内容页的板块标题一直被压回 28px，`.sec-h2{font-size:3rem}` 白写。
   只有 About 页因为 `.pg-about .sec-h2`（0,2,0）赢了才显示 48px —— 所以上一轮
   "全站放大"在内容页其实没生效（我当时只量了 About，这是个教训）。
   ⇒ 现在与 `.sec-h2` 对齐为 3rem；改字号**必须同时看这两条**，别只改一条。
   首页的 `.sec-head--center h2` 仍是 1.65rem 大写（当初照参考站定的口径，见下），未动。 */
.sec-head h2{font-size:3rem;font-weight:700;color:var(--navy);letter-spacing:-0.03em;line-height:1.14}
.sec-head p{color:var(--body);margin-block-start:10px;max-inline-size:66ch}

/* ══ 首页板块底色节奏（2026-09-28 老板定结构）═══════════════════════════
   老板：「大图、new、hot 各一行 5 个产品、产品分类图、卖点条、About 精选、Request，
         每个板块底色间隔」。
   底色序列：hero(深) → HOT(白) → NEW(浅灰) → 分类(白) → 卖点条(深) → About(浅灰) → Request(深)
   ⇒ **靠底色交替切分板块**，不靠额外分割线；这也是参考站 islamicwallartstore 的手法。 */
/* ⚠️ 选择器必须带 `.home` 前缀：首页已有 `.home section{padding-block:72px}`（specificity 0,1,1），
   裸 `.band`（0,1,0）会被它压掉，段间距失控。 */
.home .band{padding-block:64px}
.home .band--plain{background:var(--paper)}
.home .band--tint{background:var(--paper-2)}
.home .band--dark{background:var(--navy);color:var(--on-dark-1)}
.home .band--dark h2{color:var(--paper)}
.home .band--dark .lead{color:var(--on-dark-1)}
.home .band--tight{padding-block:34px}
@media(max-width:640px){.home .band{padding-block:44px}}

/* ⛔ 2026-09-28 老板：「首页分类去掉 HOT 和 NEW，这两个已经有单独的板块了」→ 9 个变 7 个。
   7 是质数，等宽栅格怎么排都有尾行。解法：**flex + 尾行居中**——
   把「整齐」交给布局，而不是靠凑数量（列数本身是响应式的，凑不出来，实测过）。
   基准取 5 列 = 老板习惯的卡片尺寸（1920@125% 下每张 286px），7 个 → 5 + 2 且尾行居中。
   ⚠️ 只用于首页；/collections/ 索引页仍用 `.cats`（那边 9 个、且要保持 HT/NEW 入口）。 */
/* 首页分类：**3 列 × 2 行 + 最右一张竖卡跨两行**（老板 2026-10-08 最终定案）
   老板原话的演进：「图片改为瀑布流」→「你不知道啥叫瀑布流？有大有小啊」
   → **「算了，该 2 行各 3 张，最右边一张竖的」＋「对齐」**。
   ⇒ 结论：要**规整对齐**的网格，不要参差。
   7 张卡 = 前 6 张（3 列 × 2 行）+ 第 7 张（第 4 列、跨 2 行）= 4 列 × 2 行，
   **正好填满、零空档** —— 这是 7 这个质数唯一能填满的规则排法。
   （上面那条 2026-09-28 的注释说"7 是质数，等宽栅格怎么排都有尾行"——
     那是按**行**填的思路。把第 7 张做成**跨行的竖卡**就绕开了：
     它不是尾行，它占满一整列。）
   ⚠️ 为什么必须 `grid`、不能用 `columns`：`columns` 是纵向填充、
      **列与列之间不对齐**（实测列高 615/615/615/639、卡片错位）；
      `grid` 才有共同的行线 ⇒ 前 6 张**行行对齐**，这才是老板要的「对齐」。

   ⛔ 图片规格（**这张表就是老板做图的尺寸依据**，改比例 = 改需求，先对齐再动）：
        前 6 张   5:3   **900×540**   ← 与现有图完全一致，**现图直接可用、不用重做**
        第 7 张   2:3   **900×1350**  ← 竖图，**只有这一张要新做**
      第 7 张必须竖：它的高度 = 两行卡高 + 一个行距（实测约 599px），
      横图填不满整列，只能拉伸变形或露底。
   ⛔ `:nth-child(7)` 依赖 DOM 顺序（`chrome_categories()` 按 `CATEGORIES` 出图、
      顺序固定）。哪天调分类顺序，这里必须同步，否则竖卡配到别的分类上。 */
.cats--home { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
/* 前 6 张保持原比例 5:3 —— 现有 900×540 的图直接用，不必重做。 */
.cats--home .cat img { aspect-ratio: 5 / 3; }
/* 第 7 张（Party Sets & Balloons）竖图；移动端也保持 2:3，
   **一套图通用**，不需要为手机单独出一版。 */
.cats--home .cat:nth-child(7) img { aspect-ratio: 2 / 3; }
/* ≥1024（桌面）：4 列；第 7 张占第 4 列、跨两行 ⇒ 与前 6 张的两行对齐。 */
@media (min-width: 1024px) {
  .cats--home { grid-template-columns: repeat(4, 1fr); }
  .cats--home .cat:nth-child(7) { grid-column: 4; grid-row: 1 / span 2; }
}

/* 区块标题居中 + 大写（老板：「标题居中，大写」）。只用于首页这几个板块，
   不覆盖 `.sec-head` 的默认左对齐（About / Wholesale 等页仍靠左）。
   ⛔ 字号对参考站：`.sec-head h2` 全站是 1.75rem；首页这几个板块用参考站口径
      （islamicwallartstore h2 = 26.3px ≈ 1.65rem）+ 字距归 0。 */
.sec-head--center{text-align:center;margin-inline:auto}
.sec-head--center h2{font-size:1.65rem;text-transform:uppercase;letter-spacing:0;line-height:1.15}
.sec-head--center p{margin-inline:auto}

/* 一行 5 个产品（HOT / NEW）—— 数量固定，不随屏幕变列数，
   只在断点下降级（5→4→3→2），避免「尺寸破格」在小屏被压扁 */
.pgrid--5{grid-template-columns:repeat(5,minmax(0,1fr))}
@media(max-width:1024px){.pgrid--5{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media(max-width:900px){.pgrid--5{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:640px){.pgrid--5{grid-template-columns:repeat(2,minmax(0,1fr))}}

/* 行标题：标题 + 「查看全部」——
   ⛔ 2026-09-28 老板第二轮：「HOT/NEW 的标都去掉，看着跟苍蝇一样。标题字体大小看参考站」。
      ① 去掉 `.pill` 徽标 —— 标题本身已说明是 Best Sellers / New Arrivals，
         再加 HOT/NEW 徽标是重复信息（老板原话"跟苍蝇一样"）。
      ② 字号对参考站：islamicwallartstore 的排版体系是
         `--typeHeaderSize: 36px`，h2 = 36 × .73 = **26.3px**，
         `--typeHeaderSpacing: 0.0em`（**不加字距**）。
         ⇒ 本类字号 1.5rem → **1.65rem（26.4px）**，并去掉 letter-spacing。
         ⛔ 别凭感觉调：参考站字距是 0，大写+加字距会显得松散、与参考站不像。
      居中 + 大写保留（老板上一轮明确要求）。 */
.rowhead{display:flex;flex-direction:column;align-items:center;text-align:center;
  gap:8px;margin-block-end:26px}
.rowhead h2{font-size:1.65rem;font-weight:700;color:var(--navy);line-height:1.15;
  text-transform:uppercase;margin:0}
.rowhead .more{font-size:.88rem;font-weight:600;color:var(--gold-dk)}
.rowhead .more:hover{color:var(--navy)}
.pill{display:inline-block;background:var(--navy);color:var(--paper);font-size:.75rem;
  font-weight:700;letter-spacing:.1em;padding:3px 11px;border-radius:99px;
  text-transform:uppercase}
.pill--gold{background:var(--gold);color:var(--on-gold)}

/* 卖点条（深色通栏）—— 承载品牌定位的可量化承诺 */
.marks{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:26px}
.mark b{display:block;color:var(--gold-lt);font-size:1.22rem;font-weight:600;
  line-height:1.3;margin-block-end:6px}
.mark span{font-size:.85rem;color:var(--on-dark-1);line-height:1.5}
@media(max-width:1024px){.marks{grid-template-columns:repeat(2,minmax(0,1fr));gap:22px}}
@media(max-width:640px){.marks{grid-template-columns:1fr;gap:18px}}

/* Request 段（深色，用 --navy-2 与页脚 navy 拉开明度差，避免两块同色糊在一起） */
.req-band{background:var(--navy-2);color:var(--on-dark-1)}
.req-band h2{color:var(--paper)}
.req-grid{display:grid;grid-template-columns:1.25fr .85fr;gap:36px;align-items:start}
.req-grid .lead{color:var(--on-dark-1);max-inline-size:62ch}
.req-steps{counter-reset:s;list-style:none;padding:0;margin:16px 0 0}
.req-steps li{counter-increment:s;position:relative;padding-inline-start:30px;
  margin-block-end:10px;font-size:.92rem;color:var(--on-dark-1)}
.req-steps li::before{content:counter(s);position:absolute;inset-inline-start:0;
  inline-size:21px;block-size:21px;border-radius:50%;background:var(--gold);
  color:var(--on-gold);font-size:12px;font-weight:700;
  display:flex;align-items:center;justify-content:center}
/* ⛔ 2026-09-28 老板：「WhatsApp 和电话号码贴在一起了，没有空间感」。
   原实现用 `<p><b>Email</b>info@…<br>…` + `b{min-inline-size:8.5em}` 对齐 ——
   但 "Phone / WhatsApp" 的实际宽度**超过 8.5em**，于是它后面的号码被挤到紧贴，
   而 "Email"（短）后面却留一大段空白 → 两行对不齐、间距也不一致。
   ⇒ 改用 dt/dd 双列 grid：列宽由**最长的标签**自动决定，行间距用 gap 固定。
      不再依赖 em 估算，加标签也不会再挤。 */
.req-contact{display:grid;grid-template-columns:max-content minmax(0, 1fr);
  gap:10px 20px;margin:0;font-size:.95rem;color:var(--on-dark-1)}
.req-contact dt{color:var(--gold-lt);font-weight:600;white-space:nowrap}
.req-contact dd{margin:0;overflow-wrap:anywhere}
.req-contact a{color:var(--on-dark-1)}
.req-contact a:hover{color:var(--paper)}
@media(max-width:900px){.req-grid{grid-template-columns:1fr;gap:24px}}

/* About 精选：左文右图 */
.about-pick{display:grid;grid-template-columns:1.05fr 1fr;gap:38px;align-items:center}
.about-pick .fig{aspect-ratio:4/3;border-radius:var(--r-md);overflow:hidden;background:var(--paper-2)}
.about-pick .fig img{width:100%;height:100%;object-fit:cover}
.about-pick h2{font-size:1.7rem;font-weight:700;color:var(--navy);letter-spacing:-.01em;margin-block-end:12px}
.about-pick p{color:var(--body);margin-block-end:12px}
.about-pick ul{list-style:none;padding:0;margin:14px 0 0}
.about-pick li{position:relative;padding-inline-start:22px;margin-block-end:8px;font-size:.92rem;color:var(--body)}
.about-pick li::before{content:"\25C6";position:absolute;inset-inline-start:0;color:var(--gold);font-size:.78rem}
@media(max-width:900px){.about-pick{grid-template-columns:1fr;gap:24px}}

.req-band h2{font-size:1.55rem;font-weight:700;letter-spacing:-.01em;margin-block-end:14px}

/* 流式栅格：列数随容器宽度自动变。实测 1132 可用宽 → 4 列（与旧版一致，零回归）；
   1612（1660 容器）→ 6 列。⛔ 不要改回固定列数：容器一宽卡片会被拉到 390px+。 */
.cats{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px}
.cat{display:block;background:var(--paper);border:1px solid var(--line);border-radius: var(--r-md);overflow:hidden;transition:.18s}
.cat:hover{border-color:var(--gold);transform:translateY(-2px)}
.cat img{width:100%;aspect-ratio:5/3;object-fit:cover;background:var(--paper-2)}
.cat .cat-txt{padding:14px 16px 16px}
.cat b{display:block;font-size:.96rem;color:var(--navy);font-weight:600}
.cat span{font-size:.8rem;color:var(--body)}
.cat .ar{display:block;font-size:.9rem;color:var(--gold-dk);margin-block-start:5px}

.why{background:var(--paper-2);border-block:1px solid var(--line)}
.why-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:26px}
.why-item h3{font-size:1rem;color:var(--navy);margin-block-end:8px;font-weight:600}
.why-item p{font-size:.9rem}
.num{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;background:var(--navy);color:var(--gold-lt);font-size:.82rem;font-weight:700;margin-block-end:12px}

.trust{background:var(--navy);color:var(--paper)}
.trust .sec-head h2{color:var(--paper)}
.trust .sec-head p{color:var(--on-dark-3)}
.certs{display:flex;gap:16px;flex-wrap:wrap;margin-block-end:44px}
.cert{background:rgba(255,255,255,.06);border:1px solid rgba(212,175,55,.35);border-radius: var(--r-sm);padding:16px 26px;text-align:center;min-inline-size:136px}
.cert b{display:block;color:var(--gold-lt);font-size:1.05rem}
.cert span{font-size:.76rem;color:var(--on-dark-2)}
.compliance{background:rgba(255,255,255,.05);border:1px solid rgba(212,175,55,.28);border-radius: var(--r-md);padding:26px 28px;margin-block-end:8px}
.compliance h3{color:var(--gold-lt);font-size:1.02rem;margin-block-end:14px;font-weight:600}
.compliance ul{list-style:none;display:grid;gap:12px}
.compliance li{font-size:.92rem;color:var(--on-dark-1);padding-inline-start:16px;position:relative}
.compliance li::before{content:"";position:absolute;inset-inline-start:0;inset-block-start:.62em;width:6px;height:6px;border-radius:50%;background:var(--gold)}
.compliance strong{color:var(--paper);font-weight:600}
.trust .shots{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.trust .shot{border-radius: var(--r-md);overflow:hidden;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.04)}
.trust .shot img{width:100%;block-size:210px;object-fit:cover}
.trust .shot figcaption{font-size:.82rem;color:var(--on-dark-2);padding:12px 14px;line-height:1.5}
.trust .shot figcaption strong{color:var(--gold-lt);display:block;font-weight:600}

.cta{background:var(--paper-2);border:1px solid var(--line);border-radius: var(--r-md);padding:52px 44px;display:flex;align-items:center;justify-content:space-between;gap:34px;flex-wrap:wrap}
.cta h2{font-size:1.6rem;font-weight:700;margin-block-end:10px;color:var(--navy)}
.cta p{max-inline-size:54ch;font-size:.96rem}
.cta .btn-gold{background:var(--navy);color:var(--gold-lt)}
.cta .btn-gold:hover{background:var(--navy-2)}

/* 2026-10-21 老板：「页脚各栏高度对齐 blog」—— flex space-between 时各栏高度随内容参差，
   改 grid：四栏同高、顶部齐平，栏宽按内容比例分（品牌栏最宽）。 */
.ft-in{display:grid;grid-template-columns:1.5fr 1fr 1.15fr 1fr;gap:30px;align-items:stretch}
@media (max-width:1024px){.ft-in{grid-template-columns:1fr 1fr}}
@media (max-width:640px){.ft-in{grid-template-columns:1fr;gap:22px}}
.ft a:hover{color:var(--gold-lt)}
/* 页脚社媒图标（2026-10-21）：内联 SVG，currentColor 描边，不引入图标库/图片资源 */
.ft-social{display:flex;gap:10px;margin-block:14px 12px}
.ft .ft-social a{display:inline-flex;align-items:center;justify-content:center;margin:0;
  inline-size:34px;block-size:34px;border:1px solid rgba(255,255,255,.22);
  border-radius:var(--r-pill);color:var(--on-dark-1)}
.ft .ft-social a:hover{border-color:var(--gold);color:var(--paper)}
.ft .ft-social svg{inline-size:16px;block-size:16px;fill:currentColor}
/* 页脚 Blog 栏：最新 5 篇，标题前带 40px 迷你缩略图 */
.ft .ft-post{display:grid;grid-template-columns:40px 1fr;gap:10px;align-items:center;
  margin-block-end:12px;text-decoration:none}
.ft-post img{inline-size:40px;block-size:40px;object-fit:cover;border-radius:var(--r-sm);
  border:1px solid rgba(255,255,255,.14)}
.ft-post span{font-size:.84rem;line-height:1.35;color:var(--on-dark-2);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ft-post:hover span{color:var(--paper)}
.ft h4{color:var(--paper);font-size:.9rem;margin-block-end:10px;font-weight:600}
.ft a, .ft p{display:block;margin-block-end:6px}
.ft-btm{margin-block-start:30px;padding-block-start:20px;border-block-start:1px solid rgba(255,255,255,.1);font-size:.82rem}
/* Footer wordmark: overrides the header .logo colour (navy on light).
   Two-class specificity so source order never matters. */
.ft .logo{color:var(--paper);margin-block-end:12px}

@media(max-width:900px){
  .cats{grid-template-columns:repeat(2,1fr)}
  .why-grid{grid-template-columns:repeat(2,1fr)}
  .trust .shots{grid-template-columns:1fr}
  .hero h1{font-size:2.05rem}
}
@media(max-width:640px){
  /* Below 640px the nav collapses into a dropdown panel (closed by default,
   opened via header.nav-open) */
  /* On small screens the header keeps only the logo and the toggle: three items
   in one row push the toggle off-screen (measured at 390px) */
  .hd-in{gap:10px}
  .hd-cta,.hd-slogan{display:none}
  .logo{font-size:1rem}
  .home section{padding-block:48px}
  .hero{padding-block:54px 62px}
  .facts{gap:26px}
  .cta{padding:36px 24px}
}

/* ══════════════════════════════════════════════════════════════════════════
   Products 目录页（/products/，2026-09-29 建 · 2026-10-08 去侧栏）
   ──────────────────────────────────────────────────────────────────────────
   ⚠️ 全部类名加 `pl-` 前缀。本页需要 side / grid / chip / more 这类通用名，
      不加前缀会与首页 `.cat`（分类卡）、`.hd`（页头）、`.more` 等互相污染 ——
      实测撞名 6 个（cat / hd / hd-in / logo / more / spec），全部靠前缀隔开。
   ⚠️ 卡片本身**复用全站 `.pcard`**（不另造一套），本段只管
      「工具条 + 一级/二级标签 + 视图头 + 骨架屏」这些本页独有件。
   ⚠️ 本页**不要 hero**（老板 2026-09-29）：买家来目录页是为了找东西，
      页头之下直接是搜索 + 标签。
   ⛔ 2026-10-08：**没有侧边目录了**。导航只有一处 —— 工具条里的 chips。
      改导航行为/样式只需改这一处，不要再往页面里加第二、第三份目录
      （旧版侧栏 + 移动抽屉 + 顶部 chips 三份，是反复漏改的根源）。
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 工具条：只剩一级/二级标签（桌面与手机**同一套组件**）─────────────────
   ⛔ 2026-10-08 老板定案：「**顶部标签能不能完全替代左侧导航？有没有办法？**」
      ⇒ 左侧栏 `.pl-side`、移动抽屉 `.pl-drawer`/`.pl-mask`、底部常驻栏
        `.pl-mbar` **整块删除**（HTML 也不再产出）。顶部 chips 是**唯一**导航，
        桌面与手机共用同一份 DOM，只有排布差异 —— 顺带消灭了"同一份数据
        在侧栏、抽屉、顶部各渲染一遍"的三份重复。
      省下的：首屏约 300px 高 + 左栏让出的 242px 宽（产品行因此多排一张）。
   ⛔ 本段是**移动优先**写法（默认样式 = 小屏，用 min-width 向上增强）——
      规范只允许断点 640/768/900/1024，而被取代的桌面优先写法需要
      `max-width:1023px`（不在白名单）。移动优先从根上避开这个边界值。
   工具条吸顶：移动时页头不吸顶，故顶部=0；≥1024 叠在页头（70px+2px 金边）之下。
   ⛔⛔ 2026-10-08 **第二次改**（老板：「**一二级 chips 和搜索框的位置大小还是别扭**」）：
      **搜索框从这条吸顶栏里搬走，进了标题行**（`.pl-head-row`，与 h1 同一行）。
      为什么必须搬 —— 实测（`.wrap` 在 1440 视口下可排宽是 **1392**，不是 1440）：

      | 方案 | 9 个 chip + 间距 | 再加搜索 300 | 结果 |
      |---|---|---|---|
      | 带计数（当时的现状） | 1351 + 64 = 1415 | 1727 | 超 287 ⇒ 换行，**第 2 行只放得下 2 个**，右空 716px |
      | 去计数 | 1173 + 64 = 1237 | 1549 | 超 109 |
      | 去计数 + 瘦身 | 1083 + 64 = 1147 | 1459 | 超 19（差一点点） |

      ⇒ 9 个长名标签**本身就占满一整行**，再塞进搜索框永远塞不下。硬塞的结果
        就是老板说的"别扭"：chips 掉成 7+2 两行、第二行一大片空白，而搜索框
        孤零零漂在右上角、下面还空一块。
      ⇒ 定案：**搜索归标题行，chips 独占一整行**。 */
.pl-bar { position: sticky; inset-block-start: 0; z-index: 40;
  background: var(--paper); border-block-end: 1px solid var(--line); }
/* ⛔ 这里曾经是 grid 两列（左 chips / 右搜索），搜索搬走后不需要了，
   退回普通块级 —— 少一层布局就少一处会失效的地方。
   ⚠️ `position: relative` 是给下面那条"右侧渐隐"用的。 */
.pl-bar-in { position: relative; padding-block: 9px; }
/* ── 横向可滑提示（只在真的溢出时出现）──────────────────────────────────
   窄屏（1318px 可排宽以下）9 个标签放不下，靠横滑 —— 但**用户看不出右边还有**：
   1366 下只切掉 31px，看起来就像"最后那个标签渲染坏了"。
   这里在右端盖一层白→透明的渐变，读起来就是"后面还有"。
   ⛔ 为什么用 `::after` 盖一层，而不是给滚动容器加 `mask-image`：
      mask 会连**命中测试**一起影响 —— Chrome 里被遮住的区域**点不着**，
      而 `::after` 只是绘制层，`pointer-events: none` 后点击完全不受影响。
   ⛔ 用 `.is-scroll` 门控（JS 按 scrollWidth>clientWidth 加）：
      不加门控的话，宽屏下最后那个标签的右边会被白白抹掉一层。
   ⛔ 渐变色用 `--paper`（工具条底色）而不是白色 —— 换主题时不会露馅。 */
.pl-bar-in::after, .pl-subrow::after {
  content: ""; position: absolute; inset-block: 0; inset-inline-end: 0;
  inline-size: 44px; pointer-events: none; opacity: 0; transition: opacity .18s;
  background: linear-gradient(to right, transparent, var(--paper) 72%); }
.pl-bar-in.is-scroll::after, .pl-subrow.is-scroll::after { opacity: 1; }
/* ⛔ 搜索框在这条吸顶栏里的那三条规则（`.pl-search` / `input` / `svg`）
   已于 2026-10-08 **随搜索框一起搬到页头**（见下方 `.pl-head-row` 注释）。 */

/* 一级标签：**任何宽度都不换行**，放不下就横滑。
   ⛔ 为什么不用 flex-wrap（曾经用）：9 个标签需要 1349px，而 1440 视口的可排宽
      只有 1392、1366 视口只有 1318 —— 一旦换行就是「7 个 + 1 个」这种最丑的形态
      （第二行孤零零一个 chip，右边空掉 900px）。横滑则永远只有一行：
      宽屏（≥1400）9 个全部露出、根本不出现滚动；窄屏才滑。
   ⛔ 滚动条必须藏掉（`scrollbar-width:none` + `::-webkit-scrollbar`），
      否则 Windows 上会多出一条 15px 高的灰条把工具条整个撑高。 */
.pl-chips { display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none;
  min-inline-size: 0; }
.pl-chips::-webkit-scrollbar { display: none; }
/* ⚠️ chips 现在是 `<a>`（原先 `<button>`）—— 链接语义是刻意的：
   有 JS 时被 preventDefault 接管做原地筛选；**没 JS 时它仍是真的分类页链接**
   （优雅降级），同时保住 /products/ 指向 9 个分类页的**可见内链**
   （目录页是站内 SEO 主入口，删掉左侧栏后不能一条 /collections/ 内链都不剩）。
   ⚠️ 尺寸（.8rem / padding 7×12 / 字重 600）是**量出来**的，不是估的：
      9 个 chip 合计 **1349px ≤ 1392**（1440 视口）⇒ 一行刚好排满、右侧仅余 43px。
      随手调大一点，1440 上就会掉到第二行。要改先按上面那条表重量一遍。 */
.pl-chip { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  border: 1px solid var(--line); background: var(--paper); color: var(--ink-2);
  border-radius: var(--r-pill); padding: 7px 12px; text-decoration: none;
  font: inherit; font-size: .8rem; font-weight: 600; cursor: pointer; transition: .16s; }
.pl-chip:hover { border-color: var(--gold); }
.pl-chip.on { background: var(--navy); border-color: var(--navy); color: var(--paper); }
/* 计数徽标：字重回落到 400，与标签本体（600）拉开层级 —— 同字重会糊成一坨。
   ⛔ 下限 .75rem 是规范硬约束（闸门 S5 逐行扫 site.css），别再往下调。 */
.pl-chip .pl-n { font-size: .75rem; font-weight: 400; opacity: .55; }
/* 策展位（HOT / NEW）用金调区分 —— 它们是"编辑部挑选"，不是产品品类；
   不与品类混为一谈，买家一眼能分辨。 */
.pl-chip--feat { border-color: var(--gold-line); background: var(--gold-tint);
  color: var(--gold-ink); font-weight: 600; }
.pl-chip--feat.on { background: var(--gold); border-color: var(--gold);
  color: var(--on-gold); }

/* ── 二级标签行（只在选中的品类下露出那一组）───────────────────────────
   ⛔ 40 个二级**一个不少**（老板 2026-10-08：「40 个二级留」）——
      它们全部渲染进 HTML，只是**同时**只显示当前品类那一组。
   ⛔ 这**不是**老板否掉的"视觉隐藏"：那条针对的是 h1 这类本页唯一的正文
      （藏起来 = 给爬虫和用户看不同内容）。二级 chips 是**用户驱动的筛选
      控件**（与 tab / 手风琴同类，Google 明确不降权），且它们的 href 与顶部
      一级 chips 指向**同样 7 个 URL**，不产生任何额外链接权重 ——
      露或不露，对 SEO 是零影响；对"别让买家被 40 个标签淹没"是正影响。
   ⚠️ 用 `.on` 类控显隐，**不用 `hidden` 属性**：`.pl-subrow` 是 flex 容器，
      `[hidden]{display:none}` 是 **UA 样式、优先级最低**，会被静默盖掉 ——
      表现为 7 组二级全堆在页面上。
   ⚠️ 与一级 chips **保持同一尺寸**（padding/字号一致），层级只靠"**字重降到 400
      + 底色转浅**"来表达。不用缩字号：一级已经压到 .8rem，二级再小就贴近规范
      下限（.75rem），而且手机上会点不准 —— 用粗细和明度分层更可靠。 */
.pl-subrow { position: relative; display: none; gap: 8px; overflow-x: auto;
  scrollbar-width: none; padding-block: 0 10px; }
.pl-subrow.on { display: flex; }
.pl-subrow::-webkit-scrollbar { display: none; }
.pl-chip--sub { font-weight: 400; background: var(--paper-2); }
.pl-chip--sub.on { background: var(--navy); border-color: var(--navy);
  color: var(--paper); }

/* ── 主布局：**单列**。左侧目录已删，产品区拿满整宽 ─────────────────── */
.pl-layout { padding-block: 14px 60px; }
@media (min-width: 1024px) {
  .pl-bar { inset-block-start: 72px; }
  .pl-bar-in { padding-block: 11px; }
  .pl-layout { padding-block: 20px var(--sp-tight); }
}

/* ── 网格上方一行：只剩计数 ─────────────────────────────────────────────
   ⛔ 2026-10-08 老板看着截图说「我觉得乱哄哄的一大堆」——
      原因之一就是**视图标题（`Ornaments & Table Decor`）与已经点亮的那个
      标签是同一句话，一行里说了两遍**。它连同原来的 `.pl-vhead` 左标题一起删掉；
      描述（`#plDesc`）搬进 `.pl-head-row` 与 h1 并排，计数挪到网格上方右端。
      净效果：**省掉一整行 65px**，页顶到第一张卡 375px → 约 260px。 */
.pl-gridhead { display: flex; justify-content: flex-end; margin-block-end: 10px; }
.pl-count { flex: none; color: var(--ink-3); font-size: .82rem;
  white-space: nowrap; }

/* ── 商品网格 ───────────────────────────────────────────────────────
   默认（手机）**强制两列**：`.pgrid` 的最小列宽 240px，375px 屏只能排 1 列，
   而目录页的商品密度必须比落地页高。≥640 交回流式，列数随容器自动变。 */
.pl-layout .pgrid { grid-template-columns: repeat(2, 1fr); gap: 11px; }
@media (min-width: 640px) {
  .pl-layout .pgrid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 14px; }
}
/* ⛔ 必须显式声明 `[hidden]{display:none}`：
   `.pcard` 的 `display:flex` 优先级高于浏览器 UA 的 `[hidden]` 规则，
   不加这一条则 JS 设 `element.hidden = true` **完全无效** ——
   表现为"筛选点了没反应"，且不会报任何错。 */
.pcard[hidden], .pl-empty[hidden] { display: none; }
.pl-empty { grid-column: 1 / -1; text-align: center; padding: 48px 20px;
  color: var(--ink-2); font-size: .92rem; }

/* ── 骨架屏 + 加载提示 ───────────────────────────────────────────── */
.pl-skel { border: 1px solid var(--line); border-radius: var(--r-md);
  overflow: hidden; background: var(--paper); }
.pl-skel span { display: block; background: var(--paper-2);
  animation: pl-pulse 1.4s ease-in-out infinite; }
.pl-skel .pl-sk-img { aspect-ratio: 1; }
.pl-skel .pl-sk-txt { padding: 11px 14px; }
.pl-skel .pl-sk-l { block-size: 11px; border-radius: 4px; margin-block-end: 8px; }
@keyframes pl-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }
.pl-more { grid-column: 1 / -1; text-align: center; padding: 18px;
  color: var(--ink-3); font-size: .84rem; }

/* ⛔⛔ 2026-10-08 删除整块：这里原本是「移动端抽屉目录（`.pl-mask` / `.pl-drawer`
   / `.pl-dsec` / `.pl-ditem` / `.pl-dsub`）+ 底部常驻栏（`.pl-mbar` / `.pl-mcat`）」，
   共 36 行样式 + 一份与顶部 chips **重复渲染**的目录数据。
   老板定案「顶部标签完全替代左侧导航」⇒ 手机端改为：吸顶栏里一级 chips 横滑，
   选中品类的二级 chips 就在**同一根吸顶栏里**接一行横滑。
   删除理由（不只是"少写点"）：
     ① 三处（侧栏 / 抽屉 / 顶部）渲染同一份导航 = 改一处必须记得改三处；
     ② 底部固定栏吃掉 61px 视口高，还要额外 96px 的底部内边距去躲它；
     ③ 抽屉要一整套开合状态 + Esc + 遮罩点击，全是可省的状态机。
   ⇒ 桌面与手机现在共用**同一份 DOM**，只有换行/横滑的排布差异。 */


/* ── 卡片上的 HOT / NEW 角标（2026-10-08 老板定：右上角**小**角标）──────
   ⛔ 老板原话：「产品图上 HOT, NEW 的标准太大太丑，应该是右上角一个小小角标」。
      "太大"在线上的**真因是 bug**，不是审美：本文件里曾同时存在两份
      `.pcard-tag`（一份 `inset-inline-start` + navy，一份 `inset-inline-end`），
      CSS 层叠**合并不同属性** ⇒ 左右各 8px ⇒ 角标被拉成通栏
      （线上实测宽 251.8px / 图片区 267.8px）。旧的那份已删，见文件上方注释。
   ⛔ 颜色（2026-10-08 老板改口径）：**HOT 深蓝、NEW 金**。
      上一版两者同金（当时原话是"金色"），本次按最新口径拆开。
   ⛔ 用 inset-inline-end 而非 right：LTR 下等价于右侧，RTL 站点自动镜像。
   ⛔ 变小只能靠**收内边距与字距**，不能靠调小字号 ——
      规范 S5 硬性要求字号 ≥ .75rem（闸门逐行扫 site.css，写 .68 会直接报红）。
   ⛔ 只在 /products/ 传 tag；首页**不打**（老板 2026-09-29 明确）。 */
.pcard-tag { position: absolute; inset-block-start: 7px; inset-inline-end: 7px;
  background: var(--navy); color: var(--paper); font-size: .75rem;
  font-weight: 700; letter-spacing: .04em; line-height: 1.45; padding: 1px 7px;
  border-radius: var(--r-pill); text-transform: uppercase; }
.pcard-tag--new { background: var(--gold); color: var(--on-gold); }

/* ── 断点收口 ──────────────────────────────────────────────────────
   ⛔ 本页是**移动优先**：默认样式即小屏形态，全部增强写在 `@media (min-width: …)`。
      因此这里**不出现任何 max-width** —— 需要表达"小于 1024"时，
      靠"默认值就是 <1024 的形态"来实现，从根上避开 1023/1025 这类表外断点。
   用到的两档：640（手机→流式网格）、1024（工具条变两列 + 标签换行铺开）。 */

/* ── Products 页顶部标题区（不是 hero，也不是文案墙）───────────────────
   ⛔ 老板 2026-09-29：「Products 页不要 hero」。
   ⛔ 2026-10-08 老板删掉那句说明文案（「这段话白白占据地方」）——
      去掉 `.pl-intro p`，标题区由 135px 压到约 56px。
   ⛔ 但 **h1 仍必须可见**，不改成"视觉隐藏" —— 老板原话：
      「**视觉隐藏会被罚 SEO 作弊**」。页面必须有 h1（SEO），
      而"当前在看哪个分类"已经由**点亮的那个标签**表达，不再另设一个随筛选
      漂移的 h2 标题（2026-10-08 删掉 —— 它与选中标签是同一句话，说两遍）。
      所以这里选择**压缩**，不是隐藏。 */
.pl-head { background: var(--paper); }
.pl-head-in { padding-block: 10px 11px; }
/* ⛔⛔ 2026-10-08 第二次重排（老板「面包屑，Ramadan & Eid products，Party Sets &
   Balloons Complete party kits…，搜索栏放在一起一行行不行？然后 2 行标签」）——
   **面包屑 · h1 · 视图描述 · 搜索 四块并成一行**，下面只留两级标签两行。
   宽度是量出来的（1440，文本实宽）：面包屑 112 + h1 275 + 描述 427 + 搜索 360
   = 1174 + 间隙 60 ≈ 1234 ≤ 可排 1392 ⇒ 放得下。
   （加上视图标题那 221px 就是 1455 > 1392 放不下 —— 所以视图标题必须先删，
     正好它本来就与选中标签重复。）
   ⚠️ 仍然要包一层 `.pl-head-row` 再上 flex，**不能把 `.pl-head-in` 直接变 flex**：
      面包屑是 `<!--PL_CRUMBS-->` 替换进来的 nav，得让它进这一行、
      但**不能**让它跟 h1 抢主轴 —— 见下面各自的 `flex` 声明。 */
.pl-head-row { display: flex; align-items: center; gap: 10px 20px;
  flex-wrap: wrap; }
/* 默认（手机 / 平板）：每一块各占一行，`flex-basis: 100%` 强制换行。 */
.pl-head-row .crumbs { flex: 1 1 100%; }
.pl-head-row h1 { flex: 1 1 100%; min-inline-size: 0;
  font-size: 1.3rem; color: var(--navy); margin: 0; letter-spacing: -.01em; }
/* 视图描述：手机上换行、跟着视图/二级筛选实时变（`#plDesc`）。 */
.pl-desc { flex: 1 1 100%; min-inline-size: 0; margin: 0;
  font-size: .84rem; color: var(--ink-3); line-height: 1.45; }
.pl-search { position: relative; flex: 1 1 100%; min-inline-size: 0; }
.pl-search input { inline-size: 100%; padding: 11px 14px 11px 40px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  font: inherit; font-size: .9rem; background: var(--paper-2); color: var(--body); }
.pl-search input:focus { outline: 2px solid var(--gold); outline-offset: 1px;
  background: var(--paper); }
.pl-search svg { position: absolute; inset-inline-start: 14px; inset-block-start: 50%;
  transform: translateY(-50%); opacity: .5; pointer-events: none; }
/* 面包屑并进标题区（老板 2026-10-08：「面包屑为什么要单独一行而且还居中？」）
   ⛔ 在这一页它**不是**分隔层：原来那条通栏灰带的作用是隔开"深色页头 / 深色 hero"
      （见文件上方 `.crumbs` 注释），而本页没有 hero、`.pl-head` 本身就是白底，
      分隔作用已经有了 ⇒ 保留它只会白占 65px（其中 22px 还是 `padding` 叠了两层）。
   ⛔ 现在它归属标题区：去底色/去下边框/去内边距、紧贴 h1 上方、**左对齐**。
      位置由 build_pages 的 `<!--PL_CRUMBS-->` 标记决定（在 `.pl-head-in` 内、h1 之前）。
   ⛔ `margin-inline: 0` 必须显式写死：`.crumbs-in` 全局带 `margin-inline: auto`
      （为块级居中），一旦它变成某个 flex 容器的子项，auto margin 会被主轴吸收
      ⇒ 又回到"居中"。这是它当年被居中的同一根因，别把这行删了。 */
.pl-head .crumbs { background: none; border-block-end: 0; }
.pl-head .crumbs-in { padding: 0; max-inline-size: none; margin-inline: 0;
  font-size: .8rem; }
@media (min-width: 1024px) {
  .pl-head-in { padding-block: 10px 11px; }
  /* ≥1024 并成一行：面包屑 · h1 · 描述 · 搜索。
     `flex` 是分工，不是随手写的：
       · 面包屑 / h1  → `flex: none` / `0 0 auto`：**宽度=内容**，不参与分剩余空间；
       · 描述        → `flex: 1 1 0`：吃掉剩下的，超长走省略号（不换行、不撑高）；
       · 搜索        → `flex: 0 1 360px`：基准 360，窄屏时按比例收缩。 */
  /* ⛔ 两条都是量出来的，别改回去：
     ① **必须 `nowrap`**：flex 默认 `wrap` 在空间不足时**优先换行、不做收缩**，
        1024 下会把搜索框挤到第二行、页头从 69px 撑到 109px（实测）。
     ② **搜索宽度用 `clamp()` 而不是固定 360px**：`flex: 0 1 360px` 在"没有溢出"
        时不会收缩，于是描述只能捡剩下的 165px（要 427px），被截成「Our best
        sellers to…」。`25vw` 让它在 1440 正好到上限 360，1024 收到 256、
        把空间让给描述（269px）。`clamp` 不是断点，不占 S3 白名单。
     实测四块始终一行、中心对齐（106 / 112）：1440 描述 581 · 1280 461 · 1024 269。 */
  .pl-head-row { display: flex; flex-wrap: nowrap; }
  .pl-head-row .crumbs, .pl-head-row h1 { flex: none; }
  .pl-head-row h1 { font-size: 1.5rem; }
  .pl-desc { flex: 1 1 0; min-inline-size: 0; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis; }
  .pl-search { flex: none; inline-size: clamp(240px, 25vw, 360px); }
}

/* ── 下单截止日计算器 /order-deadline-calculator/（2026-10-16 新建）─────────
 * 这一页是**外链诱饵**：页底给 iframe 嵌入代码，让别人把工具贴到自家站点，
 * 署名行（.dl-sig）在嵌入模式下显示 —— 那是带回本站的链接。
 * ⛔ 嵌入模式规则改动前先想清楚：iframe 高度写死 560（见 deadline.js），
 *    隐藏 chrome 后内容必须能装进 560，否则 iframe 里出现滚动条。 */
.dl-wrap { background: var(--paper-2); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 18px 18px 14px; margin-block: 16px 26px; }
.dl-form { display: grid; gap: 14px; grid-template-columns: 1fr; }
@media (min-width: 640px) {
  .dl-form { grid-template-columns: 1fr 1fr; }
  .dl-row:first-child { grid-column: 1 / -1; }   /* 目的市场：整行，选项文字长 */
}
.dl-row { display: flex; flex-direction: column; gap: 6px; }
.dl-row label { font-size: .84rem; font-weight: 600; color: var(--navy); }
.dl-row select, .dl-row input[type="date"], .dl-row input[type="number"] {
  font: inherit; font-size: .95rem; color: var(--body); background: var(--paper);
  border: 1px solid var(--line); border-radius: 8px; padding: 9px 10px;
  inline-size: 100%; block-size: 42px; }
.dl-row input[type="number"] { block-size: 42px; }
.dl-hint { font-size: .78rem; color: var(--ink-3); }
.dl-check { display: flex; align-items: center; gap: 8px; font-weight: 500 !important; }
.dl-check input { inline-size: 18px; block-size: 18px; accent-color: var(--gold-dk); }
.dl-form .btn { justify-self: start; margin-block-start: 4px; }
.dl-out-wrap:empty { display: none; }
table.dl-out { inline-size: 100%; border-collapse: collapse; margin-block: 4px 0;
  font-size: .92rem; background: var(--paper); border: 1px solid var(--line);
  border-radius: 8px; overflow: hidden; }
table.dl-out th, table.dl-out td { text-align: start; padding: 10px 12px;
  border-block-end: 1px solid var(--line); vertical-align: top; }
table.dl-out th { inline-size: 40%; font-weight: 600; color: var(--navy);
  background: var(--paper-2); }
table.dl-out td b { display: block; color: var(--gold-dk); font-size: 1rem; }
table.dl-out td span { display: block; font-size: .78rem; color: var(--ink-3);
  margin-block-start: 2px; }
table.dl-out tr:last-child th, table.dl-out tr:last-child td { border-block-end: 0; }
.dl-note { font-size: .84rem; color: var(--ink-2); margin-block: 10px 0; }
.dl-err { color: var(--danger); font-size: .9rem; }
.dl-code { background: var(--navy); color: var(--on-dark-1); font-size: .78rem;
  line-height: 1.5; padding: 14px 16px; border-radius: 8px; overflow-x: auto;
  white-space: pre-wrap; word-break: break-all; margin-block: 12px 10px; }
.dl-sig { display: none; }
/* 嵌入模式（?embed=1）：iframe 里只留计算器本身 */
body.dl-embed { background: var(--paper); }
body.dl-embed .hd, body.dl-embed .ft, body.dl-embed .crumbs,
body.dl-embed .ab-cta, body.dl-embed .pg-cta { display: none; }
body.dl-embed section.wrap.pd > * { display: none; }
body.dl-embed section.wrap.pd > .dl-wrap { display: block; }
body.dl-embed .dl-wrap { margin: 0; border: 0; border-radius: 0;
  padding: 14px; background: var(--paper); }
body.dl-embed .dl-sig { display: block; font-size: .78rem; color: var(--ink-3);
  margin-block: 10px 0; }
