/* 《这个小美/小帅能谈吗》V7.0 光影叙事 HTML 交互预览
   说明：这是本地交互预览，不引用任何外部素材或 CDN。*/

/* ==========================================================================
   Chrome 61（Android 8.1 出厂 WebView）基线约定 —— 改样式前先看这三条
   ==========================================================================
   ① **Grid 间距写两行**：`grid-gap: N; gap: N;`
      `gap` 这个简写对 Grid 容器要 Chrome 66 才认，Chrome 61 只认 `grid-gap`
      （`grid-row-gap` / `grid-column-gap` 也行）。两条同义、写在一起的顺序是
      "旧的内核读第一条、新的内核读第二条"，缺了第一条在基线上间距会整个消失。
      （Flex 的 `gap` 更晚：Chrome 84。所以 Flex 一律用"子项 margin 打底 +
      JS 行为检测出 `.supports-flex-gap` 再上 gap"，见文件末尾那一段。）
   ② **不用 `inset` 简写**（Chrome 87+），四个方向老老实实写 top/right/bottom/left。
   ③ **不在同一条声明里混现代函数**：`conic-gradient`、`aspect-ratio`、`dvh`
      这些要么有基线兜底，要么只出现在不参与渲染的死规则里。
   ========================================================================== */

/* ---------- 字体（全部本地内嵌，不依赖网络） ---------- */
/* 书法：仓耳周珂正大榜书 */
@font-face {
  font-family: "CangerBangshu";
  src: url("./assets/fonts/canger-bangshu.woff2") format("woff2");
  font-weight: 400 900;
  font-display: swap;
}

/* 宋体：字体圈欣意吉祥宋 */
@font-face {
  font-family: "JixiangSong";
  src: url("./assets/fonts/jixiang-song.woff2") format("woff2");
  font-weight: 400 900;
  font-display: swap;
}

/* 黑体：思源黑体（Noto Sans SC） */
@font-face {
  font-family: "SourceHanSans";
  src: url("./assets/fonts/source-han-sans-regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "SourceHanSans";
  src: url("./assets/fonts/source-han-sans-bold.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}

:root {
  --void: #020302;
  --ink: #f2e7d5;
  --ink-dim: rgba(242, 231, 213, .68);
  --corridor-green: #17211b;
  --corridor-brown: #23180f;
  --lamp-gold: #f0b352;
  --lamp-glow: #ffd68f;
  --woman-red: #cf3d51;
  --man-blue: #6ec8d8;
  --line: rgba(255, 232, 188, .22);
  --panel: rgba(9, 11, 9, .78);
  --danger: #b4484c;
  --mark: #8dbe8f;
  --serif: "JixiangSong", "Songti SC", "SimSun", "Noto Serif CJK SC", serif;
  --hand: "CangerBangshu", "Kaiti SC", "STKaiti", "KaiTi", serif;
  --sans: "SourceHanSans", "PingFang SC", "STHeiti", -apple-system, "Segoe UI", sans-serif;
  --chapter-ink: #d9a94f;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* 游戏内容统一禁用文字选择与 iOS 长按菜单；表单/可编辑区域在下方恢复。 */
html,
body,
#web-stage,
#web-stage * {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

#web-stage input,
#web-stage textarea,
#web-stage select,
#web-stage [contenteditable=""],
#web-stage [contenteditable="true"],
#web-stage [contenteditable="plaintext-only"] {
  -webkit-user-select: text;
  -moz-user-select: text;
  -ms-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

html, body { height: 100%; }

body {
  background:
    radial-gradient(circle at 50% 18%, #241a10 0%, #0a0806 46%, #000 100%);
  color: var(--ink);
  font-family: var(--sans);
  display: grid;
  place-items: center;
  min-height: 932px;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  touch-action: manipulation;
}

.phone {
  position: relative;
  perspective: 1800px;
  transform-style: preserve-3d;
  width: 100%;
  max-width: 414px;
  height: 932px;
  max-height: 896px;
  overflow: hidden;
  background: #121213 url("./assets/paper-dark.webp") center / cover no-repeat;
  box-shadow: 0 0 100px rgba(0, 0, 0, .96);
}

/* 手机上不再画"手机边框"：全屏铺满，由下面 .phone 的全屏规则接管 */

.screen {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .38s ease, transform .6s ease, visibility 0s linear .38s;
  overflow: hidden;
  transform: scale(.99);
}

.screen.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: rotateY(0) scale(1);
  z-index: 2;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  transition: opacity .38s ease, transform .6s ease, visibility 0s;
}

.phone.is-storyline-open .game-chrome { z-index: 70; }

/* ---------- 公共标题与标记 ---------- */
.preview-flag {
  position: absolute;
  z-index: 50;
  left: 18px;
  top: 14px;
  font: 500 10px/1 var(--sans);
  letter-spacing: .16em;
  color: rgba(255, 255, 255, .48);
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 999px;
  padding: 5px 8px;
  pointer-events: none;
}

.vertical-title {
  position: absolute;
  top: auto;
  bottom: 196px;
  left: 40px;
  z-index: 24;
  width: auto;
  max-width: calc(100% - 44px);
  height: auto;
  display: grid;
  grid-gap: 1px;
  gap: 1px;
  font-family: var(--serif);
  /* 两行：第一行「这个小美，」，第二行「能谈吗？」 */
  font-size: 37.84px;
  font-weight: 600;
  letter-spacing: .015em;
  line-height: 1.14;
  color: rgba(255,251,244,.93);
  text-shadow: 0 4px 18px rgba(19,0,2,.88), 0 0 24px rgba(255,166,136,.12);
  pointer-events: none;
  min-height: 0;
}

.vertical-title span { display: block; }
.vertical-title span:last-child { margin-left: 0; }

.vertical-title em {
  font-style: normal;
  transition: text-shadow .36s ease;
}

.vertical-title.is-woman em {
  color: #ffd4cf;
  text-shadow: 0 0 24px rgba(255,103,104,.54), 0 3px 14px rgba(19,0,2,.86);
}

.vertical-title.is-man em {
  color: #8ee6ff;
  text-shadow: 0 0 26px rgba(91,195,255,.72), 0 3px 14px rgba(4,18,28,.86);
}

.asset-slot {
  position: absolute;
  top: 6.5%;
  right: 6.5%;
  bottom: 6.5%;
  left: 6.5%;
  border: 1px dashed rgba(255, 235, 190, .30);
  border-radius: 8px;
  overflow: hidden;
  background: rgba(0, 0, 0, .20);
  color: rgba(255, 236, 198, .52);
  display: grid;
  align-content: end;
  justify-items: center;
  padding: 10px;
  font: 500 9.5px/1.3 var(--sans);
  letter-spacing: .08em;
  text-align: center;
  pointer-events: none;
  transition: opacity .4s ease, box-shadow .45s ease, border-color .45s ease;
}

/* 槽内的凹陷感 + 四周暗角 */
.asset-slot.is-active {
  box-shadow:
    inset 0 0 0 1px rgba(0,0,0,.35),
    inset 0 10px 18px -10px rgba(0,0,0,.75),
    inset 0 -10px 18px -10px rgba(0,0,0,.7);
}

.asset-slot.is-active::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(112% 78% at 50% 46%, transparent 40%, rgba(0,0,0,.34) 76%, rgba(0,0,0,.68) 100%);
}

/* 卡纸上的小字与噪点 */
.scene-print::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  border-radius: inherit;
  opacity: .16;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}

.asset-slot::before {
  content: "素材空位";
  font-family: var(--serif);
  font-size: 18px;
  letter-spacing: .28em;
  opacity: .26;
  margin-bottom: 6px;
}

.asset-slot.is-active {
  opacity: 1;
  border-color: rgba(255, 220, 150, .62);
  box-shadow: inset 0 0 34px rgba(255, 184, 80, .12);
}

.asset-slot.is-dim {
  opacity: .22;
  filter: blur(1px);
}

/* ---------- 首页：红色证件剧场 ---------- */
#screen-home {
  --slide: 0;
  --push: 0;
  --left-on: 1;
  --right-on: 0;
  --light-focus: 50%;
  color: #fff5ea;
  /* 一开始就是黑场，红纸底由 .home-red 随下拉进度显影 */
  background: #050404;
}

#screen-home::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  background:
    radial-gradient(72% 55% at 47% 38%, transparent 28%, rgba(21,0,3,.48) 72%, rgba(12,0,2,.80) 100%),
    linear-gradient(110deg, rgba(255,132,102,.08), transparent 44%),
    linear-gradient(90deg, rgba(38,2,7,.38), transparent 20% 80%, rgba(38,2,7,.42));
  pointer-events: none;
}

.poster-grain {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.018) 0 1px, transparent 1px 6px),
    radial-gradient(circle at 22% 8%, rgba(255,221,187,.12), transparent 28%);
  mix-blend-mode: screen;
  opacity: .58;
  pointer-events: none;
}

/* 遮罩与顶光全部作废：首页不再压暗，光就是照片自带的光 */
.home-darkness { display: none; }

.home-atmosphere {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 19;
  width: 100%;
  height: 100%;
  mix-blend-mode: screen;
  opacity: .92;
  pointer-events: none;
}

.home-vignette {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 20;
  pointer-events: none;
  background:
    radial-gradient(58% 44% at calc(40% + 22% * var(--slide)) 31%,
      rgba(255,199,138,.17), transparent 52%),
    radial-gradient(120% 88% at calc(42% + 18% * var(--slide)) 35%,
      transparent 30%, rgba(44,3,8,.38) 63%, rgba(20,0,3,.86) 100%);
}

.lamp {
  display: none;
}

.lamp-wire,
.lamp-bulb {
  display: block;
  border-radius: 999px;
}

.lamp-wire {
  width: 1px;
  height: 33px;
  margin: 0 auto;
  background: linear-gradient(rgba(255,235,214,.62), rgba(255,235,214,.13));
}

.lamp-bulb {
  width: 10px;
  height: 10px;
  margin: 0 auto;
  background: #fff2cf;
  box-shadow: 0 0 18px 5px rgba(255,219,157,.76), 0 0 52px 22px rgba(255,173,111,.22);
  animation: breathe 3.2s ease-in-out infinite;
}

.light-cone {
  position: absolute;
  z-index: 18;
  top: -10%;
  left: -17%;
  width: 88%;
  height: 78%;
  transform-origin: 0 0;
  transform: translateX(calc(var(--slide) * 8%)) rotate(28deg);
  background:
    radial-gradient(30% 9% at 6% 6%, rgba(255,250,225,.78), rgba(255,205,139,.22) 54%, transparent 86%),
    linear-gradient(90deg, rgba(255,248,224,.30), rgba(255,220,168,.14) 44%, transparent 92%);
  clip-path: polygon(6% 0, 11% 0, 100% 100%, 0 100%);
  filter: blur(7px);
  mix-blend-mode: screen;
  pointer-events: none;
  transition: transform .34s cubic-bezier(.12,.82,.18,1);
  opacity: .96;
}

.light-cone::after {
  content: "";
  position: absolute;
  left: 2%;
  top: 1%;
  width: 48%;
  height: 34%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,248,220,.34), transparent 68%);
  filter: blur(24px);
}

/* ---------- 首页拉绳（SVG）：一开始画面上只有绳子和「向下拉动」 ---------- */
.home-pull {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 26;
  pointer-events: none;          /* 只有绳子附近可拖，见 .home-pull-hit */
  /* 拉动时红绳整串让位给结婚照，透明度跟着 JS 写的 --pull-fade 走 */
  opacity: var(--pull-fade, 1);
  will-change: opacity;
}

.home-rope {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* ---------- 红绳挂饰：绳结 → 喜字木牌 → 鎏金球 → 流苏 ---------- */
.home-ornament {
  --orn-w: 86px;
  position: absolute;
  left: 50%;
  top: 0;
  width: var(--orn-w);
  height: calc(var(--orn-w) * 224 / 120);
  margin-left: calc(var(--orn-w) / -2);
  transform-origin: 50% 4%;
  will-change: transform;
  pointer-events: none;
}

.home-ornament svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  filter: drop-shadow(0 5px 10px rgba(24,0,4,.38));
}

/* 整串挂饰挂在绳结下沿轻轻摆（CSS 动画，离开主线程，拖拽时也顺） */
.home-ornament .ornament-sway {
  /* 摆动支点＝绳尾金扣处，整串像吊坠一样荡 */
  transform-box: view-box;
  transform-origin: 60px 8px;
  animation: ornamentSway 4.8s cubic-bezier(.37, 0, .63, 1) infinite;
}

@keyframes ornamentSway {
  0%, 100% { transform: rotate(-1.6deg); }
  50% { transform: rotate(1.6deg); }
}

/* 金环外的一层极缓呼吸光晕：让金属「活」着，又不出现硬边白块 */
.home-ornament .ornament-halo {
  animation: ornamentHalo 5.6s ease-in-out infinite;
}

@keyframes ornamentHalo {
  0%, 100% { opacity: .76; }
  50% { opacity: 1; }
}

.ornament-xi,
.ornament-xi-edge {
  font-family: var(--serif);
  font-size: 96px;
  font-weight: 700;
}

