/* 生日网页 v3「雾里的粒子心 + 星海」。所有数值来自 MASTER.md。字体在 fonts.css（tools/build_fonts.py 生成）。 */

:root {
  --fog-hi: #E4E8EF;
  --fog: #D3D9E2;
  --fog-lo: #AEB6C4;
  --ink: #161B26;
  --ink-2: #3E4656;
  --ice: #FFFFFF;
  --ice-blue: #A9C4E8;
  --night-hi: #16203A;
  --night: #0C1222;
  --night-lo: #05080F;
  --star: #EEF3FA;
  --star-2: #A9B6CC;
  --glass-dark-bg: rgba(18, 26, 44, 0.55);
  --glass-dark-edge: inset 0 0 0 1px rgba(238, 243, 250, 0.18);
  --chip-bg: #161B26;
  --chip-fg: #F2F4F8;
  --glass-bg: rgba(244, 247, 251, 0.52);
  --glass-blur: blur(22px) saturate(115%);
  --glass-edge: inset 0 0 0 1px rgba(255, 255, 255, 0.7);
  --shadow: 0 30px 60px -30px rgba(40, 52, 76, 0.35);

  --sans: "Geist", "NSC", "PingFang SC", "Microsoft YaHei", sans-serif;
  --mono: "GeistMono", "NSC", monospace;
  --art: "Art", "STKaiti", "KaiTi", "Kaiti SC", serif;   /* 结尾的白字：马善政毛笔楷书（OFL） */

  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;
  --edge-t: calc(var(--s7) + env(safe-area-inset-top, 0px));
  --edge-r: calc(var(--s7) + env(safe-area-inset-right, 0px));
  --edge-b: calc(var(--s7) + env(safe-area-inset-bottom, 0px));
  --edge-l: calc(var(--s7) + env(safe-area-inset-left, 0px));

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-in: cubic-bezier(0.55, 0, 1, 0.45);
  --t-press: 120ms;
  --t-fade: 600ms;
  --t-move: 900ms;
  --t-exit: 220ms;
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { color-scheme: light; }
html, body { height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; }
body {
  background: var(--fog);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 300;
  line-height: 1.6;
  font-synthesis: none;
  line-break: strict;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
button { font: inherit; color: inherit; touch-action: manipulation; }
p, h1, h2 { margin: 0; font-weight: inherit; }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* ---------- 底层：雾、光晕、雪、WebGL 画布 ---------- */
.fog { position: fixed; inset: 0; z-index: 0; background: radial-gradient(70% 62% at 50% 40%, var(--fog-hi), var(--fog) 55%, var(--fog-lo) 100%); }
.halo {
  position: fixed; left: 0; top: 0; width: 10px; height: 10px; z-index: 1;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0) 72%);
  pointer-events: none;
  transition: opacity var(--t-move) var(--ease-out);
}
/* 地球阶段：光晕变成贴着地球边缘的一圈 */
.halo.is-globe { background: radial-gradient(closest-side, rgba(255, 255, 255, 0) 80%, rgba(255, 255, 255, 0.55) 89%, rgba(255, 255, 255, 0) 100%); }
#sky, #snow, #gl { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; }
#sky { z-index: 1; }
#snow { z-index: 2; }
#gl { z-index: 4; }
.drag-layer { position: fixed; inset: 0; z-index: 5; touch-action: none; display: none; cursor: grab; }
.drag-layer.is-on { display: block; }
.drag-layer:active { cursor: grabbing; }

