/* noon-garden — one continuous flight through a garden in full daylight.
   The engine's own selectors (.sc-world, .sc-copy, [data-sc-*]) are the
   mechanism and are not restyled here. Everything below is this page. */

:root {
  /* Six roles, one accent, sampled from the approved reference frame.

     They are declared as component triplets and the roles are derived from
     them, so a translucent variant of a role is written `rgb(var(--x-rgb) / a)`
     rather than `color-mix()`. That is not style preference. `color-mix()`
     computes to an `oklab(... / a)` string, the verification harness reads
     computed background-color to measure contrast, and an unparsed colour is
     scored as if the plate were dark: every copy window on this page reported
     1.31:1 against a paper plate that actually measures 15:1. Rebranding is
     still six values -- these six. */
  --canvas-rgb:     238 241 233;
  --surface-rgb:    253 252 248;
  --ink-rgb:         28  36  24;
  --ink-soft-rgb:    92 107  86;
  --accent-rgb:     107  37  69;
  --accent-ink-rgb: 253 252 248;

  --sc-canvas:     rgb(var(--canvas-rgb));
  --sc-surface:    rgb(var(--surface-rgb));
  --sc-ink:        rgb(var(--ink-rgb));
  --sc-ink-soft:   rgb(var(--ink-soft-rgb));
  --sc-accent:     rgb(var(--accent-rgb));
  --sc-accent-ink: rgb(var(--accent-ink-rgb));

  --sc-font-display: "Bellefair", "Frank Ruhl Libre", serif;
  --sc-font-text:    "Heebo", system-ui, sans-serif;

  /* The elevation tokens are tinted to the canvas hue by the engine's own
     rule, and that hue is now green rather than near-black. */
  --sc-shadow-color: 105 26% 12%;

  --rule: rgb(var(--ink-rgb) / 0.24);
  --paper: rgb(var(--surface-rgb) / 0.94);
  --paper-edge: rgb(var(--ink-rgb) / 0.14);

  /* ---- the signature move: the page shares the garden's sun -------------
     The engine publishes the leg index and the progress inside it. Both are
     unitless numbers, so the sun position is derivable in CSS with no script
     and no second scroll listener. 0 at the gate, 0.5 overhead at the water,
     1 at the canopy — the same arc the film travels.

     Everything the page casts a shadow from reads these three values, so one
     light source lights the whole interface and it is the film's own. */
  --sun:      calc((var(--sc-seg, 0) + var(--sc-segp, 0)) / 5);
  --sun-d:    calc(0.5 - var(--sun));                        /*  +0.5 .. -0.5 */
  --sun-skew: calc(var(--sun-d) * 64deg);                    /*  +32deg .. -32deg */
  --sun-len:  calc(0.42 + var(--sun-d) * var(--sun-d) * 3.4); /* 1.27 low, 0.42 overhead */

  /* How far the close has burnt the world out to white. One number, used by
     the sheet that does the burning and by every shadow that has to stop
     existing while it happens: once the garden is gone there is no sun to
     cast one, and a long soft wedge lying across a blank page is a leftover. */
  --burn: clamp(0, calc((var(--sc-seg, 0) - 4 + var(--sc-segp, 0) - 0.18) / 0.55), 1);
}

html { background: var(--sc-canvas); }
body {
  background: var(--sc-canvas);
  font-family: var(--sc-font-text);
  font-weight: 400;
  letter-spacing: 0;
}

::selection { background: var(--sc-accent); color: var(--sc-accent-ink); }
:focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 3px; border-radius: 4px; }

/* A daylight world does not want the engine's night grain at full strength. */
.sc-grain { opacity: 0.022; }

/* ---------- the cast shadow --------------------------------------------- */

/* One rule, every raised thing. The blur is static; only the transform moves,
   so the scroll path stays on the compositor.

   The copy plates are deliberately NOT given `position` here. They are already
   positioned by the engine's own `.sc-copy`, and a `position: relative` at the
   same specificity later in the cascade quietly wins, drops them back into
   document flow, and breaks the one rule a worldflight has: nothing in flow
   but the spacer. Measured — `worldflight-assert.mjs` caught exactly that. */
