/* Waytripper landing page - A Day in Section.
   Tokens first: light is the icon's palette, dusk is the same scene at evening.
   Motion is transform and opacity only; everything static under prefers-reduced-motion. */

@font-face {
  font-family: "Barlow Condensed";
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/barlow-condensed-600italic.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow Condensed";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/barlow-condensed-500.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow Condensed";
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/barlow-condensed-500italic.woff2") format("woff2");
}

:root {
  color-scheme: light dark;

  /* light: the comp's palette, recorded in the spec */
  --ground: #F2E0C4;
  --poche: #1F4A7A;
  --sun: #D4562B;
  --contour: #F6E7CF;
  --light: #FB874C;           /* the wedges; sampled from the comp's beam */
  /* Light DARKENS a cream ground and LIGHTENS a navy one. Multiply can only
     ever darken, so at dusk a pale warm light multiplied over navy returns
     navy and the lit room stopped reading at all: the page's whole mechanic,
     invisible for the entire evening, while the geometry checks passed. */
  --wedge-blend: multiply;
  /* how strongly the soft light's core reads. A token because the answer
     differs by scheme. At night 0.85 washed out the navy and flattened the
     cream figures; 0.25 lifts the active room just enough to mark it, and the
     cream keeps 5.8:1 against it (Andy, 2026-09-23). */
  --light-core: 0.55;
  --wash: #8FA8C4;            /* pale navy: distance seen through a window */
  --type-on-ground: #1F4A7A;
  --button-text: #F2E0C4;
  --hairline: rgba(31, 74, 122, 0.55);
  --moon: 0;                  /* the bite is invisible while it is the sun */
  --birds-vis: visible;       /* birds fly by day */
  --stars-vis: hidden;
  --mass-fill: #1F4A7A;       /* solid poche in daylight */
  --mass-sw: 0px;
  --day-vis: visible;          /* the soft fill and two of the rays, by day only */

  --display: "Barlow Condensed", "Arial Narrow", sans-serif;
  --labels: "Barlow Condensed", "Arial Narrow", sans-serif;
  --small: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* dusk: navy sky, cream lines and type. The clock drives this after the first
       second; the media query only paints the opening frame. */
    --ground: #14325A;
    --poche: #F2E0C4;
    --sun: #F2E0C4;
    --contour: #E9D7B8;
    --light: #FFC873;
    --wedge-blend: screen;
    --light-core: 0.25;
    --wash: rgba(242, 224, 196, 0.34);   /* the same distance, read at dusk */
    --type-on-ground: #F2E0C4;
    --button-text: #1F4A7A;
    --hairline: rgba(242, 224, 196, 0.55);
    /* Night is the INVERSE of day, not a line drawing of it (Andy, 2026-09-21).
       These carried alpha 0 plus a stroke from when the art was outlines; with
       filled masses that emptied every shape instead of inverting it. Cream
       masses on the navy ground, and the cream cut into them goes transparent
       so the ground reads through as navy detail. */
    --moon: 1;                /* the bite carves the crescent at night */
    --birds-vis: hidden;      /* and the same sky holds stars instead */
    --stars-vis: visible;
    --mass-fill: #F2E0C4;
    --mass-sw: 0px;
    --day-vis: hidden;
  }
}

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

body {
  background: var(--ground);
  color: var(--type-on-ground);
  font: 16px/1.5 var(--small);
  min-height: 100svh;
}

/* ---------- the fit: one composed box, centred, never bottom anchored ----------
   The box carries the composition's own aspect ratio and is the largest such box
   that fits the viewport. Everything inside it, drawing and type alike, is placed
   and sized against the box, so the whole scene scales together. cqw resolves
   against this box, which is why container-type is load bearing.

   This replaces six absolutely stacked layer SVGs with preserveAspectRatio
   "xMidYMax meet", which bottom anchored the drawing and left about a third of
   the viewport as dead cream above it. */

.page {
  position: relative;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(12px, 2.4vw, 32px);
  /* the night copy's backdrop reaches a viewport past the box so it fills the
     letterbox margins; its clip hides it but still left the page scrollable,
     which showed scrollbars for the whole pan (recording, 2026-09-22) */
  overflow: clip;
}

.stage-box {
  position: relative;
  container-type: size;
  aspect-ratio: 1440 / 810;
  width: min(100%, calc((100svh - clamp(24px, 4.8vw, 64px)) * 1440 / 810));
  max-height: 100%;
}

