/* ==========================================================================
   臻格智能锁 ZGLock — 全站唯一设计系统
   纯静态站点：HTML + CSS + 原生 JS。无构建工具、无框架、无外链资源。

   目录
     1. 设计令牌
     2. 基础重置与排版
     3. 栅格与容器
     4. 区块与页头
     5. 按钮与链接
     6. 产品图「切轮廓」.shot
     7. 等宽接口路径 .endpoints
     8. 代码块 .code
     9. 卡片与组件
     10. 网格底纹与 hero
     11. 页头 site-header
     12. 页脚 site-footer
     13. 滚动渐显与关键帧
     14. 工具类
     15. 断点
   ========================================================================== */


/* ==========================================================================
   1. 设计令牌
   ========================================================================== */

:root {
  /* 底色层级：由深到浅承担层级差，全站不用饱和色 */
  --bg-0: #08080A;
  --bg-1: #101013;
  --bg-2: #17171B;
  --bg-3: #202025;

  /* 描边两级 + 发光描边（仅用于 cap-card 内描边） */
  --line: rgba(255, 255, 255, .08);
  --line-hi: rgba(255, 255, 255, .16);
  --glow: rgba(255, 255, 255, .10);

  /* 文字三级 */
  --text-1: #F5F5F7;
  --text-2: #A1A1A6;
  --text-3: #6E6E73;

  /* 按钮与代码块底 */
  --btn-fg: #08080A;
  --btn-bg: #F5F5F7;
  --code-bg: #0C0C0F;

  /* 品牌强调色：取自商标 logo 实测主色 #2AA2DD（logo 中占比 14.4% 的浅蓝）。
     全站唯一的饱和色。灰度底 + 单一强调色是深色科技风的稳妥配比，
     大面积铺色会失去克制感，故按「中等力度」控制覆盖面积：
       按钮、箭头链接、章节标记 .u-eyebrow、型号名 .card-model、
       标签选中态、卡片悬停描边、产品图背后冷光
     注意：--accent-ink 是强调色块上的文字色，用深墨而非纯黑，避免生硬。 */
  --accent: #2AA2DD;
  --accent-hi: #4FB8E8;
  --accent-ink: #071218;
  --accent-soft: rgba(42, 162, 221, .14);
  --accent-line: rgba(42, 162, 221, .45);

  /* 字体 */
  --font-sans: "PingFang SC", "HarmonyOS Sans SC", "Source Han Sans SC",
    "Noto Sans SC", "Microsoft YaHei", -apple-system, system-ui, sans-serif;
  --font-mono: "SF Mono", "JetBrains Mono", "Roboto Mono", ui-monospace,
    Menlo, Consolas, "Courier New", monospace;

  /* 字号 */
  --fs-display: clamp(34px, 5.2vw, 64px);
  --fs-h2: clamp(24px, 2.8vw, 38px);
  --fs-h3: clamp(19px, 1.5vw, 23px);
  --fs-lead: clamp(15px, 1.1vw, 18px);
  --fs-body: 15px;
  --fs-sm: 13px;
  --fs-xs: 12px;

  /* 间距：只用 4px 基数刻度 */
  --s-1: 4;
  --s-2: 8;
  --s-3: 12;
  --s-4: 16;
  --s-5: 24;
  --s-6: 32;
  --s-8: 48;
  --s-10: 64;
  --s-12: 80;
  --s-16: 128;

  /* 固定页头高度：.header-inner 是 72px + 1px 下边框 = 73px（各断点实测一致）。
     首屏要「刚好占满页头以下的整个视口」就得减掉它 —— 见 .hero 的 min-height。 */
  --header-h: 73px;

  /* 圆角 */
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 16px;
  --r-pill: 999px;

  /* 浮层投影：只用于抽屉等浮层 */
  --shadow-pop: 0 24px 60px rgba(0, 0, 0, .55);
}


/* ==========================================================================
   2. 基础重置与排版
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* 固定页头高度，锚点滚动不被遮挡 */
  scroll-padding-top: 88px;
  /* 双保险：抽屉关闭态仍在布局上（靠 transform 移到视口右侧），
     用 clip 而非 hidden —— overflow:hidden 会让 html 变成滚动容器，
     从而破坏页头 position:sticky 的「相对视口吸附」；clip 不建立滚动容器 */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.8;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -.01em;
}

p {
  margin: 0;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

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

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

.mono,
.u-mono {
  font-family: var(--font-mono);
  letter-spacing: .02em;
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.75;
  color: var(--text-2);
}


/* ==========================================================================
   3. 栅格与容器
   mobile <768px：4 列 / gap16 / 左右 20px
   tablet ≥768px：8 列 / gap24 / 左右 32px
   desktop ≥1180px：12 列 / gap24 / max-width 1240px / 左右 40px
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: 1240px;
  margin: 0 auto;
  padding-left: 20px;
  padding-right: 20px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

/* 手机档：跨列类统一全宽 */
.col-4,
.col-6,
.col-8,
.col-12,
.col-md-4,
.col-md-6,
.col-md-8 {
  grid-column: 1 / -1;
}

/* 卡片网格：需要严格等宽等高时使用（产品线、场景入口） */
.grid--cards,
.grid--4 {
  grid-template-columns: minmax(0, 1fr);
}

/* 两列网格：用于半栏内的条目（如开锁方式 6 项），避免 4 列挤压导致每列过窄 */
.grid--pairs {
  grid-template-columns: minmax(0, 1fr);
}

/* 五列网格：联网方式 5 项排成整齐一行，避免末行落单 */
.grid--five {
  grid-template-columns: minmax(0, 1fr);
}

/* 门锁网格：9 个型号（3 列 ×3 行） */
.grid--locks {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* 接入方式卡：桌面 4 列且必须等高，故用 grid 的默认 stretch 对齐 */
.path-grid {
  grid-template-columns: minmax(0, 1fr);
}

/* 方案框架卡 */
.frame-grid {
  grid-template-columns: minmax(0, 1fr);
}

/* 方案框架四模块：桌面一行四列，模块数由 3 增至 4 */
.frame-grid--four {
  grid-template-columns: minmax(0, 1fr);
}

/* 设备能力四类 */
.ability-grid {
  grid-template-columns: minmax(0, 1fr);
}


/* ==========================================================================
   4. 区块与页头
   区块纵向 padding：紧凑 80/64/48、主块 112/80/56、hero 128/88/64
   （桌面 / 平板 / 手机，由 §15 断点覆写）
   ========================================================================== */

.sect {
  padding: calc(var(--s-12) * 1px) 0 calc(var(--s-10) * 1px);
  background: var(--bg-0);
}

.sect--alt {
  background: var(--bg-1);
}

.sect--tight {
  padding: calc(var(--s-10) * 1px) 0 calc(var(--s-8) * 1px);
}

.sect--hero {
  padding: calc(var(--s-16) * 1px) 0 calc(var(--s-12) * 1px);
  background: var(--bg-0);
}

/* 区块头：等宽序号 + 标题 + 说明 */
.sect-head {
  margin-bottom: calc(var(--s-8) * 1px);
  max-width: 720px;
}

.sect-head .u-eyebrow {
  margin-bottom: calc(var(--s-3) * 1px);
}

.sect-head h2 {
  font-size: var(--fs-h2);
  margin-bottom: calc(var(--s-3) * 1px);
}

.sect-head p {
  color: var(--text-2);
  font-size: var(--fs-lead);
  line-height: 1.75;
}

.page-head {
  padding: calc(var(--s-12) * 1px) 0 calc(var(--s-10) * 1px);
  background: var(--bg-0);
}

.page-head .u-eyebrow {
  margin-bottom: calc(var(--s-3) * 1px);
}

.page-head h1 {
  font-size: var(--fs-display);
  margin-bottom: calc(var(--s-4) * 1px);
}

.page-head p {
  color: var(--text-2);
  font-size: var(--fs-lead);
  line-height: 1.75;
  max-width: 680px;
}


/* ==========================================================================
   5. 按钮与链接
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 calc(var(--s-5) * 1px);
  border-radius: var(--r-pill);
  font-size: var(--fs-body);
  font-weight: 500;
  border: 1px solid transparent;
  transition: background-color .2s ease, border-color .2s ease;
}

.btn--primary {
  background: var(--accent);
  color: var(--accent-ink);
}

.btn--primary:hover {
  background: var(--accent-hi);
}

.btn--ghost {
  border-color: var(--accent-line);
  color: var(--accent);
  background: transparent;
}

.btn--ghost:hover {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-hi);
}

/* 文字箭头链接：下划线由 border 实现，不使用任何文字投影属性 */
.arrow-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--fs-body);
  color: var(--accent);
  border-bottom: 1px solid var(--accent-line);
  transition: color .2s ease, border-color .2s ease;
}

.arrow-link:hover {
  color: var(--accent-hi);
  border-color: var(--accent);
}


/* ==========================================================================
   6. 产品图「切轮廓」.shot

   ▉ 实测结论（改动前必读，勿随意调整取值）
   --------------------------------------------------------------------------
   设计规格原假设「素材是黑底图，用 mix-blend-mode:lighten 让黑底消失」。
   对 public/assets 全部素材逐张采样像素后，结论与假设相反：

     · 除 智慧电表.webp 外均为「白底图」：四角与四边中位亮度均为 255
     · 仅 智慧电表.webp 为黑底图

   ── 第一阶段（已废弃的方案 D，保留记录以免重蹈） ──
   曾用 grayscale + invert 把白底反成黑底。副作用是整张图连同产品一起反相：
   9 个门锁型号的原图机身实测为深灰/黑（#1C1C1C ~ #4C4C4C），反相后被显示成
   银白色 —— 即「黑锁被显示成白锁」，属产品呈现失真；智慧水表原图的浅蓝灰
   表体（#A5B1C8）也被去色。该方案已废弃。

   ── 第二阶段（当前采用）：CSS 前真实抠底，保留产品本色 ──
   素材已在入站前完成处理：从画面四边对近白像素做洪泛填充（阈值 min(RGB)≥212），
   仅清除与边缘连通的背景，产品内部的白色高光不受影响；alpha 边缘做 0.7px
   高斯羽化以消除锯齿。结果输出为带 alpha 的 WebP（RGB → RGBA）。
   因此 .shot img 不再需要任何滤镜与混合模式，产品以真实颜色呈现。

   深色台：产品本色偏暗（门锁近黑），若底板也是近黑则轮廓不可读。故 .shot 的
   径向光晕由「纯白 13%」改为「冷调浅蓝白 20%」，在深色页面上形成一块柔和的
   受光台面，深色机身以剪影方式读出，同时给画面带一点品牌色温。
   ========================================================================== */

.shot {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  overflow: hidden;
  height: var(--shot-h, 216px);
  background:
    radial-gradient(58% 46% at 50% 44%,
      rgba(214, 236, 250, .20) 0%,
      rgba(160, 196, 220, .07) 42%,
      rgba(160, 196, 220, 0) 74%),
    var(--bg-2);
}

/* 产品图品牌水印：每张产品 / 场景图的右上角打一枚「ZG 云标 + 臻格」，强化品牌。
   ▉ 为什么另做一张 zclock-logo-watermark.png，而不是在 CSS 里复用 zclock-logo-crop.png：
   logo 原图是「白底 + 黑字 + 蓝标」，页头与首屏铭牌靠 invert(1) hue-rotate(180deg)
   把白底反成黑底、再借 mix-blend-mode: screen 让黑底隐形。但 screen 混合在**浅色区域上
   会把水印整片洗掉**（白字压在白色产品上完全不可见，实测智慧电表、人脸照片等都会踩到）。
   故离线生成水印图：alpha 取墨量、整体染成品牌蓝 --accent。
   实测深底(#17171B) / 浅色产品(#CDCDD2) / 中间调照片三种底色下均清晰可读。
   ▉ 尺寸用 clamp(36px, 18%, 70px) 跟随容器宽度自适应：桌面卡 369px → 66px（高 18.5px），
   手机卡 159px → 36px，about 大图 416px → 70px（封顶）。用 aspect-ratio 保持 640:179 原始比例。
   ▉ 为什么跳过 .shot--bare 与 .cat-lead-shots：
   前者是首屏大图，产品下方已有 .ac-brand 铭牌，再叠一枚 = 同一画面两个 logo；
   后者是门锁主卡里的缩略图（实测 82~175px），水印会吃掉三成宽度。
   ▉ 不设 opacity：这张图是真 alpha，不需要靠透明度压暗；半透明只会让 18px 高的细笔画发灰。 */
.shot::after {
  content: "";
  position: absolute;
  top: 9px;
  right: 11px;
  width: clamp(36px, 18%, 70px);
  aspect-ratio: 640 / 179;
  background: url("public/assets/zclock-logo-watermark.png") center / contain no-repeat;
  pointer-events: none;
  z-index: 2;
}

.shot--bare::after,
.cat-lead-shots .shot::after {
  display: none;
}

/* 素材已带 alpha 通道且为真实颜色，故不施加任何滤镜与混合模式 */
/* 图片四边内缩 4%，用绝对定位把尺寸钉死。
   ⚠️ 历史 Bug（用户报「很多图片没有显示完整」）：这里原来是 width/height:82%，
   但在 grid 容器里 img 的高度百分比无法对 auto 行求解，Chrome 改用图片自身
   宽高比推出高度（实测 301×244，而容器只有 369×200），配合 .shot 的
   overflow:hidden ⇒ **图片上下被裁掉**。填充率实测最高到 289%（自动锁 LD101），
   只看得见中间一条。改成绝对定位 + left/top/width/height 全给死值后，
   图片盒永远等于容器的 92%，object-fit:contain 才能真正把整张图放进来。 */
.shot img {
  position: absolute;
  left: 4%;
  top: 4%;
  width: 92%;
  height: 92%;
  object-fit: contain;
  animation: float 12s ease-in-out infinite;
}

/* 关于页大图：4:5 竖幅。现仅供 about.html 使用（首屏改用 .shot--bare 的裁剪窗） */
.shot--hero {
  --shot-h: 420px;
  aspect-ratio: 4 / 5;
}

.shot--hero img {
  width: 86%;
  height: 86%;
}

/* 首屏产品：从 DS402 正反拼图中裁出「正面单锁」，落在暗场光锥正中央。
   .shot--bare 在首屏不再自成卡片，而是舞台内的一个绝对定位「裁剪窗」：
   尺寸由首屏舞台给定（高度 74%、单锁比例 750:1485，见第 18 节），
   受光台面由舞台的 .ac-pool 承担，故此处不加底色与描边。 */
.shot--bare {
  position: absolute;
  left: 50%;
  top: 41%;
  transform: translate(-50%, -50%);
  width: auto;
  /* 原图是「正面 + 背面」两个面板并排（1500×1485）。用户明确要求两面都要在，
     故不再裁剪取单边，aspect-ratio 用整图比例，max-width 兜住窄屏不溢出；
     一旦 max-width 生效，img 的 object-fit:contain 会让整图等比缩小居中，不会被切 */
  max-width: 90%;
  height: 66%;
  aspect-ratio: 1500 / 1485;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: none;
}

/* 裁「正面单锁」：DS402.webp 为「左背面 + 右正面」并排拼图（1500×1485）。
   裁剪窗按单把锁的比例 750:1485 设置；图片放大到 200% 宽后再左移 101%，
   视窗内恰好只余右半幅 —— 带键盘与指纹环手柄的正面锁。
   ⚠ 该裁剪只作用于 .shot--bare；about.html 用的是 .shot--hero（同一张素材），
   不受影响。悬浮微动效沿用 .shot img 的 float，此处不重复声明。 */
.shot--bare img {
  position: static;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* 现场照片：3:5 竖幅。素材已抠底，保留真实颜色，仅轻微压暗以免抢占视觉重心 */
.shot--tall {
  --shot-h: 420px;
  aspect-ratio: 3 / 5;
}

.shot--tall img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: brightness(.94) contrast(1.04);
  animation: none;
}

/* 智慧电表原为原生黑底素材，现已与其他素材同样抠底转透明，保留类名仅为兼容既有引用 */
.shot--native img {
  object-fit: contain;
}


/* ==========================================================================
   7. 等宽接口路径 .endpoints
   全站复用：index hero、index 配套设备能力行、open-platform 页
   ========================================================================== */

.endpoints {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
  list-style: none;
  padding: 0;
  margin: 0;
}

