/* 磊鹏纺织客户网站 —— 小雅风高级感 */
/* 全局：滚动条占位稳定 → 居中布局左右对称（消除滚动条导致的 15px 偏移） */
html { scrollbar-gutter: stable; }

:root {
  --bg: #faf7f2;
  --ink: #23262e;
  --ink-soft: #5a5f6a;
  --gold: #b08d57;
  --gold-dark: #96733f;
  --line: #e6e0d6;
  --card: #ffffff;
  --warn: #c0392b;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
  font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
  background: var(--bg); color: var(--ink); line-height: 1.7;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
.container { max-width: 1400px; margin: 0 auto; padding: 0 24px; }
.section { padding: 42px 24px; }
/* 首页「最新上架」：去掉本版块自己的上下 padding（左右 24px 保留）。
   ⚠️ 为什么：`.section` 的上下 padding 会与**相邻版块**的叠成两倍 ——
   实测首页 hero→按分类逛 = 42px（只有一份），而「按分类逛→最新上架」= 84px、
   「最新上架→页脚」= 82px（各叠了两份），看起来就比别处空一倍
   （小王 2026-09-29：「最新上架与其他内容的上下边距太大」）。
   去掉这一份后回到全页统一的 42px 节奏（上 42 / 下 40）。
   ⚠️ 只覆写 padding-top/bottom，**不要用 padding 简写**（会把左右的 24px 也清掉）。 */
.section-latest { padding-top: 0; padding-bottom: 0; }
.section-title {
  font-size: 22px; letter-spacing: 2px; margin-bottom: 22px;
  display: flex; justify-content: space-between; align-items: baseline;
}
.section-more { font-size: 13px; color: var(--gold-dark); letter-spacing: 0; }
.empty-tip { color: var(--ink-soft); padding: 40px 0; text-align: center; }

/* ── 头部 ── */
.site-header {
  background: var(--card); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 50;
}
.header-inner { display: flex; align-items: center; justify-content: space-between; height: 68px; }
.brand { display: flex; align-items: center; gap: 12px; }
.brand-logo { width: 44px; height: 44px; object-fit: contain; border-radius: 50%; }
.brand-cn { font-size: 19px; letter-spacing: 2px; display: block; line-height: 1.2; }
.brand-en { font-size: 12.5px; font-weight: 600; color: var(--ink-soft); letter-spacing: 1px; }
.site-nav { display: flex; gap: 26px; align-items: center; }
.site-nav a { font-size: 15px; letter-spacing: 1px; color: var(--ink-soft); position: relative; }
.site-nav a:hover, .site-nav a.on { color: var(--ink); }
.site-nav a.on::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -6px; height: 2px; background: var(--gold);
}
.site-nav .nav-cta {
  border: 1px solid var(--gold); color: var(--gold-dark); padding: 7px 16px; border-radius: 999px;
}
.site-nav .nav-cta:hover, .site-nav .nav-cta.on { background: var(--gold); color: #fff; }
.nav-toggle, .nav-burger { display: none; }

/* 首屏轮播区 */
.hero { position: relative; }
/* 轮播图收窄：与下方"按分类逛"容器内容区精确对齐（container 1400 - 左右24 = 1352） */
.hero-inner {
  position: relative; width: calc(100% - 48px); max-width: 1352px;
  height: 560px; margin: 16px auto 0; overflow: hidden; border-radius: 14px;
  box-shadow: 0 8px 24px rgba(0,0,0,.08);
  background: #171a20;
}
.hero-slides, .hero-slide { position: absolute; inset: 0; }
.hero-slide { opacity: 0; transition: opacity .8s ease; }
.hero-slide.is-on { opacity: 1; }
.hero-slide img { width: 100%; height: 100%; object-fit: cover; object-position: center; }
.hero-caption { position: absolute; inset: 0; }
.hero-overlay { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(20,20,26,0.08) 0%, rgba(20,20,26,0.55) 100%); }
.hero-info { position: absolute; left: 40px; bottom: 130px; color: #fff; }
.hero-name { font-size: 30px; font-weight: 700; letter-spacing: 3px; display: block; text-shadow: 0 2px 10px rgba(0,0,0,.45); }
.hero-sub { font-size: 14px; opacity: .9; letter-spacing: 2px; display: block; margin-top: 4px; }
.hero-arrow {
  position: absolute; top: 42%; width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.7); background: rgba(255,255,255,.18); color: #fff;
  font-size: 26px; cursor: pointer; z-index: 5; line-height: 1;
}
.hero-arrow-prev { left: 18px; }
.hero-arrow-next { right: 18px; }
.hero-arrow:hover { background: rgba(255,255,255,.35); }
.hero-dots { position: absolute; bottom: 96px; left: 0; right: 0; display: flex; gap: 8px; justify-content: center; z-index: 5; }
.hero-dots i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,.45); cursor: pointer; }
.hero-dots i.on { background: #fff; }
.hero-search-wrap { position: absolute; left: 0; right: 0; bottom: 0; padding: 22px 20px 26px; z-index: 6; }
.hero-search {
  max-width: 620px; margin: 0 auto; display: flex; background: rgba(255,255,255,.96);
  border-radius: 999px; overflow: hidden; box-shadow: 0 8px 24px rgba(0,0,0,.16);
}
.hero-search input { flex: 1; border: 0; padding: 14px 22px; font-size: 14px; outline: none; }
.hero-search button {
  border: 0; background: var(--gold); color: #fff; padding: 0 26px; font-size: 14px;
  letter-spacing: 2px; cursor: pointer;
  /* ⚠️⚠️ 2026-09-30 补：按钮默认是 `flex: 0 1 auto`，会被 `flex:1` 的输入框**挤压** ——
     窄屏下被压到 89px，而「查布料」+ 字间距 2px×2 + 内边距 26px×2 需要约 100px
     ⇒ **文字折成两行**（"查布" / "料"），小王报的就是这个。
     ⇒ `flex:0 0 auto` 不许压缩；`white-space:nowrap` 兜底，任何宽度下都不折行。 */
  flex: 0 0 auto;
  white-space: nowrap;
}
.hero-search button:hover { background: var(--gold-dark); }

/* ── 样布卡片：1:1 复刻小程序「产品分类」页卡片，桌面一行 3 张（桌面整体放大）── */
.fabric-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.mp-card { position: relative; display: flex; background: #fff; border: 1px solid #e8e8e8; border-radius: 6px; padding: 10px; gap: 12px; overflow: hidden; min-height: 150px; box-sizing: border-box; box-shadow: 0 1px 3px rgba(30,30,40,.04); transition: transform .15s, box-shadow .15s; }
/* ⚠️ position: relative 是右上角「＋」的定位基准（小程序 product-card 的 .card 同理） */

/* 卡片右上角「＋」：快捷加入询价单（切换式 ＋ ↔ ✓）
   尺寸/圆角/配色都跟 .mp-cat-tag 同族 —— 小程序里那个按钮就是**按类别标签等高对齐**的
   （44rpx ≈ 标签高），这里照搬同一条思路：26px 方框 ≈ .mp-cat-tag 的高度。
   ⚠️ z-index 必须给：否则会被 .mp-card-img 盖住（同族坑见 .mp-card 那条注释）。 */
.mp-add {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  width: 26px; height: 26px; border-radius: 4px; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; line-height: 1; cursor: pointer; user-select: none;
  color: #1a3a5c; background: #e8f0f8; border: 1px solid #c8d8e8;
  transition: background .15s, color .15s, transform .1s;
}
.mp-add.on { background: #1a3a5c; border-color: #1a3a5c; color: #fff; }
.mp-add:active { transform: scale(.9); }
.mp-card:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(0,0,0,.08); }
.mp-card-img { width: 130px; height: 130px; flex-shrink: 0; overflow: hidden; background: #f0f0f0; border-radius: 6px; }
.mp-card-img img { width: 100%; height: 100%; object-fit: cover; object-position: center; }
.mp-card-body { flex: 1; min-width: 0; padding: 2px 2px 2px 8px; display: flex; flex-direction: column; justify-content: space-between; }
/* 名称独占一行：不换行、无省略号；代码移至第二行 —— 统一字符间距/行高保证稳定 */
.mp-card-body, .mp-card-body * { -webkit-font-smoothing: antialiased; }
.mp-name-line { display: block; min-width: 0; }
/* ⚠️⚠️ 2026-10-13 小王：「样布库的卡片，**英文情况下不会像中文一样换行，内容直接被吞了**」。
   实测（`.tmp/card_overflow_probe.py`，判据＝`scrollWidth > clientWidth` 且 `overflow≠visible`）：
     · 中文首页 **0/24** 张被吞 ｜ **英文首页 22/24 张**被吞（成分最多溢出 263px）
     · 搜长英文名那批（`?q=200501`）：`.mp-name` 溢出 **187px**，而且**中英文都吞**
       （那条的中文名本身就是一串英文）
   ⇒ 根因是**同一套写法用在三处**：`white-space:nowrap` + `overflow:hidden` + `text-overflow:clip`。
     短内容（中文）看不出问题，长了就**硬切**——`clip` 连省略号都不给，所以是"被吞"不是"被截断"。
   ⇒ 统一改成**允许换行**（＝排不下就往下排，和中文一样），不再靠裁剪。
   ⛔ 这不是"英文专属"问题：**中文里夹英文串的同样中招** ⇒ 不能只在 `is_en` 分支里修。
   ⚠️ 只用老特性（`overflow-wrap` / `:only-child`），不碰 `aspect-ratio`/`min()` 那类（客户机会塌）。 */
.mp-name { font-size: 16px; font-weight: 600; color: #1a1a1a; letter-spacing: .4px; line-height: 1.45; display: block; min-width: 0; overflow-wrap: break-word; }
.mp-code { font-size: 11.5px; color: #999; letter-spacing: .4px; line-height: 1.4; margin: 1px 0 0; }
.mp-specs { margin: 3px 0 0; }
.spec-row { display: flex; align-items: baseline; line-height: 1.5; min-width: 0; }
.spec-label { font-size: 13px; color: #999; flex-shrink: 0; letter-spacing: .25px; }
.spec-value { font-size: 13px; color: #555; margin-left: 5px; letter-spacing: .25px; flex: 1; min-width: 0; word-break: keep-all; }
/* 成分：两个一组整齐换行，完整显示不剪裁 */
.spec-row-comp { align-items: flex-start; }
.comp-grid { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; gap: 2px 5px; }
/* 成分：中文是**多段短词**（`composition_parts` 按空格拆）⇒ 两列排好看；
   英文是**一整串**（"28% Nylon 27% Viscose 23% Acrylic …"，最长 67 字符）——
   原来 `flex: 0 0 calc(50% - 3px)` 把那一整串也钉死在半宽里 ⇒ 只放得下前半截（实测溢出 263px）。
   ⇒ ① 允许折行（不再 nowrap+clip）；② **只有一段时占满整行**（英文/单组分正是这种）。
   ⚠️ 没走"把英文也拆成多段"那条路：英文里 "28%" 和 "Nylon" 中间有空格，
      按空格拆会变成 ['28%','Nylon',…] 四不像（中文的 "90%涤" 才是一个整体）。 */
.comp-item { flex: 0 1 calc(50% - 3px); font-size: 13px; color: #555; letter-spacing: .25px; min-width: 0; overflow-wrap: break-word; }
/* ⚠️⚠️ 下面两条**只在英文下生效**，别挪出来！
   实测教训（2026-10-13）：`comp-item:only-child → flex:1 1 100%` 一旦全局生效，
   中文也中招 —— 中文里有**单组分**的产品（"100%化纤"），它从"半宽"变成"整行"，
   中文首页卡片高度实测 **155 → 180/199**。小王这轮只说"英文被吞"，**中文必须一动不动**。 */
html[lang="en"] .comp-grid > .comp-item:only-child { flex: 1 1 100%; }
/* ⚠️⚠️ 光"允许换行"还不够（见上）——英文**标签本身就把整行吃掉**：
   实测样布库页的卡片只有 **353px**（左侧有筛选栏），`.mp-card-body` 189px，
   而 `Composition：` 一个标签就 **96px** ⇒ 留给成分值只剩 **84px**
   ⇒ 虽然不再被吞，但会折成**一词一行**（难看）。中文标签只有 40px，没这问题。
   ⇒ 英文下把「成分」这一行**改成上下排**：标签独占一行、成分值占满整行（179px）。
   `lang` 由 base.html 按语言给（`<html lang="en">` / `zh-Hans`）⇒ **不用动模板**。 */
html[lang="en"] .mp-card .spec-row-comp { display: block; }
/* 分类标签：`max-height: 24px` ＝**只留一行**。
   ⚠️ 这个"只留一行"**中文是够的**（实测中文各宽度 0 个被剪），**英文不够**（标签更长，
   实测 2/24 张被剪 29px）⇒ 只在英文下放宽到**两行**。
   ⛔ 别直接改上面那条全局值：`max-height: 24px → 53px` 会让中文卡片整体 **+1px**
     （实测 155→156：标签自然高 24.8px，原来是被硬剪 0.8px）——小王这轮只说英文，中文不动。 */
html[lang="en"] .mp-cats { max-height: 53px; }
.mp-cats { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 3px; max-height: 24px; overflow: hidden; }
.mp-cat-tag { flex: 1; text-align: center; font-size: 12px; color: #1a3a5c; background: #e8f0f8; padding: 3px 10px; border-radius: 4px; border: 1px solid #c8d8e8; white-space: nowrap; letter-spacing: .3px; line-height: 1.4; }
.mp-cat-none { color: #999; background: #f2f2f2; border-color: #e0e0e0; }
.no-img { display: flex; align-items: center; justify-content: center; height: 100%; color: #b9b2a4; font-size: 13px; }
.btn {
  display: inline-block; border-radius: 999px; padding: 11px 26px; font-size: 14px;
  letter-spacing: 2px; cursor: pointer; border: 1px solid transparent;
}
.btn-gold { background: var(--gold); color: #fff; }
.btn-gold:hover { background: var(--gold-dark); }
.btn-line { border-color: var(--gold); color: var(--gold-dark); background: var(--card); }
.btn-line:hover { background: var(--gold); color: #fff; }
.btn-wechat { background: #07c160; color: #fff; border: 1px solid #07c160; }
/* 微信二维码弹窗 */
/* ⚠️ z-index 必须 > #privacy-bar 的 9998（那个是 base.html 里的内联样式）。
   实测踩坑（2026-09-27）：原先这里是 100，于是**首次访问的客户**——
   隐私提示条正显示着——点弹窗里的按钮会被它挡住：按钮看得见却点不动，
   微信弹窗的「关闭」和邮件弹窗的按钮都中招。
   原理同 .cart-del 那条注释：fixed 定位 + z-index 更高者胜，与 DOM 顺序无关。 */
.wx-modal { display: none; position: fixed; inset: 0; background: rgba(20,22,28,.55); z-index: 9999; align-items: center; justify-content: center; }
.wx-card { background: #fff; border-radius: 14px; padding: 26px 30px; text-align: center; max-width: 320px; width: 90%; box-shadow: 0 18px 50px rgba(0,0,0,.3); }
.wx-card h3 { margin-bottom: 12px; font-size: 16px; }
/* ⚠️ 2026-09-28 修「二维码不居中」：全局第 20 行有 `img { display: block }`，
   块级元素**不吃 text-align:center** → 二维码贴着左内边距，实测中心偏左 30px
   （正好等于 .wx-card 的 padding-left）。所以这里必须显式 margin:0 auto。
   📌 别去改那条全局 reset —— 它服务全站缩略图/轮播图，动了会波及所有页面。
   实测（1440px 视口）：h3 / tip / 关闭按钮偏差均为 0，唯独 img 偏 -30px，加了这行后为 0。 */
/* ⚠️ 2026-09-30：手机端要"长按二维码"（微信内识别小程序码 / 其他浏览器存图），
   前提是**系统长按菜单能被唤起** —— `-webkit-touch-callout: none` 会让 iOS 上
   长按图片**不出**「存储图像」那一栏。全站目前没人设 none，这里显式写成 default，
   防止将来某条通用 reset（或 `user-select:none` 的连带）把它顺手关掉。 */
.wx-card img { width: 200px; height: 200px; border: 1px solid #e8e8e8; border-radius: 10px; margin: 0 auto;
  -webkit-touch-callout: default; }
.wx-card p { margin: 10px 0 4px; font-size: 14px; }
.wx-tip { color: #888; font-size: 12.5px !important; }
.wx-card .btn { margin-top: 10px; }

/* 微信弹窗：**只有一个二维码**（2026-09-27 小王要求去掉「复制询价」那一套）。
   小程序码本身带着清单，扫进去清单就填好了 —— 官网上再让客户复制一段文本纯属多余。
   于是原来的左右两栏（左二维码 / 右可复制文本）整个删掉，回归 .wx-card 的居中窄卡。 */

/* 小程序码生成中（要调微信接口，1~3 秒）。
   ⚠️ 这里**不能**写 display:none —— JS 是用 `el.style.display = ''` 来显示它的，
      去掉内联声明后会回落到这条规则；这条若也是 none，就永远显示不出来。
      初始隐藏交给 HTML 的 style="display:none"。 */
#wx-qr-loading {
  display: flex; min-height: 200px;
  align-items: center; justify-content: center;
  color: #888; font-size: 12.5px;
}
/* ⛔ 2026-09-29 删掉了 `.wx-qr-link`（手机端"点这里添加"按钮）：
   它用的 /ca/ 型链接实测在手机上**是空白的**（页面去跳 weixin:// scheme，浏览器里跳不动）。
   ⇒ `/ca/` 只适合"在微信客户端里点"，不适合放在网页上。别再加回来，除非先实测确认。 */
/* 提示语按设备分开：手机端**扫不了自己的屏幕**，要给他"长按"这条真能走的路
   （微信内长按＝识别；其他浏览器长按＝存图后到微信扫一扫→相册） */
.tip-mobile { display: none; }
.tip-desktop { display: inline; }
@media (max-width: 640px) {
  /* ⭐⭐ 2026-09-30 小王要求：手机端**也要**那张带清单的小程序码，靠"长按"用起来。
     ⇒ 原先这里的那句 `#wx-mp-qr { display: none !important; }` **已删除**
       （当时理由是"手机端扫不了自己的屏幕" —— 那只对"扫"成立、对"长按"不成立），
       JS 里同一处早退判断（`if (window.innerWidth <= 640) return;`）也一并删了。
     ⚠️ 别再"双保险"式地把它藏回去：藏了手机端就只剩企微兜底码，
        而"长按跳小程序"这条路正是小王要的。 */
  .tip-mobile { display: inline; }
  .tip-desktop { display: none; }
}

/* ═══ 询价单：左侧表格 + 右侧发送面板 ═══ */
.cart-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 18px;
  align-items: start;
}
.cart-main { min-width: 0; }
.cart-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 18px 20px;
  margin-bottom: 18px;
}
.cart-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.cart-card-head h2 { font-size: 16px; margin: 0; display: flex; align-items: center; gap: 8px; }
.cart-hint { font-size: 12px; color: #999; font-weight: normal; }
.cart-badge {
  font-size: 12px; background: #f5f2ea; color: var(--gold-dark);
  border-radius: 10px; padding: 2px 9px; white-space: nowrap;
}
.cart-link { font-size: 13px; color: var(--gold-dark); white-space: nowrap; }
.cart-meters {
  width: 64px; border: 1px solid var(--line); border-radius: 8px;
  padding: 6px 8px; font-size: 14px; text-align: center; vertical-align: middle;
}
.cart-meters:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(197,169,73,.18); }
.cart-del:hover { background: #fdecea; }
.cart-empty-row td { padding: 30px; text-align: center; color: #888; }
.cart-empty-row a { color: var(--gold-dark); }

/* 询价单：样布库同款卡片清单（图+代码名称+成份+克重+门幅+标签+米数） */
.cart-items { display: flex; flex-direction: column; gap: 12px; }
/* 卡片结构（2026-09-12 重排，为的是让缩略图上沿齐产品代码、下沿齐产品分类）：
     .cart-item        块级容器（position:relative 给右上角 ✕ 做定位基准）
     ├ .cart-item-main 横向 flex：左图 + 右文字块，align-items: stretch
     │  ├ .cart-item-img   图片容器：高度跟随同行的文字块
     │  └ .cart-item-text  标题行 + 规格行（含分类）
     └ .cart-item-ctrl 米数行
   图和文字同处 .cart-item-main 这一行且都是 stretch，
   所以图片的上沿天然对齐标题行上沿、下沿天然对齐规格块下沿。 */
.cart-item { position: relative; display: block; background: #fdfcf8; border: 1px solid #f0ead9; border-radius: 12px; padding: 12px; }
.cart-item-main { position: relative; display: flex; gap: 22px; align-items: stretch; }
/* 图片容器：宽度给死（120px，比上一版 100 大），高度交给 align-items: stretch。
   ⚠️ 内部 img 必须【绝对定位】：
      否则 img 自身的固有高度会参与这一行的高度计算，而容器高度又来自 stretch
      → 循环依赖，浏览器只能把百分比高度当 auto 处理，图片失控（上一版就是这么坏的）。
      绝对定位后容器不再被内容撑高，行高完全由右侧文字块决定。 */
.cart-item-img {
  position: relative;
  width: 120px;
  flex-shrink: 0;
  background: #f5f5f5;
  border: 1px solid #eee;
  border-radius: 8px;
  overflow: hidden;
}
.cart-item-img img { position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%; object-fit: cover; }
/* 缩略图可点看原图（lightbox.js 认 .zoomable）；
   屏上这张是 cover 裁成方形的，点开的是 data-full（1000×1000 原图）。
   与 .gallery-main.zoomable 同款光标提示。 */
.cart-item-img img.zoomable { cursor: zoom-in; }
.cart-item-img .c-noimg { position: absolute; top: 0; right: 0; bottom: 0; left: 0; display: flex; align-items: center; justify-content: center; color: #bbb; }

/* ── 已下架/失效的样布（2026-10-16 小王：「图片加上灰蒙版，且加上已下架三字」）──
   ⚠️ 只看**展示层**：购物车是 localStorage 快照，状态由 `/api/fabric-status/` 现查现标。
   ⚠️ 灰蒙版用 ::after 叠在原图上，**不改也不删原图**（数据留着，客户自己决定删不删）；
      下架项同时**不给 .zoomable**，点不出大图（详情页对下架产品本就是 404）。 */
.cart-item--off { background: #f7f7f7; border-color: #e8e8e8; }
.cart-item--off .cart-item-img::after {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0;
  background: rgba(120, 120, 120, 0.55); z-index: 1;
}
.cart-item--off .cart-off-tag {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  z-index: 2; padding: 3px 9px; border-radius: 4px;
  background: rgba(40, 40, 40, 0.82); color: #fff;
  font-size: 12px; line-height: 1.4; white-space: nowrap; letter-spacing: 1px;
}
.cart-item--off .cart-item-top b, .cart-item--off .cart-item-name { color: #9a9a9a; }
/* 顶部提示条：有几个下架/失效 ⇒ 提交会被拦，先告诉客户 */
.cart-warn {
  background: #fff7e6; border: 1px solid #ffd591; border-radius: 8px;
  padding: 10px 12px; margin-bottom: 12px; font-size: 13px; color: #8c5a00; line-height: 1.7;
}
.cart-warn b { color: #c0392b; }
.cart-warn code {
  background: #fff; border: 1px solid #ffd591; border-radius: 3px;
  padding: 0 4px; margin: 0 2px; font-size: 12px; color: #8c5a00;
}
.cart-item-text { flex: 1; min-width: 0; }
/* 标题行右侧留出 ✕ 的位置，免得压住布号 */
.cart-item-top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding-right: 40px; }
.cart-item-top b { font-size: 14px; color: #1a3a5c; }
.cart-item-name { font-size: 13px; color: #555; }
.cart-item-specs { margin-top: 6px; display: flex; flex-direction: column; gap: 3px; font-size: 12.5px; color: #666; }
.cart-spec { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.cart-spec-label { color: #999; flex-shrink: 0; }
.cart-cats { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.cart-cats .mp-cat-tag { font-size: 11px; }
/* 给右下角的「米数」让位：最后一行（通常是分类标签行）右边留出它的宽度，
   免得标签伸过去压到输入框。 */
.cart-item-specs .cart-spec:last-child { padding-right: 118px; }
/* 米数：绝对定位到【主区】右下角 —— 底边与缩略图底边严格齐平
   （缩略图底边又正好是分类行底边）。
   之前它是主区下面单独一行，所以落在图片底边之下，怎么调都差一截。 */
.cart-item-ctrl { position: absolute; right: 0; bottom: 0; display: flex; align-items: center; gap: 8px; }
.cart-item-ctrl .ctrl-label { font-size: 12px; color: #888; }
.cart-empty-row { background: #fff; border: 1px dashed var(--line); border-radius: 12px; padding: 30px; text-align: center; color: #888; font-size: 13px; }
.cart-empty-row a { color: var(--gold-dark); }
/* .section-sub 已随「询价单」页那个浅灰公司名一起删除（2026-09-29 小王：「透明的、无用删掉」）——
   全站只有 cart.html 用它，删掉后成为死规则。需要时可从 git 历史取回。 */
@media (max-width: 560px) {
  /* 窄屏：图与文字改为上下排列。
     ⚠️ 图片容器里唯一的子元素（img）是**绝对定位**、不撑高 ⇒ 这里**必须**给明确高度，
        否则容器塌成 0（2026-09-30 小王报的「卡片崩溃了」就是这么来的）。
     ⚠️⚠️ 剧情记录（别再重犯）：那天先用 `aspect-ratio: 1/1` 做"正方形"，
        在开发机上量着完全正常（259×259），但**小王的客户端不认 aspect-ratio**
        ⇒ 高度彻底没有 ⇒ 容器塌成 2px（只剩边框）⇒ 整个卡片崩溃。
        实测对照（.tmp/cart_crash_repro.py）：`aspect-ratio` 版本 + 模拟"不支持"＝ 259×2；
        下面这个写法 + 模拟"不支持"＝ 259×261（不受影响）。
     ✅ 所以用**最老的写法**：`height:0` + `padding-top:100%`
        （padding 的百分比按**父元素宽度**算）⇒ 宽高恒等、任何浏览器都认、绝不塌。
        ⚠️ 代价：它算的是"父宽"，所以**不能加 max-width 封顶**（加了就不方了）。
     内层 img 是 `inset:0 + width/height:100%` + `object-fit:cover` ⇒ 铺满这个方框。 */
  /* ⚠️⚠️ 2026-09-30 小王报的两条（手机端）：
     ①「X 和样布图片重叠」——✕ 是 `absolute; top:12px; right:12px`，
        桌面端图在左边够不到它；竖排后图变成**满宽**，✕ 就正正压在图右上角
        （实测重叠 21px，按钮才 22px 高 ⇒ 基本全糊上了）。
        ⇒ 给主区顶上留出 ✕ 的高度：`padding-top: 30px` = ✕ 的 22px + 8px 余量。
        ⚠️ 这个 30 与 `.cart-del` 的 `height: 22px` / `top: 12px` 绑定，
           改那两处必须同改这里（`.tmp/cart_mobile_check.py` 的 ① 项会当场红）。
     ②「米数和上面内容的上边距过长」——根因就是下面注释说的
         **`gap` 随 `flex-direction` 变成纵向**（22px）+ 米数行原有 `margin-top`
         ＝ 实测 32px。⇒ `gap: 0` 改由 margin 控，统一成站内竖向刻度 12px（sm12）。
        ⚠️ 用 margin 而不是 `gap: 12px`：**不依赖 flex-gap 特性**，
           老内核上 gap 不生效时也会静默变成 0 间距（图贴着字）。
     ③ 米数本行仍要脱离绝对定位（否则压到文字上），但撤掉 margin-top: 10px。 */
  .cart-item-main { flex-direction: column; gap: 0; padding-top: 30px; }
  .cart-item-text { margin-top: 12px; }
  /* ⚠️ `calc(100% - 2px)`：容器有 `border: 1px`（上下各 1px），
     不减掉的话边框盒会比宽多 2px（实测 259×261）。减掉才是**像素级正方**（259×259）。
     ⚠️ 那个 2px 与上面的 border 宽度绑定 —— 改边框宽度必须同改这里
        （`web_cart_thumb_check.py` 的 ① 项容差是 1px，改歪了会当场红）。 */
  .cart-item-img { width: 100%; height: 0; padding-top: calc(100% - 2px); }
  /* 窄屏下主区变成竖排，米数绝对定位会压到文字上 —— 恢复成正常流的一行，
     并撤掉给绝对定位预留的那段右内边距。
     间距由上一条的 margin-top 统一给 12px（不再 22px gap + 10px margin = 32px）。 */
  .cart-item-ctrl { position: static; margin-top: 12px; }
  .cart-item-specs .cart-spec:last-child { padding-right: 0; }
}

/* 联系信息表单 */
.cart-contacts .c-row { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.cart-contacts .c-row label { width: 90px; flex-shrink: 0; font-size: 13px; color: #555; }
.cart-contacts .c-row input,
.cart-contacts .c-row textarea {
  flex: 1; min-width: 0; max-width: 460px;
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font-size: 13px;
}
.cart-contacts .c-row textarea { min-height: 64px; resize: vertical; }
.cart-contacts .c-row input:focus, .cart-contacts .c-row textarea:focus {
  outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(197,169,73,.18);
}

/* 右侧发送面板（吸顶） */
.cart-side { position: sticky; top: 90px; }
.cart-send {
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  padding: 18px 20px; box-shadow: 0 6px 18px rgba(0,0,0,.05);
}
.cart-send-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 14px; }
.cart-send-head h2 { font-size: 16px; margin: 0; }
.cart-total { font-size: 13px; color: #888; }
.cart-total b { color: var(--gold-dark); font-size: 15px; }
.btn-block { display: block; width: 100%; padding: 11px 0; font-size: 14px; margin-bottom: 10px; text-align: center; }
.btn-block .ico { display: inline-block; vertical-align: middle; margin-right: 7px; }
.btn-danger { color: #c0392b; border-color: #e3cfc7; background: #fff; }
.btn-danger:hover { background: #fdecea; border-color: #c0392b; }
.btn-danger[data-armed="1"] { background: #c0392b; color: #fff; border-color: #c0392b; }
.cart-send-tip { font-size: 12px; color: #999; line-height: 1.7; margin: 8px 0 0; }
.cart-send-tip b { color: #666; }

@media (max-width: 900px) {
  .cart-layout { grid-template-columns: 1fr; }
  .cart-side { position: static; }
}
/* 宽卡片（邮件确认弹窗用；微信弹窗已改成只有一个二维码的窄卡） */
/* 邮件弹窗：加了「一键发送」后有 3 个按钮，400px 有点挤，放宽到 440 */
.wx-card-wide { max-width: 440px; text-align: left; }
.wx-card-wide h3 { margin-bottom: 10px; }
.wx-card-wide .btn { margin-top: 6px; }
/* ⭐ 2026-09-28：联系方式表单搬进邮件弹窗（原先在询价页左侧卡片）
   —— 复用 .cart-contacts 的输入框样式，但弹窗宽度有限，重设外层间距与 label 宽度。
   ⚠️ 别改 .cart-contacts 本身：它仍是询价页表单的样式来源（模板 class 两处共用）。 */
.mail-form { margin: 4px 0 2px; }
.mail-form .c-row { margin-bottom: 8px; gap: 8px; }
.mail-form .c-row label { width: 62px; font-size: 12.5px; }
.mail-form .c-row input,
.mail-form .c-row textarea { max-width: none; font-size: 13px; }
.mail-form .c-row textarea { min-height: 52px; }
.mail-form .req { color: #c0392b; font-weight: 700; }
.mail-send-to { margin: 6px 0 0 !important; }
.mail-form-err {
  display: none; margin: 8px 0 0; padding: 7px 10px; border-radius: 8px;
  background: #fdecea; border: 1px solid #f2c6c0; color: #c0392b;
  font-size: 12.5px; line-height: 1.5;
}
/* 校验未通过时抖动对应输入框 —— 比只显示一行红字更直观（小王偏好"当场看得见"） */
.field-bad { border-color: #c0392b !important; box-shadow: 0 0 0 3px rgba(192,57,43,.15) !important; }
@keyframes lp-shake {
  0%, 100% { transform: translateX(0); }
  20%, 60% { transform: translateX(-4px); }
  40%, 80% { transform: translateX(4px); }
}
.field-bad { animation: lp-shake .36s ease; }
/* 邮件确认弹窗 */
.mail-confirm-preview {
  margin: 8px 0; padding: 10px 12px; max-height: 170px; overflow: auto;
  background: #f8f8f8; border: 1px solid #e8e8e8; border-radius: 8px;
  font-size: 12.5px; color: #555; white-space: pre-wrap; word-break: break-all;
  text-align: left;
}
.mail-confirm-preview:empty { display: none; }
/* 「一键发送」失败时的替代方案提示（2026-09-30）：
   手机上没装/没配邮件 App 时，`mailto:` 被浏览器**静默忽略**（不报错、无回调）
   ⇒ 判定失败后把邮箱直接亮出来，让客户复制清单自己发。
   配色用站内"提示"的黄底金边而不是红色 —— 这不是报错，是给替代路径。 */
.mail-fallback {
  margin: 12px 0 0;
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.75;
  text-align: left;
  color: #7a5b12;
  background: #fff9e8;
  border: 1px solid #f0e2b8;
  border-radius: 8px;
}
.mail-fallback b { color: var(--gold-dark); }
.wx-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 12px; }
.wx-actions .btn { margin-top: 0; }
.wx-actions .btn-plain { background: #fff; border: 1px solid #ddd; color: #666; }
.wx-actions .btn-plain:hover { background: #f2f2f2; }
/* 微信/邮件弹窗的操作按钮：并排靠左。内边距/字距收窄，保证在窄栏里也不折行；
   flex-wrap 兜底 —— 万一将来再加按钮或用户字号放大，宁可换行也不要横向溢出。 */
.wx-actions-left { justify-content: flex-start; flex-wrap: wrap; }
.wx-actions-left .btn { padding: 10px 16px; letter-spacing: 1px; font-size: 13.5px; }
.btn-wechat:hover { background: #06ad56; }
.catalog { display: grid; grid-template-columns: 240px 1fr; gap: 32px; padding: 34px 20px; }
.catalog-side h3 { font-size: 15px; letter-spacing: 2px; margin-bottom: 10px; padding-left: 4px; }
.side-link {
  display: flex; justify-content: space-between; padding: 9px 12px; font-size: 14px;
  border-radius: 8px; color: var(--ink-soft); margin-bottom: 2px;
}
.side-link:hover { background: #f1ece2; color: var(--ink); }
.side-link.on { background: #efe8db; color: var(--ink); font-weight: 600; }
.side-link span { font-size: 12px; }
/* 系列列表：高度按「正好 10 行」算出来，不靠试。
   .side-link 单行高 = 行盒 14px × 1.7(继承 body) = 23.8px ＋ 上下 padding 9×2 = 41.8px，
   再加每条 margin-bottom 2px → 每行实际占 43.8px；10 行 = 438px。
   （原来是 320px ≈ 只露 7 行多。） */
.series-scroll { max-height: 438px; overflow-y: auto; margin-bottom: 6px; }
.side-select { width: 100%; padding: 9px 12px; border: 1px solid var(--line); border-radius: 8px; font-size: 13px; margin-bottom: 14px; background: #fffdf9; }
.side-select:focus { border-color: var(--gold); outline: none; }
.side-filter { margin-bottom: 0; }
/* 搜索联想下拉 */
.side-search, .hero-search { position: relative; }
.suggest-panel { position: absolute; top: 100%; left: 0; right: 0; background: #fff; border: 1px solid #e8e8e8; border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.12); z-index: 40; max-height: 320px; overflow: auto; margin-top: 4px; }
.suggest-item { display: block; padding: 9px 12px; font-size: 13px; color: #333; }
.suggest-item:hover { background: #f5f2ea; }
.suggest-item span { color: #999; margin-left: 8px; }
/* 询盘单 */
.nav-cart span { background: var(--gold); color: #fff; border-radius: 999px; padding: 0 7px; font-size: 11px; margin-left: 4px; }
.cart-add-row { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; align-items: center; }
.cart-add-row input[type="number"] { width: 96px; border: 1px solid var(--line); border-radius: 8px; padding: 9px 10px; font-size: 13px; }
.cart-add-row .cart-unit { font-size: 13px; color: #888; }
.cart-meters { width: 84px; border: 1px solid var(--line); border-radius: 8px; padding: 7px 8px; font-size: 13px; }
.cart-unit { color: #999; font-size: 12px; }
/* ✕：卡片右上角的删除按钮。
   上一版用 padding: 4px 10px → 左右各 10px、上下各 4px，出来是长方形。
   现在宽高都定死 22px（含 1px 边框，全局 * { box-sizing: border-box }），
   line-height = 22 - 上下边框 2 = 20px，再 text-align: center → 字形正好居中。
   right: 12px 与卡片 padding 一致，右边缘和下方「米」的右边缘对齐。 */
.cart-del {
  position: absolute; top: 12px; right: 12px;
  /* ⚠️ z-index 必须有：.cart-item-main 是这个元素的【后一个兄弟】且也是定位元素，
     两者 z-index 都是 auto 时按 DOM 顺序绘制 —— main 会盖在 X 上面。
     main 背景透明，所以 X 看着正常，但点下去命中的是 main，删除按钮就"没反应"。
     2026-09-26 加。 */
  z-index: 1;
  width: 22px; height: 22px; padding: 0;
  border: 1px solid #e6c9c9; background: #fff; color: #c0392b;
  border-radius: 6px; cursor: pointer; font-size: 12px;
  line-height: 20px; text-align: center;
}
/* ═══════════════════════════════════════════════════════════════
   手机端观看体验优化（2026-09-26）
   起因：iPhone 视口体检发现——
   · 样布库侧栏（系列+成分）在窄屏会整段堆在样布【前面】，首屏完全看不到产品
   · 表单控件 33~37px，低于拇指友好的 44px
   · 购物车表单标签在左，窄屏下输入框只剩 ~198px
   ═══════════════════════════════════════════════════════════════ */
.side-toggle { display: none; }        /* 桌面端不显示（侧栏本来就常驻可见） */

@media (max-width: 900px) {
  /* 侧栏默认收起，点「筛选」展开 —— 保证首屏就能看到样布 */
  .catalog-side { display: none; }
  .catalog-side.is-open { display: block; }

  .side-toggle {
    display: flex; align-items: center; gap: 8px;
    width: 100%; min-height: 46px; margin-bottom: 14px; padding: 10px 14px;
    border: 1px solid var(--line); background: #fff; border-radius: 10px;
    font-size: 14px; color: #333; cursor: pointer; text-align: left;
    font-family: inherit;
  }
  .side-toggle .ico { flex-shrink: 0; color: var(--gold-dark); }
  .side-toggle-cur { margin-left: auto; font-size: 13px; color: var(--gold-dark); }
  .side-toggle-chev { margin-left: 8px; color: #bbb; transition: transform .2s; font-size: 12px; }
  .side-toggle[aria-expanded="true"] .side-toggle-chev { transform: rotate(180deg); }
  .side-toggle[aria-expanded="true"] { border-color: var(--gold); }

  /* 表单控件加大到拇指友好（原来 33~37px 偏小，容易点错） */
  .side-search input, .side-search button, .side-select,
  .page-jump input[type="number"], .page-jump button { min-height: 44px; }
  .cart-contacts .c-row input, .cart-contacts .c-row textarea { min-height: 44px; }
  .pagination a, .pagination .page-jump { min-height: 44px; display: inline-flex; align-items: center; }
  .cart-link, .section-more { min-height: 40px; display: inline-flex; align-items: center; }

  /* 购物车表单：窄屏改成「标签在上、输入框占满整行」（原来标签挤在左边） */
  .cart-contacts .c-row { flex-direction: column; align-items: stretch; gap: 6px; }
  .cart-contacts .c-row label { width: auto; }
}

/* 首页分类橱窗 */
.cat-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.cat-tile { background: #fff; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; transition: transform .15s, box-shadow .15s; }
.cat-tile:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0,0,0,.08); }
.cat-tile-imgs { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }
.cat-tile-imgs img { width: 100%; aspect-ratio: 1; object-fit: cover; }
.cat-tile-name { padding: 10px 12px; font-size: 14px; font-weight: 600; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.cat-tile-name span { color: #999; font-weight: 400; font-size: 12px; margin-left: 6px; }
@media (max-width: 900px) { .cat-tiles { grid-template-columns: repeat(2, 1fr); } }
.side-search { display: flex; margin-bottom: 18px; gap: 6px; }
.side-search input { flex: 1; min-width: 0; border: 1px solid var(--line); border-radius: 8px; padding: 9px 12px; font-size: 13px; transition: border-color .15s; }
.side-search input:focus { border-color: var(--gold); outline: none; }
.side-search button { border: 0; background: var(--gold); color: #fff; border-radius: 8px; padding: 9px 14px; font-size: 13px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }
.side-search button:hover { background: var(--gold-dark); }
.filter-bar { margin-bottom: 16px; font-size: 13px; color: var(--ink-soft); display: flex; align-items: center; gap: 6px; }
.filter-tag { background: #efe8db; border-radius: 999px; padding: 4px 12px; }
.filter-tag a { color: var(--warn); margin-left: 4px; }
.pagination { display: flex; gap: 16px; align-items: center; justify-content: center; margin-top: 30px; font-size: 14px; }
.pagination a { color: var(--gold-dark); }
.page-jump { display: inline-flex; align-items: center; gap: 6px; }
.page-jump input[type="number"] { width: 74px; border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; font-size: 13px; text-align: center; }
.page-jump button { border: 0; background: var(--gold); color: #fff; border-radius: 6px; padding: 7px 14px; font-size: 13px; cursor: pointer; white-space: nowrap; }
.page-jump button:hover { background: var(--gold-dark); }

/* ── 详情 ── */
.detail-grid { display: grid; grid-template-columns: minmax(480px, 1.5fr) 1fr; gap: 34px; max-width: 1200px; margin: 0 auto; padding: 26px 16px; align-items: start; width: 100%; transform: translateX(36px); }
.detail-info { min-width: 0; }
/* 详情页图廊：左图右信息（整体居中、宽度由 grid 列约束） */
.detail-gallery { position: relative; background: var(--card); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; width: 100%; }
.gallery-main { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; background: #f5f1e8; }
/* 可点看原图的光标提示（lightbox.js 认 .zoomable）。⚠️ 屏上这张是 cover 裁成方形的，
   原图的完整比例点开才看得到 —— cursor 是唯一不改变布局的"可点"提示。 */
.gallery-main.zoomable { cursor: zoom-in; }
.gallery-thumbs { display: flex; gap: 8px; padding: 10px; border-top: 1px solid var(--line); }
.gallery-thumb { width: 66px; height: 50px; object-fit: cover; object-position: right bottom; border-radius: 6px; cursor: pointer; opacity: .6; border: 2px solid transparent; }
.gallery-thumb.is-on { opacity: 1; border-color: var(--gold); }
.detail-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.detail-code { color: #999; letter-spacing: 1.5px; font-size: 12.5px; }
.detail-name { font-size: 26px; letter-spacing: 2px; margin: 0 0 6px; }
.detail-cats { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
.cat-pill { background: #efe8db; border-radius: 999px; padding: 4px 12px; font-size: 12px; }
.spec-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.spec-table th, .spec-table td { border-bottom: 1px solid var(--line); padding: 10px 8px; text-align: left; }
.spec-table th { width: 84px; color: var(--ink-soft); font-weight: 500; }
.detail-note { color: var(--ink-soft); font-size: 12.5px; margin-top: 14px; }
.no-img-big { height: 420px; font-size: 15px; }

/* ── 页脚 ── */
.site-footer { background: #22262e; color: #cfcbc0; margin-top: 40px; padding-bottom: 8px; }
/* ⚠️ padding-bottom 不是可有可无：两个备案号是页脚的**最后两个子元素**，而最后一个子元素的
   margin-bottom 会与「没有下内边距的父元素」发生**外边距塌陷** —— 那 8px 会跑到深色页脚
   **下方**、露出页面底色。用 padding 才撑得住背景。
   2026-09-29 小王反馈「ICP 上边距太高、公安下边距太短」，实测原为 上16/中8/下2 px，
   调成 上10/中8/下10 px（详见 .tmp/measure_footer.py 的改前后对比）。 */
/* ⚠️ 下内边距 26 → 10 → 4（2026-09-29 小王三轮反馈：「把内边距也算进去、距离缩小」，再「改吧」）：
   这一段**感知距离**其实是「三列内容 → 备案号」= 本内边距 + ICP 行的 margin-top + 行盒余量。
   轨迹：26+4+2 = **32px** → 10+4+2 = **16px** → 4+4+2 = **10px**（与下方「公安→页脚底边」10px 对称）。
   ⇒ 调备案带的间距时**别只调那两行的 margin**，大头一直在这里。 */
.footer-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; padding: 36px 24px 4px; font-size: 13px; }
.footer-grid > div h4 { text-align: center; }
.footer-grid > div { padding: 0 24px; }
.site-footer h4 { color: #fff; font-size: 15px; letter-spacing: 2px; margin-bottom: 10px; }
.site-footer p { margin-top: 6px; }
.site-footer a { color: #e7e0d2; text-decoration: underline; }

/* ── 关于我们 ── */
/* 不加 max-width：与下方「工厂与门市」「联系我们」同宽（占满容器列宽） */
.about-intro {
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  padding: 26px 30px;
}
.about-name { font-size: 20px; font-weight: 700; color: var(--ink); letter-spacing: 2px; margin-bottom: 14px; }
.about-line { font-size: 14px; line-height: 2; color: var(--ink-soft); }

/* 详细介绍分段：小标题 + 正文 */
.about-block { margin-top: 26px; padding-top: 22px; border-top: 1px solid var(--line); }
.about-block:first-of-type { margin-top: 22px; }
.about-h { font-size: 16px; font-weight: 700; color: var(--ink); letter-spacing: 1px; margin-bottom: 10px; }
.about-p { font-size: 14px; line-height: 2.05; color: var(--ink-soft); text-align: justify; }

.about-places { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; margin-bottom: 18px; }
.place-card { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 20px 24px; }
.place-card h4 { font-size: 15px; color: var(--gold-dark); letter-spacing: 2px; margin-bottom: 8px; }
.place-card p { font-size: 14px; line-height: 1.9; color: var(--ink-soft); }

.about-photos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.about-photos figure { margin: 0; background: var(--card); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.about-photos img { width: 100%; height: 180px; object-fit: cover; display: block; }
.about-photos figcaption { font-size: 13px; color: var(--ink-soft); text-align: center; padding: 10px 8px; }

.about-lines { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.line-card {
  display: block; background: var(--card); border: 1px solid var(--line);
  border-radius: 12px; overflow: hidden; text-decoration: none; transition: box-shadow .2s, transform .2s;
}
.line-card:hover { box-shadow: 0 8px 20px rgba(0,0,0,.09); transform: translateY(-2px); }
.line-card img { width: 100%; height: 150px; object-fit: cover; display: block; }
.line-body { display: block; padding: 12px 14px 14px; }
.line-name { display: block; font-size: 15px; font-weight: 600; color: var(--ink); }
.line-count { display: block; font-size: 12px; color: #9a9a9a; margin-top: 4px; }

/* 联系我们：每行 3 个、共 2 排（6 项）；不设 max-width，与上方「工厂与门市」同宽
   ⚠️ `align-items: start` 不能省：企业微信那张卡里有一张二维码，卡片自然更高；
      默认 `stretch` 会把同一排的「联系人」「电话」两张卡一起拉高，
      下方留一大片空白（2026-09-29 加二维码时踩到）。 */
.about-contact { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px 14px; align-items: start; }
.contact-item { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 14px 18px; }
.contact-label { display: block; font-size: 12px; color: #9a9a9a; letter-spacing: 1px; margin-bottom: 4px; }
.contact-value { display: block; font-size: 15px; color: var(--ink); }
.contact-value a { color: var(--gold-dark); }
/* 待配置占位：虚线 + 灰字，一眼看出「这里还没填」而不是坏了 */
.contact-todo { color: #b0b0b0; border-bottom: 1px dashed #d6d0c4; padding-bottom: 1px; }

/* 「关于我们」页的企业微信二维码（老板渠道）
   ⚠️ 必须 `display:block` —— `<img>` 默认是 inline，会和后面的提示文字挤在同一行盒里，
      且行盒在元素内部留看不见的空隙（本项目在 textarea 上踩过同一个坑）。 */
/* 「关于我们」页企业微信那一栏：只放一个「点击查看」，二维码在弹窗里（2026-09-29 小王要求）。
   ⚠️ 是 `<button>` 不是 `<a>` —— 严格 CSP 会拦掉 `javascript:` 的 href，
      所以样式要手动还原成"看起来像链接"（全局 `a { text-decoration: none }`，
      这里用 hover 下划线给可点的提示）。
   原先的 `.about-qr` / `.about-qr-link` / `.about-qr-tip` 已随之删除：
   二维码改由弹窗渲染，走的是 `.wx-card img`（200×200 居中）那套现成样式。 */
.about-qr-open { background: none; border: none; padding: 0; font: inherit;
                 font-size: 15px; color: var(--gold-dark); cursor: pointer; }
.about-qr-open:hover { text-decoration: underline; }

/* ── 响应式 ── */
@media (max-width: 1024px) {
  .fabric-grid { grid-template-columns: repeat(2, 1fr); }
  .about-lines { grid-template-columns: repeat(2, 1fr); }
  /* 平板/手机回到小程序原尺寸 */
  .mp-card { padding: 4px; gap: 6px; min-height: 118px; }
  .mp-card-img { width: 110px; height: 110px; }
  .mp-card-body { padding: 2px 2px 2px 6px; }
  .mp-name { font-size: 14px; }
  .mp-code { font-size: 10.5px; margin: 0; }
  .spec-label, .spec-value { font-size: 11px; }
  .mp-cat-tag { font-size: 10px; padding: 2px 8px; }
  /* 英文放宽到两行（同桌面那条；这里标签是小号 ⇒ 一行约 20px，两行 + 间隙 = 43px）。
     中文保持原来的 20px 不动。 */
  html[lang="en"] .mp-cats { max-height: 43px; }
  .mp-cats { max-height: 20px; }
}
@media (max-width: 900px) {
  .catalog, .detail-grid { grid-template-columns: 1fr; }
  /* ⚠️ 必须复位桌面上那句 `transform: translateX(36px)`（见 .detail-grid 定义处）：
     它的理由是「左图列 180 / 右侧信息贴近右缘，视觉偏右饱满」—— **只对两列布局成立**。
     变成一列后还右移 36px，就等于把内容推出屏幕：实测 390 视口下
     网格 right=411 > 视口 390 ⇒ **右侧被切 21px，手机还能横向拖动**（2026-09-29 修）。
     桌面端不受影响（1440 下仍是 左留白 149 / 右留白 92 的偏右饱满观感）。 */
  .detail-grid { transform: none; }
  .footer-grid { grid-template-columns: 1fr; }
  .about-places { grid-template-columns: 1fr; }
  .about-photos { grid-template-columns: repeat(2, 1fr); }
  .about-contact { grid-template-columns: repeat(2, 1fr); }

  /* ── 手机端导航：改成「品牌行 + 导航行」两行常驻，不再用汉堡下拉 ──
     ⚠️ 为什么改（2026-09-28 小王反馈"左右滑动时导航跟着动、露出空白"）：
       原方案是 .nav-burger 点开的 absolute 下拉菜单。它有两个毛病：
       ① absolute 定位不受 sticky 约束 → 滑动时跟着页面跑、露白
       ② 每次看导航都得点一下 ☰
     ✅ 改成常驻横排：随 .site-header 一起 sticky 固定，一屏看全、零点击。
     实测导航 5 项文字总宽 258px，最窄手机(320px)减掉内边距仍有 280px → 放得下。 */
  .header-inner {
    height: auto; flex-wrap: wrap;
    padding-top: 8px; padding-bottom: 0;
  }
  .brand { flex: 1 1 100%; gap: 10px; }      /* 品牌独占第一行 */
  .brand-logo { width: 38px; height: 38px; } /* 手机端略收，避免头部长太高 */
  .brand-cn { font-size: 18px; }
  .brand-en { font-size: 11.5px; }
  .nav-burger, .nav-toggle { display: none; } /* 常驻横排后彻底不需要汉堡 */

  .site-nav {
    /* 覆盖桌面端的横排间隙与手机端原先的下拉定位 */
    display: flex; position: static; flex-direction: row;
    flex: 1 1 100%;
    gap: 0;
    justify-content: space-between;   /* 5 项均分，不挤也不溢 */
    padding: 2px 0 0;
    background: transparent; border-bottom: 0; border-top: 0;
    margin-top: 8px;
  }
  .site-nav a { padding: 10px 0; font-size: 14px; letter-spacing: 0; }
  /* 下划线收进链接自己的下留白内（原 bottom:-6px 是给无 padding 的桌面端算的） */
  .site-nav a.on::after { bottom: 4px; }
  /* 「中文」原本是描边胶囊，横排下换成和其他项一致的纯文字，避免一行里高低不齐 */
  .site-nav .nav-cta {
    border: 0; padding: 10px 0; border-radius: 0;
    color: var(--ink-soft); font-size: 14px;
  }
  .site-nav .nav-cta:hover, .site-nav .nav-cta.on { background: transparent; color: var(--ink); }

  .hero-inner { height: 400px; }
  .hero-sub { font-size: 13px; letter-spacing: 1px; }   /* 副标题：手机端不宜过大 */
  .hero-info { left: 20px; bottom: 120px; }
  /* 搜索框：窄屏把按钮内边距与字间距收紧 —— 既保证「查布料」一行放得下，
     也给输入框留出更多位置（placeholder 之前被截成「…如 GX3」）。 */
  .hero-search button { padding: 0 16px; letter-spacing: 1px; }
}

/* 超窄屏（320px 一类）：再降一档字号，留出安全余量 */
@media (max-width: 360px) {
  .site-nav a, .site-nav .nav-cta { font-size: 13px; }
  .brand-cn { font-size: 17px; }
}

/* 手机端：一行一张（同小程序） */
@media (max-width: 620px) {
  .fabric-grid { grid-template-columns: 1fr; }
  /* 手机端首页「最新上架」只显示前 4 张（小王 2026-09-29）。
     ⚠️ 为什么用 CSS 而不是让视图少渲染：home 视图有 @cache_page(60)，
        若按 UA 给不同条数，**手机渲染的结果会被缓存后喂给桌面访客**（反之亦然）。
        CSS 隐藏与缓存无关，也不需要 UA 嗅探。
     ⚠️ 隐藏的卡片**不会真的下载图片**：卡片 img 带 loading="lazy"，
        而 display:none 的元素没有布局盒、永不进入视口 ⇒ 不浪费手机流量。
     桌面仍渲染 9 张（3 列三整行）。 */
  .section-latest .fabric-grid .mp-card:nth-child(n+5) { display: none; }
  .about-lines { grid-template-columns: 1fr; }
  .about-photos { grid-template-columns: 1fr; }
  .about-contact { grid-template-columns: 1fr; }
  .about-intro { padding: 20px 18px; }
  .hero-inner { height: 340px; }
  .hero-inner { width: calc(100% - 32px); }
  .hero-info { bottom: 110px; }
}