/* 人生模拟器 · 视觉与交互样式
 *
 * 方向：「知乎蓝 · 答卡」——白底、知乎蓝 #1772F6、亮蓝 #52D9FE（只进渐变与光晕，不压字）。
 * 界面语气是一篇正在被写出来的知乎回答：顶上一条品牌渐变细线，一枚阶段标与三段进度，
 * 正文卡片偏左，桌面端右侧多一栏「你走过的路」（记下你每一次取舍与那个危机）。
 *
 * 两条不能动的结构约束（改动前先看这两条）：
 *  1. #panel 必须是唯一的滚动容器，且下边界停在 --stand-h 上方（卡片区离画框下沿只留 16px）——剧情页的滚动规则
 *     （js/ui.js 的 storyScroll，自检工具 frontend/tools/ui-scroll-check.mjs）按它量。
 *  2. #char 是「卡头」：趴在正文卡片的上沿，上半身探出来、下半身被卡片压住。它不进页面底部、不出画框、
 *     只被卡片遮——窄屏站在 HUD 下面那条「卡头带」里，桌面由 js/ui.js 的 placeMascot() 跟着卡片上沿走
 *     （上下各夹一道）。改角色位置前先读 docs/视觉与交互规范.md §5.2。
 *
 * 主题：亮色是默认（:root = 白纸 + 知乎蓝），暗色是知乎夜间（[data-theme="dark"] = 近黑 + 提亮蓝）。
 * 两套色值都过了 4.5:1（文字）与 3:1（焦点环、蓝色图形标记），含「半透明卡片压在照片上」的
 * 最坏情况——用 tools/theme-contrast-check.mjs 复核；--brand-sky 只做渐变与光晕，
 * 不承担可读性，所以那个工具没有、也不该给它设阈值。
 */

:root {
  color-scheme: light;

  /* —— 知乎品牌三色：主蓝 / 亮蓝 / 白 ——
     主蓝 #1772F6 压白底只有 4.42:1，差 0.08 不到 AA，所以「小字」和「实心按钮底」另用同一色相
     压深的 --brand-deep（5.7:1）。这不是两套蓝，是一套蓝的两个明度档。 */
  --brand: #1772f6;
  --brand-deep: #0a62d0;
  --brand-ink: #0a62d0;
  --brand-sky: #52d9fe;
  --brand-soft: rgba(23, 114, 246, 0.08);
  --brand-on: #ffffff;
  /* 渐变按钮（窄屏抽屉里的「重新开始」）的两个色站：深 → 亮。两端都按「白字压得住」挑——
     深端 5.7:1、亮端 4.6:1，所以渐变走到哪一格，压在它上面的白字都过 AA。
     亮蓝 --brand-sky 只做它脚下的光晕与上沿那道细线，不上按钮面（1.6:1 压不了字）。 */
  --brand-grad-deep: #0a62d0;
  --brand-grad-bright: #1670f0;

  /* —— 纸与墨 —— */
  --paper: #ffffff;
  --paper-deep: #f1f6fe;
  --card: rgba(255, 255, 255, 0.97);
  --card-solid: #ffffff;
  --ink: #121212;
  --ink-dim: #3d434b;
  --ink-faint: #656d78;
  --line: rgba(18, 24, 35, 0.1);
  --line-strong: rgba(18, 24, 35, 0.22);

  --danger: #c8281c;
  --danger-ink: #a81f14;
  --danger-soft: rgba(200, 40, 28, 0.08);

  /* —— 画面：压在图上的白纱、角色脚下的亮蓝光、上沿的压边 —— */
  --veil: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.97) 0%,
    rgba(255, 255, 255, 0.9) 18%,
    rgba(255, 255, 255, 0.5) 42%,
    rgba(255, 255, 255, 0.34) 66%,
    rgba(255, 255, 255, 0.52) 100%
  );
  --glow-color: rgba(82, 217, 254, 0.32);
  /* HUD 自带一层压边：画面上沿可能是雪地也可能是夜景，靠这一层把文字底子钉死，
     不指望薄纱在每个素材上都刚好够深（见 tools/theme-contrast-check.mjs 的 HUD 两项）。
     fade 那一档用同色 0 透明，避免「透明黑」把中间地带压浑。 */
  --hud-scrim: rgba(255, 255, 255, 0.9);
  --hud-scrim-fade: rgba(255, 255, 255, 0);
  --haze: rgba(82, 217, 254, 0.2);
  --char-shadow: 0 18px 28px -12px rgba(12, 52, 110, 0.4);
  --shadow: 0 18px 40px -26px rgba(10, 60, 140, 0.45), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
  --shadow-lift: 0 24px 44px -24px rgba(10, 60, 140, 0.5);
  /* 焦点环走「纸色留白 + 实心主色」两道：单靠半透明主色在白卡上会糊成一片（WCAG 2.4.11 要 3:1） */
  --focus: 0 0 0 3px var(--paper), 0 0 0 5px var(--brand);

  /* —— 字体：楷体给「时刻」（欢迎页大标题、危机名），黑体给正文与界面 —— */
  --font-body: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", "Source Han Sans SC", system-ui, sans-serif;
  --font-display: "Kaiti SC", "STKaiti", "KaiTi", "楷体", "Songti SC", "Noto Serif SC", "Source Han Serif SC", "SimSun", serif;
  --font-mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Courier New", monospace;

  --radius-lg: 18px;
  --radius: 14px;
  --radius-sm: 10px;

  /* 顶部品牌渐变细线的高度：HUD 与卡片区都要让开它 */
  --rule-h: 3px;
  /* HUD 那一行占多高：卡片区的上边界（= 压边下沿）与它共用同一个数，
     所以滚动内容正好被裁在压边结束的地方，不会从半透明的 HUD 里透出来。 */
  --hud-h: 62px;

  /* 刘看山的站位高度：卡片区在底部让出同样高的一条带，站着的那只才是看得见的。
     下界收在 158px：再小就只剩个头顶，玩家看不出「答完一题换了一次形象」。 */
  /* 卡片区离画框下沿只留一口气：文字贴底才符合阅读习惯（角色已经不在下面了，不必再让出一条站位带） */
  --stand-h: 16px;
  /* 刘看山压在卡片底下的那一截（placeMascot 读它来决定角色要多低才「坐在卡片上沿」） */
  --char-tuck: 58px;
  /* 顶部的「卡头带」：窄屏没有侧边空间，就在 HUD 下面留一条固定高度的带子给角色站，
     卡片区从带子下面开始（注意是 .panel 的 top 往下挪，不是 padding——padding 会跟着滚动，
     内容一滚就窜进带子里把角色盖住了）。桌面档另有办法（角色跟着卡片上沿走），这里是 0。 */
  --mascot-shelf: clamp(140px, 20dvh, 190px);
  /* 刘海屏底部安全区：footer 与加载胶囊共用，桌面端 inset 为 0 不会多出一条滚动条 */
  --safe-b: env(safe-area-inset-bottom, 0px);
  --footer-h: calc(48px + var(--safe-b));
}

/* 夜间：近黑（不是蓝黑），主色提亮到能在暗面上当文字用。 */
[data-theme="dark"] {
  color-scheme: dark;

  --brand: #4e9bff;
  /* 夜间这档要比亮色那一档浅：#1268E8 压最亮的卡片只有 2.98:1，差一点点够不到图形要求的 3:1，
     而白字压它又要 ≥4.5。往上抬一格（#1670F0）两个都过——4.6:1 / 3.3:1。 */
  --brand-deep: #1670f0;
  --brand-ink: #7cb4ff;
  --brand-sky: #52d9fe;
  --brand-soft: rgba(78, 155, 255, 0.14);
  --brand-on: #ffffff;
  /* 渐变按钮在近黑面上整体抬一格：深端用亮色那档的 #0A62D0 压纸底只有 2.9:1，
     按钮的左边角会糊进背景里；抬到 #0F66DC 是 3.5:1，白字压它仍有 5.3:1。 */
  --brand-grad-deep: #0f66dc;
  --brand-grad-bright: #1670f0;

  --paper: #121212;
  --paper-deep: #1a1c20;
  --card: rgba(30, 31, 34, 0.95);
  --card-solid: #1e1f22;
  --ink: #e8eaed;
  --ink-dim: #b4b8bf;
  --ink-faint: #8e939c;
  --line: rgba(232, 234, 237, 0.12);
  --line-strong: rgba(232, 234, 237, 0.24);

  --danger: #ff8a7d;
  --danger-ink: #ffb4aa;
  --danger-soft: rgba(255, 138, 125, 0.12);

  --veil: linear-gradient(
    180deg,
    rgba(14, 15, 17, 0.95) 0%,
    rgba(14, 15, 17, 0.85) 20%,
    rgba(14, 15, 17, 0.42) 44%,
    rgba(14, 15, 17, 0.3) 68%,
    rgba(14, 15, 17, 0.55) 100%
  );
  --glow-color: rgba(82, 217, 254, 0.16);
  --hud-scrim: rgba(18, 18, 18, 0.9);
  --hud-scrim-fade: rgba(18, 18, 18, 0);
  --haze: rgba(78, 155, 255, 0.16);
  --char-shadow: 0 18px 30px -12px rgba(0, 0, 0, 0.66);
  --shadow: 0 18px 40px -26px rgba(0, 0, 0, 0.72), 0 1px 0 rgba(255, 255, 255, 0.04) inset;
  --shadow-lift: 0 24px 46px -22px rgba(0, 0, 0, 0.8);
  --focus: 0 0 0 3px var(--paper), 0 0 0 5px var(--brand);
}

* {
  box-sizing: border-box;
}

/* .loading / .errorbox 用了 display:flex|grid，会盖掉浏览器默认的 [hidden]，这里显式兜住 */
[hidden] {
  display: none !important;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  /* 只让底色与文字色随主题过渡，别把整页属性都挂上 transition（滚动时会卡） */
  transition: background-color 0.3s ease, color 0.3s ease;
}

/* 页面底纸：顶上落一团亮蓝雾（#52D9FE 的第二次出场），往下化进纸色。
   手机上被画面整块盖住，桌面上是画框外的那圈底色。 */
.app {
  min-height: 100dvh;
  display: grid;
  grid-template-rows: 1fr auto;
  background-color: var(--paper);
  background-image: radial-gradient(90% 46% at 50% 0%, var(--haze), transparent 70%);
  background-repeat: no-repeat;
}

/* ————————————————— 舞台：手机全屏沉浸，桌面收成一张画框 ————————————————— */

.stage {
  position: relative;
  width: 100%;
  /* 双写一份：老浏览器不认识 env() 时也不会把整条 min-height 丢掉 */
  min-height: calc(100dvh - 48px);
  min-height: calc(100dvh - var(--footer-h));
  overflow: hidden;
  isolation: isolate;
}

.stage__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  visibility: hidden;
  filter: brightness(1) saturate(1);
  transition: opacity 0.7s ease, filter 0.32s ease;
  z-index: 0;
}