.endpoint {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: .02em;
  color: var(--text-2);
  background: var(--code-bg);
  border: 1px solid var(--line);
  border-left: 2px solid var(--line-hi);
  border-radius: var(--r-sm);
  padding: 6px 10px;
  white-space: nowrap;
}

/* 方法词只用三级灰阶区分，禁止用颜色区分 */
.endpoint b {
  color: var(--text-1);
  font-weight: 500;
}

.endpoint em {
  color: var(--text-3);
  font-style: normal;
}


/* ==========================================================================
   8. 代码块 .code
   全站总数 ≤ 3 块；灰阶手工 span 高亮，不引第三方高亮库、不引外链
   ========================================================================== */

.code {
  background: var(--code-bg);
  border: 1px solid var(--line);
  border-left: 2px solid var(--line-hi);
  border-radius: var(--r-md);
  padding: 20px 22px;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.75;
  color: var(--text-2);
  white-space: pre;
  margin: 0;
}

.code .k {
  color: var(--text-1);
}

.code .s {
  color: var(--text-2);
}

.code .c {
  color: var(--text-3);
}


/* ==========================================================================
   9. 卡片与组件
   卡片 hover 只做底色 + 描边变化，禁止位移 / 缩放 / 发光
   ========================================================================== */

.pcard {
  display: flex;
  flex-direction: column;
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: background-color .2s ease, border-color .2s ease;
}

.pcard:hover {
  background: var(--bg-2);
  border-color: var(--accent-line);
}

.pcard-body {
  padding: calc(var(--s-4) * 1px);
  display: flex;
  flex-direction: column;
  gap: calc(var(--s-2) * 1px);
}

.card-model {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: .06em;
  color: var(--accent);
}

.card-name {
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.4;
}

.card-open {
  font-size: var(--fs-sm);
  color: var(--text-2);
}

.card-diff {
  font-size: var(--fs-sm);
  color: var(--text-3);
}

/* 中性说明行 */
.note-line {
  margin-top: calc(var(--s-5) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

/* 开锁方式条目 */
.method-item {
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-0);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: background-color .2s ease, border-color .2s ease;
}

.method-item:hover {
  background: var(--bg-2);
  border-color: var(--accent-line);
}

.method-item h3 {
  font-size: var(--fs-body);
  font-weight: 600;
  margin-bottom: calc(var(--s-2) * 1px);
}

.method-item p {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.7;
}

/* 管理系统主卡：网格底纹 + 1px 发光描边（底纹定义见 §10） */
.cap-card {
  position: relative;
  padding: calc(var(--s-8) * 1px);
  background-color: var(--bg-1);
  border: 1px solid var(--line-hi);
  border-radius: var(--r-lg);
  box-shadow: inset 0 0 0 1px var(--glow);
  overflow: hidden;
}

.cap-group {
  padding-bottom: calc(var(--s-5) * 1px);
  margin-bottom: calc(var(--s-5) * 1px);
  border-bottom: 1px solid var(--line);
}

.cap-group:last-child {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: 0;
}

.cap-group h3 {
  font-size: var(--fs-body);
  font-weight: 600;
  margin-bottom: calc(var(--s-3) * 1px);
}

.cap-group li {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.9;
}

/* 开放接入条目 */
.cap-item {
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: background-color .2s ease, border-color .2s ease;
}

.cap-item:hover {
  background: var(--bg-2);
  border-color: var(--accent-line);
}

.cap-item h3 {
  font-size: var(--fs-body);
  font-weight: 600;
  margin-bottom: calc(var(--s-2) * 1px);
}

.cap-item p {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.7;
}

/* 场景卡：四张等宽等高，尺寸完全一致 */
.scene-card {
  display: flex;
  flex-direction: column;
  padding: calc(var(--s-6) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: background-color .2s ease, border-color .2s ease;
}

.scene-card:hover {
  background: var(--bg-2);
  border-color: var(--accent-line);
}

.scene-card h3 {
  font-size: var(--fs-h3);
  font-weight: 600;
  margin-bottom: calc(var(--s-3) * 1px);
}

.scene-card p {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.75;
  margin-bottom: calc(var(--s-5) * 1px);
}

/* 尾部 CTA */
.cta-tail {
  padding: calc(var(--s-12) * 1px) 0;
  background: var(--bg-1);
  text-align: center;
}

.cta-tail h2 {
  font-size: var(--fs-h2);
  margin-bottom: calc(var(--s-4) * 1px);
}

.cta-tail p {
  color: var(--text-2);
  max-width: 560px;
  margin: 0 auto calc(var(--s-6) * 1px);
}

/* 徽标 */
.badge {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 0 calc(var(--s-3) * 1px);
  border: 1px solid var(--line-hi);
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .06em;
  color: var(--text-2);
}

/* 表格（后续页面复用） */
.matrix {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.matrix th,
.matrix td {
  padding: calc(var(--s-3) * 1px) calc(var(--s-4) * 1px);
  border-bottom: 1px solid var(--line);
  text-align: left;
  color: var(--text-2);
}

.matrix th {
  color: var(--text-1);
  font-weight: 500;
}

/* 标签页（solutions.html 使用，切换逻辑见 site.js） */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--s-2) * 1px);
  border-bottom: 1px solid var(--line);
  margin-bottom: calc(var(--s-6) * 1px);
}

.tab {
  min-height: 44px;
  padding: 0 calc(var(--s-4) * 1px);
  color: var(--text-3);
  border-bottom: 2px solid transparent;
  transition: color .2s ease, border-color .2s ease;
}

.tab:hover {
  color: var(--text-2);
}

.tab.is-selected {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* 通用内容卡（后续页面复用） */
.path-card,
.frame-item,
.gain-item,
.pain-item,
.case-item,
.ability-card,
.support-col,
.step-item,
.tree-item {
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.75;
}

.path-card h3,
.frame-item h3,
.gain-item h3,
.pain-item h3,
.case-item h3,
.ability-card h3,
.support-col h3,
.step-item h3,
.tree-item h3 {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-1);
  margin-bottom: calc(var(--s-2) * 1px);
}

/* 卡片内的次级小标题（.frame-item 等的「一句功能名中英双写」） */
.item-lead {
  display: block;
  margin-bottom: calc(var(--s-2) * 1px);
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-1);
}

.item-en {
  display: block;
  margin-bottom: calc(var(--s-3) * 1px);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .06em;
  color: var(--text-3);
}

/* 卡片内的加粗利益点 */
.item-gain {
  margin-bottom: calc(var(--s-2) * 1px);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-1);
}


/* ==========================================================================
   9b. 第二轮新增组件
   ========================================================================== */

/* ---- 标签：联网方式 / 型号等一行小标签 ---- */
.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--s-2) * 1px);
  margin-top: calc(var(--s-4) * 1px);
}

.tag {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 0 calc(var(--s-3) * 1px);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--code-bg);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .04em;
  color: var(--text-2);
}

/* ---- 产品图比例变体：仪表类与采集器 ---- */
/* 计量行三张卡必须等高（用户报电表与水表不平齐）：统一用 .shot--meter */
.shot--meter {
  --shot-h: 250px;
}

.shot--device {
  --shot-h: 180px;
  aspect-ratio: 1 / 1;
}

/* 说明：仪表类与采集器图片不再单独覆盖尺寸。
   ⚠️ 这里曾有一条 `.shot--meter img, .shot--meter-tall img, .shot--device img
   { width:80%; height:80% }` —— 它的权重（0,2,0）高于基类 `.shot img`（0,1,1），
   会覆盖掉基类的绝对定位（left/top:4%），使仪表图片退回静态位置、不居中。
   现在统一由 `.shot img`（绝对定位 + 四边内缩 4%）负责，任何变体都不要再改 img 的尺寸。 */

/* ---- 区块内的分节标题（用于方案五段式、开放平台各区块） ---- */
.sub-head {
  margin-bottom: calc(var(--s-5) * 1px);
}

.sub-head .u-eyebrow {
  margin-bottom: calc(var(--s-2) * 1px);
}

.sub-head h3 {
  font-size: var(--fs-h3);
  font-weight: 600;
}

/* 方案五段式：段与段之间靠留白与序号切分，不用分割线 */
.tsection {
  padding-bottom: calc(var(--s-10) * 1px);
}

.tsection:last-child {
  padding-bottom: 0;
}

.tsection > .sub-head {
  margin-bottom: calc(var(--s-5) * 1px);
}

/* ---- 标签页：sticky 顶栏，吸附在页头下方 ----
   注：此处不使用毛玻璃模糊（全站仅 header 与移动抽屉两处允许），
   改用不透明实色底，避免内容透出即可。 */
.tabs--sticky {
  position: sticky;
  top: 72px;
  z-index: 40;
  background: var(--bg-0);
  margin-bottom: calc(var(--s-8) * 1px);
  padding-top: calc(var(--s-2) * 1px);
}

/* ---- 标签页面板：无 JS 时四段全部铺开，有 JS 时由脚本接管 ----
   面板即页面内 <section data-panel>。与 `.js .reveal` 同一套路：
   .js 类由 site.js 首行注入（在任何样式计算之前）。
     · 关闭 JS → 没有 .js 类 → [data-panel] 全部 display:block，
       四个方案内容全部可见可读，不会只剩一个面板
     · 开启 JS → 仅 .is-active 的面板显示
   HTML 里不再使用 hidden 属性（那会导致无 JS 时只剩首段可读）。 */
[data-panel] {
  display: block;
}

.js [data-panel] {
  display: none;
}

.js [data-panel].is-active {
  display: block;
}

/* ⚠️ 面板是「贴边」的 section（占满整个视口宽），而全站 :focus-visible 给的是
   `2px solid var(--accent)` + `outline-offset: 3px` —— 面板一旦被键盘聚焦，这条外框的
   上边就横贯整屏，左右两条边被推出视口裁掉，看起来就是**凭空多出一道蓝线**
   （实测：section 顶边 184 ⇒ 蓝线落在 y=179~180、宽 1430/1440）。
   根因已处理：面板内含大量可聚焦元素（小节导航、资源链接），按标签页规范**不需要**
   再给 tabindex="0"，已从 4 个面板上移除。此处再兜一道 —— 万一以后有人加回来，
   焦点环也只圈内容头部，不再横贯整屏。 */
.sect[data-panel]:focus-visible {
  outline: none;
}

.sect[data-panel]:focus-visible .sect-head {
  outline: 2px solid var(--accent);
  outline-offset: 8px;
  border-radius: var(--r-md);
}

/* ---- 接入方式卡（open-platform 核心区） ---- */
.path-card {
  display: flex;
  flex-direction: column;
}

.path-no {
  display: block;
  margin-bottom: calc(var(--s-3) * 1px);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .1em;
  color: var(--text-3);
}

.path-fit,
.path-nofit {
  margin-bottom: calc(var(--s-3) * 1px);
  font-size: var(--fs-sm);
  line-height: 1.75;
}

.path-fit li,
.path-nofit li {
  position: relative;
  padding-left: calc(var(--s-4) * 1px);
  margin-bottom: calc(var(--s-1) * 1px);
}

.path-fit li::before,
.path-nofit li::before {
  position: absolute;
  left: 0;
  font-family: var(--font-mono);
  color: var(--text-3);
}

.path-fit li::before {
  content: "+";
}

.path-nofit li::before {
  content: "\2212";
}

.path-nofit li {
  color: var(--text-3);
}

.path-sub {
  margin-bottom: calc(var(--s-2) * 1px);
  font-size: var(--fs-xs);
  color: var(--text-3);
}

/* 一行 mono 起点，末段用 margin-top:auto 对齐各卡基线 */
.path-start {
  margin-top: auto;
  padding-top: calc(var(--s-4) * 1px);
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .02em;
  color: var(--text-2);
  word-break: break-all;
}

/* ---- 技术资料区：左树右步骤 ---- */
.resource-grid {
  display: grid;
  gap: calc(var(--s-6) * 1px);
}

.tree {
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-0);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.tree-group {
  padding-bottom: calc(var(--s-4) * 1px);
  margin-bottom: calc(var(--s-4) * 1px);
  border-bottom: 1px solid var(--line);
}

.tree-group:last-child {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: 0;
}

.tree-group > b {
  display: block;
  margin-bottom: calc(var(--s-2) * 1px);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .06em;
  color: var(--text-3);
}

.tree-group li {
  padding: var(--s-1) 0 var(--s-1) calc(var(--s-4) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-2);
  border-left: 1px solid var(--line);
}

.steps {
  counter-reset: step;
}

.step-item {
  position: relative;
  padding-left: calc(var(--s-12) * 1px);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
}

.step-item:last-child {
  border-bottom: 0;
}

.step-no {
  position: absolute;
  left: 0;
  top: calc(var(--s-5) * 1px);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .08em;
  color: var(--text-3);
}

.step-out {
  display: block;
  margin-top: calc(var(--s-1) * 1px);
  font-size: var(--fs-xs);
  color: var(--text-3);
}

/* ---- 设备能力（布尔 / 数值 / 枚举 / 透传） ---- */
.ability-card .code {
  margin-top: calc(var(--s-4) * 1px);
  padding: calc(var(--s-4) * 1px);
  font-size: var(--fs-xs);
}

/* ---- API 速查：密集排布 ---- */
.endpoints--dense {
  gap: 6px 8px;
}

.api-group {
  margin-bottom: calc(var(--s-6) * 1px);
}

.api-group:last-child {
  margin-bottom: 0;
}

.api-group > b {
  display: block;
  margin-bottom: calc(var(--s-3) * 1px);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .1em;
  color: var(--text-3);
}

/* ---- 徽章行（安全合规） ---- */
.badge-row {
  display: grid;
  gap: calc(var(--s-4) * 1px);
}

.badge-item {
  padding: calc(var(--s-4) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: background-color .2s ease, border-color .2s ease;
}

.badge-item:hover {
  background: var(--bg-2);
  border-color: var(--line-hi);
}

.badge-item .badge {
  margin-bottom: calc(var(--s-2) * 1px);
}

.badge-item p {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.7;
}

/* ---- 支持与资源 ---- */
.support-grid {
  display: grid;
  gap: calc(var(--s-4) * 1px);
}

/* 每列内的资源链接各自独占一行，靠下描边分隔；
   必须用 flex（块级）而非 inline-flex，否则多个 <a> 会并排挤在同一行 */
.support-col a {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--fs-sm);
  color: var(--text-1);
  border-bottom: 1px solid var(--line-hi);
  transition: color .2s ease;
}

.support-col a:hover {
  color: var(--text-2);
}

/* ---- 章节标记：底色切换处的 mono 标记 ---- */
.chapter-mark-band {
  background: var(--bg-1);
}

.chapter-mark {
  padding: calc(var(--s-6) * 1px) 0;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .14em;
  color: var(--text-3);
}

/* ---- 案例分组 ---- */
.case-group {
  margin-bottom: calc(var(--s-8) * 1px);
}

.case-group:last-child {
  margin-bottom: 0;
}

.case-group > .u-eyebrow {
  margin-bottom: calc(var(--s-4) * 1px);
}

/* 案例条目本身即链接，hover 仍只改底色与描边，不做位移 */
a.case-item {
  transition: background-color .2s ease, border-color .2s ease;
}

a.case-item:hover {
  background: var(--bg-2);
  border-color: var(--accent-line);
}

/* ---- 型号选配表 ---- */
.model-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.model-table th,
.model-table td {
  padding: calc(var(--s-3) * 1px) calc(var(--s-4) * 1px);
  border-bottom: 1px solid var(--line);
  text-align: left;
  color: var(--text-2);
  vertical-align: top;
}

.model-table th {
  color: var(--text-1);
  font-weight: 500;
}

.model-table td:first-child {
  font-family: var(--font-mono);
  letter-spacing: .04em;
  color: var(--text-1);
}

