/* plum.css — Plum 章节页。雾镜 → 三联镜 → 胶片横廊 → 染色转场 → 金夜杂志版 → 工艺三格 → 冷收尾。
   规则同 portal.css：只消费 vendor 语义变量，不碰 vendor 文件，不造 vx- 类。 */

/* ── 通用 ── */

.ph { color: var(--text-low); font-size: calc(12px * var(--ratio, 1)); letter-spacing: .04em; }
.ph::before { content: "〔待品牌方：" attr(data-ph) "〕"; }
/* i18n 接上后由 applyLang 写 data-ph-label（前缀跟语言走，占位项名保持中文——
   读者是品牌方）。没有 JS 时上面那条就是终态，两者中文写法刻意一致，不会闪一下 */
.ph[data-ph-label]::before { content: "〔" attr(data-ph-label) "〕"; }

/* 导航保底压暗（2026-07-30 全站 26 点对比度实测后加）：
   vendor 的 .vx-nav 默认全透明，滚动后也只加一层很淡的毛玻璃，链接色是 --text-mid。
   导航压在亮画面上时对比度实测掉到 1.08–1.13（玄关双门那扇天光窗、
   胶片横廊的白瓷浴缸、partner 的亮底幅）——那三个字在截图里根本认不出来。
   用渐变而非实底色：保留「悬浮在画面上」的观感，往下多铺 30px 淡出，不留硬边；
   底色取 --bg-base，跟着分区主题走（亮色模式下自然变成亮 scrim，方向仍然正确）。
   ::before 必须 position:absolute —— .vx-nav 是 flex 容器，
   静态定位的伪元素会变成 flex item，把品牌与链接挤开。 */
.vx-nav::before {
  content: "";
  position: absolute;
  /* 往下多铺 46px 而不是 30px：盒子越高，尾巴越长，亮画面上才不会看出一条硬边的黑带。
     链接行落在盒子 15%–41% 处（导航高约 71px），所以 44% 之前必须还是满强度。 */
  inset: 0 0 -46px 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--bg-base) 92%, transparent) 0%,
    color-mix(in oklab, var(--bg-base) 84%, transparent) 44%,
    color-mix(in oklab, var(--bg-base) 34%, transparent) 72%,
    transparent 100%);
}

.world-nav-links { display: flex; gap: clamp(18px, 3vw, 40px); }
.world-nav-links a {
  color: var(--text-mid);
  text-decoration: none;
  font-size: calc(12.5px * var(--ratio, 1));
  letter-spacing: .22em;
  transition: color var(--dur-base, .3s);
}
.world-nav-links a:hover { color: var(--text-hi); }

/* 整页连续染色的氛围光：motion.js 在 html 上写 --sync-from/--sync-to/--sync-p，
   color-mix 把相邻分区的 accent 连续混出来——滚过转场幕时整页光色从冷蓝化进梅紫 */
body { --sync-mix: color-mix(in oklab, var(--sync-from, var(--accent)), var(--sync-to, var(--accent)) calc(var(--sync-p, 0) * 100%)); }

.world-tint {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 90% 62% at 50% -6%,
    color-mix(in oklab, var(--sync-mix) 16%, transparent),
    transparent 74%);
}
/* 别把 .vx-nav 收进这条：vendor 的导航是 position:fixed（自带 z-index:var(--z-nav)=110），
   写 relative 会把它打回文档流，页顶多出一条 235px 的实体 nav 带 */
main, .vx-footer { position: relative; z-index: 1; }

.world-nav .vx-nav__brand img { width: 34px; display: block; }

/* ── 幕 0 · 雾镜（滚动＝擦开霜面） ── */

/* aspect-ratio 必须撤：vx-dolly 默认 16/9，而这一幕是纯文字扉页、高度由
   min-height:100lvh 定。竖屏下「高 × 16/9」会变成比视口还宽的自动最小尺寸，
   把整页 scrollWidth 撑到 1671px（390 视口实测），手机上整站能横着拖。
   ember 的扉页早已写了同一行——这里是漏改，不是差异 */
.plum-fog { display: grid; place-items: center; text-align: center; aspect-ratio: auto; }

/* 霜面：多层冷雾渐变，透明度与缩放都由 --dolly-progress 驱动。
   首屏载入时 progress≈0.5（enter-bottom 已走完一半），0.5→0.92 的滚动区间内雾散尽 */