.stage__bg.is-visible {
  opacity: 1;
  visibility: visible;
}

/* 薄纱：把插画压到能读字的程度，但中下段留一条让画面透出来（那是插画的脸面） */
.stage__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--veil);
}

/* 角色脚下的亮蓝光：让刘看山像站在灯下，而不是贴在图上的贴纸。
   光心跟着角色走（--glow-x / --glow-y 逐档在下面改），否则角色换了站位、光还留在中间。 */
.stage__glow {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: radial-gradient(58% 42% at var(--glow-x, 50%) var(--glow-y, 86%), var(--glow-color), rgba(82, 217, 254, 0) 72%);
  pointer-events: none;
  transition: opacity 0.32s ease;
}

/* 危机揭晓前让环境短暂收暗：只动背景，不把正文盖黑。盖章落下后画面恢复。 */
.app.is-crisis-revealing .stage__bg {
  filter: brightness(0.74) saturate(0.82);
}

.app.is-crisis-revealing .stage__glow {
  opacity: 0.46;
}

/* 顶部品牌渐变细线：整屏唯一一处「纯装饰的 #52D9FE」，一眼认出知乎蓝。
   压在 HUD 之上（z-index 6），滚动的卡片永远碰不到它。 */
.stage__rule {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--rule-h);
  z-index: 6;
  background: linear-gradient(90deg, var(--brand) 0%, var(--brand-sky) 76%, rgba(82, 217, 254, 0) 100%);
}

/* 刘看山：**卡头装饰**。它趴在正文卡片的上沿——上半身探出来挥手，下半身被卡片压住。
 *
 * 三条硬规则（用户提的，逐条对应到这里）：
 *  1. 不许出现在页面底部 → 它只在卡片上沿活动，脚下永远在卡片底下或被 --char-max-gap 兜住；
 *  2. 可以被页面元素遮挡、不许被可视区边界遮挡 → z-index 在卡片**之下**（卡片压它是对的），
 *     但 JS 的 placeMascot() 会在上下各夹一道：头不顶进 HUD，脚不贴到画框下沿，
 *     所以它不会被画框的边切到，横向也留在画面里（不再出血到框外）；
 *  3. 文字贴底 → 卡片区贴底（--stand-h 只剩 16px 的呼吸位），卡片因此从下往上长，
 *     角色的位置必须跟着卡片的上沿走，这就是 placeMascot() 存在的理由。
 *
 * 位置由 --char-left / --char-right / --char-top / --char-bottom / --char-h / --char-tf 给，
 * 基础档写在下面，各断点在自己的媒体查询里改尺寸与横向偏移。
 * --char-tf 用变量是为了让 bob 动画能带上各档自己的水平位移（transform 会被动画整个覆盖掉）。 */
.stage__char {
  position: absolute;
  left: var(--char-left, 3%);
  right: var(--char-right, auto);
  /* 窄屏：站在顶部那条固定带子里，脚踩着卡片区的上沿。
     桌面档由 placeMascot() 量出卡片上沿后写 inline 的 top 覆盖掉这里。 */
  top: var(--char-top, calc(var(--rule-h) + var(--hud-h)));
  bottom: var(--char-bottom, auto);
  height: var(--char-h, var(--mascot-shelf));
  max-width: 92%;
  object-fit: contain;
  object-position: bottom;
  --char-tf: translateX(0px);
  transform: var(--char-tf);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.7s ease;
  z-index: 2;
  pointer-events: none;
  filter: drop-shadow(var(--char-shadow));
}

.stage {
  --glow-x: 18%;
  --glow-y: 30%;
}

.stage__char.is-visible {
  opacity: 1;
  visibility: visible;
  /* 站定之后轻轻呼吸一下：让它看起来是活的，而不是一张图 */
  animation: bob 5.6s ease-in-out infinite;
}

/* —— 交叉淡化的上层（js/fader.js）：平时完全隐身，换图时新图在它上面淡入，
   落定后底层接管、它隐身待命。曲线 ease-in-out：两张图都在屏上，是 morphing 不是入场。 —— */
.stage__bg--alt,
.stage__char--alt {
  transition: opacity 0.7s cubic-bezier(0.455, 0.03, 0.515, 0.955);
}

/* 上层角色不呼吸：呼吸是「站定之后」的活气，淡入中的剪影再叠一个相位会出鬼影 */
.stage__char--alt.is-visible {
  animation: none;
}

/* ————————————————— HUD：阶段标 + 计数 + 三段进度 + 主题开关 —————————————————
 *
 * 桌面端它读起来像回答页的头部（左边是哪一段、右边是全局状态），
 * 手机端它压成一行：阶段名 + 计数占左侧，三段进度条与开关贴右侧。
 */

.hud {
  position: absolute;
  top: var(--rule-h);
  left: 0;
  right: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px 16px;
  /* 压边：上沿最实、向下化开，HUD 的文字因此不依赖素材的明暗 */
  background: linear-gradient(180deg, var(--hud-scrim) 0%, var(--hud-scrim-fade) 100%);
}

.hud__lead {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin: 0;
  min-width: 0;
}

/* 阶段标：一枚蓝色小方块 + 阶段名。不是胶囊、不带边框——上一次那种「一屏三个 chip」的
   芯片汤是通用感的来源之一。 */
.hud__step {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink);
  white-space: nowrap;
}

.hud__step::before {
  content: "";
  width: 6px;
  height: 14px;
  border-radius: 3px;
  background: linear-gradient(180deg, var(--brand), var(--brand-sky));
}

.hud__step:empty {
  display: none;
}

.hud__tail {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
}

.hud__progress {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.hud__progress:empty {
  display: none;
}

/* 三段进度：青年 ▮▯▯ 中年 ▮▮▯ 后半生 ▮▮▮。
   走过的一段是亮蓝、当前的一段是主蓝且更长、还没到的是浅灰。 */
.journey {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.journey__stop {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  transition: color 0.3s ease;
}

.journey__dot {
  width: 18px;
  height: 5px;
  border-radius: 999px;
  background: var(--line-strong);
  transition: background 0.3s ease, width 0.3s ease;
}

/* 手机上只留三段条：阶段名读屏仍能听到（视觉隐藏而不是 display:none） */
.journey__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}

.journey[data-stage="youth"] .journey__stop[data-stop="youth"],
.journey[data-stage="midlife"] .journey__stop[data-stop="midlife"],
.journey[data-stage="ending"] .journey__stop[data-stop="ending"] {
  color: var(--brand-ink);
}

.journey[data-stage="youth"] .journey__stop[data-stop="youth"] .journey__dot,
.journey[data-stage="midlife"] .journey__stop[data-stop="midlife"] .journey__dot,
.journey[data-stage="ending"] .journey__stop[data-stop="ending"] .journey__dot {
  width: 28px;
  background: var(--brand);
}

.journey[data-stage="midlife"] .journey__stop[data-stop="youth"] .journey__dot,
.journey[data-stage="ending"] .journey__stop[data-stop="youth"] .journey__dot,
.journey[data-stage="ending"] .journey__stop[data-stop="midlife"] .journey__dot {
  background: var(--brand-sky);
}

/* 主题开关：显示的是「按下去会变成什么」（亮色下显示月亮） */
.iconbtn {
  position: relative;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--card-solid);
  color: var(--ink-dim);
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease, background 0.18s ease, transform 0.18s ease;
}

.iconbtn__icon {
  grid-area: 1 / 1;
  width: 18px;
  height: 18px;
  transition: opacity 0.22s ease, transform 0.34s cubic-bezier(0.34, 1.56, 0.64, 1);
}

[data-theme="light"] .iconbtn__icon--sun,
[data-theme="dark"] .iconbtn__icon--moon {
  opacity: 0;
  transform: rotate(-38deg) scale(0.62);
}

[data-theme="light"] .iconbtn__icon--moon {
  transform: rotate(38deg) scale(0.62);
}

[data-theme="dark"] .iconbtn__icon--sun {
  transform: rotate(-38deg) scale(0.62);
}

/* ————————————————— 卡片区（唯一的滚动容器） ————————————————— */

.panel {
  position: absolute;
  /* 上边界落在 HUD 压边下沿再往下让出「卡头带」（而不是 top:0 + padding 顶开）：
     内容被裁在带子下面，既不会从半透明的压边里透出来，也窜不进带子里把角色盖住。
     下边界只留一口气——文字贴底才是读起来顺的那一种，角色已经不在下面了。 */
  top: calc(var(--rule-h) + var(--hud-h) + var(--mascot-shelf));
  left: 0;
  right: 0;
  bottom: var(--stand-h);
  z-index: 3;
  display: flex;
  flex-direction: column;
  /* 不写 justify-content: flex-end —— 它跟 overflow 一起用会把滚动内容的顶部裁掉 */
  padding: 10px 14px 8px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;

  /* 「上下边缘切得生硬」的解法：不叠一层白色蒙版（那会把背后的插画一起糊掉），
     而是让滚动容器自己的内容在两端渐隐——切口变成溶解口。
     只在那一侧真的还有内容时挂上（见 js/ui.js 的 syncScrollEdges），滚到头就恢复实边。 */
  --fade-top: 26px;
  --fade-bottom: 30px;
}

.panel.is-cuttop {
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--fade-top));
  mask-image: linear-gradient(180deg, transparent 0, #000 var(--fade-top));
}

.panel.is-cutbottom {
  -webkit-mask-image: linear-gradient(0deg, transparent 0, #000 var(--fade-bottom));
  mask-image: linear-gradient(0deg, transparent 0, #000 var(--fade-bottom));
}

.panel.is-cuttop.is-cutbottom {
  -webkit-mask-image: linear-gradient(
    180deg,
    transparent 0,
    #000 var(--fade-top),
    #000 calc(100% - var(--fade-bottom)),
    transparent 100%
  );
  mask-image: linear-gradient(180deg, transparent 0, #000 var(--fade-top), #000 calc(100% - var(--fade-bottom)), transparent 100%);
}

/* Firefox 用上面两个标准属性；Chromium 走下面这套：细滚动条 + 圆角滑块，
   并且去掉两端的箭头按钮（那个小三角在画框里很显眼，也没人会去点）。 */
.panel::-webkit-scrollbar {
  width: 8px;
}

.panel::-webkit-scrollbar-track {
  background: transparent;
}

.panel::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 999px;
}

.panel::-webkit-scrollbar-button {
  display: none;
}

/* 内容分栏的容器：手机上是一列（正文在上、「你走过的路」在下），桌面端把它挪到右侧一栏。
   margin-top: auto 让内容不足一屏时贴底（替掉 justify-content: flex-end）。 */
.panel__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  margin-top: auto;
}

/* 明确的换屏退场，和下一张卡自带的 rise 入场接成一段连续动作。 */
.panel__inner.is-leaving {
  pointer-events: none;
  animation: panel-leave 0.18s ease both;
}

.panel__main {
  min-width: 0;
}

.panel__rail {
  min-width: 0;
}

/* ————————————————— 卡片 ————————————————— */

.card {
  position: relative;
  background: var(--card);
  /* 卡片的边要比其它线更实一点：换一张明亮的插画做背景时，
     0.97 的纸白很容易和画面糊在一起，靠这道边把卡片的形状钉出来 */
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: 16px;
  box-shadow: var(--shadow);
  animation: rise 0.34s ease both;
}

/* 卡片上沿的一道品牌渐变（#1772F6 → #52D9FE）：全站统一的「这是知乎蓝」标记。
   从左边起画到 76% 处化开，所以不会变成一根横贯的粗线。 */
.card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 18px;
  right: 26%;
  height: 3px;
  border-radius: 0 0 3px 3px;
  background: linear-gradient(90deg, var(--brand) 0%, var(--brand-sky) 82%, rgba(82, 217, 254, 0) 100%);
  opacity: 0.9;
}