/* ---- 成本论证 ---- */
.cost-block {
  /* 与 .dg-flow / .dg 的横向内边距一致（原先 32 比它们多 8px，卡片内文字起点对不齐） */
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.cost-formula {
  margin-bottom: calc(var(--s-4) * 1px);
  font-size: var(--fs-body);
  color: var(--text-1);
}

.cost-block .code {
  margin-bottom: calc(var(--s-3) * 1px);
}

.cost-line {
  margin-bottom: calc(var(--s-3) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.75;
}

.cost-note {
  font-size: var(--fs-sm);
  color: var(--text-3);
}

/* ---- 关于页 ---- */
/* 关于页页头：客户 2026-10-13 反馈「关于臻格」标题占了太多版面、要下拉才看到品牌故事
   ⇒ 去掉 60vh 的半屏高度（原为 flex 居中撑满 60vh），压成紧凑页头，品牌简介直接进首屏。 */
.page-head--short {
  padding: calc(var(--s-10) * 1px) 0 calc(var(--s-6) * 1px);
}

.about-grid {
  display: grid;
  gap: calc(var(--s-8) * 1px);
  align-items: start;
}

.about-copy p {
  margin-bottom: calc(var(--s-5) * 1px);
  font-size: var(--fs-body);
  color: var(--text-2);
  line-height: 1.8;
}

.about-copy h3 {
  font-size: var(--fs-h3);
  font-weight: 600;
  margin-bottom: calc(var(--s-3) * 1px);
}

.cap-grid {
  display: grid;
  gap: calc(var(--s-4) * 1px);
}

.cap-grid .cap-item {
  background: var(--bg-0);
}

.cap-grid .cap-item li {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.85;
}

.method-list {
  display: grid;
  gap: calc(var(--s-4) * 1px);
}

.method-item {
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.method-item h3 {
  font-size: var(--fs-body);
  font-weight: 600;
  margin-bottom: calc(var(--s-2) * 1px);
}

.method-item p {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.75;
}

/* ---- 联系页：超大 mono 号码为唯一视觉重心 ---- */
.contact-hero {
  min-height: 50vh;
  display: flex;
  align-items: center;
  text-align: center;
}

.contact-phone {
  display: inline-block;
  margin: calc(var(--s-5) * 1px) 0 calc(var(--s-3) * 1px);
  font-family: var(--font-mono);
  font-size: clamp(36px, 6vw, 72px);
  letter-spacing: .02em;
  line-height: 1.1;
  color: var(--text-1);
  transition: color .2s ease;
}

.contact-phone:hover {
  color: var(--text-2);
}

.contact-dial {
  display: block;
  font-size: var(--fs-sm);
  color: var(--text-3);
}

/* --- 邮箱 + 微信二维码（2026-10-13 客户：把联系方式补充完整）------------
   与电话同区呈现：左栏是「电话 → 邮箱」两条并列渠道，右栏是扫码卡片。
   ⚠️ .contact-qr 是 <figure> ⇒ 浏览器给它 UA 默认 `margin: 1em 40px`，
      必须显式归零，否则整块会比同级内容多缩进 40px（本项目已踩过一次）。
   ⚠️ 二维码必须**白底黑码**：不加 filter、不反色 —— 反色会让部分机型扫不出。 */
.contact-grid {
  display: grid;
  gap: calc(var(--s-8) * 1px);
  justify-items: center;
}

.contact-mail-eyebrow {
  margin-top: calc(var(--s-8) * 1px);
}

.contact-mail {
  display: inline-block;
  margin-top: calc(var(--s-3) * 1px);
  font-family: var(--font-mono);
  font-size: clamp(17px, 2.2vw, 28px);
  letter-spacing: .01em;
  color: var(--text-2);
  overflow-wrap: anywhere;
  transition: color .2s ease;
}

.contact-mail:hover {
  color: var(--text-1);
}

.contact-note {
  display: block;
  margin-top: calc(var(--s-2) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.contact-qr {
  margin: 0;
  display: grid;
  gap: calc(var(--s-4) * 1px);
  justify-items: center;
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  text-align: center;
}

.contact-qr img {
  display: block;
  width: 168px;
  height: 168px;
  background: #fff;
  border-radius: var(--r-sm);
}

/* 不要限宽：限宽会把说明挤成两行、末尾只剩两个字（已实测出现「沟通更 / 快。」） */
.contact-qr figcaption {
  display: grid;
  gap: calc(var(--s-1) * 1px);
}

.contact-qr figcaption b {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-1);
}

.contact-qr figcaption span {
  font-size: var(--fs-sm);
  color: var(--text-3);
  line-height: 1.7;
}

/* ≥768：电话/邮箱在左、扫码卡在右；<768 单列居中堆叠 */
@media (min-width: 768px) {
  .contact-grid {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    justify-items: start;
    gap: calc(var(--s-10) * 1px);
    text-align: left;
  }

  .contact-qr {
    justify-items: center;
  }
}

.guide-grid {
  display: grid;
  gap: calc(var(--s-4) * 1px);
}

.guide-item {
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.guide-item b {
  display: block;
  margin-bottom: calc(var(--s-2) * 1px);
  font-size: var(--fs-body);
  font-weight: 600;
}

.guide-item p {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.75;
}


/* ==========================================================================
   12. 关于页「品牌简介」
   文案 + 三张能力配图（工厂 / 仓储 / 数据大屏）。
   ⚠️ 三张图统一用 aspect-ratio: 3/2 定高（素材本身就是 3:2），不给 img 写单独的
      width/height —— 这样同一行三张必然等高，也不会出现「同一容器两种排版」。
   ⚠️ .about-fig 是 <figure>，必须显式把 margin 归零（UA 默认 1em 40px）。
   ========================================================================== */

.brand-copy {
  max-width: 860px;
}

.brand-copy p {
  margin-bottom: calc(var(--s-4) * 1px);
  font-size: var(--fs-body);
  color: var(--text-2);
  line-height: 1.8;
}

.brand-copy p:last-child {
  margin-bottom: 0;
}

.about-figs {
  display: grid;
  gap: calc(var(--s-4) * 1px);
  margin-top: calc(var(--s-8) * 1px);
}

.about-fig {
  margin: 0;
  padding: calc(var(--s-4) * 1px);
  background: var(--bg-0);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.about-fig img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--r-sm);
}

.about-fig figcaption {
  margin-top: calc(var(--s-3) * 1px);
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--text-3);
}

/* ==========================================================================
   10. 网格底纹与 hero
   网格底纹现仅保留在 .cap-card（首页板块 4「管理系统」大卡）。
   首屏改为「暗场光锥」后不再铺满屏纹理，四角保持纯黑（背景交给第 18 节）。

   实现说明：底纹必须挂在 ::before 伪元素上，不能直接挂在 .cap-card
   本身。mask-image 会作用于元素的全部绘制内容（含子元素），若直接挂在
   容器上，标题、正文会一起被径向遮罩淡化。改为伪元素后，遮罩只作用于
   底纹层，内容层不受影响。
   ========================================================================== */

/* 能力大卡保留原来的方格网 */
.cap-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, .035) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, .035) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, #000 30%, transparent 78%);
  mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, #000 30%, transparent 78%);
  pointer-events: none;
}

/* 内容层需位于底纹之上 */
.hero-inner,
.cap-card > * {
  position: relative;
}

.cap-card {
  background-color: var(--bg-1);
}

.hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 640px;

  /* ⚠️ 这里以前是 min-height:100vh，是「首屏信息偏下、上方黑色太多」的根因：
     页头是 position:sticky，**仍然占据文档流**，首屏从 y=73 才开始，
     于是 100vh 高的首屏底边落到 973（视口只有 900）——
       ① 首屏最底下那行 endpoints 被切在视口外；
       ② 首屏的视觉中心落在 531，比屏幕中心 450 低 81px。
     减去页头高度后：首屏 = 73 .. 100vh，正好是页头以下的整块可见区，
     flex 居中据此计算，内容才真正居中在屏幕上。 */
  min-height: calc(100vh - var(--header-h));
  background-color: var(--bg-0);
  padding: calc(var(--s-16) * 1px) 0 calc(var(--s-12) * 1px);
}

.hero-inner {
  width: 100%;
}

  .hero h1 {
    font-size: var(--fs-display);
    margin-bottom: calc(var(--s-5) * 1px);
  }

  /* 首屏 h1「自研门锁，自研系统」客户要求 **任何宽度都不许换行**。
     它是 9 个全宽字符 ⇒ 一行需要「9 × 字号」的宽度，而 --fs-display 在 1440 下
     是 64px（9 × 64 = 576px）> 桌面两栏的栏宽 568px —— 于是被断成两行
     （先断成「自研门锁，自研系 / 统」，加 span 后断成逗号处两行，都不是客户要的）。
     解法：nowrap 锁死 + 把字号压到栏宽以内。
     桌面两栏（≥1180）栏宽 = min(vw,1240)/2 - 52，按 9 字 + 2% 余量反推：
       ≤ (vw/2 - 52) / 9.4 ≈ 5.32vw - 5.5px
     取 5.4vw - 5.4px 并封顶 62px（62 × 9 = 558 ≤ 568）。
     ≤1180 时 .col-6 是 grid-column:1/-1（整栏宽），空间充裕；
     只有 ≤346px 的极窄屏才需要让位，补丁在 @media (max-width:480px) 里。

     ⚠️ 必须挂在 .h1--oneline 上而不是裸的 `.hero h1`：
        `.hero` 被 open-platform.html 复用（那里 h1 是 6 个字的「按你的路接入」，
        本来就不会换行），不给它打标记就会连带把它的字号从 64px 压到 62px。 */
  .hero h1.h1--oneline {
    white-space: nowrap;
  }

  @media (min-width: 1180px) {
    .hero h1.h1--oneline {
      font-size: min(62px, calc(5.4vw - 5.4px));
    }
  }

.hero-lead {
  font-size: var(--fs-lead);
  line-height: 1.75;
  color: var(--text-2);
  max-width: 560px;
  margin-bottom: calc(var(--s-6) * 1px);
}

/* 首屏导语按客户要求拆成两段（第一段讲定制与生产，第二段讲系统与联网方式）。
   实测：拆段只多了 12px + 一行（约 28px），**没有顶破一屏** ——
   因为桌面档一屏高度是被 .ac-stage（100vh-272px）撑着的，文案列比舞台列矮，
   多出来的 40px 由 min-height 与舞台的高度差吸收掉了。
   ⚠️ 但这条余量不是无限的：一旦文案列长过舞台列，首屏就会顶出一屏、翻页落点跟着错位。
   文案列 = eyebrow + h1 + 两段导语 + 按钮；舞台 = clamp(430px, 100vh-272px, 680px)。改这两侧都要复测「首屏严格一屏」。 */
.hero-lead + .hero-lead {
  margin-top: calc(var(--s-3) * 1px);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--s-3) * 1px);
  margin-bottom: calc(var(--s-8) * 1px);
}

.hero-foot {
  padding-top: calc(var(--s-5) * 1px);
  border-top: 1px solid var(--line);
}


/* ==========================================================================
   11. 页头 site-header

   ▉ 关键实测结论（改动前必读，勿把 blur 改回 .site-header 自身）
   --------------------------------------------------------------------------
   QA 独立验收实测反证：把 blur 直接写在 .site-header 上会形成「包含块」。
   凡带 backdrop-filter / filter / transform / perspective / will-change 的
   元素，都会成为其后代 position:fixed 的包含块。抽屉 .main-nav 与遮罩
   .nav-scrim 都在页头内部，于是 position:fixed 不再相对视口，而被压进
   72px 高的页头里，实测后果：

     · 抽屉展开 offsetHeight = 72（应等于视口高）
     · 遮罩只覆盖页头那 72px，点空白关不掉抽屉
     · 抽屉关闭态（translateX(100%)）离屏 320px，把文档 scrollWidth 撑到
       695 vs clientWidth 375 → 7 个页面在窄屏全部出现横向滚动条

   最终方案（择一后实测确认）：把 blur 移到 .site-header::before 伪元素上。
   页头自身不再带任何 filter 属性 → 不再是包含块 → 抽屉与遮罩恢复
   position:fixed 相对视口；磨砂观感完整保留（伪元素 inset:0 铺满页头，
   z-index:-1 让它落在页头背景与内部内容之间；页头 z-index:50 已建立
   层叠上下文，负 z-index 不会掉到页面背景之后）。
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  /* 背景与模糊都交给 ::before，自身保持「无 filter」，避免形成包含块 */
  background: transparent;
  border-bottom: 1px solid var(--line);
}

/* 磨砂玻璃层：必须挂在伪元素上，不能挂在 .site-header 自身（见上方结论） */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(8, 8, 10, .72);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: calc(var(--s-5) * 1px);
  height: 72px;
}

/* 只放 logo 图片，不叠加任何文字：logo 图已含「臻格 ZHENGE」中英字样 */
.brand-lockup {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  height: 28px;
}

.brand-lockup img {
  height: 28px;
  width: auto;

  /* 实测结论：zclock-logo-crop.png 为「黑字白底 + 蓝色图形标」，主色 #2AA2DD。
     直接放在深色页面上白底会成为刺眼方块，故：
       invert(1)        白底 → 近黑，与 --bg-0 无缝融合；黑字 → 白字
       hue-rotate(180deg) 把 invert 造成的色相翻转再翻回来
     净效果：品牌蓝保留（实测约 #1088C3，比原色深一档，深底上更稳），
     与全站 --accent: #2AA2DD 同色系。商标图形与字样零改动，
     将来换标准版 logo 只需删掉本行滤镜。 */
  filter: invert(1) hue-rotate(180deg);
}

.main-nav {
  display: flex;
  align-items: center;
  gap: calc(var(--s-1) * 1px);
  margin-left: auto;
}

.main-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 calc(var(--s-3) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-2);
  transition: color .2s ease;
}

.main-nav a:hover {
  color: var(--text-1);
}

.main-nav a.active {
  color: var(--text-1);
}

.nav-contact {
  margin-left: calc(var(--s-3) * 1px);
  flex-shrink: 0;
}

.menu-toggle {
  display: none;
  margin-left: auto;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  color: var(--text-1);
}

.nav-scrim {
  display: none;
}


/* ==========================================================================
   12. 页脚 site-footer
   ========================================================================== */

.site-footer {
  background: var(--bg-1);
  border-top: 1px solid var(--line);
}

.footer-main {
  display: grid;
  gap: calc(var(--s-8) * 1px);
  padding: calc(var(--s-12) * 1px) 0 calc(var(--s-8) * 1px);
}

.footer-brand img {
  height: 26px;
  width: auto;
  filter: invert(1) hue-rotate(180deg);
}

.footer-brand p {
  margin-top: calc(var(--s-4) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-3);
  max-width: 240px;
}

.footer-cols {
  display: grid;
  gap: calc(var(--s-6) * 1px);
}

.footer-col .u-eyebrow {
  margin-bottom: calc(var(--s-3) * 1px);
}

.footer-col li {
  margin-bottom: calc(var(--s-1) * 1px);
}

.footer-col a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  font-size: var(--fs-sm);
  color: var(--text-2);
  transition: color .2s ease;
}

.footer-col a:hover {
  color: var(--text-1);
}

/* 左：项目咨询（眼眉 + 电话 + 邮箱）；右：微信二维码。
   ⚠️ 二维码顶端与「项目咨询」眼眉对齐（客户圈的位置就是这一列右侧）。 */
.footer-contact {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: calc(var(--s-4) * 1px);
}

.footer-contact .u-eyebrow {
  margin-bottom: calc(var(--s-2) * 1px);
}

/* 全站唯一转化入口 */
.footer-contact a {
  font-family: var(--font-mono);
  font-size: var(--fs-h3);
  letter-spacing: .02em;
  color: var(--text-1);
  transition: color .2s ease;
}

.footer-contact a:hover {
  color: var(--text-2);
}

/* ⚠️ 邮箱是次级入口：必须覆盖 .footer-contact a 的 --fs-h3（否则和电话号码一样大） */
.footer-contact .footer-mail {
  display: block;
  margin-top: calc(var(--s-2) * 1px);
  font-size: var(--fs-body);
  letter-spacing: 0;
  color: var(--text-2);
  overflow-wrap: anywhere;
}

.footer-contact .footer-mail:hover {
  color: var(--text-1);
}

/* ⚠️ .footer-qr 是 <figure> ⇒ 浏览器 UA 默认 `margin: 1em 40px`，必须显式归零。
   ⚠️ 二维码必须白底黑码：不加 filter、不反色（反色会让部分机型扫不出）。
   ⚠️ 尺寸是**实测**出来的：本图 37 模块 + 8 静区 = 45 模块，
      108px（2.4px/模块）jsQR **解不出来**，120px（2.67）才通过 ⇒ 取 **144px（3.2px/模块）**留 20% 余量。
      **别凭感觉把二维码缩小**，改尺寸必须重跑解码验证。 */
.footer-qr {
  margin: 0;
  flex: 0 0 auto;
}

