/* ============================================
   宋京 SONG JING — styles.css
   星辰大海 · 地球生态 · 日夜主题
============================================ */

/* ---------- Theme: Night (default) ---------- */
:root {
  color-scheme: dark;      /* Safari reads this to paint its chrome in the dark tone */
  --bg-0: #05081a;
  --bg-1: #0a1234;
  --bg-2: #1a2350;
  --ink-0: #eaf0ff;
  --ink-1: #c9d2ea;
  --ink-2: #8c97b8;
  --accent: #ffd58a;
  --accent-2: #d97757;
  --accent-3: #6ea8c8;
  --leaf: #9ed18a;
  --grass: #5a8a4a;
  --shadow: 0 10px 30px rgba(0,0,0,.35);
  --radius: 18px;
  --tx: 0px;
  --ty: 0px;
  /* theme-dependent — dramatic night sky: top aurora tint + horizon glow */
  --sky-bg:
    radial-gradient(140% 48% at 50% 100%, rgba(46,110,150,0.55) 0%, rgba(46,110,150,0) 70%),
    radial-gradient(95% 55% at 50% 0%, rgba(120, 90, 210, 0.30) 0%, transparent 60%),
    linear-gradient(180deg, #060a1f 0%, #0a1132 22%, #101a48 48%, #182456 72%, #1f2c6a 90%, #0e1a3a 100%);
  --night-els: 1;   /* opacity of night-only elements */
  --day-els: 0;     /* opacity of day-only elements */
  --bird-ink: #1c2748;
  --win-color: #ffd58a;
  --glow-strength: 1;
  --brand-ink: #ffffff;
  --meta-theme: #140d2e;   /* night = 紫黑: purple-black, == .top-wash top == night theme-color */
  --hint-bg: rgba(12,18,38,.72);
  --hint-ink: #ffe9c2;
  --hint-border: rgba(255,213,138,.45);
  --hint-shadow: 0 6px 24px rgba(0,0,0,.45), 0 0 22px rgba(255,200,120,.16);
}


/* ---------- Theme: Day ---------- */
[data-theme="day"] {
  color-scheme: light;     /* Safari paints its chrome in the light tone */
  --sky-bg:
    linear-gradient(180deg, #4a9fdc 0%, #79bde8 38%, #a8d8f0 66%, #d4ecf6 100%);
  --night-els: 0;
  --day-els: 1;
  --bird-ink: #2a3a5c;
  --win-color: #ffe9b0;
  --glow-strength: .45;
  --brand-ink: #12325a;
  --ink-2: #4a6a94;
  --meta-theme: #4a9fdc;   /* = top stop of the day sky gradient */
  --hint-bg: rgba(255,255,255,.88);
  --hint-ink: #0e3a66;
  --hint-border: rgba(255,255,255,.9);
  --hint-shadow: 0 6px 22px rgba(30,80,140,.28), 0 0 0 1px rgba(255,255,255,.35);
}

/* Bulletproof day/night exclusivity: visibility flips driven directly by
   data-theme. On some Chromium-based browsers (Dia), var(--day-els) /
   var(--night-els) opacity transitions mis-render and leave day elements
   (e.g. clouds) as opaque silhouettes over a night sky. Pairing visibility
   with opacity removes them from paint AND hit-tree. */
/* Day mode: hide night-only elements */
[data-theme="day"] .moon,
[data-theme="day"] .starfield,
[data-theme="day"] .shooters,
[data-theme="day"] .planet--ring,
[data-theme="day"] .nebula,
[data-theme="day"] .top-wash,
[data-theme="day"] .horizon-glow { visibility: hidden; }
/* Night mode: hide day-only elements */
[data-theme="night"] .clouds,
[data-theme="night"] .sun,
[data-theme="night"] .birds { visibility: hidden; }
/* Day mode: show day-only elements */
[data-theme="day"] .clouds,
[data-theme="day"] .sun,
[data-theme="day"] .birds { visibility: visible; }
/* Night mode: show night-only elements */
[data-theme="night"] .moon,
[data-theme="night"] .starfield,
[data-theme="night"] .shooters,
[data-theme="night"] .planet--ring,
[data-theme="night"] .nebula,
[data-theme="night"] .top-wash,
[data-theme="night"] .horizon-glow { visibility: visible; }

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: 'Outfit', 'Noto Sans SC', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  color: var(--ink-1);
  background: var(--sky-bg);          /* full-bleed fallback so any area outside the fixed scene still shows sky */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow: hidden;
}

button { font: inherit; color: inherit; }

img { display: block; max-width: 100%; }

a { color: inherit; text-decoration: none; }

/* ============================================
   HERO SCENE
============================================ */
.home.scene-root {
  position: fixed;          /* edge-to-edge: extends under the status bar and home indicator */
  inset: 0;
  width: 100%;
  height: 100dvh;      /* tracks the collapsing address bar → no jump, no letterbox */
  min-height: min(600px, 100svh);   /* floor for landscape, but never taller than the screen */
  overflow: hidden;
  isolation: isolate;
  background: var(--sky-bg);
  transition: background 1.1s ease;
}

.parallax {
  position: absolute;
  inset: -2%;
  width: 104%;
  height: 104%;
  transform: translate3d(var(--tx), var(--ty), 0);
  will-change: transform;
}

.layer {
  position: absolute;
  inset: 0;
}

/* ---------- Sky ---------- */
.layer.sky { z-index: 1; }

.nebula {
  position: absolute;
  border-radius: 50%;
  filter: blur(40px);
  opacity: calc(.55 * var(--night-els));
  mix-blend-mode: screen;
  pointer-events: none;
  transition: opacity 1.1s ease;
}
.nebula--a {
  /* Top aurora scrim — spans the full width, but kept gentle so the very top
     stays 紫黑 (purple-black) and the stars read clearly. */
  width: 100%; height: 360px;
  left: 0; top: -30px;
  border-radius: 0;
  background: radial-gradient(ellipse 100% 100% at 50% 0%,
    rgba(120, 85, 185, 0.30) 0%,
    rgba(95, 66, 172, 0.16) 45%,
    rgba(75, 55, 150, 0.07) 78%,
    transparent 100%);
  filter: blur(30px);
  opacity: calc(.8 * var(--night-els));
  animation: drift 44s ease-in-out infinite alternate; }
.nebula--b { width: 640px; height: 640px; right: -160px; top: 18%;
  background: radial-gradient(circle, #c46bff 0%, transparent 60%);
  animation: drift 38s ease-in-out infinite alternate-reverse; }
.nebula--c { width: 480px; height: 480px; left: 38%; top: 50%;
  background: radial-gradient(circle, #6aa9ff 0%, transparent 60%);
  opacity: calc(.45 * var(--night-els));
  animation: drift 44s ease-in-out infinite alternate; }

/* Status-bar cap: pinned to the very top so the iOS/Android status bar melts into
   the sky edge-to-edge. Its TOP pixel is solid --meta-theme (== night theme-color),
   so the OS chrome and the page share the exact same colour and there is no seam on
   ANY browser (Chrome paints it as the bar; Safari paints a translucent bar over it).
   It then fades into the starry sky below so the stars still read clearly. */
.top-wash {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 84px;
  background: linear-gradient(180deg,
    var(--meta-theme) 0%,
    rgba(20, 13, 46, 0.78) 34%,
    rgba(20, 13, 46, 0.34) 64%,
    transparent 100%);
  pointer-events: none;
  z-index: 2;
  opacity: var(--night-els);
  transition: opacity 1.1s ease;
}

@keyframes drift {
  from { transform: translate3d(0,0,0) scale(1); }
  to   { transform: translate3d(40px,-30px,0) scale(1.08); }
}

.starfield {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: var(--night-els);
  transition: opacity 1.1s ease;
}

/* Moon (night) */
.moon {
  position: absolute;
  width: 90px;
  height: 90px;
  top: 10%;
  right: 8%;
  opacity: var(--night-els);
  transition: opacity 1.1s ease, transform 1.1s ease;
  filter: drop-shadow(0 0 24px rgba(255,236,180,.45));
  animation: moon-float 14s ease-in-out infinite alternate;
}
@keyframes moon-float {
  from { transform: translateY(0) rotate(-2deg); }
  to   { transform: translateY(-14px) rotate(2deg); }
}

/* Sun (day) */
.sun {
  position: absolute;
  width: 110px;
  height: 110px;
  top: 9%;
  right: 8%;
  opacity: var(--day-els);
  transition: opacity 1.1s ease, transform 1.1s ease;
  pointer-events: none;
}
.sun__core {
  position: absolute;
  inset: 18px;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 34%, #fffbe8 0%, #ffe08a 55%, #ffb84d 100%);
  box-shadow:
    0 0 40px rgba(255,214,120,.9),
    0 0 110px rgba(255,190,90,.55);
  animation: sun-pulse 5s ease-in-out infinite alternate;
}
.sun__rays {
  position: absolute;
  inset: -16px;
  border-radius: 50%;
  background:
    conic-gradient(
      rgba(255,210,110,.55) 0deg 6deg, transparent 6deg 30deg,
      rgba(255,210,110,.55) 30deg 36deg, transparent 36deg 60deg,
      rgba(255,210,110,.55) 60deg 66deg, transparent 66deg 90deg,
      rgba(255,210,110,.55) 90deg 96deg, transparent 96deg 120deg,
      rgba(255,210,110,.55) 120deg 126deg, transparent 126deg 150deg,
      rgba(255,210,110,.55) 150deg 156deg, transparent 156deg 180deg,
      rgba(255,210,110,.55) 180deg 186deg, transparent 186deg 210deg,
      rgba(255,210,110,.55) 210deg 216deg, transparent 216deg 240deg,
      rgba(255,210,110,.55) 240deg 246deg, transparent 246deg 270deg,
      rgba(255,210,110,.55) 270deg 276deg, transparent 276deg 300deg,
      rgba(255,210,110,.55) 300deg 306deg, transparent 306deg 330deg,
      rgba(255,210,110,.55) 330deg 336deg, transparent 336deg 360deg);
  -webkit-mask: radial-gradient(circle, transparent 46%, #000 50%);
          mask: radial-gradient(circle, transparent 46%, #000 50%);
  animation: sun-spin 40s linear infinite;
}
@keyframes sun-pulse {
  from { box-shadow: 0 0 40px rgba(255,214,120,.9), 0 0 110px rgba(255,190,90,.5); }
  to   { box-shadow: 0 0 54px rgba(255,214,120,1),  0 0 150px rgba(255,190,90,.7); }
}
@keyframes sun-spin { to { transform: rotate(360deg); } }

/* Clouds (day) */
.clouds {
  position: absolute;
  inset: 0;
  opacity: var(--day-els);
  transition: opacity 1.1s ease;
  pointer-events: none;
}
.cloud {
  position: absolute;
  opacity: .92;
  filter: drop-shadow(0 8px 16px rgba(60,100,150,.18));
}
.cloud--1 { width: 210px; top: 12%; left: -220px; animation: cloud-drift 56s linear infinite; }
.cloud--2 { width: 150px; top: 26%; left: -160px; animation: cloud-drift 74s linear infinite 12s; opacity: .8; }
.cloud--3 { width: 260px; top: 7%;  left: -280px; animation: cloud-drift 92s linear infinite 30s; opacity: .7; }
@keyframes cloud-drift {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(100vw + 320px)); }
}

/* Distant planet (night) */
.planet--ring {
  position: absolute;
  width: 130px;
  height: 130px;
  left: 6%;
  top: 11%;
  border-radius: 50%;
  opacity: var(--night-els);
  transition: opacity 1.1s ease;
  background:
    radial-gradient(circle at 35% 35%, #f4d6a8 0%, #b07d4a 60%, #5d3a22 100%);
  box-shadow: inset 0 0 30px rgba(0,0,0,.4);
  animation: planet-spin 28s linear infinite;
}
.planet--ring::after {
  content: "";
  position: absolute;
  inset: -22px -34px;
  border: 2px solid rgba(218,177,121,.55);
  border-radius: 50%;
  transform: rotate(-18deg);
  box-shadow: 0 0 0 1px rgba(0,0,0,.2) inset;
  animation: ring-tilt 12s ease-in-out infinite alternate;
}
@keyframes planet-spin {
  from { transform: translateY(0) rotate(0deg); }
  to   { transform: translateY(-10px) rotate(360deg); }
}
@keyframes ring-tilt {
  from { transform: rotate(-22deg) scaleX(1); }
  to   { transform: rotate(-14deg) scaleX(1.06); }
}

/* Shooting stars (night) */
.shooters {
  position: absolute;
  inset: 0;
  opacity: var(--night-els);
  transition: opacity 1.1s ease;
  pointer-events: none;
}
.shooter {
  position: absolute;
  top: 8%;
  width: 140px;
  height: 1.5px;
  background: linear-gradient(90deg, transparent, #fff 60%, #fff);
  filter: drop-shadow(0 0 4px #fff);
  opacity: 0;
  transform: rotate(20deg);
  animation: shoot 7s ease-in infinite;
}
.s1 { left: 10%; animation-delay: 1.2s; }
.s2 { left: 40%; top: 18%; animation-delay: 3.6s; animation-duration: 9s; }
.s3 { left: 70%; top: 6%;  animation-delay: 5.4s; animation-duration: 8s; }

@keyframes shoot {
  0%   { opacity: 0; transform: translate(0,0) rotate(20deg); }
  4%   { opacity: 1; }
  20%  { opacity: 0; transform: translate(420px,180px) rotate(20deg); }
  100% { opacity: 0; transform: translate(420px,180px) rotate(20deg); }
}

/* ---------- Birds ---------- */
.layer.mid { z-index: 3; pointer-events: none; }
.birds {
  position: absolute;
  width: 100%;
  height: 60%;
  top: 0;
  fill: none;
  stroke: var(--bird-ink);
  stroke-width: 2;
  stroke-linecap: round;
  /* birds fly across the sky in daytime, fade out at night */
  opacity: calc(.9 * var(--day-els));
  transition: opacity 1.1s ease, stroke 1.1s ease;
}
.bird-flap { transform-box: fill-box; transform-origin: 50% 100%; animation: flap 1.6s ease-in-out infinite; }
.bird-flap.delay-2 { animation-delay: .3s; }
.bird-flap.delay-3 { animation-delay: .6s; }
.bird-flap.delay-4 { animation-delay: .9s; }
.bird-flap.delay-5 { animation-delay: 1.2s; }
.bird-flap.delay-6 { animation-delay: .5s; animation-duration: 1.5s; }
.bird-flap.delay-7 { animation-delay: .8s; animation-duration: 1.7s; }
@keyframes flap {
  0%,100% { transform: scaleY(1); }
  50%     { transform: scaleY(.55); }
}
.b1 { animation: fly  28s linear infinite; }
.b2 { animation: fly2 36s linear infinite; }
.b3 { animation: fly3 32s linear infinite; }
.b4 { animation: fly4 40s linear infinite; }
.b5 { animation: fly5 34s linear infinite; }
.b6 { animation: fly6 46s linear infinite 6s; }
.b7 { animation: fly7 38s linear infinite 14s; }

@keyframes fly {
  0%   { transform: translate(-80px, 140px) scale(.9); }
  50%  { transform: translate(700px, 100px) scale(1); }
  100% { transform: translate(1700px, 160px) scale(.9); }
}
@keyframes fly2 {
  0%   { transform: translate(1700px, 200px) scale(1); }
  50%  { transform: translate(800px, 240px) scale(.95); }
  100% { transform: translate(-100px, 220px) scale(1); }
}
@keyframes fly3 {
  0%   { transform: translate(-100px, 80px) scale(.7); }
  100% { transform: translate(1800px, 60px) scale(.7); }
}
@keyframes fly4 {
  0%   { transform: translate(1700px, 300px) scale(.85); }
  100% { transform: translate(-100px, 280px) scale(.85); }
}
@keyframes fly5 {
  0%   { transform: translate(-100px, 220px) scale(.6); }
  100% { transform: translate(1800px, 200px) scale(.6); }
}
@keyframes fly6 {
  0%   { transform: translate(-100px, 180px) scale(.75); }
  50%  { transform: translate(800px, 150px) scale(.8); }
  100% { transform: translate(1800px, 190px) scale(.75); }
}
@keyframes fly7 {
  0%   { transform: translate(1700px, 70px) scale(.65); }
  50%  { transform: translate(750px, 95px) scale(.7); }
  100% { transform: translate(-100px, 75px) scale(.65); }
}

/* ---------- Earth ---------- */
.layer.earth-layer { z-index: 4; }

/* Earth atmosphere / horizon glow: fills the strip above the planet's arc and
   the very bottom edge so the home indicator fuses with a glowing earth. */
.earth-layer::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 36%;
  background:
    linear-gradient(180deg,
      transparent 0%,
      transparent 48%,
      rgba(70, 185, 150, 0.55) 74%,
      rgba(30, 95, 72, 0.78) 90%,
      #16301f 100%);
  z-index: 1;
  pointer-events: none;
}

/* Ground rim-light: luminous planet-edge glow at the very bottom so the
   navigation-bar area reads as a lit atmosphere, not a flat green patch. */
.ground-mist {
  position: absolute;
  left: -25%; right: -25%;
  bottom: 0;
  height: 24%;
  background:
    radial-gradient(36% 100% at 50% 100%, rgba(210, 255, 225, 0.72) 0%, rgba(140, 240, 185, 0.42) 18%, rgba(80, 200, 140, 0.20) 40%, transparent 62%),
    radial-gradient(85% 55% at 50% 100%, rgba(110, 225, 160, 0.50) 0%, rgba(60, 170, 110, 0.22) 32%, transparent 62%),
    radial-gradient(102% 38% at 50% 100%, rgba(90, 190, 130, 0.36) 0%, transparent 58%);
  filter: blur(5px);
  pointer-events: none;
  z-index: 3;
  opacity: var(--night-els);
  transition: opacity 1.1s ease;
}

/* Horizon atmosphere band — a soft teal glow sitting in the sky just above
   the planet's edge. Placed in the sky layer so it shows wherever the earth
   is transparent (above the arc), creating a luminous horizon on every device. */
.horizon-glow {
  position: absolute;
  left: 50%;
  bottom: 22%;
  width: 200%;
  height: 24%;
  transform: translateX(-50%);
  background:
    radial-gradient(45% 100% at 50% 100%, rgba(70, 210, 180, 0.50) 0%, rgba(40, 160, 140, 0.25) 45%, transparent 75%),
    radial-gradient(95% 65% at 50% 100%, rgba(50, 180, 160, 0.32) 0%, transparent 68%);
  filter: blur(16px);
  pointer-events: none;
  opacity: var(--night-els);
  transition: opacity 1.1s ease;
}

.earth {
  position: absolute;
  left: 50%;
  bottom: -8%;
  width: min(1800px, 112%);
  transform: translateX(-50%);
  z-index: 2;
  filter: drop-shadow(0 30px 80px rgba(0,0,0,.6));
  animation: earth-breath 8s ease-in-out infinite alternate;
}
@keyframes earth-breath {
  from { transform: translateX(-50%) translateY(0); }
  to   { transform: translateX(-50%) translateY(-6px); }
}

/* Grass sway */
.grass path { transform-box: fill-box; transform-origin: 50% 100%; animation: sway 4s ease-in-out infinite; }
.grass path:nth-child(2n) { animation-duration: 5s; animation-delay: -1s; }
.grass path:nth-child(3n) { animation-duration: 6s; animation-delay: -2s; }
@keyframes sway { 0%,100% { transform: rotate(-4deg);} 50% { transform: rotate(4deg);} }

/* Flowers bob */
.flower .flower-inner { transform-box: fill-box; transform-origin: 50% 50%; animation: bob 3s ease-in-out infinite; }
.f2 .flower-inner { animation-duration: 3.6s; animation-delay: -.4s; }
.f3 .flower-inner { animation-duration: 4.2s; animation-delay: -.8s; }
.f4 .flower-inner { animation-duration: 3.4s; animation-delay: -1.2s; }
.f5 .flower-inner { animation-duration: 4s;   animation-delay: -1.6s; }
@keyframes bob {
  0%,100% { transform: translate(0,0) rotate(-3deg); }
  50%     { transform: translate(0,-3px) rotate(3deg); }
}

/* Trees sway */
.trees .tree-sway { transform-box: fill-box; transform-origin: 50% 100%; animation: tree-sway 6s ease-in-out infinite; }
.trees .tree-sway:nth-child(1) { animation-delay: 0s; }
.trees .tree-sway:nth-child(2) { animation-delay: -1.4s; animation-duration: 7s; }
.trees .tree-sway:nth-child(3) { animation-delay: -2.8s; animation-duration: 5.5s; }
.trees .tree-sway:nth-child(4) { animation-delay: -1s; animation-duration: 6.5s; }
.trees .tree-sway:nth-child(5) { animation-delay: -2.2s; animation-duration: 7s; }
.trees .tree-sway:nth-child(6) { animation-delay: -0.6s; animation-duration: 5.8s; }
.trees .tree-sway:nth-child(7) { animation-delay: -3.2s; animation-duration: 6.2s; }
@keyframes tree-sway { 0%,100% { transform: rotate(-2deg);} 50% { transform: rotate(2deg);} }

/* Pond ripples */
.pond .ripple { transform-box: fill-box; transform-origin: center; animation: ripple-expand 4.5s ease-out infinite; }
.pond .ripple.r2 { animation-delay: -2.2s; }
@keyframes ripple-expand {
  0%   { transform: scale(.35); opacity: .6; }
  70%  { opacity: .25; }
  100% { transform: scale(1.3); opacity: 0; }
}

/* Fish swim + tail wag */
.fish { animation: fish-swim 7.5s ease-in-out infinite; }
@keyframes fish-swim {
  0%,100% { transform: translateX(-32px); }
  50%     { transform: translateX(30px); }
}
.fish-tail { transform-box: fill-box; transform-origin: 12px 0; animation: tail-wag .8s ease-in-out infinite; }
@keyframes tail-wag { 0%,100% { transform: rotate(-13deg); } 50% { transform: rotate(13deg); } }

/* Frog blink */
.frog-eye { transform-box: fill-box; transform-origin: center; animation: frog-blink 4.5s ease-in-out infinite; }
@keyframes frog-blink { 0%,92%,100% { transform: scaleY(1); } 96% { transform: scaleY(.1); } }

/* ---------- Villa ---------- */
.villa {
  position: absolute;
  width: 250px;
  left: 22%;
  bottom: clamp(32%, 36vh, 42%);   /* distance from earth scales with viewport height, like the character */
  z-index: 5;
  filter: drop-shadow(0 8px 14px rgba(0,0,0,.45));
}
.villa .win {
  fill: var(--win-color);
  filter: drop-shadow(0 0 8px rgba(255,213,138, calc(.85 * var(--glow-strength))));
  animation: window-glow 4s ease-in-out infinite alternate;
  transition: fill 1.1s ease;
}
@keyframes window-glow {
  from { opacity: .85; }
  to   { opacity: 1; }
}
.smoke circle { animation: rise 5s ease-in infinite; opacity: 0; }
.smoke circle:nth-child(1) { animation-delay: 0s; }
.smoke circle:nth-child(2) { animation-delay: 1.4s; }
.smoke circle:nth-child(3) { animation-delay: 2.8s; }
@keyframes rise {
  0%   { transform: translate(0,0); opacity: 0; }
  20%  { opacity: .55; }
  100% { transform: translate(8px,-60px); opacity: 0; }
}
/* string lights twinkle */
.string-lights .light {
  transform-box: fill-box;
  transform-origin: center;
  filter: drop-shadow(0 0 5px currentColor);
  animation: light-twinkle 2.8s ease-in-out infinite;
}
.string-lights .light:nth-child(2) { animation-delay: .5s; }
.string-lights .light:nth-child(3) { animation-delay: 1s; }
.string-lights .light:nth-child(4) { animation-delay: 1.5s; }
.string-lights .light:nth-child(5) { animation-delay: 2s; }
@keyframes light-twinkle {
  0%,100% { opacity: 1; }
  50%     { opacity: calc(.35 + .3 * var(--glow-strength)); }
}

/* ---------- RV ---------- */
.rv {
  position: absolute;
  width: 280px;
  right: 18%;
  bottom: clamp(32%, 36vh, 42%);   /* distance from earth scales with viewport height, like the character */
  filter: drop-shadow(0 8px 14px rgba(0,0,0,.45));
  z-index: 5;
  animation: rv-bob 5s ease-in-out infinite alternate;
}
@keyframes rv-bob {
  from { transform: translateY(0); }
  to   { transform: translateY(-3px); }
}
.rv .wheel { animation: wheel 2s linear infinite; transform-origin: center; transform-box: fill-box; }
@keyframes wheel { to { transform: rotate(360deg); } }
.rv .awnlight { animation: blink 2.4s ease-in-out infinite; }
@keyframes blink { 50% { opacity: .3; } }
/* exhaust puffs */
.exhaust circle { animation: puff 3.2s ease-out infinite; }
.exhaust circle:nth-child(1) { animation-delay: 0s; }
.exhaust circle:nth-child(2) { animation-delay: .8s; }
.exhaust circle:nth-child(3) { animation-delay: 1.6s; }
@keyframes puff {
  0%   { transform: translate(0,0) scale(.5); opacity: 0; }
  15%  { opacity: .55; }
  100% { transform: translate(-26px,-16px) scale(1.7); opacity: 0; }
}

/* ---------- Character: programmer at desk ---------- */
.character-layer {
  z-index: 6;
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.character {
  pointer-events: auto;
  position: absolute;
  left: 50%;
  bottom: clamp(26%, 30vh, 36%);
  width: 230px;
  height: 192px;
  transform: translateX(-50%);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  transition: transform .3s cubic-bezier(.16,1,.3,1);
}
.character:hover { transform: translateX(-50%) translateY(-4px) scale(1.04); }
.character:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: 14px; }
.character svg { width: 100%; height: 100%; overflow: visible; }

/* head: subtle bob (looking at screen) */
.character-fig .head {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: head-bob 5s ease-in-out infinite;
}
@keyframes head-bob {
  0%,100% { transform: rotate(-2deg) translateY(0); }
  50%     { transform: rotate(1.5deg) translateY(1.5px); }
}
/* body breathe */
.character-fig .body {
  transform-box: fill-box;
  transform-origin: 50% 0%;
  animation: breathe 4.5s ease-in-out infinite;
}
@keyframes breathe { 50% { transform: scaleY(1.012); } }

/* typing hands */
.character-fig .hand {
  transform-box: fill-box;
  transform-origin: center;
}
.character-fig .hand--l { animation: type-l .26s ease-in-out infinite alternate; }
.character-fig .hand--r { animation: type-r .26s ease-in-out infinite alternate .13s; }
@keyframes type-l { from { transform: translateY(0); } to { transform: translateY(3px); } }
@keyframes type-r { from { transform: translateY(3px); } to { transform: translateY(0); } }

/* screen glow */
.character-fig .screen-glow {
  transform-box: fill-box;
  transform-origin: center;
  animation: screen-pulse 3.4s ease-in-out infinite alternate;
}
@keyframes screen-pulse {
  from { opacity: calc(.16 * var(--glow-strength) + .06); }
  to   { opacity: calc(.34 * var(--glow-strength) + .1); }
}
.character-fig .laptop-logo {
  transform-box: fill-box;
  transform-origin: center;
  animation: logo-glow 3.4s ease-in-out infinite alternate;
}
@keyframes logo-glow {
  from { opacity: .8; filter: drop-shadow(0 0 4px rgba(143,208,255,.7)); }
  to   { opacity: 1;  filter: drop-shadow(0 0 10px rgba(143,208,255,.95)); }
}

/* tea steam */
.character-fig .steam path {
  stroke-dasharray: 26;
  animation: steam-rise 3s ease-in-out infinite;
  opacity: 0;
}
.character-fig .steam path:nth-child(2) { animation-delay: 1.5s; }
@keyframes steam-rise {
  0%   { stroke-dashoffset: 26; opacity: 0; transform: translateY(0); }
  30%  { opacity: .8; }
  100% { stroke-dashoffset: -26; opacity: 0; transform: translateY(-6px); }
}

/* floating code symbols */
.character-fig .code {
  transform-box: fill-box;
  transform-origin: center;
  animation: code-float 4s ease-in-out infinite;
  opacity: .75;
}
.character-fig .c1 { animation-delay: 0s; }
.character-fig .c2 { animation-delay: 1.3s; }
.character-fig .c3 { animation-delay: 2.6s; }
@keyframes code-float {
  0%,100% { transform: translateY(0) rotate(-4deg); opacity: .4; }
  50%     { transform: translateY(-8px) rotate(4deg); opacity: .9; }
}

.halo {
  position: absolute;
  inset: -10% -10%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,213,138,.35), transparent 60%);
  opacity: 0;
  transition: opacity .4s ease;
  pointer-events: none;
}
.character:hover .halo,
.character:focus-visible .halo { opacity: 1; }

/* hint — label above the character's head */
.hint {
  position: absolute;
  left: 50%;
  bottom: 100%;          /* anchored just above the character's head on every device */
  margin-bottom: 16px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  border-radius: 999px;
  background: var(--hint-bg);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--hint-border);
  box-shadow: var(--hint-shadow);
  color: var(--hint-ink);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: .06em;
  white-space: nowrap;
  opacity: 0;
  animation: hint-fade 8s ease-in-out 1.5s infinite;
  pointer-events: none;
  transition: background 1.1s ease, color 1.1s ease, border-color 1.1s ease, box-shadow 1.1s ease;
}
.hint::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -7px;
  width: 12px;
  height: 12px;
  transform: translateX(-50%) rotate(45deg);
  background: var(--hint-bg);
  border-right: 1px solid var(--hint-border);
  border-bottom: 1px solid var(--hint-border);
  transition: background 1.1s ease, border-color 1.1s ease;
}
.hint__dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 14px var(--accent);
  animation: pulse 1.6s ease-in-out infinite;
  flex: none;
}
@keyframes pulse { 50% { transform: scale(1.5); opacity: .5; } }
@keyframes hint-fade {
  0% { opacity: 0; transform: translateX(-50%) translateY(6px); }
  20%,70% { opacity: 1; transform: translateX(-50%) translateY(0); }
  85% { opacity: 1; transform: translateX(-50%) translateY(-3px); }
  100% { opacity: 0; transform: translateX(-50%) translateY(6px); }
}

/* ---------- Brand / Signature / Theme toggle ---------- */
/* Brand + signature + theme/lang toggles all use position:fixed so they sit in
   the global stacking context and stay above the scene (which is `isolation:
   isolate` inside <main>). On browsers with quirky stacking-context handling
   (e.g. some Chromium-based forks), `position:absolute` children of an
   isolated ancestor can be silently clipped; pinning to fixed sidesteps it. */
.brand {
  position: fixed;
  top: max(22px, env(safe-area-inset-top) + 14px);
  left: max(28px, env(safe-area-inset-left) + 14px);
  z-index: 70;
  display: flex;
  align-items: baseline;
  gap: 8px;
  color: var(--ink-1);
  letter-spacing: .02em;
  transition: color 1.1s ease;
}
.brand__mark {
  font-family: 'Noto Serif SC', 'Fraunces', serif;
  font-weight: 700;
  font-size: 24px;
  color: var(--brand-ink);
  transition: color 1.1s ease;
}
.brand__sub {
  font-size: 12px;
  color: var(--ink-2);
  letter-spacing: .12em;
  text-transform: uppercase;
}

.theme-toggle {
  position: fixed;
  top: max(20px, env(safe-area-inset-top) + 12px);
  right: max(24px, env(safe-area-inset-right) + 14px);
  z-index: 10;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.08);
  color: var(--ink-0);
  backdrop-filter: blur(10px);
  cursor: pointer;
  transition: transform .25s ease, background .25s ease;
}
.theme-toggle:hover { background: rgba(255,255,255,.18); transform: rotate(20deg) scale(1.06); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* stay reachable above the intro overlay (z-index 50) */
.theme-toggle { z-index: 60; }
[data-theme="day"] .theme-toggle { border-color: rgba(20,50,90,.25); background: rgba(255,255,255,.5); color: #23557e; }
.theme-toggle .icon { grid-area: 1 / 1; transition: opacity .5s ease, transform .5s ease; }
.theme-toggle .icon--moon { opacity: var(--night-els); transform: rotate(calc((1 - var(--night-els)) * 90deg)); }
.theme-toggle .icon--sun  { opacity: var(--day-els);  transform: rotate(calc((1 - var(--day-els)) * -90deg)); }

/* Language toggle (next to theme toggle) */
.lang-toggle {
  position: fixed;
  top: max(20px, env(safe-area-inset-top) + 12px);
  right: max(78px, env(safe-area-inset-right) + 68px);
  z-index: 10;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.08);
  color: var(--ink-0);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  cursor: pointer;
  font: 600 13px/1 'Outfit', 'Noto Sans SC', sans-serif;
  letter-spacing: .02em;
  transition: transform .25s ease, background .25s ease;
}
.lang-toggle:hover { background: rgba(255,255,255,.18); transform: translateY(-2px); }
.lang-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.lang-toggle { z-index: 60; }
[data-theme="day"] .lang-toggle { border-color: rgba(20,50,90,.25); background: rgba(255,255,255,.5); color: #23557e; }

/* Back-to-top (About page; shown after scrolling) */
.intro-top {
  position: fixed;
  right: 26px;
  bottom: 26px;
  z-index: 55;                 /* above intro overlay (50), below toggles (60) */
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  color: var(--ink-1);
  background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 50%;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  cursor: pointer;
  opacity: 0;
  transform: translateY(16px) scale(.92);
  pointer-events: none;
  transition: opacity .35s ease, transform .35s ease, background .25s ease;
}
.intro-top.is-shown {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.intro-top:hover {
  background: rgba(255,255,255,.16);
  color: var(--accent);
}
.intro-top:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (max-width: 600px) {
  .intro-top { right: 18px; bottom: 18px; width: 44px; height: 44px; }
}

.signature {
  position: fixed;
  bottom: max(22px, env(safe-area-inset-bottom) + 18px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 70;
  font-size: 12px;
  letter-spacing: .22em;
  color: var(--ink-0);
  opacity: .95;
  padding: 7px 18px;
  border-radius: 999px;
  background: rgba(10,14,28,.42);
  border: 1px solid rgba(255,255,255,.16);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  text-shadow: 0 1px 3px rgba(0,0,0,.55);
  white-space: nowrap;
  pointer-events: none;
  transition: opacity .35s ease, transform .35s ease, background .35s ease;
}
.signature:hover {
  opacity: 1;
  transform: translateX(-50%) translateY(-3px);
  background: rgba(10,14,28,.55);
}

/* ============================================
   INTRO PAGE (overlay)
============================================ */
.intro {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--sky-bg);            /* same sky as the homepage, theme-adaptive */
  background-color: var(--bg-0);
  transform: translateY(100%);
  transition: transform .9s cubic-bezier(.16,1,.3,1), background 1.1s ease;
  overflow: hidden;   /* .intro no longer scrolls; .intro__inner is the scroller so the back button can stay pinned */
  color: var(--ink-1);
}
.intro.is-open { transform: translateY(0); }

/* Earth-horizon glow at the bottom, echoing the homepage scene so the page blends in */
.intro::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 42%;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 0%, rgba(94,160,120,.10) 55%, rgba(70,120,80,.22) 100%);
  z-index: 0;
}

.intro__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.intro__stars {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(1px 1px at 12% 18%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 28% 42%, #cfe2ff 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 44% 8%,  #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 60% 30%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 75% 60%, #cfe2ff 50%, transparent 51%),
    radial-gradient(1.4px 1.4px at 88% 12%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 92% 78%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 20% 80%, #cfe2ff 50%, transparent 51%),
    radial-gradient(1px 1px at 50% 92%, #fff 50%, transparent 51%),
    radial-gradient(1.4px 1.4px at 6%  62%, #fff 50%, transparent 51%);
  opacity: var(--night-els);           /* visible at night, hidden in day mode */
  animation: twinkle 5s ease-in-out infinite alternate;
}
@keyframes twinkle { to { filter: brightness(.55); } }

.intro__back {
  position: absolute;   /* pinned top-left of the non-scrolling .intro wrapper; stays put while .intro__inner scrolls */
  top: max(20px, env(safe-area-inset-top) + 12px);
  left: max(22px, env(safe-area-inset-left) + 14px);
  z-index: 60;          /* above intro content, level with the theme/lang toggles */
  width: fit-content;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  background: rgba(255,255,255,.06);
  color: var(--ink-1);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: 999px;
  backdrop-filter: blur(10px);
  cursor: pointer;
  transition: transform .2s ease, background .2s ease;
}
.intro__back:hover { background: rgba(255,255,255,.12); transform: translateX(-2px); }
.intro__back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.intro__inner {
  position: absolute;   /* the actual scroll container inside the non-scrolling .intro wrapper */
  inset: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
  padding: 84px 24px 72px;
}

.intro__card {
  position: relative;
  width: min(860px, 100%);
  padding: 48px 44px 40px;
  background:
    linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.02));
  border: 1px solid rgba(255,255,255,.1);
  border-radius: var(--radius);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.12),
    0 30px 80px rgba(0,0,0,.45);
  backdrop-filter: blur(14px);
}
.intro__card--map { width: min(1100px, 100%); padding: 36px 36px 32px; }

/* ===== About-page left rail: TOC + portrait + contact card column =====
   Default (phones): the rail dissolves via display:contents so its children join
   .intro__inner's flex column. The TOC nav is hidden, and the contact column is
   pushed to the very bottom with `order`. */
.intro__rail { display: contents; }
.intro__toc { display: none; }

/* Contact card column — base (phone) styling: a full-width card at the bottom */
.intro__contact {
  order: 99;
  width: 100%;
  max-width: 760px;
  padding: 16px 14px 18px;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 14px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
/* Personal portrait sits in the middle of the contact column, centered */
.intro__toc-portrait {
  margin: 14px auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.intro__toc-portrait-img {
  display: block;
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: 12px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.12),
    0 8px 22px rgba(0,0,0,.30);
}
.intro__toc-portrait-cap {
  margin-top: 7px;
  font-size: 12px;
  letter-spacing: .08em;
  color: var(--ink-2);
}
/* Hide the portrait on phones — the contact column stacks at the very bottom on
   mobile, where the photo adds little and takes vertical space. Shown again at
   ≥860px where it sits inside the sidebar rail. */
@media (max-width: 859px) {
  .intro__toc-portrait { display: none; }
}
.intro__contact-title {
  margin: 0 0 12px;
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-2);
  font-weight: 600;
}
.contact-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 8px;
}
.contact-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 10px;
  text-decoration: none;
  color: var(--ink-1);
  background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.08);
  transition: background .2s ease, color .2s ease, border-color .2s ease, transform .15s ease;
}
.contact-card:hover,
.contact-card:focus-visible {
  background: rgba(255,213,138,.12);
  color: var(--ink-0);
  border-color: rgba(255,213,138,.32);
  transform: translateX(2px);
}
.contact-card__icon {
  flex: 0 0 24px;
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  background: rgba(255,213,138,.14);
  color: var(--accent);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1;
}
.contact-card__label {
  font-size: 13.5px;
  font-weight: 500;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.intro__content {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
}

@media (min-width: 1100px) {
  /* Wide screens: phantom right column balances the sidebar's weight so the
     card's centerline aligns with the viewport's centerline. */
  .intro__inner {
    display: grid;
    grid-template-columns: 160px minmax(0, 900px) 160px;
    column-gap: 28px;
    align-items: start;
    justify-content: center;
    padding: 84px 24px 72px;
  }
  /* The rail (TOC + portrait + contact) is one sticky block in column 1 */
  .intro__rail {
    grid-column: 1;
    display: flex;
    flex-direction: column;
    gap: 12px;
    position: sticky;
    top: 84px;
    max-height: calc(100vh - 190px);
    overflow-y: auto;
    /* `auto` (not `contain`) so the wheel keeps scrolling the page once the rail
       reaches its own end — `contain` made the pointer feel trapped over the rail. */
    overscroll-behavior: auto;
    scrollbar-width: thin;
  }
  .intro__toc {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 14px 12px;
    background: rgba(255,255,255,.05);
    border: 1px solid rgba(255,255,255,.12);
    border-radius: 14px;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
  }
  /* Contact column: single vertical stack inside the narrow rail */
  .intro__contact { order: 0; width: auto; max-width: none; }
  .contact-cards { grid-template-columns: 1fr; gap: 4px; }
  .contact-card { padding: 5px 8px; gap: 8px; }
  .intro__content {
    grid-column: 2;
    width: 100%;
    max-width: 900px;
    justify-self: center;
  }
}

@media (min-width: 860px) and (max-width: 1099px) {
  /* Mid screens: 2-col layout, composition centered via justify-content. */
  .intro__inner {
    flex-direction: row;
    align-items: flex-start;
    gap: 24px;
    justify-content: center;
    padding: 84px 20px 72px;
  }
  .intro__content { flex: 0 1 auto; min-width: 0; max-width: 760px; }

  .intro__rail {
    display: flex;
    flex-direction: column;
    gap: 12px;
    flex: 0 0 160px;
    align-self: flex-start;
    position: sticky;
    top: 84px;
    max-height: calc(100vh - 190px);
    overflow-y: auto;
    /* `auto` (not `contain`) so the wheel keeps scrolling the page once the rail
       reaches its own end — `contain` made the pointer feel trapped over the rail. */
    overscroll-behavior: auto;
    scrollbar-width: thin;
  }
  .intro__toc {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 14px 12px;
    background: rgba(255,255,255,.05);
    border: 1px solid rgba(255,255,255,.12);
    border-radius: 14px;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
  }
  .intro__contact { order: 0; width: auto; max-width: none; }
  .contact-cards { grid-template-columns: 1fr; gap: 4px; }
  .contact-card { padding: 5px 8px; gap: 8px; }
  .intro__contact-title { margin-bottom: 8px; }
}

@media (min-width: 860px) {
  /* The sidebar is `position: sticky; top: 84px`, and that offset is measured
     from .intro__inner's content box — which already starts 84px down because of
     the container's padding-top. So the sidebar settles at 84 + 84 = 168px while
     the content column starts at 84px. Push the content down by the same 84px so
     the card's top edge lines up with the sidebar's top edge. */
  .intro__content { margin-top: 84px; }

  .intro__toc-title {
    font-size: 11px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--ink-2);
    padding: 2px 10px 8px;
    font-weight: 600;
  }
  .intro__toc-link {
    display: block;
    padding: 5px 10px;
    border-radius: 9px;
    color: var(--ink-2);
    text-decoration: none;
    font-size: 13.5px;
    line-height: 1.3;
    border-left: 2px solid transparent;
    transition: background .2s ease, color .2s ease, border-color .2s ease;
  }
  .intro__toc-link:hover {
    background: rgba(255,255,255,.08);
    color: var(--ink-0);
  }
  .intro__toc-link.is-active {
    background: rgba(255,213,138,.16);
    color: var(--accent);
    border-left-color: var(--accent);
    font-weight: 600;
  }
}

