/* Type follows the drawing: Geist, light, ivory on night and ink on paper, labels hung off the buildings by a hairline.
   The world script moves every colour below between night and paper; pink never changes. */
:root {
  --paint: #000000;
  --ink: #f2ede4;
  --soft: #b9b4ab;
  --muted: #85827c;
  --edge: #2a2a2e;
  --pink: #ff2e93;
  --line-x: max(24px, calc(50% - 380px));
  --type: "Geist", system-ui, sans-serif;
  color-scheme: dark;
}
* { box-sizing: border-box; }
html, body { background: var(--paint); }
body { margin: 0; color: var(--ink); font: 300 16px/1.6 var(--type); -webkit-font-smoothing: antialiased; overflow-x: clip; }
a { color: var(--muted); text-underline-offset: 3px; }
button { font: inherit; }

#world { position: fixed; inset: 0; width: 100vw; height: 100vh; opacity: 0; }
.scroll-room { height: 3760vh; }
.lead-line { position: fixed; top: 0; bottom: 0; left: 0; width: 1px; pointer-events: none; background: linear-gradient(transparent, var(--ink) 10%, var(--ink) 90%, transparent); opacity: .8; }
.leaders { position: fixed; inset: 0; width: 100vw; height: 100vh; pointer-events: none; overflow: visible; }
.leader { stroke: var(--ink); stroke-width: .7; opacity: .42; }
.anchor { fill: var(--ink); opacity: .85; }

.label { display: flex; align-items: center; gap: 14px; font: 400 11px/1.4 var(--type); letter-spacing: .16em; text-transform: uppercase; color: var(--muted); margin: 0 0 14px; }
.label.pink { color: var(--pink); }
.wave { display: inline-flex; align-items: center; gap: 3px; height: 14px; }
.wave i { width: 1.5px; height: 100%; background: var(--edge); transform: scaleY(.15); transition: background .2s; }
.wave.speaking i { background: var(--ink); animation: speak .42s ease-in-out infinite alternate; }
.wave.correcting i { background: var(--pink); }
@keyframes speak { from { transform: scaleY(.15); } to { transform: scaleY(1); } }

del { text-decoration: none; background: linear-gradient(var(--pink), var(--pink)) no-repeat 0 60% / 0% 1px; transition: background-size .55s ease-out, color .55s; }
del.struck, html:not(.js) del, .reading del { background-size: 100% 1px; color: var(--muted); }
ins { text-decoration: none; }
.nahi { color: var(--pink); font-weight: 400; }

/* Words sit on the drawing, so they carry a halo of the ground colour instead of a box. */
.station { text-shadow: 0 0 2px var(--paint), 0 0 18px var(--paint), 0 0 34px var(--paint); }

.spoken { font: 300 15px/1.6 var(--type); color: var(--soft); margin: 0 0 28px; min-height: 1.6em; }
.hero h1 { font: 500 clamp(56px, 9vw, 112px)/.98 var(--type); letter-spacing: -.035em; margin: 0; }
.hero h1 .light { font-weight: 300; }
.under { max-width: 470px; color: var(--soft); margin-top: 28px; }
.claim { font: 300 clamp(22px, 2.6vw, 28px)/1.3 var(--type); letter-spacing: -.01em; margin: 0 0 12px; }
.truth { font-size: 16.5px; color: var(--soft); margin: 0; max-width: 520px; }
.truth ins { color: var(--ink); }
.imagined-line { font: 300 clamp(22px, 2.6vw, 28px)/1.35 var(--type); letter-spacing: -.01em; margin: 0; max-width: 560px; }
.tag-name { font: 400 13px/1.3 var(--type); letter-spacing: .02em; color: var(--ink); margin: 0 0 4px; white-space: nowrap; }
.tag-desc { font: 300 12px/1.45 var(--type); color: var(--muted); margin: 0; max-width: 330px; }
.finale-line { font: 300 clamp(30px, 3.6vw, 46px)/1.15 var(--type); letter-spacing: -.025em; margin: 0 0 22px; max-width: 420px; }
.js:not(.reading) .finale { max-width: min(380px, calc(50vw - 80px)); }
.avail { font-size: 17px; margin: 0 0 10px; }
.built { font-size: 12.5px; color: var(--muted); margin: 0; }