/* ---------- 读数小方块 ---------- */
.chips { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s1); }
.chips span {
  display: inline-block;
  padding: 5px 8px 4px;
  background: var(--chip-bg);
  color: var(--chip-fg);
  font: 400 12.5px/1 var(--mono);
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.chips.row { flex-direction: row; flex-wrap: wrap; }
.corner { position: fixed; z-index: 10; }
.corner.tl { top: var(--edge-t); left: var(--edge-l); }
.corner.tr { top: var(--edge-t); right: var(--edge-r); align-items: flex-end; }
.globe-title { display: flex; flex-direction: column; gap: var(--s2); }

.soft { font: 300 15px/1.7 var(--sans); color: var(--ink-2); letter-spacing: 0.04em; transition: color 1.6s ease; }
.sr-only { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.title { font: 200 clamp(34px, 3.7vw, 46px)/1.25 var(--sans); letter-spacing: 0.12em; color: var(--ink); }

/* ---------- 开场 ---------- */
.intro { position: fixed; inset: 0; z-index: 10; pointer-events: none; transition: opacity var(--t-fade) var(--ease-out); }
.intro.is-leaving { opacity: 0; }
.intro > * { pointer-events: auto; }
.intro-text { position: absolute; left: var(--edge-l); bottom: var(--edge-b); max-width: 80vw; pointer-events: none; }
.intro-text .soft { margin-top: var(--s3); }
.title .ch { display: inline-block; opacity: 0; filter: blur(8px); transform: translateY(8px); animation: ch-in 1100ms var(--ease-out) forwards; animation-delay: calc(500ms + var(--i) * 80ms); }
@keyframes ch-in { to { opacity: 1; filter: blur(0); transform: none; } }
#intro-hint { opacity: 0; animation: fade-in var(--t-fade) var(--ease-out) 1.8s forwards; }
#intro-hint.is-off { display: none; }
@keyframes fade-in { to { opacity: 1; } }
.secret { margin-top: var(--s2); font: 300 17px/1.8 var(--sans); color: var(--ink); white-space: pre-line; min-height: 1.8em; }
.secret .ch { display: inline-block; opacity: 0; filter: blur(4px); animation: ch-in 800ms var(--ease-out) forwards; animation-delay: calc(var(--i) * 45ms); }
/* 右上角三个黑框：乱码，隔一会儿闪出真的数字；按住就停在数字上 */
.codes span { min-width: calc(var(--n, 8) * 0.62em + 16px); text-align: center; cursor: pointer; touch-action: manipulation; transition: background-color 300ms ease, color 300ms ease; }
.chips.codes span { transition: background-color 250ms ease, color 250ms ease; }
.chips.codes span.is-real { background: var(--ice-blue); color: var(--ink); }
.heart-hit { position: absolute; border: 0; padding: 0; background: none; border-radius: 50%; cursor: pointer; touch-action: none; -webkit-touch-callout: none; }
.heart-fallback { display: none; }
.no-webgl .heart-fallback {
  display: block; position: absolute; left: 50%; top: 42%; width: min(40vh, 56vw); height: min(40vh, 56vw);
  transform: translate(-50%, -50%); color: var(--ice);
  filter: drop-shadow(0 0 24px rgba(255, 255, 255, 0.9)) drop-shadow(0 20px 40px rgba(40, 52, 76, 0.25));
}

/* 开场前：雾里散着的粒子 + 一行字；点一下，音乐响起、粒子聚成心、字一个个浮出来 */
.gate {
  position: fixed; inset: 0; z-index: 50; border: 0; padding: 0; margin: 0; background: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s3);
  color: var(--ink); transition: opacity 900ms var(--ease-out);
}
.gate-main { font: 200 clamp(26px, 2.8vw, 34px)/1.3 var(--sans); letter-spacing: 0.24em; animation: gate-breathe 3.2s ease-in-out infinite; }
.gate-sub { font: 300 15px/1.7 var(--sans); letter-spacing: 0.08em; color: var(--ink-2); }
@keyframes gate-breathe { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }
.gate.is-off { opacity: 0; pointer-events: none; }
.intro.is-waiting .title .ch, .intro.is-waiting #intro-hint { animation-play-state: paused; }
.intro.is-waiting .codes, .intro.is-waiting .heart-hit { opacity: 0; pointer-events: none; }
.intro .codes { transition: opacity 1.2s var(--ease-out) 1.2s; }

/* ---------- 地球界面 ---------- */
.globe-ui { position: fixed; inset: 0; z-index: 13; pointer-events: none; opacity: 0; transition: opacity var(--t-move) var(--ease-out); }
.globe-ui.is-on { opacity: 1; }
.globe-ui > * { pointer-events: auto; }
.top-actions { display: flex; align-items: center; gap: var(--s3); flex-direction: row; }
.progress { display: flex; }
.progress-dot { position: relative; width: 28px; height: 44px; padding: 0; border: 0; background: none; cursor: pointer; }
.progress-dot::before {
  content: ""; position: absolute; left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  border: 1.5px solid var(--ink); background: transparent; transition: background-color var(--t-fade) var(--ease-out), border-color var(--t-fade) var(--ease-out);
}
.progress-dot.is-on::before { background: var(--ice-blue); }
.progress.is-compact .progress-dot { width: 16px; }
.globe-hint {
  position: fixed; left: 50%; bottom: var(--edge-b); transform: translateX(-50%);
  white-space: nowrap; pointer-events: none; transition: opacity var(--t-fade) var(--ease-out);
}
.globe-hint.is-off { opacity: 0; }

.icon-btn {
  position: relative; display: inline-grid; place-items: center;
  width: 44px; height: 44px; padding: 0; border: 0; border-radius: 50%;
  background: var(--glass-bg); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-edge); color: var(--ink); cursor: pointer;
  transition: transform var(--t-press) ease-out, background-color var(--t-press) ease-out, color var(--t-fade) var(--ease-out), box-shadow var(--t-fade) var(--ease-out);
}
.icon-btn > svg { width: 20px; height: 20px; }
.icon-btn:active { transform: scale(0.97); background: rgba(255, 255, 255, 0.8); }
.icon-btn:disabled { opacity: 0.4; cursor: default; }
.icon-btn.small > svg { width: 18px; height: 18px; }
.swap svg { position: absolute; left: 50%; top: 50%; width: 20px; height: 20px; margin: -10px 0 0 -10px; transition: opacity 300ms var(--ease-out), transform 300ms var(--ease-out), filter 300ms var(--ease-out); }
.swap .swap-b { opacity: 0; transform: scale(0.25); filter: blur(4px); }
.swap.is-alt .swap-a { opacity: 0; transform: scale(0.25); filter: blur(4px); }
.swap.is-alt .swap-b { opacity: 1; transform: none; filter: none; }

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 var(--s5); border: 0; border-radius: 2px;
  background: rgba(255, 255, 255, 0.55); box-shadow: inset 0 0 0 1px rgba(22, 27, 38, 0.35);
  color: var(--ink); font: 400 15px/1 var(--sans); letter-spacing: 0.08em; white-space: nowrap; cursor: pointer;
  transition: transform var(--t-press) ease-out, background-color var(--t-press) ease-out;
}
.btn:active { transform: scale(0.97); background: rgba(255, 255, 255, 0.8); }
.btn:disabled { opacity: 0.4; cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .btn:hover, .icon-btn:hover { background: rgba(255, 255, 255, 0.72); }
}