.ornament-xi {
  fill: url(#xi-wood);
  /* 厚描边把宋体撑成实木牌的体量感 */
  stroke: #b1111a;
  stroke-width: 7;
  stroke-linejoin: round;
  paint-order: stroke;
}
.ornament-xi-edge {
  fill: none;
  stroke: url(#xi-wood-edge);
  stroke-width: 1.6;
  transform: translateY(2px);
}

/* 绳尾提示：箭头 + 文案，跟着挂饰一起走 */
.home-pull-cue {
  position: absolute;
  left: 50%;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  will-change: transform;
  pointer-events: none;
}

.home-pull-arrow {
  display: block;
  width: 30px;
  height: 34px;
  filter: drop-shadow(0 3px 10px rgba(0,0,0,.8));
  animation: pullArrowBob 1.55s cubic-bezier(.4, 0, .6, 1) infinite;
}

.home-pull-arrow svg { display: block; width: 100%; height: 100%; }

.home-pull-arrow path {
  fill: none;
  stroke: #ffd9a0;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@keyframes pullArrowBob {
  0%, 100% { transform: translateY(-4px); opacity: .5; }
  50% { transform: translateY(6px); opacity: 1; }
}

.home-pull-label {
  font-family: var(--serif);
  font-size: 17px;
  letter-spacing: .30em;
  text-indent: .30em;
  white-space: nowrap;
  color: rgba(250,238,220,.96);
  text-shadow: 0 2px 14px rgba(0,0,0,.95);
  animation: dialNoteBreathe 2.6s ease-in-out infinite;
}

/* 红绳下方那一行：把动作说全 */
.home-pull-sub {
  margin-top: -2px;
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .18em;
  text-indent: .18em;
  white-space: nowrap;
  color: rgba(255,232,198,.62);
  text-shadow: 0 2px 12px rgba(0,0,0,.92);
  animation: dialNoteBreathe 2.6s ease-in-out infinite;
}

/* 绳结与挂饰周围的可拖区域（够大，好抓） */
.home-pull-hit {
  position: absolute;
  left: 50%;
  top: 0;
  width: 210px;
  height: 300px;
  margin-left: -105px;
  border-radius: 44%;
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  will-change: transform;
}

.home-pull-hit:active { cursor: grabbing; }

#screen-home.is-cert-dropped .home-pull { opacity: 0; pointer-events: none; }

/* 拉下来之前：只有红绳和「向下拉动」，别的一律不出现 */
.vertical-title,
.home-fan-wrap,
.home-meta,
.dial-tip {
  transition: opacity .46s cubic-bezier(.23, 1, .32, 1), transform .62s cubic-bezier(.23, 1, .32, 1);
}

#screen-home:not(.is-cert-dropped) .vertical-title,
#screen-home:not(.is-cert-dropped) .home-fan-wrap,
#screen-home:not(.is-cert-dropped) .home-meta,
#screen-home:not(.is-cert-dropped) .home-hold,
#screen-home:not(.is-cert-dropped) .dial-tip { opacity: 0; pointer-events: none; }

.home-hold { transition: opacity .46s cubic-bezier(.23, 1, .32, 1); }

#screen-home:not(.is-cert-dropped) .vertical-title { transform: translateY(30px); }
#screen-home:not(.is-cert-dropped) .home-fan-wrap { transform: translateY(24px) scale(.94); transform-origin: 100% 100%; }
#screen-home:not(.is-cert-dropped) .home-meta { transform: translateY(14px); }

/* 落定后依次浮现：标题 → 操作提示 → 圆钮 → 角标，60–80ms 级差 */
#screen-home.is-cert-dropped .vertical-title { transition-delay: .05s; }
#screen-home.is-cert-dropped .home-fan-wrap { transition-delay: .23s; }
#screen-home.is-cert-dropped .home-meta { transition-delay: .37s; }
#screen-home.is-cert-dropped .home-hold { transition-delay: .44s; }

/* ---------- 首页：黑场 → 暗红辉光 → 红纸底（随下拉进度显影） ---------- */
/* 辉光先起，红纸后到；两级都是 opacity 渐变，只走合成层 */
.home-ember {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(74% 54% at 50% 44%, rgba(158,16,26,.94), rgba(84,7,15,.62) 46%, rgba(20,2,6,0) 78%),
    linear-gradient(180deg, rgba(52,5,11,.5), rgba(12,1,4,0) 64%);
  opacity: var(--bg-ember, 0);
  will-change: opacity;
}

.home-red {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  pointer-events: none;
  background: url("./assets/home-red-bg.webp") center / cover no-repeat;
  opacity: var(--bg-red, 0);
  will-change: opacity;
}

/* 滑到小帅那一侧：整幅底子从红渐变成黑 */
.home-ink {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
  background: radial-gradient(130% 96% at 50% 26%, #0C0E14 0%, #05060A 58%, #000000 100%);
  /* 注意别用 --ink：那是全局文字色 token */
  opacity: var(--ink-on, 0);
  transition: opacity .66s cubic-bezier(.16, 1, .3, 1);
  will-change: opacity;
}

/* 顶光与压暗层已整体删除：照片原本的光就够，再加一层人工灯只剩糊成一片黑 */

.certificate-scene {
  position: absolute;
  z-index: 10;
  left: 0;
  right: 0;
  /* 让开顶部摄像头区域：证件整体落在它下面 */
  top: 92px;
  height: 466px;
  max-height: 448px;
  display: grid;
  place-items: center;
  /* 透视拉远：只留一点点空间感，避免近大远小把证件照拧成梯形（之前 900px 太近，畸变明显） */
  perspective: 2600px;
  pointer-events: none;
}

.certificate-stage {
  position: relative;
  /* aspect-ratio 是 Chrome 88+；基线直接用高度倒推宽度，比例一致 */
  width: calc(466px * 1000 / 1440);
  max-width: calc(448px * 1000 / 1440);
  height: 466px;
  max-height: 448px;
  transform-style: preserve-3d;
  /* 放大时主要往下长，避免顶进摄像头区域 */
  transform-origin: 50% 18%;
  /* 跟手变量：--cert-y 控制上下（%），--cert-rot 控制微旋转（deg） */
  --cert-y: -92;
  --cert-rot: -8;
  --cert-scale: 1;
  /* 滑动时证件整体轻微侧身＋靠近镜头。这里全部走 2D（位移/缩放/微旋转），
     不再用 rotateX/rotateY 做大幅 3D 翻转 —— 那会把原本正常的证件照拉成梯形。 */
  transform:
    translate3d(calc((0.5 - var(--slide, .5)) * 26px), calc(var(--push, 0) * -16px + var(--cert-y) * 1%), 0)
    rotateZ(calc(-.6deg + var(--cert-rot) * .35deg + (var(--slide, .5) - .5) * 2.6deg))
    scale(calc((1.04 + var(--push, 0) * .05) * var(--cert-scale)));
  /* 先快后慢的落位曲线：拖动时被 .is-hand-follow 关掉，松手才走这条 */
  transition: transform .68s cubic-bezier(.16, 1, .3, 1);
  will-change: transform;
}

/* 浮动层：承接「微微上下晃」与「选人时拉近放大」，不参与上面那套跟手位移 */
.certificate-float {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  transform-origin: 50% 42%;
  will-change: transform;
}

/* 三块底板严格重叠：尺寸、位置、角度完全一致，只靠透明度换人。
   不再往照片上盖人工补光——光是从原图里来的，硬加一层就会打架。 */
.certificate-plate {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* 换人也是先快后慢地化开，不在刻度间硬切 */
  transition: opacity .52s cubic-bezier(.16, 1, .3, 1);
  will-change: opacity;
}

.certificate-plate.is-full {
  filter: saturate(1.02) contrast(1.07) brightness(.98) drop-shadow(0 28px 50px rgba(27,0,3,.68));
}

/* 滑到小美一侧：只留小美那张底板盖住合影；滑到小帅一侧反过来 */
.certificate-plate.is-mei { opacity: var(--left-on, 0); }
.certificate-plate.is-shuai { opacity: var(--right-on, 0); }

/* 手指还在屏幕上时关掉换人缓动，跟手；松手再交给上面的曲线 */
.certificate-stage.is-hand-follow .certificate-plate { transition: none; }

/* 入局前推进镜头时用：照片轻微糊掉，才像被"吸"进画面里 */
.certificate-float.is-diving .certificate-plate { filter: blur(1px); }

/* 照片位置的指示：一条贴边的发光竖条 + 一枚小箭头，不用文字标签 */
.photo-mark {
  position: absolute;
  /* 证件照在 1000×1440 画布里的实测范围：x 52.6%–83.1%，y 25.6%–40% */
  top: 26.6%;
  width: 2px;
  height: 12.4%;
  border-radius: 2px;
  background: linear-gradient(180deg,
    rgba(255,232,186,0) 0%,
    rgba(255,226,168,.85) 26%,
    rgba(255,226,168,.85) 74%,
    rgba(255,232,186,0) 100%);
  box-shadow: 0 0 10px rgba(255,196,110,.55);
  transform-origin: 50% 0;
  transition: opacity .52s cubic-bezier(.16,1,.3,1), transform .52s cubic-bezier(.16,1,.3,1);
}

.photo-mark::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -12px;
  width: 0;
  height: 0;
  margin-left: -4px;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid rgba(255,228,170,.92);
  filter: drop-shadow(0 0 6px rgba(255,196,110,.6));
}

.photo-mark.is-mei { left: 52.6%; --side-on: var(--left-on, 0); }
.photo-mark.is-shuai { right: 17.2%; --side-on: var(--right-on, 0); }

/* 没选之前两侧都隐约在；选中的那侧亮起并稍微拉长 */
.photo-mark {
  opacity: calc(.26 + .74 * var(--side-on, 0));
  transform: scaleY(calc(.86 + .14 * var(--side-on, 0)));
}

.certificate-shadow {
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: 0;
  height: 44px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(18,0,2,.74), transparent);
  filter: blur(14px);
  transform: translateY(calc(var(--push) * 9px)) scaleX(calc(1 - var(--push) * .07));
  transition: transform .18s ease-out;
}

/* 「小美 / 小帅」文字标签已删除，改由证件照上的 .photo-mark 箭头与发光边条承担 */

/* 圆钮下方：两行说明（滑选 / 长按入局），左侧一枚弧线 logo。
   弧线跟滑盘同一条曲率（半径比例一致），光点在弧上左右往复；
   图标与两行文字的闪烁用同一组 keyframes、同一时长，整体一起亮暗。 */
.home-hint {
  position: absolute;
  top: 100%;
  /* 右缘与圆钮右缘对齐（圆钮在扇盘内 right:12px，扇盘又往外探 6px） */
  right: 6px;
  z-index: 24;
  margin: 12px 0 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  pointer-events: none;
  will-change: opacity;
}

.home-hint-icon {
  display: block;
  flex: none;
  width: 36px;
  height: 36px;
  animation: homeHintBlink 2.1s ease-in-out infinite;
}

.home-hint-icon svg { display: block; width: 100%; height: 100%; overflow: visible; }

.home-hint-arc {
  fill: none;
  stroke: rgba(255,229,175,.8);
  stroke-width: 1.7;
  stroke-linecap: round;
}

.home-hint-dot {
  fill: #ffe7b4;
  filter: drop-shadow(0 0 7px rgba(255,205,128,.95));
  animation: homeHintDot 2.1s cubic-bezier(.45, 0, .55, 1) infinite alternate;
}

.home-hint-lines {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  font-family: var(--sans);
  font-weight: 500;
  letter-spacing: .06em;
  color: rgba(255,244,228,.88);
  text-shadow: 0 2px 12px rgba(0,0,0,.9);
}

.home-hint-text {
  display: block;
  font-size: 13.5px;
  line-height: 1.25;
  white-space: nowrap;
  animation: homeHintBlink 2.1s ease-in-out infinite;
}

.home-hint-text.is-second {
  font-size: 12px;
  color: rgba(255,232,198,.78);
}

/* 光点沿弧线从左端走到右端（三点成弧，不走直线弦） */
@keyframes homeHintDot {
  0% { transform: translate(0, 0); }
  50% { transform: translate(8.6px, -14.6px); }
  100% { transform: translate(23.9px, -22.2px); }
}

/* 图标与文字共用这一组：相位一致 → 联动闪烁 */
@keyframes homeHintBlink {
  0%, 100% { opacity: .32; }
  42% { opacity: 1; }
  70% { opacity: .68; }
}

.vertical-title em {
  font-style: normal;
  transition: text-shadow .36s ease;
}

.vertical-title.is-woman em {
  color: #ffd4cf;
  text-shadow: 0 0 24px rgba(255,103,104,.54), 0 3px 14px rgba(19,0,2,.86);
}

.vertical-title.is-man em {
  color: #8ee6ff;
  text-shadow: 0 0 26px rgba(91,195,255,.72), 0 3px 14px rgba(4,18,28,.86);
}

.home-sub {
  display: none;
}

.home-meta {
  position: absolute;
  z-index: 24;
  left: 28px;
  right: 220px;
  bottom: 46px;
  display: grid;
  grid-gap: 4px;
  gap: 4px;
  font: 500 9px/1.4 var(--sans);
  letter-spacing: .16em;
  color: rgba(255,244,232,.44);
}

.hold-toast {
  position: absolute;
  z-index: 28;
  top: 74px;
  right: 16px;
  left: auto;
  bottom: auto;
  width: auto;
  max-width: 250px;
  margin: 0;
  padding: 6px 9px;
  border: 1px solid rgba(255,235,203,.14);
  border-radius: 999px;
  background: rgba(11,0,3,.42);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  font-family: var(--serif);
  font-size: 9.5px;
  line-height: 1.25;
  white-space: nowrap;
  color: rgba(255,235,212,.72);
}

.hold-toast:empty { display: none; }

.hold-toast b {
  color: #ffd793;
  font-weight: 700;
}

/* ---------- 扇形选人控制器 ---------- */
.dial-wrap {
  --control-center: 120px;
  --control-radius: 85px;
  --button-size: 82px;
  --ring-size: 96px;
  --ring-inset: calc((var(--button-size) - var(--ring-size)) / 2);
  position: absolute;
  right: 12px;
  bottom: 44px;
  z-index: 30;
  width: 240px;
  height: 168px;
}

.dial-tip {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--serif);
  font-size: 10px;
  letter-spacing: .1em;
  color: rgba(255,238,216,.58);
  white-space: nowrap;
}

.dial-track {
  position: absolute;
  left: calc(var(--control-center) - var(--control-radius));
  top: calc(var(--control-center) - var(--control-radius));
  width: calc(var(--control-radius) * 2);
  height: calc(var(--control-radius) * 2);
  box-sizing: border-box;
  border: 1px solid rgba(255,234,199,.24);
  border-radius: 50%;
  clip-path: inset(-2px -2px 50% -2px);
  background:
    radial-gradient(calc(var(--control-radius) - 2px) calc(var(--control-radius) - 2px) at 50% 100%,
      transparent 72%, rgba(255,224,178,.06) 78%, rgba(255,224,178,.20) 89%, rgba(255,224,178,.03) 97%, transparent 100%),
    conic-gradient(from 270deg,
      rgba(255,224,178,.02), rgba(255,224,178,.10) 25%, rgba(255,224,178,.02) 50%,
      rgba(255,224,178,.10) 75%, rgba(255,224,178,.02));
  cursor: grab;
  touch-action: none;
}

.dial-track:active { cursor: grabbing; }

.dial-knob {
  position: absolute;
  z-index: 2;
  width: 27px;
  height: 27px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle at 34% 30%, #fffdf4, #ffb763 48%, #7b341a);
  box-shadow: 0 0 18px rgba(255,188,114,.62), 0 3px 10px rgba(28,0,5,.46);
  pointer-events: none;
  transition: left .34s cubic-bezier(.22,1.12,.36,1), top .34s cubic-bezier(.22,1.12,.36,1);
}

/* 按钮、充能环与扇形轨道共用同一个几何圆心。 */
.dial-center-stack {
  position: absolute;
  left: var(--control-center);
  top: var(--control-center);
  width: var(--button-size);
  height: var(--button-size);
  transform: translate(-50%, -50%);
}

.dial-center {
  position: relative;
  width: var(--button-size);
  height: var(--button-size);
  border: 0;
  border-radius: 50%;
  color: #ffedd2;
  font-family: var(--serif);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .1em;
  line-height: 1.25;
  background:
    radial-gradient(circle at 50% 18%, #71161f, #39070e 56%, #180206 100%);
  box-shadow:
    0 0 24px rgba(255,188,124,.16),
    0 10px 26px rgba(26,0,5,.46),
    inset 0 0 0 3px rgba(255,225,184,.10),
    inset 0 0 18px rgba(0,0,0,.42);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}

.dial-center:disabled { opacity: .5; cursor: not-allowed; }

#screen-home .charge-ring {
  position: absolute;
  left: var(--ring-inset);
  top: var(--ring-inset);
  width: var(--ring-size);
  height: var(--ring-size);
  transform: rotate(-90deg);
  pointer-events: none;
}

.charge-ring {
  position: absolute;
  width: 96px;
  height: 96px;
  transform: rotate(-90deg);
  pointer-events: none;
}

.charge-ring circle {
  fill: none;
  stroke-width: 3;
}

.charge-bg { stroke: rgba(255,244,225,.18); }
.charge-fill {
  stroke: #ffd08c;
  stroke-dasharray: 264;
  stroke-dashoffset: 264;
}

/* ---------- 首页复用游戏内四分之一圆控件 ---------- */
.home-fan-wrap {
  position: absolute;
  right: 26px;
  /* 抬高一档，给圆钮下方的两行说明留位置 */
  bottom: 96px;
  z-index: 32;
  width: 190px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

/* 首页滑盘：沿用游戏内那套四分之一圆弧（圆钮沿弧线选人），
   但去掉圆盘底、虚线点阵与胶囊刻度，只留弧线、两个名字和一个圆钮 */
.home-fan-wrap .home-fan {
  position: relative;
  display: block;
  width: 164px;
  height: 156px;
  margin: 0 -6px -8px 0;
  padding: 0;
  touch-action: none;
}

/* 弧线：一条干净的实线，不再是虚线点阵 */
.home-fan .fan-arc-path {
  stroke: rgba(255,226,184,.30);
  stroke-width: 1.2;
  stroke-dasharray: none;
}

/* 两颗角色名就是文字本身，没有圆底、没有胶囊 */
.home-fan .fan-tick {
  width: auto;
  height: auto;
  margin: 0;
  padding: 6px 10px;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  font: 600 16px/1 var(--serif);
  letter-spacing: .14em;
  text-indent: .14em;
  color: rgba(255,238,216,.40);
  transform: translate(-50%, -50%);
  transition: color .46s cubic-bezier(.16,1,.3,1), text-shadow .46s ease;
}

.home-fan .fan-tick.is-active {
  border: 0;
  background: none;
  box-shadow: none;
  color: #fff3d8;
  text-shadow: 0 0 18px rgba(255,214,150,.42);
  transform: translate(-50%, -50%);
}

/* 拖动时圆钮 1:1 跟手，松手才走曲线回到刻度 */
.home-fan.is-dragging .arc-thumb,
.home-fan.is-selecting .arc-thumb {
  transition: none;
}

/* 长按入局：不再往圆钮上叠圆环，改成「整屏压暗收边 + 屏幕底边一条进度线」 */
.home-hold-veil {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 30;
  pointer-events: none;
  opacity: var(--hold, 0);
  background: radial-gradient(122% 82% at 50% 52%,
    rgba(5,2,3,0) 30%,
    rgba(5,2,3,.74) 72%,
    rgba(5,2,3,.98) 100%);
  will-change: opacity;
}

.home-hold {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 34;
  height: 26px;
  pointer-events: none;
}

.home-hold-fill {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  transform: scaleX(var(--charge, 0));
  transform-origin: 0 50%;
  background: linear-gradient(90deg, rgba(255,231,174,.25), #FFE7AE 42%, #D9A441);
  box-shadow: 0 0 12px rgba(240,179,82,.55);
}

/* ---------- 入局转场：红印从圆钮处荡开，整幅画面被吞进证件的红底 ---------- */
.entry-veil {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 120;
  visibility: hidden;
  pointer-events: none;
}

.entry-veil.is-active { visibility: visible; }

.entry-ink,
.entry-ring {
  position: absolute;
  left: var(--entry-x, 82%);
  top: var(--entry-y, 88%);
  pointer-events: none;
}

.entry-ink {
  width: 1864px;
  height: 1864px;
  margin: -932px 0 0 -932px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 47% 45%, #b62b3c 0 6%, #87182b 30%, #450b16 66%, #170309 100%);
  box-shadow: inset 0 0 140px 34px rgba(255,196,120,.12);
  opacity: 0;
  transform: scale(.02) rotate(-12deg);
}

.entry-ring {
  width: 420px;
  height: 420px;
  margin: -210px 0 0 -210px;
  border-radius: 50%;
  border: 2px solid rgba(255,224,170,.72);
  box-shadow:
    0 0 48px rgba(255,196,110,.48),
    inset 0 0 48px rgba(255,196,110,.28);
  opacity: 0;
  transform: scale(.3);
}

/* 红印荡满之后，在钮口盖一枚「入」 */
.entry-seal {
  position: absolute;
  left: var(--entry-x, 82%);
  top: var(--entry-y, 88%);
  transform: translate(-50%, -50%);
  font-family: var(--hand);
  font-size: 64px;
  line-height: 1;
  color: rgba(255,230,180,.92);
  text-shadow:
    0 0 26px rgba(255,196,110,.7),
    0 0 70px rgba(0,0,0,.55);
  opacity: 0;
  pointer-events: none;
}

/* 训练节奏：红绳落定后才提示左右滑动选人 */
#screen-home:not(.is-cert-dropped) .dial-tip { opacity: 0; }

.dial-tip { transition: opacity .5s ease; }

/* ---------- 结婚照出场：跟手下落，滑到哪露到哪 ---------- */
.certificate-scene {
  opacity: calc(var(--cert-drop, 0) * 1.8);
  transition: opacity .12s linear;
}

/* 落定后完全显影；未落定时由 --cert-drop 控制渐显 */
#screen-home.is-cert-dropped .certificate-scene { opacity: 1; }

/* 手指拖动期间交给 JS 直接驱动 transform，关掉 CSS 缓动以跟手 */
.certificate-stage.is-hand-follow { transition: none; }

/* 旧的手绘台灯与光锥不再参与首页，避免和新的打光打架 */
#screen-home .lamp,
#screen-home .light-cone { display: none; }

@media (max-height: 0px) {
  .vertical-title { bottom: 150px; height: auto; font-size: 29px; }
  .certificate-scene { top: 84px; height: 372.8px; }
  .certificate-stage { height: 372.8px; }
  .home-sub { bottom: 100px; }
  .hold-toast { display: none; }
  .home-meta { bottom: 24px; }
  .dial-wrap { bottom: 30px; transform: scale(.9); transform-origin: 100% 100%; }
}

/* ---------- 入场书法与素材占位 ---------- */
.cinema {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  background: #000 url("./assets/paper-dark.webp") center / cover no-repeat;
  opacity: 0;
  pointer-events: none;
  transition: opacity .5s ease;
}

.cinema.is-active { opacity: 1; pointer-events: auto; }

.cinema-look {
  width: 78%;
  max-width: 300px;
  height: calc(335.4px * 14 / 9);
  max-height: calc(300px * 14 / 9);
  border: 1px dashed rgba(255, 226, 166, .28);
  border-radius: 16px;
  display: grid;
  align-content: center;
  justify-items: center;
  grid-gap: 8px;
  gap: 8px;
  color: rgba(255, 230, 190, .55);
  font: 500 10px/1.4 var(--sans);
  text-align: center;
  opacity: .25;
  transition: opacity .7s ease, transform 1s ease;
}

.cinema.is-look .cinema-look {
  opacity: 1;
  transform: scale(1.08);
}

.cinema.is-flicker .cinema-look { animation: flicker .32s steps(2) 2; }

.letterbox {
  position: absolute;
  left: 0; right: 0; height: 0;
  background: #000;
  z-index: 70;
  transition: height .7s cubic-bezier(.16, 1, .3, 1);
}

.letterbox.top { top: 0; }
.letterbox.bottom { bottom: 0; }

.cinema.is-cinematic .letterbox { height: 76px; }

.verse {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 80;
  display: grid;
  place-content: center;
  justify-items: center;
  padding: 32px 20px;
  text-align: center;
  background: #000;
  opacity: 0;
  pointer-events: none;
  transition: opacity .6s ease;
}

.verse.is-active { opacity: 1; pointer-events: auto; }

/* ---------- 进入游戏前的提醒页 ---------- */
.reminder {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 78;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  padding: 34px 20px 22px;
  background: #050505;
  opacity: 0;
  pointer-events: none;
  transition: opacity .5s ease;
}

.reminder.is-active {
  opacity: 1;
  pointer-events: auto;
}

/* 胶片闪光 */
.reminder-flash {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 3;
  background: #fff;
  opacity: 0;
  pointer-events: none;
}

/* 胶片噪点 */
.reminder-grain {
  position: absolute;
  top: -6%;
  right: -6%;
  bottom: -6%;
  left: -6%;
  z-index: 2;
  pointer-events: none;
  opacity: .26;
  mix-blend-mode: overlay;
  background-image: 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='.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

.reminder-body {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .92fr);
  align-items: center;
  grid-gap: 14px;
  gap: 14px;
  min-height: 0;
}

.reminder-tag {
  margin: 0 0 12px;
  font-family: var(--serif);
  font-size: 15px;
  letter-spacing: .3em;
  color: rgba(240,179,82,.9);
}

.reminder-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-gap: 14px;
  gap: 14px;
  counter-reset: reminder;
}

.reminder-list li {
  position: relative;
  padding-left: 22px;
  font-family: var(--serif);
  font-size: 13.5px;
  line-height: 1.78;
  color: rgba(243,235,222,.9);
  text-shadow: 0 1px 8px rgba(0,0,0,.9);
}

.reminder-list li::before {
  counter-increment: reminder;
  content: counter(reminder);
  position: absolute;
  left: 0;
  top: 3px;
  width: 15px;
  height: 15px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(240,179,82,.5);
  border-radius: 50%;
  font: 700 9px/1 var(--sans);
  color: rgba(240,179,82,.95);
}

/* 右侧配图：下半部分渐黑，与背景融合 */
.reminder-art {
  position: relative;
  margin: 0;
  min-width: 0;
  max-height: 100%;
  display: grid;
  place-items: center;
}

.reminder-art img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 577.84px;
  object-fit: contain;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 52%, rgba(0,0,0,.45) 74%, transparent 96%);
  mask-image: linear-gradient(180deg, #000 0%, #000 52%, rgba(0,0,0,.45) 74%, transparent 96%);
}