/* 剧情卡是逐段新增重绘的，卡片本身不能重播入场动画，否则每来一段就闪一下；
   节奏感交给 .story__text.is-new 的 fade-up。 */
.card--story {
  animation: none;
}

.card__title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 14px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--brand-ink);
}

.card__title::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--line-strong), transparent);
}

.card__tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 10px;
}

.tag {
  padding: 3px 8px;
  border-radius: 6px;
  font-size: 11.5px;
  letter-spacing: 0.04em;
  background: var(--brand-soft);
  color: var(--brand-ink);
}

/* 阶段标签（眼下 / 往后 / 到头来）：同一套蓝，靠字重与底色深浅分层 */
.tag--phase {
  background: var(--paper-deep);
  color: var(--ink-dim);
}

.card__scenario {
  margin: 0 0 12px;
  padding: 8px 12px;
  border-radius: 10px;
  border-left: 2px solid var(--brand);
  background: var(--brand-soft);
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--ink-dim);
}

.card__question {
  margin: 0 0 14px;
  font-size: 17.5px;
  line-height: 1.6;
  font-weight: 600;
  letter-spacing: 0.01em;
}

/* ————————————————— 选项：像投票选项那样带字母牌 ————————————————— */

.options {
  display: grid;
  gap: 8px;
}

.option {
  appearance: none;
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 11px;
  width: 100%;
  padding: 12px 14px;
  text-align: left;
  font: inherit;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--card-solid);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  overflow: hidden;
  transition: border-color 0.2s ease, background 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease,
    filter 0.2s ease;
}

/* 点击确认：蓝线从左到右走完这一拍；另外两项退后，避免用户怀疑是否点错。 */
.option::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--brand), var(--brand-sky));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.26s ease;
}

.options.is-committing {
  pointer-events: none;
}

.option.is-selected {
  border-color: var(--brand);
  background: var(--brand-soft);
  box-shadow: var(--shadow-lift);
  transform: translateY(-1px) scale(0.995);
}

.option.is-selected::after {
  transform: scaleX(1);
}

.option.is-selected .option__key {
  color: var(--brand-on);
  background: var(--brand);
  transform: scale(1.06);
}

.option.is-dimmed {
  opacity: 0.42;
  filter: saturate(0.55);
  transform: translateX(5px);
}

.option:disabled {
  cursor: default;
}

/* 选项控件的边界由这枚字母牌承担：蓝色压白卡片 4.4:1，够 WCAG 的 3:1 图形要求 */
.option__key {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  margin-top: 1px;
  border-radius: 6px;
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 700;
  transition: background 0.16s ease, color 0.16s ease, transform 0.16s ease;
}

.option__text {
  display: block;
  min-width: 0;
}

/* 按下要看得出来（拇指按下去时没有 hover 可依赖） */
.option:active {
  transform: scale(0.988);
  border-color: var(--brand);
  background: var(--brand-soft);
}

/* 悬停反馈只在真能悬停的设备上给（笔记本有，触屏不会留下粘住的 hover 态）；
   位移只给按钮自己（transform），不改尺寸，所以鼠标划过时布局不跳。 */
@media (hover: hover) {
  .option:not(:disabled):hover {
    border-color: var(--brand);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lift);
  }

  .option:not(:disabled):hover .option__key {
    background: var(--brand);
    color: var(--brand-on);
    transform: rotate(-6deg);
  }
}

.option:focus-visible,
.btn:focus-visible,
.iconbtn:focus-visible,
.footer__handle:focus-visible {
  outline: none;
  box-shadow: var(--focus);
}

/* ————————————————— 剧情正文 ————————————————— */

.story__text,
.ending__paragraph {
  margin: 0 0 12px;
  font-size: 15.5px;
  line-height: 1.95;
  color: var(--ink);
  /* 首行缩进两格：中文故事段落的样子 */
  text-indent: 2em;
}

.story__text:last-child,
.ending__paragraph:last-child {
  margin-bottom: 0;
}

/* 新到的这一段淡入上浮一下，读起来像一句句写上去的 */
.story__text.is-new,
.ending__paragraph.is-new {
  animation: fade-up 0.28s ease both;
}

/* 正在逐字书写的那一段：句尾一枚知乎蓝光标，硬闪烁（写完由 ui.js 摘掉 is-typing）。
   段落本身不再做 fade-up——逐字出现就是它的入场，两个动画叠播会闪。 */
.story__text.is-typing::after,
.ending__paragraph.is-typing::after {
  content: '';
  display: inline-block;
  width: 2px;
  height: 0.95em;
  margin-left: 3px;
  vertical-align: -0.12em;
  background: var(--brand);
  animation: caret-blink 1.1s linear infinite;
}

/* 正文还没到时占位用的三条灰杠：比一张空卡片像话，也不假装「正在写」的假字 */
.skeleton {
  display: grid;
  gap: 10px;
}

.skeleton__line {
  height: 11px;
  border-radius: 999px;
  background: var(--line-strong);
  animation: pulse 1.5s ease-in-out infinite;
}

.skeleton__line--short {
  width: 62%;
}

.skeleton__line:nth-child(2) {
  animation-delay: 0.18s;
}

.skeleton__line:nth-child(3) {
  animation-delay: 0.36s;
}

.reveal {
  display: grid;
  gap: 12px;
  margin-top: 18px;
}

.reveal__hint {
  margin: 0;
  font-size: 13px;
  color: var(--ink-faint);
}

/* 揭晓那一刻：像在纸上盖了一枚章 */
.stamp {
  display: grid;
  justify-items: center;
  gap: 2px;
  margin: 0;
  padding: 12px 16px;
  border: 2px solid var(--brand);
  border-radius: 12px;
  background: var(--brand-soft);
  transform: rotate(-1.4deg);
  animation: stamp 0.42s cubic-bezier(0.2, 1.5, 0.4, 1) both;
}

.stamp__label {
  font-size: 11px;
  letter-spacing: 0.22em;
  color: var(--brand-ink);
}

.stamp strong {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--ink);
}

/* 走过多少个中年：六个点，走过的填实 */
.trail {
  margin: 0;
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-dim);
}

.trail__dots {
  display: flex;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.trail__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1.5px solid var(--line-strong);
}

.trail__dot.is-seen {
  border-color: var(--brand);
  background: var(--brand);
}

.trail__dot.is-current {
  border-color: var(--brand);
  background: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.trail__hint {
  margin: 0;
  font-size: 12px;
  line-height: 1.7;
  color: var(--ink-faint);
}

/* ————————————————— 结局长卷：后半生 / 人间回声 / 你走过的路 ————————————————— */

/* 结局不再沿用「正文 + 右栏」：三个章节沿同一条阅读轴展开。 */
.panel[data-screen="ending"] .panel__inner {
  display: block;
  width: min(100%, 820px);
  margin: 0 auto;
}

.panel[data-screen="ending"] .panel__rail {
  display: none;
}

.ending {
  display: grid;
  gap: 18px;
}

.ending-chapter {
  position: relative;
  padding: 24px 20px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--card);
  box-shadow: var(--shadow);
  scroll-margin-top: 22px;
}