/* ---------- 地球上的地点 ---------- */
.pins { position: fixed; inset: 0; z-index: 6; pointer-events: none; transition: opacity var(--t-fade) var(--ease-out); }
body.sea-open .pins { opacity: 0; }
.pin {
  position: absolute; left: 0; top: 0; width: 44px; height: 44px; margin: -22px 0 0 -22px;
  padding: 0; border: 0; background: none; cursor: pointer; pointer-events: auto;
  transition: opacity 300ms var(--ease-out);
}
.pin.is-hidden, .pin.is-merged { opacity: 0; pointer-events: none; }
.pin-dot {
  position: absolute; left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%;
  background: var(--ice); box-shadow: 0 0 0 1.5px var(--ink), 0 0 10px 2px rgba(255, 255, 255, 0.9);
  transition: background-color var(--t-fade) var(--ease-out), transform var(--t-press) ease-out;
}
.pin-ring { position: absolute; left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%; box-shadow: 0 0 0 1.5px var(--ice); animation: breathe 2.8s var(--ease-out) infinite; }
@keyframes breathe { 0% { transform: scale(1); opacity: 0.9; } 80%, 100% { transform: scale(2.6); opacity: 0; } }
.pin.is-visited .pin-ring { display: none; }
.pin.is-visited .pin-dot { background: var(--ice-blue); }
.pin:active .pin-dot { transform: scale(0.97); }
.pin:focus-visible { outline: none; }
.pin:focus-visible .pin-dot { outline: 2px solid var(--ink); outline-offset: 4px; }
.pin-label {
  position: absolute; left: 36px; top: 50%; transform: translateY(-50%);
  font: 400 14px/1 var(--sans); color: var(--ink); letter-spacing: 0.04em; white-space: nowrap;
  text-shadow: 0 0 6px var(--fog-hi), 0 0 12px var(--fog-hi);
  transition: opacity 200ms ease-out;
}
.pin.label-left .pin-label { left: auto; right: 36px; }
.pin.label-hidden .pin-label { opacity: 0; }
.pin-more { display: none; position: absolute; right: 2px; top: 4px; padding: 3px 5px 2px; background: var(--chip-bg); color: var(--chip-fg); font: 400 11px/1 var(--mono); }
.pin.has-group .pin-more { display: block; }
.pin.has-group:not(.label-left) .pin-label { left: 50px; }