.bar__mark, .cta, .dial { position: relative; }
.card::before, .plate::before, .sheet::before,
.cta::before, .dial::before {
  content: "";
  position: absolute; inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: rgb(16 26 12 / 0.62);
  opacity: calc(0.13 * (1 - var(--burn)));
  filter: blur(16px);
  /* The origin is the TOP edge, so the shadow is thrown down and away from the
     light the way a real one is. Anchored at the bottom it grows upward out of
     the object, which reads as a smudge rather than a shadow. */
  transform-origin: 50% 0%;
  transform: translateY(6px) skewX(var(--sun-skew)) scaleY(var(--sun-len));
  will-change: transform;
}
.cta::before, .dial::before { filter: blur(7px); opacity: calc(0.14 * (1 - var(--burn))); }

/* ---------- fixed chrome ------------------------------------------------- */

.bar {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sc-4);
  padding: clamp(0.9rem, 2.4vw, 1.3rem) var(--sc-gutter);
  background: linear-gradient(to bottom,
              rgb(255 255 255 / 0.62),
              transparent);
}
.bar__mark {
  font-family: var(--sc-font-display);
  font-size: 1.15rem; letter-spacing: 0.2em; color: var(--sc-ink);
  text-shadow: 0 1px 0 rgb(255 255 255 / 0.7);
}

.cta {
  font: inherit; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  white-space: nowrap;
  padding: 0.6rem 1.15rem;
  font-size: 0.9rem; font-weight: 500; letter-spacing: 0.01em;
  border-radius: 2px;
  border: 1px solid var(--sc-accent);
  background: var(--sc-surface); color: var(--sc-accent);
  transition: transform 140ms var(--sc-ease-out),
              background-color 200ms var(--sc-ease-out),
              color 200ms var(--sc-ease-out);
}
.cta:hover { background: var(--sc-accent); color: var(--sc-accent-ink); transform: translateY(-1px); }
.cta:active { transform: translateY(1px) scale(0.985); }

/* ---------- the dial -----------------------------------------------------
   The nav is the sun. The dot sits on the arc where the sun sits in the film,
   because both read --sun, and pressing it opens the stations. A rail of
   always-visible waypoints is the other build's treatment. */
.dial {
  position: fixed; z-index: 41;
  inset-block-end: clamp(1rem, 3vh, 2rem);
  inset-inline-start: clamp(1rem, 3vw, 2.4rem);
  width: 64px; height: 44px; padding: 0;
  border: 0; background: none; cursor: pointer;
  color: rgb(var(--ink-rgb) / 0.55);
  transition: color 200ms var(--sc-ease-out);
}
.dial:hover { color: var(--sc-accent); }
.dial__arc { width: 64px; height: 40px; }
.dial__dot {
  /* Physical `left`/`top`, not the logical pair. `offset-path` coordinates are
     measured from the box's own position, and in RTL `inset-inline-start`
     anchors that box to the dial's RIGHT edge — so the dot walked off the side
     of the viewport instead of along the arc. Measured: x 1234 to 1286 in a
     1280px window. The path is the SVG's, so the origin has to be the SVG's. */
  position: absolute; top: 0; left: 0;
  width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  background: var(--sc-accent);
  offset-path: path("M6 34 A26 26 0 0 1 58 34");
  offset-distance: calc(var(--sun) * 100%);
  offset-rotate: 0deg;
}
/* Without offset-path the dot would stack at the arc's origin and read as a
   defect. Park it at the top of the arc instead: still true at the canopy,
   never wrong-looking. */
@supports not (offset-path: path("M0 0 L1 1")) {
  .dial__dot { top: 8px; left: 32px; margin: 0; }
}

/* `[hidden]` is a UA rule, so an author `display` on the same element beats it
   and the overlay stays open forever — with a backdrop-filter over the whole
   page. Say it here, next to the display that would otherwise win. */