.reminder-foot {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: end;
  grid-gap: 8px;
  gap: 8px;
  padding-bottom: 4px;
}

.reminder-hint {
  margin: 0;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .1em;
  color: rgba(245,232,212,.6);
  animation: dialNoteBreathe 2.6s ease-in-out infinite;
}

.reminder-confirm {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 24px 12px 26px;
  border: 1px solid rgba(255,222,165,.42);
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(38,26,12,.9), rgba(12,9,6,.94));
  color: #ffe9be;
  font-family: var(--serif);
  font-size: 14px;
  letter-spacing: .18em;
  text-indent: .18em;
  cursor: pointer;
  box-shadow: 0 10px 28px rgba(0,0,0,.62), inset 0 1px 0 rgba(255,240,212,.1);
  transition: transform .3s cubic-bezier(.16,1,.3,1), border-color .3s ease;
}

.reminder-confirm:active { transform: scale(.95); }
.reminder-confirm i { font-style: normal; font-size: 16px; }

/* 入局箴言：两行书法，居中缓慢写出 */
.verse-line {
  display: block;
  white-space: nowrap;
}

.verse-title .verse-char {
  display: inline-block;
  will-change: transform, opacity, filter;
}

.verse-title {
  display: grid;
  justify-items: center;
  grid-gap: .18em;
  gap: .18em;
  max-width: 100%;
  padding: 0 16px;
  font-family: var(--hand);
  /* 每行 16 字，字号必须能在一屏宽里放得下 */
  font-size: 21.07px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: .02em;
  color: #f6e3bd;
  text-shadow:
    0 0 42px rgba(240,179,82,.30),
    0 6px 26px rgba(0,0,0,.9);
}

.verse-title .verse-char {
  display: inline-block;
  will-change: transform, opacity, filter;
}

.verse-choices {
  display: flex;
  gap: 14px;
}

.verse-choice {
  padding: 11px 26px;
  border: 1px solid rgba(240,179,82,.42);
  border-radius: 999px;
  background: rgba(0,0,0,.4);
  color: rgba(247,211,143,.86);
  font-family: var(--serif);
  font-size: 14px;
  letter-spacing: .22em;
  text-indent: .22em;
  cursor: pointer;
  transition: border-color .3s ease, color .3s ease, background .3s ease, transform .3s ease;
}

.verse-choice:hover,
.verse-choice:active {
  border-color: rgba(240,179,82,.8);
  color: #ffe9bd;
  transform: translateY(-1px);
}

.verse-choice.is-primary {
  border-color: rgba(240,179,82,.7);
  background: linear-gradient(180deg, rgba(255,214,150,.18), rgba(255,178,92,.08));
  color: #fff0d4;
}

/* ---------- 剧情页 ---------- */
#screen-story, #screen-ending {
  background: linear-gradient(180deg, rgba(10,10,11,.55), rgba(8,8,9,.78));
}

#screen-story {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  grid-gap: 6px;
  gap: 6px;
  padding: 12px 15px 10px;
  background: linear-gradient(180deg, rgba(10,10,11,.5), rgba(8,8,9,.76));
}

.story-flip {
  position: relative;
  z-index: 1;
  min-height: 0;
  perspective: 2400px;
  transform-style: preserve-3d;
  transition: transform .72s cubic-bezier(.22,1,.36,1);
  will-change: transform;
}

.story-flip.is-flipped { transform: rotateY(180deg); }

.flip-face {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.flip-front {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  grid-gap: 0;
  gap: 0;
  opacity: 1;
  transition: opacity .3s ease .18s;
}

.flip-back {
  border-radius: 4px;
  background:
    linear-gradient(180deg, rgba(12,12,13,.95), rgba(8,8,9,.97)),
    url("./assets/paper-dark.webp") center / 260% auto no-repeat;
  transform: rotateY(180deg);
  opacity: 0;
  transition: opacity .3s ease;
}

.story-flip.is-flipped .flip-front { opacity: 0; pointer-events: none; transition-delay: 0s; }
.story-flip.is-flipped .flip-back { opacity: 1; transition-delay: .2s; }

#screen-story .preview-flag { display: none; }

/* ---------- 剧情主界面：顶栏 / 照片堆叠 / 扇形操作 ---------- */
.game-chrome {
  position: relative;
  z-index: 60;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  grid-gap: 8px;
  gap: 8px;
  padding: 0 2px;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-6px);
  transition: opacity .42s ease, transform .42s cubic-bezier(.16,1,.3,1);
}

.game-chrome.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.chrome-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.chrome-slot.is-right { align-items: center; }

.chrome-caption {
  max-width: 100%;
  padding: 3px 8px;
  border: 1px solid rgba(255,232,188,.14);
  border-radius: 999px;
  background: rgba(0,0,0,.32);
  font: 500 9px/1.2 var(--sans);
  letter-spacing: .06em;
  color: rgba(255,236,198,.6);
  white-space: nowrap;
}

.chrome-btn {
  width: 42px;
  height: 42px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255,232,188,.22);
  border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, rgba(255,224,176,.12), rgba(8,4,6,.62) 62%);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  color: rgba(255,238,210,.74);
  cursor: pointer;
  transition: transform .24s ease, border-color .3s ease, color .3s ease, background .3s ease;
}

.chrome-btn svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

.chrome-btn:active { transform: scale(.93); }

.chrome-btn.is-glow {
  border-color: rgba(240,179,82,.62);
  animation: chromeGlow 3.4s ease-in-out infinite;
}

.chapter-meter {
  position: relative;
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 6px 7px;
  border-radius: 18px;
  background-color: #17161a;
  background-image: url("./assets/paper-dark.webp");
  background-size: 240% auto;
  background-position: 50% 44%;
  box-shadow:
    0 4px 12px rgba(0,0,0,.62),
    inset 0 1px 0 rgba(255,240,214,.09),
    inset 0 -1px 0 rgba(0,0,0,.66);
  perspective: 160px;
}

.chapter-halo {
  position: absolute;
  top: -8px;
  right: -8px;
  bottom: -8px;
  left: -8px;
  border-radius: 18px;
  background: radial-gradient(58% 58% at 50% 50%, rgba(0,0,0,.6), rgba(0,0,0,.18) 62%, transparent 76%);
  filter: blur(5px);
  pointer-events: none;
}

.chapter-cavity {
  position: absolute;
  top: 3px;
  right: 3px;
  bottom: 3px;
  left: 3px;
  border-radius: 14px;
  background: linear-gradient(180deg, #292521 0%, #201d1a 52%, #191614 100%);
  box-shadow:
    inset 0 3px 6px rgba(0,0,0,.88),
    inset 0 -2px 3px rgba(255,236,208,.05),
    inset 0 0 0 1px rgba(0,0,0,.55);
  pointer-events: none;
}

.chapter-grain {
  position: absolute;
  top: 3px;
  right: 3px;
  bottom: 3px;
  left: 3px;
  border-radius: 14px;
  opacity: .16;
  mix-blend-mode: overlay;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}

.digit-window {
  position: relative;
  z-index: 2;
  width: 22px;
  height: 27px;
  overflow: hidden;
  border-radius: 8px;
  background: transparent;
  box-shadow: none;
}

.digit-window { margin: 0; }

.digit-window::before,
.digit-window::after { display: none; }

.digit-strip {
  position: relative;
  z-index: 2;
  display: block;
  transform: translateY(0);
  transition: transform .64s cubic-bezier(.16,1.18,.28,1);
}

.digit-strip i {
  display: grid;
  place-items: center;
  width: 100%;
  height: 27px;
  font-family: var(--hand);
  font-style: normal;
  font-size: 21px;
  font-weight: 400;
  line-height: 1;
  color: var(--chapter-ink);
  text-shadow: 0 1px 0 rgba(0,0,0,.92), 0 0 10px rgba(217,169,79,.28);
  font-variant-numeric: tabular-nums;
}

/* 序章：不占数字，只显示「序章」，进线后才切到滚动的 1-1 表盘 */
.chapter-prologue {
  position: relative;
  z-index: 2;
  display: none;
  font-family: var(--hand);
  font-size: 19px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: .06em;
  color: var(--chapter-ink);
  text-shadow: 0 1px 0 rgba(0,0,0,.92), 0 0 10px rgba(217,169,79,.28);
  animation: chapterRoll .58s cubic-bezier(.16,1.18,.28,1);
}

.chapter-meter.is-prologue .chapter-prologue { display: inline; }
.chapter-meter.is-prologue .digit-window,
.chapter-meter.is-prologue .chapter-dash { display: none; }

/* 章节号：1-1 形态。大章节号与小节号各自独立滚动 */
.chapter-dash {
  position: relative;
  z-index: 2;
  margin: 0 -1px;
  font-family: var(--hand);
  font-size: 18px;
  font-weight: 400;
  color: var(--chapter-ink);
  opacity: .72;
  text-shadow: 0 1px 0 rgba(0,0,0,.9);
}

.digit-window.is-rolling {
  animation: chapterRoll .58s cubic-bezier(.16,1.18,.28,1);
}

.digit-window.is-minor.is-rolling {
  animation-duration: .5s;
}

.digit-window.is-major.is-rolling {
  animation-duration: .68s;
}

.chapter-label {
  font: 500 8px/1 var(--sans);
  letter-spacing: .26em;
  text-indent: .26em;
  color: rgba(255,238,210,.4);
}

/* 剧情照片堆叠：错开幅度很小，像一叠实体照片 */
.scene-photo {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  /* 底部留白把整张画面往上顶一点，字幕也就不再压到画面外 */
  padding: 0 0 52px;
}

.photo-stack {
  position: relative;
  width: 240px;
  height: 320px;
  transform: rotate(calc(-.6deg + var(--stack-tilt, 0deg)));
  transition: transform .5s cubic-bezier(.16,1,.3,1);
}

.photo-stack[data-depth="0"] .scene-sheet,
.photo-stack[data-depth="1"] .sheet-2,
.photo-stack[data-depth="1"] .sheet-3,
.photo-stack[data-depth="2"] .sheet-3 {
  opacity: 0;
  transform: scale(.97);
}

.scene-sheet {
  transition: opacity .45s ease, transform .5s cubic-bezier(.16,1,.3,1);
}

.scene-sheet {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  border-radius: 2px;
  background: linear-gradient(180deg, #5b5750 0%, #3a3733 28%, #201e1c 100%);
  box-shadow: 0 14px 26px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,246,232,.22);
}

.scene-sheet.sheet-1 { transform: translate(5px, -5px) rotate(calc(.8deg + var(--stack-tilt, 0deg))); }

.scene-sheet.sheet-2 {
  transform: translate(11px, -8px) rotate(calc(-1.2deg - var(--stack-tilt, 0deg)));
  filter: brightness(.94);
}

.scene-sheet.sheet-3 {
  transform: translate(14px, -14px) rotate(calc(1.9deg + var(--stack-tilt, 0deg)));
  filter: brightness(.88);
}

/* 剧情卡 = 深色全屏卡：一整块深色面，内里一道渐变的凹槽，
   槽里上方是照片，槽里下方就是剧情文字（同一块面，不是浮在照片上） */
.scene-print {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  overflow: hidden;
  border-radius: 24px;
  background:
    linear-gradient(180deg, #1b1917 0%, #141211 42%, #0d0c0b 78%, #090808 100%);
  box-shadow:
    0 26px 48px rgba(0,0,0,.72),
    0 3px 10px rgba(0,0,0,.55),
    inset 0 1px 0 rgba(255,244,224,.10),
    inset 0 -1px 0 rgba(0,0,0,.6);
}

/* 渐变凹槽：内阴影把它压出一道下沉的面 */
.scene-print::before {
  content: "";
  position: absolute;
  top: 9px;
  right: 9px;
  bottom: 9px;
  left: 9px;
  border-radius: 17px;
  pointer-events: none;
  z-index: 1;
  background: linear-gradient(180deg, rgba(0,0,0,.42) 0%, rgba(0,0,0,.16) 38%, rgba(255,255,255,.018) 72%, rgba(0,0,0,.34) 100%);
  box-shadow:
    inset 0 4px 12px rgba(0,0,0,.92),
    inset 0 -2px 6px rgba(0,0,0,.72),
    inset 0 0 0 1px rgba(255,236,206,.045),
    0 1px 0 rgba(255,244,224,.05);
}

.scene-print .asset-slot {
  position: absolute;
  top: 18px;
  left: 18px;
  right: 18px;
  bottom: auto;
  height: 60%;
  border: 0;
  border-radius: 12px;
  overflow: hidden;
  background: none;
  display: grid;
  place-items: center;
  font-size: 10.5px;
  letter-spacing: .16em;
  color: rgba(255,236,206,.42);
  text-align: center;
  padding: 0 18px 158px;
  filter: sepia(.24) saturate(.88) contrast(1.04) brightness(.96);
}

.scene-print .asset-slot::before {
  top: 12px;
  right: 12px;
  bottom: 12px;
  left: 12px;
  border: 1px dashed rgba(255,226,184,.16);
  border-radius: 2px;
  background: none;
  animation: none;
}

.scene-print .asset-slot.has-image {
  padding: 0;
  border: 0;
  color: transparent;
  background-color: transparent;
  /* 槽内的凹陷 + 四周暗角都做在照片这一层 */
  box-shadow:
    inset 0 0 0 1px rgba(0,0,0,.38),
    inset 0 12px 20px -12px rgba(0,0,0,.8),
    inset 0 -12px 20px -12px rgba(0,0,0,.72);
  background-position: center;
  background-size: cover;
  filter: saturate(.92) contrast(1.025) brightness(.96);
}

.scene-print .asset-slot.has-image::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(118% 82% at 50% 44%, transparent 44%, rgba(0,0,0,.30) 78%, rgba(0,0,0,.62) 100%);
}

.scene-print .asset-slot.has-image::before { display: none; }

.print-leak {
  position: absolute;
  top: 18px;
  left: 18px;
  right: 18px;
  height: 60%;
  border-radius: 12px;
  z-index: 5;
  pointer-events: none;
  background:
    linear-gradient(133deg, rgba(255,214,158,.16) 0%, rgba(255,196,132,.04) 30%, transparent 52%),
    radial-gradient(120% 60% at 108% -6%, rgba(255,168,104,.16), transparent 60%);
  mix-blend-mode: screen;
}

.print-grain {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  border-radius: 24px;
  pointer-events: none;
  opacity: .22;
  mix-blend-mode: overlay;
  background-image: 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)'/%3E%3C/svg%3E");
}

.scene-print::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  border-radius: 2px;
  background:
    radial-gradient(118% 76% at 44% 34%, transparent 42%, rgba(0,0,0,.46) 100%),
    linear-gradient(180deg, rgba(255,236,206,.05), transparent 26%);
}