.footer-qr img {
  display: block;
  width: 144px;
  height: 144px;
  background: #fff;
  border-radius: var(--r-sm);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--s-3) * 1px);
  padding: calc(var(--s-5) * 1px) 0;
  border-top: 1px solid var(--line);
  font-size: var(--fs-xs);
  color: var(--text-3);
}

/* 低调入口：无边框、不上浮、不加 logo */
.footer-ext {
  color: var(--text-3);
  transition: color .2s ease;
}

.footer-ext:hover {
  color: var(--text-2);
}


/* ==========================================================================
   13. 滚动渐显与关键帧
   全站仅 1 个 @keyframes：float（产品图微悬浮）。
   滚动渐显**用 transition 实现**（不是 animation）—— 原因见 `.js .reveal.is-active`
   的注释：animation 在冻结时间线的环境里会卡在起始帧把内容藏掉。
   初始态由 .js .reveal 隐藏；js 类由 site.js 首行注入，
   无 JS 时内容照常可见，不会整站空白
   ========================================================================== */

.js .reveal {
  opacity: 0;
  transform: translateY(12px);
  /* ⚠️ 渐显必须用 transition，不能用 animation —— 见下方 .is-active 的说明 */
  transition: opacity .4s cubic-bezier(.22, .61, .36, 1),
    transform .4s cubic-bezier(.22, .61, .36, 1);
}

.js .reveal.is-active {
  /* 「可见」必须是声明式的最终态。早前写的是 `animation: reveal .4s ... forwards`，
     踩了一个很隐蔽的坑：在不推进动画时间线的环境里（屏幕外 iframe、被遮挡的内嵌
     面板、无头模式），动画会**冻结在 t=0 的起始帧**（opacity:0），而"冻结中的动画"
     依然持续生效并覆盖声明值 ⇒ 整页 41 个 .reveal（含 26 张产品卡）全部隐身，
     用户会以为"很多内容没显示出来"。改用 transition 后，跑不动就直接落在终态可见。 */
  opacity: 1;
  transform: none;
}



@keyframes float {
  0%,
  100% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-6px);
  }
}


/* 分段小标题与分段间距：同一 section 内放多组网格时用（products.html 网关/配套） */
.sub-block-head {
  margin-bottom: calc(var(--s-4) * 1px);
}

.sub-block + .sub-block {
  margin-top: calc(var(--s-8) * 1px);
}

.sub-block .grid + .grid {
  margin-top: calc(var(--s-5) * 1px);
}


/* ==========================================================================
   14. 工具类
   ========================================================================== */

.u-center {
  text-align: center;
}

.u-hide-sm,
.u-hide-md {
  display: none;
}

.u-eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .12em;
  color: var(--accent);
}

.u-note {
  font-size: var(--fs-sm);
  color: var(--text-3);
}


/* ==========================================================================
   15. 断点
   仅使用 1180px / 1024px / 768px / 480px 四个值
   ========================================================================== */

/* ---- 手机 < 768px ---- */

/* 窄屏下接口路径允许横向滚动，禁止省略号截断 */
@media (max-width: 480px) {
  /* 极窄屏（≤346px，如 320×568）上整栏宽只有 vw - 40，
     装不下 9 个 34px 的字（306px > 280px）⇒ 让字号跟着宽度收，
     保证首屏 h1 在任何宽度仍是单行（配合上面的 white-space:nowrap）。 */
  .hero h1.h1--oneline {
    font-size: min(var(--fs-display), calc((100vw - 40px) / 9.4));
  }

  .endpoints {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 4px;
  }
}

