/* Scooterland — the site
   (version F of the drafts, promoted to index.html on 2026-08-26 when Aaron
   picked it. A–E and the draft 3 pair are archived in bu/web_versions/.)
   ============================================================================
   A strip of film. One photograph, fixed, running the whole height of the
   page; over it a stack of frames that alternate between two states:

     band-film    a solid peach panel, ink navy
     band-open    nothing but the photograph, ink peach

   The panels do not reach the edges of the window. The photograph shows down
   both sides, and a sprocket rail runs the full length of the right-hand
   margin, hard against the panel edges — a bar of peach with rounded holes
   punched through it. The sprockets are evenly spaced down
   the whole page and deliberately unrelated to where panels begin and end,
   the way perforations ignore frame lines on real film.

   Below 900px all of that collapses: panels go edge to edge, the rail
   disappears, and the page is a single column again.

   COLOUR. One peach, doing every job.
     --peach  #edc0ad  panels, ink, drawings, sprockets, wordmark. Arrived at
                       in two moves: the midpoint of the draft 2 wordmark
                       #f9a887 (too sweet as a large flat field) and the
                       desaturated #d8b7a8 that briefly replaced it (too dead
                       as ink), then lifted a fifth of the way to white.
                       Measured: 9.1:1 under navy as a panel, and 5.3:1 as ink
                       over the veiled photograph at its brightest hundredth
                       of a percent, so body copy clears AA anywhere.
     --navy   #16283c  ink on the panels.

   TYPE is the Gridlover scale Aaron supplied: 20px root on a 12px baseline,
   Nerko One, factor 1.5 (1 -> 1.333 -> 2 -> 3 -> 4.5 -> 6.75).

   NOTE ON WEIGHT: Nerko One ships a single weight. There is no bold to give
   the headings or the credits, so every hierarchy here is size, caps,
   letter-spacing and rules. A weighted companion means a second family.
   ========================================================================== */

:root {
  --peach:  #edc0ad;
  --navy:   #16283c;
  --dark:   #0b1119;   /* the veil over the photograph */

  /* Scrim strength, which matters on the open panels only. The script in
     index.html rides it from 0.28 at rest to 0.72 once the copy is on screen.
     This default is the readable end, so the page works with no JS at all. */
  --scrim: 0.72;

  /* The margin the photograph shows through, and the width of the sprocket
     rail, which is attached to the right edge of every panel with no gap
     between them. Perforations belong to the film, not beside it. */
  --edge: 3vw;
  --rail-w: 5.5rem;

  /* Heading multiplier, applied to h1-h2 only. The 1.333em emphasis steps are
     left out of it: shrunk on a phone they fall below the body copy. */
  --hs: 1;
}

/* ---- the grid ---------------------------------------------------------- */

html, .root {
  font-size: 20px;
  line-height: 12px;      /* the baseline unit, per Gridlover */
}

body, .article {
  font-family: "Nerko One", "Comic Sans MS", cursive;
  font-size: 1em;
  line-height: 1.2em;
  margin: 0;
  color: var(--peach);
  background: var(--dark);
  -webkit-font-smoothing: antialiased;
}

/* ---- the fixed photograph and its veil --------------------------------- */

.bg {
  position: fixed;
  inset: 0;
  z-index: -2;
  background-image: url("streetcar-2400.jpg");
  background-position: 62% center;
  background-size: cover;
  background-repeat: no-repeat;
}

@media (max-width: 900px) {
  .bg { background-image: url("streetcar-1200.jpg"); }
}

.scrim {
  position: fixed;
  inset: 0;
  z-index: -1;
  background: var(--dark);
  opacity: var(--scrim);
  transition: opacity 120ms linear;
}

/* ---- hero --------------------------------------------------------------
   Shorter than a full screen on purpose: the first panel breaks the bottom
   edge, so the page reads as a strip of frames before anyone scrolls, and
   less empty picture elapses before the copy starts.
   ---------------------------------------------------------------------- */

.hero {
  min-height: 74vh;
  min-height: 74svh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 5vw;
  box-sizing: border-box;
}

.wordmark {
  margin: 0;
  width: min(89vw, 50.6rem);   /* draft 4: up 15% on Aaron's note */
}