/* ---------- 打开一个地方：磨砂面板 ---------- */
.glass { background: var(--glass-bg); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); box-shadow: var(--glass-edge), var(--shadow); border-radius: 2px; }
.sheet { position: fixed; inset: 0; z-index: 20; }
.panel {
  position: absolute; top: var(--edge-t); bottom: var(--edge-b); right: var(--edge-r); width: min(400px, 42vw);
  display: flex; flex-direction: column; gap: var(--s4);
  padding: var(--s5);
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  opacity: 0; transform: translateY(14px) scale(0.985);
}
.sheet.is-open .panel { opacity: 1; transform: none; transition: opacity var(--t-fade) var(--ease-out), transform var(--t-move) var(--ease-out); }
.sheet.is-closing .panel { opacity: 0; transform: translateY(8px); transition: opacity var(--t-exit) var(--ease-in), transform var(--t-exit) var(--ease-in); }
.sheet-close { position: absolute; top: calc(var(--edge-t) + var(--s3)); right: calc(var(--edge-r) + var(--s3)); opacity: 0; transition: opacity var(--t-fade) var(--ease-out) 200ms; }
.sheet.is-open .sheet-close { opacity: 1; }
#place-chips { flex-direction: row; flex-wrap: wrap; padding-right: 52px; }

/* 视频的喇叭：放在最上面那张照片的右下角 */
/* 照片区：平时 4:3.6；话很长、屏幕又矮的时候它让出高度（最矮 160px），话和按钮总是放得下 */
.pile-wrap { position: relative; flex: 0 1 auto; aspect-ratio: 4 / 3.6; min-height: 160px; }
.pile-sound { position: absolute; z-index: 60; right: calc((100% - var(--cw, 100%)) / 2 + 14px); bottom: calc((100% - var(--ch, 100%)) / 2 + 14px); }
.pile { position: relative; width: 100%; height: 100%; touch-action: pan-y; }
.pile:focus-visible { outline: none; }
.pile:focus-visible .card.is-top { outline: 2px solid var(--ink); outline-offset: 3px; }
.card {
  position: absolute; left: calc(50% - var(--cw, 100%) / 2); top: calc(50% - var(--ch, 100%) / 2); width: var(--cw, 100%); height: var(--ch, 100%); margin: 0; padding: 6px;
  background: rgba(255, 255, 255, 0.85); box-shadow: 0 18px 36px -22px rgba(40, 52, 76, 0.45);
  transform: translate(var(--x, 0px), var(--y, 0px)) rotate(var(--r, 0deg));
  transition: transform 450ms var(--ease-out); cursor: grab;
}
.card.is-dragging { transition: none; cursor: grabbing; }
.card.is-flying { transition: transform 320ms var(--ease-in); }
.card img, .card video { display: block; width: 100%; height: 100%; object-fit: cover; background: var(--fog-lo); pointer-events: none; -webkit-user-drag: none; }
.pile-nav { display: flex; align-items: center; justify-content: center; gap: var(--s3); flex: none; }
.pile-dots { display: flex; gap: var(--s2); }
.pile-dots i { width: 6px; height: 6px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--ink); transition: background-color 200ms ease-out; }
.pile-dots i.is-on { background: var(--ink); }
.place-name { font: 300 24px/1.3 var(--sans); letter-spacing: 0.08em; margin-top: var(--s1); }
.note { font: 300 17px/1.95 var(--sans); color: var(--ink); }
.note .line { display: block; white-space: pre; opacity: 0; transform: translateY(6px); filter: blur(4px); }
.sheet.is-open .note.is-in .line { opacity: 1; transform: none; filter: none; transition: opacity 700ms var(--ease-out), transform var(--t-move) var(--ease-out), filter 700ms var(--ease-out); transition-delay: calc(500ms + var(--i) * 260ms); }
.sheet.is-open .note.is-in.is-swap .line { transition-delay: calc(60ms + var(--i) * 120ms); }
.note.is-draft { color: var(--ink-2); font-size: 15px; }
body.in-sea .note.is-draft { color: var(--star-2); }
.panel-actions { margin-top: auto; padding-top: var(--s3); display: flex; }