/* ---- 平板 >= 768px ---- */
@media (min-width: 768px) {
  .wrap {
    padding-left: 32px;
    padding-right: 32px;
  }

  .grid {
    grid-template-columns: repeat(8, minmax(0, 1fr));
    gap: 24px;
  }

  .col-md-4 {
    grid-column: span 4;
  }

  .col-md-6 {
    grid-column: span 6;
  }

  .col-md-8 {
    grid-column: span 8;
  }

  .grid--cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .grid--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .grid--pairs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .grid--five {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* 门锁：平板 3 列 */
  .grid--locks {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* 接入方式卡：平板 2 列 */
  .path-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .frame-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .frame-grid--four {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ability-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* 第二轮各内容网格的平板档 */
  .resource-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .badge-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .support-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .cap-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .guide-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .method-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .about-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .about-figs {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .tabs--sticky {
    top: 72px;
  }

  /* 紧凑 80 / 主块 112 / hero 128 在平板档降为 64 / 80 / 88 */
  .sect {
    padding: calc(var(--s-10) * 1px) 0 calc(var(--s-8) * 1px);
  }

  .sect--tight {
    padding: calc(var(--s-8) * 1px) 0 calc(var(--s-6) * 1px);
  }

  .sect--hero {
    padding: calc(var(--s-12) * 1px) 0 calc(var(--s-10) * 1px);
  }

  .page-head {
    padding: calc(var(--s-10) * 1px) 0 calc(var(--s-8) * 1px);
  }

  .shot {
    --shot-h: 190px;
  }

  .shot--hero {
    --shot-h: 460px;
  }

  .shot--tall {
    --shot-h: 460px;
  }

  /* 仪表与采集器高度需在 .shot / .shot--tall 之后声明 */
  .shot--meter,
  .shot--device {
    --shot-h: 210px;
  }

  /* 首屏上下留白：对称 + 固定 64px。
     对称是必须的 —— 非对称（原来是 80 / 64）会让内容整体下移 8px，抵消掉居中。
     首屏不再靠留白控制高度，而是靠 .ac-stage 的高度随视口收缩（见 ≥1180 档）：
       73（页头）+ 64 + stage + 62（.hero-foot）+ 64 = 100vh
     ⇒ stage = 100vh - 263，取 -272 留 9px 余量，保证 content < min-height，
       首屏正好一屏且内容居中。 */
  .hero {
    padding: 0;
    padding-block: calc(var(--s-10) * 1px);
  }

  .footer-cols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .footer-main {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---- <= 1024px：抽屉导航 ---- */
@media (max-width: 1024px) {
  .menu-toggle {
    display: inline-flex;
  }

  .main-nav {
    position: fixed;
    inset: 0 0 0 auto;
    z-index: 60;
    width: min(320px, 86vw);
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin-left: 0;
    padding: calc(var(--s-6) * 1px) calc(var(--s-5) * 1px);
    background: var(--bg-1);
    border-left: 1px solid var(--line);
    box-shadow: var(--shadow-pop);

    /* 全站第二处（也是最后一处）毛玻璃模糊；
       抽屉自身不是任何 fixed 后代的祖先，故不影响包含块 */
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);

    /* 关闭态：移出视口 + 隐藏 + 不接收指针事件，
       避免离屏元素参与溢出计算、也避免透明层截获点击。
       visibility 参与过渡，使关闭动画播完后才真正隐藏 */
    transform: translateX(100%);
    visibility: hidden;
    pointer-events: none;
    transition: transform .28s ease, visibility .28s ease;
    overflow-y: auto;
  }

  .main-nav.is-open {
    transform: translateX(0);
    visibility: visible;
    pointer-events: auto;
  }

  .main-nav a {
    min-height: 48px;
    padding: 0 calc(var(--s-3) * 1px);
    font-size: var(--fs-body);
    border-bottom: 1px solid var(--line);
  }

  .nav-contact {
    margin: calc(var(--s-5) * 1px) 0 0;
  }

  .nav-contact .btn {
    width: 100%;
  }

  .nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;
    background: rgba(0, 0, 0, .6);
    opacity: 0;
    visibility: hidden;
    transition: opacity .28s ease, visibility .28s ease;
  }

  .nav-scrim.is-open {
    opacity: 1;
    visibility: visible;
  }
}

/* ---- 桌面 >= 1180px ---- */
@media (min-width: 1180px) {
  .wrap {
    max-width: 1240px;
    padding-left: 40px;
    padding-right: 40px;
  }

  .grid {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 24px;
  }

  .col-4 {
    grid-column: span 4;
  }

  .col-6 {
    grid-column: span 6;
  }

  .col-8 {
    grid-column: span 8;
  }

  .col-12 {
    grid-column: span 12;
  }

  .grid--cards {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* 半栏内保持两列，与 12 栅格的 col-6 宽度相称 */
  .grid--pairs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .grid--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* 联网方式 5 项排成整齐一行 */
  .grid--five {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  /* 门锁：桌面 3 列 ×3 行，9 个型号正好铺满 */
  .grid--locks {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* 接入方式卡：桌面 4 列，等高由 grid 默认 stretch + 卡内 margin-top:auto 保证 */
  .path-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .frame-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .frame-grid--four {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .ability-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* 第二轮各内容网格的桌面档 */
  .resource-grid {
    grid-template-columns: 1fr 1.5fr;
  }

  .badge-row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .support-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .cap-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .guide-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .method-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .about-grid {
    grid-template-columns: 1fr 1fr;
    gap: calc(var(--s-10) * 1px);
  }

  .case-group .case-item {
    padding: calc(var(--s-4) * 1px) calc(var(--s-5) * 1px);
  }

  .shot {
    --shot-h: 216px;
  }

  /* 仪表与采集器高度需在 .shot 之后声明，否则被同优先级的 .shot 覆盖 */
  .shot--meter,
  .shot--device {
    --shot-h: 250px;
  }

  .shot--hero {
    --shot-h: 520px;
  }

  .shot--tall {
    --shot-h: 520px;
  }

  .hero .grid {
    align-items: center;
  }

  .footer-main {
    /* ⚠️ 最后一栏是「项目咨询」，栏内要放 144px 二维码 + 大号等宽电话号码（1440 下实宽 160px）
       ⇒ 中间栏 1.6fr → 1.45fr，最后一栏 1fr → 1.35fr（实测 272 → 348px，文本列剩 188px）。 */
    grid-template-columns: 1.2fr 1.45fr 1.35fr;
    gap: calc(var(--s-10) * 1px);
  }
}

/* 注：断点仅允许 1180 / 1024 / 768 / 480 四个值，故不设超大屏档，
   首屏图高度在 1180px 档定为 520px 后不再变化。 */


/* ==========================================================================
   无障碍：用户偏好减少动效时，渐显与悬浮全部关闭
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .shot img {
    animation: none;
  }

  .js .reveal,
  .js .reveal.is-active {
    opacity: 1;
    transform: none;
    transition: none;
    animation: none;
  }

  .main-nav,
  .nav-scrim,
  .btn,
  .arrow-link,
  .pcard,
  .cap-item,
  .scene-card,
  .method-item,
  .tab,
  .footer-col a,
  .footer-contact a,
  .footer-ext {
    transition: none;
  }
}


/* ==========================================================================
   16. 导航下拉（产品中心）与首页品类总览
   独立追加，不改动既有选择器，避免与上文规则冲突。
   ========================================================================== */

/* 锚点跳转时给吸顶页头留出高度，否则标题会被页头盖住 */
section[id] {
  scroll-margin-top: 96px;
}

.nav-item {
  position: relative;
  display: flex;
  align-items: center;
}

.nav-caret {
  display: inline-flex;
  color: var(--text-3);
  pointer-events: none;
}

.nav-caret svg {
  display: block;
}

/* 桌面：悬停或键盘聚焦时展开。不用 JS，避免脚本失效后菜单打不开 */
.nav-drop {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 60;
  min-width: 240px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: calc(var(--s-2) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity .18s ease, transform .18s ease, visibility .18s;
}

.nav-item--drop:hover .nav-drop,
.nav-item--drop:focus-within .nav-drop {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* 覆盖 .main-nav a 的横排内边距，改为下拉条目形态 */
.nav-drop a {
  display: block;
  min-height: 36px;
  padding: calc(var(--s-2) * 1px) calc(var(--s-3) * 1px);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--text-2);
}

.nav-drop a:hover {
  background: var(--bg-2);
  color: var(--text-1);
}

/* 首页品类总览：门锁为宽幅主卡，其余五类为等宽次要卡 */
.cat-lead {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: calc(var(--s-5) * 1px);
  padding: calc(var(--s-6) * 1px);
  margin-bottom: calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: background-color .2s ease, border-color .2s ease;
}

.cat-lead:hover {
  background: var(--bg-2);
  border-color: var(--accent-line);
}

.cat-lead h3 {
  font-size: var(--fs-h3);
  font-weight: 600;
  margin: calc(var(--s-2) * 1px) 0;
}

.cat-lead p {
  font-size: var(--fs-sm);
  color: var(--text-2);
  max-width: 48ch;
}

.cat-lead-shots {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: calc(var(--s-3) * 1px);
}

.cat-lead-shots .shot {
  /* 既有溢出修复：基类同时带 aspect-ratio:1/1 与 height:var(--shot-h)，
     Chrome 下宽度被算成等于高度（140/180），而三列轨道每列仅 ~84/116px，
     导致第 3 张右缘越过视口被 clip 掩盖。改为宽度由轨道决定、高度按 1:1 推出。 */
  width: 100%;
  height: auto;
  --shot-h: 140px;
}

.cat-grid {
  grid-template-columns: minmax(0, 1fr);
}

/* 卡片标题长短不一时，把「查看」压到卡片底部，保证一行内 CTA 对齐 */
.scene-card > .arrow-link {
  margin-top: auto;
}

@media (min-width: 768px) {
  .cat-lead {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    align-items: center;
  }

  .cat-lead-shots .shot {
    --shot-h: 180px;
  }

  .cat-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 1180px) {
  .cat-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

/* 移动端抽屉内：下拉改为常驻缩进列表，触屏没有悬停态 */
@media (max-width: 1024px) {
  .nav-item--drop {
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
  }

  .nav-caret {
    display: none;
  }

  .nav-drop {
    position: static;
    width: 100%;
    min-width: 0;
    margin: 0 0 calc(var(--s-3) * 1px) calc(var(--s-3) * 1px);
    padding: 0 0 0 calc(var(--s-3) * 1px);
    background: transparent;
    border: 0;
    border-left: 2px solid var(--line);
    border-radius: 0;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }
}


/* ==========================================================================
   17. 联网方式 · 环形组网图（2026-10-11 换掉原「等宽协议条」）

   原来这里是 6 个「等宽名称 + 4~6 字限定语」的芯片排成一行（.net-name / .net-note
   + .grid--six），信息层级扁平、没有主次。现改为「中心门锁实拍 + 5 个设备实拍节点
   + 细引线 + 左右规格块」的环形组网图 —— 与板块 02 的门锁线稿是同一套语言。

   几何约定（改一处必须成对改）：
     · .ring-stage 用 aspect-ratio 1160/620 锁死比例，.ring-lines 的 viewBox 与之同源
     · 节点位置由 .ring-node--n 的百分比给出，引线端点 = 圆心 ± 半径 46（圆片直径 92）
     · 单 DOM：桌面 .ring-hero/.ring-list/.ring-unit 全用 display:contents 拍平成舞台
       直系，窄屏再各自还原为 block / grid / flex —— 一套 DOM 两套布局，文案不重复
   ⚠️ 产品图呈现真实颜色，不加任何 filter。
   ========================================================================== */
.ring-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 1160 / 620;
}

.ring-hero,
.ring-list,
.ring-unit,
.ring-specs {
  display: contents;
}

/* 中心受光圆盘：极淡冷光 + 1px 品牌色描边，不做实心铺色 */
.ring-disc {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 21.5517%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: var(--r-pill);
  border: 1px solid var(--accent-line);
  background:
    radial-gradient(circle at 50% 46%, rgba(79, 184, 232, .20) 0%, rgba(42, 162, 221, .07) 56%, rgba(42, 162, 221, 0) 74%);
}

/* 外圈辅助环：与节点轨道同一条椭圆 */
.ring-orbit {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44.4828%;
  height: 64.5161%;
  transform: translate(-50%, -50%);
  border: 1px solid var(--line);
  border-radius: 50%;
}

/* 中心门锁：取景窗只框「正面板 + 执手」那半边（双面板图裁掉背板） */
.ring-core {
  position: absolute;
  left: 54.0948%;
  top: 50%;
  width: 16.4%;
  aspect-ratio: 560 / 1188;
  transform: translate(-50%, -50%);
  overflow: hidden;
}

.ring-lock {
  position: absolute;
  height: 100%;
  /* ⚠️ 必须显式放开：全站 img { max-width:100% } 会把这里的 width:auto（应约 410px）
     钳回取景窗宽（190px），再叠加 left:-114.29% 之后整张图被推到可视区之外 —— 中心
     会变成一片空的受光圆盘。与 .shot--bare img 的 200% 裁剪是同一个坑。 */
  width: auto;
  max-width: none;
  left: -114.29%;
  top: 0;
}

/* 引线 */
.ring-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.ring-lines path {
  fill: none;
  stroke: var(--accent);
  stroke-opacity: .42;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.ring-lines circle {
  fill: var(--accent);
  fill-opacity: .85;
}

/* 环形节点：5 个圆片，直径 92/1160，圆片即取景窗（overflow 圆裁） */
.ring-node {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 7.9310%;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-hi);
  overflow: hidden;
  background:
    radial-gradient(circle at 50% 36%, rgba(255, 255, 255, .06) 0%, rgba(255, 255, 255, 0) 72%),
    var(--bg-2);
}

.ring-node--1 {
  left: 56.8707%;
  top: 19.3226%;
}

.ring-node--2 {
  left: 72.2414%;
  top: 50%;
}

.ring-node--3 {
  left: 56.8707%;
  top: 80.6774%;
}

.ring-node--4 {
  left: 32.0086%;
  top: 31.0323%;
}

.ring-node--5 {
  left: 32.0086%;
  top: 68.9677%;
}

.ring-node-img {
  width: 86%;
  height: 86%;
  object-fit: contain;
  display: block;
}

/* JK-POE 实拍拖着一根长天线，板体被挤在下缘：铺满取景窗后平移+放大取板体，
   天线随之移出圆窗（只调 CSS，不动素材；1.28 使板体对角刚好落在圆窗内） */
.ring-node--4 .ring-node-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: translate(-20%, -31.9%) scale(1.28);
}

/* JK-WIFI 实拍是竖长板 + 下方排线：同样取板体，使竖板完整落在圆窗内、不变形 */
.ring-node--5 .ring-node-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: translate(.1%, 17.1%) scale(1.18);
}

/* 规格文字块：裸文本 + 等宽型号，与板块 02 的 .cb 同语言 */
.ring-spec {
  position: absolute;
  transform: translateY(-50%);
  width: 19.3103%;
}

.ring-spec--l {
  text-align: right;
}

.ring-spec--r {
  text-align: left;
}

.ring-spec--1 {
  left: 80.6897%;
  top: 19.3226%;
}

.ring-spec--2 {
  left: 80.6897%;
  top: 50%;
}

.ring-spec--3 {
  left: 80.6897%;
  top: 80.6774%;
}

.ring-spec--4 {
  left: 0;
  top: 31.0323%;
}

.ring-spec--5 {
  left: 0;
  top: 68.9677%;
}

.ring-idx {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .1em;
  color: var(--accent);
}

.ring-model {
  display: block;
  margin-top: calc(var(--s-1) * 1px);
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  letter-spacing: .02em;
  color: var(--text-1);
}

.ring-note {
  display: block;
  margin-top: calc(var(--s-1) * 1px);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--text-2);
}

/* 窄屏：**不再把节点与引线撤掉改成纯列表**，而是保住整张环图，只做等比缩小。
   客户反馈手机端"每张图按顺序排下去"，故淘汰原先「撤引线 + 节点改列表行」的写法。
   分两档：
     · ≤1024：整张环图（受光圆盘 + 中心门锁 + 引线 + 5 个实拍节点 + 两侧规格块）
       连规格一起等比缩小；内部一切百分比与桌面逐字节一致，只把标注字号压一档。
     · ≤768：窄到两侧放不下标注 —— 环图（含节点与引线）整体留在上方，
       5 条规格收成环图下方的双列列表。构图（环 + 节点 + 引线）不丢，只是标注另起一块。 */
@media (max-width: 1024px) {
  .ring-stage {
    aspect-ratio: 1160 / 620;
    max-width: 720px;
    margin-inline: auto;
  }

  /* 只压标注字号；节点 / 引线 / 圆盘 / 门锁的绝对定位与百分比全部保持基类不动 */
  .ring-model {
    font-size: var(--fs-sm);
  }

  .ring-note {
    font-size: var(--fs-xs);
    line-height: 1.45;
  }
}

@media (max-width: 768px) {
  .ring-stage {
    aspect-ratio: auto;
  }

  /* 环图区：与桌面同源的比例（内部 % 不许动） */
  .ring-hero {
    position: relative;
    display: block;
    aspect-ratio: 1160 / 620;
  }

  /* 节点容器：叠在与 hero 同尺寸同位置的一层上 ⇒ 节点 left/top% 与桌面一致。
     ⚠️ .ring-list 基类是 display:contents，必须先 display:block，否则
        position / width / aspect-ratio 全部无效，节点会散落到整节上。 */
  .ring-list {
    display: block;
    position: absolute;
    top: 0;
    right: auto;
    bottom: auto;
    left: 0;
    width: 100%;
    height: auto;
    aspect-ratio: 1160 / 620;
    transform: none;
  }

  /* 规格块已移到下方列表，引线没有指向对象 —— 隐藏这一层（否则是一排朝空白射出的断线）。
     ⚠️ 只禁 .ring-lines；轨道环 .ring-orbit、中心门锁 .ring-core 与 5 个 .ring-node
        全部保留 ⇒ 环图语义（环 + 中心 + 5 节点）依然完整。 */
  .ring-lines {
    display: none;
  }

  /* 规格块：环图下方的双列列表 */
  .ring-specs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: calc(var(--s-5) * 1px) calc(var(--s-4) * 1px);
    margin-top: calc(var(--s-6) * 1px);
  }

  .ring-spec {
    position: static;
    left: auto;
    top: auto;
    transform: none;
    width: auto;
    text-align: left;
    min-width: 0;
    padding-top: calc(var(--s-3) * 1px);
    border-top: 1px solid var(--line);
  }

  .ring-idx {
    display: none;
  }
}

/* ≤480：规格列表与标注再收紧一档 */
@media (max-width: 480px) {
  .ring-specs {
    gap: calc(var(--s-4) * 1px) calc(var(--s-3) * 1px);
  }

  .ring-note {
    font-size: var(--fs-xs);
  }
}

/* 场景入口：大号等宽序号承担视觉锚点，替代原先的场景插画 */
.scene-no {
  display: block;
  font-family: var(--font-mono);
  font-size: 26px;
  line-height: 1;
  letter-spacing: .02em;
  color: var(--text-3);
  margin-bottom: calc(var(--s-4) * 1px);
}

/* 用 p.scene-keys 而非 .scene-keys：需与 .scene-card p 同权重并靠后声明才能生效 */
p.scene-keys {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .02em;
  line-height: 1.6;
  color: var(--text-2);
  margin-bottom: 0;
}

/* 首页板块 6（场景入口）由 4 张扩为 5 张后改用五列栅格（.grid--five，≥1180 为 5 列）。
   五列下卡宽 213px，扣掉 .scene-card 的 --s-6（32px）内边距后内容宽只有 149px，
   而 4 词关键词（如「房源 · 住户 · 权限 · 欠费」）实测约 161px ⇒ 会被折成两行；
   四列时内容宽 224px，本来是单行。
   本栅格内把内边距收到 --s-5、关键词去掉字距，关键词回到单行。
   ⚠️ 作用域限定在 `.grid--five`：板块 1 的 5 张卡用的是 `.cat-grid`，不受影响；
      solutions 里用 `.grid--five` 的是 `.cap-item`，也不受影响。 */
.grid--five .scene-card {
  /* 纵向 --s-5、横向 --s-4：1180 档卡宽只有 201px，横向留 24px 时内容宽 153px 仍差 4px，
     收到 16px 后内容宽 169px，关键词在 1180~1440 全档都是单行。 */
  padding: calc(var(--s-5) * 1px) calc(var(--s-4) * 1px);
}

.grid--five p.scene-keys {
  letter-spacing: 0;
}

/* --------------------------------------------------------------------------
   板块 02 开锁方式 · 产品线稿 + 六条引线 + 权限收束节点（2026-10-10 重做）

   原来这里挂的是一张外来营销位图（2200×1325）：底色实测 RGB(18,27,38) 偏蓝，
   而页面底色是 --bg-0 (8,8,10)，在深色页里就是一块「蓝底矩形」；而且那张图是
   「结构爆炸图」（锁体 / 电路板 / 螺丝），与本节主题「开锁方式」不对题，还与
   下方 6 项信息重复 —— 这正是本节「看着廉价」的根因。现改为自绘线稿：

     · .b-art      门锁正视图（内联 SVG，viewBox 180×330），只画结构线，无填充无阴影
     · .b-lines    六条引线（viewBox 与 .b-stage 同为 1160×560，端点与线稿成对）
     · .b-cbs      六条标注：桌面绝对定位贴引线端点，窄屏回落为两列
     · .b-collect  收束节点：六种方式 → DSLock 同一套权限 → 覆盖门锁 / 门禁 / 水电表

   ⚠️ 几何约定：.b-stage 用 aspect-ratio 锁死比例，.b-lines 的 viewBox 才能与线稿的
   百分比定位完全对齐（圆点在等比缩放下不会变椭圆）。改线稿落位或引线端点必须成对改。
   ⚠️ 主轮廓 .s / .f 亮、细节线 .d 淡，靠灰度做层级 —— 不用发光描边。
   -------------------------------------------------------------------------- */
.b-stage {
  position: relative;
  aspect-ratio: 1160 / 560;
}

.b-hero {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* 产品图背后的受光台面：极弱，只贴着锁体轮廓提一点亮 */
.b-glow {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 24%;
  height: 86%;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(42% 56% at 50% 50%, rgba(222, 241, 253, .10) 0%, rgba(158, 196, 220, .03) 52%, rgba(158, 196, 220, 0) 70%),
    radial-gradient(58% 62% at 50% 50%, rgba(42, 162, 221, .055) 0%, rgba(42, 162, 221, 0) 64%);
}

.b-art {
  position: absolute;
  left: 39.9017%;
  top: 4.0821%;
  width: 22.1672%;
  height: 84.1845%;
}

.b-art .s {
  fill: none;
  stroke: rgba(255, 255, 255, .19);
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.b-art .d {
  fill: none;
  stroke: rgba(255, 255, 255, .10);
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.b-art .f {
  fill: var(--bg-1);
  stroke: rgba(255, 255, 255, .20);
  stroke-width: 1;
}

/* 人脸模组：镜头芯 + 红外补光点 */
.b-art .lens {
  fill: rgba(255, 255, 255, .55);
  stroke: none;
}

.b-art .ir {
  fill: var(--accent);
  fill-opacity: .78;
  stroke: none;
}

.b-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.b-lines path {
  fill: none;
  stroke: var(--accent);
  stroke-opacity: .42;
  stroke-width: 1;
}

.b-lines path.lead-soft {
  stroke-opacity: .3;
}

.b-lines circle {
  fill: var(--accent);
  fill-opacity: .85;
}

/* 六条标注：桌面绝对定位，垂直位置 = 它标注的部件高度（stage 560 为分母） */
.b-cbs {
  display: contents;
}

.cb {
  position: absolute;
  transform: translateY(-50%);
}

.cb--l {
  left: 2%;
  width: 37%;
  text-align: right;
}

.cb--r {
  left: 61%;
  width: 37%;
  text-align: left;
}

.cb--finger {
  top: 29.1071%;
}

.cb--pin {
  top: 45.7143%;
}

.cb--card {
  top: 58.75%;
}

.cb--face {
  top: 13.5714%;
}

.cb--key {
  top: 69.8214%;
}

.cb--phone {
  top: 46.25%;
}

.cb-i {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .1em;
  color: var(--accent);
}

.cb-n {
  display: block;
  margin-top: calc(var(--s-1) * 1px);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.25;
}

.cb-b {
  display: block;
  margin-top: calc(var(--s-1) * 1px);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--text-2);
}

/* 收束节点 */
.b-collect {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--s-2) * 1px);
  width: fit-content;
  margin: 0 auto;
  padding: calc(var(--s-3) * 1px) calc(var(--s-5) * 1px);
  background: var(--bg-2);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-md);
}

.b-collect-row {
  display: flex;
  align-items: baseline;
  gap: calc(var(--s-3) * 1px);
}

.b-collect-k {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .14em;
  color: var(--accent);
}

.b-collect-t {
  font-size: var(--fs-sm);
  color: var(--text-1);
}

.b-collect-out {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--s-3) * 1px);
  width: 100%;
  padding-top: calc(var(--s-2) * 1px);
  border-top: 1px solid var(--line);
}

.b-collect-scope {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .08em;
  color: var(--text-3);
}

.b-collect-item {
  font-size: var(--fs-xs);
  color: var(--text-2);
  padding-left: calc(var(--s-3) * 1px);
  border-left: 1px solid var(--line);
}

/* 窄屏：线稿归中、引线收起、标注回落为两列 */
@media (max-width: 1024px) {
  .b-stage {
    aspect-ratio: auto;
  }

  .b-hero {
    position: relative;
    height: 330px;
  }

  .b-glow {
    top: 50%;
    width: 72%;
    height: 88%;
  }

  .b-art {
    left: 50%;
    top: 50%;
    width: 170px;
    height: auto;
    transform: translate(-50%, -50%);
  }

  .b-lines {
    display: none;
  }

  .b-cbs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: calc(var(--s-5) * 1px) calc(var(--s-4) * 1px);
    margin-top: calc(var(--s-8) * 1px);
  }

  .cb {
    position: static;
    transform: none;
    width: auto;
    text-align: left;
    border-top: 1px solid var(--line);
    padding-top: calc(var(--s-3) * 1px);
  }

  .cb-n {
    font-size: var(--fs-body);
  }

  .b-collect {
    margin-top: calc(var(--s-5) * 1px);
    width: 100%;
    text-align: center;
  }

  .b-collect-row {
    justify-content: center;
    flex-wrap: wrap;
  }

  .b-collect-out {
    flex-wrap: wrap;
    row-gap: calc(var(--s-2) * 1px);
  }
}


/* ==========================================================================
   18. 首屏光锥舞台 .ac-stage（A 方案 · 暗场光锥）

   首屏右栏舞台由三层构成，几何上全部以锁为圆心向外发散：
     · .ac-pool  受光台面 —— 位于产品之下的背景层，把近黑锁体从近黑页面切出来
     · .ac-cone  DSMesh 光锥 —— 同心环 + 向四周发散的射线，靠径向遮罩在边缘归零
     · .ac-bus   设备带   —— 四台设备 + 网关挂在一根总线上，再各自上汇到门锁

   ▉ 几何约定（勿随意改）：节点用 CSS 百分比定位，连线用
   viewBox="0 0 1000 1000" + preserveAspectRatio="none" 的 SVG ——
   (500,760) 即舞台 50% / 76%，(100,880) 即 10% / 88%。直线拉伸后仍是直线，
   节点本身不受拉伸影响；线再挂 vector-effect="non-scaling-stroke"，
   线宽与圆点半径都不随拉伸变形。
   ⚠ 节点位置（.ac-node--N 的 left）与 .ac-bus 的路径/圆点坐标必须成对修改。

   名称前缀 ac- 为本方案专用，已核对与既有类无重合。
   ========================================================================== */

/* 单列（<1180）时舞台整栏交给产品，顶部留出与文案的距离；
   桌面双栏（≥1180）改由视口高决定，并取消额外上边距。 */
.ac-stage {
  position: relative;
  height: 520px;
  margin-top: 32px;
}

@media (min-width: 1180px) {
  /* ⚠️ 这个高度和 .hero 的「一屏」是绑定的，改一个必须改另一个：
       首屏总高 = 73（页头）+ 64 + stage + 62（.hero-foot）+ 64，
       要正好等于 100vh ⇒ stage = 100vh - 263。这里取 -272 留 9px 余量，
       保证首屏内容略小于 min-height ⇒ min-height 生效 ⇒ 首屏严格一屏、内容居中。
     旧值 calc(100vh - 220px)（叠加旧的 80/64 非对称留白）会让首屏高到 902px，
     而页头以下的可见区只有 827px —— 底部的 endpoints 被切在视口外，
     内容视觉中心也比屏幕中心低 70px（客户反馈「信息偏下、上方黑色空间大」）。 */
  .ac-stage {
    height: clamp(430px, calc(100vh - 272px), 680px);
    margin-top: 0;
  }
}

/* 受光台面：位于产品之下，把近黑锁体从近黑页面切出来（非图片发光） */
.ac-pool {
  position: absolute;
  left: 50%;
  top: 41%;
  width: 88%;
  height: 62%;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(46% 40% at 50% 50%,
      rgba(222, 241, 253, .30) 0%,
      rgba(158, 196, 220, .10) 48%,
      rgba(158, 196, 220, 0) 78%),
    radial-gradient(64% 58% at 50% 50%,
      rgba(42, 162, 221, .16) 0%,
      rgba(42, 162, 221, 0) 72%);
  pointer-events: none;
}

/* 光锥：锁背后的 DSMesh 织物向四周发散，用径向遮罩让射线在边缘归零 */
.ac-cone {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(66% 62% at 50% 44%, #000 0%, #000 34%, rgba(0, 0, 0, .5) 64%, transparent 88%);
  mask-image: radial-gradient(66% 62% at 50% 44%, #000 0%, #000 34%, rgba(0, 0, 0, .5) 64%, transparent 88%);
}

.ac-ray {
  fill: none;
  stroke: var(--accent);
  stroke-opacity: .26;
  stroke-width: 1;
}

.ac-ring {
  fill: none;
  stroke: var(--accent);
  stroke-opacity: .14;
  stroke-width: 1;
}

/* 设备带：一根横向总线 + 每个节点的上汇支线，两端用线性遮罩淡出 */
.ac-bus {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 10%, #000 90%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 10%, #000 90%, transparent 100%);
}

.ac-line {
  fill: none;
  stroke: var(--accent);
  stroke-opacity: .42;
  stroke-width: 1;
}

.ac-joint {
  fill: var(--accent);
  fill-opacity: .85;
}

/* 设备节点：圆角瓦片 + 24 网格图标 + 等宽标签，统一挂在总线之上 */
.ac-node {
  position: absolute;
  top: 88%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  transform: translate(-50%, -22px);
}

.ac-node--1 {
  left: 10%;
}

.ac-node--2 {
  left: 30%;
}

.ac-node--3 {
  left: 50%;
}

.ac-node--4 {
  left: 70%;
}

.ac-node--5 {
  left: 90%;
}

/* 主图内的品牌署名：置于产品下方的铭牌位（产品占 8%~74%、设备母线在 88%），
   与页头 logo 共用同一套滤镜（白底反成黑底、黑字反成白字、品牌蓝保留） */
.ac-brand {
  position: absolute;
  left: 50%;
  top: 80%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.ac-brand img {
  display: block;
  width: auto;
  height: 26px;
  filter: invert(1) hue-rotate(180deg);
  /* 反相后白底变纯黑，直接叠在 #08080A 上会露出一块更黑的方块。
     screen 让纯黑完全透明（对底无影响），只留亮部字与图形标，接缝消失。
     ⚠️ 这里不能加 opacity<1 —— 半透明会把"纯黑底"按比例压上去，暗块又会回来 */
  mix-blend-mode: screen;
}

@media (min-width: 1180px) {
  .ac-brand img {
    height: 30px;
  }
}

@media (max-width: 768px) {
  .ac-brand img {
    height: 22px;
  }
}

.ac-tile {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--bg-2);
  border: 1px solid var(--line-hi);
  color: var(--text-2);
}

/* 中心节点 DSMesh 网关是全图唯一强调色 */
.ac-node--3 .ac-tile {
  border-color: var(--accent-line);
  color: var(--accent);
}

.ac-tile svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ac-label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .04em;
  color: var(--text-2);
  white-space: nowrap;
}

/* 断点：仅 1180 / 1024 / 768 / 480（1180 档见上，此处为窄屏） */
@media (max-width: 768px) {
  .ac-stage {
    height: 460px;
    margin-top: 24px;
  }

  .ac-node {
    transform: translate(-50%, -19px);
  }

  .ac-tile {
    width: 38px;
    height: 38px;
    border-radius: 10px;
  }

  .ac-tile svg {
    width: 19px;
    height: 19px;
  }
}

@media (max-width: 480px) {
  .ac-stage {
    height: 400px;
  }

  .ac-label {
    font-size: 10px;
  }

  .ac-node--1 {
    left: 9%;
  }

  .ac-node--2 {
    left: 30.5%;
  }

  .ac-node--4 {
    left: 69.5%;
  }

  .ac-node--5 {
    left: 91%;
  }
}


/* ==========================================================================
   19. 板块 4 管理系统 · 左卡右图叠放合成图（2026-10-11 接入正式官网）

   把设计稿「04 / 管理系统」整节搬进站内：
     · 左栏＝三张能力卡竖排（.s4-caps / .s4-cap）；
     · 右栏＝一整张叠放合成图（.cap-card.s4-stage）—— 一体机（背景层）
       → 两台手机（中前层、错落）→ 两台采集仪（最前层）；四者共用一条地平线
       （.s4-ground），越靠前底边越低。

   设备外壳是实拍照片抠图（public/assets/dev-aio.webp、dev-phone.webp，带 alpha），
   屏区在素材里挖空为透明，界面截图从素材背后透出（零变形、无缝）。

   本节只新增 s4-* / dev-* 规则，不改动站内任何既有类
   （.cap-card / .code / img / ul / .sect 一律沿用站内定义）。
   ⚠ 站内 .cap-card 自带 48px 内边距，舞台必须归零 —— 否则合成图各图层的
     百分比定位会改以 padding-box 为基准，整体走形。
   ⚠ 设计稿 ≤768 / ≤480 两档里对 .sect / .wrap / .sect-head 的覆写**未搬入**，
     纵向节奏继续交给站内 §15 断点统一管理。
   ⚠ 设计稿 .code 基类自带 margin:24px 0 0，站内 .code 是 margin:0，
     故把这段「与上方栅格的间距」落到 .s4-code 上，观感不变。
   ========================================================================== */

/* ============================================================
   两栏版式：左栏＝三张能力卡（竖排）／右栏＝整张叠放合成图
   ============================================================ */
.s4-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.34fr);
  gap: 24px;
  align-items: start;
}