.wordmark img {
  display: block;
  width: 100%;
  height: auto;
}

/* ---- the reel and its sprockets ----------------------------------------
   The rail is one tile repeated down the whole reel: a bar of peach with a
   rounded rectangle punched out of it by fill-rule, so what shows through the
   hole is the photograph. Tile 110 square, perforation 84 by 64. If the
   peach ever changes, sprockets.svg has to be regenerated to match — the
   fill is baked into that file.
   ---------------------------------------------------------------------- */

.reel {
  position: relative;
  /* The strip has a maximum width of its own. Past about this, panels stop
     reading as frames and become slabs: at 2560 the copy sat in a 600px
     column inside a 2400px field of base. Capped, the photograph simply
     shows wider down both sides, which is what a strip of film on a light
     table looks like anyway. */
  max-width: 84rem;
  margin: 0 auto;
}

.sprockets {
  position: absolute;
  top: 0;
  bottom: 0;
  right: var(--edge);
  width: var(--rail-w);
  background: url("sprockets.svg") repeat-y left top;
  background-size: 100% auto;
  pointer-events: none;
}

/* ---- the panels --------------------------------------------------------- */

.band {
  margin-left: var(--edge);
  margin-right: calc(var(--edge) + var(--rail-w));
  padding: 4.8em 0;          /* 96px, eight baselines */
}

.band-film {
  background: var(--peach);
  color: var(--navy);
}

.band-open {
  color: var(--peach);
}

/* The end of the reel: solid navy, peach ink. The photograph stops here
   rather than running out under the sign-off. */
.band-navy {
  background: var(--navy);
  color: var(--peach);
}

.band-close {
  padding: 3.6em 0;
}

/* Below the reel: no panel, no rail, just the photograph. The strip has to
   end somewhere visible, so it ends here, with more than one sprocket and one
   gap of clear picture under it. */
.tail {
  height: 7rem;
}

.inner {
  max-width: 64rem;
  margin: 0 auto;
  padding: 0 2.8rem;
  box-sizing: border-box;
}

.inner-narrow { max-width: 34rem; }

.col-text { max-width: 30rem; }

/* Split panels: drawing one side, copy the other.

   Draft 4 halves the panel evenly — 1fr / 1fr, not 0.9 / 1.1 — and centres
   each side in its own half. Aaron's instruction: read the measure as two
   subcolumns, one for the copy and one for the drawing, each thing centred in
   the subcolumn it owns. The old uneven split left the drawings sitting off
   the axis of their own half, which is what he was seeing.

   Both drawings sit on the LEFT of their panel, over the streetcar, which is
   the dark half of the photograph. The right half is where the child stands,
   and a peach line drawing placed there lands on top of him — tried, and the
   two collided; because the photograph is fixed while the panels scroll, that
   collision moves with the window width and cannot be nudged out of the way.
   So the drawings take the dark side and the copy takes the light one. */
.inner-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 3.2rem;
  align-items: center;
}

.inner-split .col-art  { grid-column: 1; grid-row: 1; }
.inner-split .col-text { grid-column: 2; }

/* The other hand: copy left, drawing in the right half. It is centred in that
   half like the camera is in its own — draft 4 dropped the earlier
   justify-content: flex-start, which hung the scooter off the copy's axis
   instead of its own column's. */