.fog-veil {
  position: absolute;
  inset: -4%;
  pointer-events: none;
  z-index: 2;
  background:
    radial-gradient(ellipse 66% 44% at 28% 24%, color-mix(in oklab, var(--accent) 26%, transparent), transparent 70%),
    radial-gradient(ellipse 52% 40% at 74% 66%, rgba(214, 228, 244, .14), transparent 72%),
    linear-gradient(174deg, rgba(190, 212, 236, .17), rgba(10, 14, 26, .5) 82%);
  opacity: clamp(0, calc((0.92 - var(--dolly-progress, 0.5)) * 2.6), 1);
  transform: scale(calc(1 + (0.92 - var(--dolly-progress, 0.5)) * 0.05));
}

.fog-body { position: relative; z-index: 1; }

.fog-kicker {
  font-size: clamp(14px, 1.5vw, 18px);
  letter-spacing: .9em;
  text-indent: .9em;
  color: var(--text-mid);
}
.fog-kicker .ph { display: block; margin-top: 10px; letter-spacing: .06em; text-indent: 0; }

.fog-title {
  margin-top: calc(26px * var(--ratio, 1));
  font-weight: 200;
  font-size: clamp(30px, 4.6vw, 62px);
  letter-spacing: .18em;
  text-indent: .18em;
  color: var(--text-hi);
  /* 字与雾同呼吸：雾未散时字也是糊的 */
  filter: blur(calc(clamp(0, calc((0.92 - var(--dolly-progress, 0.5)) * 2.6), 1) * 5px));
}

.fog-hint {
  margin-top: calc(40px * var(--ratio, 1));
  font-size: 13.5px;
  font-weight: 560;
  letter-spacing: .4em;
  text-indent: .4em;
  color: var(--text-hi);
}

@media (prefers-reduced-motion: reduce) {
  .fog-veil { opacity: 0; }
  .fog-title { filter: none; }
}

/* ── 幕 1 · 三联镜 ── */

/* 三面镜并立在暗场上：中镜是「正镜」（拱顶，视频，滚动拖动时间），
   两侧是同一房间的另两个机位（静帧，反向缓移的镜群差速） */
.triptych {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: 1fr 1.55fr 1fr;
  gap: clamp(12px, 1.6vw, 26px);
  padding: 6svh clamp(18px, 4.5vw, 64px);
  align-items: stretch;
}

.pane {
  position: relative;
  overflow: clip;
  border-radius: var(--radius-lg, 16px);
  border: 1px solid color-mix(in oklab, var(--accent) 30%, transparent);
  box-shadow: 0 30px 90px -34px rgba(0, 0, 0, .6);
  isolation: isolate;
}
.pane-main { border-radius: 999px 999px 18px 18px; }

.pane > img,
.pane > video {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}

/* 侧镜：压一档亮度让主次分明；随行程与中镜反向缓移 */
.pane-side > img { filter: brightness(.8) saturate(.92); }
.pane-side { transform: translateY(calc(var(--scrub-progress, 0) * 4svh)); }
.pane-side:last-child { transform: translateY(calc(var(--scrub-progress, 0) * -4svh)); }

/* 中镜画面驱动：推近（不做溶出——本幕没有内容咬合上来遮挡，
   溶出会变成无遮挡裸消失，实测被用户抓到；行程走完 sticky 解钉自然滚走） */
.plum-bath .vx-scrub__media {
  object-position: 50% 35%;
  transform: scale(calc(1 + 0.08 * var(--scrub-progress, 0)));
  transform-origin: 50% 35%;
  will-change: transform;
}

/* 字幕：竖排立左缘暗场，行程 62% 起让位 */
.plum-bath .vx-scrub__overlay {
  opacity: calc(min(1, (1 - var(--scrub-progress, 0)) * 2.6));
}
.bath-line {
  writing-mode: vertical-rl;
  position: absolute;
  left: clamp(14px, 2.2vw, 34px);
  top: 50%;
  translate: 0 -50%;
  font-size: clamp(17px, 2vw, 25px);
  font-weight: 600;
  letter-spacing: .34em;
  color: var(--text-hi);
  /* 柔晕加到三层，理由同玄关窗幕：竖屏下这行字挪到画面顶部居中（见下方 portrait 块），
     那一带是浴室的高光，390 档实测 2.18（小字门槛 4.5） */
  text-shadow: 0 0 3px rgb(4 6 12 / .96), 0 0 11px rgb(4 6 12 / .88), 2px 2px 34px rgb(4 6 12 / .72);
}