.s4-caps {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  align-content: start;
}

.s4-cap {
  padding: 20px;
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

.s4-cap h3 {
  font-size: var(--fs-body);
  font-weight: 600;
  margin-bottom: 10px;
}

.s4-cap li {
  position: relative;
  padding-left: 14px;
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.8;
}

.s4-cap li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .72em;
  width: 4px;
  height: 4px;
  border-radius: var(--r-pill);
  background: var(--accent);
}

/* ============================================================
   右栏舞台：一整张叠放合成图
   （底纹 / 描边 / 圆角沿用站内 .cap-card，见 §9·§10）
   ============================================================ */
.s4-stage {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  aspect-ratio: 1160 / 754;
}

/* 地平线 / 台面：显示器立在它上面，手机、采集仪依次更靠前、底边更低 */
.s4-ground {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 11%;
  height: 1px;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(90deg,
      transparent 2%,
      var(--line) 14%,
      var(--line-hi) 50%,
      var(--line) 86%,
      transparent 98%);
}

/* 图层：铺满舞台，仅用于分层（z-index）；不吃指针事件，
   这样「支架是否被遮挡」可用 elementFromPoint 精确判定到真实设备 */
.s4-lay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.s4-lay .dev-aio,
.s4-lay .s4-phone,
.s4-lay .s4-collector {
  pointer-events: auto;
}

.s4-lay--aio {
  z-index: 2;
}

.s4-lay--phones {
  z-index: 3;
}

.s4-lay--collectors {
  z-index: 4;
}

/* 接触阴影：纯静态径向渐变，落在同一张台面上 */
.s4-lay::before {
  content: "";
  position: absolute;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .55), rgba(0, 0, 0, 0) 74%);
}

.s4-lay--aio::before {
  left: 28.5%;
  bottom: 9.9%;
  width: 32.5%;
  height: 22px;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .74), rgba(0, 0, 0, 0) 72%);
}

.s4-lay--phones::before {
  left: 63%;
  bottom: 11.4%;
  width: 32%;
  height: 26px;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .66), rgba(0, 0, 0, 0) 74%);
}

.s4-lay--collectors::before {
  left: 7%;
  bottom: 6.6%;
  width: 24%;
  height: 18px;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .62), rgba(0, 0, 0, 0) 74%);
}

/* ===== 图层 1（背景层）：一体机，支架完整可见，落在台面上 ===== */
.s4-lay .dev-aio {
  position: absolute;
  left: 6%;
  bottom: 11%;
  width: 68%;
}

/* ===== 图注：整张合成图的图例（一行，等宽字体） ===== */
.s4-legend {
  position: absolute;
  left: 3%;
  right: 3%;
  bottom: 4px;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 28px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 1.2;
  color: var(--text-3);
}

/* ============================================================
   一体机：素材 dev-aio.webp（1134×914，实拍银铝机身，含支架颈与底座脚）
   白底抠图：alpha 由「亮度梯度」软边生成（1~2px 抗锯齿，非二值硬边），未做任何放大。
   屏幕（壁纸）为直角矩形，按同一矩形在原图上挖空为透明；
   截图从素材背后透出，贴图四周各外扩约 12px 被机身黑边压住，接缝永远被盖住。
   ============================================================ */
.dev-aio {
  position: relative;
  width: 100%;
  aspect-ratio: 1134 / 914;
}

/* 实拍机身：压在截图上，负责整机轮廓、下巴、支架颈、底座脚 */
.dev-aio-shell {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  z-index: 2;
  pointer-events: none;
}

/* 屏幕截图层：比挖孔四周各外扩约 12px（素材像素），外扩部分被机身黑边压住；
   宽高由 <img> 自身比例决定（width:100% + height:auto，不做任何拉伸） */
.dev-aio-screen {
  position: absolute;
  left: 2.8219%;
  top: 4.3285%;
  width: 94.3563%;
  z-index: 1;
  overflow: hidden;
  border-radius: 0;
  background: #000;
}

.dev-aio-screen img {
  display: block;
  width: 100%;
  height: auto;
}

/* 下巴 / 支架颈 / 底座脚：外壳已画在实拍素材里，这里只放同名透明命中层，
   保证 elementFromPoint 落在真实部件上（也是量测基准） */
.dev-aio-chin {
  position: absolute;
  left: 0;
  top: 69.4748%;
  width: 100%;
  height: 16.3020%;
  z-index: 3;
  pointer-events: auto;
}

.dev-aio-neck {
  position: absolute;
  left: 39.4180%;
  top: 85.7768%;
  width: 21.2522%;
  height: 11.9256%;
  z-index: 3;
  pointer-events: auto;
}

.dev-aio-foot {
  position: absolute;
  left: 34.8325%;
  top: 97.9212%;
  width: 30.4233%;
  height: 2.0788%;
  z-index: 3;
  pointer-events: auto;
}

/* ============================================================
   手机：素材 dev-phone.webp（464×949，只取实拍正面视图：黑金属中框 + 灵动岛）
   屏区外沿保留 3px 近黑环、屏孔再内缩 3px 挖空为透明，截图从背后透出；
   灵动岛在素材里（不透明），天然压住截图
   ============================================================ */
.s4-phone {
  position: absolute;
  margin: 0;
}

.s4-phone--back {
  left: 78%;
  bottom: 14.5%;
  width: 13%;
  z-index: 1;
}

.s4-phone--front {
  left: 67%;
  bottom: 12.6%;
  width: 15.3%;
  z-index: 2;
}

.dev-phone {
  position: relative;
  width: 100%;
  aspect-ratio: 464 / 949;
}

.dev-phone-shell {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  z-index: 2;
  pointer-events: none;
}

/* 屏幕截图层：比挖孔四周各外扩 2px；截图（1080×2400）比屏孔略高，
   用 flex 垂直居中、overflow 裁掉上下各约 13px（只裁不拉伸，比例不变） */
.dev-phone-screen {
  position: absolute;
  left: 4.3103%;
  top: 1.7914%;
  width: 91.3793%;
  height: 96.4173%;
  z-index: 1;
  overflow: hidden;
  display: flex;
  align-items: center;
  border-radius: 9.1981% / 4.2623%;
  background: #000;
}

.dev-phone-screen img {
  display: block;
  width: 100%;
  height: auto;
  flex: 0 0 auto;
}

/* ===== 图层 3（最前层）：人脸采集仪 + 指纹采集仪 ===== */
.s4-collector {
  position: absolute;
  margin: 0;
}

.s4-collector img {
  display: block;
  width: 100%;
  height: auto;
}

.s4-collector--face {
  left: 7%;
  bottom: 9.2%;
  width: 7%;
  z-index: 1;
}

.s4-collector--fp {
  left: 12%;
  bottom: 7.8%;
  width: 17%;
  z-index: 2;
}

/* ===== 接口条：保留代码块，压成通栏薄条弱化（基类见 §8 .code） ===== */
.s4-code {
  margin-top: 24px;
  padding: 16px 20px;
  font-size: var(--fs-xs);
  line-height: 1.7;
}

/* ===== 断点：仅 1180 / 1024 / 768 / 480 ===== */

/* ≤1180：整体等比缩小；舞台略压扁，补偿窄屏下设备占比变化 */
@media (max-width: 1180px) {
  .s4-stage {
    aspect-ratio: 1160 / 750;
  }
}

/* ≤1024：改回单栏（卡片在上、图在下）；合成图居中并限宽，保持「不需要太大」 */
@media (max-width: 1024px) {
  .s4-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }

  .s4-caps {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 16px;
  }

  .s4-stage {
    justify-self: center;
    width: 100%;
    max-width: 720px;
    aspect-ratio: 1160 / 750;
  }
}

/* ≤768：不再「上下堆叠」，而是**保住桌面那张叠放合成图、整体等比缩小**。
   客户反馈手机端"每张图按顺序排下去"，故淘汰原先 flex-column 的竖排覆写。
   合成图全靠绝对定位 + 百分比，天然等比缩放：这里只做两件必要的事 ——
   (1) 把舞台限宽并居中；(2) 图注收紧。
   ⚠️ 绝不改任何 left / top / width / bottom 百分比，aspect-ratio 也保持 1160/754
      （置 auto 会退回堆叠 —— 那正是要淘汰的写法）。 */
@media (max-width: 768px) {
  .s4-caps {
    grid-template-columns: minmax(0, 1fr);
  }

  .s4-stage {
    max-width: 520px;
    margin-inline: auto;
  }

  .s4-legend {
    gap: 14px;
  }
}

/* ≤480：仍保持同一张等比合成图，只把图注一行再收紧 */
@media (max-width: 480px) {
  .s4-legend {
    gap: 5px;
    font-size: 10px;
  }
}


/* ==========================================================================
   19. 手机档（< 768px）网格化 —— 让窄屏也保持与 PC 一致的多列节奏
   --------------------------------------------------------------------------
   【用户反馈 2026-10-11】手机上"基本上每个图片都是按顺序排下去的"，
   与 PC 的多列节奏差异过大。

   【根因】本站是 mobile-first，但基础档把绝大多数内容网格都写成了单列
   （`.grid--cards` / `.grid--4` / `.grid--pairs` / `.grid--five` / `.path-grid` /
   `.frame-grid` / `.frame-grid--four` / `.ability-grid` / `.resource-grid` /
   `.about-grid` / `.badge-row` / `.cat-grid` / `.cap-grid` / `.support-grid` /
   `.guide-grid` / `.method-list` 全部是 `minmax(0, 1fr)`），
   只有 ≥768 才升 2~3 列、≥1180 才升 3~5 列 ⇒ 手机上每张卡独占一行。

   【改法】手机档统一补成 2 列；奇数项区块让末项跨双列（右下不留空洞）。
   断点取 767px —— 现有档位是 768 / 1024 / 1180，767 正好落在 768 之下，互不重叠。
   ⚠️ 本块在文件末尾，同特异性下后定义者胜 ⇒ 能覆盖基础档与既有 max-width 块。
   ⚠️ 只动网格与图片框尺寸，不改卡片内的字号 / 内边距 —— 那部分等 375 截图确认后再调。
   ========================================================================== */