/* World mode: one station at a time. Corrections sit low on the left; place tags hang off their building. */
.js:not(.reading) .station { position: fixed; left: var(--line-x); bottom: 10vh; max-width: min(600px, calc(100vw - 48px)); opacity: 0; visibility: hidden; transition: opacity .6s, visibility 0s .6s; pointer-events: none; }
.js:not(.reading) .station.active { opacity: 1; visibility: visible; transition: opacity .6s; }
.js:not(.reading) .tag-box { position: fixed; left: 0; top: 0; will-change: transform; }
.js:not(.reading) .hero { top: 0; bottom: 0; display: flex; flex-direction: column; justify-content: center; padding-left: 40px; }
.js:not(.reading) .imagined { display: none; }
.js:not(.reading) .flying .imagined { display: block; }
.js:not(.reading) .station.flying .proof, .js:not(.reading) .station.flying .claim, .js:not(.reading) .station.flying .truth, .js:not(.reading) .station.flying .tag-name, .js:not(.reading) .station.flying .tag-desc { display: none; }
.js:not(.reading) .station.flying .tag-box, .js:not(.reading) .station.flying .story, .js:not(.reading) .station.flying .lead { display: none; }

.js .w { opacity: 0; transition: opacity .18s; }
.js .w.on, .reading .w { opacity: 1; }
.js .fade { opacity: 0; transform: translateY(6px); transition: opacity .8s, transform .8s; }
.js .fade.on, .reading .fade { opacity: 1; transform: none; }

.fork-cta, .back, .read-mode, .sound { position: fixed; background: transparent; border: 1px solid var(--edge); color: var(--muted); font: 400 10.5px var(--type); letter-spacing: .16em; text-transform: uppercase; padding: 9px 13px; cursor: pointer; text-shadow: 0 0 10px var(--paint); }
.fork-cta { transform: translate(-50%, 70%); border-color: var(--pink); color: var(--pink); white-space: nowrap; }
.back { left: var(--line-x); bottom: 4vh; color: var(--soft); }
.read-mode { right: 22px; top: 18px; }
.sound { right: 162px; top: 18px; }
.sound[aria-pressed="true"] { color: var(--ink); border-color: var(--muted); }
.fork-cta:hover, .back:hover, .read-mode:hover, .sound:hover { color: var(--ink); border-color: var(--muted); }

.reading #world, .reading .lead-line, .reading .leaders, .reading .scroll-room, .reading .fork-cta, .reading .back, html:not(.js) #world, html:not(.js) .leaders { display: none; }
.reading main, html:not(.js) main { max-width: 680px; margin: 0 auto; padding: 12vh 24px; }
.reading .station, html:not(.js) .station { margin-bottom: 12vh; text-shadow: none; }
.reading .imagined, html:not(.js) .imagined { margin-top: 22px; padding-left: 16px; border-left: 1px solid var(--pink); }

@media (prefers-reduced-motion: reduce) { .wave.speaking i { animation: none; transform: scaleY(.5); } }

/* Proof sits under each correction: the links and my voice, small and quiet. */
.proof { font: 400 10.5px/1.9 var(--type); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin: 14px 0 0; }
.proof a { color: var(--muted); }
.proof a:hover { color: var(--ink); }
.clip { background: none; border: 0; padding: 0; font: inherit; letter-spacing: inherit; text-transform: inherit; color: var(--pink); cursor: pointer; }
.js:not(.reading) .station.active a, .js:not(.reading) .station.active button { pointer-events: auto; }
.js:not(.reading) .read-only { display: none; }
.care { color: var(--soft); font-size: 15px; margin-top: 18px; }
.result { font: 300 15px/1.6 var(--type); color: var(--soft); margin: 14px 0 0; }
.result .pending { color: var(--pink); }
.how { font-size: 13.5px; line-height: 1.6; color: var(--muted); margin: 12px 0 0; max-width: 540px; }

/* The story line under each stop: what I say there, appearing as I say it. */
.story { font: 300 clamp(19px, 1.9vw, 23px)/1.45 var(--type); letter-spacing: -.005em; margin: 0; max-width: 600px; }
.lead { font: 300 16px/1.5 var(--type); color: var(--soft); margin: 0 0 8px; max-width: 560px; }
.hint { font: 400 10.5px var(--type); letter-spacing: .16em; text-transform: uppercase; color: var(--muted); margin-top: 22px; }