/* 竖屏：只留中镜，侧镜藏起 */
@media (orientation: portrait) {
  .triptych { grid-template-columns: 1fr; padding: 5svh 5vw; }
  .pane-side { display: none; }
  /* 字幕挪到顶部之后要有上缘光衰兜底：390 档实测 2.18 → 只加三层柔晕 4.30（仍差 0.2）
     → 配这道光衰才过线。30% 处归零，中镜主体不蒙灰，且跟着字幕同一个 opacity 一起淡出 */
  .plum-bath .vx-scrub__overlay {
    background: linear-gradient(180deg, rgb(4 6 12 / .7) 0%, rgb(4 6 12 / .46) 14%, transparent 30%);
  }
  .bath-line {
    writing-mode: horizontal-tb;
    left: 50%; top: max(5svh, 72px);
    translate: -50% 0;
  }
}

/* 静帧/减弱动效：中镜回文档流 */
.plum-bath.is-static .triptych { position: static; display: block; padding: 6svh 0; }
.plum-bath.is-static .pane-side { display: none; }
.plum-bath.is-static .pane-main {
  position: relative;
  width: min(88vw, 56svh);
  aspect-ratio: 9 / 16;
  margin: 0 auto;
  opacity: 1;
}
.plum-bath.is-static .vx-scrub__media { position: absolute; transform: none; }
.plum-bath.is-static .vx-scrub__overlay { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .triptych { position: static; display: block; padding: 6svh 0; }
  .pane-side { display: none; }
  .pane-main { position: relative; width: min(88vw, 56svh); aspect-ratio: 9 / 16; margin: 0 auto; opacity: 1; }
  .plum-bath .vx-scrub__media { transform: none; }
}

/* ── 幕 2 · 胶片横廊 ── */

/* ── 幕 3 · 胶片横廊（对「≥92vw 一屏一幅」的显式豁免，2026-07-30 登记）──
   为什么不改成一屏一幅：这一幕的语义是「同一个下午 · 六格」——一张印样（contact sheet），
   六格是同一时刻的连续序列，**看见序列本身**就是内容。拆成一屏一幅会把它变成
   六个互不相干的时刻，正好毁掉它要说的那件事。
   ≥92vw 那条规矩管的是「一幅画面 = 一个独立时刻」的叙事满幅幕；印样是一个复合物件，
   不在它的作用域内（门幕双开门同理，见 portal.css）。
   与 ember 画廊的差别是内容结构决定的，不是不一致：那组是六件不同的符号器物
   ⇒ 一次一件、邻件探出、你逐件打量；这里是一个下午的六格 ⇒ 一次看见整条。
   本幕同时充当本章的密度峰 1（打量），峰 2（驻停）在夜幕 .night-pin。 */
.plum-strip { padding-block: clamp(56px, 9svh, 120px); }

.strip-head { margin-bottom: clamp(26px, 4svh, 48px); }

.strip-kicker {
  font-size: clamp(14px, 1.5vw, 18px);
  letter-spacing: .8em;
  text-indent: .8em;
  color: var(--text-mid);
  text-align: center;
}

.strip-track { cursor: grab; }
.strip-track.is-grabbing {
  cursor: grabbing;
  scroll-snap-type: none;
  user-select: none;
}

.strip-cell { margin: 0; border: 1px solid color-mix(in oklab, var(--accent) 22%, transparent); }

/* 格号（01–06）压在画面左下角，而这六帧的下缘正是白瓷浴缸和高光皮肤：
   实测「01」对比度 1.09 —— 原先只给 text-shadow，8px 柔晕撑不住 11px 小字。
   改成每格自带一条底缘压暗，照片配字幕的常规做法，不侵入画面主体。 */
.strip-cell::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 34%;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 0%,
    rgb(4 3 10 / .34) 52%, rgb(4 3 10 / .86) 100%);
}

.strip-cell figcaption {
  position: absolute;
  left: 12px; bottom: 10px;
  z-index: 2;
  font-size: 11px;
  letter-spacing: .3em;
  color: var(--text-hi);
  text-shadow: 0 1px 8px rgba(0, 0, 0, .8);
}

.strip-hint {
  margin-top: clamp(18px, 3svh, 32px);
  text-align: center;
  font-size: calc(11.5px * var(--ratio, 1));
  letter-spacing: .4em;
  text-indent: .4em;
  color: var(--text-mid);
}