@media (max-width: 767px) {
  /* ---------- 1) 内容网格：手机档 2 列 ---------- */
  .grid--cards,
  .grid--4,
  .grid--pairs,
  .grid--five,
  .path-grid,
  .frame-grid,
  .frame-grid--four,
  .ability-grid,
  /* ⚠️ 刻意**不含** `.resource-grid` —— 它是「左树状目录 + 右七步主线」的**文档双栏**
     （桌面 1fr / 1.5fr），不是等宽卡片网格；手机档强分 2 列会把左树与右步骤挤成
     两条窄柱、文字碎成一片（open-platform「技术资料」节实测反而更高更碎）。保持 1 列。 */
  /* ⚠️ 刻意**不含** `.s4-caps` —— 04 块已改为「保持桌面合成图、只等比缩小」，
     左栏三张能力卡在 ≤768 继续保持单列（与 ≤1024 单栏一致），不参与手机 2 列。 */
  /* ⚠️ 刻意**不含** `.about-grid` —— 它是「左长文 + 右大图」的编辑排版（桌面 1fr / 1fr），
     375 强分 2 列会把正文压到 ~162px、≈10 字/行（可读性硬伤），故恢复基础档单列。
     判定标准统一为：正文单行字数低于约 14 字即转单列（同 `.resource-grid`）。 */
  .badge-row,
  .cat-grid,
  .cap-grid,
  .support-grid,
  .guide-grid,
  .method-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
  }

  /* ---------- 1b) `.about-grid`：恢复基础档单列（文案通栏在上、图通栏在其下） ----------
     桌面 1fr / 1fr 与其余几何一字不动；仅手机档回到「左文右图」上下堆叠。
     ⚠️ `.shot--hero` 一并在本档回到**基础尺寸**：`.shot{--shot-h:148px}` 是 2 列档为压矮
        图框而设的压缩值，单列后不应再压。用 (0,2,0) 选择器把 `--shot-h` 复位为基础 420px，
        配合 `.shot--hero{aspect-ratio:4/5}` → 336×420，恰好通栏置于文案之下。 */
  .about-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .about-grid .shot--hero {
    --shot-h: 420px;
  }

  /* ---------- 2) 奇数项：末项通栏，避免右下角留一个空洞 ----------
     5 项的区块（产品线 cat-grid / 场景入口 grid--4）
     与 3 项的区块（能力 / 支持 / 指引 / 方法列表 / 案例 pairs / s4 图注）都命中这条。
     ⚠️ `.grid--pairs`：cases 的 g1/g2/g5 各 3 项 → 末项通栏；
        solutions 的公租房痛点卡为 8 项（偶数）→ 本条不命中，该节几何不受影响。 */
  .grid--4 > :last-child:nth-child(odd),
  .grid--pairs > :last-child:nth-child(odd),
  .grid--five > :last-child:nth-child(odd),
  .cat-grid > :last-child:nth-child(odd),
  .cap-grid > :last-child:nth-child(odd),
  .support-grid > :last-child:nth-child(odd),
  .guide-grid > :last-child:nth-child(odd),
  .method-list > :last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }

  /* ---------- 3) 图片框跟着列宽一起收 ----------
     基类是 `height: var(--shot-h, 216px)` + `aspect-ratio: 1/1`；
     列宽从 ~335px 掉到 ~165px 后，若高度不跟着收，图框会变高瘦、四周留白过多。 */
  .shot {
    --shot-h: 148px;
  }

  /* 水印跟着缩一档，否则在 165px 宽的图框里占比过大 */
  .shot::after {
    top: 6px;
    right: 7px;
    width: clamp(30px, 22%, 46px);
  }

  /* 现场照片是 3:5 竖幅，2 列后同样压矮一档 */
  .shot--tall {
    --shot-h: 228px;
  }
}

/* ==========================================================================
   20. 首页板块 1 品类卡 · 右下角产品小图（.scene-thumb）
   --------------------------------------------------------------------------
   需求：首页板块 1 的 5 张品类卡（门禁与梯控 / 智慧网关 / 智慧水电表 /
   取电开关 / 采集设备）各配一张真实产品小图，落在**卡片右下角**，
   与左下角「查看」链接置于同一水平带。

   ▉ 为什么不改 `.scene-card` 基类：`.scene-card` 在首页**板块 6（场景入口）**
   也用了 4 张，动基类会连带影响那边。故只给板块 1 的这 5 张卡挂
   `has-thumb`（提供定位上下文）+ `scene-thumb`（右下角浮层），
   其余 `.scene-card` 完全不受影响。

   ▉ 为什么不复用 `.shot`：`.shot` 自带品牌水印 ::after 与多层径向发光底，
   在 ~72px 下只会变成噪点与糊斑；这里用轻量专属容器。
   ▉ 按用户要求**去掉"框框"**：不设 background、不设 box-shadow，设备透明抠图
   直接落在卡面上（`overflow: visible`，不裁切产品）。

   ▉ 为什么不参与文档流：小图 `position:absolute`，不撑高卡片，
   同一行 5 张卡仍靠 grid 的默认 stretch 保持等高。

   ▉ 产品图真实颜色：不加任何 filter / opacity / mix-blend-mode。
   ▉ `right` / `bottom` 均取卡片内边距 `--s-6`（= 32px），与「查看」链接
   的下内边距对齐；尺寸用 clamp 随视口收缩（桌面封顶 72px，375 档 ≈48.75px），
   以免在 2 列窄卡（375 档卡内宽仅 98px）里与左下角链接重叠。
   ========================================================================== */

.has-thumb {
  position: relative;
}

.scene-thumb {
  position: absolute;
  right: calc(var(--s-6) * 1px);
  bottom: calc(var(--s-6) * 1px);
  width: clamp(46px, 5vw + 30px, 72px);
  height: clamp(46px, 5vw + 30px, 72px);
  /* 无底板、无描边、无圆角框：设备直接落在卡面上。 */
  pointer-events: none;
  /* 没有框就不该裁切产品：改为 visible（img 仍 object-fit:contain 居中铺满）。 */
  overflow: visible;
}

/* 产品图用**绝对定位 + 显式尺寸**钉死（同 `.shot img` 的历史修复）：
   若直接给子元素 width/height:100%，在“网格 + 内在比例”下窄高素材
   会退化成 auto、撑破容器；这里 inset 4px → 64×64 居中，配 object-fit:contain
   才能把整张图完整放进容器且不变形、不裁切。 */
.scene-thumb img {
  position: absolute;
  left: 4px;
  top: 4px;
  width: calc(100% - 8px);
  height: calc(100% - 8px);
  display: block;
  object-fit: contain;
}

/* ============================================================

   21. 首屏三段式 · 视频 → 文案 → 原大图浮现（2026-10-12）

   --------------------------------------------------------------------------
   状态机挂在 `.ac-stage` 的 `data-stage` 上：video（默认）→ text → lock。
   三段之间**只用 transition**，不新增任何 @keyframes（全站仍只有 float 一个）。

   ⚠️ 全部规则都以 `html.js-film` 为前提 —— 该类由 site.js 在**解析完 DOM、首次绘制之前**
      判定并打上（桌面档 + 未开启「减弱动态效果」+ 支持 mp4 三者同时满足才打）。
      · 无 JS、移动档、用户开了减弱动效 ⇒ **没有 .js-film** ⇒ 这三层永不进场、
        原大图/铭牌/节点保持可见 —— **绝不空屏**，这是本节的底线。
      · 加了 .js-film 才把原大图置为初始隐藏态，所以也不会「先闪一下原图再切视频」。

   ▉ 槽位：`.ac-video` 与 `.shot--bare` 用**同一套定位**
      （left 50% / top 41% / translate(-50%,-50%) / max-width 90% / height 66%）。
      原图是 1500×1485 ≈ 1.0101，视频是 1920×1920 = 1:1 —— 比例几乎一致，
      所以切换时 **版面不动、不跳**。

   ▉ 光锥场景（.ac-pool / .ac-cone / .ac-bus）是这场戏的舞台，**三段里一直在**；
      隐藏与浮现的只有「属于产品」的 `.shot--bare`、`.ac-brand`、`.ac-node`。

   ============================================================ */

/* —— 三个新图层默认不显示；只有 .js-film 才让它们进场 —— */
.ac-video,
.ac-film-text,
.ac-skip {
  display: none;
}

.js-film .ac-video,
.js-film .ac-film-text,
.js-film .ac-skip {
  display: block;
}