/* ---------- 路线回放 ---------- */
.replay-hud { position: fixed; left: 50%; bottom: var(--edge-b); transform: translateX(-50%); display: flex; align-items: center; gap: var(--s5); }
.replay-hud .chips { align-items: flex-end; }
.km { font: 200 54px/1 var(--sans); letter-spacing: 0.02em; font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap; }
.km small { font-size: 17px; margin-left: var(--s2); letter-spacing: 0.08em; }
.end-card {
  position: fixed; left: 50%; top: 50%; width: min(420px, 86vw); padding: var(--s6);
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s4);
  transform: translate(-50%, -46%); opacity: 0;
  transition: opacity var(--t-exit) var(--ease-in), transform var(--t-exit) var(--ease-in);
}
.end-card.is-on { opacity: 1; transform: translate(-50%, -50%); transition: opacity var(--t-fade) var(--ease-out), transform var(--t-move) var(--ease-out); }
.end-card .btn { margin-top: var(--s2); }

/* ---------- 信 ---------- */
.letter { position: fixed; inset: 0; z-index: 30; background: rgba(3, 5, 10, 0.1); opacity: 0; transition: opacity var(--t-fade) var(--ease-out); color: var(--star); }
.letter .paper { background: rgba(8, 12, 22, 0.26); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: inset 0 0 0 1px rgba(238, 243, 250, 0.22); }
.letter .paper p { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9), 0 0 10px rgba(0, 0, 0, 0.75), 0 0 22px rgba(0, 0, 0, 0.5); }
.letter .btn { background: rgba(238, 243, 250, 0.08); box-shadow: inset 0 0 0 1px rgba(238, 243, 250, 0.38); color: var(--star); }
.letter .btn:active { background: rgba(238, 243, 250, 0.18); }
.letter.is-open { opacity: 1; }
.letter-scroll {
  height: 100%; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  display: flex; flex-direction: column; align-items: center; gap: var(--s6);
  padding: var(--edge-t) var(--s5) var(--edge-b);
}
.letter-scroll:focus { outline: none; }
.letter-scroll:focus-visible .paper { box-shadow: inset 0 0 0 1px rgba(238, 243, 250, 0.16), 0 0 0 2px var(--star); }
.paper { flex: none; width: min(660px, 100%); padding: var(--s8) clamp(28px, 7vw, 64px) var(--s7); -webkit-user-select: text; user-select: text; }
.paper p { font: 300 19px/2.05 var(--sans); text-indent: 2em; margin: 0 0 var(--s4); color: var(--star); opacity: 0; transform: translateY(8px); filter: blur(4px); }
/* 信：一段一段慢慢浮出来；滑到哪段，哪段才出来（app.js 里 revealLetter 排队，前后两段至少隔 1.1 秒） */
.letter.is-open .paper p.is-in { opacity: 1; transform: none; filter: none; transition: opacity 1.8s var(--ease-out), transform 2s var(--ease-out), filter 1.6s var(--ease-out); }
.paper p { text-wrap: pretty; } /* 段尾不留一两个字单独一行 */
.paper .greet { text-indent: 0; }
.paper .sign, .paper .date { text-indent: 0; text-align: right; }
.paper .sign { margin-top: var(--s6); }
.paper .date { font: 400 12.5px/1 var(--mono); color: var(--star-2); }
.letter .btn { flex: none; }