/* ── 幕 3 · 染色转场（文字随本幕穿屏进度蓝→粉紫；金线同步点亮） ── */

.plum-turn {
  padding-block: clamp(80px, 12svh, 170px);
  /* 挂了 vx-dolly 只为拿 --dolly-progress，不要它的 16:9 媒体框 */
  aspect-ratio: auto;

  /* 进度源是本幕穿屏进度（进视口底 0 → 出视口顶 1）——整页 --sync-p 的
     过渡窗在文字露头前就走完，不能用。文字居中，可见期约 p∈[0.18, 0.82]，
     重映射后：刚露头纯蓝、离场前扫完变纯粉，中段两色同屏 */
  --turn-p: clamp(0, (var(--dolly-progress, 0) - 0.18) / 0.64, 1);

  /* 端点色是 world.js 探针读出的两主题冷系强调色（--accent-alt 计算值），不硬编码 */
  --turn-c-a: var(--theme-accent-alt-azure, var(--accent-alt));
  --turn-c-b: var(--theme-accent-alt-plum, var(--accent-alt));
  --turn-mix: color-mix(in oklab, var(--turn-c-a), var(--turn-c-b) calc(var(--turn-p) * 100%));
}

.turn-wrap {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: clamp(24px, 4vw, 64px);
}

.turn-copy { text-align: left; }

/* 过渡态两色同屏：粉紫从左侧进场，色界随滚动向右扫（35% 软过渡带），
   把蓝逐渐挤出文字——不是整段统一变色。上面叠一层半透明白/黑保留立体光影 */
.turn-line {
  font-weight: 200;
  font-size: clamp(26px, 3.6vw, 50px);
  letter-spacing: .22em;
  line-height: 2;
  --vx-text-gradient:
    linear-gradient(178deg,
      rgb(255 255 255 / .34) 0%, transparent 32%,
      transparent 62%, rgb(0 0 0 / .38) 100%),
    linear-gradient(94deg,
      var(--turn-c-b) calc(var(--turn-p) * 135% - 35%),
      var(--turn-c-a) calc(var(--turn-p) * 135%));
}

/* 日落线：宽度与文字扫色同步，颜色 = 当刻混色。滚过这幕，线从左往右点亮 */
.turn-wire {
  height: 1px;
  width: calc(var(--turn-p) * 100%);
  background: var(--turn-mix);
  box-shadow: 0 0 12px color-mix(in oklab, var(--turn-mix) 60%, transparent);
}

/* 减弱动效：dolly 不跑（--dolly-progress 恒 0），别让文字停在蓝色端点 */
@media (prefers-reduced-motion: reduce) {
  .plum-turn { --turn-p: 1; }
}

@media (max-width: 640px) {
  .turn-wrap { grid-template-columns: 1fr; }
  .turn-wire { justify-self: start; }
}

/* ── 幕 4 · 深红夜（钉住舞台 + 原地运镜 + 推入式交接） ── */

.plum-night {
  /* 从转场幕下方推上来盖住它（同玄关卡片压窗口那招），出血无内边距 */
  margin-top: clamp(-16svh, -10svh, -5svh);
  position: relative;
  z-index: 2;
  /* 无内边距：下一幕（工艺三格）是文档流暗块，靠负 margin 从下方推上来交叉溶解。
     曾经这里留过 34svh/10svh 暗尾，那是为了隔开中间插入过的满幅诊室幕——
     品牌方定稿撤掉那一幕后，暗尾与熄灯一并撤回（见 _index/derived/README 第十二次修订） */
  padding: 0;
  background:
    radial-gradient(130% 100% at 50% 24%, rgb(74 13 24 / .38), transparent 70%),
    var(--bg-base);
}

/* 容器给行程，舞台钉住一屏：两者的差值就是镜头运动的可用距离。
   300svh 与 ember 的 .pin-e5 同档（研究「两世界同构：峰值强度相当」；研究给本章峰
   的预算是 320svh，那一幕撤了，预算移到这里）。2026-07-30 由 210 提到 300：
   驻停要的是「行程很长而画面几乎不动」，行程不够就只是推近快一点，成不了峰。 */