/* —— 视频层：与原大图同一槽位 —— */
.ac-video {
  position: absolute;
  left: 50%;
  top: 41%;
  transform: translate(-50%, -50%);
  width: auto;
  max-width: 90%;
  height: 66%;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: none;
  opacity: 1;
  transition: opacity .4s ease;
  pointer-events: none;
  /* ⚠️ 片子是近黑底（实测四角 RGB 10,9,12）而页面底色是 #08080A（8,8,10），
     两者只差 1~2 级、肉眼几乎看不出；但**视频矩形会挡住背后 .ac-pool 的受光台面**，
     于是矩形边缘会被光晕勾出一圈可见的"框"。用一层同心径向羽化把四周溶掉。
     ⚠️ 不透明半径的取值被**标注文字的位置**卡死了，不能只按锁体算：
       片子里的竖排标注（图标 + 人脸/密码/NFC/指纹/机械钥匙）落在画面左侧 **x 3.0%~30%**，
       图标中心在 4.6% —— 旧值 82%（不透明区只到 ±82%，即 x < 9% 就开始变淡）
       把图标压到 56% 不透明度、文字压到 76%，客户反馈「红框里的文字显示不出来」。
       现取值 95%：变淡区只剩 x < 2.5%，落在图标（3.0% 起）之外 ⇒ 标注 100% 保留；
       代价是羽化带从 31px 收到 10px，矩形边缘的"框"会略微更实一点。
       实测锁体占到 ±72%，所以下限不能低于 82%（取 55% 会把锁的上下两端一起压暗，画面均值 13.8 → 9.4）。 */
  -webkit-mask-image: radial-gradient(closest-side, #000 95%, rgba(0, 0, 0, .5) 98%, transparent 100%);
  mask-image: radial-gradient(closest-side, #000 95%, rgba(0, 0, 0, .5) 98%, transparent 100%);
}

/* —— 文案层：视频结束后出现在同一槽位中央 —— */
.ac-film-text {
  position: absolute;
  left: 50%;
  top: 41%;
  transform: translate(-50%, -50%) translateY(12px);
  width: 78%;
  margin: 0;
  text-align: center;
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.7;
  letter-spacing: .01em;
  color: var(--text-1);
  opacity: 0;
  transition: opacity .6s ease, transform .6s ease;
  pointer-events: none;
}

/* —— 跳过：只在 video / text 两态可见（进 lock 后淡出并让出指针） —— */
.ac-skip {
  position: absolute;
  left: 50%;
  bottom: 5%;
  transform: translateX(-50%);
  margin: 0;
  padding: 6px 16px;
  border: 1px solid var(--line-hi);
  border-radius: var(--r-pill);
  background: none;
  color: var(--text-2);
  font: inherit;
  font-size: var(--fs-xs);
  letter-spacing: .06em;
  cursor: pointer;
  opacity: 1;
  transition: opacity .4s ease, color .2s ease, border-color .2s ease;
}

.ac-skip:hover {
  color: var(--text-1);
  border-color: var(--text-3);
}

.ac-skip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* —— 初始态 video：只出视频；原大图、铭牌、5 节点全部隐去 —— */
.js-film .ac-stage .shot--bare {
  opacity: 0;
  transform: translate(-50%, -50%) translateY(14px) scale(.985);
  transition: opacity .9s ease, transform .9s ease;
}

.js-film .ac-stage .ac-brand,
.js-film .ac-stage .ac-node {
  opacity: 0;
  transition: opacity .9s ease .18s;
}

/* —— 态 text：视频退场，文案进场 —— */
.js-film .ac-stage[data-stage="text"] .ac-video {
  opacity: 0;
}

.js-film .ac-stage[data-stage="text"] .ac-film-text {
  opacity: 1;
  transform: translate(-50%, -50%);
}

/* —— 态 lock：终态。原大图 + 铭牌 + 节点「浮现」—— */
.js-film .ac-stage[data-stage="lock"] .ac-video,
.js-film .ac-stage[data-stage="lock"] .ac-film-text,
.js-film .ac-stage[data-stage="lock"] .ac-skip {
  opacity: 0;
  pointer-events: none;
}

.js-film .ac-stage[data-stage="lock"] .shot--bare {
  opacity: 1;
  transform: translate(-50%, -50%);
}

.js-film .ac-stage[data-stage="lock"] .ac-brand,
.js-film .ac-stage[data-stage="lock"] .ac-node {
  opacity: 1;
}


/* ==========================================================================
   29. 解决方案 · 公租房面板 v2（自外部「官网区块」整合，2026-10-12）

   ⚠️ 本节的来源是 `推广物料\臻格公租房方案-官网区块.html` 自带的 <style>。
      该 <style> 共 107 条声明，其中 **57 条与本站逐字相同**（作者是照本站规范写的），
      本节**只并入站内原本没有的 47 条**，因此对其它三个方案面板、其它页面零影响。
   ⚠️ 刻意**没有**并入的两类（避免覆盖与串味）：
      · `.page-head`（区块里是 128/80 的上内边距）—— 区块自己标注「页面导语整合时不复制」；
      · `.pain-item { line-height }`（区块 1.7 / 站内 1.75）—— 站内值已定稿，且四个方案面板共用。
   ⚠️ 本节全部是新类族（线图 / 配图 / 设备条），与既有类无重名。
   ========================================================================== */

.model-table--pic td:first-child {
  font-family: inherit;
  letter-spacing: normal;
  width: 76px;
}

.cell-pic {
  padding: calc(var(--s-2) * 1px) calc(var(--s-3) * 1px) !important;
  vertical-align: middle !important;
}

.cell-pic img {
  display: block;
  width: 64px;
  height: 64px;
  object-fit: contain;
}

/* 型号表图列没有对应产品图时的占位（保持 64×64 占位不变，行高不塌） */
.cell-pic-none {
  display: block;
  width: 64px;
  height: 64px;
  line-height: 64px;
  text-align: center;
  color: var(--text-3);
}

/* 窄屏（375）下，型号表的最小宽度不应被长型号串撑破容器 ——
   例：DS101-FSQD / PS-ZBW02 这类无空格长串默认不可断行，会把表宽抬到 350px（容器只有 335px）。
   允许在任意点断行后，表宽回到容器宽；宽屏下该属性不生效（有富余空间，不会真的断行）。 */
.model-table th,
.model-table td {
  overflow-wrap: anywhere;
}

/* 窄屏（375）下，型号表的最小宽度不应被长型号串撑破容器 ——
   例：DS101-FSQD / PS-ZBW02 这类无空格长串默认不可断行，会把表宽抬到 350px（容器只有 335px）。
   允许在任意点断行后，表宽回到容器宽；宽屏下该属性不生效（有富余空间，不会真的断行）。 */
.model-table th,
.model-table td {
  overflow-wrap: anywhere;
}

.contact-line {
  margin-top: calc(var(--s-5) * 1px);
  font-size: var(--fs-h3);
  color: var(--text-1);
  letter-spacing: .04em;
}

.contact-sub {
  margin-top: calc(var(--s-2) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.figure {
  margin: calc(var(--s-6) * 1px) 0 0;
  padding: calc(var(--s-4) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.figure + .figure {
  margin-top: calc(var(--s-4) * 1px);
}

.figure img {
  display: block;
  width: 100%;
  height: var(--pic-h, 200px);
  object-fit: contain;
  object-position: center;
  border-radius: var(--r-sm);
}

.figure--tall img {
  width: auto;
  max-width: 100%;
  margin: 0 auto;
}

.figure figcaption {
  margin-top: calc(var(--s-3) * 1px);
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--text-3);
}

.with-figure {
  display: grid;
  gap: calc(var(--s-6) * 1px);
}

.with-figure > .figure {
  margin-top: 0;
}

.dg-flow {
  margin-top: calc(var(--s-6) * 1px);
  padding: calc(var(--s-6) * 1px) calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.flow-row {
  display: grid;
  gap: calc(var(--s-4) * 1px);
  align-items: start;
}

.flow-node {
  position: relative;
  padding: 0 0 0 calc(var(--s-5) * 1px);
}

.flow-node::before {
  content: "";
  position: absolute;
  left: 0;
  top: .7em;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

.flow-node::after {
  content: "";
  position: absolute;
  left: 3px;
  top: calc(.7em + 14px);
  bottom: calc(var(--s-4) * -1px + 8px);
  width: 1px;
  background: var(--line);
}

.flow-node:last-child::after {
  display: none;
}

.flow-node h4 {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-1);
}

.flow-node p {
  margin-top: calc(var(--s-1) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.7;
}

.dg-cap {
  margin-top: calc(var(--s-5) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

/* ⚠️ `figure` 有 UA 默认 `margin: 1em 40px` —— 只写 margin-top 会把左右 40px 留着，
   整张线图因此比「方案介绍」的流程框多缩进 40px（2026-10-13 客户：「块与块排版不对」）。
   必须显式把左右归零，才能与 .dg-flow 的边框完全对齐。 */
.dg {
  margin: calc(var(--s-6) * 1px) 0 0;
  padding: calc(var(--s-6) * 1px) calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.dg svg {
  display: block;
  width: 100%;
  height: auto;
}

.dg text {
  font-family: var(--font-sans);
  fill: var(--text-2);
  font-size: 13px;
}

.dg .t-1 {
  fill: var(--text-1);
  font-weight: 600;
}

.dg .t-3 {
  fill: var(--text-3);
  font-size: 12px;
}

.dg .t-a {
  fill: var(--accent);
}

.dg .box {
  fill: var(--bg-0);
  stroke: var(--line);
}

.dg .box-a {
  fill: var(--bg-0);
  stroke: var(--accent-line);
}

.dg .ln {
  stroke: var(--line-hi);
  fill: none;
}

.dg .ln-a {
  stroke: var(--accent);
  fill: none;
}

.dg .dot {
  fill: var(--accent);
}

/* 自绘箭头（开放接口 → 项目定制管理平台）：不用 <marker>，省掉一个 id */
.dg .ar {
  fill: var(--accent);
  stroke: none;
}

.device-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(var(--s-4) * 1px);
  margin-top: calc(var(--s-5) * 1px);
}

.device-item {
  display: flex;
  align-items: center;
  gap: calc(var(--s-3) * 1px);
  padding: calc(var(--s-3) * 1px) calc(var(--s-4) * 1px);
  background: var(--bg-0);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}

.device-item img {
  flex: none;
  width: 40px;
  height: 40px;
  object-fit: contain;
}

.device-item span {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.5;
}

.device-item b {
  display: block;
  color: var(--text-1);
  font-weight: 600;
}

@media (min-width: 768px) {
  .flow-row {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: calc(var(--s-5) * 1px);
  }

  .flow-node {
    padding: calc(var(--s-4) * 1px) 0 0;
  }

  .flow-node::before {
    top: 0;
  }

  .flow-node::after {
    left: calc(var(--s-5) * 1px);
    right: calc(var(--s-5) * -1px);
    top: 3px;
    bottom: auto;
    width: auto;
    height: 1px;
  }

  .device-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .with-figure {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
  }

  .figure--wide {
    --pic-h: 260px;
  }

  .figure--pair {
    --pic-h: 200px;
  }

  .figure--tall {
    --pic-h: 360px;
  }

}

@media (min-width: 1180px) {
  .device-grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

}

/* 公租房 v2 面板里唯一一处内联 style 的等价类（站内红线禁内联 style） */
.frame-grid--top {
  margin-top: calc(var(--s-6) * 1px);
}

/* ---- 29.x 面板减负：现场困境折叠 + 方案介绍分步（2026-10-12 客户「文字太多、太繁琐」）------------
   文字量：默认可见 2391 字 → 约 1250 字。做法是"折叠 + 分步"，不是删内容 —— 细节全留在 DOM 里。

   ⚠️ 折叠用**原生 `<details>`**：不写一行 JS，浏览器自带展开语义，JS 没跑起来照样能点开，
     搜索引擎也读得到（不是 display:none 藏内容）。
   ⚠️ 分步的显隐写在 `.js [data-step-panel]` 下 —— 与 `.js [data-panel]` 同一套退化路径：
     JS 失效时四步全部铺开，仍然可读，不会只剩第一步。
   ⚠️ 内层刻意用 `data-step` / `data-step-panel`，**绝不能用 `data-panel`**：
     initTabs 用的是全局 `querySelectorAll('[data-panel]')`，复用会把外层方案面板一起切走。
   -------------------------------------------------------------------------- */

/* 现场困境：三组平铺卡片（桌面三列 / 平板两列 / 手机一列）。
   一组一张卡 = 一张现状配图 + 组名 + 「现在的做法」+ 现象清单 + 「门锁联网之后」。
   三组名取自原「线索图」的三组归纳 —— 原来那 8 条长句与那张总结图讲的是同一批内容的两遍，现合并为一处。
   ⚠️ 跨卡对齐（2026-10-12：客户「三个段落对齐不一致」）：
     三张卡的四块内容长度都不等 ——「现在的做法」1~2 行、现象 2~4 条、强调句 2~3 行。
     若各按内容自然堆叠，下面每块的顶边就各落在不同高度上。做法是让每块高度确定：
       ① `.pain-now` 在并排布局下预留 2 行（见 768 断点），使清单顶边对齐；
       ② `.pain-list` 去掉 `flex:1 1 auto`，改 `align-content:start` + 预留 4 条高度，
          使多余空间不再分摊进行高（旧版行距被撑开），强调块顶边因此对齐；
       ③ `.pain-fix` 用 `flex:1 1 auto` 吸收卡底剩余高度，顶边与底边同时对齐成齐整色块。
     单列（<768）无跨卡对齐概念，故 ①② 的预留只在 768 断点内生效，卡内不留空白。 */
.pains {
  display: grid;
  gap: calc(var(--s-4) * 1px);
}

.pain {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.pain-fig {
  background: var(--bg-2);
}

/* 配图高度走变量（与 §四之十四「只给框定高、不给 img 定宽」同一口径）：
   三张图同高 ⇒ 不会出现「同一容器两种排版」的那种乱。 */
.pain-fig img {
  display: block;
  width: 100%;
  height: var(--pain-pic-h, 200px);
  object-fit: cover;
}

.pain-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  padding: calc(var(--s-5) * 1px);
}

.pain-key {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-1);
}

.pain-now {
  margin-top: calc(var(--s-1) * 1px);
  font-size: var(--fs-sm);
  line-height: 1.8;
  color: var(--text-3);
}

.pain-list {
  flex: 0 0 auto;
  display: grid;
  align-content: start;
  gap: calc(var(--s-2) * 1px);
  margin: calc(var(--s-4) * 1px) 0;
}

.pain-list li {
  position: relative;
  padding-left: calc(var(--s-4) * 1px);
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.7;
}

.pain-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .62em;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--text-3);
}

.pain-fix {
  flex: 1 1 auto;
  padding-left: calc(var(--s-4) * 1px);
  border-left: 2px solid var(--accent-line);
  font-size: var(--fs-sm);
  color: var(--text-1);
  line-height: 1.7;
}

/* 方案介绍：四个流程节点变成可点的步骤条（沿用 .flow-row / .flow-node 的圆点与连线，不另画图）。
   未选中的节点圆点压成灰阶，选中/悬停时才回到文字一级亮度 —— 品牌蓝只留给选中态。 */
.flow-node {
  appearance: none;
  width: 100%;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  background: none;
  border: 0;
  cursor: pointer;
}

.flow-name {
  display: block;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-2);
  transition: color .2s ease;
}

.flow-node:hover .flow-name,
.flow-node.is-selected .flow-name {
  color: var(--text-1);
}

.flow-node:not(.is-selected)::before {
  background: var(--text-3);
}

.flow-node:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: var(--r-sm);
}

/* 四个阶段的文案全部常显、排成一行：列模板与间距必须与 .flow-row / .step-figs 完全一致，
   ⚠️ 三处成对改，否则图文与文案会错列。（2026-10-13 客户：不要点击才显示） */
.step-bodies {
  display: grid;
  gap: calc(var(--s-4) * 1px);
  margin-top: calc(var(--s-5) * 1px);
}

.step-body h4 {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-1);
  margin-bottom: calc(var(--s-2) * 1px);
}

.step-body p {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.75;
  max-width: 78ch;
}

.step-body p + p {
  margin-top: calc(var(--s-3) * 1px);
}

.js [data-step-panel] {
  display: none;
}

.js [data-step-panel].is-active {
  display: block;
}

/* 面板内粘性小节导航：面板很长，没有目录只能一路滚。
   与页头下的标签条同一手法（.tabs--sticky），top 贴住 72px 页头下沿；
   sticky 的作用域被父级 .wrap 约束，不会溢出到下一个面板。 */
.subnav {
  position: sticky;
  top: 72px;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--s-4) * 1px);
  margin-bottom: calc(var(--s-6) * 1px);
  padding: calc(var(--s-3) * 1px) 0;
  background: var(--bg-0);
  border-bottom: 1px solid var(--line);
}

.subnav a {
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.subnav a:hover,
.subnav a:focus-visible {
  color: var(--accent);
}

/* 现场困境三组：平板两列 / 桌面三列（断点只用站内允许的 768 与 1180） */
@media (min-width: 768px) {
  .pains {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* 并排（两列 / 三列）时同一行内跨卡对齐：按「最多行数 / 最多条数」给长度不一的
     两块预留高度，四块内容的顶边即落在同一条水平基准上。单列不预留，卡内不留空白。 */
  .pain-now {
    min-height: calc(2 * 1.8 * var(--fs-sm)); /* 「现在的做法」最多 2 行 */
  }

  .pain-list {
    min-height: calc(4 * 1.7 * var(--fs-sm) + 3 * (var(--s-2) * 1px)); /* 现象最多 4 条 */
  }
}

@media (min-width: 1180px) {
  .pains {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ---- 30. 校园面板「按部位选择设备」：四张卡各配对应门锁的产品图（2026-10-13 客户）-------------
   ① 学生宿舍 → DS109（NFC 一卡通档）；② 实验室 · 办公室 → DS209（指纹档）；
   ③ 楼栋门 · 楼道门 → F18081 人脸门禁终端；④ 功能房 → DS309（人脸档）。
   与「型号选配」表的部位→型号映射一一对应。
   ⚠️ 尺寸只给「框」定高（改 --cap-pic-h 即可），**不给 img 单独写 width / max-width** ——
      否则同容器会出现两种排版（站内铁律，同 .figure 系列）。
   ⚠️ 这是 140px 级产品缩略图，按站内规则**不加品牌水印**（与 .cell-pic 一致）。
   ≥768 起给标题预留两行高度，四张卡的正文顶边落在同一条水平基准上。 */

#campus-do .cap-item {
  --cap-pic-h: 140px;
}

#campus-do .cap-item img {
  display: block;
  width: 100%;
  height: var(--cap-pic-h, 140px);
  object-fit: contain;
  object-position: center;
  margin-bottom: calc(var(--s-4) * 1px);
}

@media (min-width: 768px) {
  #campus-do .cap-item h3 {
    min-height: calc(2 * 1.4 * var(--fs-body)); /* 标题最多两行 */
  }
}

/* ---- 29.y 公租房面板第二轮（2026-10-13 客户 6 项）--------------------------------------------
   ①「方案介绍」→「方案介绍」（小节目录 / eyebrow / 分段注释 / aria-label 四处同步）；
   ② 流程四阶段各配一张 3:2 实拍图，排在流程条上方、与阶段名同列对齐；
   ③ 可见收益仍保留 6 张（「催缴有据可依」与「缴费状态与水表计量」并为一张，新增「采集能上门」）；
   ④ 接入线图补上路径三汇入 DSLock 的那一笔；
   ⑤ 新增「开放与接口」段（其后的成本论证顺延为 06）；
   ⑥ 电脑端配图改成三端合成图（沿用首页 .cap-card.s4-stage 的实拍外壳与分层）。
   -------------------------------------------------------------------------- */

/* 流程四阶段配图：列模板与间距**必须与 .flow-row 成对改**，否则四张图与四个阶段名错位。
   .flow-row 基础档是单列（流程竖排），≥768 才变四列 —— 这里用同一套值。 */
.step-figs {
  display: grid;
  gap: calc(var(--s-4) * 1px);
  margin-bottom: calc(var(--s-5) * 1px);
}

.step-fig {
  margin: 0;
}

/* 给框定高（站内口径）：3:2 与素材同比例 ⇒ object-fit 既不裁也不拉 */
.step-fig img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}

/* 开放与接口：引导句（与 .step-body p 同一档字号与行高） */
.open-lead {
  margin-top: calc(var(--s-3) * 1px);
  font-size: var(--fs-body);
  line-height: 1.75;
  color: var(--text-2);
  max-width: 78ch;
}

/* 三端合成图：外壳与分层全部沿用首页 .cap-card.s4-stage（含网格底纹 —— 站内只允许 hero 与 .cap-card
   用底纹）。这里只把舞台宽度收窄居中：全宽会让 1160/754 的舞台撑到 754px 高。 */
.three-ends {
  margin: calc(var(--s-6) * 1px) 0 0;
}

/* ⚠️ 不要再给舞台设 max-width：原为 900px，导致这一块的卡片比上下其它块各窄 130px，
   客户报「整个块与块之间的排版布局不对」。铺满内容列后舞台 1160×754（比 900 宽时高 169px）。 */
.three-ends .s4-stage {
  max-width: none;
}

.three-ends figcaption {
  margin-top: calc(var(--s-3) * 1px);
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--text-3);
  max-width: 78ch;
}

@media (min-width: 768px) {
  .step-figs,
  .step-bodies {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: calc(var(--s-5) * 1px);
  }
}


/* ---- 31. 酒店 · 民宿面板的「节电测算器」（2026-10-13 客户：把独立测算器并进方案页）------------------
   ⚠️ 全部规则限定在 `.calc` 之下，不污染其它面板与组件。
   ⚠️ 无 JS 时页面照样可读：HTML 里已写死默认参数对应的静态数值，柱状图只是不出现。
   ⚠️ 结构由 site.js 第 9 项负责（柱状图用 createElement 逐根建，不用 innerHTML）。 */

.calc {
  margin-top: calc(var(--s-6) * 1px);
  display: grid;
  gap: calc(var(--s-4) * 1px);
}

@media (min-width: 768px) {
  .calc {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .calc-formula {
    grid-column: 1 / -1;
  }
}

.calc-panel {
  padding: calc(var(--s-5) * 1px);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.calc-panel h4 {
  margin: 0 0 calc(var(--s-5) * 1px);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-3);
  letter-spacing: .04em;
}

.calc-field {
  margin-bottom: calc(var(--s-5) * 1px);
}

.calc-field:last-child {
  margin-bottom: 0;
}

.calc-lab {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(var(--s-3) * 1px);
  margin-bottom: calc(var(--s-2) * 1px);
}

.calc-lab > span:first-child {
  font-size: var(--fs-sm);
  color: var(--text-2);
}

.calc-lab .v {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--accent);
}

.calc input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 2px;
  margin: 0;
  background: var(--line);
  border-radius: 2px;
  outline: none;
}

.calc input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
}

.calc input[type="range"]::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
}

.calc input[type="number"] {
  width: 96px;
  padding: calc(var(--s-1) * 1px) calc(var(--s-2) * 1px);
  background: var(--bg-0);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--text-1);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  text-align: right;
}

.calc input[type="number"]:focus {
  outline: none;
  border-color: var(--accent);
}

.calc-hint {
  margin: calc(var(--s-2) * 1px) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-3);
  line-height: 1.7;
}

.calc-hint b {
  color: var(--text-2);
  font-weight: 500;
}

.calc-res {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(var(--s-3) * 1px);
  padding: calc(var(--s-3) * 1px) 0;
  border-bottom: 1px solid var(--line);
}

.calc-res:last-of-type {
  border-bottom: none;
}

.calc-res .k {
  font-size: var(--fs-sm);
  color: var(--text-2);
}

.calc-res .v {
  font-family: var(--font-mono);
  font-size: var(--fs-h3);
  color: var(--text-1);
}

.calc-res .v.big {
  font-size: var(--fs-h2);
  color: var(--accent);
}

.calc-bars {
  margin-top: calc(var(--s-5) * 1px);
}

.calc-bars-hd {
  display: flex;
  justify-content: space-between;
  gap: calc(var(--s-3) * 1px);
  margin-bottom: calc(var(--s-2) * 1px);
  font-size: var(--fs-xs);
  color: var(--text-3);
  line-height: 1.6;
}

.calc-bar-row {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: calc(var(--s-12) * 1px);
}

.calc-bar-row .bar {
  flex: 1;
  min-height: 2px;
  background: var(--bg-2);
  border-radius: 2px 2px 0 0;
}

.calc-bar-row .bar.on {
  background: var(--accent);
}

.calc-bar-labs {
  display: flex;
  gap: 4px;
  margin-top: calc(var(--s-1) * 1px);
}

.calc-bar-labs span {
  flex: 1;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-3);
}

.calc-formula {
  margin-top: 0;
}