/* 后两章是滚动阅读节点：进入视野再出现，首章始终立即可读。 */
.reveal-on-scroll {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.58s ease, transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.reveal-on-scroll.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

.reveal-on-scroll.is-revealed .related__item,
.reveal-on-scroll.is-revealed .life-timeline__stage,
.reveal-on-scroll.is-revealed .ending-actions {
  animation: detail-rise 0.46s ease both;
}

.reveal-on-scroll.is-revealed .related__item:nth-child(2),
.reveal-on-scroll.is-revealed .life-timeline__stage:nth-child(2) {
  animation-delay: 0.08s;
}

.reveal-on-scroll.is-revealed .related__item:nth-child(3),
.reveal-on-scroll.is-revealed .life-timeline__stage:nth-child(3),
.reveal-on-scroll.is-revealed .ending-actions {
  animation-delay: 0.16s;
}

.ending-chapter::before {
  content: "";
  position: absolute;
  top: 0;
  left: 20px;
  width: 88px;
  height: 3px;
  border-radius: 0 0 3px 3px;
  background: linear-gradient(90deg, var(--brand), var(--brand-sky));
}

.ending-chapter--final {
  display: flex;
  min-height: clamp(440px, 68dvh, 650px);
  flex-direction: column;
  justify-content: center;
  padding-top: clamp(38px, 7vh, 66px);
  padding-bottom: clamp(30px, 6vh, 58px);
}

.ending-chapter__index {
  margin: 0 0 15px;
  color: var(--brand-ink);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
}

.ending__title {
  margin: 0 0 24px;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: clamp(30px, 7vw, 48px);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.08em;
}

.ending__prose {
  max-width: 680px;
}

.ending__paragraph {
  margin-bottom: 15px;
  font-size: clamp(16px, 2.4vw, 18px);
  line-height: 2.05;
}

.ending__coda {
  max-width: 680px;
  margin: 24px 0 0;
  padding-top: 19px;
  border-top: 1px solid var(--line);
  color: var(--ink-faint);
  font-family: var(--font-display);
  font-size: 14px;
  line-height: 1.8;
  letter-spacing: 0.04em;
}

.ending__continue {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 28px;
  padding: 8px 0;
  border: 0;
  color: var(--brand-ink);
  background: transparent;
  font: inherit;
  font-size: 12.5px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

.ending__continue span:last-child {
  font-size: 16px;
  animation: ending-nudge 1.8s ease-in-out infinite;
}

.ending__continue:focus-visible {
  outline: none;
  border-radius: 5px;
  box-shadow: var(--focus);
}

.ending-chapter__title,
.related__title {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: clamp(22px, 4vw, 30px);
  font-weight: 400;
  line-height: 1.45;
}

/* 第二章是延伸阅读：去掉旧版的「卡片套卡片」，只用细线分开不同人的声音。 */
.related {
  display: grid;
  gap: 11px;
}

.related__note,
.related__status {
  margin: 0;
  color: var(--ink-faint);
  font-size: 12.5px;
  line-height: 1.75;
}

.related__list {
  display: grid;
  margin-top: 10px;
}

.related__item {
  padding: 18px 0;
  border-top: 1px solid var(--line);
}

.related__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 12px;
  margin: 0 0 6px;
  color: var(--brand-ink);
  font-size: 11px;
}

.related__item-title {
  margin: 0 0 5px;
  color: var(--ink);
  font-size: 15.5px;
  line-height: 1.6;
}

.related__summary {
  margin: 0;
  color: var(--ink-dim);
  font-size: 13.5px;
  line-height: 1.85;
}

.related__link {
  display: inline-block;
  margin-top: 8px;
  color: var(--brand-ink);
  font-size: 12.5px;
  font-weight: 650;
  text-decoration: none;
}

.related__link:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.related__link:focus-visible {
  outline: none;
  border-radius: 4px;
  box-shadow: var(--focus);
}

/* 第三章的人生时间线：蓝点负责阶段，危机用一枚斜章强调，但不再额外套卡。 */
.life-timeline {
  position: relative;
  display: grid;
  gap: 0;
  margin: 25px 0 0;
  padding: 0;
  list-style: none;
}

.life-timeline::before {
  content: "";
  position: absolute;
  top: 9px;
  bottom: 25px;
  left: 5px;
  width: 1px;
  background: linear-gradient(var(--brand), var(--brand-sky), var(--line-strong));
}

.life-timeline__stage {
  position: relative;
  padding: 0 0 27px 29px;
}

.life-timeline__stage:last-child {
  padding-bottom: 0;
}

.life-timeline__dot {
  position: absolute;
  top: 6px;
  left: 0;
  width: 11px;
  height: 11px;
  border: 2px solid var(--card-solid);
  border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 0 0 2px var(--brand-soft);
}

.life-timeline__stage--later .life-timeline__dot {
  background: var(--brand-sky);
}

.life-timeline__label {
  margin: 0 0 9px;
  color: var(--brand-ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
}

.life-timeline__choices {
  display: grid;
  gap: 7px;
  margin: 0;
  padding: 0;
  color: var(--ink-dim);
  font-size: 13.5px;
  line-height: 1.65;
  list-style: none;
}

.life-timeline__choices li::before {
  content: "—";
  margin-right: 8px;
  color: var(--ink-faint);
}

.life-timeline__empty,
.life-timeline__later {
  margin: 0;
  color: var(--ink-faint);
  font-size: 13px;
  line-height: 1.7;
}

.life-timeline__crisis {
  display: inline-grid;
  gap: 2px;
  margin: 0 0 12px;
  padding: 8px 12px;
  border: 1px solid var(--brand);
  border-radius: 8px;
  background: var(--brand-soft);
  transform: rotate(-0.7deg);
}

.life-timeline__crisis span {
  color: var(--brand-ink);
  font-size: 9.5px;
  letter-spacing: 0.16em;
}

.life-timeline__crisis strong {
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 400;
}

.ending-trail {
  display: grid;
  gap: 8px;
  margin-top: 29px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}

.ending-actions {
  display: grid;
  gap: 12px;
  margin-top: 25px;
}

.ending-actions__archive {
  min-height: 50px;
  font-family: var(--font-display);
  font-size: 17px;
  letter-spacing: 0.08em;
}

.ending-actions__replay {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}

.ending-actions__replay .btn {
  width: 100%;
  font-size: 13px;
}

@media (min-width: 720px) {
  .ending-actions__replay {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  }
}

@keyframes ending-nudge {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(4px);
  }
}

/* ————————————————— 人生留影：结局的沉浸式回望与分享卡 ————————————————— */

body.has-life-archive {
  overflow: hidden;
}

.life-archive {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: max(14px, env(safe-area-inset-top)) 14px max(14px, env(safe-area-inset-bottom));
  opacity: 0;
  transition: opacity 0.28s ease;
}

.life-archive.is-open {
  opacity: 1;
}

.life-archive__backdrop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: rgba(7, 17, 32, 0.76);
  backdrop-filter: blur(13px) saturate(0.8);
  cursor: default;
}

.life-archive__sheet {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 12px;
  width: min(520px, 100%);
  max-height: 95dvh;
  padding: 15px;
  overflow-y: auto;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 22px;
  background: var(--card-solid);
  box-shadow: 0 30px 90px -20px rgba(0, 0, 0, 0.72);
  transform: translateY(24px) scale(0.97);
  transition: transform 0.42s cubic-bezier(0.22, 1, 0.36, 1);
  scrollbar-width: thin;
}

.life-archive.is-open .life-archive__sheet {
  transform: translateY(0) scale(1);
}

.life-archive__close {
  position: absolute;
  top: 25px;
  right: 25px;
  z-index: 5;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0 0 2px;
  border: 1px solid rgba(18, 24, 35, 0.15);
  border-radius: 50%;
  color: #33404d;
  background: rgba(255, 255, 255, 0.82);
  font: 300 25px/1 var(--font-body);
  cursor: pointer;
  backdrop-filter: blur(8px);
}

.life-archive__close:focus-visible {
  outline: none;
  box-shadow: var(--focus);
}

.life-card {
  position: relative;
  min-height: min(640px, 72dvh);
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  background: var(--paper-deep);
  color: #121212;
  isolation: isolate;
}

.life-card__bg,
.life-card__wash {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.life-card__bg {
  z-index: -3;
  object-fit: cover;
}

.life-card__wash {
  z-index: -2;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0.91) 46%, rgba(255, 255, 255, 0.98));
}

.life-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  width: 45%;
  height: 4px;
  background: linear-gradient(90deg, #1772f6, #52d9fe, transparent);
}

.life-card__body {
  position: relative;
  z-index: 2;
  display: flex;
  min-height: min(640px, 72dvh);
  flex-direction: column;
  padding: clamp(26px, 6vw, 42px);
}

.life-card__eyebrow,
.life-card__brand {
  margin: 0;
  color: #0a62d0;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
}

.life-card__title {
  max-width: 88%;
  margin: 12px 0 18px;
  font-family: var(--font-display);
  font-size: clamp(27px, 7vw, 38px);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: 0.04em;
}

.life-card__crisis {
  display: inline-grid;
  align-self: flex-start;
  gap: 2px;
  padding: 8px 12px;
  border: 1px solid #1772f6;
  border-radius: 9px;
  background: rgba(23, 114, 246, 0.08);
  transform: rotate(-0.7deg);
}

.life-card__crisis span {
  color: #0a62d0;
  font-size: 8.5px;
  letter-spacing: 0.12em;
}

.life-card__crisis strong {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 400;
}

.life-card__path {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
  margin-top: 22px;
}

.life-card__path h3 {
  margin: 0 0 8px;
  color: #0a62d0;
  font-size: 10px;
  letter-spacing: 0.16em;
}

.life-card__choices {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  color: #3d434b;
  font-size: clamp(10.5px, 2.7vw, 12.5px);
  line-height: 1.55;
  list-style-position: inside;
}

.life-card__empty {
  margin: 0;
  color: #656d78;
  font-size: 11px;
}

.life-card__coda {
  max-width: 68%;
  margin: auto 0 9px;
  padding-top: 16px;
  border-top: 1px solid rgba(18, 24, 35, 0.13);
  color: #656d78;
  font-family: var(--font-display);
  font-size: 11px;
  line-height: 1.7;
}

.life-card__char {
  position: absolute;
  right: -2%;
  bottom: 0;
  z-index: 1;
  width: 36%;
  max-height: 35%;
  object-fit: contain;
  object-position: right bottom;
  filter: drop-shadow(0 14px 20px rgba(10, 60, 140, 0.25));
}

.life-archive__actions {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 8px;
}

.life-archive__status {
  min-height: 1.5em;
  margin: 0;
  color: var(--ink-faint);
  font-size: 11.5px;
  line-height: 1.5;
  text-align: center;
}

@media (max-width: 480px) {
  .life-archive {
    padding-right: 8px;
    padding-left: 8px;
  }

  .life-archive__sheet {
    padding: 9px;
    border-radius: 18px;
  }

  .life-card__body {
    min-height: min(620px, 74dvh);
  }

  .life-archive__actions {
    grid-template-columns: 1fr;
  }
}

/* ————————————————— 你走过的路（桌面端右栏 / 手机端在剧情页尾） ————————————————— */

.archive {
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 14px 15px;
  box-shadow: var(--shadow);
  animation: rise 0.34s ease both;
}

.archive__head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--brand-ink);
}

.archive__head::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--line-strong), transparent);
}

.archive__group {
  margin: 0 0 12px;
}

.archive__group:last-of-type {
  margin-bottom: 0;
}

.archive__label {
  margin: 0 0 6px;
  font-size: 11px;
  letter-spacing: 0.16em;
  color: var(--ink-faint);
}

.archive__list {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.archive__item {
  position: relative;
  padding-left: 13px;
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--ink-dim);
}

.archive__item::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--brand);
  opacity: 0.75;
}

.archive__empty {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--ink-faint);
}

.archive__crisis {
  display: grid;
  gap: 2px;
  margin: 12px 0 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--brand-soft);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--ink-dim);
}

.archive__crisis strong {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--ink);
}

/* ————————————————— 欢迎页 ————————————————— */

.card--welcome {
  padding: 22px 20px;
}

.welcome__eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  font-size: 11.5px;
  letter-spacing: 0.24em;
  color: var(--brand-ink);
}

.welcome__eyebrow::after {
  content: "";
  width: 34px;
  height: 3px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--brand), var(--brand-sky));
}

.title {
  margin: 0 0 12px;
  font-family: var(--font-display);
  font-size: clamp(30px, 8vw, 40px);
  font-weight: 400;
  line-height: 1.24;
  letter-spacing: 0.04em;
}

.subtitle {
  margin: 0 0 16px;
  font-size: 14.5px;
  line-height: 1.75;
  color: var(--ink-dim);
}

/* 三站预览：一条横向时间线（数字 + 站名 + 引线），不是三枚 chip */
.welcome__stops {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 10px;
  margin: 0 0 18px;
  padding: 0;
  list-style: none;
}

.welcome__stop {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12.5px;
  color: var(--ink-dim);
}

.welcome__stop + .welcome__stop::before {
  content: "";
  align-self: center;
  width: 16px;
  height: 1px;
  margin-right: 4px;
  background: var(--line-strong);
}

.welcome__stop b {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--brand-ink);
}

.hint {
  margin: 14px 0 0;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--ink-faint);
}

/* ————————————————— 按钮 ————————————————— */

.btn {
  appearance: none;
  font: inherit;
  font-size: 15px;
  padding: 13px 20px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.16s ease, opacity 0.16s ease, background 0.16s ease, filter 0.16s ease, box-shadow 0.16s ease,
    border-color 0.16s ease, color 0.16s ease;
}

.btn:active {
  transform: scale(0.99);
}