.stage,
.stage-art,
.stage-front {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  fill: none;
}

/* The drawing's own layer (#2093): the pan moves .mover by transform, so the
   compositor slides what is already drawn; .mover-clip keeps it inside the box
   (the night copy's box is open on three sides for its backdrop). */
.mover-clip,
.mover {
  position: absolute;
  inset: 0;
}
.mover-clip { overflow: clip; }
.mover { will-change: transform; }
/* SPIKE (?rays=scatter, Andy's option A): today's rays, redrawn in the scatter
   canvas beneath the drawing and cut where it blocks the sun. Plain alpha: the
   drawn rays' blend has nothing under it inside the drawing's own group, so it
   comes out plain too. The live drawing's rays hide, the night copy keeps its
   own (its canvas clone is blank), and the soft fill is untouched. */
.scatter {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.scatter-on .ray:not(.night-box .ray) { display: none; }

/* the front layer covers the building; only the rail takes the pointer */
.stage-front { pointer-events: none; }
.stage-front .rail-group { pointer-events: auto; }

.stage { z-index: 0; }
/* The overlay is UI and paints above the drawing. Without an explicit order the
   building's own beams painted over the plan tag and ate the last letter of a
   longer plan name ("Priya and Sam's weeken"). The tag cannot simply move left
   of the building either, because building widths differ per theme and some
   start hard against the frame edge; its ground coloured moat already makes it
   read as a card sitting on the drawing, which is the same layering the sun and
   the button use. */
.overlay { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
.overlay a,
.overlay button { pointer-events: auto; }

/* ---------- type, sized against the stage box ---------- */

.type-block {
  position: absolute;
  top: 5cqh;
  left: 5cqw;
  margin: 0;
  max-width: 34cqw;
}

.wordmark {
  margin: 0;
  font: italic 600 7.2cqw/0.95 var(--display);
  letter-spacing: 0.01em;
  color: var(--type-on-ground);
}

/* the one element kept from the serif mock, drawn as a stroke */
.swash {
  display: block;
  width: 82%;
  height: auto;
  margin: 0.06em 0 0 0.04em;
  overflow: visible;
}
.swash path {
  fill: none;
  stroke: var(--type-on-ground);
  stroke-width: 1.6;
  stroke-linecap: round;
}

.line {
  margin: 0.5em 0 0;
  font: 500 2.2cqw/1.2 var(--labels);
  color: var(--type-on-ground);
}

.btn {
  display: inline-block;
  margin-top: 1.3em;
  padding: 0.72em 1.5em;
  border-radius: 6px;
  background: var(--sun);
  /* The sun passes BEHIND the copy, and the disc is the same rust as the
     button, so without an edge the two merge into one shape. A hairline in the
     ground colour is invisible against cream and separates them cleanly when
     the sun is behind it (Andy, 2026-09-20). */
  border: 1.5px solid var(--ground);
  /* A hairline alone was not enough: an independent reviewer read the disc and
     the button as one competing shape, because they are the same rust and the
     disc is much larger. This moat in the ground colour is invisible against
     the page and gives the button a clean edge wherever the sun is behind it.
     It inverts with the scheme, so it works at dusk too. */
  box-shadow: 0 0 0 4px var(--ground);
  color: var(--button-text);
  font: 500 1.9cqw/1 var(--labels);
  text-decoration: none;
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.btn:hover { transform: translateY(-2px); }
.btn:focus-visible {
  outline: 2px solid var(--type-on-ground);
  outline-offset: 3px;
}

/* The plan tag. Left of the rooms graphic (Andy, 2026-09-20), reading
   "Active plan:" plus the plan's name in the voice you would use with a friend,
   never a year. Clicking it, or the building, advances to the next plan, so it
   is a real button rather than a caption. */
/* The tag and its two arrows ride as one row. On desktop the back arrow hangs
   in the margin, so the tag itself stays on the copy's column. */
.plan-steps {
  position: absolute;
  left: max(0px, calc(5cqw - 44px));
  top: 52cqh;
  display: flex;
  align-items: center;
}

/* Drawn chevrons in the page's own line, no chrome: faint at rest, full on
   hover and focus. The button is the 44px target; the glyph sits inside it. */
.step {
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--type-on-ground);
  cursor: pointer;
}
.step svg {
  width: 0.95cqw;
  min-width: 10px;
  height: auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.45;
  transition: opacity 0.2s ease-out;
}
/* each chevron sits snug against the tag inside its 44px target */
.step-back { justify-items: end; padding-right: 6px; }
.step-fwd { justify-items: start; padding-left: 6px; }
.step:hover svg,
.step:focus-visible svg { opacity: 1; }
/* above the tag, whose ground coloured moat would otherwise hide the ring's
   inner side */
.step:focus-visible { outline: 2px solid var(--type-on-ground); outline-offset: -4px; position: relative; z-index: 1; }

.title-block {
  pointer-events: auto;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25em;
  padding: 0.6em 0.9em;
  /* FILLED, not transparent. With no background the building showed through the
     box and the tag's navy text sat on navy structure, so the tail of a longer
     plan name simply vanished: "Priya and Sam's weeken". The text was rendering
     and was topmost; it was contrast, not paint order. Same failure the room
     labels solve with a halo, and the same one as --wash and the dusk blend: a
     value that is correct against one background and invisible against another. */
  background: var(--ground);
  border: 1px solid var(--poche);
  /* Same moat as the button. The sun passes behind the copy by decision, and on
     phone the tag sits in that column: a reviewer saw the disc swallow the tag's
     border and read it as a collision rather than layering. Invisible against
     the page, inverts with the scheme. */
  box-shadow: 0 0 0 4px var(--ground);
  border-radius: 6px;
  color: var(--type-on-ground);
  font-family: var(--labels);
  text-align: left;
  cursor: pointer;
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.title-block:hover { transform: translateY(-2px); }
.title-block:focus-visible { outline: 2px solid var(--type-on-ground); outline-offset: 3px; }

.tag-static {
  font: 500 1.05cqw/1 var(--labels);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.72;
}
.tag-name {
  font: italic 500 1.75cqw/1.1 var(--labels);
  letter-spacing: 0.01em;
  white-space: nowrap;
  /* eases to the next trip's name width, so the arrows glide with it */
  transition: width 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---------- the drawing ---------- */

.sky { fill: var(--ground); }
.sun { fill: var(--sun); }

/* The traced art carries no fill of its own (cut.mjs strips it), so the whole
   theme takes its colour from here and the dusk tween swings it. */
.theme path { fill: var(--mass-fill); stroke: var(--poche); stroke-width: var(--mass-sw); }
/* the third value: distance seen through a window, so it stays flat and never
   takes the line art's stroke */
/* Distance, not a flat panel. A solid wash gave the window views a single hard
   edge and no sense of depth: two independent reviewers called the built page
   flatter than the comp and named this as the cause. The fill fades from the
   wash token to the ground token, so the far edge dissolves into the page the
   way haze does. Same three colours, no new paths, no added weight
   (Andy, 2026-09-20). */
.theme path.wash { fill: url(#washGrad); stroke: none; }
.wash-stop-near { stop-color: var(--wash); stop-opacity: 1; }
.wash-stop-far { stop-color: var(--wash); stop-opacity: 0.12; }

.bird { fill: var(--poche); }

/* ---------- light: one soft light from one sun ---------- */

.wedges { will-change: opacity; }
.wedge { mix-blend-mode: var(--wedge-blend); }
/* At night the rays are sparser: two of the six are day only (Andy,
   2026-09-22). The soft fill stays at night, dim (--light-core), so the
   active room still reads as active (2026-09-23). */
.ray.day-only { visibility: var(--day-vis); }
.ray-stop { stop-color: var(--light); }

/* THE VEIL. One per bay, between the light and the artwork. A bay the sun has
   left is dimmed by RAISING this, not by fading its beam, so every beam keeps
   one saturation and the light reads as the same light seen further away
   rather than as a weaker light (Andy, 2026-09-21).
   It takes --ground, never a literal cream: the ground goes navy after dark,
   and a hard-coded cream would paint every unlit room cream at night. That is
   the scheme-inert-value defect this page has already shipped four times
   (--wash, the multiply blend, the labels, the button). */
.scrim { fill: var(--ground); }
.scrims { will-change: opacity; }
/* the soft light's falloff: full at the sun, about half across the middle of
   its reach, nothing at the edge, so it never has an edge of its own */
.light-stop-core { stop-color: var(--light); stop-opacity: var(--light-core); }
.light-stop-mid { stop-color: var(--light); stop-opacity: calc(var(--light-core) * 0.55); }
.light-stop-edge { stop-color: var(--light); stop-opacity: 0; }

/* ---------- labels on the drawing ---------- */

/* The labels sit over illustration-density line art, so navy on navy is
   unreadable. A halo in the ground colour carries them over anything and
   inverts correctly at dusk, when --ground and --type-on-ground swap. */
.label {
  font: italic 500 30px/1 var(--labels);
  letter-spacing: 0.04em;
  fill: var(--type-on-ground);
  stroke: var(--ground);
  stroke-width: 7px;
  stroke-linejoin: round;
  paint-order: stroke fill;
}
.label.small { font-size: 22px; stroke-width: 6px; }

/* THE PEOPLE TALK: paper balloons in the page's own tokens, so they invert at
   dusk with everything else. Opacity only, per the motion rule above. */
.talk-balloon { opacity: 0; transition: opacity 0.25s ease-out; }
.talk-balloon.is-on { opacity: 1; }
.talk-moat { fill: var(--ground); stroke: var(--ground); stroke-width: 7px; stroke-linejoin: round; }
.talk-body { fill: var(--ground); stroke: var(--poche); stroke-width: 1.5px; stroke-linejoin: round; }
.talk-text { font: italic 500 17px/1 var(--labels); fill: var(--type-on-ground); }
/* between two messages from one speaker in one balloon */
.talk-divider { stroke: var(--poche); stroke-width: 0.8px; opacity: 0.45; }
.talk-phone rect { fill: none; stroke: var(--type-on-ground); stroke-width: 1.5px; }
.talk-phone .talk-phone-island { fill: var(--type-on-ground); stroke: none; }

/* ---------- the rail ---------- */

.rail { stroke: var(--poche); stroke-width: 1; fill: none; }
.tick { stroke: var(--poche); stroke-width: 1; fill: none; }
.tick.next-day { opacity: 0.35; stroke-dasharray: 2 3; }
.marker { fill: var(--sun); stroke: none; transition: r 0.2s ease-out; }
/* the ring on the ball is the focus indicator, drawn in the page's line; the
   browser's square outline around the group is dropped for it */
.marker-wrap { outline: none; }
.marker-wrap:focus-visible .marker { stroke: var(--type-on-ground); stroke-width: 2; }
/* play and pause, drawn in the ball in the ground colour: play whenever the
   clock is held, pause only when the pointer or focus is on a running ball.
   The ball grows to hold the glyph. */
.ball-icon { fill: var(--ground); opacity: 0; pointer-events: none; transition: opacity 0.15s ease-out; }
.marker-wrap[data-icon="play"] .ball-play,
.marker-wrap[data-icon="pause"].is-hot .ball-pause,
.marker-wrap[data-icon="pause"]:focus-visible .ball-pause { opacity: 1; }
.marker-wrap[data-icon="play"] .marker,
.marker-wrap.is-hot .marker,
.marker-wrap:focus-visible .marker { r: 10px; }
.rail-label {
  font: 500 13px/1 var(--labels);
  font-variant-numeric: tabular-nums;
  fill: var(--type-on-ground);
  stroke: none;
}

/* ---------- phone: a different composition, not a scaled desktop ---------- */

@media (max-width: 719px) {
  /* copy on top, a window on the building, the rail under it. The window shows
     one full bay plus about a third of the next, and pans with the clock. */
  .stage-box { aspect-ratio: 390 / 780; width: 100%; max-height: 100%; }
  /* The copy and the tag FLOW here rather than each being pinned to its own
     guessed offset. Pinning them is what put the tag on top of the button: the
     copy's height is content-driven (wordmark, tagline, button all wrap), so any
     fixed `top` for the tag is a guess that a longer plan name or a wider glyph
     breaks. A column cannot overlap itself. */
  .overlay {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 3cqh 6cqw 0;
    gap: 1.4cqh;
  }
  .type-block { position: static; max-width: 82cqw; }
  .plan-steps { position: static; margin-left: -6cqw; }
  .title-block { padding: 0.45em 0.7em; }
  .step svg { width: 2.6cqw; }
  .wordmark { font-size: 11cqw; }
  .line { font-size: 4cqw; }
  .btn { font-size: 3.6cqw; margin-top: 0.85em; }
  .tag-static { font-size: 2.3cqw; }
  .tag-name { font-size: 3.6cqw; }
  .rail-label { font-size: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  .btn { transition: none; }
  .tag-name { transition: none; }
  .talk-balloon { transition: none; }
}

/* The moon is the same disc as the sun, in cream, with a ground coloured disc
   stamped out of it and offset. scene.js keeps the bite's centre on the sun's
   every frame; --moon switches it on when the wipe flips the scheme. */
.moon-bite { fill: var(--ground); opacity: var(--moon); }

/* The birds and the stars share the sky and swap at the wipe. The button
   takes its fill from --sun, which goes cream for the moon, so its text
   goes navy at night or it is cream on cream (Andy, 2026-09-21). */
/* visibility, NOT opacity: settle fades these same groups in on load and
   writes opacity inline, which beats a stylesheet rule, so an opacity token
   here is silently overridden the moment settle runs. */
.birds-far, .birds-near { visibility: var(--birds-vis); }
.stars { visibility: var(--stars-vis); }
.star { fill: var(--poche); }

/* The sunset wipe. It is the night ground colour, so the moment it covers the
   stage the scheme can flip behind it invisibly, and what it uncovers on the
   way out is already night. */

/* ---------- the sunset wipe: two layers, one edge ----------
   A night copy of the page sits above the day one, clipped to a rectangle whose
   right edge is the wipe (scene.js setWipe writes the clip on the copy itself). Day to the right of the edge, night to its left, and
   because both copies carry real type you can read the words on both sides at
   once. The copy is rebuilt from the live page while the wipe runs, so it is
   never a stale picture of an earlier moment.

   Tokens are declared HERE rather than on :root, which is the whole trick: a
   <use> instance was tried first and does not work, because custom properties
   in a use shadow tree resolve against the original's place in the tree, not
   against where the instance sits. Measured: the sky in a use came back cream
   while the group around it read #14325A. A clone with its defs stripped does
   inherit them, and scene.js gives it renamed copies of the definitions, so
   its gradients take these night tokens rather than the day page's. */

/* ---------- the sunset: a night copy of the page, revealed by one edge ----------
   Everything night sits ABOVE everything day and is clipped to the same edge, so
   the boundary has day on one side and night on the other and the type stays
   readable the whole way across. The copy is a clone of the whole composed box,
   so it brings its own sky, building, rail and type. Its backdrop is its own
   first child rather than a separate panel: a viewport wide panel and the
   narrower box each clip to a percentage of their OWN width, which puts their
   edges in different places and leaves a strip of bare ground past the drawing.
   One parent, one clip, one edge. The clip opens on three sides so the
   oversized backdrop still reaches the letterbox margins. */
.night-box {
  --ground: #14325A;
  --poche: #F2E0C4;
  --light: #FFC873;
  --light-core: 0.25;
  --wash: rgba(242, 224, 196, 0.34);
  --contour: #E9D7B8;
  --sun: #F2E0C4;
  --moon: 1;
  --birds-vis: hidden;
  --stars-vis: visible;
  --button-text: #1F4A7A;
  --type-on-ground: #F2E0C4;
  --hairline: rgba(242, 224, 196, 0.55);
  --mass-fill: #F2E0C4;
  --mass-sw: 0px;
  --wedge-blend: screen;
  --day-vis: hidden;
  clip-path: inset(-100vh 100% -100vh -100vw);
  pointer-events: none;
}

/* the copy's own backdrop, oversized so it reaches the letterbox margins the
   box cannot; clipped by its parent, so its edge and the drawing's are one */
.night-bg {
  position: absolute;
  inset: -100vh -100vw;
  background: var(--ground);
}

.night-box {
  z-index: 3;
}

/* both boxes occupy the one grid cell, so the copy sits exactly over the page */
.stage-box,
.night-box {
  grid-area: 1 / 1;
}

/* The clone is a still picture of the night page, not a live scene, so its
   light has nothing to blend WITH. Leaving mix-blend-mode on it made the
   clone a blending participant above the day layer, and the composite of the
   two was not stable between identical captures. Normal compositing: the
   clone paints, the clip decides where, and nothing beneath it re-composites. */
.night-box .wedge { mix-blend-mode: normal; }
.night-box .wedges { opacity: 1; }