/* 驻停曲线：把线性进度 --pin-p 重映射成「缓入 → 平台 → 缓出」的 --q，
   所有运镜量都读 --q 而不是 --pin-p。
   分段（行程占比 → 运动量占比）：0–32% → 46%｜32–68% 平台 → 8%｜68–100% → 46%。
   ⇒ 中段 36% 的行程只走 8% 的运动量：scale 总幅 22%，平台里只变 1.8%，
     远低于研究对驻停的要求（平台中段、幅度<5%）。这就是「时间密度峰」的做法——
     你还在滚，她几乎不动，主观时间被拉长；留 8% 而不是 0 是为了不让人以为页面卡死。
   为什么不是 ease 曲线：CSS 的 easing 只能作用于 transition/animation，
   这里是滚动逐帧写入的变量，只能自己做分段线性映射。
   ⚠ 映射必须声明在 .night-pin（带 data-pin 的那个元素）上：--pin-p 由 world.js
     写在它身上，自定义属性只向下继承——写在父级 .plum-night 上读到的恒是回退值 0，
     实测表现为「整段行程 scale 一直是 1」（2026-07-30 踩过）。 */
.night-pin {
  position: relative;
  height: 300svh;
  --p: var(--pin-p, 0);
  --q: calc(
      min(var(--p), .32) / .32 * .46
    + clamp(0, var(--p) - .32, .36) / .36 * .08
    + max(0, var(--p) - .68) / .32 * .46
  );
}

.night-stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: clip;
  isolation: isolate;
}

/* 焦点随进度大幅下移：镜头一路压到她的眼睛上。
   必须改 --focal 变量而不是给 img 写 object-position——
   vendor 的 .vx-focal > img{object-position:inherit} 优先级更高，直接写会被压掉 */
.night-lead-focal {
  position: absolute; inset: 0; display: block;
  overflow: clip;
  /* 顶缘柔化：与被压住的上一幕交叠时不留硬横线。蒙版挂图片容器上，
     挂外层会连竖排字一起吃淡 */
  mask-image: linear-gradient(180deg, transparent 0, #000 8%, #000 100%);
  --focal: 50% calc(var(--fy, 28%) + var(--q, 0) * 4%);
}

/* 运镜属性一律不挂 transition：滚动每帧都给新目标值，过渡只会让它追不上 */
.night-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(calc(1 + .22 * var(--q, 0)));
  /* 推近中心放在眼睛一带：origin 偏下（42%）会把她的眼睛顶出上边缘（实测被切） */
  transform-origin: 50% 25%;
  filter: brightness(calc(.82 + .26 * var(--q, 0)));
  /* 不做溶出：钉住结束时下一幕只盖到六成屏，图一透明就露出一片纯背景色
     （实测 p=1 时舞台仍占 309px）。让它随舞台自然滚出画面更连贯 */
}

/* 竖排字反向上浮：与推进的画面形成对向运动，并先一步退场 */
.night-vline {
  position: absolute;
  z-index: 1;
  left: clamp(18px, 5vw, 84px);
  top: clamp(20px, 9svh, 96px);
  writing-mode: vertical-rl;
  font-weight: 300;
  font-size: clamp(24px, 2.8vw, 42px);
  letter-spacing: .3em;
  color: #fff;
  text-shadow: 0 2px 26px rgb(0 0 0 / .75);
  transform: translateY(calc(var(--q, 0) * -14svh));
  /* 字在平台开始之前就退干净（p=.30 归零，平台从 .32 起）：
     研究「驻停→末幕：无新信息——纯张力，信息静默是节奏设计的一部分」。
     平台段留纯画面对视，不留任何还在读的东西。 */
  opacity: calc(clamp(0, (.3 - var(--p, 0)) * 8, 1));
}

/* ── 幕 5 · 工艺四格（从夜幕舞台下方推上来盖住它） ── */

.plum-detail {
  margin-top: -62svh;
  position: relative;
  z-index: 3;
  /* 顶部 20svh 由透明渐到底色：推上来时不是一条硬边压住夜幕，
     而是把还在推近的画面慢慢吞掉（交叉溶解） */
  background: linear-gradient(180deg, transparent 0, var(--bg-base) 20svh);
}

.detail-kicker {
  text-align: center;
  font-size: clamp(14px, 1.5vw, 18px);
  letter-spacing: .8em;
  text-indent: .8em;
  color: var(--text-mid);
  margin-bottom: clamp(30px, 5svh, 56px);
}