.btn:disabled {
  opacity: 0.45;
  cursor: default;
}

/* 实心主按钮用 --brand-deep：白字压 #1772F6 只有 4.42:1，压深一档才到 5.7:1 */
.btn--primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  color: var(--brand-on);
  font-weight: 600;
  letter-spacing: 0.04em;
  background: var(--brand-deep);
  box-shadow: 0 12px 24px -14px rgba(10, 98, 208, 0.85);
}

.btn__arrow {
  width: 17px;
  height: 17px;
  transition: transform 0.2s ease;
}

.btn--ghost {
  color: var(--ink);
  border-color: var(--line-strong);
  background: var(--card-solid);
}

.btn--quiet {
  color: var(--ink-faint);
  border-color: transparent;
  background: transparent;
}

/* 「重新开始」在平板与桌面是一枚收在角落的弱化入口：功能入口不占中轴，也不跟主按钮抢蓝。
   窄屏另有一套——收进底部的抽屉里，点开才出现（见样式表「响应式」一节的窄屏档）。 */
.btn--reset {
  padding: 7px 13px;
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  background: none;
  border: 1px dashed transparent;
}

@media (hover: hover) {
  .btn--primary:hover {
    background: var(--brand);
    box-shadow: 0 16px 30px -14px rgba(23, 114, 246, 0.9);
  }

  .btn--primary:hover .btn__arrow {
    transform: translateX(3px);
  }

  .btn--ghost:hover {
    border-color: var(--brand);
    background: var(--brand-soft);
  }

  .btn--quiet:hover {
    color: var(--brand-ink);
    background: var(--brand-soft);
  }

  .btn--reset:hover {
    color: var(--brand-ink);
    border-color: var(--line-strong);
  }

  .iconbtn:hover {
    color: var(--brand);
    border-color: var(--brand);
  }
}

/* ————————————————— 等待与出错 —————————————————
 *
 * 两个都贴着「卡片区下沿 + 8px」浮着，而不是压到画面底部：刘看山站在底部正中，
 * 压在画面底部就等于糊在它身上。
 */

.loading {
  position: absolute;
  left: 50%;
  bottom: calc(var(--stand-h) + 8px);
  z-index: 6;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 9px;
  /* width: max-content 不能省：绝对定位元素在 left:50% 下的可用宽度只有一半，
     写成 max-width 就会把「正在往下写…」折成两行（旧版的胶囊一直是折的）。 */
  width: max-content;
  max-width: calc(100% - 28px);
  padding: 10px 16px;
  border-radius: 999px;
  background: var(--card-solid);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-lift);
  overflow: hidden;
  animation: loading-arrive 0.28s ease both;
}

.loading::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 42%;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--brand), var(--brand-sky), transparent);
  animation: loading-travel 1.9s ease-in-out infinite;
}

.loading__icon {
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
  color: var(--brand);
}

.loading__text {
  margin: 0;
  font-size: 13px;
  color: var(--ink-dim);
}

.loading__dots {
  display: flex;
  gap: 4px;
}

.loading__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--brand);
  animation: blink 1.1s infinite ease-in-out;
}

.loading__dot:nth-child(2) {
  animation-delay: 0.16s;
}

.loading__dot:nth-child(3) {
  animation-delay: 0.32s;
}

.errorbox {
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: calc(var(--stand-h) + 8px);
  z-index: 7;
  display: grid;
  gap: 10px;
  padding: 15px;
  border-radius: var(--radius);
  border: 1px solid var(--danger);
  border-left-width: 4px;
  background: var(--card-solid);
  color: var(--danger-ink);
  box-shadow: var(--shadow-lift);
}

[data-theme="light"] .errorbox {
  background: linear-gradient(180deg, var(--card-solid), var(--danger-soft));
}

.errorbox__text {
  margin: 0;
  font-size: 14px;
  line-height: 1.7;
}

/* ————————————————— 页脚 —————————————————
 *
 * 窄屏（<720px）是一个**浮层**：页脚不占版面（收起态 0 高度，舞台拿满一屏），常态只剩
 * 屏幕底下的一道短横（`.footer__handle` 里的 `.footer__grip`），点一下抽屉从画面外滑上来。
 * 平板与桌面空间够，按钮直接摆出来，拉手与抽屉不出现（见样式表末尾的窄屏档）。
 */

.footer {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: var(--footer-h);
  padding-bottom: var(--safe-b);
  background: transparent;
}

/* 拉手只在窄屏出现：那是页脚收起时唯一的入口 */
.footer__handle {
  display: none;
}

