/* =========================================================
   长征 · 山河卷 —— 翻书式影像专题
   ========================================================= */

/* --t：翻页进度 0→1；注册为 @property 后可用于 transition */
@property --t { syntax: '<number>'; inherits: true; initial-value: 0; }

:root {
  --gold: #E0B45C;
  --gold-2: #F3D79B;
  --gold-dim: rgba(224, 180, 92, .34);
  --ink: #0A0B0A;
  --ink-2: #101210;
  --text: #F2EBE0;
  --muted: rgba(242, 235, 224, .60);
  --faint: rgba(242, 235, 224, .34);
  --line: rgba(242, 235, 224, .13);
  --red: #C8102E;

  /* 视口高度基准。手机上 100vh 是「地址栏收起时」的大视口，
     而实际能看到的往往更矮 —— 底部内容会被浏览器 UI 盖住，
     又因为 html/body 是 overflow:hidden，用户没有任何办法把它拉出来。
     所以优先用动态视口单位（dvh = 当前真实可视高度）。
     ⚠️ 绝不能用「同名声明覆盖」来兜底：
          --vh: 100vh;
          --vh: 100dvh;   ← 错！
        自定义属性不做语法校验，不认 dvh 的浏览器照样会让第二条生效，
        于是 calc(100dvh - …) 在计算期整体失效，--book-h 与 height 全部变 unset，
        .app 和 .book-zone 的高度双双塌成 0px（整本书消失）。
        微信安卓内核（X5/XWeb）、iOS 15.4 以下、Chrome 108 以下都不认 dvh。
     必须用 @supports 在规则层把关（见下方 :root 之后的块）。 */
  --vh: 100vh;

  --hud-t: 60px;
  --hud-b: 96px;
  --book-w: min(1160px, 92vw);
  --book-h: calc(var(--vh) - var(--hud-t) - var(--hud-b) - 8px);
  --book-off: calc(50vw - (var(--book-w) / 2) + 70px);

  --flip: 980ms;
  --ease: cubic-bezier(.42, .02, .2, 1);

  --ff-serif: "Noto Serif SC", "Source Han Serif SC", "STZhongsong", "STSong", "SimSun", serif;
  --ff-sans: "Noto Sans SC", "PingFang SC", "HarmonyOS Sans SC", "Microsoft YaHei", system-ui, sans-serif;
  --ff-kai: "STKaiti", "KaiTi", "楷体", var(--ff-serif);

  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; }

/* 只在不认 dvh 的浏览器之外才切换视口单位。放在 @supports 里，
   不支持的引擎根本看不到这条声明，--vh 保持 100vh（有效值），
   不会出现「整条 calc 变 unset → 高度塌成 0」的事故。 */
@supports (height: 100dvh) {
  :root { --vh: 100dvh; }
}

html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--ink); color: var(--text);
  font-family: var(--ff-sans);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
body.is-dragging { cursor: grabbing; }
body.is-dragging * { user-select: none !important; }
::selection { background: var(--gold); color: #1a1206; }

/* 高度跟随 --vh（而非纯 inset:0），保证舞台与上下 HUD 都贴合真实可视高度，
   地址栏展开时底部进度条 / 翻页按钮不会被推出屏幕外。
   同时保留 inset: 0 兜底：万一 --vh 解析失败（height 变 unset → auto），
   top/bottom 同时存在会让它自动撑满，不会塌成 0。 */
.app { position: fixed; top: 0; right: 0; bottom: 0; left: 0; height: var(--vh); }

/* ---------------- 桌面 / 书 ---------------- */
.stage {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0; overflow: hidden;
  background:
    radial-gradient(120% 100% at 50% 38%, #14170f 0%, #080a09 46%, #030403 100%);
}
.stage::after {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; pointer-events: none;
  background-image: var(--noise); opacity: .12; mix-blend-mode: overlay;
}

.book-zone {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: var(--book-w); height: var(--book-h);
  perspective: 5200px;
  perspective-origin: 50% 44%;
  touch-action: pan-y;
}

/* 书影 + 书脊装饰 */
.book-deco { position: absolute; top: -2px; right: -2px; bottom: -2px; left: -2px; pointer-events: none; }
.book-deco::before {
  content: ''; position: absolute; top: -14%; right: -8%; bottom: -14%; left: -8%;
  background: radial-gradient(58% 52% at 50% 46%, rgba(224,180,92,.075), transparent 70%);
}
.book-deco i {
  position: absolute; left: 6%; right: 6%; bottom: -34px; height: 40px;
  background: radial-gradient(50% 100% at 50% 0%, rgba(0,0,0,.75), transparent 72%);
  filter: blur(9px);
}
.book-deco b {
  position: absolute; left: -1px; top: 0; bottom: 0; width: 22px;
  background: linear-gradient(90deg, rgba(0,0,0,.72), rgba(0,0,0,.18) 46%, rgba(0,0,0,0));
}
.book-deco b::after {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: linear-gradient(180deg, transparent, var(--gold-dim) 10%, var(--gold-dim) 90%, transparent);
}

.book { position: absolute; top: 0; right: 0; bottom: 0; left: 0; transform-style: preserve-3d; }

.leaf {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0;
  transform-origin: left center;
  transform-style: preserve-3d;
  transform: translateX(calc(var(--t, 0) * var(--book-off) * -1))
             rotateY(calc(var(--t, 0) * -180deg));
  transition: --t var(--flip) var(--ease);
}
/* 这里刻意不给 .leaf 常驻 will-change。
   11 页各自提升为独立全屏合成层（每层还带大范围 box-shadow），
   移动端 GPU 显存吃紧时 iOS / 微信 webview 会反复丢弃并重建图层，
   表现为整页闪烁。改为只在真正翻动的那一页临时挂 .is-turning（JS 在 step() 里切换）。 */
.leaf.is-turning { will-change: transform; }
.leaf.no-anim { transition: none; }

/* ============ Swiper flip 接管（2026-10-12）============
   翻页引擎已换成 Swiper 6.8.4（effect:'flip'，assets/vendor/swiper/ 本地化）。
   #book 即 swiper 容器，.leaf 同时是 .swiper-slide（flex 子项、回到文档流），
   上面 --t 驱动的旧 3D 翻页规则全部失效；transform 与过渡全由 Swiper 内联管理。
   Swiper 只用最基础的 CSS 3D transform（Chrome 12+ / 微信 X5 均支持），
   低版本内核不再有 @property / inset 之类的特性依赖。 */
.swiper-container { touch-action: pan-y; }
.swiper-container .leaf {
  position: relative; top: auto; right: auto; bottom: auto; left: auto;
  transform-origin: 50% 50%;
  transform: none;
}
/* flip 模式下翻过的页整页转向背面（slide 背面被 backface-visibility 隐藏），
   衬页永远没有出场机会，display:none 省一份渲染内存 */
.swiper-container .face--back { display: none; }

.face {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0; overflow: hidden;
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
  background: var(--ink-2);
  border-radius: 2px;
  box-shadow: 0 30px 90px rgba(0,0,0,.55);
}
.face--back {
  transform: rotateY(180deg);
  background: linear-gradient(90deg, #171a1b 0%, #23262a 52%, #121416 100%);
}
/* 翻动时的受光 / 背光 */
.face--front::after {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; pointer-events: none;
  background:
    linear-gradient(270deg, rgba(255,243,218,.9) 0%, rgba(255,243,218,.24) 1.7%, rgba(255,243,218,0) 6.5%),
    linear-gradient(90deg, rgba(0,0,0,.58) 0%, rgba(0,0,0,.16) 28%, rgba(0,0,0,0) 60%);
  opacity: calc(var(--t, 0) * 1.15);
}
.face--back::after {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; pointer-events: none;
  background:
    linear-gradient(270deg, rgba(255,236,200,.22) 0%, rgba(255,236,200,.05) 30%, rgba(0,0,0,.42) 100%),
    linear-gradient(90deg, rgba(255,243,218,.10), rgba(255,243,218,0) 22%);
  opacity: calc((var(--t, 0) - .5) * 2);
}

/* 纸张背面 */
.paper-back { position: absolute; top: 0; right: 0; bottom: 0; left: 0; }
.paper-back__v {
  position: absolute; right: clamp(26px, 5%, 74px); top: 50%; transform: translateY(-50%);
  writing-mode: vertical-rl;
  font-family: var(--ff-kai);
  font-size: clamp(20px, 2vw, 30px);
  letter-spacing: .44em;
  color: rgba(224, 180, 92, .3);
  border-right: 1px solid rgba(224, 180, 92, .18);
  padding-right: 20px; height: 56%;
}
.paper-back__n {
  position: absolute; left: clamp(26px, 5%, 74px); bottom: 12%;
  font-family: var(--ff-serif); font-size: clamp(54px, 6vw, 86px); line-height: 1;
  color: rgba(242,235,224,.07); letter-spacing: .06em;
}
.paper-back__sig {
  position: absolute; left: clamp(26px, 5%, 74px); top: 12%;
  font-size: 11px; letter-spacing: .34em; color: rgba(242,235,224,.2);
}

#view-fullscreen,#cancel-fullscreen {
position:fixed;
top:50px;
right:50px;
z-index:9999;
width:130px;
height:130px;
font-size:16px;	
background:url(index-ico.png) -210px -20px;
border:none;
text-indent: -9999px;
	cursor: pointer;
}
#cancel-fullscreen {
background:url(index-ico.png) -20px -20px;	
}

/* ---------------- 页面通用 ---------------- */
.page { position: absolute; top: 0; right: 0; bottom: 0; left: 0; overflow: hidden; }

.page .anim { opacity: 0; transform: translateY(20px); }
.page.is-live .anim {
  animation: riseIn .8s var(--ease) both;
  animation-delay: var(--d, 0ms);
}
@keyframes riseIn {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}
.page.is-live .fadeAnim { animation: fadeIn 1.1s ease both; animation-delay: var(--d, 0ms); }
@keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }

