/* ============================================================
   LOAD & REVEAL — the house's first paint (labs/load-lab.html, the user's
   picks of 2026-09-13; memory: load-reveal-picks)
     LD14  the first screen: the heading's house line mask; on a photo
           hero (.stage__plate / .stage__person) the room lights up with
           it and the person settles
     LD06  below the fold: the kit's soft rise; headings keep the line mask
     LD12  page to page: the browser's cross-fade
   The one rule: nothing is shown and then hidden. The engine's pages set
   html.ld-js in <head> before the first paint (never under reduced
   motion); behaviours.js arms html.reveal-ready. If it hasn't 3 s after
   the page is parsed, the head snippet drops ld-js and the page simply
   shows. Needs <main id="main"> with the sections as its children.
   ============================================================ */

/* ---------- fonts: fallbacks with the real faces' metrics ----------
   Measured in Chrome against the kit's own styles (the load lab), so the
   swap from Arial to Archivo barely moves a line. The heading face is
   picked by font-stretch (the kit's 112 %), so 700 buttons don't get it. */
@font-face { font-family: "Archivo Fallback"; src: local("Arial"), local("ArialMT"); font-weight: 100 599;
  size-adjust: 98.5%; ascent-override: 89.3%; descent-override: 21.3%; line-gap-override: 0%; }
@font-face { font-family: "Archivo Fallback"; src: local("Arial Bold"), local("Arial-BoldMT"); font-weight: 600 900; font-stretch: 105% 125%;
  size-adjust: 110.6%; ascent-override: 79.6%; descent-override: 19%; line-gap-override: 0%; }
@font-face { font-family: "Bricolage Fallback"; src: local("Arial"), local("ArialMT");
  size-adjust: 92.9%; ascent-override: 100.1%; descent-override: 29.1%; line-gap-override: 0%; }
:root {
  --font-head:   'Archivo', 'Archivo Fallback', sans-serif;
  --font-body:   'Archivo', 'Archivo Fallback', sans-serif;
  --font-accent: 'Bricolage Grotesque', 'Bricolage Fallback', sans-serif;
}

/* ---------- page to page (LD12) ---------- */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }

/* ---------- 1 · drawn, not yet armed ----------
   The runtime draws the sections, then behaviours.js arrives and arms the
   reveal (on a slow phone that takes seconds: it measures every block).
   In between the words wait at 1 % (Chrome still counts that paint for
   LCP), so nothing is painted that the reveal would hide again. The first
   section's photo layers show at once, dim under the lights (section 2),
   so the first screen is never blank; below it, whole sections wait. */
html.ld-js:not(.reveal-ready) #main > * { opacity: .01; }
html.ld-js:not(.reveal-ready) #main > :first-child { opacity: 1; }
html.ld-js:not(.reveal-ready) #main > :first-child :is(h1, h2, h3, p, ul, ol, dl, .btn, .actions) { opacity: .01; }
/* Hidden means 1 %, never 0: the kit's 0 would move LCP to the end of a reveal. */
html.ld-js.reveal-ready .reveal:not([data-reveal="lines"]) { opacity: .01; }

/* ---------- 2 · the first screen (LD14) ---------- */
/* What follows the heading waits for its lines, then follows them. */
html.ld-js #main > :first-child .reveal[data-reveal="lines"]:not(.is-in) ~ .reveal { animation: none; }

/* Lights up: on a photo hero the room (the plate only) waits dim under a
   ground-coloured layer and brightens as the heading's lines rise; the
   person settles. The wave bands above the plate are never dimmed: they
   draw in at full strength as soon as the page is up (the user, 2026-09-13).
   Compositor only; the photo itself paints at once (LCP unchanged). The
   person moves by translate/scale, which compose with the parallax and
   pointer transforms behaviours.js sets. */
html.ld-js #main > :first-child .stage__plate::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: var(--bg, #070b14); opacity: 0;
  animation: ld-lights 1.8s cubic-bezier(.3, .1, .3, 1) .1s backwards;
}
html.ld-js #main > :first-child :is(.stage__person, .stage__cast) img { animation: ld-settle 1.8s var(--ease-out, cubic-bezier(.16, 1, .3, 1)) backwards; }
/* held at the animations' first frame until the heading is in, so their start is no jump */
html.ld-js #main > :first-child:has(h1.reveal[data-reveal="lines"]:not(.is-in)) .stage__plate::after { animation: none; opacity: .8; }
html.ld-js #main > :first-child:has(h1.reveal[data-reveal="lines"]:not(.is-in)) :is(.stage__person, .stage__cast) img { animation: none; translate: 0 10px; scale: 1.015; }
@keyframes ld-lights { from { opacity: .8; } }
@keyframes ld-settle { from { translate: 0 10px; scale: 1.015; } }
/* ---------- 3 · safety nets ---------- */
/* No gate (the failsafe dropped it before the reveal armed): the kit's reveal hides nothing. */
html.reveal-ready:not(.ld-js) .reveal { opacity: 1; animation: none; }
html:not(.ld-js) .reveal[data-reveal="lines"] :is(.ln, .ln__i) { transform: none; opacity: 1; animation: none; }
/* The preference changes after load. */
@media (prefers-reduced-motion: reduce) {
  html.ld-js.reveal-ready .reveal:not([data-reveal="lines"]) { opacity: 1; animation: none; }
  html.ld-js .stage__plate::after { display: none; }
  html.ld-js :is(.stage__person, .stage__cast) img { animation: none; translate: none; scale: none; }}
@media print {
  html.ld-js #main > * { opacity: 1 !important; }
  html.ld-js .stage__plate::after { display: none; }
}