/* 抽屉：平板与桌面就是按钮的一个普通容器（在流里、居中），窄屏那套浮层排布另写。 */
.footer__sheet {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* ————————————————— 动效 ————————————————— */

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(7px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes panel-leave {
  to {
    opacity: 0;
    transform: translateY(-7px) scale(0.992);
  }
}

@keyframes detail-rise {
  from {
    opacity: 0;
    transform: translateY(9px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes loading-arrive {
  from {
    opacity: 0;
    transform: translate(-50%, 7px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0) scale(1);
  }
}

@keyframes loading-travel {
  0% {
    transform: translateX(-110%);
  }
  55%,
  100% {
    transform: translateX(340%);
  }
}

/* 打字光标的硬闪烁：前半程实、后半程无，两段之间没有渐变（49.9% → 50% 只有约 1ms 过渡） */
@keyframes caret-blink {
  0%,
  49.9% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

/* 呼吸只改 Y：各档自己的水平定位由 --char-tf 带进来，否则动画一跑就把站位冲掉 */
@keyframes bob {
  0%,
  100% {
    transform: var(--char-tf, translateX(0px)) translateY(0);
  }
  50% {
    transform: var(--char-tf, translateX(0px)) translateY(-4px);
  }
}

@keyframes stamp {
  from {
    opacity: 0;
    transform: rotate(-12deg) scale(1.45);
  }
  to {
    opacity: 1;
    transform: rotate(-1.4deg) scale(1);
  }
}

@keyframes pulse {
  0%,
  100% {
    opacity: 0.45;
  }
  50% {
    opacity: 0.9;
  }
}

@keyframes blink {
  0%,
  80%,
  100% {
    opacity: 0.25;
    transform: translateY(0);
  }
  40% {
    opacity: 1;
    transform: translateY(-2px);
  }
}

/* 关掉动效偏好：卡片/新段落/呼吸/盖章全部停掉、过渡压到最短。
   加载提示不靠动画传达进度——文案本身就一直在变，仍然报得出「正在做什么」。 */
@media (prefers-reduced-motion: reduce) {
  .card,
  .archive,
  .panel__inner.is-leaving,
  .reveal-on-scroll.is-revealed .related__item,
  .reveal-on-scroll.is-revealed .life-timeline__stage,
  .reveal-on-scroll.is-revealed .ending-actions,
  .story__text.is-new,
  .story__text.is-typing::after,
  .ending__paragraph.is-new,
  .ending__paragraph.is-typing::after,
  .ending__continue span:last-child,
  .skeleton__line,
  .loading,
  .loading::after,
  .loading__dot,
  .stamp {
    animation: none;
  }

  .skeleton__line {
    opacity: 0.7;
  }

  .stage__char.is-visible {
    animation: none;
  }

  .loading__dot {
    opacity: 0.6;
  }

  .reveal-on-scroll {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .life-archive,
  .life-archive__sheet {
    transition: none;
  }

  .option,
  .btn,
  .iconbtn,
  .journey__dot,
  .stage__bg,
  .stage__char,
  .stage__bg--alt,
  .stage__char--alt,
  .iconbtn__icon {
    transition-duration: 0.01s;
  }
}

/* ————————————————— 响应式 —————————————————
 *
 * 手机（<720px）：全屏沉浸，画面出血，画框不存在。正文一栏，「你走过的路」在剧情页跟在正文后面。
 * 平板（720–1023px）：收成一张带衬纸的画框，仍是一栏，正文列宽被画框本身限制住。
 * 桌面（≥1024px）：画框加宽到两栏——正文在左（≤720px 行宽），「你走过的路」钉在右侧并且
 *                  sticky 跟随滚动。横向多出来的空间给这一栏，而不是把正文拉成一行 45 字。
 */

/* 手机页脚是一个**浮层**：页脚自己不吃版面（`position: fixed`，收起态 0 高度），舞台拿满一屏。
   常态只剩屏幕底下的一道短横（拉手），点一下抽屉从画面外滑上来——展开时它盖住卡片区下沿，
   而正文的滚动位置与 #panel 的高度一动都不动（没有重排，就没有「读到哪里」被打断的问题）。 */
@media (max-width: 719px) {
  .app {
    /* 页脚浮着，不占高度：舞台 = 100dvh */
    --footer-h: 0px;
    /* 卡片区到屏幕底的那口气：要同时装下拉手（24px）与刘海屏的 home indicator */
    --stand-h: calc(26px + var(--safe-b));
    --drawer-h: 112px;
  }

  .footer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 8;
    display: block;
    min-height: 0;
    padding: 0;
    /* 浮层默认不吃指针：卡片区下沿那 26px 照常能滚、能点，只有拉手与抽屉自己例外 */
    pointer-events: none;
  }

  /* 拉手是屏幕上唯一常驻的东西，所以它得轻：没有白底、没有描边、没有投影，
     只剩一道 40×4 的淡横线，躺在画面下沿的呼吸位里。 */
  .footer__handle {
    position: absolute;
    left: 50%;
    bottom: var(--safe-b);
    transform: translateX(-50%);
    display: grid;
    place-items: center;
    width: 88px;
    height: 24px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    pointer-events: auto;
    /* 抽屉升起来时它跟着升（同一条曲线、同一个时长），看起来就是抽屉把拉手顶上去了 */
    transition: bottom 0.3s cubic-bezier(0.32, 0.9, 0.25, 1);
  }

  /* 100% = 抽屉的高度（抽屉是页脚里唯一的在流内容），所以拉手正好停在抽屉上沿 */
  .app.is-footer-open .footer__handle {
    bottom: 100%;
  }

  /* 抓痕用 --ink-faint 而不是更淡的 --line-strong：它是手机端唯一的重启入口，
     压在插画上要看得见（实测 4:1 上下），而 40×4 这道线本身已经够轻了。 */
  .footer__grip {
    width: 40px;
    height: 4px;
    border-radius: 999px;
    background: var(--ink-faint);
    transition: background 0.2s ease, opacity 0.16s ease;
  }

  /* 拇指按下去给一下 —— 拉手就这么细一点，反馈只能是它自己 */
  .footer__handle:active .footer__grip {
    opacity: 0.6;
  }

  /* 抽屉：一张白纸从画面外滑上来。高度固定——它同时也是拉手要升多高的那个数
     （`bottom: 100%` 与 `translateY(100%)` 都指着它），所以只需要改这一处。 */
  .footer__sheet {
    display: flex;
    justify-content: center;
    align-items: center;
    height: var(--drawer-h);
    padding: 0 14px var(--safe-b);
    background: var(--card-solid);
    border-top: 1px solid var(--line-strong);
    box-shadow: 0 -22px 46px -30px rgba(10, 60, 140, 0.55);
    transform: translateY(100%);
    pointer-events: auto;
    /* 收起时按钮必须退出 Tab 顺序，否则键盘玩家会 Tab 到一个看不见的「重新开始」上；
       visibility 的切换压到滑下去之后再发生（关的那一下仍然是滑下去，不是啪一下没）。 */
    visibility: hidden;
    transition: transform 0.3s cubic-bezier(0.32, 0.9, 0.25, 1), visibility 0s linear 0.3s;
  }

  .app.is-footer-open .footer__sheet {
    transform: none;
    visibility: visible;
    transition: transform 0.3s cubic-bezier(0.32, 0.9, 0.25, 1);
  }

  /* 抽屉里的「重新开始」：知乎蓝渐变 + 亮蓝光晕。
     收起时页面上一个蓝点都没有，蓝只属于玩家拉开抽屉、正要按的那一下。 */
  .btn--reset {
    width: 100%;
    padding: 14px 18px;
    color: var(--brand-on);
    font-weight: 600;
    letter-spacing: 0.04em;
    background: linear-gradient(118deg, var(--brand-grad-deep) 0%, var(--brand-grad-bright) 100%);
    box-shadow: 0 12px 22px -12px rgba(82, 217, 254, 0.9), 0 18px 34px -18px rgba(23, 114, 246, 0.75),
      inset 0 1px 0 rgba(82, 217, 254, 0.55);
  }

  /* 页脚这三条 transition 都写在这个媒体查询里，晚于文件上面那条 prefers-reduced-motion——
     所以那里收不到它们，就近再收一次（媒体查询里再套一层）。 */
  @media (prefers-reduced-motion: reduce) {
    .footer__handle,
    .footer__grip,
    .footer__sheet {
      transition-duration: 0.01s;
    }
  }
}

/* 窄屏的「重新开始」是实心按钮：hover 只提亮，不换文字色与描边
   （弱化入口那一套 hover 是给它平板/桌面的样子准备的）。 */
@media (hover: hover) and (max-width: 719px) {
  .btn--reset:hover {
    color: var(--brand-on);
    border-color: transparent;
    filter: brightness(1.07);
  }

  .footer__handle:hover .footer__grip {
    background: var(--ink-dim);
  }
}

/* 矮屏手机（SE 一代、老安卓）：HUD 与卡片密度再收一档，少滚一段是一段。
   收不干净也不硬收——剩下的交给滚动边缘的渐隐。 */
@media (max-width: 719px) and (max-height: 700px) {
  .stage {
    --hud-h: 56px;
  }

  .card {
    padding: 14px;
  }

  .option {
    padding: 10px 12px;
  }
}

/* 窄屏：「你走过的路」跟在正文下面；题干页连下面都不占（进度已经写在 HUD 的三段条里），
   这样题目卡不会因为多出一张卡而变成可滚动、边缘被咬掉一口。 */
@media (max-width: 1023px) {
  /* 先把两个具名区域钉出来，再谈谁在上谁在下。漏掉这一步的话，grid-area: main/rail
     会去引用并不存在的具名线，浏览器转而在前面补出两条 0px 的隐式列——卡片会凭空右移 24px。 */
  .panel__inner {
    grid-template-areas: "main" "rail";
  }

  /* 剧情页把「你走过的路」摆在正文之前：先看见自己选过什么，再读故事（与桌面端右栏的读法一致） */
  .panel[data-screen="bridge"] .panel__inner {
    grid-template-areas: "rail" "main";
  }

  .panel__main {
    grid-area: main;
  }

  .panel__rail {
    grid-area: rail;
  }

  /* 题干页连「你走过的路」都不占：进度已经写在 HUD 的三段条里，
     多一张卡会把题目卡顶成可滚动、下边缘被咬掉一口。 */
  .panel[data-screen="youth"] .panel__rail,
  .panel[data-screen="midlife"] .panel__rail {
    display: none;
  }
}

@media (min-width: 720px) {
  .app {
    align-content: center;
    justify-items: center;
    padding: 20px 0;
  }

  .stage {
    width: min(680px, 90vw);
    min-height: 0;
    /* 画框 + 上下 padding(40) + 页脚(--footer-h) 要正好等于视口，否则桌面端会多出一条滚动条、
       「重新开始」被顶到折线以下。 */
    height: min(880px, calc(100dvh - var(--footer-h) - 40px));
    border-radius: 24px;
    /* 画框的边：一层实边 + 一层蓝调大投影，纯 box-shadow，不参与布局，
       所以绝对定位的角色不会被推走 */
    box-shadow: 0 30px 80px -34px rgba(10, 60, 140, 0.5), 0 0 0 1px var(--line-strong);
    --hud-h: 68px;
  }

  .hud {
    padding: 14px 20px 20px;
  }

  /* 平板档：卡头带比手机高一档（角色跟着变大，因为它的高度就是带子的高度），横向也让开一点 */
  .stage {
    --mascot-shelf: clamp(160px, 19dvh, 220px);
    --glow-x: 20%;
  }

  .stage__char {
    --char-left: 5%;
  }

  /* 有了横向空间才把三段进度的站名写出来 */
  .journey__label {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
  }

  /* 渐隐的两段长度必须写在 .panel 自己身上：写在 .stage 上会被 .panel 里的那份盖掉 */
  .panel {
    padding: 14px 22px 12px;
    --fade-top: 30px;
    --fade-bottom: 34px;
  }

  .card {
    padding: 20px 22px;
  }

  .card--welcome {
    padding: 28px 28px;
  }

  .footer {
    width: auto;
  }
}

@media (min-width: 1024px) {
  /* 桌面端每一像素都要用在正文上：页脚压到 44px、画框外再留 12px 就够，
     省下来的额度全给卡片区（否则 1440×800 这类笔记本上会有一题的选项被切掉） */
  .app {
    --footer-h: calc(44px + var(--safe-b));
    padding: 12px 0;
  }

  .stage {
    width: min(1160px, 94vw);
    height: min(900px, calc(100dvh - var(--footer-h) - 34px));
    box-shadow: 0 36px 96px -38px rgba(10, 60, 140, 0.55), 0 0 0 1px var(--line-strong);
    --hud-h: 66px;
    /* 桌面有侧边空间，不走「卡头带」：带子归零，角色由 placeMascot() 钉在卡片上沿 */
    --mascot-shelf: 0px;
    --glow-y: 30%;
    --glow-x: clamp(140px, 14%, 220px);
  }

  /* 桌面档：同一套卡头，角色再大一档、横向钉在卡片左侧三分之一处。
     刻意离画框右沿很远：它挥手的朝向是右上，右边留够余量才不像被边框挤住。
     这几个变量必须写在 .stage__char 自己身上——基础档与平板档也是写在元素上的，
     写在 .stage 上会被元素自己的声明盖掉（left 与 right 同时有值时 left 获胜）。 */
  .stage__char {
    --char-left: clamp(150px, 16%, 250px);
    --char-right: auto;
    --char-h: clamp(200px, 25dvh, 270px);
    --char-tf: translateX(0px);
  }

  .hud {
    padding: 12px 24px 14px;
  }

  .panel {
    /* 下边距留宽一点：加载胶囊与错误框在桌面上靠左（见 .loading），要压在卡片的下边距里。 */
    padding: 18px 26px 48px;
  }

  /* 两栏：正文 | 你走过的路（刘看山趴在卡片上沿，不占列）。
     正文一列封顶 640px（一行 30~40 字），中间多出来的宽度全部给留白。
     内容照旧贴底（.panel__inner 的 margin-top: auto）——文字贴底才是读起来顺的那一种，
     卡片因此从下往上长，卡头角色的位置由 placeMascot() 跟着卡片上沿走。 */
  .panel__inner {
    grid-template-columns: minmax(0, 640px) minmax(0, 280px);
    grid-template-areas: "main rail";
    gap: 22px;
    justify-content: space-between;
  }

  .panel__main {
    grid-area: main;
  }

  .panel__rail {
    grid-area: rail;
  }

  /* 「你走过的路」跟随滚动：剧情读到哪里，你的取舍都留在视野里。
     上边距要让开顶部那一段渐隐（见 .panel 的 --fade-top）——否则钉在顶端的那张卡
     会被自己的渐隐吃掉一截标题，看起来像没渲染完。 */
  .panel__rail {
    position: sticky;
    top: var(--fade-top);
    align-self: start;
  }

  /* 加载胶囊/错误框在桌面上靠左：对齐正文列、落在卡片的下边距里。
     放右侧会跟「你走过的路」那一栏抢位置，放中间又正对着卡片正文。 */
  .loading {
    left: 26px;
    transform: none;
    width: max-content;
    max-width: calc(100% - 52px);
  }

  .errorbox {
    left: 26px;
    right: auto;
    width: min(520px, 62%);
  }

  .card__question {
    font-size: clamp(18px, 1.3vw, 20px);
  }

  .story__text {
    font-size: clamp(15.5px, 1vw, 16.5px);
    line-height: 2;
  }

  .option {
    padding: 13px 16px;
    font-size: 15px;
  }

  .subtitle {
    font-size: 15.5px;
  }

  .journey__stop {
    font-size: 12.5px;
  }

  .hud__progress {
    font-size: 13px;
  }

  .iconbtn {
    width: 40px;
    height: 40px;
  }

  .iconbtn__icon {
    width: 20px;
    height: 20px;
  }

  /* 页脚贴到画框的右端：功能入口在角落，不占中轴 */
  .footer {
    width: min(1160px, 94vw);
    justify-content: flex-end;
  }
}

/* 矮窗下的平板档：卡头角色与 HUD 各收一档，优先保证三道选项都能看完。
   角色小一圈不好看，但比「第三个选项被切掉一截」好。 */
@media (min-width: 720px) and (max-width: 1023px) and (max-height: 820px) {
  .stage {
    --hud-h: 62px;
  }

  .stage__char {
    --char-h: clamp(150px, 19dvh, 200px);
  }
}

/* 超大屏：画框不再长高，只把两侧留白撑开，避免出现一根细长的画框 */
@media (min-width: 1500px) {
  .stage {
    height: min(920px, calc(100dvh - var(--footer-h) - 60px));
  }
}

/* 结局的刘看山站在章节卷首上方，不再跟着卡片上沿移动。选择器刻意比各响应式档更具体，
   让手机、平板和桌面都保留同一套“角色引出长卷”的阅读姿态。 */
.app[data-screen="ending"] .stage {
  --mascot-shelf: clamp(108px, 15dvh, 138px);
  --glow-x: 82%;
  --glow-y: 22%;
}

.app[data-screen="ending"] .stage__char {
  --char-left: auto;
  --char-right: clamp(18px, 7%, 78px);
  --char-h: clamp(112px, 15dvh, 145px);
  --char-tf: translateX(0);
}

/* ————————————————— 开场换装：背景图承托的液态玻璃控制台 —————————————————
 * 这是独立开场，不改后续叙事卡片。三层衣物均是 SVG，可单独换色或替换路径。
 */
.app[data-screen="wardrobe"] {
  --footer-h: 0px;
}

.app[data-screen="wardrobe"] .footer {
  display: none;
}

.app[data-screen="wardrobe"] .stage {
  min-height: 100dvh;
  height: 100dvh;
  --mascot-shelf: 0px;
  --stand-h: 0px;
}

.app[data-screen="wardrobe"] .stage__bg {
  filter: saturate(0.96) brightness(0.92);
}

.app[data-screen="wardrobe"] .stage__veil {
  background: linear-gradient(180deg, rgba(8, 28, 57, 0.18), rgba(8, 29, 58, 0.02) 42%, rgba(7, 22, 45, 0.44));
}

.app[data-screen="wardrobe"] .stage__glow,
.app[data-screen="wardrobe"] .stage__rule,
.app[data-screen="wardrobe"] .hud__lead,
.app[data-screen="wardrobe"] .journey {
  display: none;
}

.app[data-screen="wardrobe"] .hud {
  justify-content: flex-end;
  background: none;
  pointer-events: none;
}

.app[data-screen="wardrobe"] .iconbtn {
  pointer-events: auto;
  color: #0a2e51;
  border-color: rgba(255, 255, 255, 0.66);
  background: rgba(255, 255, 255, 0.42);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  backdrop-filter: blur(18px) saturate(1.25);
  box-shadow: inset 0 1px rgba(255, 255, 255, 0.72), 0 10px 30px rgba(12, 46, 82, 0.18);
}

.panel[data-screen="wardrobe"] {
  top: 0;
  bottom: 0;
  padding: 18px;
  overflow: hidden;
  mask-image: none;
  -webkit-mask-image: none;
}

.panel[data-screen="wardrobe"] .panel__inner,
.panel[data-screen="wardrobe"] .panel__main {
  width: 100%;
  height: 100%;
  margin: 0;
}

.wardrobe-shell {
  position: relative;
  height: 100%;
  display: grid;
  grid-template-columns: minmax(250px, 0.78fr) minmax(300px, 1.12fr) minmax(310px, 0.92fr);
  grid-template-rows: 1fr;
  align-items: center;
  gap: clamp(16px, 2.2vw, 32px);
  padding: clamp(56px, 7vh, 78px) clamp(12px, 2vw, 30px) clamp(20px, 3vh, 34px);
  color: #10243b;
}

.wardrobe-heading {
  align-self: start;
  max-width: 360px;
  padding: 22px 24px 24px;
  border: 1px solid rgba(255, 255, 255, 0.62);
  border-radius: 28px 28px 28px 9px;
  background: linear-gradient(145deg, rgba(255, 255, 255, 0.6), rgba(232, 246, 255, 0.3));
  -webkit-backdrop-filter: blur(24px) saturate(1.25);
  backdrop-filter: blur(24px) saturate(1.25);
  box-shadow: inset 0 1px rgba(255, 255, 255, 0.86), 0 24px 60px rgba(20, 62, 105, 0.18);
}

.wardrobe-heading__eyebrow {
  margin: 0 0 13px;
  font: 650 11px/1 var(--font-mono);
  letter-spacing: 0.14em;
  color: #0a62d0;
}

.wardrobe-heading h1 {
  margin: 0;
  max-width: 9em;
  font: 700 clamp(28px, 3.3vw, 47px)/1.12 var(--font-display);
  letter-spacing: -0.035em;
  text-wrap: balance;
}

.wardrobe-heading > p:last-child {
  margin: 16px 0 0;
  max-width: 28em;
  color: #30465c;
  font-size: 14px;
  line-height: 1.75;
}

.wardrobe-stage {
  position: relative;
  align-self: end;
  justify-self: center;
  width: min(100%, 410px);
  height: min(78vh, 720px);
  display: grid;
  place-items: end center;
}

.wardrobe-avatar {
  position: relative;
  width: min(100%, 386px);
  aspect-ratio: 2 / 3;
  filter: drop-shadow(0 28px 28px rgba(15, 48, 84, 0.28));
}

.wardrobe-avatar__halo {
  position: absolute;
  left: 14%;
  right: 14%;
  bottom: 1%;
  height: 9%;
  border-radius: 50%;
  background: rgba(102, 223, 255, 0.35);
  filter: blur(18px);
}

.wardrobe-avatar__base,
.wardrobe-avatar__clothes {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.wardrobe-avatar__clothes {
  overflow: visible;
  pointer-events: none;
}

.garment {
  display: none;
}

.wardrobe-avatar[data-top="sunrise-shell"] .garment--sunrise-shell,
.wardrobe-avatar[data-top="ink-poncho"] .garment--ink-poncho,
.wardrobe-avatar[data-top="pixel-knit"] .garment--pixel-knit,
.wardrobe-avatar[data-bottom="violet-cargo"] .garment--violet-cargo,
.wardrobe-avatar[data-bottom="teal-track"] .garment--teal-track,
.wardrobe-avatar[data-bottom="coral-shorts"] .garment--coral-shorts,
.wardrobe-avatar[data-shoes="lime-runners"] .garment--lime-runners,
.wardrobe-avatar[data-shoes="violet-boots"] .garment--violet-boots,
.wardrobe-avatar[data-shoes="coral-high-tops"] .garment--coral-high-tops {
  display: block;
  animation: garment-snap 0.24s ease both;
}

.wardrobe-stage__badge {
  position: absolute;
  left: 50%;
  bottom: 1.5%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  padding: 8px 13px;
  border: 1px solid rgba(255, 255, 255, 0.64);
  border-radius: 999px;
  background: rgba(237, 249, 255, 0.48);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  box-shadow: inset 0 1px rgba(255, 255, 255, 0.8), 0 12px 30px rgba(21, 57, 94, 0.16);
  color: #26435f;
  font-size: 11px;
  white-space: nowrap;
}

.wardrobe-stage__badge span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #52d9fe;
  box-shadow: 0 0 0 4px rgba(82, 217, 254, 0.19);
}

.wardrobe-console {
  position: relative;
  align-self: center;
  display: grid;
  gap: 18px;
  padding: 22px;
  border: 1px solid rgba(255, 255, 255, 0.66);
  border-radius: 32px 32px 12px 32px;
  background: linear-gradient(145deg, rgba(247, 252, 255, 0.66), rgba(212, 236, 250, 0.33));
  -webkit-backdrop-filter: blur(28px) saturate(1.28);
  backdrop-filter: blur(28px) saturate(1.28);
  box-shadow: inset 0 1px rgba(255, 255, 255, 0.88), inset 1px 0 rgba(255, 255, 255, 0.38), 0 28px 70px rgba(10, 52, 96, 0.22);
}

.wardrobe-console::before {
  content: "";
  position: absolute;
  inset: 8px 18px auto;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.9), transparent);
}

.wardrobe-console__pickers {
  display: grid;
  gap: 16px;
}

.wardrobe-picker {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.wardrobe-picker legend {
  float: left;
  width: 54px;
  padding: 10px 0 0;
  color: #29445f;
  font-size: 12px;
  font-weight: 700;
}

.wardrobe-picker__items {
  margin-left: 58px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 7px;
}

.wardrobe-swatch {
  min-width: 0;
  min-height: 55px;
  display: grid;
  grid-template-columns: 13px minmax(0, 1fr);
  align-items: center;
  gap: 7px;
  padding: 8px;
  border: 1px solid rgba(40, 73, 106, 0.14);
  border-radius: 13px;
  color: #2d4155;
  background: rgba(255, 255, 255, 0.36);
  font: 600 11px/1.25 var(--font-body);
  text-align: left;
  cursor: pointer;
  transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}

.wardrobe-swatch__color {
  width: 13px;
  height: 28px;
  border-radius: 999px;
  background: var(--swatch);
  box-shadow: inset 0 1px rgba(255, 255, 255, 0.72), 0 3px 8px color-mix(in srgb, var(--swatch), transparent 50%);
}

.wardrobe-swatch.is-selected {
  border-color: rgba(10, 98, 208, 0.48);
  background: rgba(255, 255, 255, 0.78);
  box-shadow: 0 8px 22px rgba(21, 73, 123, 0.12), inset 0 1px rgba(255, 255, 255, 0.92);
}

.wardrobe-console__launch {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
  padding-top: 16px;
  border-top: 1px solid rgba(39, 78, 114, 0.14);
}

.wardrobe-console__launch p {
  margin: 0;
  display: grid;
  gap: 3px;
  color: #24405a;
  font-size: 12px;
}

.wardrobe-console__launch p span {
  color: #53697d;
  font-size: 10.5px;
}

.wardrobe-console__launch .btn {
  width: 100%;
  padding: 12px 15px;
  border-radius: 14px;
  background: linear-gradient(118deg, #0a62d0, #1772f6);
  box-shadow: 0 12px 24px rgba(10, 98, 208, 0.26), inset 0 1px rgba(255, 255, 255, 0.3);
}

@media (hover: hover) {
  .wardrobe-swatch:hover {
    transform: translateY(-2px);
    border-color: rgba(10, 98, 208, 0.38);
    background: rgba(255, 255, 255, 0.66);
  }
}

@keyframes garment-snap {
  from { opacity: 0; transform: translateY(-9px) scale(1.015); }
  to { opacity: 1; transform: none; }
}

@keyframes wardrobe-arrive {
  from { opacity: 0; transform: translateY(22px) scale(0.97); }
  to { opacity: 1; transform: none; }
}

@media (max-width: 900px) {
  .panel[data-screen="wardrobe"] {
    padding: 12px;
    overflow-y: auto;
  }

  .wardrobe-shell {
    min-height: 940px;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto minmax(430px, 1fr) auto;
    gap: 12px;
    padding: 54px 4px 18px;
  }

  .wardrobe-heading {
    grid-column: 1 / -1;
    justify-self: start;
    max-width: 520px;
    padding: 16px 18px;
    border-radius: 22px 22px 22px 8px;
  }

  .wardrobe-heading h1 {
    font-size: clamp(27px, 6vw, 40px);
    max-width: none;
  }

  .wardrobe-heading > p:last-child {
    margin-top: 8px;
  }

  .wardrobe-stage {
    grid-column: 1;
    height: 500px;
  }

  .wardrobe-console {
    grid-column: 2;
    align-self: center;
    padding: 16px;
    border-radius: 26px 26px 10px 26px;
  }

  .wardrobe-picker legend {
    float: none;
    width: auto;
    padding: 0 0 7px;
  }

  .wardrobe-picker__items {
    margin-left: 0;
    grid-template-columns: 1fr;
  }

  .wardrobe-swatch {
    min-height: 42px;
    grid-template-columns: 12px 1fr;
  }

  .wardrobe-swatch__color {
    width: 12px;
    height: 23px;
  }

  .wardrobe-console__launch {
    align-items: stretch;
    flex-direction: column;
  }
}

@media (max-width: 620px) {
  .panel[data-screen="wardrobe"] {
    padding: 10px;
  }

  .wardrobe-shell {
    min-height: 810px;
    display: flex;
    flex-direction: column;
    padding: 48px 0 16px;
  }

  .wardrobe-heading {
    width: calc(100% - 12px);
    padding: 14px 16px;
  }

  .wardrobe-heading__eyebrow {
    margin-bottom: 8px;
  }

  .wardrobe-heading h1 {
    font-size: 29px;
  }

  .wardrobe-heading > p:last-child {
    font-size: 12px;
    line-height: 1.55;
  }

  .wardrobe-stage {
    flex: 0 0 306px;
    height: 306px;
    width: min(72%, 226px);
  }

  .wardrobe-console {
    width: 100%;
    padding: 15px;
  }

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

  .wardrobe-swatch {
    min-height: 64px;
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
    font-size: 10.5px;
  }

  .wardrobe-swatch__color {
    width: 30px;
    height: 8px;
  }

  .wardrobe-console__launch .btn {
    width: 100%;
  }
}

[data-theme="dark"] .app[data-screen="wardrobe"] .stage__veil {
  background: linear-gradient(180deg, rgba(4, 11, 23, 0.45), rgba(5, 18, 37, 0.18) 45%, rgba(3, 12, 25, 0.64));
}

[data-theme="dark"] .wardrobe-heading,
[data-theme="dark"] .wardrobe-console {
  color: #eef7ff;
  border-color: rgba(217, 238, 255, 0.28);
  background: linear-gradient(145deg, rgba(18, 37, 59, 0.76), rgba(16, 41, 67, 0.46));
}

[data-theme="dark"] .wardrobe-heading > p:last-child,
[data-theme="dark"] .wardrobe-console__launch p,
[data-theme="dark"] .wardrobe-picker legend {
  color: #d9e9f7;
}

[data-theme="dark"] .wardrobe-console__launch p span {
  color: #a9bfd1;
}

[data-theme="dark"] .wardrobe-swatch {
  color: #e6f2fb;
  border-color: rgba(217, 238, 255, 0.18);
  background: rgba(9, 27, 47, 0.42);
}

[data-theme="dark"] .wardrobe-swatch.is-selected {
  border-color: rgba(82, 217, 254, 0.6);
  background: rgba(33, 67, 99, 0.76);
}

@media (prefers-reduced-motion: reduce) {
  .wardrobe-avatar,
  .wardrobe-avatar .garment {
    animation: none !important;
  }
}

.app[data-screen="ending"] .hud {
  opacity: 0.86;
}

.panel[data-screen="ending"] {
  padding-bottom: 48px;
}

@media (min-width: 720px) {
  .ending-chapter {
    padding-right: clamp(34px, 7vw, 66px);
    padding-left: clamp(34px, 7vw, 66px);
  }
}

@media (max-width: 719px) {
  .ending {
    gap: 13px;
  }

  .ending-chapter {
    padding: 22px 17px;
    border-radius: 15px;
  }

  .ending-chapter--final {
    min-height: clamp(430px, 67dvh, 570px);
    padding-top: 34px;
    padding-bottom: 30px;
  }

  .ending__title {
    margin-bottom: 19px;
  }

  .ending__paragraph {
    font-size: 15.5px;
    line-height: 1.95;
  }
}

/* ————————————————— 人生开局抽卡：事件、场景与完整造型一次揭晓 ————————————————— */
.app[data-screen="prologue"] { --footer-h: 0px; }
.app[data-screen="prologue"] .footer,
.app[data-screen="prologue"] .stage__glow,
.app[data-screen="prologue"] .stage__rule,
.app[data-screen="prologue"] .hud__lead,
.app[data-screen="prologue"] .journey { display: none; }

.app[data-screen="prologue"] .stage { min-height: 100dvh; height: 100dvh; --mascot-shelf: 0px; --stand-h: 0px; }
.app[data-screen="prologue"] .stage__bg { filter: saturate(.88) brightness(.72); transform: scale(1.015); }
.app[data-screen="prologue"] .stage__veil {
  background: linear-gradient(90deg, rgba(5, 18, 31, .72), rgba(4, 17, 31, .12) 49%, rgba(3, 14, 27, .58));
}
.app[data-screen="prologue"] .hud { justify-content: flex-end; background: none; pointer-events: none; }
.app[data-screen="prologue"] .iconbtn { pointer-events: auto; color: #eef9ff; border-color: rgba(255,255,255,.26); background: rgba(8,30,48,.34); backdrop-filter: blur(18px) saturate(1.2); }

.panel[data-screen="prologue"] { inset: 0; padding: 18px; overflow: hidden; mask-image: none; -webkit-mask-image: none; }
.panel[data-screen="prologue"] .panel__inner,
.panel[data-screen="prologue"] .panel__main { width: 100%; height: 100%; margin: 0; }

.prologue-shell {
  height: 100%; display: grid; grid-template-columns: minmax(260px,.8fr) minmax(290px,.9fr) minmax(300px,.82fr);
  align-items: center; gap: clamp(18px,3vw,48px); padding: clamp(70px,9vh,96px) clamp(14px,3vw,48px) clamp(28px,5vh,52px);
  color: #f4fbff;
}
.prologue-heading { align-self: start; max-width: 430px; text-shadow: 0 2px 22px rgba(0,0,0,.34); }
.prologue-heading__eyebrow { margin: 0 0 16px; color: #9beaff; font: 650 11px/1 var(--font-mono); letter-spacing: .16em; }
.prologue-heading h1 { margin: 0; font: 720 clamp(34px,4vw,58px)/1.08 var(--font-display); letter-spacing: -.045em; text-wrap: balance; }
.prologue-heading > p:last-child { max-width: 30em; margin: 18px 0 0; color: rgba(237,248,255,.78); font-size: 14px; line-height: 1.8; }

.prologue-card-zone { display: grid; place-items: center; min-width: 0; height: 100%; perspective: 1100px; }
.opening-deck { position: relative; width: min(28vw,300px); aspect-ratio: .68; animation: deck-breathe 3.2s ease-in-out infinite; }
.opening-deck__card { position: absolute; inset: 0; border: 1px solid rgba(190,234,255,.46); border-radius: 22px; background: #0b2b47; box-shadow: 0 32px 70px rgba(0,0,0,.38), inset 0 0 0 8px rgba(143,221,255,.07); }
.opening-deck__card::before { content:""; position:absolute; inset:16px; border:1px solid rgba(159,225,255,.28); border-radius:14px; background: repeating-linear-gradient(45deg, transparent 0 14px, rgba(129,216,255,.035) 14px 15px); }
.opening-deck__card--left { transform: rotate(-8deg) translate(-16px,8px); opacity:.72; }
.opening-deck__card--right { transform: rotate(7deg) translate(17px,7px); opacity:.78; }
.opening-deck__card--front { display:grid; place-items:center; }
.opening-deck__card--front i { z-index:1; display:grid; place-items:center; width:64px; height:64px; border:1px solid rgba(158,229,255,.55); border-radius:50%; color:#b7efff; font:500 24px/1 var(--font-display); font-style:normal; box-shadow:0 0 32px rgba(88,206,255,.22); }

.opening-card { position: relative; width: min(30vw,340px); aspect-ratio: .68; margin:0; overflow:hidden; border:1px solid rgba(221,245,255,.62); border-radius:24px; background:#081c2e; box-shadow:0 38px 80px rgba(0,0,0,.44), inset 0 1px rgba(255,255,255,.48); }
.opening-card::after { content:""; position:absolute; inset:0; background:linear-gradient(180deg,transparent 42%,rgba(3,12,21,.92)); pointer-events:none; }
.opening-card img { width:100%; height:100%; object-fit:cover; display:block; }
.opening-card figcaption { position:absolute; z-index:1; inset:auto 23px 22px; }
.opening-card figcaption span,.prologue-panel__label { color:#88dcf8; font:650 10px/1 var(--font-mono); letter-spacing:.14em; }
.opening-card h2 { margin:9px 0 8px; color:#fff; font:700 clamp(25px,2.1vw,32px)/1.1 var(--font-display); }
.opening-card p { margin:0; color:rgba(239,249,255,.8); font-size:12px; line-height:1.55; }

.prologue-panel { align-self:center; padding:26px; border:1px solid rgba(224,244,255,.33); border-radius:30px 30px 10px 30px; background:linear-gradient(145deg,rgba(224,245,255,.19),rgba(7,28,46,.35)); backdrop-filter:blur(28px) saturate(1.22); box-shadow:inset 0 1px rgba(255,255,255,.38),0 28px 65px rgba(0,0,0,.28); }
.prologue-panel__label { margin:0 0 12px; }
.prologue-panel h2 { margin:0; color:#fff; font:680 clamp(22px,2.1vw,30px)/1.2 var(--font-display); }
.prologue-panel > p:not(.prologue-panel__label) { margin:14px 0 22px; color:rgba(235,247,255,.75); font-size:13px; line-height:1.75; }
.prologue-panel .btn { width:100%; min-height:48px; border-radius:15px; background:#e8f8ff; color:#0a3553; box-shadow:0 13px 30px rgba(0,0,0,.22),inset 0 1px #fff; }

@keyframes deck-breathe { 50% { transform:translateY(-9px) rotateX(2deg); } }

@media (max-width: 900px) {
  .panel[data-screen="prologue"] { padding:12px; overflow-y:auto; }
  .prologue-shell { min-height:900px; grid-template-columns:1fr 1fr; grid-template-rows:auto 1fr; padding:62px 12px 24px; gap:18px; }
  .prologue-heading { grid-column:1/-1; }
  .prologue-heading h1 { font-size:clamp(34px,7vw,50px); }
  .opening-deck,.opening-card { width:min(43vw,320px); }
}

@media (max-width: 620px) {
  .app[data-screen="prologue"] .stage__veil { background:linear-gradient(180deg,rgba(4,15,27,.48),rgba(3,14,26,.16) 38%,rgba(3,13,24,.76)); }
  .prologue-shell { min-height:920px; display:flex; flex-direction:column; align-items:stretch; padding:58px 4px 22px; }
  .prologue-heading { align-self:stretch; }
  .prologue-heading h1 { font-size:34px; }
  .prologue-heading > p:last-child { margin-top:10px; font-size:12px; line-height:1.6; }
  .prologue-card-zone { height:auto; min-height:410px; }
  .opening-deck,.opening-card { width:min(75vw,270px); }
  .prologue-panel { padding:20px; border-radius:24px 24px 9px 24px; }
}

@media (prefers-reduced-motion: reduce) {
  .opening-deck,.opening-card { animation:none !important; }
}