/* 原 .noise 颗粒层规则已移除：地图整块删除后不再有任何 .noise 元素。
   全屏噪点效果仍由 .stage::after 使用 --noise 变量提供（窄屏已关闭）。 */

/* =========================================================
   封面 · 长征路线图
   ========================================================= */
/* 封面背景：专题图 01 封面.png 干净版（文字已抹除，渐变兜底） */
.page--cover {
  --cvw: max(var(--book-w), calc(var(--book-h) * 1.4138)); /* 背景图 cover 后的显示宽度 */
  background:
    url("../img/cover-clean.png") center / cover no-repeat,
    radial-gradient(115% 88% at 74% 30%, #16211b 0%, #0A0C0A 46%, #050605 100%);
}

/* 封面改用专题图整页背景（assets/img/cover-clean.png）。
   原先那一整块地图容器（空 <svg class="cv-map"> + .noise）已从 HTML 删除 ——
   它被 display:none 隐藏，从未渲染过任何内容，是纯体积与解析开销。
   如需恢复可交互地图：从 tools/backup-wx/ 取模板，并把 assets/data/maps.js
   加回 build_static.js 的数据源数组。 */

/* ---- 文字对位层：复现背景图的 cover 几何（1920×1358），
   内部 left/top 百分比 = 图内像素 / 1920 或 /1358，字号 = 图内像素 / 1920 ---- */
.cv-fit {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: var(--cvw);
  aspect-ratio: 1920 / 1358;
  pointer-events: none;
}

/* ---- 亚像素吸附（桌面）----
   .cv-fit 的宽度 = max(--book-w, --book-h × 1.4138)，两者至少有一个是小数的
   组合；再加上下面 translate(-50%,-50%) 的百分比位移，整层几乎必然落在非整数
   设备像素上。.leaf / .face 已在 preserve-3d 上下文里被提升为合成层，层坐标
   只要非整数就会被 GPU 双线性重采样 —— 整段正文发虚。
   由 index.html 的 syncFitLayers() 把尺寸与位置（连同 .pv-fit）取整到设备像素后
   写内联覆盖本规则；取整误差 ≤0.5px，文案与背景图的对位关系视觉零变化。
   ⚠️ 手机端（≤980px）走「页面坐标 + 100% 宽」的另一套布局，
      JS 会清掉内联几何，下方 @media 里的 .cv-fit / .pv-fit 规则照常生效。 */
/* 文字块：对应原图右侧文字列（x 994–1762, y 313 起） */
.cv-copy {
  position: absolute; left: 51.7%; top:18.9%; right: 8.2%;
  display: flex; flex-direction: column; align-items: flex-start;
}
.cv-copy > * { pointer-events: auto; }
/* ⚠️ 封面文案字号一律「固定像素」，不再跟 --cvw 缩放（2026-10-14 用户裁定）。
   原因：calc(--cvw/1920*N) 出来的字号必然是小数（如 50.75px / 13.2917px），
   而 --cvw 本身随窗口尺寸变 → 小数字号让字形按缩放后的轮廓栅格化，笔画发虚；
   固定成整数 px 后任何窗口尺寸下渲染完全一致，也顺带避开了亚像素问题。
   下面这些值 = 原公式在 --book-w 上限 1160px 时的结果（取最接近的整数）：
     kicker 30 → 18px   title 84 → 51px   cv-desc 22 → 13px
     stats b 27 → 16px  stats i 12 → 7px  cv-start 26 → 16px
   正文 .cv-en 见下一行（现为 14px）。
   ⚠️ 以后要调字号，直接改这些 px 值；不要改回 calc(--cvw...) 那套。
   ⚠️ 手机端（≤980px）本来就是固定值 / clamp，见文件下方 @media。 */
.page--cover .cv-kicker {
  font-size: 18px; letter-spacing: .38em; margin-bottom: .9em;
  /* 撑满 .cv-copy 宽度，否则 align-items:flex-start 会把 kicker 缩成内容宽、居中失效 */
  align-self: stretch;
  /* letter-spacing 会在「末字之后」也多出一个字距，导致文本框右边界多出 .38em，
     视觉重心整体右偏。左右各补半个字距把这份多余宽度对称摊开，实测偏移精确归零。
     （窄屏用 .3em，见下方媒体查询，两处必须同步改。） */
  padding-left: .19em; padding-right: .19em;
}
.page--cover .cv-title  { font-size: 51px; margin: 0 0 .12em; }
/* 正文段落（两段，对应原图正文字号 21px / 行距 1.62 / 首行缩进 2em） */
.page--cover .cv-en     {  font-size: 14px; line-height: 1.62; letter-spacing: .01em; color:#D4AC67; margin: 0 0 0.5em; text-indent: 2em; font-family:"微软雅黑", "宋体";}
.page--cover .cv-desc   { font-size: 13px; line-height: 1.62; margin: 0 0 1.6em; padding-left: .85em; }
.page--cover .cv-stats  { gap: 1.7em; margin: 0 0 1.4em; }
.page--cover .cv-stats b{ font-size: 16px; }
.page--cover .cv-stats i{ font-size: 7px; }
/* 按钮：对应原图右下按钮位（x 1532–1763, y 939–1016） */
.page--cover .cv-start  {
  position: absolute; right: 8.2%; top: 69.1%;
  font-size: 16px;
  padding: .72em 2em;
}

.cv-inner {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 3;
  padding: clamp(24px, 4.5%, 58px);
  display: flex; flex-direction: column; justify-content: center;
  pointer-events: none;
}
.cv-left { max-width: 56%; pointer-events: auto; }

.cv-kicker {
  /* 独占一行居中：容器撑满 .cv-copy 宽度，内部文字居中，装饰线对称分布在文字两侧。
     注意不要给本元素加 display:flex + 外层的 text-align:center ——
     flex 容器里文字是匿名 flex item，text-align 对它无效，只会缩成内容宽贴左。 */
  font-size: 12px; letter-spacing: .46em;
  color: var(--gold); margin-bottom: 20px;
  display: flex; align-items: center; justify-content: center; gap: 14px;
}
.cv-kicker::before,
.cv-kicker::after {
  content: ''; flex: 0 1 92px; height: 1px;
}
.cv-kicker::before { background: linear-gradient(270deg, var(--gold-dim), transparent); }
.cv-kicker::after  { background: linear-gradient(90deg,  var(--gold-dim), transparent); }

.cv-title {
  font-family: var(--ff-serif); font-weight: 700;
  font-size: clamp(40px, 5.6vw, 55px); line-height: 1.04;
  margin: 0 0 4px; letter-spacing: .05em;
  background: linear-gradient(174deg, #FFF6E2 8%, var(--gold-2) 44%, #B8863A 94%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.cv-title span { -webkit-text-fill-color: var(--red); color: var(--red); margin: 0 .04em; }

.cv-en { font-size: 14px; letter-spacing: .56em; color:#fff; margin: 12px 0 24px; }
.cv-desc {
  font-size: 13.5px; line-height: 2.05; color: var(--muted);
  margin: 0 0 26px; max-width: 44ch;
  border-left: 2px solid var(--gold-dim); padding-left: 16px;
}
.cv-stats { display: flex; gap: 30px; list-style: none; margin: 0 0 30px; padding: 0; }
.cv-stats li { display: flex; flex-direction: column; gap: 6px; }
.cv-stats b { font-family: var(--ff-serif); font-size: clamp(19px, 1.8vw, 27px); color: var(--text); line-height: 1; }
.cv-stats i { font-style: normal; font-size: 10.5px; letter-spacing: .3em; color: var(--faint); }

.cv-start {
  pointer-events: auto; cursor: pointer;
  display: inline-flex; align-items: center; gap: 13px;
  padding: 14px 32px; border-radius: 999px;
  border: 1px solid var(--gold-dim);
  background: linear-gradient(180deg, rgba(224,180,92,.17), rgba(224,180,92,.05));
  color: var(--gold-2); font-family: var(--ff-sans); font-size: 14px; letter-spacing: .2em;
  transition: all .35s ease;
}
.cv-start:hover { background: var(--gold); color: #20160A; border-color: var(--gold); letter-spacing: .28em; }

.cv-chapters {
  position: absolute; left: clamp(24px, 4.5%, 58px); right: clamp(24px, 4.5%, 58px);
  bottom: clamp(20px, 4%, 40px);
  display: flex; align-items: center; gap: 8px; pointer-events: auto;
  border-top: 1px solid var(--line); padding-top: 14px;
}
.cv-chapters__lb { font-size: 10.5px; letter-spacing: .3em; color: var(--faint); margin-right: 10px; white-space: nowrap; }
.cv-chap {
  flex: 1; cursor: pointer; text-align: center; padding: 6px 2px;
  border-radius: 5px; background: rgba(255,255,255,.025); border: 1px solid transparent;
  transition: all .28s ease;
}
.cv-chap b { display: block; font-family: var(--ff-serif); font-size: 14px; color: rgba(242,235,224,.74); }
.cv-chap i { display: block; font-style: normal; font-size: 9.5px; letter-spacing: .18em; color: rgba(242,235,224,.3); margin-top: 3px; }
.cv-chap:hover { background: rgba(224,180,92,.13); border-color: var(--gold-dim); }
.cv-chap:hover b { color: var(--gold-2); }

/* =========================================================
   省份页
   —— 背景改用「专题图」同名省份图（1920×1358），文字对位层与其 cover 几何同步
   ========================================================= */
.page--prov {
  --pvw: max(var(--book-w), calc(var(--book-h) * 1.4138)); /* 背景图 cover 后的显示宽度 */
  /* 兜底：图未加载时显示同色系渐变。
     ⚠️ 旧内核兼容（Chromium < 111 不认 color-mix）：
     color-mix 写在 background 简写里，只要有一个分量非法，**整条 background 会被丢弃**，
     连兜底渐变都不会剩。所以下面先写一条不含 color-mix 的版本 ——
     现代内核由紧随其后的 color-mix 版本覆盖，旧内核则保留这一条。
     两条必须在同一个规则块内、且顺序不能颠倒。 */
  background: linear-gradient(158deg, var(--deep, #101210) 0%, #070807 82%);
  background:
    radial-gradient(88% 74% at 72% 40%, color-mix(in srgb, var(--b) 32%, transparent) 0%, transparent 60%),
    linear-gradient(158deg, color-mix(in srgb, var(--deep) 88%, #000) 0%, #070807 82%);
}
/* 省份背景图：铺满页面并 cover（逐省 data-slug 指定） */
.page--prov::before {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 0;
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
}
.page--prov[data-slug="jiangxi"]::before   { background-image: url("../img/province/jiangxi-clean.png"); }
.page--prov[data-slug="fujian"]::before    { background-image: url("../img/province/fujian-clean.png"); }
.page--prov[data-slug="guangdong"]::before { background-image: url("../img/province/guangdong-clean.png"); }
.page--prov[data-slug="hunan"]::before     { background-image: url("../img/province/hunan-clean.png"); }
.page--prov[data-slug="guangxi"]::before   { background-image: url("../img/province/guangxi-clean.png"); }
.page--prov[data-slug="guizhou"]::before   { background-image: url("../img/province/guizhou-clean.png"); }
.page--prov[data-slug="yunnan"]::before    { background-image: url("../img/province/yunnan-clean.png"); }
.page--prov[data-slug="sichuan"]::before   { background-image: url("../img/province/sichuan-clean.png"); }
.page--prov[data-slug="gansu"]::before     { background-image: url("../img/province/gansu-clean.png"); }
.page--prov[data-slug="shaanxi"]::before   { background-image: url("../img/province/shaanxi-clean.png"); }
.page--prov::after {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; pointer-events: none; z-index: 2;
  background: linear-gradient(90deg, rgba(0,0,0,.46) 0%, rgba(0,0,0,0) 36%);
}

/* ---- 背景「呼吸」动效（A 方案）------------------------------------
   给背景图一层极缓的缩放 + 轻微明暗起伏，制造"画面活着"的呼吸感。
   只有箭头是位图时唯一可行的低风险做法：不区分元素，整图一起动。

   参数取舍：
   - scale 1.00 → 1.035：再大就会看出画面在"推拉"，再小则察觉不到
   - 24s 一轮：接近人呼吸的慢节奏，久看不会烦
   - 缓动用 ease-in-out 双向对称，避免起止突兀
   - transform-origin 定在 62% 46%（路线与主城集中的区域），
     这样放大时视觉重心不会跑出画面

   注意：动画挂在 ::before 上，而 .pv-fit 文字层是独立元素，
   不会跟着缩放 —— 文字保持锐利、位置不动。 */
@keyframes provBreathe {
  0%   { transform: scale(1);      filter: brightness(1); }
  50%  { transform: scale(1.035);  filter: brightness(1.045); }
  100% { transform: scale(1);      filter: brightness(1); }
}


/* 省份 SVG 轮廓 / 长征点位已从 HTML 中彻底移除 ——
   背景图 assets/img/province/<slug>-clean.png 自带地图与地名标注，
   原样式为 display:none，属于纯体积负担（44KB HTML、270 个隐形节点）。
   如需恢复：从 tools/backup-wx/ 取构建模板，并把 assets/data/maps.js 加回
   build_static.js 的数据源数组。 */

/* ---- 文字对位层：复现背景图的 cover 几何（1920×1358）
   内部 left/top 百分比 = 图内像素 / 1920 或 /1358，字号 = 图内像素 / 1920 ---- */
.pv-fit {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: var(--pvw);
  aspect-ratio: 1920 / 1358;
  pointer-events: none; z-index: 3;
}
/* 文字块：三层各自绝对定位，y 直接对齐背景图三行文字的实测位置 */
.pv-copy {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0;
  display: block; pointer-events: none;
}
.pv-copy > * { pointer-events: auto; position: absolute; }

/* 居中省份：用 left 作为水平中心；四川为左对齐（用 left 作左边界） */
.page--prov .pv-copy > * { transform: translateX(-50%); }
.page--prov[data-slug="sichuan"] .pv-copy > * { transform: none; }

/* kicker：对应图中红色时间段。y 已含「行盒顶部→文字顶部」的偏移补偿 */
.page--prov .pv-kicker {
  font-family: var(--ff-sans); font-weight: 500;
  color: #E23B34; letter-spacing: .16em; line-height: 1; white-space: nowrap;
}
/* title：对应图中金色省份名。
   底色是纯金 #F0CE7A，支持 background-clip:text 时换成与封面标题 .cv-title
   同一套的竖向鎏金渐变（#FFF6E2 → --gold-2 → #B8863A，174deg 近垂直）。 */
.page--prov .pv-cn2 {
  font-family: var(--ff-serif); font-weight: 700; color: #F0CE7A;
  line-height: 1; letter-spacing: .1em; margin: 0; white-space: nowrap;
  text-shadow: 0 0 44px rgba(0,0,0,.5);
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .page--prov .pv-cn2 {
    background: linear-gradient(174deg, #FFF6E2 8%, var(--gold-2) 44%, #B8863A 94%);
    -webkit-background-clip: text;
            background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    /* 字形填透明后 text-shadow 会从字里透出来把渐变染灰，
       改用 filter: drop-shadow —— 它作用在合成后的渐变字上，
       阴影只落在字形外轮廓，字面保持干净。 */
    text-shadow: none;
    filter: drop-shadow(0 0 22px rgba(0, 0, 0, .55));
  }
}
/* body：对应图中白色正文 */
.page--prov .pv-body {
  font-family: var(--ff-sans); color: rgba(255,255,255,.94);
  line-height: 1.62; letter-spacing: .02em; margin: 0;
  text-align: left; text-indent: 20px;
}
/* （四川的左对齐已由上面的全局 text-align: left 覆盖，原逐条冗余声明已删） */


/* =========================================================
   版权页（制作团队）—— 末页，第 12 页
   无对位背景图，纯排版：暗色纸 + 金色细线 + 居中落款。
   与封面文案同一原则：**字号一律固定像素**（不跟 --cvw / --pvw 缩放），
   避免小数字号在合成层里发虚。窄屏在下方 @media (max-width:980px) 里另给一套值。
   ========================================================= */
.page--credits {
  display: flex; align-items: center; justify-content: center;
  padding: 7% 8%;
  /* 兜底色：图未加载/旧内核都成立（不使用 color-mix） */
  background: linear-gradient(158deg, #13100A 0%, #070807 80%);
}
/* 中心柔光：衬出纸面层次，纯装饰、不参与交互 */
.page--credits::before {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 0;
  pointer-events: none;
  background: radial-gradient(66% 58% at 50% 40%, rgba(224,180,92,.10) 0%, rgba(224,180,92,0) 68%);
}
.cr-inner { position: relative; z-index: 1; width: min(820px, 100%); }

/* 眉标：英文小字 + 细线，与站内英文副题的调性一致 */
.cr-kicker {
  font-family: var(--ff-sans);
  font-size: 11px; letter-spacing: .52em; text-indent: .52em;
  text-align: center; color: rgba(224,180,92,.72);
  padding-bottom: 20px; margin-bottom: 30px;
  border-bottom: 1px solid rgba(224,180,92,.16);
}

.cr-list { list-style: none; margin: 0; padding: 0; }
.cr-row {
  display: flex; align-items: baseline; gap: 28px;
  padding: 15px 4px;
  border-bottom: 1px solid rgba(242,235,224,.09);
}
.cr-row b {
  flex: 0 0 96px;
  font-family: var(--ff-serif); font-weight: 600;
  font-size: 15px; letter-spacing: .4em;
  color: var(--gold);
}
.cr-row span {
  font-family: var(--ff-serif);
  font-size: 18px; line-height: 1.95; letter-spacing: .12em;
  color: rgba(242,235,224,.92);
}

/* 落款：出品单位 */
.cr-sign { margin-top: 54px; text-align: center; }
.cr-sign b {
  display: block;
  font-family: var(--ff-serif); font-weight: 700;
  font-size: 27px; line-height: 1; letter-spacing: .2em; text-indent: .2em;
  color: #F0CE7A;
  text-shadow: 0 0 34px rgba(224,180,92,.22);
}
.cr-sign i {
  display: block; margin-top: 16px;
  font-style: normal; font-size: 11px; letter-spacing: .5em; text-indent: .5em;
  color: rgba(224,180,92,.62);
}
/* 与 .pv-cn2 / .cv-title 同一套鎏金渐变（background-clip:text 与 text-shadow
   不能共存，故换成 filter: drop-shadow） */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .cr-sign b {
    background: linear-gradient(174deg, #FFF6E2 8%, var(--gold-2) 44%, #B8863A 94%);
    -webkit-background-clip: text;
            background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    text-shadow: none;
    filter: drop-shadow(0 0 18px rgba(0, 0, 0, .5));
  }
}
/* 字号（图内像素 → 视口像素） */
.page--prov .pv-kicker { font-size: calc(var(--pvw) / 1920 * 30); }
.page--prov .pv-cn2    { font-size: calc(var(--pvw) / 1920 * 92); }
.page--prov .pv-body   { font-size: calc(var(--pvw) / 1920 * 23); }

/* ---- 逐省坐标：left = 水平中心（四川为左边界），top = 行盒顶部 ----
   三个值依次为 kicker / title / body，单位 %（x/1920, y/1358） */
.page--prov[data-slug="jiangxi"]   .pv-kicker { left: 30.0%; top: 15.0%; }
.page--prov[data-slug="jiangxi"]   .pv-cn2    { left: 30.0%; top: 17.6%; }
.page--prov[data-slug="jiangxi"]   .pv-body   { left: 20.0%; top:27.2%; width: 30%; }

.page--prov[data-slug="fujian"]    .pv-kicker { left: 32.2%; top: 20.0%; }
.page--prov[data-slug="fujian"]    .pv-cn2    { left: 32.2%; top:22.6%; }
.page--prov[data-slug="fujian"]    .pv-body   { left: 24.2%; top: 30.6%; width: 25%; }

.page--prov[data-slug="guangdong"]  .pv-kicker { left: 18.0%; top: 40.6%; }
.page--prov[data-slug="guangdong"]  .pv-cn2    { left: 20.0%; top: 44.2%; }
.page--prov[data-slug="guangdong"]  .pv-body   { left: 12.0%; top: 52.7%; width: 30%; }

.page--prov[data-slug="hunan"]     .pv-kicker { left: 18.8%; top: 22.2%; }
.page--prov[data-slug="hunan"]     .pv-cn2    { left: 20.8%; top: 25.9%; }
.page--prov[data-slug="hunan"]     .pv-body   { left: 10.8%; top: 35.4%; width: 35%; }

.page--prov[data-slug="guangxi"]   .pv-kicker { left: 18.0%; top: 40.6%; }
.page--prov[data-slug="guangxi"]   .pv-cn2    { left: 20.0%; top: 44.2%;  }
.page--prov[data-slug="guangxi"]   .pv-body   { left: 12.0%; top: 52.7%; width: 30%; }

.page--prov[data-slug="guizhou"]   .pv-kicker { left: 18.0%; top: 57.6%; }
.page--prov[data-slug="guizhou"]   .pv-cn2    { left: 20.0%; top:60.2%; }
.page--prov[data-slug="guizhou"]   .pv-body   { left: 12.0%; top: 68.7%; width: 30%;  }

.page--prov[data-slug="yunnan"]    .pv-kicker { left: 19.1%; top: 18.4%; }
.page--prov[data-slug="yunnan"]    .pv-cn2    { left: 20.1%; top: 22.1%; }
.page--prov[data-slug="yunnan"]    .pv-body   { left: 12.1%; top: 30.8%; width: 35%; }

.page--prov[data-slug="sichuan"]   .pv-kicker { left: 29.5%; top: 38.0%; }
.page--prov[data-slug="sichuan"]   .pv-cn2    { left: 30.5%; top: 41.7%; }
.page--prov[data-slug="sichuan"]   .pv-body   { left: 23.5%; top: 50.4%; width:28%; }

.page--prov[data-slug="gansu"]     .pv-kicker { left: 15.9%; top: 18.8%; }
.page--prov[data-slug="gansu"]     .pv-cn2    { left: 16.9%; top: 22.5%; }
.page--prov[data-slug="gansu"]     .pv-body   { left: 10.9%; top: 31.0%; width: 30%; }

.page--prov[data-slug="shaanxi"]   .pv-kicker { left: 24.0%; top: 55.4%; }
.page--prov[data-slug="shaanxi"]   .pv-cn2    { left: 24.0%; top: 58.2%; }
.page--prov[data-slug="shaanxi"]   .pv-body   { left:19.0%; top: 66.4%; width: 30%; }

/* ---- 大屏 / 窄高页防裁切（.pv-copy 整列平移）------------------------
   根因：--pvw 是背景图 cover 后的完整宽度，而 --book-w 被钉在 ≤1160px。
   视口越高（4K、16:10 大屏），cover 左右裁掉的越多，
   文字（x 最小到 10.8%）会整块落进被裁区域，被 .page 的 overflow:hidden 裁断。
   实测：3840×2160 时江西正文左缘超出页外 267px；2560×1440 时
   湖南/广东/广西/贵州/甘肃的正文已开始被裁。

   修法：把「可视区左/上边缘在对位层内的位置」直接算出来——
     左边缘 = (pvw - book-w) / 2   （cover 左右对称裁切）
     上边缘 = (pvw/1.4138 - book-h) / 2
   用 max(0, 边缘 + 安全距 - 该省最靠边文字的声明位置) 得出整列平移量：
   · 没被裁时平移量 = 0，所有已调好的视口视觉零变化；
   · 被裁时整列刚性平移，列内三行文字的相对位置一字不变。
   --col-x / --col-y 取自上方逐省坐标里最小的 left / top（图内比例）。
   只在桌面（>980px）生效；窄屏已改为文档流布局，与此无关。 */
@media (min-width: 981px) {
  .page--prov .pv-copy {
    transform:
      translate(
        max(0px, calc((var(--pvw) - var(--book-w)) / 2 + 24px - var(--pvw) * var(--col-x, 0))),
        max(0px, calc((var(--pvw) / 1.4138 - var(--book-h)) / 2 + 14px - var(--pvw) / 1.4138 * var(--col-y, 0)))
      );
  }
  .page--prov[data-slug="jiangxi"]   .pv-copy { --col-x: .200; --col-y: .150; }
  .page--prov[data-slug="fujian"]    .pv-copy { --col-x: .242; --col-y: .200; }
  .page--prov[data-slug="guangdong"] .pv-copy { --col-x: .120; --col-y: .406; }
  .page--prov[data-slug="hunan"]     .pv-copy { --col-x: .108; --col-y: .222; }
  .page--prov[data-slug="guangxi"]   .pv-copy { --col-x: .120; --col-y: .406; }
  .page--prov[data-slug="guizhou"]   .pv-copy { --col-x: .120; --col-y: .576; }
  .page--prov[data-slug="yunnan"]    .pv-copy { --col-x: .121; --col-y: .184; }
  .page--prov[data-slug="sichuan"]   .pv-copy { --col-x: .235; --col-y: .380; }
  .page--prov[data-slug="gansu"]     .pv-copy { --col-x: .109; --col-y: .188; }
  .page--prov[data-slug="shaanxi"]   .pv-copy { --col-x: .190; --col-y: .554; }
}

/* 注意：各省 .pv-body 的 left / top / width 必须写在同一条声明里。
   早期为避开影像档案卡片，另起过一组「只写 width」的补丁规则追加在文件末尾，
   与上面的逐省规则同优先级 —— 后写的 width 会静默覆盖上面的 width，
   导致该省 width 怎么改都不生效。现已合并，勿再拆开。 */

/* ---- 影像档案：浮在背景图上（右下角区域） ---- */
.pv-arch {
  position: absolute; z-index: 5;
  right: clamp(16px, 3.4%, 46px); bottom: clamp(52px, 9%, 90px);
  width: min(500px, 46%);
  display: flex; flex-direction: column; gap: 12px;
  pointer-events: none;
}
.pv-arch > * { pointer-events: auto; }

/* 省份页原有的左右两栏结构（.pv-inner/.pv-left/.pv-no…）已由 .pv-fit 对位层替代。
   旧 CSS 全部移除，HTML 中也已同步删除对应标记。 */

/* 影像档案浮层的标题行 */
.pv-arch__head { display: flex; align-items: center; gap: 11px; font-size: 11px; letter-spacing: .28em; color: var(--muted);
                 text-shadow: 0 1px 8px rgba(0,0,0,.9); }
.pv-arch__head .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--red); box-shadow: 0 0 12px var(--red); }
.pv-arch__head .hr { flex: 1; height: 1px; background: linear-gradient(90deg, var(--line), transparent); }
.pv-arch__head b { font-weight: 400; color: rgba(242,235,224,.45); letter-spacing: .2em; }

.clips { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(10px, 1.2vw, 20px); list-style: none; margin: 0; padding: 0; }
#sic  .clips {
	grid-template-columns: repeat(3, 1fr); 
}
.clip {
  position: relative; cursor: pointer; overflow: hidden;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,.018));
  transition: transform .5s var(--ease), border-color .4s ease, box-shadow .5s ease;
}
.clip:hover { transform: translateY(-6px); border-color: var(--gold-dim); box-shadow: 0 22px 54px rgba(0,0,0,.55); }

.clip__poster { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: #111; }
.clip__poster img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: saturate(.7) contrast(1.06) brightness(.8);
  transform: scale(1.02);
  transition: transform 1.1s var(--ease), filter .6s ease;
  pointer-events: none; user-select: none; -webkit-user-drag: none;
}
.clip:hover .clip__poster img { transform: scale(1.09); filter: saturate(1) contrast(1.1) brightness(.95); }
.clip__poster::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: linear-gradient(180deg, rgba(6,8,6,.08) 0%, rgba(6,8,6,.6) 100%); }

.clip__play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 46px; height: 46px; border-radius: 50%; z-index: 2;
  border: 1.5px solid rgba(255,255,255,.68); background: rgba(10,10,10,.3);
  backdrop-filter: blur(6px);
  display: flex; align-items: center; justify-content: center;
  transition: all .4s var(--ease);
}
.clip__play::before {
  content: ''; border-style: solid; border-width: 7px 0 7px 12px;
  border-color: transparent transparent transparent #fff; margin-left: 3px;
}
.clip:hover .clip__play { background: var(--gold); border-color: var(--gold); transform: translate(-50%, -50%) scale(1.14); }
.clip:hover .clip__play::before { border-left-color: #1a1206; }

.clip__dur {
  position: absolute; right: 9px; bottom: 8px; z-index: 2;
  font-size: 10px; letter-spacing: .1em; padding: 3px 7px; border-radius: 3px;
  background: rgba(6,8,6,.66); color: rgba(255,255,255,.86);
}

.clip__body { padding: 14px 15px 15px; }
.clip__body h3 {
  font-family: var(--ff-serif); font-size: clamp(14px, 1.1vw, 16.5px);
  font-weight: 600; line-height: 1.5; margin: 0 0 7px; color: #FBF5EA;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  transition: color .3s ease;
}
.clip:hover .clip__body h3 { color: var(--gold-2); }
.clip__body p {
  font-size: 11.8px; line-height: 1.7; color: var(--faint); margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.clip__meta {
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: center;
  font-size: 10px; letter-spacing: .2em; color: rgba(242,235,224,.34);
}
.clip__meta b { color: var(--gold); font-weight: 500; font-family: var(--ff-serif); }

.pv-sites { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.pv-sites__lb { font-size: 10.5px; letter-spacing: .28em; color: var(--faint); margin-right: 4px; }
.pv-sites__item {
  font-size: 11px; letter-spacing: .06em; padding: 5px 10px; border-radius: 4px;
  border: 1px dashed var(--line); color: rgba(242,235,224,.58);
}
.pv-sites__item b { color: var(--gold-2); font-weight: 500; margin-right: 6px; }

.pv-foot {
  position: absolute; left: clamp(22px, 4%, 52px); right: clamp(22px, 4%, 52px);
  bottom: clamp(16px, 3%, 30px); z-index: 4;
  display: flex; justify-content: space-between; align-items: center;
  font-size: 10.5px; letter-spacing: .3em; color: rgba(242,235,224,.26);
  border-top: 1px solid var(--line); padding-top: 12px;
}
.pv-foot i { font-style: normal; font-family: var(--ff-serif); color: var(--gold-dim); letter-spacing: .2em; }

/* =========================================================
   HUD
   ========================================================= */
.hud { position: absolute; left: 0; right: 0; z-index: 600; display: flex; align-items: center; padding: 0 clamp(18px, 3.2vw, 50px); pointer-events: none; }
.hud > * { pointer-events: auto; }

.hud--top { top: 0; height: var(--hud-t); justify-content: space-between; background: linear-gradient(180deg, rgba(4,6,5,.78), rgba(4,6,5,0)); }
.hud--bottom { bottom: 0; height: var(--hud-b); justify-content: space-between; background: linear-gradient(0deg, rgba(4,6,5,.86), rgba(4,6,5,0)); }

.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; color: inherit; }
.brand__mark {
  width: 28px; height: 28px; flex: none; position: relative;
}
/* 中国共产党党徽（镰刀和锤头）
   图案取自官方标准版本（共产党员网发布的 1024×1024 标准图），描线转为矢量后
   以 mask 上色 —— 颜色由 --gold 控制，任意尺寸都锐利，体积仅 2KB。
   注意：SVG 必须带 width/height，只有 viewBox 会被当成 0×0 而不渲染。
   光晕用 filter: drop-shadow 而非 box-shadow —— 只有前者会贴合镰刀锤头的外形。 */
.brand__mark::after {
  content: ''; position: absolute; top: 1px; right: 1px; bottom: 1px; left: 1px;
  background: var(--gold);
  -webkit-mask-image: url("../img/emblem/danghui.svg");
          mask-image: url("../img/emblem/danghui.svg");
  -webkit-mask-repeat: no-repeat;  mask-repeat: no-repeat;
  -webkit-mask-position: center;   mask-position: center;
  -webkit-mask-size: contain;      mask-size: contain;
  filter: drop-shadow(0 0 5px rgba(200,16,46,.5));
}
.brand__txt { display: flex; flex-direction: column; gap: 3px; line-height: 1; }
.brand__txt b { font-family: var(--ff-serif); font-size: 15px; letter-spacing: .2em; font-weight: 600; }
.brand__txt i { font-style: normal; font-size: 8.5px; letter-spacing: .34em; color: var(--faint); }

.hud__right { display: flex; align-items: center; gap: 20px; }
.chips { display: flex; gap: 4px; }
.chip { width: 24px; height: 3px; border: 0; padding: 0; cursor: pointer; border-radius: 2px; background: rgba(242,235,224,.2); transition: all .3s ease; }
.chip:hover { background: rgba(224,180,92,.7); }
.chip.is-on { background: var(--gold); width: 38px; }
.chip.is-done { background: rgba(242,235,224,.42); }

.btn {
  font-family: var(--ff-sans); cursor: pointer; background: none; border: 0; color: var(--text);
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 12.5px; letter-spacing: .16em; padding: 9px 15px; border-radius: 999px;
  transition: all .28s ease;
}
.btn:disabled { opacity: .26; cursor: not-allowed; }
.btn--ghost { border: 1px solid var(--line); color: var(--muted); }
.btn--ghost:hover:not(:disabled) { border-color: var(--gold-dim); color: var(--gold-2); background: rgba(224,180,92,.08); }
.btn--nav { border: 1px solid var(--line); color: var(--muted); padding: 11px 20px; }
.btn--nav:hover:not(:disabled) { border-color: var(--gold-dim); color: var(--gold-2); background: rgba(224,180,92,.08); }
.btn--sm { border: 1px solid var(--line); color: var(--muted); font-size: 11.5px; padding: 8px 14px; }
.btn--sm:hover:not(:disabled) { border-color: var(--gold-dim); color: var(--gold-2); }
.btn--x { font-size: 13px; color: var(--muted); padding: 7px 10px; }
.btn--x:hover { color: var(--gold-2); background: rgba(255,255,255,.06); }

.ico-list { width: 14px; height: 10px; border-top: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; position: relative; }
.ico-list::after { content: ''; position: absolute; left: 0; right: 0; top: 50%; border-top: 1.5px solid currentColor; }
.arw { width: 6px; height: 6px; border-top: 1.5px solid currentColor; border-right: 1.5px solid currentColor; }
.arw--l { transform: rotate(-135deg); }
.arw--r { transform: rotate(45deg); }

.pager { flex: 1; max-width: 440px; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.pager__now { font-family: var(--ff-serif); display: flex; align-items: baseline; gap: 7px; }
.pager__now b { font-size: 18px; color: var(--gold); font-weight: 600; letter-spacing: .06em; }
.pager__now span { color: rgba(242,235,224,.22); font-size: 12px; }
.pager__now i { font-style: normal; font-size: 11.5px; color: var(--faint); letter-spacing: .1em; }
.pager__track { width: 100%; height: 2px; background: rgba(242,235,224,.12); position: relative; overflow: hidden; }
.pager__track i { position: absolute; left: 0; top: 0; bottom: 0; background: linear-gradient(90deg, rgba(224,180,92,.4), var(--gold)); transition: width .6s var(--ease); }
.pager__name { font-size: 10.5px; letter-spacing: .26em; color: var(--faint); }

.hint {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--hud-b) - 4px); z-index: 620;
  display: flex; align-items: center; gap: 9px;
  font-size: 10.5px; letter-spacing: .14em; color: rgba(242,235,224,.42);
  padding: 6px 16px; border-radius: 999px;
  background: rgba(6,8,6,.5); border: 1px solid var(--line);
  transition: opacity .6s ease; pointer-events: none;
}
.hint.is-off { opacity: 0; }
.hint__k { color: var(--gold); border: 1px solid var(--gold-dim); border-radius: 4px; padding: 2px 7px; font-size: 10px; }
.hint__d { width: 1px; height: 11px; background: var(--line); }

/* =========================================================
   目录抽屉
   ========================================================= */
.toc { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 900; pointer-events: none; }
.toc[aria-hidden="false"] { pointer-events: auto; }
.toc__bd { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: rgba(3,4,3,.62); opacity: 0; transition: opacity .45s ease; backdrop-filter: blur(4px); }
.toc[aria-hidden="false"] .toc__bd { opacity: 1; }
.toc__panel {
  position: absolute; right: 0; top: 0; bottom: 0; width: min(430px, 88vw);
  background: linear-gradient(180deg, #0E1210, #080A09);
  border-left: 1px solid var(--line);
  transform: translateX(100%); transition: transform .55s var(--ease);
  display: flex; flex-direction: column;
  box-shadow: -30px 0 80px rgba(0,0,0,.6);
}
.toc[aria-hidden="false"] .toc__panel { transform: none; }
.toc__head { display: flex; align-items: center; justify-content: space-between; padding: 24px 24px 16px; border-bottom: 1px solid var(--line); }
.toc__head h2 { margin: 0; font-family: var(--ff-serif); font-size: 18px; letter-spacing: .2em; font-weight: 600; display: flex; align-items: baseline; gap: 11px; }
.toc__head i { font-style: normal; font-size: 9px; letter-spacing: .34em; color: var(--faint); }
.toc__list { flex: 1; overflow: auto; margin: 0; padding: 10px 12px; list-style: none; }
.toc__list li { display: flex; align-items: center; gap: 15px; padding: 12px 14px; cursor: pointer; border-radius: 8px; transition: background .25s ease; }
.toc__list li:hover { background: rgba(224,180,92,.09); }
.toc__list li.is-on { background: rgba(200,16,46,.14); box-shadow: inset 2px 0 0 var(--red); }
.toc__no { font-family: var(--ff-serif); font-size: 12px; color: var(--gold); letter-spacing: .1em; width: 26px; opacity: .8; }
.toc__cn { font-family: var(--ff-serif); font-size: 16.5px; letter-spacing: .1em; }
.toc__sub { margin-left: auto; font-size: 10.5px; letter-spacing: .14em; color: var(--faint); text-align: right; }
.toc__foot { padding: 16px 24px 24px; border-top: 1px solid var(--line); font-size: 10.5px; letter-spacing: .14em; color: var(--faint); }

/* =========================================================
   播放弹窗
   ========================================================= */
.player { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 950; display: flex; align-items: center; justify-content: center; padding: clamp(14px, 3.6vw, 54px); pointer-events: none; }
.player[aria-hidden="false"] { pointer-events: auto; }
.player__bd { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: rgba(2,3,2,.84); opacity: 0; transition: opacity .4s ease; backdrop-filter: blur(10px); }
.player[aria-hidden="false"] .player__bd { opacity: 1; }
.player__box {
  position: relative; width: min(1160px, 94vw);
  background: linear-gradient(180deg, #121614, #0A0C0B);
  border: 1px solid var(--line); border-radius: 3px; overflow: hidden;
  box-shadow: 0 40px 120px rgba(0,0,0,.75);
  transform: translateY(18px) scale(.98); opacity: 0;
  transition: transform .5s var(--ease), opacity .4s ease;
}
.player[aria-hidden="false"] .player__box { transform: none; opacity: 1; }
.player__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; padding: 18px 20px 14px; border-bottom: 1px solid var(--line); }
.player__prov { font-size: 10.5px; letter-spacing: .32em; color: var(--gold); margin-bottom: 7px; }
.player__titles h3 { margin: 0 0 6px; font-family: var(--ff-serif); font-size: clamp(16px, 1.6vw, 23px); letter-spacing: .04em; font-weight: 600; }
.player__titles p { margin: 0; font-size: 12px; color: var(--faint); line-height: 1.7; }
.player__stage { position: relative; background: #000; aspect-ratio: 16 / 9; }
.player__stage video { width: 100%; height: 100%; display: block; background: #000; }
.player__loading {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0; display: flex; align-items: center; justify-content: center; gap: 11px;
  font-size: 11.5px; letter-spacing: .2em; color: var(--muted); background: rgba(0,0,0,.7);
  transition: opacity .4s ease;
}
.player__loading span { width: 15px; height: 15px; border: 2px solid rgba(224,180,92,.25); border-top-color: var(--gold); border-radius: 50%; animation: spin .8s linear infinite; }
.player__loading.is-off { opacity: 0; pointer-events: none; }
@keyframes spin { to { transform: rotate(360deg) } }
.player__foot { display: flex; align-items: center; justify-content: space-between; padding: 13px 20px 16px; }
.player__idx { font-size: 11px; letter-spacing: .3em; color: var(--faint); }

/* =========================================================
   响应式
   ========================================================= */
@media (max-width: 1180px) {
  :root { --book-w: min(1000px, 94vw); }
  .cv-left { max-width: 62%; }
}
@media (max-width: 980px) {
  :root { --hud-t: 64px; --hud-b: 88px; --book-w: 94vw; --book-h: calc(var(--vh) - var(--hud-t) - var(--hud-b) - 4px); }
  .cv-chapters, .chips, .hint { display: none; }
  .cv-left { max-width: 88%; }

  /* =========================================================
     移动端翻页说明（2026-10-12 Swiper flip 版）
     翻页引擎已整体换成 Swiper flip（见 .swiper-container 覆盖块），
     窄屏不再走旧的「2D 摊平 --t 横滑」方案。Swiper 的 3D flip 只依赖
     基础 CSS 3D transform，且页内纵向滚动由 .book-zone（3D 上下文之外）
     承担，不触发旧时代「3D 渲染上下文里 overflow 失效」的问题。
     ========================================================= */
  /* 书区 = 「按页内容定高」的纵向滚动容器（见 index.html 的 measurePages）。
     高度仍是 --book-h（一屏可用高），但 overflow-y:auto —— 长页整页撑开后
     可以上下滑动看完，不必再按一屏裁切。横向拖拽翻页不受影响：
     方向锁定会把纵向占主导的手势让给这里的滚动。 */
  .book-zone {
    left: 0; right: 0; top: var(--hud-t);
    width: auto; height: var(--book-h);
    transform: none;
    perspective: none;
    overflow-y: auto; overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }
  /* 书宽仍是 --book-w，在滚动容器里居中（Swiper 容器） */
  .book { position: relative; width: var(--book-w); height: 100%; margin: 0 auto; }
  /* 每页高度由 JS 写死为 --leaf-h（= max(一屏, 内容高)）。
     Swiper slide 是 flex 子项、顶端对齐：短页 --leaf-h = 一屏 = 书高，天然填满，
     不再需要旧的 top:50% + translateY(-50%) 居中手段（那是绝对定位时代的写法）。
     注意：绝不能回到 transform-style:flat —— flip 效果需要 preserve-3d。 */
  .swiper-container .leaf { height: var(--leaf-h, 100%); }
  /* 翻动受光/背光层在 2D 滑动下只会把页面越滑越黑，关掉 */
  .face--front::after, .face--back::after { content: none; }
  /* 书影装饰在 2D 滑动下看不到；纸张背面已由上面的 .swiper-container .face--back 统一隐藏 */
  .book-deco { display: none; }
  /* 底部 HUD 避开 iPhone Home 指示条 */
  .hud--bottom { padding-bottom: env(safe-area-inset-bottom); }

  /* =========================================================
     移动端 / 微信 webview 降开销
     以下四项都会强制「每帧重绘整屏」，是页面闪烁与持续卡顿的主因。
     桌面端保留原效果，窄屏才关掉。
     ========================================================= */
  /* 1) 全屏噪点层带 mix-blend-mode: overlay —— 混合模式会把整个舞台
        拉进同一个合成上下文，任何一帧变化都要重新混合整屏 */
  .stage::after { display: none; }
  /* 2) backdrop-filter：30 张影像卡的播放按钮各要一次背景采样 */
  .clip__play {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: rgba(8, 9, 8, .44);
  }
  .toc__bd, .player__bd { -webkit-backdrop-filter: none; backdrop-filter: none; }
  /* 3) 背景呼吸动效：24s 无限循环，每帧都对整张 1920×1358 做 filter + scale 重绘 */
  .page--prov.is-live::before { animation: none !important; }
  /* 4) 纸张投影：22 个面各带 90px 模糊的大阴影，窄屏收到轻量档 */
  .face { box-shadow: 0 12px 34px rgba(0, 0, 0, .5); }

  /* 窄屏/竖屏：页面比封面图(1.414:1)更窄，背景图左右被裁，
     不再与背景图做像素对位，文字改按页面坐标排布 */
  .cv-fit {
    left: 0; top: 0; transform: none;
    width: 100%; height: 100%; aspect-ratio: auto;
    display: flex; flex-direction: column;
    /* ⚠️ 不能用 justify-content:center —— 「居中 flex + 溢出」是经典截断 bug：
       内容比容器高时溢出被从两头裁掉，上面滚不回来、下面（开始翻阅按钮）
       在 vivo / 部分国产内核里根本滚不到。改用 auto margin 居中：
       装得下时效果与 center 完全一致，装不下时 margin 归零、顶端对齐、整段可滚。 */
    justify-content: flex-start;
    overflow-y: auto; padding: 0 8%;
    /* 滚动容器强化：iOS 惯性滚动 + 不把滚动链传给 body（body 是 overflow:hidden） */
    /* ⚠️ 同 .page--prov：不能 contain，否则手势上不了链（见下方省份页注释） */
    overscroll-behavior: auto;
    touch-action: pan-y;
    -webkit-overflow-scrolling: touch;
  }
  .cv-copy { position: relative; z-index: 1; left: 0; right: 0; top: auto; margin-top: auto; }
  /* 文字底下垫一层柔和暗渐变，避免压在地图线条上 */
  .cv-fit::before {
    content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; pointer-events: none;
    background: radial-gradient(130% 86% at 50% 42%, rgba(4,6,5,.16) 0%, rgba(4,6,5,.6) 100%);
  }
  .page--cover .cv-kicker {
    font-size: 11px; letter-spacing: .3em; margin-bottom: 16px;
    /* 窄屏容器只有 ~300px，两侧装饰线会挤掉大半宽度且收缩不均导致偏心，
       直接去掉线、纯文字居中（justify-content:center 已由基础规则提供）。 */
    justify-content: center; padding-left: 0; padding-right: 0;
  }
  .page--cover .cv-kicker::before,
  .page--cover .cv-kicker::after { display: none; }
  .page--cover .cv-title  { font-size: clamp(30px, 8.8vw, 46px); margin-bottom: 8px; }
  .page--cover .cv-en     { font-size: 13px; line-height: 1.95; margin-bottom: 16px; }
  .page--cover .cv-stats  { gap: 24px; margin: 6px 0 0; }
  .page--cover .cv-stats b{ font-size: 20px; }
  .page--cover .cv-stats i{ font-size: 9.5px; }
  .page--cover .cv-start  {
    position: relative; z-index: 1; left: 0; right: 0; top: auto;
    margin-top: 30px; margin-bottom: auto; align-self: flex-start;
    font-size: 13px; padding: 12px 30px;
  }
  /* 窄屏/竖屏：页面比省份图(1.414:1)更窄，背景图左右被裁，
     不再与背景图做像素对位，文字改按页面坐标排布。
     关键：把 .pv-fit(文字对位层) 与 .pv-arch(影像档案) 放进同一个
     纵向流里，两者都回到普通块级布局，绝不重叠。 */
  /* 省份页内容在手机上一定比书页高（文字 + 影像档案 + 长征节点）。
     现在由 JS 的 measurePages 把 .leaf 撑到内容真实高度、纵向滚动统一
     交给 .book-zone（见 index.html），这里的 overflow-y:auto 只是兜底：
     万一某页量矮了，本容器还能自己滚，不至于被 .face 直接裁掉。
     ⚠️ 两条前提：
       ① 内联 JS 在触摸时不能对 pointerdown 调 preventDefault，
          否则 WebKit / 微信 webview 会吃掉整段手势，这里的 overflow 全部失效；
       ② overscroll-behavior 必须是 auto，绝不能 contain（2026-10-13 修复）——
          本容器 scrollHeight === clientHeight、自己滚不动，一旦写 contain
          就会禁止把手势链给祖先 .book-zone，整段手势被吞：
          表现为「长页（四川）内容截断、右侧没有滚动条、滑不动」。 */
  .page--prov {
    overflow-y: auto; overflow-x: hidden;
    overscroll-behavior: auto;
    touch-action: pan-y;
    -webkit-overflow-scrolling: touch;
  }
  .pv-fit {
    position: static; left: auto; top: auto; transform: none;
    width: 100%; height: auto; aspect-ratio: auto;
    display: block;
  }
  .page--prov .pv-copy {
    position: static; top: auto; right: auto; bottom: auto; left: auto;
    padding: 9% 7% 4% 6%;
    display: block; overflow: visible;
  }
  /* 逐省 left/top 在窄屏全部作废 */
  .page--prov .pv-copy > *,
  .page--prov[data-slug] .pv-copy > * {
    position: static; left: auto !important; top: auto !important;
    transform: none !important; width: auto !important;
    text-align: left; white-space: normal;
  }
  .page--prov .pv-kicker { font-size: 11px; letter-spacing: .2em; margin: 0 0 10px; }
  .page--prov .pv-cn2    { font-size: clamp(38px, 12vw, 58px); margin: 0 0 14px; }
  .page--prov .pv-body   { font-size: 13px; line-height: 1.85; max-width: none; margin: 0; }

  /* 版权页：手机端改为顶对齐 + 自身可滚。
     ⚠️ 绝不能保留 align-items:center —— 「居中 flex + 溢出」会让超出部分两头被裁、
     顶部永久滚不回来（同 .cv-fit 的老教训），顶对齐 + .cr-inner 的 auto margin
     在装得下时与居中完全一致，装不下时顶端对齐、整段可滚。
     overscroll-behavior 必须 auto：本容器多数时候滚不动，一旦 contain 会掐断手势链。 */
  .page--credits {
    align-items: flex-start;
    padding: 12% 8%;
    overflow-y: auto; overflow-x: hidden;
    overscroll-behavior: auto;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
  }
  .page--credits .cr-inner { margin: auto 0; width: 100%; }
  .page--credits .cr-kicker { font-size: 9.5px; letter-spacing: .42em; text-indent: .42em; padding-bottom: 14px; margin-bottom: 20px; }
  .page--credits .cr-row { gap: 14px; padding: 11px 0; }
  .page--credits .cr-row b { flex: 0 0 56px; font-size: 13px; letter-spacing: .26em; }
  .page--credits .cr-row span { font-size: 13.5px; line-height: 1.9; letter-spacing: .06em; }
  .page--credits .cr-sign { margin-top: 32px; }
  .page--credits .cr-sign b { font-size: 19px; letter-spacing: .14em; text-indent: .14em; }
  .page--credits .cr-sign i { margin-top: 12px; font-size: 10px; letter-spacing: .46em; text-indent: .46em; }

  /* 影像档案：在文字之后正常排列，不再绝对定位到页首 */
  .pv-arch {
    position: static; right: auto; left: auto; bottom: auto; top: auto;
    width: auto; margin: 26px 6% 26px; gap: 10px;
  }
  .clips { grid-template-columns: 1fr; }

  /* ============================================================
     移动端入场动画压到「一帧」（根因修复）。
     中低端安卓 / 微信 WebView 会 throttle 或直接丢弃 0.8s + 最长 560ms
     的入场动画；一旦动画没跑成，.anim 就永远停在 opacity:0 的静态值 ——
     表现就是「电脑端正常，手机端翻到的页中间内容（正文 + 影像卡）空白」。
     改成 1ms：视觉上立即整页显示（无渐入，正合“特效过多”的诉求），
     但动画本身仍跑一帧 —— 保留“靠 riseIn 强制主线程重绘”这条
     旧内核上唯一的重绘保险（旧教训：animation:none 会让新页永远不重绘）。
     这里只压时长/延迟，绝不叠 opacity/transform 的 !important，
     否则会把动画的 from/to 架空、重绘保险随之失效。 */
  .page.is-live .anim { animation: riseIn 1ms linear both !important; animation-delay: 0ms !important; }
  .page.is-live .fadeAnim { animation: fadeIn 1ms linear both !important; animation-delay: 0ms !important; }

	#view-fullscreen,#cancel-fullscreen  {
		
		display: none;
	}	
	
}

@media (max-width: 700px) {
  .hud--top, .hud--bottom { padding: 0 14px; }
  .cv-title { font-size: 34px; }

  .cv-stats { gap: 20px; }
  .pager__name { display: none; }
  .player__box { width: 96vw; }
  .btn--nav span:not(.arw) { display: none; }
  .pv-arch__head { display: none; }
  .page--prov .pv-body { font-size: 12.5px; }
#sic  .clips {
	grid-template-columns: repeat(1, 1fr); 
}
		#view-fullscreen,#cancel-fullscreen  {
		
		display: none;
	}	
}
@media (prefers-reduced-motion: reduce) {
  :root { --flip: 1ms; }
  .page.is-live .anim { animation: none; opacity: 1; transform: none; }
  /* 背景呼吸动效同样需要尊重系统的「减弱动态效果」设置 */
  .page--prov.is-live::before { animation: none !important; }
}

/* =========================================================
   旧内核兜底（小米 / 华为自带浏览器、UC、钉钉、支付宝、老 ROM WebView）
   —— 目标内核：Chromium 66 / 69 / 74 / 76 / 78 / 86
   ========================================================= */

/* 1) 无 @property 的引擎（Chromium < 85）
   `transition: --t` 依赖 @property 注册（Chrome 85+），否则自定义属性不可动画，
   --t 一帧从 0 跳到 1 —— 翻页没有过渡，视觉上就是「闪一下」。
   兜底：改为过渡 transform。--t 变化会让引用它的 transform 计算值跟着变，
   浏览器据此对 transform 做补间，实测帧序列与现代内核一致（39 帧 vs 40 帧）。
   这个类由 index.html 里的特性检测脚本挂在 <html> 上。 */
.no-propvar .leaf { transition: transform var(--flip) var(--ease); }
.no-propvar .leaf.no-anim { transition: none; }
/* 翻页时的受光/背光遮罩同样依赖 --t，一并补上 */
.no-propvar .face--front::after,
.no-propvar .face--back::after { transition: opacity var(--flip) var(--ease); }

/* 2) 无 aspect-ratio 的引擎（Chromium < 88）
   现代内核的 .clip__poster / .player__stage 靠 aspect-ratio 定高，
   旧引擎会退成「图片自然高度」→ 卡片高度不齐，且与
   「后补 src 不造成跳动」的前提冲突。用 padding 撑高的经典写法兜底。 */
@supports not (aspect-ratio: 16 / 9) {
  .clip__poster,
  .player__stage { height: 0; padding-top: 56.25%; }
  .clip__poster img,
  .clip__poster::after,
  .player__stage video {
    position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  }
  /* 桌面端 .cv-fit / .pv-fit 是与背景图做像素对位的层，
     里面全是绝对定位子元素，没有 aspect-ratio 就会塌成 0 高、文字全消失。
     用与 aspect-ratio 等价的显式高度还原（1920 / 1358 = 1.4138）。 */
  .cv-fit { height: calc(var(--cvw) / 1.4138); }
  .pv-fit { height: calc(var(--pvw) / 1.4138); }
}

/* 3) 无 color-mix() 的引擎（Chromium < 111）
   color-mix 在 background 简写里，一个分量非法会让**整条 background 被丢弃**。
   兜底写在原 .page--prov 规则内部、color-mix 那条之前（见该规则内的注释）——
   不能追加在文件末尾，否则会因同优先级后写覆盖，把现代内核的版本也顶掉。 */