.inner-swap { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.inner-swap .col-text { grid-column: 1; }
.inner-swap .col-art  { grid-column: 2; grid-row: 1; }

/* The form panel hangs its drawing from the top rather than centring it, so
   the scooter stands at the head of the panel. */
.inner-top { align-items: start; }

.col-art {
  display: flex;
  justify-content: center;
}

.art { display: block; }

/* The drawings are outlines with open interiors, so the photograph shows
   through the camera itself. Sized on one axis, with the other explicitly
   auto: the img elements carry width and height attributes, and setting only
   one side in CSS leaves the other at the attribute value, which squashes the
   box. The SVG then letterboxes itself inside it and quietly renders small.
   Both axes are stated here for that reason. */
.art-scooter { height: 15.1rem; width: auto; }
.art-camera  { width: min(100%, 14.6rem); height: auto; }

/* ---- headings ----------------------------------------------------------
   Gridlover's steps are h1 6.75em, h2 4.5em, h3 3em, h4 2em, h5 1.333em.
   Section heads take the 3em step, not 4.5em: at this measure 4.5em put
   "CASTING A YOUNG LEAD." on three lines and the panel read as a poster with
   copy attached. h1 keeps 6.75em; the only h1 is the wordmark image.
   ---------------------------------------------------------------------- */

h1, .h1 {
  font-size: calc(6.75em * var(--hs));
  line-height: 1.06666667em;
  margin-top: 0.08888889em;
  margin-bottom: 0.17777778em;
}

h2, .h2 {
  font-size: calc(3em * var(--hs));
  line-height: 1.2em;            /* 72px, six baselines */
  margin-top: 0;
  margin-bottom: 0.4em;
  font-weight: normal;           /* one weight in the family; fake none */
}

p {
  margin-top: 0;
  margin-bottom: 1.2em;          /* 24px, two baselines */
}

/* The lines the copy sets in bold. No bold exists, so emphasis is a step up
   the same scale. */
.shout {
  font-size: 1.33333333em;
  line-height: 1.35em;
  margin-bottom: 0.9em;
}

.centred { text-align: center; }

/* ---- the credits --------------------------------------------------------
   The roles read as end credits: boxed, centred, role in letterspaced caps
   over its line, and no arrows. No rules between entries — the space does
   that work, and hairlines turned the block back into a table.
   ---------------------------------------------------------------------- */

.credits {
  list-style: none;
  margin: 0 0 2.4em;
  padding: 3.6em 2.8em;
  border: 5px dashed var(--navy);
  text-align: center;
}

.credits li { margin-bottom: 1.8em; }
.credits li:last-child { margin-bottom: 0; }

.credit-role {
  display: block;
  font-size: 1.33333333em;
  line-height: 1.35em;
  text-transform: uppercase;
  letter-spacing: 0.09em;
}

.credit-note {
  display: block;
  font-size: 0.9em;
  line-height: 1.33333333em;
  opacity: 0.9;
}

/* ---- links -------------------------------------------------------------- */

/* One weight in Nerko One, so a link cannot get bolder — it can only get
   thicker underneath. Draft 4 doubled the resting rule and more than doubled it
   again on hover; the state change is the whole gesture.

   THE RULE IS NOT A text-decoration. It is a background, and the reason is a
   Chrome limitation worth writing down: `text-decoration-thickness` paints in
   WHOLE CSS PIXELS ONLY. 2.5px renders byte-identical to 3px — measured at
   device scale 1, 1.25, 1.5 and 2, so it is not a HiDPI question, and asking
   for a half pixel there is a silent no-op that looks like a change in the
   file. That left 2px and 3px and nothing between, and across two passes on
   2026-08-26 Aaron found 2px too light (it read as ordinary underlined text
   until you pointed at it) and 3px a shade heavy.

   A background gradient does antialias, so the thickness is continuous: at
   2.7px the rule paints two solid rows and a third at about half coverage,
   an ink weight of 2.69 against 2.00 and 3.00 for the two decoration steps.
   Verified by sampling the gap between two words of a rendered link, where
   nothing but the rule paints.

   What the swap costs. The rule no longer knows about descenders — irrelevant
   here, since skip-ink was already off and the line was meant to be one
   unbroken bar. It is positioned by hand: 1.15em from the top of the box is
   the row Chrome's own underline sat on at this size, and it grows DOWNWARD
   from there on hover, away from the letters, as the decoration did. The
   padding-bottom is only there to give the 5px hover room inside the
   background box; inline padding does not reflow anything.

   The offset is in em, so it tracks the two other sizes links appear at (the
   1.333em .shout, and the sign-off). Verified at render on all of them. If the
   type scale or line-height moves, this constant has to be re-checked — that
   is the maintenance cost of having a dial here instead of two settings. */
a {
  color: inherit;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 1.15em;
  background-size: 100% 2.7px;
  padding-bottom: 0.25em;
  transition: background-size 90ms linear;
}

a:hover { background-size: 100% 5px; }

a:focus-visible,
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

::selection {
  background: var(--peach);
  color: var(--navy);
}

/* ---- the form, on the open panel ---------------------------------------
   Version E’s form, which Aaron picked: the fields are cut out of the
   photograph rather than laid on top of it. Dark translucent panes with a
   peach edge, peach ink inside, and a peach button sized to its own words
   instead of stretched across the column.
   ---------------------------------------------------------------------- */

form { margin: 0; }

.field-set { margin-bottom: 1.8em; }

label {
  display: block;
  font-size: 1.33333333em;
  line-height: 1.35em;
  margin-bottom: 0.3em;
}

/* The fields are the one place Nerko One is dropped. It is a single-weight
   handwriting face; a paragraph typed into it by someone describing their
   child is hard to read back. Labels, help and button stay in Nerko One. */
textarea,
input[type="email"] {
  display: block;
  width: 100%;
  box-sizing: border-box;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 0.85em;             /* 17px — over the 16px floor, below which
                                    iOS zooms the page on focus */
  line-height: 1.55;
  color: var(--peach);
  background: rgba(11, 17, 25, 0.55);
  border: 2px solid var(--peach);
  border-radius: 0;
  padding: 0.6em 0.7em;
  -webkit-appearance: none;
  appearance: none;
}

textarea { min-height: 9rem; resize: vertical; }

/* Focus. The generic :focus-visible ring drew a second rectangle outside the
   field's own edge, so a focused box read as two thin outlines with a gap —
   fussy at this size and nothing like the rest of the page. Draft 4 switches
   that ring off here and thickens the box itself instead: the 2px border plus
   a 3px ring sitting flush against it, which renders as one solid 5px line.
   Done as a box-shadow rather than a wider border so nothing reflows and the
   text inside does not jump when you click into it. Same gesture as the
   chunky underline — the line you already had, made heavier. */
textarea:focus,
input[type="email"]:focus,
textarea:focus-visible,
input[type="email"]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--peach);
}