.print-meta {
  z-index: 6;
  position: absolute;
  right: 30px;
  top: 30px;
  max-width: 66%;
  text-align: right;
  font: 500 8.5px/1.3 var(--sans);
  letter-spacing: .1em;
  color: rgba(255,236,206,.62);
  text-shadow: 0 1px 5px rgba(0,0,0,.85);
}

/* 节点名称与剧情介绍：直接压在画面上，底部用一层渐变保证可读性 */
.print-caption {
  position: absolute;
  z-index: 4;
  left: 22px;
  right: 22px;
  top: calc(60% + 30px);
  bottom: 18px;
  overflow: hidden;
  padding: 4px 0 62px;
  background: none;
  pointer-events: none;
  transition: opacity .34s ease, transform .34s ease;
}

.print-caption-label {
  font-family: var(--sans);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .24em;
  color: rgba(240,179,82,.92);
  text-shadow: 0 1px 5px rgba(0,0,0,.85);
}

.print-caption-title {
  margin: 5px 0 6px;
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 800;
  line-height: 1.28;
  color: #fdf3e2;
  text-shadow: 0 2px 10px rgba(0,0,0,.92), 0 1px 2px rgba(0,0,0,.9);
}

/* 小美线镜头模式：整段剧情台词完整呈现，不做行数截断 */
.print-caption.is-beat { padding: 38px 17px 60px; }

.print-caption.is-beat .print-caption-label {
  font-size: 10px;
  letter-spacing: .18em;
}

.print-caption.is-beat .print-caption-scene {
  display: block;
  -webkit-line-clamp: none;
  overflow: visible;
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 1.76;
  color: rgba(247,239,226,.94);
  text-shadow: 0 1px 8px rgba(0,0,0,.95), 0 1px 2px rgba(0,0,0,.9);
}

/* 打字机逐字单元：保持 inline，换行/排版与整段文本一致 */
.beat-char { display: inline; }
.beat-char.beat-break { display: block; }

.print-caption-scene {
  font-family: var(--sans);
  font-size: 11.5px;
  line-height: 1.62;
  color: rgba(242,231,213,.82);
  text-shadow: 0 1px 7px rgba(0,0,0,.92);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.story-continue {
  position: absolute;
  z-index: 8;
  right: 22px;
  bottom: 20px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 13px 8px 16px;
  border: 1px solid rgba(255,222,165,.38);
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(26,18,10,.72), rgba(8,6,5,.78));
  -webkit-backdrop-filter: blur(9px);
  backdrop-filter: blur(9px);
  color: #ffe9be;
  font-family: var(--serif);
  font-size: 12px;
  letter-spacing: .14em;
  text-indent: .14em;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(0,0,0,.48), inset 0 1px 0 rgba(255,240,212,.08);
  transition: opacity .3s ease, transform .36s cubic-bezier(.16,1,.3,1), border-color .3s ease;
}

.story-continue i {
  font: 500 18px/1 var(--sans);
  font-style: normal;
  transform: translateY(-1px);
}

.story-continue:active { transform: scale(.96); }

/* 选项 + 扇形操作盘：覆盖在照片下方，剧情文字退场后才出现 */
.choice-zone {
  position: absolute;
  z-index: 30;
  left: 0;
  right: 0;
  bottom: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 164px;
  grid-template-rows: minmax(0, 1fr) auto;
  align-items: end;
  grid-gap: 2px 4px;
  gap: 2px 4px;
  min-height: 258px;
  padding: 116px 0 0;
  overflow: visible;
  background: linear-gradient(180deg,
    rgba(3,3,3,0) 0%,
    rgba(4,4,4,.28) 26%,
    rgba(4,4,4,.78) 66%,
    rgba(3,3,3,.94) 100%);
  opacity: 0;
  transform: translateY(14px);
  pointer-events: none;
  transition: opacity .42s ease, transform .46s cubic-bezier(.16,1,.3,1);
}