/* The world can be looked around by dragging; vertical swipes on a phone still scroll. */
html.js:not(.reading) { touch-action: pan-y; }
html.js:not(.reading) body { cursor: grab; }
html.looking body { cursor: grabbing; user-select: none; }

/* Chapter numbers sit above each stop like a title card. */
.chapter { font: 400 10px var(--type); letter-spacing: .32em; text-transform: uppercase; color: var(--muted); margin: 0 0 12px; opacity: .8; }
.station.tag .chapter, .station.moment .chapter { margin-bottom: 14px; }
.js:not(.reading) .moment { bottom: 12vh; }

/* Taking a pink road is a scene of its own: the frame narrows, like a film cutting to a memory. */
html::before, html::after { content: ""; position: fixed; left: 0; right: 0; height: 0; background: #000; z-index: 5; pointer-events: none; transition: height 1.2s cubic-bezier(.4, 0, .2, 1); }
html::before { top: 0; }
html::after { bottom: 0; }
html.cinema::before, html.cinema::after { height: 9vh; }

.fork-cta, .back, .read-mode, .sound { z-index: 10; }
.js:not(.reading) .station.flying .chapter, .js:not(.reading) .station.flying > .label { display: none; }
.js:not(.reading) .station.flying { bottom: calc(9vh + 72px); }
.back { bottom: calc(9vh + 16px); }

/* The last page: a narrow column on the left, so the pavilion and the fork stay clear. */
.js:not(.reading) .finale { max-width: min(400px, calc(46vw - 40px)); bottom: 4.5vh; }
.finale .lead, .finale .avail { max-width: 400px; }
.finale .lead { font-size: 14.5px; }

/* A silent landmark has no words of mine, so it carries no chapter card either. */
.station[data-silent] .chapter { display: none; }

/* Act cards: a numeral and a title, centred, rising out of the dark and settling back into it. */
.act-card { position: fixed; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; pointer-events: none; opacity: 0; transform: translateY(10px); transition: opacity 1.4s ease, transform 1.8s ease; z-index: 4; text-shadow: 0 0 30px var(--paint), 0 0 60px var(--paint); }
.act-card.on { opacity: 1; transform: none; }
.act-number { font: 300 13px var(--type); letter-spacing: .5em; color: var(--muted); margin: 0 0 14px; padding-left: .5em; }
.act-title { font: 300 clamp(30px, 4.2vw, 54px)/1.1 var(--type); letter-spacing: -.02em; color: var(--ink); margin: 0; text-align: center; }
.reading .act-card, .reading .credits, html:not(.js) .act-card, html:not(.js) .credits { display: none; }

/* End credits: they come up quietly on the right when the road runs out. */
.credits { position: fixed; right: max(24px, calc(50% - 560px)); bottom: 9vh; text-align: right; font: 300 12.5px/2 var(--type); letter-spacing: .04em; color: var(--muted); opacity: 0; transition: opacity 2.4s ease 1.2s; pointer-events: none; }
.credits.on { opacity: 1; pointer-events: auto; }
.credits p { margin: 0; }
.credits strong { font-weight: 400; color: var(--ink); }
.credits a { color: var(--muted); }

/* While an act card is up it owns the screen: words and buttons step back and return when it settles. */
.station, .fork-cta, .leaders { transition: opacity .8s ease; }
html.act-on .fork-cta, html.act-on .leaders, html.act-on .tag-box { opacity: 0 !important; }

/* A memory appears small and quiet in the empty sky at the upper right. The frame takes each photo's own shape,
   so nothing important is cropped; only the outermost edge feathers into the dark. Each photo develops in
   (a touch bright and soft, then into focus), drifts very slowly, and dissolves into the next. */
.memory { position: fixed; bottom: 9vh; right: max(28px, 4vw); width: 300px; height: 225px; margin: 0; pointer-events: none; z-index: 1;
  transition: opacity 1.6s ease, width 1.4s ease, height 1.4s ease; }
.memory.away, html.act-on .memory { opacity: 0; }
.memory img, .memory video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 9%, #000 91%, transparent), linear-gradient(to bottom, transparent, #000 9%, #000 91%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, transparent, #000 9%, #000 91%, transparent), linear-gradient(to bottom, transparent, #000 9%, #000 91%, transparent);
  mask-composite: intersect;
  filter: saturate(.8) sepia(.1) brightness(.95) blur(3px);
  transform: scale(1.04);
  transition: opacity 2.4s ease, filter 3s cubic-bezier(.2, .7, .2, 1), transform 10s ease-out; }