.stations[hidden] { display: none; }
.stations {
  position: fixed; inset: 0; z-index: 55;
  display: grid; place-items: center;
  background: rgb(var(--canvas-rgb) / 0.88);
  backdrop-filter: blur(6px);
}
.stations__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: clamp(0.4rem, 1.6vh, 1rem);
  text-align: center;
}
.stations__leg {
  font: inherit; cursor: pointer; background: none; border: 0;
  padding: 0.5rem 1rem;
  display: grid; gap: 0.1rem;
  color: var(--sc-ink);
  transition: color 180ms var(--sc-ease-out);
}
.stations__leg i {
  font-style: normal; font-size: 0.7rem; letter-spacing: 0.24em;
  color: var(--sc-ink-soft);
}
.stations__leg span {
  font-family: var(--sc-font-display);
  font-size: clamp(1.7rem, 6vw, 2.6rem); line-height: 1.1;
}
.stations__leg:hover, .stations__leg[aria-current="true"] { color: var(--sc-accent); }

/* ---------- the burn-out ------------------------------------------------
   The close. Over the last leg the garden over-exposes to white and the page
   becomes paper. Derived from the leg index, so it is tied to the film rather
   than to a scroll number that would drift when the weights change. */
.burn {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: var(--sc-surface);
  opacity: var(--burn);
}

/* ---------- paper -------------------------------------------------------
   Copy never sits on the film. Measured on the reference frame the text band
   runs YAVG 106 with YLOW 35 and YHIGH 173, so neither dark ink nor light ink
   clears 4.5:1 against it unaided. The plate is the fix, and it is the same
   object three times: the hero card, the copy plates, and the closing sheet. */
.card, .plate, .sheet {
  background: var(--paper);
  border: 1px solid var(--paper-edge);
  border-radius: 2px;
  color: var(--sc-ink);
}

.card {
  inset-inline: auto; left: 50%; top: 50%; translate: -50% -50%;
  text-align: center;
  width: min(30rem, 82vw);
  padding: clamp(2rem, 6vw, 3.4rem) clamp(1.4rem, 5vw, 3rem);
}
.card__eyebrow {
  margin: 0;
  font-family: var(--sc-font-display);
  font-size: clamp(1.9rem, 7vw, 3.1rem); line-height: 1.1;
  letter-spacing: 0.02em;
}
.card__hint {
  margin: 0;
  font-size: 0.78rem; letter-spacing: 0.22em;
  color: var(--sc-ink-soft);
}

.plate {
  inset-inline: auto; left: 50%; translate: -50% 0;
  bottom: clamp(3.5rem, 14vh, 8rem);
  text-align: center;
  width: min(34rem, 86vw);
  padding: clamp(1.3rem, 4vw, 2.1rem) clamp(1.2rem, 4vw, 2.4rem);
}
.plate--names { bottom: clamp(4rem, 18vh, 10rem); }

/* ---------- the writing --------------------------------------------------
   Each line derives its own state from the engine's published leg progress
   with a per-line offset, so the writing is paced by the camera and not by a
   timer: stop scrolling and the writing stops with you.

   The first build wiped its lines up from below with a clip-path. This one
   lifts them and opens a hairline from the inline-start edge, which is the
   direction the language runs. */
.ink {
  --t: clamp(0, calc((var(--sc-segp, 0) - 0.08 - var(--i, 0) * 0.05) / 0.18), 1);
  opacity: var(--t);
  transform: translateY(calc((1 - var(--t)) * 0.42em));
}
.rule {
  --t: clamp(0, calc((var(--sc-segp, 0) - 0.08 - var(--i, 0) * 0.05) / 0.18), 1);
  margin: clamp(0.7rem, 2.2vw, 1.1rem) auto;
  width: clamp(3rem, 22%, 6rem); height: 1px;
  background: var(--rule);
  transform: scaleX(var(--t));
  transform-origin: 100% 50%;   /* the inline-start edge in RTL */
}

/* The hero card is on the engine's `hero` window, which holds from the first
   pixel — so its lines are not keyed off leg progress. At scroll 0 the leg
   progress is 0, every derived `--t` is 0, and the page would open on an empty
   white rectangle. The invitation says what it is before anyone moves. */
.card .ink, .card .rule { --t: 1; }