.flip-front.is-choice-ready .choice-zone {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.flip-front.is-choice-ready .print-caption {
  opacity: 0;
  transform: translateY(14px);
  pointer-events: none;
}

.flip-front.is-choice-ready .story-continue {
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
}

.choice-list {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  /* 选项整体抬高，别贴着屏幕底边 */
  padding-bottom: 66px;
  min-width: 0;
}

.arc-option {
  position: relative;
  animation: optionIn .44s cubic-bezier(.16,1,.3,1) both;
  padding: 6px 6px 6px 12px;
  border: 0;
  background: none;
  text-align: left;
  font-family: var(--serif);
  font-size: 13px;
  line-height: 1.4;
  color: rgba(255,236,206,.44);
  cursor: pointer;
  transition: color .28s ease, transform .32s cubic-bezier(.16,1,.3,1);
}

.option-letter {
  display: inline-grid;
  place-items: center;
  min-width: 16px;
  height: 16px;
  margin-right: 7px;
  border: 1px solid rgba(255,224,178,.28);
  border-radius: 4px;
  font: 600 9px/1 var(--sans);
  letter-spacing: .04em;
  color: rgba(255,224,178,.5);
  vertical-align: 1px;
  transition: color .28s ease, border-color .28s ease, background .28s ease, box-shadow .28s ease;
}

.arc-option.is-active .option-letter {
  border-color: rgba(255,206,142,.9);
  background: linear-gradient(180deg, rgba(255,214,150,.22), rgba(255,178,92,.10));
  color: #fff3e2;
  box-shadow: 0 0 12px rgba(240,179,82,.34);
}

.arc-option::before {
  content: "";
  position: absolute;
  left: 0;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: rgba(255,236,206,.18);
  transition: background .28s ease, box-shadow .28s ease;
}

.arc-option .option-underline {
  position: absolute;
  left: 8px;
  right: 4px;
  bottom: 0;
  height: 5px;
  transform: scaleX(0) rotate(-.5deg);
  transform-origin: left center;
  opacity: 0;
  border-radius: 999px;
  background:
    linear-gradient(90deg, rgba(240,179,82,0) 0%, rgba(255,206,142,.92) 12%, rgba(255,224,178,.98) 52%, rgba(240,179,82,.5) 88%, rgba(240,179,82,0) 100%);
  filter: blur(.2px);
  transition: transform .42s cubic-bezier(.16,1.05,.3,1), opacity .3s ease;
}

.arc-option.is-active {
  color: #fff3e2;
  transform: translateX(5px);
}

.arc-option.is-active::before {
  background: rgba(255,206,142,.72);
  box-shadow: 0 0 12px rgba(240,179,82,.5);
}

.arc-option.is-active .option-underline {
  transform: scaleX(1) rotate(-.5deg);
  opacity: 1;
}

/* 右下角四分之一圆操作区：确认钮嵌在最右下角，虚线弧向外展开 */
.fan {
  position: relative;
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: end;
  width: 164px;
  height: 156px;
  margin: 0 -6px -8px 0;
  flex: 0 0 auto;
  touch-action: none;
}

.fan-disc {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 152px;
  height: 152px;
  border-radius: 100% 0 0 0;
  background:
    radial-gradient(circle at 100% 100%, rgba(255,214,150,.10), rgba(255,206,142,.028) 40%, transparent 66%);
  box-shadow: inset 1px 1px 0 rgba(255,226,184,.10);
  pointer-events: none;
}

.fan-arc-svg {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.fan-arc-path {
  fill: none;
  stroke: rgba(255,216,148,.40);
  stroke-width: 1;
  stroke-dasharray: 2 6;
  stroke-linecap: round;
}

.fan-track-dots {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
}

.fan-track-dot {
  position: absolute;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: rgba(255,226,184,.34);
  transition: background .3s ease, box-shadow .3s ease, transform .3s cubic-bezier(.16,1,.3,1);
}

.fan-track-dot.is-active {
  background: #ffe9c2;
  box-shadow: 0 0 9px rgba(240,179,82,.8);
  transform: scale(1.35);
}

.fan-ticks {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.fan-tick {
  position: absolute;
  display: grid;
  place-items: center;
  width: 31px;
  height: 31px;
  margin: -15.5px 0 0 -15.5px;
  padding: 0;
  border: 1px solid rgba(255,226,184,.24);
  border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, rgba(40,34,28,.96), rgba(9,7,6,.94));
  color: rgba(255,226,184,.52);
  font: 600 11px/1 var(--sans);
  cursor: pointer;
  pointer-events: auto;
  transition: transform .38s cubic-bezier(.16,1,.3,1), background .3s ease, box-shadow .3s ease, color .3s ease, border-color .3s ease;
}

.fan-tick.is-active {
  border-color: rgba(255,214,150,.92);
  background: radial-gradient(circle at 36% 30%, #fff3dc, #d8a35c 78%);
  color: #2a1a06;
  box-shadow: 0 0 16px rgba(240,179,82,.58), 0 0 30px rgba(240,179,82,.24);
  transform: scale(1.14);
}

.arc-thumb {
  position: absolute;
  left: 0;
  top: 0;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #fff8ea, #d8a35c);
  box-shadow: 0 0 12px rgba(240,179,82,.72), 0 0 0 3px rgba(240,179,82,.14);
  transform: translate3d(var(--thumb-x, 0px), var(--thumb-y, 0px), 0) translate(-50%, -50%) scale(1);
  opacity: 0;
  pointer-events: none;
  cursor: grab;
  transition:
    transform .3s cubic-bezier(.22,1.12,.36,1),
    opacity .3s ease,
    box-shadow .25s ease;
}

.arc-thumb.is-visible { opacity: .95; pointer-events: auto; }

/* 拖动中：短一点、快一点的吸附，落在固定刻度上 */
.fan.is-dragging .arc-thumb {
  cursor: grabbing;
  transition: transform .13s cubic-bezier(.22,1.12,.36,1), opacity .2s ease;
  transform: translate3d(var(--thumb-x, 0px), var(--thumb-y, 0px), 0) translate(-50%, -50%) scale(1.22);
  box-shadow: 0 0 16px rgba(240,179,82,.9), 0 0 0 4px rgba(240,179,82,.18);
}

/* 确认钮：暗黄压印，中间微凹，黑体字 */
.arc-center {
  position: absolute;
  right: 12px;
  bottom: 10px;
  width: 76px;
  height: 76px;
  border: 0;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 46%,
      #c49429 0%, #c99a30 38%, #cd9d31 46%,
      #d6aa42 54%, #d2a53a 66%, #c9972b 84%, #bc8a22 100%);
  color: #2c1e04;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .18em;
  text-indent: .18em;
  text-shadow: 0 1px 0 rgba(255,238,190,.35);
  box-shadow:
    inset 0 5px 8px rgba(118,72,6,.5),
    inset 0 -4px 7px rgba(255,240,196,.42),
    inset 0 0 0 5px rgba(190,138,30,.34),
    inset 0 0 24px rgba(120,74,8,.42),
    0 9px 18px rgba(0,0,0,.6),
    0 0 0 1px rgba(0,0,0,.4);
  cursor: pointer;
  z-index: 5;
  user-select: none;
  -webkit-user-select: none;
  transform: translate(var(--arc-nudge-x, 0px), var(--arc-nudge-y, 0px));
  transition: transform .46s cubic-bezier(.16,1,.3,1), box-shadow .32s ease;
}

.arc-center:active,
.arc-center.is-pressed {
  transform: translate(var(--arc-nudge-x, 0px), var(--arc-nudge-y, 0px)) scale(.94);
}

/* 按住拖动时跟手（短过渡），松手后回到默认的长过渡 → 自动弹回原位 */
.arc-center.is-nudging,
.arc-center.is-nudging:active {
  transition: transform .08s linear, box-shadow .32s ease;
  transform: translate(var(--arc-nudge-x, 0px), var(--arc-nudge-y, 0px)) scale(1);
}

/* 扇盘的其它元素：任何情况下都不参与位移 */
.fan-disc,
.fan-arc-svg,
.fan-track-dots,
.fan-ticks,
.arc-thumb {
  will-change: auto;
}
.arc-center:disabled { opacity: .5; cursor: not-allowed; }

.arc-center.is-ready { animation: confirmBreath 3.4s ease-in-out infinite; }

/* 确认钮下方的操作提示：滑动选、点按确认 */
.dial-note {
  display: block;
  margin: 6px 0 2px;
  text-align: right;
  padding-right: 6px;
  font-family: var(--sans);
  font-size: 10.5px;
  letter-spacing: .08em;
  color: rgba(255,236,206,.62);
  text-shadow: 0 1px 6px rgba(0,0,0,.9);
  animation: dialNoteBreathe 2.6s ease-in-out infinite;
}

@keyframes dialNoteBreathe {
  0%, 100% { opacity: .55; }
  50% { opacity: 1; }
}

/* ---------- 结局：一张 9:16 结局卡占主导，诗句写在卡上 ---------- */
#screen-ending .preview-flag { display: none; }

.ending-wrap {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 14px 14px 12px;
}

.ending-card {
  position: relative;
  flex: 0 1 auto;
  /* 9:16 且高度不超可用空间：宽高都从可用高度推出来（Chrome 61 没有 aspect-ratio / dvh） */
  width: calc((932px - 216px) * 9 / 16);
  max-width: 100%;
  height: calc(932px - 216px);
  max-height: 680px;
  border-radius: 22px;
  overflow: hidden;
  background: #0b0a0a;
  box-shadow:
    0 24px 48px rgba(0,0,0,.72),
    0 0 0 1px rgba(255,236,206,.10),
    inset 0 1px 0 rgba(255,246,230,.10);
}

.ending-asset-slot {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: grid;
  place-items: center;
  padding: 0 18px 40%;
  text-align: center;
  font: 500 10px/1.6 var(--sans);
  letter-spacing: .18em;
  color: rgba(255,236,206,.3);
  background:
    linear-gradient(180deg, #34302b 0%, #26221f 34%, #171414 68%, #0c0b0b 100%);
}

.ending-asset-slot::before {
  content: "";
  position: absolute;
  top: 14px;
  right: 14px;
  bottom: 14px;
  left: 14px;
  border: 1px dashed rgba(255,226,184,.14);
  border-radius: 4px;
}

.ending-vignette {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  background:
    radial-gradient(122% 76% at 50% 32%, transparent 26%, rgba(0,0,0,.5) 72%, rgba(0,0,0,.86) 100%),
    linear-gradient(180deg, rgba(0,0,0,.5) 0%, transparent 20%, transparent 38%, rgba(0,0,0,.82) 78%, rgba(0,0,0,.94) 100%);
}

.ending-overlay {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 14px 15px 16px;
}

.ending-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.ending-rarity {
  font: 600 9.5px/1 var(--sans);
  letter-spacing: .1em;
  padding: 5px 9px;
  border-radius: 999px;
  border: 1px solid rgba(240,179,82,.4);
  background: rgba(0,0,0,.44);
  color: #f2c887;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.ending-letter {
  font: 500 9.5px/1 var(--sans);
  letter-spacing: .16em;
  color: rgba(255,238,206,.6);
  text-shadow: 0 2px 8px rgba(0,0,0,.9);
}

.ending-caption {
  display: grid;
  grid-gap: 9px;
  gap: 9px;
  text-align: center;
}

.ending-poem {
  display: grid;
  grid-gap: 1px;
  gap: 1px;
  font-family: var(--hand);
  font-size: 26.66px;
  font-weight: 700;
  line-height: 1.46;
  letter-spacing: .05em;
  color: #ffe8bc;
  text-shadow: 0 3px 16px rgba(0,0,0,.95), 0 0 26px rgba(240,179,82,.22);
}

.ending-poem .poem-line {
  display: block;
  white-space: nowrap;
}

/* 书法逐字入场：初始态由 GSAP 设置，这里只保证布局 */
.ending-poem .poem-char {
  display: inline-block;
  will-change: transform, opacity, filter;
}

.ending-poem .poem-line.is-offset { transform: translateX(10px); }

/* 结局：书法落款直接压在最后一张分镜上，不再单独占一个板块 */
.ending-card.has-image .ending-asset-slot { display: none; }

.ending-card.has-image {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.ending-card.has-image .ending-overlay {
  padding: 14px 15px 20px;
  background: linear-gradient(180deg,
    rgba(0,0,0,.54) 0%,
    rgba(0,0,0,.12) 22%,
    rgba(0,0,0,0) 44%,
    rgba(0,0,0,.40) 72%,
    rgba(0,0,0,.84) 100%);
}

.ending-card.has-image .ending-caption {
  align-self: flex-end;
  justify-self: end;
  max-width: 84%;
  gap: 8px;
  text-align: right;
}

.ending-card.has-image .ending-poem {
  font-size: 27.52px;
  line-height: 1.54;
  letter-spacing: .08em;
  color: #ffefd2;
  text-shadow: 0 2px 12px rgba(0,0,0,.98), 0 0 22px rgba(240,179,82,.24);
}

/* 落款处的小红印 */
.ending-card.has-image .ending-caption::after {
  content: "";
  width: 13px;
  height: 13px;
  margin-left: auto;
  border-radius: 2px;
  background: #a4221f;
  box-shadow: 0 2px 9px rgba(0,0,0,.72), inset 0 0 0 1px rgba(255,222,204,.3);
}

.ending-foot {
  flex: 0 0 auto;
  width: calc((932px - 216px) * 9 / 16);
  max-width: 100%;
  display: grid;
  grid-gap: 8px;
  gap: 8px;
}

.mark-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.mark-chip {
  font-size: 10px;
  padding: 4px 7px;
  border-radius: 999px;
  border: 1px solid rgba(141,190,143,.36);
  color: rgba(184,226,187,.72);
  background: rgba(141,190,143,.10);
}

.mark-chip:not(.earned) {
  border-color: rgba(255,255,255,.10);
  color: rgba(255,255,255,.30);
  background: rgba(255,255,255,.04);
}

.ending-actions {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-gap: 7px;
  gap: 7px;
}

.action-btn {
  appearance: none;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.04);
  color: rgba(255,238,208,.76);
  font: 500 11.5px/1 var(--sans);
  padding: 12px 6px;
  border-radius: 10px;
  cursor: pointer;
  transition: border-color .2s, background .2s, color .2s;
}

.action-btn.primary {
  border-color: rgba(240,179,82,.62);
  background: rgba(240,179,82,.14);
  color: #ffdf9d;
}

.action-btn.hidden-btn {
  border-color: rgba(240,179,82,.62);
  background: linear-gradient(90deg, rgba(207,61,81,.16), rgba(110,200,216,.12));
  color: #ffeec7;
  font-family: var(--serif);
  font-size: 13px;
  letter-spacing: .16em;
}

/* ---------- 倒计时：全屏压迫感，数字逐秒砸入 ---------- */
.confirm-mask {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: 24px;
  overflow: hidden;
  background:
    radial-gradient(circle at 50% 48%, rgba(117,20,25,.28), rgba(0,0,0,.94) 58%, #000 100%);
  opacity: 0;
  pointer-events: none;
  transition: opacity .24s ease;
}

.confirm-mask::before {
  content: "";
  position: absolute;
  top: -38%;
  right: -38%;
  bottom: -38%;
  left: -38%;
  background:
    repeating-radial-gradient(circle at 50% 50%, transparent 0 54px, rgba(226,98,82,.045) 55px 56px),
    radial-gradient(circle, rgba(207,61,61,.16), transparent 58%);
  pointer-events: none;
}

/* 只在遮罩真正出现时才转动，隐藏时不空转（省电，也避免截图/录制被无限动画卡住） */
.confirm-mask.is-active { opacity: 1; pointer-events: auto; }
.confirm-mask.is-active::before { animation: confirmDrift 9s linear infinite; }

.confirm-card {
  position: relative;
  width: 100%;
  max-width: 360px;
  min-height: 671.04px;
  max-height: 640px;
  display: grid;
  place-content: center;
  justify-items: center;
  overflow: hidden;
  padding: 28px 20px;
  border: 0;
  background: radial-gradient(circle at 50% 46%, rgba(52,13,18,.38), rgba(0,0,0,0) 62%);
  text-align: center;
  perspective: 900px;
}

.confirm-ripple {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 352.6px;
  max-width: 460px;
  height: 352.6px;
  max-height: 460px;
  border: 1px solid rgba(221,102,91,.18);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.confirm-ripple.ripple-b { width: 249.4px; max-width: 320px; height: 249.4px; max-height: 320px; border-color: rgba(240,179,82,.16); }
.confirm-ripple.ripple-c { width: 163.4px; max-width: 205px; height: 163.4px; max-height: 205px; border-color: rgba(221,102,91,.22); }

.confirm-kicker {
  margin: 0 0 2px;
  font: 600 9px/1 var(--sans);
  letter-spacing: .38em;
  text-indent: .38em;
  color: rgba(232,152,133,.58);
}

.timer {
  width: auto;
  height: auto;
  margin: 0 0 8px;
  display: block;
  border: 0;
  color: #ffd092;
  font-family: var(--serif);
  font-size: 146.2px;
  font-weight: 900;
  line-height: .82;
  text-shadow:
    0 0 26px rgba(231,105,79,.62),
    0 0 72px rgba(173,42,33,.38),
    0 12px 28px rgba(0,0,0,.92);
  font-variant-numeric: tabular-nums;
}

.confirm-title {
  margin: 0;
  font-family: var(--serif);
  font-size: 20px;
  font-weight: 800;
  letter-spacing: .1em;
  color: #fff0d2;
  text-shadow: 0 3px 16px rgba(0,0,0,.9);
}

.confirm-copy {
  max-width: 310px;
  margin: 12px auto 22px;
  color: rgba(245,225,213,.68);
  font-family: var(--sans);
  font-size: 12.5px;
  line-height: 1.72;
}

.confirm-actions {
  width: 100%;
  max-width: 310px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 9px;
  gap: 9px;
}

@keyframes confirmDrift {
  from { transform: rotate(0deg) scale(1); }
  to { transform: rotate(360deg) scale(1.02); }
}

/* ---------- 角色图鉴 · 胶片遮罩里的人像（无卡片边框） ---------- */
.sheet-mask {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 90;
  visibility: hidden;
  display: grid;
  align-items: end;
  padding: 14px 8px 8px;
  background: rgba(0,0,0,.66);
  -webkit-backdrop-filter: blur(10px) saturate(.72);
  backdrop-filter: blur(10px) saturate(.72);
  opacity: 0;
  pointer-events: none;
  transition: opacity .34s ease, visibility 0s linear .34s;
}

.sheet-mask.is-active {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transition: opacity .34s ease, visibility 0s;
}

.sheet-card {
  position: relative;
  width: 100%;
  height: 820.16px;
  max-height: 812px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 30px 30px 0 0;
  background:
    linear-gradient(180deg, rgba(38,38,37,.975) 0%, rgba(22,22,23,.985) 54%, rgba(11,11,12,1) 100%),
    url("./assets/paper-dark.webp") center / cover no-repeat;
  box-shadow: 0 -30px 80px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.05);
  padding: 9px 0 10px;
  transform: translate3d(0, 104%, 0);
  transition: transform .68s cubic-bezier(.16,1,.3,1);
  /* 卡片本身没有可滚动区域，竖向手势全部交给 JS 判（下滑收起 / 划走一张） */
  touch-action: none;
  will-change: transform;
  backface-visibility: hidden;
}

.sheet-mask.is-active .sheet-card { transform: translate3d(0, 0, 0); }

/* 图鉴卡片：从卡片上沿往下滑 = 收起。拖动期间必须关掉 transform 过渡，
   否则跟手会慢半拍；暗场按 app.js 每帧写进 --sheet-dim 的值变淡，
   松手后这个类被摘掉，一切回到原来的开合动画。 */
.sheet-mask.is-sheet-dragging .sheet-card { transition: none; }

.sheet-mask.is-sheet-dragging {
  background: rgba(0, 0, 0, var(--sheet-dim, .66));
}

.sheet-grab {
  display: block;
  width: 40px;
  height: 3px;
  margin: 0 auto 9px;
  border-radius: 999px;
  background: rgba(255,255,255,.16);
}

.sheet-head {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding: 0 18px;
  margin-bottom: 2px;
}

.sheet-title {
  margin: 0;
  font-family: var(--serif);
  font-size: 21px;
  font-weight: 900;
  letter-spacing: .01em;
  color: #fdf6ec;
}

.sheet-meta {
  margin-left: 10px;
  margin-right: 34px;
  font: 500 9.5px/1 var(--sans);
  letter-spacing: .1em;
  color: rgba(255,255,255,.34);
  font-variant-numeric: tabular-nums;
}

.sheet-close {
  position: absolute;
  top: -4px;
  right: 12px;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  background: rgba(255,255,255,.06);
  color: rgba(255,255,255,.6);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: background .25s ease, color .25s ease;
}

.sheet-close:active { background: rgba(255,255,255,.14); color: #fff; }

/* 展示区：一张大图，胶片遮罩，小幅/大幅滑动 */
.figure-gallery {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}

.figure-stage {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.figure-shot {
  display: flex;
  align-items: center;
  justify-content: center;
  max-height: 100%;
  /* 这里原有一条 figureIn 入场动画：它把 transform 整个接管，动画结束那一帧写的是
     transform:none，等于把 GSAP 摆好的槽位整个抹掉 —— 照片会先跑到右下再弹回原位。
     照片的入场现在由 GSAP 管（见 app.js 的 figureApplySlots）。 */
}

/* 胶片遮罩：四周压黑、暗角很深，中间是人像 */
.figure-mask {
  position: relative;
  height: 428.72px;
  max-height: 392px;
  width: calc(428.72px * 3 / 4.35);
  max-width: 361.2px;
  overflow: hidden;
  border-radius: 10px;
  background: radial-gradient(96% 70% at 50% 40%, #3a342d 0%, #1c1917 30%, #080808 58%, #000 84%);
  box-shadow:
    0 26px 48px rgba(0,0,0,.8),
    inset 0 0 120px 52px rgba(0,0,0,.99),
    inset 0 0 0 1px rgba(255,236,206,.05);
}

/* 这一条是「胶片遮罩卡片」时代的相纸定位（绝对定位 + top/right/bottom/left 百分比）。
   后来相纸改成在 .figure-shot 定位层里 flex 居中，这一段却留了下来：
   相纸被改成 position:relative 之后，四个百分比偏移照样生效 ——
   等于把照片硬生生往右下推（top:7% ≈ 下移 35px、left:8% ≈ 右移 34px），
   就是反馈里"照片不在画面中间"的原因。整块删掉，位置全部由 flex 居中交代。 */

.photo-backdrop {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background:
    linear-gradient(133deg, rgba(255,222,176,.16) 0%, rgba(255,206,158,.05) 26%, transparent 52%),
    radial-gradient(78% 54% at 32% 16%, rgba(255,214,168,.13), transparent 74%),
    radial-gradient(62% 42% at 50% 102%, rgba(0,0,0,.5), transparent 72%),
    linear-gradient(180deg, #3a3733 0%, #242220 60%, #121110 100%);
}

.photo-floor {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 34%;
  background: linear-gradient(180deg, transparent, rgba(0,0,0,.6));
}

.figure-silhouette {
  position: absolute;
  left: 50%;
  bottom: 4%;
  height: 86%;
  width: auto;
  transform: translateX(-50%);
  fill: rgba(226,206,184,.2);
  filter: drop-shadow(0 20px 24px rgba(0,0,0,.5));
  transition: fill .4s ease, filter .4s ease;
}

/* 人物图鉴：直接用人物照，不再用剪影占位 */
.figure-photo {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 22%;
  border-radius: 6px;
  filter: saturate(.94) contrast(1.04);
  -webkit-user-drag: none;
  user-select: none;
}

/* 还没玩到的人物：整张压暗，但仍能看出是个人 */
.figure-shot.is-locked .figure-photo {
  filter: grayscale(.55) brightness(.46) contrast(1.05) blur(.4px);
}

.figure-shot.is-locked .figure-mask {
  box-shadow:
    0 22px 40px rgba(0,0,0,.82),
    inset 0 0 130px 62px rgba(0,0,0,.98),
    inset 0 0 0 1px rgba(255,236,206,.04);
}

.figure-shot.is-unlocked .figure-silhouette {
  fill: rgba(255,214,168,.52);
  filter: drop-shadow(0 16px 26px rgba(0,0,0,.5)) drop-shadow(0 0 18px rgba(255,178,104,.16));
}

.figure-shot.is-current .figure-silhouette {
  fill: rgba(255,232,192,.74);
  filter: drop-shadow(0 16px 26px rgba(0,0,0,.5)) drop-shadow(0 0 22px rgba(255,186,112,.28));
}

.figure-shot:not(.is-unlocked) .figure-silhouette { fill: rgba(210,200,190,.12); }

.mask-vignette {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  background:
    radial-gradient(88% 64% at 50% 38%, transparent 12%, rgba(0,0,0,.66) 46%, rgba(0,0,0,.96) 78%, #000 100%),
    radial-gradient(120% 90% at 50% 50%, transparent 40%, rgba(0,0,0,.5) 82%, #000 100%),
    linear-gradient(180deg, rgba(0,0,0,.62) 0%, transparent 18%, transparent 56%, rgba(0,0,0,.82) 100%);
}

/* 相纸上的字：左下角那行场次字已按反馈删除（DOM 里也不再生成），只剩右下角"第几张" */
.figure-shot-count {
  position: absolute;
  z-index: 2;
  font: 500 9px/1 var(--sans);
  letter-spacing: .12em;
  font-variant-numeric: tabular-nums;
  color: rgba(255,224,178,.66);
  text-shadow: 0 2px 10px rgba(0,0,0,.9);
}

.figure-shot-count {
  right: 12px;
  bottom: 11px;
  color: rgba(255,224,178,.44);
}

.figure-text {
  display: grid;
  grid-gap: 4px;
  gap: 4px;
  max-width: 361.2px;
  text-align: center;
}

.figure-name {
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 900;
  color: #fdf3e4;
}

.figure-role {
  font: 500 9.5px/1.4 var(--sans);
  letter-spacing: .14em;
  color: rgba(255,224,178,.56);
}

.figure-blurb {
  max-width: 300px;
  font-size: 11px;
  line-height: 1.6;
  color: rgba(255,240,220,.5);
}

.figure-shot:not(.is-unlocked) .figure-name { color: rgba(255,246,236,.34); }
.figure-shot:not(.is-unlocked) .figure-role { color: rgba(255,240,220,.3); }
.figure-shot:not(.is-unlocked) .figure-blurb { color: rgba(255,240,220,.24); }

.figure-nav {
  position: absolute;
  top: 42%;
  /* 照片层现在是"铺满整块展台"的定位层（z-index 20~40，放大时 400），
     压在它下面的话这两个按钮就点不到了，所以压到照片层之上。 */
  z-index: 500;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(0,0,0,.4);
  color: rgba(255,255,255,.6);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: background .25s ease, color .25s ease, transform .25s ease, opacity .34s ease;
}

.figure-nav:active { background: rgba(255,255,255,.16); color: #fff; transform: scale(.94); }
.figure-nav:disabled { opacity: .16; pointer-events: none; }
.figure-nav.is-prev { left: 4px; }
.figure-nav.is-next { right: 4px; }

.figure-swipe-hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2px;
  text-align: center;
  font: 400 9px/1 var(--sans);
  letter-spacing: .12em;
  color: rgba(255,255,255,.26);
}

.figure-progress {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  grid-gap: 10px;
  gap: 10px;
  padding: 8px 18px 4px;
}

.figure-progress-track {
  position: relative;
  display: block;
  height: 2px;
  border-radius: 999px;
  background: rgba(255,255,255,.12);
  overflow: hidden;
}

.figure-progress-track i {
  position: absolute;
  top: 0;
  right: auto;
  bottom: 0;
  left: 0;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, rgba(240,179,82,.5), rgba(255,224,178,.9));
  transition: width .42s cubic-bezier(.16,1,.3,1);
}

.figure-progress-label {
  font: 500 9px/1 var(--sans);
  letter-spacing: .08em;
  color: rgba(255,255,255,.36);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ---------- 故事线：整屏翻面 ---------- */
.storyline-head {
  position: absolute;
  left: 4px;
  right: 4px;
  top: -2px;
  z-index: 4;
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 2px 4px 4px;
  pointer-events: none;
}

.storyline-title {
  font-family: var(--serif);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .22em;
  color: rgba(255,240,214,.86);
}

.storyline-route {
  font: 500 9px/1 var(--sans);
  letter-spacing: .18em;
  color: rgba(255,226,184,.44);
}

.storyline-map {
  position: absolute;
  left: 0;
  right: 0;
  top: 26px;
  bottom: 88px;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.storyline-map:active { cursor: grabbing; }

.tree-canvas {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate3d(0, 0, 0);
  transform-origin: 0 0;
  will-change: transform;
}

.story-tree {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  overflow: visible;
}

.tree-edge {
  fill: none;
  stroke: var(--lane-color, #f0b352);
  stroke-width: 1;
  stroke-opacity: .20;
  stroke-linecap: round;
  transition: stroke-opacity .42s ease, filter .42s ease, stroke-width .42s ease, opacity .42s ease;
}

.tree-edge.is-chosen {
  stroke: var(--lane-color);
  stroke-opacity: 1;
  stroke-width: 1.9;
  filter: drop-shadow(0 0 7px var(--lane-glow));
}

.tree-edge.is-locked-lane {
  stroke-opacity: .055;
  filter: blur(1.2px);
  pointer-events: none;
}

.tree-node {
  position: absolute;
  width: 128px;
  min-height: 54px;
  padding: 7px 8px 8px 10px;
  display: grid;
  align-content: center;
  grid-gap: 3px;
  gap: 3px;
  border: 1px solid rgba(255,255,255,.08);
  border-left: 2px solid var(--lane-color);
  border-radius: 10px;
  background: linear-gradient(90deg, rgba(20,8,10,.90), rgba(7,4,5,.80));
  color: rgba(255,238,210,.34);
  transform: translate(-50%, -50%);
  text-align: left;
  cursor: pointer;
  transition: border-color .34s ease, color .34s ease, background .34s ease, box-shadow .34s ease, opacity .34s ease, transform .34s ease;
}

.tree-node:disabled { cursor: default; pointer-events: none; }

.tree-node:not(:disabled):active { transform: translate(-50%, -50%) scale(.97); }

.tree-node-code {
  font: 700 9px/1 var(--sans);
  letter-spacing: .14em;
  color: var(--lane-color);
  opacity: .72;
}

.tree-node-title {
  display: block;
  font-family: var(--serif);
  font-size: 12px;
  font-weight: 700;
  line-height: 1.28;
  color: rgba(255,238,210,.48);
  transition: color .3s ease, opacity .3s ease;
}

.tree-node.is-root {
  width: 158px;
  min-height: 58px;
  border-color: rgba(255,225,173,.82);
  color: #fff1cf;
  background: linear-gradient(90deg, rgba(255,224,168,.18), rgba(9,4,5,.92) 72%);
}

.tree-node.is-unplayed {
  opacity: .42;
  background: linear-gradient(90deg, rgba(17,8,10,.76), rgba(7,4,5,.58));
}

.tree-node.is-visited {
  border-color: var(--lane-color);
  border-left-color: var(--lane-color);
  background: linear-gradient(90deg, var(--lane-glow), rgba(8,4,5,.92) 72%);
  box-shadow: 0 0 16px var(--lane-glow);
  cursor: pointer;
}

.tree-node.is-visited .tree-node-title,
.tree-node.is-current .tree-node-title,
.tree-node.is-earned .tree-node-title {
  color: rgba(255,245,226,.88);
}

.tree-node.is-visited:hover {
  transform: translate(-50%, -50%) translateY(-2px);
  box-shadow: 0 0 24px var(--lane-glow);
}

.tree-node.is-current {
  border-color: #fff1cf;
  color: #fff4da;
  box-shadow: 0 0 24px var(--lane-glow), 0 0 0 5px rgba(255,255,255,.035);
  animation: nodePulse 2.4s ease-in-out infinite;
}

.tree-node.is-ending {
  width: 130px;
  min-height: 48px;
  border-radius: 4px 18px 4px 18px;
}

.tree-node.is-ending.is-earned {
  color: #ffe9bc;
  background: linear-gradient(90deg, var(--lane-glow), rgba(8,4,5,.92) 74%);
  box-shadow: 0 0 22px var(--lane-glow);
}

.tree-node.is-locked-lane {
  width: 20px;
  min-height: 20px;
  padding: 0;
  border-color: rgba(255,255,255,.12);
  border-left-width: 1px;
  border-radius: 50%;
  opacity: .055;
  filter: blur(1.1px);
  pointer-events: none;
}

.tree-node.is-locked-lane .tree-node-code,
.tree-node.is-locked-lane .tree-node-title {
  display: none;
}

/* 当前所在节点：大号气泡指引 + 环形脉冲 */
.tree-node.is-current::after {
  content: "";
  position: absolute;
  top: -9px;
  right: -9px;
  bottom: -9px;
  left: -9px;
  border-radius: 14px;
  border: 2px solid var(--lane-color);
  opacity: .5;
  pointer-events: none;
  animation: currentRing 2.3s ease-out infinite;
}

@keyframes currentRing {
  0% { transform: scale(.95); opacity: .55; }
  70% { transform: scale(1.08); opacity: 0; }
  100% { transform: scale(1.08); opacity: 0; }
}

/* 当前节点引导：脱离画布缩放，固定在屏幕层，因此始终醒目 */
.tree-focus {
  /* 必须与 .storyline-map 的可视区域完全重合，否则气泡会整体偏移 */
  position: absolute;
  left: 0;
  right: 0;
  top: 26px;
  bottom: 88px;
  z-index: 8;
  overflow: hidden;
  pointer-events: none;
  --lane-color: #f0b352;
  --lane-glow: rgba(240,179,82,.28);
}

.tree-focus-lead {
  position: absolute;
  left: 0;
  top: 0;
  height: 3px;
  border-radius: 3px;
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--lane-color), rgba(255,255,255,.22));
  box-shadow: 0 0 14px var(--lane-glow);
  opacity: .92;
}

.tree-focus-bead {
  position: absolute;
  left: 0;
  top: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2.5px solid var(--lane-color);
  background: radial-gradient(circle at 38% 32%, rgba(255,246,230,.55), rgba(0,0,0,0) 68%);
  box-shadow: 0 0 22px var(--lane-glow), inset 0 0 14px var(--lane-glow);
  animation: focusBead 2.2s ease-in-out infinite;
}

@keyframes focusBead {
  0%, 100% { opacity: .55; }
  50% { opacity: 1; }
}

.tree-focus-bubble {
  position: absolute;
  left: 0;
  top: 0;
  width: max-content;
  max-width: 216px;
  padding: 10px 15px 13px;
  border: 2px solid var(--lane-color);
  border-radius: 17px;
  background: linear-gradient(180deg, rgba(48,30,16,.985), rgba(11,7,5,.99));
  box-shadow:
    0 22px 46px rgba(0,0,0,.84),
    0 0 36px var(--lane-glow),
    inset 0 1px 0 rgba(255,247,232,.16);
  animation: focusGlow 2.6s ease-in-out infinite;
}

@keyframes focusGlow {
  0%, 100% { box-shadow: 0 22px 46px rgba(0,0,0,.84), 0 0 26px var(--lane-glow), inset 0 1px 0 rgba(255,247,232,.16); }
  50% { box-shadow: 0 22px 46px rgba(0,0,0,.84), 0 0 48px var(--lane-glow), inset 0 1px 0 rgba(255,247,232,.16); }
}

.tree-focus-bubble .focus-tag {
  display: inline-block;
  padding: 3px 9px 4px;
  border-radius: 999px;
  background: var(--lane-color);
  color: #17110a;
  font: 800 10px/1 var(--sans);
  letter-spacing: .18em;
}

.tree-focus-bubble .focus-title {
  display: block;
  margin-top: 8px;
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 900;
  line-height: 1.34;
  color: #fff4e0;
  text-shadow: 0 1px 0 rgba(0,0,0,.6);
}

.tree-lane-label {
  position: absolute;
  z-index: 2;
  transform: translate(-50%, -100%);
  color: var(--lane-color);
  font-family: var(--serif);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .16em;
  white-space: nowrap;
  text-shadow: 0 0 14px var(--lane-glow);
  pointer-events: none;
}

.tree-lane-label.is-locked {
  opacity: .06;
  filter: blur(1.8px);
}

.alt-route {
  --hold-progress: 0;
  position: absolute;
  right: 20px;
  bottom: 42px;
  z-index: 3;
  min-width: 152px;
  padding: 10px 0 9px;
  display: grid;
  justify-items: end;
  grid-gap: 5px;
  gap: 5px;
  cursor: pointer;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.alt-route-title {
  margin: 0;
  font-family: var(--serif);
  font-size: 18px;
  font-weight: 900;
  line-height: 1;
  white-space: nowrap;
  transition: color .24s ease, text-shadow .24s ease, transform .24s ease;
}

.alt-route-title.is-man { color: rgba(110,200,216,.26); }
.alt-route-title.is-woman { color: rgba(255,72,88,.25); }

.alt-route-note {
  font: 500 8.5px/1 var(--sans);
  letter-spacing: .14em;
  color: rgba(255,255,255,.12);
}

.alt-route.is-holding .alt-route-title {
  color: #fff1d0;
  text-shadow: 0 0 18px rgba(255,179,91,.58);
  transform: translateY(-1px);
}

.alt-route.is-holding .alt-route-note {
  color: rgba(255,232,187,.72);
}

.alt-route-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  border-radius: 999px;
  background: linear-gradient(90deg, #ff713c, #ffd185);
  box-shadow: 0 0 12px rgba(255,113,60,.62);
  transform: scaleX(var(--hold-progress));
  transform-origin: left center;
  opacity: .2;
}

.alt-route.is-holding .alt-route-progress { opacity: 1; }

.storyline-hint {
  position: absolute;
  left: 22px;
  bottom: 24px;
  font-size: 9.5px;
  color: rgba(255,238,210,.34);
}

.seal-transition {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 160;
  visibility: hidden;
  display: grid;
  place-items: center;
  overflow: hidden;
  pointer-events: none;
}

.seal-transition.is-active {
  visibility: visible;
}

.seal-ink,
.seal-ring,
.seal-mark {
  position: absolute;
  pointer-events: none;
}

.seal-ink {
  width: 1584.4px;
  height: 1584.4px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 48% 46%, #a72637 0 10%, #751426 38%, #3a0712 72%, #150208 100%);
  box-shadow:
    inset 0 0 90px 22px rgba(255,192,120,.10),
    0 0 0 8px rgba(255,214,156,.06);
  transform: scale(.02) rotate(-18deg);
  opacity: 0;
}

.seal-ring {
  width: 481.6px;
  height: 481.6px;
  border: 2px solid rgba(255,221,170,.58);
  border-radius: 50%;
  box-shadow:
    0 0 38px rgba(255,194,113,.30),
    inset 0 0 38px rgba(255,194,113,.18);
  transform: scale(.05) rotate(0deg);
  background: transparent;
  opacity: 0;
}

.seal-mark {
  color: rgba(255,226,176,.92);
  font-family: var(--serif);
  font-size: 94.6px;
  font-weight: 900;
  line-height: 1;
  text-shadow: 0 0 28px rgba(255,178,92,.48);
  transform: scale(.18) rotate(-14deg);
  opacity: 0;
}

.seal-transition.is-active .seal-ink {
  animation: sealInk 1.45s cubic-bezier(.16,1,.3,1) forwards;
}

.seal-transition.is-active .seal-ring {
  animation: sealRing 1.08s .06s cubic-bezier(.16,1,.3,1) forwards;
}

.seal-transition.is-active .seal-mark {
  animation: sealMark 1.18s .10s cubic-bezier(.16,1,.3,1) forwards;
}

@keyframes sealInk {
  0% { transform: scale(.02) rotate(-18deg); opacity: 0; }
  10% { opacity: 1; }
  46% { transform: scale(1) rotate(0deg); opacity: 1; }
  72% { transform: scale(1) rotate(0deg); opacity: 1; }
  100% { transform: scale(1.18) rotate(0deg); opacity: 0; }
}

@keyframes sealRing {
  0% { transform: scale(.05) rotate(0deg); opacity: 0; }
  24% { opacity: .72; }
  58% { transform: scale(.78) rotate(18deg); opacity: .56; }
  100% { transform: scale(1.08) rotate(24deg); opacity: 0; }
}

@keyframes sealMark {
  0% { transform: scale(.18) rotate(-14deg); opacity: 0; }
  28% { transform: scale(1.08) rotate(0deg); opacity: 1; }
  62% { transform: scale(1) rotate(0deg); opacity: .92; }
  100% { transform: scale(1.3) rotate(0deg); opacity: 0; }
}

@keyframes confirmBreath {
  0%, 100% {
    box-shadow:
      inset 0 5px 8px rgba(118,72,6,.5),
      inset 0 -4px 7px rgba(255,240,196,.42),
      inset 0 0 0 5px rgba(190,138,30,.34),
      inset 0 0 24px rgba(120,74,8,.42),
      0 9px 18px rgba(0,0,0,.6);
  }
  50% {
    box-shadow:
      inset 0 5px 9px rgba(118,72,6,.52),
      inset 0 -4px 7px rgba(255,240,196,.46),
      inset 0 0 0 5px rgba(212,164,56,.48),
      inset 0 0 28px rgba(120,74,8,.48),
      0 10px 20px rgba(0,0,0,.64),
      0 0 18px rgba(214,170,66,.22);
  }
}

@keyframes optionIn {
  0% { opacity: 0; transform: translateX(-10px); }
  100% { opacity: 1; transform: translateX(0); }
}

/* 新照片是「缓慢显影叠上去」，不是滑进来 */
@keyframes printEnter {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

@keyframes printSettle {
  0% { transform: none; opacity: 1; }
  100% { transform: translate(var(--gx, 6px), var(--gy, -5px)) rotate(var(--gr, .8deg)); opacity: 1; }
}

.photo-stack.is-entering .scene-print:not(.print-ghost) {
  animation: printEnter .95s cubic-bezier(.22,.61,.36,1) both;
}

.photo-stack.has-history .scene-sheet { opacity: 0 !important; }

/* 上一幕照片留在堆叠里，新照片直接盖上去 */
/* 底下的残影只留照片，不留文字和按钮（否则底部会露出半行旧台词） */
.scene-print.print-ghost .print-caption,
.scene-print.print-ghost .story-continue,
.scene-print.print-ghost .print-meta { display: none; }

.scene-print.print-ghost {
  z-index: 1;
  transform: translate(var(--gx, 6px), var(--gy, -5px)) rotate(var(--gr, .8deg));
  pointer-events: none;
}

/* 残影不再有落位动画：位置固定，画面保持静止 */
.scene-print.print-ghost.is-settling { animation: none; }

.photo-stack .scene-print { z-index: 4; }

@keyframes chromeGlow {
  0%, 100% {
    border-color: rgba(255,206,142,.20);
    box-shadow: 0 0 0 rgba(255,190,120,0);
    color: rgba(255,238,210,.66);
  }
  50% {
    border-color: rgba(255,206,142,.78);
    box-shadow: 0 0 24px rgba(255,190,120,.24);
    color: #fff2d8;
  }
}

@keyframes nodePulse {
  0%, 100% { filter: drop-shadow(0 0 5px var(--lane-glow)); }
  50% { filter: drop-shadow(0 0 16px var(--lane-glow)); }
}

@keyframes chapterRoll {
  0% { transform: rotateX(0deg); }
  52% { transform: rotateX(-9deg) translateY(-1px); }
  100% { transform: rotateX(0deg); }
}

/* ---------- 动效 ---------- */
@keyframes breathe {
  0%, 100% { opacity: .68; }
  50% { opacity: 1; }
}

@keyframes flicker {
  0%, 100% { opacity: 1; }
  50% { opacity: .18; }
}

/* 焦点框只在「键盘操作」时出现——点按/触摸不该弹边框（首页那颗大黄钮最明显）。
   :focus-visible 需要 Chrome 86+，旧内核用 html.is-keynav *:focus 兜底；
   app.js 里 keydown 时加 is-keynav、pointerdown 时摘掉。 */
html.is-keynav *:focus,
:focus-visible {
  outline: 2px solid var(--lamp-gold);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ==========================================================================
   2026-09-23 重构一：首页改成「序列帧胶片」
   四段视频（下拉 / 上滑小帅 / 下滑小美 / 人物切换）转成序列帧，
   由手指位置直接决定画到第几帧 —— 苹果官网那种无极滑动手感。
   画面里已经包含红纸、流苏、结婚照与打光，所以旧的底图与证件层全部让位。
   ========================================================================== */

.home-film {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
  /* 画布尺寸由 app.js 按屏幕（×DPR）开，绘制时已做 cover 裁切，CSS 不再缩放变形 */
  opacity: 0;
  transition: opacity .55s ease;
  pointer-events: none;
}

#screen-home.has-film .home-film { opacity: 1; }

/* 画面自带底与光，旧的这几层全部关掉，免得两层叠一起变脏 */
#screen-home.has-film .home-red,
#screen-home.has-film .home-ember,
#screen-home.has-film .home-ink,
#screen-home.has-film .poster-grain,
#screen-home.has-film .home-darkness { display: none; }

#screen-home.has-film::before { display: none; }

/* 提示文字留在画面上，位置固定；下拉过程中由 JS 淡出 */
#screen-home.has-film .home-pull-cue {
  position: absolute;
  left: 50%;
  top: 63%;
  transform: translateX(-50%);
  transition: opacity .3s ease;
}

/* 整屏都能拖，不需要单独的热区 */
#screen-home.has-film .home-pull-hit { display: none; }

/* 圆钮未选择时停在弧线正中：那条弧上要看得见一颗实心小圆（.arc-thumb 已在用） */
.home-fan .arc-thumb.is-center { opacity: .55; }

/* ==========================================================================
   2026-09-23 重构二：剧情页改成「黑底 + 圆角窗」
   几何直接照 素材/生产素材/背景图（带透明底）.png 量的：
     窗 x 5.4%~94.5%（宽 89.1%）、y 11.5%~95.8%（高 84.4%）、圆角 ≈ 窗宽的 7.9%
   窗户里就是剧情照片本身，照片与照片之间直接过渡（淡出→换图→淡入）。
   原来的「圆角矩形卡片 + 渐变凹槽」整体作废。
   ========================================================================== */

#screen-story { background: #070607; }

#screen-story::before,
#screen-story::after { display: none; }

/* 顶部工具条浮在窗外上方，落在黑边里 */
#screen-story .game-chrome { z-index: 40; }

.scene-photo {
  position: absolute;
  left: 5.4%;
  right: 5.4%;
  top: 11.5%;
  bottom: 4.1%;
  width: auto;
  height: auto;
  padding: 0;
  display: block;
  border-radius: 26px;
  overflow: hidden;
  background: #000;
  box-shadow: 0 20px 54px rgba(0, 0, 0, .72);
}

.photo-stack,
.scene-print {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: auto;
  height: auto;
  border-radius: 0;
  box-shadow: none;
  background: #000;
  transform: none !important;
}

/* 旧的纸叠层与凹槽不要了 */
.scene-sheet,
.scene-print::before { display: none; }

/* 照片铺满整个窗 */
.scene-print .asset-slot {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  height: auto;
  border: 0;
  border-radius: 0;
  background-position: center;
  background-size: cover;
  filter: saturate(.96) contrast(1.03) brightness(.98);
}

.scene-print .asset-slot.has-image::after {
  background: radial-gradient(120% 84% at 50% 40%, transparent 52%, rgba(0, 0, 0, .28) 82%, rgba(0, 0, 0, .55) 100%);
}

/* 剧情文字改成压在照片下沿，靠一层渐变暗角保证可读 */
.print-caption {
  left: 0;
  right: 0;
  top: auto;
  bottom: 0;
  max-height: 66%;
  padding: 78px 20px 66px;
  background: linear-gradient(to top,
    rgba(4, 3, 3, .94) 0%,
    rgba(4, 3, 3, .82) 34%,
    rgba(4, 3, 3, .40) 68%,
    rgba(4, 3, 3, 0) 100%);
}

.print-caption.is-beat {
  padding: 78px 20px 66px;
}

.print-caption.is-beat .print-caption-scene {
  font-size: 15.5px;
  line-height: 1.7;
}

/* 继续 / 做出选择 按钮压在同一块暗角上 */
.story-continue {
  right: 18px;
  bottom: 16px;
  z-index: 9;
}

/* 抉择时：选项与弧盘也压在照片上 */
#screen-story .choice-zone {
  min-height: 0;
  padding: 0;
  align-items: end;
}

/* ==========================================================================
   2026-09-23 修正批（按反馈逐条）
   ========================================================================== */

/* ① 提示图标补上「大圆钮」：弧线 + 钮 + 沿弧移动的小球，一眼看出是拖钮 */
.home-hint-icon { width: 40px; height: 36px; }

.home-hint-btn { fill: #f0b352; }

.home-hint-btn-ring {
  fill: none;
  stroke: rgba(255, 238, 200, .85);
  stroke-width: 1.1;
}

.home-hint-dot { fill: #fff6e2; }

/* 两个点各自沿同一条弧走，采样点都是「圆心 (32,32)」上的精确解：
     小白点 半径 26.6 → 落在弧线外侧（视觉上在弧线上面）
     小黄圈 半径 13.4 → 落在弧线内侧（视觉上在弧线下面，外沿离弧线 1.6）
   linear 是为了匀速滑，不要在每个采样点之间再做一次缓动（那样会一顿一顿的）。 */
@keyframes homeHintDot {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(2.6px, -7.66px); }
  50%  { transform: translate(7.39px, -14.19px); }
  75%  { transform: translate(13.91px, -18.98px); }
  100% { transform: translate(21.58px, -21.58px); }
}

.home-hint-dot {
  animation: homeHintDot 2.6s linear infinite alternate;
}

/* 黄钮贴在弧线下方，只跟着挪一小段（不是走满全程，也不跟小球重合） */
@keyframes homeHintKnob {
  0%   { transform: translate(-2.36px, 3.18px); }
  25%  { transform: translate(-1.3px, 1.5px); }
  50%  { transform: translate(0, 0); }
  75%  { transform: translate(1.5px, -1.3px); }
  100% { transform: translate(3.18px, -2.36px); }
}

.home-hint-btn,
.home-hint-btn-ring {
  animation: homeHintKnob 2.6s linear infinite alternate;
}

/* ② 长按进度条挪到上方，并做 R 角（与屏幕边缘一致） */
.home-hold {
  top: 0;
  bottom: auto;
  height: 22px;
}

.home-hold-fill {
  top: 9px;
  bottom: auto;
  left: 14px;
  right: 14px;
  height: 3px;
  border-radius: 999px;
  transform: scaleX(var(--charge, 0));
  transform-origin: 0 50%;
  background: linear-gradient(90deg, rgba(255,231,174,.30), #FFE7AE 46%, #D9A441);
  box-shadow: 0 0 14px rgba(240,179,82,.55);
}

/* ③ 剧情窗放大：上边收窄，离顶部两个图标更近，画面更有沉浸感 */
.scene-photo {
  left: 3.1%;
  right: 3.1%;
  top: 5.8%;
  bottom: 2.6%;
  border-radius: 22px;
}

/* ⑦ 大黄钮保持原样（不动），只有弧线上的圆点跟着走 */
.home-fan.is-selecting .arc-thumb,
.home-fan.is-dragging .arc-thumb {
  transition: transform .16s cubic-bezier(.22, 1.12, .36, 1), opacity .2s ease;
}

/* ④ 窗边不再有那圈"低透明度圆环"：图片朝四边柔和融进黑底 */
.print-leak,
.print-grain,
.scene-print .asset-slot.has-image::after { display: none !important; }

.scene-print .asset-slot {
  top: -1.5%;
  right: -1.5%;
  bottom: -1.5%;
  left: -1.5%;
  -webkit-mask-image: radial-gradient(128% 108% at 50% 48%,
    #000 58%, rgba(0,0,0,.92) 76%, rgba(0,0,0,.62) 92%, rgba(0,0,0,.34) 100%);
  mask-image: radial-gradient(128% 108% at 50% 48%,
    #000 58%, rgba(0,0,0,.92) 76%, rgba(0,0,0,.62) 92%, rgba(0,0,0,.34) 100%);
}

/* ⑤ 两张照片之间用一层真正的交叉淡化，不再"闪两下" */
.story-photo-ghost {
  position: absolute;
  top: -1.5%;
  right: -1.5%;
  bottom: -1.5%;
  left: -1.5%;
  z-index: 0;
  background-position: center;
  background-size: cover;
  opacity: 0;
  pointer-events: none;
  filter: saturate(.96) contrast(1.03) brightness(.98);
  -webkit-mask-image: radial-gradient(128% 108% at 50% 48%,
    #000 58%, rgba(0,0,0,.92) 76%, rgba(0,0,0,.62) 92%, rgba(0,0,0,.34) 100%);
  mask-image: radial-gradient(128% 108% at 50% 48%,
    #000 58%, rgba(0,0,0,.92) 76%, rgba(0,0,0,.62) 92%, rgba(0,0,0,.34) 100%);
}

.scene-print .asset-slot { z-index: 1; }

/* ⑥ 未解锁角色：剪影 + 问号（不再放出真人照片） */
.figure-lock {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 6;
  transform: translate(-50%, -50%);
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 226, 170, .42);
  background: rgba(8, 4, 6, .52);
  color: rgba(255, 232, 190, .92);
  font: 700 24px/1 var(--serif);
  text-shadow: 0 2px 10px rgba(0, 0, 0, .8);
  pointer-events: none;
}

.figure-shot.is-locked .figure-portrait { opacity: .5; filter: grayscale(.6) brightness(.5); }

/* ⑧ 提醒页：确认按钮与提示文字整体上移（原来太贴底） */
.reminder { padding-bottom: 92px; }
.reminder-foot { margin-bottom: 26px; }

/* ⑨ 剧情窗再往上抬一点；窗边与照片四面都柔和收进去，不再出现"下面是硬黑边" */
.scene-photo {
  top: 2.4%;
  bottom: 3.4%;
}

.scene-print .asset-slot,
.story-photo-ghost {
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  -webkit-mask-image: radial-gradient(126% 106% at 50% 46%,
    #000 62%, rgba(0,0,0,.94) 80%, rgba(0,0,0,.72) 93%, rgba(0,0,0,.46) 100%);
  mask-image: radial-gradient(126% 106% at 50% 46%,
    #000 62%, rgba(0,0,0,.94) 80%, rgba(0,0,0,.72) 93%, rgba(0,0,0,.46) 100%);
}

/* 文案暗角收短、减轻，避免窗底出现一整条死黑 */
.print-caption,
.print-caption.is-beat {
  max-height: 62%;
  /* 文案与按钮整体下移到窗口下沿附近 */
  padding: 56px 20px 26px;
  background: linear-gradient(to top,
    rgba(4, 3, 3, .78) 0%,
    rgba(4, 3, 3, .55) 42%,
    rgba(4, 3, 3, .22) 74%,
    rgba(4, 3, 3, 0) 100%);
}

/* 按钮跟着往下挪一点 */
.story-continue { bottom: 12px; }

/* 占位底改深色：图片没解码完时不再闪出浅底 */
.scene-print .asset-slot { background-color: #0b0a09; }

/* 照片与黑底：再叠一层内部投影，边缘更"化"进去，不再有切割感 */
.scene-photo::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 3;
  pointer-events: none;
  border-radius: inherit;
  box-shadow:
    inset 0 0 34px 10px rgba(6, 5, 5, .55),
    inset 0 0 90px 26px rgba(6, 5, 5, .38);
}

/* ==========================================================================
   2026-09-24 图鉴：实体照片叠放 + 点按原地放大（GSAP 驱动）
   ========================================================================== */

/* 每张照片 = 一层铺满展台的定位层，相纸在层里居中。
   层与相纸同心，所以 JS 直接对层写 x / y / rotation / scale 就够了 ——
   不用在 CSS 里拼 translate(-50%,-50%)，也就不会出现
   "动画中途把居中位移覆盖掉、照片先跳到右下再弹回原位" 那种错位。
   槽位（最上面那张 + 底下两张的错位与角度）在 app.js 的 FIGURE_SLOTS 里。 */
#figure-rail {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
}

.figure-stage { position: relative; }

.figure-shot {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* transform 全部交给 GSAP（拖拽 / 回弹 / 放大 / 划走），CSS 里不留 transition，
     否则两边抢同一批属性，就会出现"先从旧值慢慢爬过去"的假动画。 */
  transition: opacity .35s ease, filter .35s ease;
  animation: none;
  will-change: transform;
}

.figure-shot.is-top { filter: drop-shadow(0 18px 34px rgba(0, 0, 0, .55)); }

/* 放大态：这张相纸被拿到最前面（比左右按钮的 500 更高），
   位置 / 角度 / 倍率全部由 app.js 的 figureLiftState 算好写进 GSAP。 */
.figure-shot.is-lifted {
  z-index: 600 !important;
  filter: drop-shadow(0 34px 60px rgba(0, 0, 0, .78));
}

/* ==========================================================================
   2026-09-24 图鉴放大：尺寸更大 + 角度回正 + 背景真的糊掉
   ==========================================================================
   上一版放大只在原地加了 10% 的倍率，背景只是压暗（用户："放大尺寸要大一些、
   角度要回正、背景要模糊"）。现在：
     · 倍率 / 位置：app.js 的 figureLiftState 按"标题以下、进度条以上"那块
       可用区算，相纸能长到 ~1.45 倍并且居中，角度回正成 0；
     · 背景：其它照片 + 人物说明 + 标题 + 提示全部压暗 **并施加 filter: blur()**。
       注意这里不用 backdrop-filter —— 基线 Chrome 61（Android 8.1 出厂 WebView）
       完全不认它（Chrome 76 才有），只认的话在老机器上等于什么都没做；
       filter: blur() 是 CSS Filter Effects 的老成员，Chrome 18 起就有。
   ========================================================================== */

/* 其它照片：退到焦外 */
.figure-stage.is-zoomed .figure-shot:not(.is-lifted) {
  opacity: .3;
  filter: brightness(.42) blur(6px);
}

/* 人物说明 / 滑动提示 / 标题：跟着一起糊。
   标题只糊文字本身，右上角的关闭按钮保持清晰 —— 那是放大态唯一的"出口"。 */
.figure-caption,
.figure-swipe-hint,
.sheet-title,
.sheet-meta,
.figure-progress {
  transition: opacity .34s ease, filter .34s ease;
}

.sheet-mask.is-zoomed .figure-caption,
.sheet-mask.is-zoomed .figure-swipe-hint,
.sheet-mask.is-zoomed .sheet-title,
.sheet-mask.is-zoomed .sheet-meta {
  opacity: .3;
  filter: blur(3px);
}

.sheet-mask.is-zoomed .figure-progress { opacity: .28; }

/* 放大态下左右按钮会被相纸盖住，索性收掉：再点一下照片就是退回叠放 */
.sheet-mask.is-zoomed .figure-nav { opacity: 0; pointer-events: none; }

/* ==========================================================================
   2026-09-24 换镜「闪一下」的真正根因：CSS transition 与 GSAP 抢同一批属性
   ==========================================================================
   剧情窗里这几个元素的 opacity / transform 全部由 GSAP 逐帧写行内样式：
     .asset-slot（照片层）、.story-photo-ghost（旧图垫底）、
     .print-caption（文案）、.story-continue（继续）、.choice-zone（抉择区）
   而它们身上又各挂了一条 CSS transition。两边同时改同一个属性时，
   浏览器会把 GSAP 写下的新值当成"过渡目标"，从旧值慢慢爬过去 ——
   于是换图那一瞬：GSAP 把新图设成 0、再逐帧淡上来，
   CSS 却把 0 当目标从 1 往回拖，新图先被拽暗、再慢慢爬回来，
   看上去就是"闪一下 / 图片先暗再亮"。
   这一批属性统一交给 GSAP，CSS 不再插手。
   ========================================================================== */

#scene-stack,
.scene-print .asset-slot,
.story-photo-ghost,
.print-caption,
.print-caption.is-beat,
.story-continue,
#screen-story .choice-zone {
  transition: none !important;
}

/* ==========================================================================
   2026-09-24 图鉴改版：不做"卡片"，做一叠摊在暗桌上的实体照片（参考图 2）
   ==========================================================================
  原来每张照片外面套了一层深色卡纸（.figure-mask 的径向底 + 重暗角 + 内阴影），
  照片看起来像"卡片/海报"。现在整层卡纸拿掉：
     · 照片自己就是相纸，四角只留一点点圆，边上一道投影把它压回桌面；
     · 三张照片错开角度叠在一起，最上面那张完整露出，底下两张各露出一角；
     · 照片上不写字（左下角那行场次字按反馈撤掉了），只留右下角"第几张"。
   人物名与身份放在照片叠外面（.figure-caption），永远正着排。
   ========================================================================== */

/* 桌面：干净的暗底。
   这里原来还有一团 radial-gradient 的"环境光"，在暗底上会显出一块有边界的亮区，
   玩家看到的"照片底下有个半透明底、框边看得见"就是它 + 展台颗粒层拼出来的。
   展台不再画任何底色，只留面板自己的底。 */

/* 相纸本体：没有卡纸、没有暗角，只有照片 + 一道落影 */
.figure-portrait {
  position: relative;
  display: block;
  /* 四个方向明确写 auto：相纸靠父层 flex 居中，
     旧定义里那组 top/right/bottom/left 百分比要在这里彻底断掉。 */
  top: auto;
  right: auto;
  bottom: auto;
  left: auto;
  height: 354.16px;
  max-height: 322px;
  /* 3:4.35 的相纸：宽度由高度倒推，Chrome 61 也准 */
  width: calc(354.16px * 3 / 4.35);
  max-width: 318.2px;
  margin: 0;
  overflow: hidden;
  border-radius: 2px;
  background: #0d0c0c;
  box-shadow: 0 16px 30px rgba(0,0,0,.62), 0 2px 6px rgba(0,0,0,.5);
  transform: none;
}

.figure-photo {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%;
  border-radius: inherit;
  filter: saturate(.97) contrast(1.05);
}

/* 底下的两张只露边角，稍微压暗一点，视线自然落在最上面那张 */
.figure-shot:not(.is-top) .figure-portrait {
  filter: brightness(.74) saturate(.9);
  box-shadow: 0 12px 24px rgba(0,0,0,.55);
}

/* 相纸上的字：左下角那行场次字按反馈删掉（DOM 里也不再生成），只留右下角"第几张" */
.figure-shot:not(.is-top) .figure-shot-count { display: none; }

.figure-shot-count { right: 10px; bottom: 9px; }

/* 人物说明：照片叠之外，正着排 */
.figure-caption {
  display: grid;
  grid-gap: 4px;
  gap: 4px;
  flex: 0 0 auto;
  padding: 12px 18px 4px;
  text-align: center;
}

.figure-caption .figure-name { font-size: 18px; }

/* ==========================================================================
   2026-09-24 修正二：照片守 9:16，窗底不够的部分渐隐成黑；文案让开按钮
   ==========================================================================
   分镜图本身是 1008×1792（9:16），剧情窗比 9:16 更"窄高"。
   上一版让照片铺满整扇窗，等于把 9:16 的图 cover 拉伸裁剪了 —— 比例被破坏。
   现在照片按宽度顶到窗上沿、保持 9:16，差额留在窗底；
   那一段不画硬边，改成"照片下沿渐隐进黑底"，
   黑底正好把剧情文字和「继续」衬清楚。
   ========================================================================== */

/* ① 照片层自己守 9:16、顶上贴边；整扇窗的其余部分（文案/按钮/抉择区）以窗为基准。
      之前是"照片铺满整扇窗"，等于把 9:16 的图 cover 拉伸裁剪了。 */
.scene-print .asset-slot,
.story-photo-ghost {
  top: 0;
  left: 0;
  right: 0;
  bottom: auto;
  width: 100%;
  /* 9:16 比例盒：高度由 padding-top 撑出来（百分比相对父级宽度），Chrome 61 可用 */
  height: 0;
  padding-top: 177.78%;
  /* 上沿与两侧干净，只有下沿渐隐成黑（不再是四周一圈径向暗角） */
  -webkit-mask-image: linear-gradient(to bottom,
    #000 0%, #000 72%,
    rgba(0, 0, 0, .88) 82%,
    rgba(0, 0, 0, .56) 91%,
    rgba(0, 0, 0, .22) 97%,
    transparent 100%);
  mask-image: linear-gradient(to bottom,
    #000 0%, #000 72%,
    rgba(0, 0, 0, .88) 82%,
    rgba(0, 0, 0, .56) 91%,
    rgba(0, 0, 0, .22) 97%,
    transparent 100%);
}

/* 照片下方那截留白：纯黑起底，和照片下沿的渐隐接上，看不出接缝 */
.scene-photo,
.scene-print { background: #000; }

/* ③ 文案上方的标题改成表格里的「剧情短句」（4~6 字），
      原来是「序章 · 01-02」这种小字，现在字要撑得住"标题"这个身份：
      字号提到 12px、字距收窄一点（中文 4 个字用 .18em 会散成一排点）。 */
.print-caption.is-beat .print-caption-label,
.print-caption-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  color: rgba(240, 179, 82, .97);
}

/* ==========================================================================
   2026-09-24 修正三：首页圆钮在"还没选人"的初始状态下长按无效
   ==========================================================================
   弧线正中 = 未选择（homeFilm.chosen 为 null）。这时候长按必须没反应，
   必须先真的把圆钮滑到「小美」或「小帅」那一端。
   拒绝时给一点反馈，否则"按了没反应"会被当成故障：
   两颗名字左右抖一下、暗一档，配一句提示语（toast 在 app.js 的 refuseHomeEnter）。
   注意不要用 GSAP 去动 .arc-thumb 的 transform —— 它的位移是靠 CSS 变量
   --thumb-x / --thumb-y 表达的，行内 transform 会把它整个冲掉。
   这里改用独立的 translate 属性做关键帧，和元素原有的 transform 叠加，互不干扰。
   ========================================================================== */

@keyframes homeRefuseShake {
  0%, 100% { transform: translate(-50%, -50%); }
  18%      { transform: translate(-50%, -50%) translateX(-5px); }
  42%      { transform: translate(-50%, -50%) translateX(5px); }
  68%      { transform: translate(-50%, -50%) translateX(-3px); }
}

@keyframes homeRefuseDim {
  0%, 100% { opacity: 1; }
  45%      { opacity: .28; }
}

#screen-home.is-refused .home-fan .fan-tick {
  animation:
    homeRefuseShake .44s cubic-bezier(.36, .07, .19, .97),
    homeRefuseDim .44s ease;
}

/* 拒绝时圆钮跟着轻轻一缩，手指能感觉到"没吃进去" */
@keyframes homeRefusePress {
  0%, 100% { transform: translate(var(--arc-nudge-x, 0px), var(--arc-nudge-y, 0px)) scale(1); }
  40%      { transform: translate(var(--arc-nudge-x, 0px), var(--arc-nudge-y, 0px)) scale(.96); }
}

#screen-home.is-refused .arc-center {
  animation: homeRefusePress .34s cubic-bezier(.36, .07, .19, .97);
}

/* ② 文案：底部让出「继续」按钮的高度（bottom:12px + 钮高 36px ≈ 48px），
      文字底边落在按钮之上，再也不会被压住；底衬也压得更实一点。 */
.print-caption,
.print-caption.is-beat {
  padding: 56px 20px 60px;
  background: linear-gradient(to top,
    rgba(3, 2, 2, .97) 0%,
    rgba(3, 2, 2, .93) 30%,
    rgba(3, 2, 2, .78) 56%,
    rgba(3, 2, 2, .48) 80%,
    rgba(3, 2, 2, 0) 100%);
}
/* 展台底色：见上方说明，这里不再画环境光（原来这条是上面那段的重复定义）。 */

/* 底下那行"小幅滑动换照片"是绝对定位在画廊底部的，给文案留出它的位置 */
.figure-gallery { padding-bottom: 18px; }

/* ==========================================================================
   Chrome 61 布局基线：Grid gap 用 grid-gap，Flex gap 用子项 margin 兜底
   ==========================================================================
   容器最低兼容 Android 8.1 出厂 Chrome / WebView 61：
     · Grid 的 gap 简写是 Chrome 66 才有的，61 只认 grid-gap；
     · Flex 的 gap 是 Chrome 84 才有的，61 上完全无效。
   所以：Grid 补一条 grid-gap；Flex 先按子项单边 margin 排（基线），
   再由 app.js 用真实布局行为检测给 <html> 加 .supports-flex-gap，
   命中时才改用 gap 并把兜底 margin 清掉。
   ========================================================================== */

/* Grid：补 Chrome 61 认识的 grid-gap（与上面的 gap 等价） */
.vertical-title { grid-gap: 1px; }
.home-meta { grid-gap: 4px; }
.cinema-look { grid-gap: 8px; }
.reminder-body { grid-gap: 14px; }
.reminder-list { grid-gap: 14px; }
.reminder-foot { grid-gap: 8px; }
.verse-title { grid-gap: .18em; }
#screen-story { grid-gap: 6px; }
.flip-front { grid-gap: 0; }
.game-chrome { grid-gap: 8px; }
.choice-zone { grid-gap: 2px 4px; }
.ending-caption { grid-gap: 9px; }
.ending-poem { grid-gap: 1px; }
.ending-foot { grid-gap: 8px; }
.ending-actions { grid-gap: 7px; }
.confirm-actions { grid-gap: 9px; }
.figure-text { grid-gap: 4px; }
.figure-progress { grid-gap: 10px; }
.tree-node { grid-gap: 3px; }
.alt-route { grid-gap: 5px; }
.figure-caption { grid-gap: 4px; }

/* Flex 基线：子项单边 margin（Chrome 61 可用） */
.home-pull-cue > * + * { margin-top: 9px; }
.home-hint > * + * { margin-left: 8px; }
.home-hint-lines > * + * { margin-top: 3px; }
.reminder-confirm > * + * { margin-left: 8px; }
.verse-choices > * + * { margin-left: 14px; }
.chrome-slot > * + * { margin-top: 6px; }
.chapter-meter > * + * { margin-left: 3px; }
.story-continue > * + * { margin-left: 6px; }
.choice-list > * + * { margin-top: 7px; }
.ending-wrap > * + * { margin-top: 10px; }
.ending-head > * + * { margin-left: 8px; }
.mark-row > * + * { margin-left: 6px; }
.sheet-head > * + * { margin-left: 9px; }
.storyline-head > * + * { margin-left: 8px; }

/* Flex 增强：实测 Flex gap 真的生效时，撤掉兜底 margin 改用 gap */
.supports-flex-gap .home-pull-cue { gap: 9px; }
.supports-flex-gap .home-pull-cue > * + * { margin-top: 0; }
.supports-flex-gap .home-pull-cue > * + * { margin-left: 0; }
.supports-flex-gap .home-hint { gap: 8px; }
.supports-flex-gap .home-hint > * + * { margin-top: 0; }
.supports-flex-gap .home-hint > * + * { margin-left: 0; }
.supports-flex-gap .home-hint-lines { gap: 3px; }
.supports-flex-gap .home-hint-lines > * + * { margin-top: 0; }
.supports-flex-gap .home-hint-lines > * + * { margin-left: 0; }
.supports-flex-gap .reminder-confirm { gap: 8px; }
.supports-flex-gap .reminder-confirm > * + * { margin-top: 0; }
.supports-flex-gap .reminder-confirm > * + * { margin-left: 0; }
.supports-flex-gap .verse-choices { gap: 14px; }
.supports-flex-gap .verse-choices > * + * { margin-top: 0; }
.supports-flex-gap .verse-choices > * + * { margin-left: 0; }
.supports-flex-gap .chrome-slot { gap: 6px; }
.supports-flex-gap .chrome-slot > * + * { margin-top: 0; }
.supports-flex-gap .chrome-slot > * + * { margin-left: 0; }
.supports-flex-gap .chapter-meter { gap: 3px; }
.supports-flex-gap .chapter-meter > * + * { margin-top: 0; }
.supports-flex-gap .chapter-meter > * + * { margin-left: 0; }
.supports-flex-gap .story-continue { gap: 6px; }
.supports-flex-gap .story-continue > * + * { margin-top: 0; }
.supports-flex-gap .story-continue > * + * { margin-left: 0; }
.supports-flex-gap .choice-list { gap: 7px; }
.supports-flex-gap .choice-list > * + * { margin-top: 0; }
.supports-flex-gap .choice-list > * + * { margin-left: 0; }
.supports-flex-gap .ending-wrap { gap: 10px; }
.supports-flex-gap .ending-wrap > * + * { margin-top: 0; }
.supports-flex-gap .ending-wrap > * + * { margin-left: 0; }
.supports-flex-gap .ending-head { gap: 8px; }
.supports-flex-gap .ending-head > * + * { margin-top: 0; }
.supports-flex-gap .ending-head > * + * { margin-left: 0; }
.supports-flex-gap .mark-row { gap: 6px; }
.supports-flex-gap .mark-row > * + * { margin-top: 0; }
.supports-flex-gap .mark-row > * + * { margin-left: 0; }
.supports-flex-gap .sheet-head { gap: 9px; }
.supports-flex-gap .sheet-head > * + * { margin-top: 0; }
.supports-flex-gap .sheet-head > * + * { margin-left: 0; }
.supports-flex-gap .storyline-head { gap: 8px; }
.supports-flex-gap .storyline-head > * + * { margin-top: 0; }
.supports-flex-gap .storyline-head > * + * { margin-left: 0; }

/* ==========================================================================
   视口高度：932px 在地址栏收起 / 软键盘弹出时并不等于可视高度
   ==========================================================================
   app.js 的 updateAppHeight() 会把真实 innerHeight 写进 --app-height。
   这里“先 932px 兜底、再让变量覆盖”，两端都成立；不依赖 dvh（Chrome 108+）。 */
body { min-height: 932px; min-height: var(--app-height, 932px); }

.phone {
  height: 932px;
  max-height: 896px;
  height: var(--app-height, 932px);
}

/* 剧本里的长台词/长名字在某些机型上会撑破 flex 子项，按方向显式收一下 */
.print-caption-scene,
.figure-blurb,
.tree-node { min-width: 0; }

/* 照片层的 9:16 比例盒要压过 .asset-slot.has-image 里的 `padding: 0`
   （那条选择器是 3 个类，权重更高），所以这里再声明一次同权重/更高的选择器。 */
.scene-print .asset-slot,
.scene-print .asset-slot.has-image,
.scene-print .asset-slot.is-active,
.story-photo-ghost {
  height: 0;
  padding-top: 177.78%;
}

/* ==========================================================================
   2026-09-24 修正四：全屏自适应 + 让开容器自带导航栏
   ========================================================================== */

/* ① 全屏：原来锁死 width≤414 / height≤896，在 430×932 这类手机上四周会留黑边。
      现在直接铺满设备尺寸（高度用 --app-height 跟真实可视高度走）。 */
.phone {
  width: 100%;
  max-width: none;
  height: 932px;
  height: var(--app-height, 932px);
  max-height: none;
  box-shadow: none;
}

/* ② 容器（小红书小工具外壳）自带返回/分享按钮，是**浮在页面上面**的，
      不会给网页留位置。顶部按「状态栏安全区 + 容器导航栏」预留一条，
      剧情页的工具条与照片窗整体下移，避免两个按钮被盖住。
      基线写死 82px；支持 env() 的内核再叠加真实安全区（Chrome 61 不认 env，
      但 @supports 会让整块跳过，基线的 82px 仍然生效）。
      2026-09-24 第二轮：原来 66px + safe(=125px) 离容器那条返回/分享栏太远，
      中部空出一大块；改成 44 + safe ≈ 103px，图标刚好贴在容器栏下沿。 */
:root { --app-topbar: 0px; }

@supports (padding-top: env(safe-area-inset-top)) {
  :root {
    --app-topbar: var(--safe-area-inset-top, env(safe-area-inset-top, 0px));
  }
}

#screen-story,
#screen-ending { padding-top: var(--app-topbar); }

/* 首页左上角那枚开发标签原来只让开了状态栏（10px + safe ≈ 69px），
   正好落在容器那条返回/分享栏里，会被返回箭头压住。改成整条预留带之下。 */
@supports (padding-top: env(safe-area-inset-top)) {
  .preview-flag { top: calc(var(--app-topbar) + 6px); }
}

/* ==========================================================================
   2026-09-24 修正五：按截图逐条改（剧情图标抬升 / 照片不裁 / 结局页重排）
   ========================================================================== */

/* ① 剧情窗里的照片由 app.js 的 fitStoryPhotoBox() 按 9:16 算好行内尺寸，
      整张永远落在窗内；这里只保证「没跑 JS 之前」也有一个合理兜底，
      并且两侧多出来的黑边不要露出窗底那道纯黑以外的杂色。 */
.scene-print { background: #000; }

/* ② 结局页：整块（卡 + 下方按钮组）按顶部工具条下移，别再顶着状态栏/电池。
      卡片尺寸改成「先按可用高度定高、再反推 9:16 的宽」，
      这样背景图是原比例铺满，不会再被 cover 裁掉一截。 */
.ending-wrap {
  padding: var(--app-topbar) 14px 12px;
}

.ending-card {
  width: calc((var(--app-height, 932px) - var(--app-topbar) - 118px) * 9 / 16);
  height: calc(var(--app-height, 932px) - var(--app-topbar) - 118px);
  max-width: 100%;
  max-height: none;
}

.ending-foot {
  width: calc((var(--app-height, 932px) - var(--app-topbar) - 118px) * 9 / 16);
  max-width: 100%;
}

/* ③ 结局卡左上角：那枚「稀有度」胶囊整条撤掉，
      只留一行「结局 G」，颜色/字体跟剧情页的「序章」一致。 */
.ending-rarity { display: none; }

.ending-head {
  justify-content: flex-start;
  padding-top: 2px;
}

.ending-letter {
  font-family: var(--hand);
  font-size: 16px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: .06em;
  color: var(--chapter-ink);
  text-shadow: 0 1px 0 rgba(0, 0, 0, .92), 0 0 10px rgba(217, 169, 79, .28);
}

/* ④ 落款：书法下面的红底「醒」换成黑体黄字一行（「这个小美/小帅能谈吗？」） */
.ending-card.has-image .ending-caption::after { display: none; }

/* 没有底图时（分镜缺失）落款居中排，不要吊在右下角 */
.ending-caption { justify-items: center; }
.ending-card.has-image .ending-caption { justify-items: end; }

/* ⑤ 全局提示条：结局页的「已保存到相册」这类反馈走这里，写在屏幕上层的底部 */
.app-toast {
  position: absolute;
  z-index: 320;
  left: 50%;
  /* 结局页底部那排按钮高约 45px + 12px 内边距，提示条要浮在它们上面才不会盖住按钮 */
  bottom: calc(96px + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
  max-width: 76%;
  margin: 0;
  padding: 10px 16px;
  border: 1px solid rgba(240, 179, 82, .44);
  border-radius: 999px;
  background: rgba(12, 7, 4, .9);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: 0 12px 30px rgba(0, 0, 0, .6);
  font-family: var(--sans);
  font-size: 12.5px;
  line-height: 1.35;
  letter-spacing: .04em;
  text-align: center;
  color: #ffe3ad;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateX(-50%) translateY(8px);
  transition: opacity .26s ease, transform .26s cubic-bezier(.16, 1, .3, 1), visibility 0s linear .26s;
}

.app-toast.is-on {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
  transition-delay: 0s;
}

/* Chrome 61 不认 env()：上面那条带 env 的声明会被整条丢掉，
      这里补一条纯 var 的兜底，保证提示条永远在屏幕里。 */
@supports not (padding-top: env(safe-area-inset-top)) {
  .app-toast { bottom: 96px; }
}

/* ⑥ 照片下沿的渐隐收短一点：照片现在是「整张落在窗里」，下沿离窗底还有一截，
      原来从 72% 就开始化，等于把画面下四分之一又吃掉一遍。改成 78% 起、
      更浅一档，整张 9:16 的画面基本都看得见，只有最底那几像素融进黑底。 */
.scene-print .asset-slot,
.story-photo-ghost {
  -webkit-mask-image: linear-gradient(to bottom,
    #000 0%, #000 78%,
    rgba(0, 0, 0, .9) 87%,
    rgba(0, 0, 0, .6) 94%,
    rgba(0, 0, 0, .24) 98%,
    transparent 100%);
  mask-image: linear-gradient(to bottom,
    #000 0%, #000 78%,
    rgba(0, 0, 0, .9) 87%,
    rgba(0, 0, 0, .6) 94%,
    rgba(0, 0, 0, .24) 98%,
    transparent 100%);
}

/* ==========================================================================
   2026-09-24 修正六：首页操作区放大 / 提醒页与剧情字放大 /
                    结局卡重排 / 图鉴大改
   ========================================================================== */

/* ---------- ① 首页"选择操作"整块放大一档 ---------- */
.home-fan-wrap {
  right: 20px;
  bottom: 84px;
  width: 216px;
}

.home-fan-wrap .home-fan {
  width: 188px;
  height: 178px;
}

.home-fan .fan-tick {
  padding: 7px 11px;
  font-size: 18px;
}

.home-fan .arc-center {
  right: 13px;
  bottom: 11px;
  width: 88px;
  height: 88px;
  font-size: 14.5px;
}

.home-fan .arc-thumb {
  width: 17px;
  height: 17px;
}

/* 说明图标也一起放大；黄钮和钮前那颗小球现在沿同一条弧一起走 */
.home-hint { right: 8px; margin-top: 14px; }
.home-hint-icon { width: 44px; height: 40px; }
.home-hint-text { font-size: 15px; }
.home-hint-text.is-second { font-size: 13.5px; }

/* 曾经把「钮 + 小球」塞进同一个 <g class="home-hint-runner"> 整组平移，
   结果两点压在一起、也看不出谁在弧上谁在弧下 —— 这版拆回两个独立运动的点，
   动画定义统一放在文件上方 ① 那一段，这里不再覆盖。 */

/* ---------- ② 提醒页：两条正文 + 底部提示都放大 ---------- */
.reminder-list li { font-size: 15.5px; line-height: 1.82; }
.reminder-list li::before { top: 4px; width: 16px; height: 16px; font-size: 9.5px; }
.reminder-tag { font-size: 16.5px; }
.reminder-hint { font-size: 13.5px; letter-spacing: .08em; }
.reminder-confirm { font-size: 15.5px; padding: 13px 26px 13px 28px; }

/* ---------- ③ 剧情页：照片下方的剧情文字与标题都放大一档 ---------- */
.print-caption.is-beat .print-caption-scene { font-size: 17px; line-height: 1.78; }
.print-caption-label,
.print-caption.is-beat .print-caption-label { font-size: 13.5px; }

/* ---------- ④ 结局卡 ---------- */
/* 「结局 A」换成首页标题那套字（JixiangSong），字号抬起来 */
.ending-letter {
  font-family: var(--serif);
  font-size: 23px;
  font-weight: 600;
  letter-spacing: .04em;
}

/* 落款改成暗红圆章 + 镂空「喜」：字是掏空的，底图从笔画里透出来 */
.ending-sigil {
  display: block;
  width: 42px;
  height: 42px;
  margin: 4px 0 0 auto;
  filter: drop-shadow(0 4px 12px rgba(0, 0, 0, .7));
}

.ending-sigil svg { display: block; width: 100%; height: 100%; }

/* 右上角：跟首页同款排版同款字体的标题，压到很淡，不抢画面 */
.ending-brand {
  position: absolute;
  top: 15px;
  right: 16px;
  z-index: 2;
  display: grid;
  grid-gap: 1px;
  gap: 1px;
  font-family: var(--serif);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.16;
  letter-spacing: .02em;
  text-align: right;
  color: rgba(255, 250, 242, .62);
  text-shadow: 0 2px 12px rgba(0, 0, 0, .85);
  opacity: .68;
  pointer-events: none;
}

.ending-brand span { display: block; }

.ending-brand em { font-style: normal; }

/* 小美/小帅按首页那套配色来：小美粉、小帅蓝（首页 .vertical-title.is-woman/.is-man 同色号），
   带一点点同色辉光，压得再暗也认得出是哪条线。 */
.ending-brand em.is-woman {
  color: #ffd4cf;
  text-shadow: 0 0 18px rgba(255, 103, 104, .52), 0 2px 10px rgba(0, 0, 0, .85);
}

.ending-brand em.is-man {
  color: #8ee6ff;
  text-shadow: 0 0 18px rgba(91, 195, 255, .58), 0 2px 10px rgba(0, 0, 0, .85);
}

/* ---------- ⑤ 人物图鉴：面板 689.68px，底边固定（越高越往上），叠放相纸 391.44px / 372px 上限。
       点按放大的倍率不在这里写死，按"标题下沿 → 说明区底沿"现算，
       上限是面板宽的 92%（见 app.js 的 figureLiftState），
       并且放大态是"以叠放位置为中心长在原地"，不跳位。 ---------- */
.sheet-card {
  height: 689.68px;
  max-height: 700px;
}

.figure-portrait {
  height: 391.44px;
  max-height: 372px;
  width: calc(391.44px * 3 / 4.35);
  max-width: 344px;
}

.figure-shot-count { font-size: 10px; }

.figure-nav {
  top: 38%;
  width: 38px;
  height: 38px;
  font-size: 22px;
}

/* 双指缩放要在 pointer 事件里自己做，交给浏览器就收不到 pointermove 了 */
.figure-gallery { touch-action: none; }

/* 点按放大：原地放大，角度与错位都不动。位移 / 倍率 / 摆正与否全部由 GSAP 写，
   CSS 不参与 transform（见 app.js 的 figureApplySlots / toggleFigureLift）。 */

/* ==========================================================================
   2026-09-24 修正三（第二轮反馈逐条）
   ========================================================================== */

/* ⑦ 抉择区：选项文字大一点（13 → 15.5），A/B/C 角标跟着抬一档。
   弧上的字母刻度（.fan-tick）不动 —— 它的半径与居中位移是 JS 算的，
   改尺寸会连着弧线对位一起偏。 */
.arc-option { font-size: 15.5px; }

.option-letter {
  min-width: 18px;
  height: 18px;
  font-size: 10px;
  margin-right: 8px;
}

.dial-note { font-size: 11.5px; }