.memory img.on, .memory video.on { opacity: .9; filter: saturate(.8) sepia(.1) brightness(.95) blur(0); transform: scale(1); }
.memory img.developing { filter: saturate(.7) sepia(.1) brightness(1.4) blur(4px); }
.reading .memory, html:not(.js) .memory { display: none; }
@media (max-width: 720px) { .memory { bottom: auto; top: 9vh; right: 16px; } }
@media (prefers-reduced-motion: reduce) { .memory img { transition: opacity 1s ease; transform: none; } }

/* Phones: the story column takes the full width, labels give way to the words that already name each place,
   memories stay small at the top, and the last page keeps its line whole. */
@media (max-width: 720px) {
  .js:not(.reading) .finale { max-width: calc(100vw - 48px); bottom: 5vh; }
  .finale-line { font-size: 30px; max-width: none; }
  .js:not(.reading) .tag-box, .js:not(.reading) .leaders { display: none; }
  .memory { width: 44vw; top: 8vh; }
  html.finale-on .memory { opacity: 0; }
  .js:not(.reading) .station { left: 24px; max-width: calc(100vw - 48px); }
}

/* The fork button keeps its words legible over bright lines: a faint dark glass behind it. */
.fork-cta { background: rgba(0, 0, 0, .55); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }

/* The first thing that happens: the line of light draws itself down the page, then my name begins. */
.lead-line { transform-origin: top; animation: draw-line 1.8s cubic-bezier(.6, 0, .2, 1) both; }
@keyframes draw-line { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@media (prefers-reduced-motion: reduce) { .lead-line { animation: none; } }

/* The two controls share one row at the top right, so a longer label never runs into its neighbour. */
.controls { position: fixed; top: 18px; right: 22px; display: flex; gap: 12px; z-index: 10; }
.controls .sound, .controls .read-mode { position: static; }

/* Words sit in a soft pool of the ground colour, like a subtitle shadow in film: no box, no edge,
   just enough darkness that a bright line passing behind never cuts through a sentence. */
.js:not(.reading) .station:not(.hero)::before { content: ""; position: absolute; inset: -60px -90px -50px -70px; z-index: -1; pointer-events: none;
  background: radial-gradient(ellipse 50% 50% at 50% 50%, color-mix(in srgb, var(--paint) 78%, transparent) 0%, color-mix(in srgb, var(--paint) 50%, transparent) 50%, transparent 100%); }
.js:not(.reading) .station.tag::before { inset: -60px -90px -50px -70px; }

/* At a silent landmark there are no words of mine, so the memory takes their place in the lower left
   and the building keeps the whole right side to itself. */
@media (min-width: 721px) { html.silent-on .memory { right: auto; left: var(--line-x); } }

/* Phone: the finale fills the lower screen, so the credits move up under the controls, centred and smaller. */
@media (max-width: 720px) {
  .credits { right: 16px; left: 16px; bottom: auto; top: 64px; text-align: center; font-size: 11px; line-height: 1.75; text-shadow: 0 0 12px var(--paint), 0 0 24px var(--paint); }
}

/* The last fork is the line a reader must not miss, so its pool is deeper: the road behind it fades to a whisper. */
.js:not(.reading) .station[data-kind="finale"]::before { inset: -80px -120px -60px -90px;
  background: radial-gradient(ellipse 60% 58% at 46% 52%, color-mix(in srgb, var(--paint) 92%, transparent) 0%, color-mix(in srgb, var(--paint) 72%, transparent) 55%, transparent 100%); }
/* The last fork needs no number; "the last fork" already says where we are, and the pavilion gets its breathing room. */
.station[data-kind="finale"] .chapter { display: none; }
/* The name gets the same pool as every chapter, so the first building sketching itself never runs through "I am Zaid." */
.js:not(.reading) .hero::before { content: ""; position: absolute; inset: 22vh -140px 22vh -40px; z-index: -1; pointer-events: none;
  background: radial-gradient(ellipse 50% 50% at 45% 50%, color-mix(in srgb, var(--paint) 88%, transparent) 0%, color-mix(in srgb, var(--paint) 60%, transparent) 55%, transparent 100%); }
