/* ============================================================
   Boot — the first three seconds.

   The page does not fade in. It opens on a flat sheet of ink-blue
   with the wordmark set small and tracked wide in the middle of it,
   a hairline filling beside the wordmark while the fonts and the
   hero photograph land, and then the sheet slides off to the left
   to leave the headline already in place over the room.

   Two rules make it work:

     - The headline never moves. It is revealed on the blue, and the
       blue is then taken away from underneath it. Anything that
       animates the headline a second time turns a reveal into a
       transition, and the room stops feeling like it was always
       behind the sheet.

     - The sheet the wordmark sits on and the curtain that wipes off
       the hero are the same colour and the same element family, so
       the handover between them is invisible. The overlay carries
       the wordmark; the curtain lives inside .hero, underneath the
       headline in the stack, which is the only way a wipe can pass
       behind live text.

   Gated on .js and on prefers-reduced-motion. Nothing here is ever
   allowed to be the reason content cannot be read.
   ============================================================ */

/* ---- The scroll lock ----
   position:fixed on <body> would lose the scroll position; the page
   is at the top during boot, so overflow is enough and cheaper. */
html.is-booting,
html.is-booting body {
  overflow: hidden;
  height: 100%;
}

/* ---- The sheet ---- */

/* Only ever displayed while a boot is actually running. The element
   is in the markup rather than written by JS so it can be painted on
   the very first frame, which means the default has to be `none` —
   a warm load must not flash a blue rectangle for the one tick it
   takes the deferred boot.js to remove it. */
#boot { display: none; }

html.is-booting #boot {
  position: fixed;
  inset: 0;
  /* Above the nav (8000) and the drawer (8400), below the skip link
     (9000) — a keyboard user landing on the page mid-sequence must
     still be able to jump past it. */
  z-index: 8600;
  display: grid;
  place-items: center;
  background: var(--blue);
  color: var(--paper);
  /* Nothing under it is interactive while it is up, but a stray
     pointer-down on the way out should already reach the page. */
  pointer-events: none;
}

/* Belt and braces: `hidden` wins even if is-booting is somehow still
   set, so the sheet can never sit invisibly over the nav. */
#boot[hidden] { display: none !important; }

.boot__mark {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 2vw, 1.6rem);
  padding-inline: var(--gutter);
}

/* Held until splitChars has run, exactly like the headings — an
   unsplit wordmark flashing at full opacity and then jumping into
   its masks is the one frame that gives the whole sequence away. */
.boot__word:not(.is-split) { visibility: hidden; }

.boot__word {
  font-family: var(--body);
  font-size: var(--t-small);
  font-weight: 500;
  /* The same 0.16em the labels use, opened up: at this size the
     tracking is what makes six characters read as a wordmark rather
     than as a caption. */
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* The loading rule. It is a real progress bar — boot.js scales it
   against fonts, the hero image and a floor duration — not a fixed
   animation pretending to measure something. */
.boot__rule {
  position: relative;
  width: clamp(80px, 14vw, 200px);
  height: 1px;
  background: rgb(255 255 255 / 0.22);
  overflow: hidden;
}
.boot__rule::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--paper);
  transform: scaleX(var(--boot-progress, 0));
  transform-origin: left center;
}

/* ---- The curtain that comes off the hero ----
   z-index 2 puts it above the photograph, the scrim and the grid,
   and below .hero__body at 3. That gap is the whole trick. */
.hero__curtain {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--blue);
  pointer-events: none;
  /* Only exists while a boot is actually running. */
  display: none;
}
html.is-booting .hero__curtain,
html.boot-revealing .hero__curtain { display: block; }

/* The navigation is part of the arrival, not part of the sheet. It
   fades in with the room rather than sitting over a loading screen —
   which is also the only reason the boot wordmark reads as the
   wordmark rather than as a second copy of the one in the corner.
   Held with visibility as well as opacity so nothing in it can be
   tabbed to while it is invisible. The transition for this pair is
   declared in css/nav.css, which loads after this file.

   Only `is-booting`, deliberately. Once the sheet has been handed to
   the curtain, boot.js owns the bar with an autoAlpha tween and
   brings it back mid-wipe, with the room — leaving it on the class
   would hold it out until the very last beat of the timeline. */
html.is-booting .nav {
  opacity: 0;
  visibility: hidden;
}

/* Everything in the hero that is NOT the headline is held back until
   the curtain has gone, so the sheet stays a flat sheet: no drafting
   marks and no paper bar showing through it. */
html.is-booting .hero__bar,
html.is-booting .hero__eyebrow,
html.is-booting .draft-field,
html.boot-revealing .hero__bar,
html.boot-revealing .hero__eyebrow,
html.boot-revealing .draft-field { opacity: 0; }

/* ---- Reduced motion, and the no-JS path ----
   Without JS the .is-booting flag is never set, so #boot stays
   display:none and the page is simply the page. Under reduced motion
   the flag is not set either, but the rules below make it impossible
   for a stale class to lock the document. */
@media (prefers-reduced-motion: reduce) {
  #boot, html.is-booting #boot { display: none !important; }
  .hero__curtain { display: none !important; }
  html.is-booting, html.is-booting body { overflow: visible; height: auto; }
}