.names {
  margin: 0;
  font-family: var(--sc-font-display);
  font-weight: 400;
  font-size: clamp(2.6rem, 11vw, 5rem);
  line-height: 1.02;
  letter-spacing: 0.01em;
  display: flex; justify-content: center; align-items: baseline; gap: 0.28em;
  flex-wrap: wrap;
}
.names .amp { color: var(--sc-accent); font-size: 0.62em; }
.under {
  margin: 0;
  font-size: 0.8rem; letter-spacing: 0.28em; color: var(--sc-ink-soft);
}

.date {
  margin: 0;
  display: grid; gap: 0.25rem;
  font-family: var(--sc-font-display);
  font-size: clamp(1.5rem, 5.4vw, 2.3rem); line-height: 1.18;
}
.hebdate {
  margin: 0;
  font-size: 0.82rem; letter-spacing: 0.16em; color: var(--sc-ink-soft);
}

.times { margin: 0; display: grid; gap: 0.55rem; }
.times__row {
  display: flex; justify-content: center; align-items: baseline; gap: 0.7rem;
}
.times__row dt {
  font-size: 0.78rem; letter-spacing: 0.2em; color: var(--sc-ink-soft);
}
.times__row dd {
  margin: 0;
  font-family: var(--sc-font-display);
  font-size: clamp(1.6rem, 5.6vw, 2.4rem); line-height: 1;
}

.place {
  margin: 0;
  font-family: var(--sc-font-display);
  font-size: clamp(1.7rem, 6vw, 2.6rem); line-height: 1.1;
}
.addr { margin: 0.2rem 0 0; font-size: 0.9rem; color: var(--sc-ink-soft); }

.actions {
  margin-block-start: clamp(0.9rem, 3vw, 1.3rem);
  display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6rem;
}
.btn {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.55rem 1rem;
  font-size: 0.86rem; font-weight: 500;
  text-decoration: none;
  border: 1px solid rgb(var(--ink-rgb) / 0.26);
  border-radius: 2px;
  color: var(--sc-ink); background: rgb(var(--surface-rgb) / 0.7);
  transition: border-color 180ms var(--sc-ease-out), color 180ms var(--sc-ease-out);
}
.btn svg { width: 17px; height: 17px; }
.btn:hover { border-color: var(--sc-accent); color: var(--sc-accent); }

/* ---------- the sheet ----------------------------------------------------
   The world has burnt out to white and only the document is left. The form is
   not an object in the scene; it is the page the scene became. */
.sheet {
  inset-inline: auto; left: 50%; top: 50%; translate: -50% -50%;
  width: min(34rem, 90vw);
  padding: clamp(1.1rem, 4vw, 2rem) clamp(1rem, 4vw, 2.2rem);
  text-align: start;
}
.form { display: grid; gap: clamp(0.5rem, 1.6vh, 0.85rem); }
.form h2 {
  margin: 0 0 0.2rem;
  font-family: var(--sc-font-display); font-weight: 400;
  font-size: clamp(1.6rem, 5.6vw, 2.2rem); line-height: 1.1;
  text-align: center;
}
.field { display: grid; gap: 0.28rem; }
.field label, .fieldset legend {
  font-size: 0.74rem; letter-spacing: 0.14em; color: var(--sc-ink-soft);
}
.field input {
  font: inherit; font-size: 0.95rem;
  padding: 0.5rem 0.7rem;
  color: var(--sc-ink);
  background: rgb(246 248 241);
  border: 1px solid rgb(var(--ink-rgb) / 0.20);
  border-radius: 2px;
  min-width: 0;
}
.field input:focus { border-color: var(--sc-accent); }
.fieldset { margin: 0; padding: 0; border: 0; display: grid; gap: 0.28rem; }
.fieldset legend { padding: 0; }
.choices { display: flex; gap: 0.5rem; }
.choice {
  flex: 1;
  display: flex; align-items: center; gap: 0.4rem;
  padding: 0.45rem 0.6rem;
  font-size: 0.9rem;
  border: 1px solid rgb(var(--ink-rgb) / 0.20);
  border-radius: 2px;
  cursor: pointer;
}
.choice input { accent-color: var(--sc-accent); }
.choice:has(input:checked) { border-color: var(--sc-accent); color: var(--sc-accent); }
.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; }