.detail-grid {
  display: grid;
  /* 四格：第 4 格是原诊室幕降级后的落点（品牌方 2026-07-30 定） */
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(14px, 2vw, 28px);
}

.detail-cell {
  position: relative;
  margin: 0;
  aspect-ratio: 1;
  border-radius: var(--radius-lg, 16px);
  overflow: clip;
  isolation: isolate;
}
/* 每格自成一台推轨镜头：滚动推近 + 焦点下移 + 光渐亮（同玄关门卡那套） */
.detail-media {
  position: absolute; inset: 0;
  display: block;
  aspect-ratio: auto;
}
.detail-focal {
  position: absolute; inset: 0; display: block;
  --focal: 50% calc(var(--fy, 45%) + var(--dolly-progress, 0) * 5%);
}

/* 运镜属性一律不挂 transition：滚动每帧都给新目标值，过渡只会让它永远追不上 */
.detail-cell img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(calc(1 + .1 * var(--dolly-progress, 0)));
  transform-origin: 50% 42%;
  filter: brightness(calc(.86 + .18 * var(--dolly-progress, 0)));
}
/* hover 走容器阴影，不碰 img 的运镜属性 */
.detail-cell {
  transition: box-shadow var(--dur-slow, .5s) var(--ease-out, ease);
}
.detail-cell:hover {
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--accent) 42%, transparent),
              0 26px 60px -30px rgb(0 0 0 / .8);
}

.detail-cell figcaption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  padding: 34px 14px 14px;
  background: linear-gradient(to top, rgba(0, 0, 0, .62), transparent);
  font-size: calc(13px * var(--ratio, 1));
  letter-spacing: .2em;
  color: var(--text-hi);
  text-align: center;
}

.detail-note { margin-top: clamp(20px, 3svh, 34px); text-align: center; }

@media (max-width: 700px) {
  .detail-grid { grid-template-columns: 1fr; }
  .detail-cell { aspect-ratio: 4 / 3; }
}

/* ── 幕 7 · 冷收尾 ── */

.plum-exit { padding-block: clamp(120px, 22svh, 260px); }

.exit-wrap { text-align: center; display: grid; gap: clamp(30px, 5svh, 52px); }

.exit-line {
  font-weight: 200;
  font-size: clamp(22px, 3vw, 40px);
  letter-spacing: .24em;
  text-indent: .24em;
  color: var(--text-hi);
}

.exit-links { display: flex; justify-content: center; gap: clamp(34px, 6vw, 90px); }

.exit-links a {
  color: var(--text-mid);
  text-decoration: none;
  font-size: calc(15px * var(--ratio, 1));
  letter-spacing: .26em;
  padding-bottom: 7px;
  border-bottom: 1px solid color-mix(in oklab, var(--accent) 22%, transparent);
  transition: color var(--dur-base, .3s), border-color var(--dur-base, .3s);
}
.exit-links a:hover {
  color: var(--text-hi);
  border-color: color-mix(in oklab, var(--accent) 70%, transparent);
}

/* 长语种下导航容易换行：窄屏先收紧间距，实在放不下再换行——
   换行本身不再是 bug（顶距已跟着 --nav-h 走），只是尽量别发生 */
@media (max-width: 620px) {
  .world-nav-links { gap: clamp(10px, 3vw, 18px); row-gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
  .world-nav-links a { font-size: calc(11.5px * var(--ratio, 1)); letter-spacing: .14em; }
}

/* ═══ 减弱动效：必须放在文件末尾 ═══
   没有 --pin-p，钉住舞台退成普通图块，负 margin 交叠一并撤掉；
   dolly 不跑（--dolly-progress 恒 0），别让画面停在最暗的起点。

   位置是硬要求：这一段原本夹在文件中段，`.plum-detail{margin-top:-62svh}` 与
   `.detail-cell img{...}` 都写在它后面 —— 同特异度、后写的赢，两条撤销被静默作废。
   实测：减弱动效下工艺三格仍上提 62svh，把诊室的静态主帧盖掉 558px。
   新增覆盖一律往这里加，不要往回塞。 */
@media (prefers-reduced-motion: reduce) {
  .plum-night { margin-top: 0; }
  .night-pin { height: auto; }
  .night-stage { position: static; height: clamp(320px, 62vw, 82svh); }
  .night-img, .detail-cell img { filter: brightness(1); opacity: 1; }
  .night-vline { transform: none; opacity: 1; }
  .plum-detail { margin-top: 0; }
}