/* Day theme: keep the sidebar readable on the bright card */
[data-theme="day"] .intro__toc {
  background: rgba(255,255,255,.82);
  border-color: rgba(20,42,72,.16);
}
[data-theme="day"] .intro__toc-link { color: #4a6a94; }
[data-theme="day"] .intro__toc-link:hover { background: rgba(20,42,72,.06); color: #14253c; }
[data-theme="day"] .intro__toc-link.is-active {
  background: rgba(217,119,87,.14);
  color: #c0532f;
  border-left-color: var(--accent-2);
}
[data-theme="day"] .intro__toc-portrait-img {
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 8px 22px rgba(40,80,130,.22);
}

/* Day theme: contact card column */
[data-theme="day"] .intro__contact {
  background: rgba(255,255,255,.82);
  border-color: rgba(20,42,72,.16);
}
[data-theme="day"] .intro__contact-title { color: #4a6a94; }
[data-theme="day"] .contact-card {
  background: rgba(20,42,72,.05);
  border-color: rgba(20,42,72,.12);
  color: #1c2c44;
}
[data-theme="day"] .contact-card:hover,
[data-theme="day"] .contact-card:focus-visible {
  background: rgba(217,119,87,.12);
  border-color: rgba(217,119,87,.34);
  color: #14253c;
}
[data-theme="day"] .contact-card__icon {
  background: rgba(217,119,87,.16);
  color: #c0532f;
}

/* ---------- Day theme: keep the About page readable on the bright homepage sky ---------- */
[data-theme="day"] .intro {
  --ink-0: #14253c;          /* brightest text (titles/values) — was near-white, invisible on the light card */
  --ink-1: #1c2c44;
  --ink-2: #4a6a94;
}
[data-theme="day"] .intro__card {
  background: linear-gradient(180deg, rgba(255,255,255,.96), rgba(255,255,255,.86));
  border-color: rgba(255,255,255,.85);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 30px 80px rgba(40,80,130,.28);
}
[data-theme="day"] .intro__name { color: #10243f; }
[data-theme="day"] .intro__name span { color: var(--accent-2); }

/* chips / list items / work cards: swap the near-transparent night whites for a soft dark tint */
[data-theme="day"] .intro__names li {
  background: rgba(20,42,72,.05);
  border-color: rgba(20,42,72,.14);
}
[data-theme="day"] .chip {
  background: rgba(20,42,72,.05);
  border-color: rgba(20,42,72,.14);
}
[data-theme="day"] .work {
  background: rgba(20,42,72,.05);
  border-color: rgba(20,42,72,.14);
}
/* section-title divider + timeline accent: readable on the light card */
[data-theme="day"] .intro__sec-title::after {
  background: linear-gradient(90deg, rgba(20,42,72,.28), transparent);
}
[data-theme="day"] .timeline__year { color: #b9762e; }
[data-theme="day"] .timeline::before {
  background: linear-gradient(180deg, rgba(185,118,46,.55), rgba(40,110,160,.4));
}
/* Back-to-top button: nearly-invisible white on white card — give it a dark tint + border in day mode */
[data-theme="day"] .intro-top {
  background: rgba(20,42,72,.14);
  border-color: rgba(20,42,72,.34);
  color: #14253c;
  box-shadow: 0 4px 14px rgba(20,42,72,.18);
}
[data-theme="day"] .intro-top:hover {
  background: rgba(20,42,72,.22);
  color: #0a1830;
}
[data-theme="day"] .intro::after {
  background: linear-gradient(180deg, transparent 0%, rgba(94,160,120,.16) 55%, rgba(70,120,80,.30) 100%);
}

/* scroll reveal */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.16,1,.3,1);
}
.intro.is-open .reveal { opacity: 1; transform: none; }
.intro.is-open .reveal:nth-child(2) { transition-delay: .15s; }

.intro__avatar {
  width: min(148px, 38vw);
  border-radius: 20px;
  margin: -104px auto 16px;   /* negative top margin lifts it over the card edge */
  background: linear-gradient(135deg, #2563eb, #1e40af);
  padding: 6px;
  box-shadow: 0 16px 38px rgba(0,0,0,.45);
}
@supports (aspect-ratio: 6 / 5) {
  .intro__avatar { aspect-ratio: 6 / 5; }
}
@supports not (aspect-ratio: 6 / 5) {
  .intro__avatar { height: calc(min(148px, 38vw) * 5 / 6); }
}
.intro__avatar img {
  width: 100%; height: 100%;
  border-radius: 50%;
  object-fit: cover;
}
/* animated mini-character version (reuses the hero figure) */
.intro__avatar--anim {
  overflow: visible;
  padding: 6px;
  background:
    radial-gradient(130% 95% at 50% 118%, #163a2a 0%, #122a44 58%, #0e1830 100%),
    linear-gradient(135deg, #2563eb, #1e40af);
}
.intro__avatar--anim .character-fig {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  transform: translateY(-6px);
}
/* Day theme: lighten the mini-avatar frame so it sits cleanly on the white card */
[data-theme="day"] .intro__avatar--anim {
  background:
    radial-gradient(130% 95% at 50% 118%, #dff0e6 0%, #cfe6f4 58%, #e8f3fb 100%),
    linear-gradient(135deg, #3b82f6, #1e40af);
}

.intro__hi {
  margin: 0 0 8px;
  font-size: 13px;
  letter-spacing: .14em;
  color: var(--ink-2);
  text-align: center;
}
.intro__name {
  margin: 0 0 18px;
  font-family: 'Noto Serif SC', 'Fraunces', serif;
  font-size: clamp(34px, 6vw, 50px);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.1;
  color: #fff;
  text-align: center;
}
.intro__name span {
  color: var(--accent-2);
  font-family: 'Fraunces', serif;
  font-weight: 600;
  font-size: .62em;
  display: block;
  margin-top: 6px;
  letter-spacing: .06em;
}

/* meta names grid */
.intro__names {
  list-style: none;
  padding: 0;
  margin: 0 auto 22px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px 14px;
  max-width: 560px;
}
.intro__names li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 8px 12px;
  background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 10px;
  font-size: 14px;
}
.intro__names .k {
  font-size: 12px;
  color: var(--ink-2);
  letter-spacing: .08em;
  flex-shrink: 0;
}
.intro__names .v {
  color: var(--ink-0);
  font-weight: 500;
  min-width: 0;          /* allow the value cell to shrink and wrap inside narrow viewports */
  overflow-wrap: anywhere;
}

.intro__role {
  margin: 0 auto 6px;
  max-width: 56ch;
  font-size: 16px;
  color: var(--ink-1);
  text-align: center;
  line-height: 1.7;
}
.intro__sub {
  margin: 0 auto 26px;
  text-align: center;
  font-size: 13px;
  color: var(--ink-2);
  letter-spacing: .1em;
}

.intro__sec-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 30px 0 14px;
  font-family: 'Noto Serif SC', serif;
  font-size: 18px;
  font-weight: 600;
  color: var(--ink-0);
  letter-spacing: .04em;
}
.intro__sec-title::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, rgba(255,255,255,.16), transparent);
}
.intro__sec-title--map { margin-top: 0; }
.map-pin { color: var(--accent-2); }

.intro__skills {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.chip {
  display: inline-flex;
  align-items: center;
  padding: 6px 13px;
  font-size: 13px;
  letter-spacing: .02em;
  color: var(--ink-1);
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 999px;
  transition: background .2s ease, transform .2s ease;
}
.chip:hover { background: rgba(255,213,138,.14); transform: translateY(-1px); border-color: rgba(255,213,138,.35); }

/* works */
.intro__works {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}

/* Blog section: Notion embed kept fully inside the content column so it can
   never push the page wider. The iframe is width:100% + max-width:100% and the
   wrapper clips any overflow; nothing here breaks the surrounding layout. */
.intro__blog {
  width: 100%;
  max-width: 100%;
  overflow: hidden;
  border-radius: 14px;
  border: 1px solid rgba(255,255,255,.1);
  background: rgba(255,255,255,.03);
}
.intro__blog iframe {
  display: block;
  width: 100%;
  max-width: 100%;
  height: 600px;
  border: 0;
}
.intro__blog-fallback {
  margin: 0;
  padding: 10px 14px;
  text-align: center;
  font-size: 13px;
  color: var(--ink-2);
}
.intro__blog-fallback a {
  color: var(--accent, #6aa9ff);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}
.intro__blog-fallback a:hover {
  filter: brightness(1.15);
}
.work {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.09);
  border-radius: 14px;
  transition: transform .2s ease, border-color .2s ease;
}
.work:hover { transform: translateY(-2px); border-color: rgba(255,213,138,.3); }
.work--proj { text-decoration: none; color: inherit; cursor: pointer; }
.work--proj:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.work__icon { font-size: 26px; }
.work__title {
  font-family: 'Noto Serif SC', serif;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink-0);
  display: block;
}
.work__sub {
  font-size: 12px;
  color: var(--ink-2);
  display: block;
  margin-top: 2px;
}

/* timeline
   Geometry is driven by three variables so the year column, the rail and the
   dot can never collide with the body text at any width:
     --tl-year  width of the year column
     --tl-gap   gap between the year column and the body text; the rail sits
                at its midpoint, so clearance = gap/2 - dot/2
     --tl-dot   dot diameter
   Note: .timeline has no horizontal padding, so `left` on ::before (relative
   to .timeline) and on ::after (relative to .timeline__item) share an origin. */
.timeline {
  --tl-year: 88px;
  --tl-gap: 34px;
  --tl-dot: 12px;
  --tl-mid: calc(var(--tl-year) + var(--tl-gap) / 2);   /* rail centre line */

  list-style: none;
  margin: 0;
  padding: 6px 0 0;
  position: relative;
}
.timeline::before {
  content: "";
  position: absolute;
  left: var(--tl-mid);
  margin-left: -1px;           /* centre the 2px rail on --tl-mid */
  top: 16px;
  bottom: 16px;
  width: 2px;
  background: linear-gradient(180deg, rgba(255,213,138,.5), rgba(143,208,255,.25));
  border-radius: 2px;
}
.timeline__item {
  position: relative;
  display: flex;
  gap: var(--tl-gap);
  padding: 10px 0;
}
.timeline__year {
  flex-shrink: 0;
  width: var(--tl-year);
  text-align: right;
  font-family: 'Fraunces', serif;
  font-size: 17px;
  font-weight: 600;
  color: var(--accent);
  padding-top: 2px;
}
.timeline__item::after {
  content: "";
  position: absolute;
  left: calc(var(--tl-mid) - var(--tl-dot) / 2);   /* dot centred on the rail */
  top: 18px;
  width: var(--tl-dot);
  height: var(--tl-dot);
  border-radius: 50%;
  background: var(--accent);
  border: 2.5px solid #0a1234;
  box-shadow: 0 0 10px rgba(255,213,138,.5);
}
.timeline__body { flex: 1; min-width: 0; }
.timeline__title {
  margin: 0 0 4px;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-0);
}
.timeline__desc {
  margin: 0;
  font-size: 14px;
  color: var(--ink-2);
  line-height: 1.7;
}

/* quote */
.intro__quote {
  margin: 30px 0 0;
  padding: 18px 22px;
  border-left: 3px solid var(--accent-2);
  background: rgba(217,119,87,.08);
  border-radius: 0 12px 12px 0;
}
.intro__quote p {
  margin: 0;
  font-family: 'Noto Serif SC', serif;
  font-size: 16px;
  color: var(--ink-0);
  letter-spacing: .06em;
}
.intro__quote cite {
  display: block;
  margin-top: 6px;
  font-style: normal;
  font-size: 12px;
  color: var(--ink-2);
}

/* Hide language-conditional chips: the class now lives on the host cell (closest <li>)
   so the whole grid slot is removed; keep the data-show-lang form for any inner-link case. */
[data-show-lang].is-hidden,
li.is-hidden:has([data-show-lang]),
.contact-cards li.is-hidden { display: none; }
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  font-size: 14px;
  color: var(--ink-1);
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: 999px;
  transition: transform .2s ease, background .2s ease, border-color .2s ease;
}
.btn:hover { background: rgba(255,255,255,.14); transform: translateY(-1px); border-color: rgba(255,255,255,.28); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn--primary {
  color: #1a1f33;
  background: linear-gradient(135deg, #ffd58a, #ffae66);
  border-color: transparent;
  box-shadow: 0 8px 24px rgba(255,180,100,.35);
}
.btn--primary:hover { color: #1a1f33; background: linear-gradient(135deg, #ffdfa8, #ffb87a); }

/* ============================================
   JOURNEY MAP
============================================ */
.map__sub {
  margin: -6px 0 18px;
  font-size: 13px;
  color: var(--ink-2);
  letter-spacing: .05em;
}
.map__scroller {
  overflow-x: auto;
  border-radius: 16px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.map {
  display: block;
  width: 100%;
  min-width: 640px;
  height: auto;
}
.map--world { min-width: 980px; }
.map-land { stroke: var(--map-land-dot, rgba(160,180,220,.45)); transition: stroke 1.1s ease; }
[data-theme="day"] .map-land { --map-land-dot: rgba(35,75,130,.35); }
.map--world .node__city { font-size: 15px; font-weight: 600; }
.map--world .node__city--tiny { font-size: 11.5px; font-weight: 600; }
.map--world .node__year { font-size: 10.5px; }

.route { fill: none; }
.route--base {
  stroke: rgba(255,255,255,.12);
  stroke-width: 5;
  stroke-linecap: round;
}
.route--flow {
  stroke: url(#routeGrad);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 3 16;
  animation: dashflow 2.6s linear infinite;
  filter: drop-shadow(0 0 5px rgba(255,190,120,.5));
}
@keyframes dashflow { to { stroke-dashoffset: -19; } }
.route--future {
  stroke: rgba(143,208,255,.4);
  stroke-width: 2.4;
  stroke-dasharray: 4 10;
  stroke-linecap: round;
  animation: dashflow 3.4s linear infinite;
}

.node__pulse {
  transform-box: fill-box;
  transform-origin: center;
  animation: nodepulse 2.6s ease-out infinite;
}
@keyframes nodepulse {
  0%   { transform: scale(.55); opacity: .9; }
  100% { transform: scale(2); opacity: 0; }
}
.node__core {
  filter: drop-shadow(0 0 6px rgba(255,220,150,.55));
}
.node__city {
  font-family: 'Noto Serif SC', serif;
  font-size: 17px;
  font-weight: 600;
  fill: #eaf0ff;
}
.node__year {
  font-family: 'Outfit', 'Noto Sans SC', sans-serif;
  font-size: 11.5px;
  fill: #8c97b8;
  letter-spacing: .04em;
}
.node--future .node__city { fill: #8fd0ff; font-size: 14px; }

/* journey phase captions (① around China / ② around the world) */
.map-phase {
  font-family: 'Noto Serif SC', serif;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .18em;
  fill: var(--map-phase-ink, rgba(234,240,255,.9));
  transition: fill 1.1s ease;
}
.map-phase--1 { fill: rgba(255,213,138,.92); }
.map-phase--2 { fill: rgba(143,208,255,.92); }
[data-theme="day"] .map-phase--1 { fill: rgba(122,86,10,.85); }
[data-theme="day"] .map-phase--2 { fill: rgba(20,80,130,.85); }

.compass__needle {
  transform-box: fill-box;
  transform-origin: center;
  animation: compass-sway 6s ease-in-out infinite;
}
@keyframes compass-sway {
  0%,100% { transform: rotate(-8deg); }
  50%     { transform: rotate(10deg); }
}

/* ============================================
   RESPONSIVE
============================================ */
@media (max-width: 900px) {
  .villa { width: 195px; left: 6%; bottom: clamp(30%, 34vh, 40%); }
  .rv    { width: 220px; right: 3%; bottom: clamp(30%, 34vh, 40%); }
  .character { width: 185px; height: 155px; bottom: clamp(24%, 28vh, 34%); }
  .hint { font-size: 15px; padding: 8px 16px; gap: 8px; }
  .moon { width: 64px; height: 64px; }
  .sun { width: 80px; height: 80px; }
  .planet--ring { width: 90px; height: 90px; top: 9%; left: 5%; }
  .timeline { --tl-year: 78px; --tl-gap: 32px; --tl-dot: 12px; }
  .timeline__year { font-size: 16px; }
}

@media (max-width: 600px) {
  .brand { top: max(14px, env(safe-area-inset-top) + 10px); left: max(16px, env(safe-area-inset-left) + 10px); }
  .brand__mark { font-size: 20px; }
  .brand__sub { font-size: 10px; }
  .theme-toggle { top: max(14px, env(safe-area-inset-top) + 10px); right: max(14px, env(safe-area-inset-right) + 10px); width: 40px; height: 40px; }
  .lang-toggle { top: max(14px, env(safe-area-inset-top) + 10px); right: max(62px, env(safe-area-inset-right) + 58px); width: 40px; height: 40px; font-size: 12px; }
  .intro__back { top: max(14px, env(safe-area-inset-top) + 10px); left: max(16px, env(safe-area-inset-left) + 10px); padding: 8px 13px; font-size: 12px; }
  .signature { font-size: 10px; bottom: max(12px, env(safe-area-inset-bottom) + 10px); letter-spacing: .14em; padding: 5px 14px; }
  .intro__card { padding: 40px 20px 32px; }
  .intro__card--map { width: 100%; padding: 28px 16px 24px; }
  .intro__avatar { width: min(128px, 38vw); margin-top: -86px; }
  /* Give the scroller more top room on phones so the card doesn't sit jammed
     under the header toggles — the whole layout was reading too far up. */
  .intro__inner { padding-top: 116px; }
  @supports not (aspect-ratio: 6 / 5) {
    .intro__avatar { height: calc(min(128px, 38vw) * 5 / 6); }
  }
  .earth { width: 260%; bottom: -4%; }
  .villa { width: 135px; left: 3%; bottom: clamp(26%, 30vh, 36%); }
  .rv { width: 150px; right: 2%; bottom: clamp(26%, 30vh, 36%); }
  .character { width: 150px; height: 125px; bottom: clamp(20%, 26vh, 32%); }
  .hint { font-size: 14px; padding: 7px 14px; gap: 7px; }
  .intro__names { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 8px; }
  .timeline { --tl-year: 70px; --tl-gap: 30px; --tl-dot: 11px; }
  .timeline__year { font-size: 15px; }
  .map { min-width: 720px; }
}

/* Small phones: tighten the timeline further so the body text keeps its width */
@media (max-width: 400px) {
  .timeline { --tl-year: 56px; --tl-gap: 26px; --tl-dot: 10px; }
  .timeline__year { font-size: 13.5px; }
  .timeline__title { font-size: 14px; }
  .timeline__desc { font-size: 13px; }
  /* Single column on phones: avoids wrapping short tokens like "Jinjing" mid-word */
  .intro__names { grid-template-columns: 1fr; gap: 6px; }
}

/* ============================================
   REDUCED MOTION
============================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .parallax { transform: none !important; }
}