.form button[type="submit"] {
  font: inherit; cursor: pointer;
  margin-block-start: 0.2rem;
  padding: 0.62rem 1rem;
  font-size: 0.95rem; font-weight: 500;
  color: var(--sc-accent-ink); background: var(--sc-accent);
  border: 1px solid var(--sc-accent); border-radius: 2px;
  transition: transform 140ms var(--sc-ease-out), opacity 200ms var(--sc-ease-out);
}
.form button[type="submit"]:hover { transform: translateY(-1px); }
.form button[type="submit"]:disabled { opacity: 0.55; cursor: default; transform: none; }

.result {
  margin: 0; font-size: 0.88rem; text-align: center;
  padding: 0.4rem 0.6rem; border-radius: 2px;
}
.result--ok  { color: var(--sc-ink); background: rgb(var(--accent-rgb) / 0.12); }
.result--bad { color: var(--sc-accent); background: rgb(var(--accent-rgb) / 0.10); }

.foot {
  margin: clamp(0.6rem, 2vh, 1rem) 0 0;
  font-size: 0.72rem; letter-spacing: 0.14em; text-align: center;
  color: var(--sc-ink-soft);
}

/* ---------- reduced motion -----------------------------------------------
   No clip is fetched at all; the posters are the film and they cross-dissolve
   through the same seams at the same scroll positions. What goes is movement:
   the sun stops at noon and every line is settled and readable. */
@media (prefers-reduced-motion: reduce) {
  :root { --sun: 0.5; --sun-d: 0; }
  .ink, .rule { --t: 1; }
  .ink { transform: none; }
  .card::before, .plate::before, .sheet::before,
  .cta::before, .dial::before { transform: none; }
  .stations { backdrop-filter: none; }
}

/* ---------- phone --------------------------------------------------------
   The plates get closer to the edges and the dial moves out of the thumb's
   way. Nothing is removed: a phone reader gets the same six windows. */
@media (max-width: 700px) {
  /* No blurred layers over the film. Six `filter: blur()` pseudo-elements
     composited above five mounted clips is the same kind of cost the first
     build removed its full-screen grain filter for, and a phone spends that
     budget on the one hardware video decoder instead. The sun still moves —
     the skew and the length are transforms — it just casts a hard shadow
     here, which a midday sun does anyway. */
  .card::before, .plate::before, .sheet::before,
  .cta::before, .dial::before { filter: none; opacity: calc(0.07 * (1 - var(--burn))); }

  .plate, .card, .sheet { width: min(34rem, 92vw); }
  .plate { bottom: clamp(3rem, 11vh, 6rem); }
  .plate--names { bottom: clamp(3.5rem, 15vh, 8rem); }

  /* Phone type sizes, carried over from the first build's real-device round.
     A date is read, not admired: at 8vw it touches both gutters on a 390px
     screen and reads as broken layout rather than as scale. */
  .card__eyebrow { font-size: clamp(1.8rem, 9vw, 2.6rem); }
  .names { font-size: clamp(2.4rem, 13vw, 3.8rem); }
  .date { font-size: clamp(1.15rem, 5.6vw, 1.75rem); text-wrap: balance; }
  .times dd, .place { font-size: clamp(1.4rem, 7.5vw, 2.1rem); }
  .actions .btn { flex: 1 1 auto; justify-content: center; }
  .dial {
    inset-block-end: max(0.9rem, env(safe-area-inset-bottom));
    inset-inline-start: 0.9rem;
    transform: scale(0.85); transform-origin: 0 100%;
  }
  .row2 { gap: 0.5rem; }
  .form { gap: 0.45rem; }
  .sheet { padding: 1rem 0.95rem; }
}

/* A guest count is typed or tapped, never nudged one at a time: the native
   spinner is two 8px hit targets on a touch screen, well under the 44px floor,
   and it steals width from the number itself. `inputmode="numeric"` already
   gives the phone the right keypad. Carried over from the first build, where
   it was found on a real device. */
.field input[type="number"] { appearance: textfield; -moz-appearance: textfield; }
.field input[type="number"]::-webkit-outer-spin-button,
.field input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none; appearance: none; margin: 0;
}