/* ---------- 信的背景 + 结尾：烟花视频 → 画出来的烟花、照片 → 黑下来出字 ---------- */
.show { position: fixed; inset: 0; z-index: 29; background: #000; opacity: 0; transition: opacity 900ms var(--ease-out); overflow: hidden; color: var(--star); }
.show.is-on { opacity: 1; }
.show-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: opacity 4.6s ease-in-out, transform 4.6s ease-in-out, filter 4.6s ease-in-out; }
.show-video.is-out { opacity: 0; transform: scale(1.08); filter: blur(8px) brightness(0.55); }
.show-sky, .show-fw { position: absolute; inset: 0; width: 100%; height: 100%; }
.show-photos { position: absolute; inset: 0; pointer-events: none; }
.fw-img {
  position: absolute; margin: 0; opacity: 0; filter: blur(8px);
  transform: translate(-50%, -50%) rotate(var(--r, 0deg)) scale(0.9);
  transition: opacity 1.2s var(--ease-out), filter 1.2s var(--ease-out), transform var(--life, 5s) cubic-bezier(0.2, 0.6, 0.3, 1);
}
.fw-img img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.fw-img.is-in { opacity: 1; filter: none; transform: translate(-50%, calc(-50% - 16px)) rotate(var(--r, 0deg)) scale(1); }
.fw-img.is-out { opacity: 0; filter: blur(4px); transition-duration: 1.3s, 1.3s, var(--life, 5s); }
.fw-img.is-chat { border-radius: 12px; box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14), 0 24px 60px -24px rgba(0, 0, 0, 0.8), 0 0 46px rgba(200, 220, 255, 0.12); }
.fw-img.is-photo { padding: 6px; background: #fff; box-shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.85), 0 0 46px rgba(255, 240, 220, 0.14); }
.show-veil { position: absolute; inset: 0; background: #000; opacity: 0; pointer-events: none; transition: opacity 3.6s ease-in-out; }
.show.is-black .show-veil { opacity: 1; }
.show-words { position: absolute; inset: 0; display: grid; place-items: center; padding: var(--edge-t) var(--s6) var(--edge-b); pointer-events: none; }
.fw-word {
  grid-area: 1 / 1; max-width: 94vw; margin: 0; text-align: center;
  font: 400 clamp(26px, 3.1vw, 40px)/1.95 var(--art); letter-spacing: 0.06em; color: #fff;
  text-shadow: 0 0 18px rgba(255, 255, 255, 0.35), 0 0 42px rgba(160, 190, 255, 0.18);
  transition: opacity 1.6s ease-in-out, filter 1.6s ease-in-out;
}
.fw-word span { opacity: 0; filter: blur(6px); transition: opacity 1.1s ease-out, filter 1.1s ease-out; transition-delay: calc(var(--k) * var(--step, 0.05s)); }
.fw-word.is-in span { opacity: 1; filter: none; }
.fw-word.is-out { opacity: 0; filter: blur(4px); }
.fw-word.is-last { font-size: clamp(44px, 6.6vw, 88px); letter-spacing: 0.12em; line-height: 1.4; }
.show-actions { position: absolute; right: var(--edge-r); bottom: var(--edge-b); display: flex; gap: var(--s3); opacity: 0; pointer-events: none; transition: opacity 1.2s ease 1.5s; }
.show.is-end .show-actions { opacity: 0.55; pointer-events: auto; }
.btn-egg small { font-size: 0.82em; opacity: 0.7; margin-left: 0.1em; }
.egg { position: fixed; inset: 0; z-index: 32; display: grid; place-items: center; background: rgba(0, 0, 0, 0.66); opacity: 0; transition: opacity 600ms var(--ease-out); }
.egg.is-open { opacity: 1; }
.egg-video { display: block; width: min(72vw, calc(66vh * 960 / 544)); aspect-ratio: 960 / 544; height: auto; background: #000; border-radius: 2px; box-shadow: 0 0 0 1px rgba(238, 243, 250, 0.16), 0 40px 90px -30px rgba(0, 0, 0, 0.95); transform: scale(0.96); transition: transform 600ms var(--ease-out); }
.egg.is-open .egg-video { transform: none; }
.show .btn { background: rgba(238, 243, 250, 0.06); box-shadow: inset 0 0 0 1px rgba(238, 243, 250, 0.3); color: var(--star); }

/* ---------- 点照片放大看 ---------- */
.lightbox { position: fixed; inset: 0; z-index: 26; background: rgba(4, 6, 12, 0.9); display: grid; place-items: center; opacity: 0; transition: opacity 400ms var(--ease-out); }
.lightbox.is-open { opacity: 1; }
.lb-stage { width: 100%; height: 100%; display: grid; place-items: center; padding: calc(var(--edge-t) + 24px) var(--s6) var(--edge-b); }
.lb-stage img, .lb-stage video { max-width: calc(100vw - 2 * var(--s6)); max-height: calc(100vh - var(--edge-t) - var(--edge-b) - 40px); width: auto; height: auto; object-fit: contain; box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.9); transform: scale(0.94); transition: transform 500ms var(--ease-out); }
.lightbox.is-open .lb-stage img, .lightbox.is-open .lb-stage video { transform: none; }
.lb-close, .egg-close { position: absolute; top: var(--edge-t); right: var(--edge-r); background: rgba(238, 243, 250, 0.1) !important; box-shadow: inset 0 0 0 1px rgba(238, 243, 250, 0.35) !important; color: var(--star) !important; }
.card img { cursor: zoom-in; }

/* ---------- 星海（整个作品唯一的深色段） ---------- */
/* 天空、星河、地标都画在 canvas 上：进场时从雾慢慢黑成夜，所以这一层自己没有底色 */
.sea { position: fixed; inset: 0; z-index: 12; color: var(--star); touch-action: none; }
.sea-title, .sea-back, .sea-hint { opacity: 0; transition: opacity var(--t-move) var(--ease-out); }
.sea.is-ui .sea-title, .sea.is-ui .sea-back, .sea.is-ui .sea-hint { opacity: 1; }
#sea-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.sea-stars { position: absolute; inset: 0; pointer-events: none; }
.star { position: absolute; left: 0; top: 0; width: 44px; height: 44px; margin: -22px 0 0 -22px; padding: 0; border: 0; background: none; cursor: pointer; pointer-events: auto; opacity: 0; color: var(--star); transition: opacity var(--t-fade) var(--ease-out); }
.sea.is-ready .star { opacity: 1; transition-delay: calc(var(--i) * var(--gap, 260ms)); }
.star-dot { position: absolute; left: 50%; top: 50%; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; background: var(--star); transition: background-color var(--t-fade) var(--ease-out), transform var(--t-press) ease-out; }
.star.is-seen .star-dot { background: var(--ice-blue); }
.star-ring { position: absolute; left: 50%; top: 50%; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; box-shadow: 0 0 0 1.2px var(--star); animation: breathe 2.8s var(--ease-out) infinite; animation-delay: calc(var(--i) * 400ms); }
.star.is-seen .star-ring { display: none; }
.star:active .star-dot { transform: scale(0.97); }
.star:focus-visible { outline: none; }
.star:focus-visible .star-dot { outline: 2px solid var(--star); outline-offset: 5px; }
.sea-title { display: flex; flex-direction: column; gap: var(--s3); }
.city { margin: 0; font: 200 clamp(44px, 5.2vw, 64px)/1.1 var(--sans); letter-spacing: 0.14em; color: var(--star); }
.sea .chips span { background: var(--star); color: var(--night); }
.sea-hint { position: fixed; left: 50%; bottom: var(--edge-b); transform: translateX(-50%); white-space: nowrap; color: var(--star-2); pointer-events: none; }
body.sheet-open .sea.is-ui .sea-hint { opacity: 0; transition-duration: var(--t-fade); }
.sea-back { position: fixed; left: var(--edge-l); bottom: calc(var(--edge-b) - 12px); }
.sea .btn, body.in-sea .btn { background: rgba(238, 243, 250, 0.08); box-shadow: inset 0 0 0 1px rgba(238, 243, 250, 0.38); color: var(--star); }
.sea .btn:active, body.in-sea .btn:active { background: rgba(238, 243, 250, 0.16); }
@media (hover: hover) and (pointer: fine) { .sea .btn:hover, body.in-sea .btn:hover { background: rgba(238, 243, 250, 0.16); } }
.sea .btn:focus-visible, body.in-sea :focus-visible { outline-color: var(--star); }
/* 星海里：地球界面的标题和提示让开，右上角的进度和声音换成浅色 */
body.in-sea .globe-title, body.in-sea .globe-hint, body.in-sea .replay-hud { opacity: 0; pointer-events: none; }
body.in-sea .icon-btn, body.is-night .icon-btn { background: rgba(238, 243, 250, 0.08); box-shadow: inset 0 0 0 1px rgba(238, 243, 250, 0.3); color: var(--star); }
body.in-sea .progress-dot::before, body.is-night .progress-dot::before { border-color: var(--star); }
body.in-sea .progress-dot.is-some::before, body.is-night .progress-dot.is-some::before { box-shadow: inset 0 0 0 3px var(--night), inset 0 0 0 6px var(--star); }
.progress-dot.is-some::before { box-shadow: inset 0 0 0 3px var(--fog), inset 0 0 0 6px var(--ink); }
/* 地球上的夜里：标题、提示、地名、路线回放、结尾卡片都换成浅色 */
body.is-night .globe-title .soft, body.is-night .globe-hint, body.is-night .end-card .soft { color: var(--star-2); }
body.is-night .globe-title .chips span, body.is-night .replay-hud .chips span { background: var(--star); color: var(--night); }
body.is-night .km { color: var(--star); }
body.is-night .halo { opacity: 0.6; }
body.is-night .pin-label { color: var(--star); text-shadow: 0 0 6px var(--night), 0 0 12px var(--night); }
body.is-night .pin-dot { box-shadow: 0 0 0 1.5px var(--star), 0 0 12px 3px rgba(255, 255, 255, 0.75); }
body.is-night .globe-ui .btn { background: rgba(238, 243, 250, 0.08); box-shadow: inset 0 0 0 1px rgba(238, 243, 250, 0.38); color: var(--star); }
body.is-night .end-card { background: var(--glass-dark-bg); box-shadow: var(--glass-dark-edge), 0 30px 60px -30px rgba(0, 0, 0, 0.6); }
.pin-label, .km, .chips span, .end-card, .globe-ui .btn, .pin-dot { transition: color 1.6s ease, background-color 1.6s ease, box-shadow 1.6s ease, text-shadow 1.6s ease, opacity 300ms ease; }
/* 星海里的面板：深色磨砂玻璃 */
body.in-sea .glass { background: var(--glass-dark-bg); box-shadow: var(--glass-dark-edge), 0 30px 60px -30px rgba(0, 0, 0, 0.6); }
body.in-sea .panel, body.in-sea .note, body.in-sea .place-name { color: var(--star); }
body.in-sea #place-chips span { background: var(--star); color: var(--night); }
body.in-sea .pile-dots i { box-shadow: inset 0 0 0 1.5px var(--star); }
body.in-sea .pile-dots i.is-on { background: var(--star); }

/* ---------- 竖着拿 ---------- */
@media (max-aspect-ratio: 1/1) {
  .panel { top: auto; left: var(--s5); right: var(--s5); bottom: calc(var(--s5) + env(safe-area-inset-bottom, 0px)); width: auto; height: 62vh; }
  .sheet-close { top: auto; bottom: calc(62vh + var(--s5) + var(--s3) + env(safe-area-inset-bottom, 0px)); right: var(--s5); }
  .pile-wrap { width: min(100%, 360px); align-self: center; aspect-ratio: 5 / 5.4; }
  .show-actions { left: 0; right: 0; justify-content: center; }
  .egg-video { width: 88vw; }
  .replay-hud { flex-direction: column; gap: var(--s3); }
}

/* ---------- 减少动态效果：大动作直接到结果，状态变化保留 200ms 淡入淡出，不缩放、不位移、不循环 ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; transition-duration: 200ms !important; transition-delay: 0s !important; }
  .pin-ring { display: none; }
  .panel, .card, .note .line, .paper p, .title .ch { transform: none !important; filter: none !important; }
  .end-card { transform: translate(-50%, -50%) !important; }
}
html.reduce *, html.reduce *::before, html.reduce *::after { animation-duration: 0.01ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; transition-duration: 200ms !important; transition-delay: 0s !important; }
html.reduce .pin-ring { display: none; }
html.reduce .panel, html.reduce .card, html.reduce .note .line, html.reduce .paper p, html.reduce .title .ch { transform: none !important; filter: none !important; }
html.reduce .end-card { transform: translate(-50%, -50%) !important; }

/* ---------- 没有 WebGL 时：地点排成一列 ---------- */
.no-webgl .pins { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s2); }
.no-webgl .pin { position: relative; margin: 0; width: auto; height: 44px; padding: 0 var(--s4) 0 40px; transform: none !important; }
.no-webgl .pin-dot, .no-webgl .pin-ring { left: 20px; }
.no-webgl .pin-label { position: static; transform: none; }