textarea::placeholder,
input::placeholder { color: rgba(233, 176, 152, 0.55); }

.help {
  font-size: 0.9em;
  line-height: 1.33333333em;
  margin: 0.6em 0 0;
  opacity: 0.85;
}

/* Send. Draft 4 empties it out at rest — a wash of peach inside a peach edge,
   peach ink — so that hovering fills it solid and flips the ink to navy. The
   button was a solid slab in both states before, and the hover did almost
   nothing; now the state change is the whole point of the shape.

   THE WASH IS 0.30, raised from 0.10 on 2026-08-26 because at rest the button
   read as an empty outline. It stops short of the halfway point Aaron asked
   for, and the reason is measured rather than taste. Peach ink cannot survive
   on a peach fill: sampling the actual pixels behind this button across nine
   window sizes from 390 to 2560 gives, for the resting label,

     0.10  8.4 – 9.5:1     0.30  3.7 – 5.0:1     0.35  3.3 – 4.4:1
     0.38  3.1 – 4.0:1     0.40  3.0 – 3.8:1     0.55  2.6 – 2.8:1

   The label is 26.7px, so 3:1 is the floor it has to clear, and the binding
   size is always 390px — the phone crop puts a brighter piece of pavement
   behind the button than any desktop crop does. There it reads 3.67 at 0.30,
   3.29 at 0.35, 3.08 at 0.38 and 2.96 at 0.40. So 0.35 is the last setting
   with margin left in it and 0.40 is already over the line. Past this the only
   way to go on filling the shape is to flip the resting ink to navy, and that
   spends the hover, which is the one thing the button has. If it still wants
   presence, thicken the edge, do not fill it further. */
button[type="submit"] {
  font-family: inherit;
  font-size: 1.33333333em;
  line-height: 1.35em;
  color: var(--peach);
  background: rgba(237, 192, 173, 0.35);
  border: 2px solid var(--peach);
  border-radius: 0;
  padding: 0.3em 1.4em;
  cursor: pointer;
  transition: background-color 120ms linear, color 120ms linear;
}

button[type="submit"]:hover,
button[type="submit"]:focus-visible {
  background: var(--peach);
  color: var(--navy);
}

.privacy {
  font-size: 0.9em;
  line-height: 1.33333333em;
  margin: 1.6em 0 0;
  opacity: 0.85;
}

/* ---- the thank-you, in place -------------------------------------------
   2026-08-26. The form posts over fetch and this panel becomes the thank-you
   rather than sending anyone to thanks.html. That page still exists and still
   works; it is now the no-JS fallback.

   The height is frozen in the script at the moment of the swap, not guessed
   here, because it depends on how the two fields have wrapped. The panel
   keeps the size it had and centres the message in it — this is the open
   panel, so the room it keeps on holding is photograph, which is the one
   place on the page where leftover space costs nothing. Column flex rather
   than row: a single flex item in a row shrinks to its own text and the
   measure would jump narrower than the form's. */
#sayhi-panel.is-done {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

#sayhi-done h2:focus { outline: none; }

#sayhi-title,
#sayhi-form,
#sayhi-done { transition: opacity 180ms linear; }

#sayhi-title.is-out,
#sayhi-form.is-out,
#sayhi-done.is-out { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  #sayhi-title,
  #sayhi-form,
  #sayhi-done { transition: none; }
}

/* Sending. The button is the only thing on the page that can report a request
   in flight, so it says so and stops taking clicks. The hover is held down
   too, or a disabled button still lights up under the cursor. */
button[type="submit"][disabled] {
  opacity: 0.6;
  cursor: default;
}

button[type="submit"][disabled]:hover {
  background: rgba(237, 192, 173, 0.35);
  color: var(--peach);
}

/* The failure. Cut out of the photograph like the fields are, so it reads as
   part of the form rather than as the page coming apart. */
.form-error {
  font-size: 0.9em;
  line-height: 1.33333333em;
  margin: 0 0 1.2em;
  padding: 0.6em 0.7em;
  color: var(--peach);
  background: rgba(11, 17, 25, 0.55);
  border: 2px solid var(--peach);
}

/* ---- sign-off ----------------------------------------------------------- */

.sign { margin-top: 2.4em; }

/* ---- narrow -------------------------------------------------------------
   The frames become the whole window: no margins, no rail, one column. A
   sprocket rail at phone width would eat a tenth of the measure to decorate
   a page nobody is reading as a filmstrip anyway.
   ---------------------------------------------------------------------- */

@media (max-width: 900px) {
  :root {
    --hs: 0.66;                  /* 3em section heads become 40px, not 60px */
    --edge: 0px;
    --rail-w: 0px;
  }

  .sprockets { display: none; }

  .band { padding: 3.6em 0; }
  .band-close { padding: 2.8em 0; }
  .tail { height: 5rem; }

  .inner { padding: 0 1.4rem; }
  .col-text { max-width: none; }

  /* One column, in DOM order, so each drawing heads its own panel. */
  .inner-split {
    grid-template-columns: 1fr;
    gap: 2.4rem;
  }
  .inner-split .col-art,
  .inner-split .col-text { grid-column: 1; }
  .inner-split .col-art { grid-row: auto; }

  /* Left, not centred: at phone width the fixed photograph puts the child
     right of centre, and a centred drawing sits on top of him. */
  .col-art { justify-content: flex-start; }

  .art-scooter { height: 10.5rem; width: auto; }
  .art-camera  { width: min(100%, 10.5rem); height: auto; }

  /* The 15% is honoured here too, which means the hero's side padding has to
     give: at 86vw the mark already sat inside a 5vw gutter, and 15% more than
     that does not fit one. The gutter drops to 2vw and the mark takes 92 —
     96 was tried and the tail of the "d" kissed the right edge, which reads as
     a clipped image rather than a bleed. So the phone gets about 7%, not 15;
     there is no more room on a 390px screen. */
  .hero { padding: 0 2vw; }
  .wordmark { width: 92vw; }

  /* Cover on a tall narrow window samples a thin vertical slice of the
     photograph. At 62% the child sits half off the right edge, so the crop
     moves right to keep him in the frame the wordmark rests on. */
  .bg { background-position: 74% center; }

  .credits { padding: 2.6em 1.6em; }
  /* Letterspaced caps at 26.7px break a long role across three lines on a
     phone. One step down, and looser tracking traded for fewer breaks. */
  .credit-role { font-size: 1.1em; letter-spacing: 0.06em; }
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
