/* The scroll-scrubbed founder sequence.
 *
 * NO BAND, NO BOX. The section used to be a full-bleed near-black panel, which made the
 * figure easy to light but announced itself as a separate thing bolted onto the page. It
 * now sits directly on whatever background the site has, in both themes, with no border
 * and no container — the figure travels across the page rather than performing inside a
 * rectangle.
 *
 * THAT MAKES THE RIM LIGHT LOAD-BEARING RATHER THAN DECORATIVE, and the measurement is the
 * argument: a white lab coat against the light theme's white page is 1.04:1. It is not
 * subtle, it is invisible. The blue rim is what draws the silhouette, so it is stronger and
 * tighter on light than on dark, and it uses the site's own accent — 7.24:1 on white —
 * rather than the pale glow that worked against black and measures 2.45:1 here.
 *
 * SO THE AURA IS THEME-AWARE, AND THE VALUES LIVE HERE. coat.js reads all four at start-up
 * and again whenever the theme changes; none of them are in the script.
 */
.coat { display: none; }
.coat[data-coat-ready="1"] { display: block; }

.coat {
  position: relative;
  background: transparent;

  /* LIGHT THEME — a tight, strong rim, because the page is white and the coat is white.
     --coat-aura is --accent-solid, the blue already used for the nav and every button. */
  --coat-aura: #2743C9;
  --coat-halo-blur: 22;      /* px, read as a number by the script */
  --coat-halo-alpha: 0.55;   /* the rim has to carry the silhouette on its own */
  --coat-dust-alpha: 0.42;   /* dust on white needs to be darker and sparser to read */
  --coat-spill: 0.10;        /* barely any: white fabric tints far too easily */
}

/* DARK THEME — the page is nearly black, the coat reads on its own, and the rim can go
   back to being atmosphere rather than an outline: wider, softer, paler. */
:root[data-theme="dark"] .coat {
  --coat-aura: #7C9CFF;
  --coat-halo-blur: 46;
  --coat-halo-alpha: 0.34;
  --coat-dust-alpha: 1;
  --coat-spill: 0.26;
}

/* ---- the runway ----
   THE SECTION DECLARES ITS OWN HEIGHT, and that is a deliberate reversal.
   It used to take its height from the copy: three blocks of 104vh each, stacked in flow,
   and the figure's position was a function of how far through that stack you were. Which
   meant the pacing was a side effect of how long a paragraph happened to be — edit a
   sentence and the pauses move.

   Now the copy is positioned absolutely and scheduled by coat.js on explicit scroll
   windows, so it contributes no height at all and the runway has to be stated. That is the
   whole trade, and it is worth it: the holds are the point of the section.

   580vh, less one screen of pinning, leaves 480vh of travel: six phases share it, and each
   of the three pauses gets roughly a screen of scrolling to itself. It was 640vh, which
   gave the closing pause 157vh — nearly twice either of the others, and he complained that
   the section sat there rather than moving on. The holds are now even, and the last one
   ends promptly so the page can hand over to the next section. This number is the one dial
   for the whole thing: everything else is a fraction of it. */
.coat { min-height: 580vh; }

/* ---- the pinned layer ----
   ONE STICKY BOX WITH NO MARGINS, holding the figure and the copy as two absolute layers
   inside it. That is not tidiness, it is the fix for a real bug.

   IT WAS TWO SIBLING STICKY LAYERS OVERLAPPED BY margin-bottom: -100vh, AND THAT MARGIN
   OVERRAN THE SECTION BY A FULL SCREEN. A sticky box is constrained so its MARGIN box
   stays inside its containing block — and a -100vh bottom margin on a 100vh box makes that
   margin box zero-height, so the browser kept it pinned for another 900px after the
   section had ended. Measured at 1440x900: at 800px past the foot of the runway the stage
   was still sitting at viewport top while the next section had scrolled up to 100px, which
   is exactly how the experience timeline ended up printed across the figure's chest.

   A single wrapper with an honest 100vh margin box releases at precisely the end of the
   runway, so the whole tableau scrolls away together. It also means the layer order is
   plain z-index between two siblings rather than a negative margin nobody can read. */
.coat-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  z-index: 0;
}

/* The figure. Full width, so the canvas can carry him anywhere across the page. The travel
   is drawn, not laid out: moving a canvas element would move its backing store and force a
   repaint of the whole stage on every scroll frame. */
.coat-stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.coat-canvas { display: block; width: 100%; height: 100%; background: transparent; }

/* ---- the copy ----
   The layer over the stage, holding all three blocks at once. Only one is ever visible:
   coat.js writes each block's opacity from the scroll position, on windows that sit
   strictly inside the phases where the figure is standing still.

   OPACITY, NOT display OR visibility, and the reason is a screen reader. A block that is
   display:none for four fifths of the section is a block that is missing from the page for
   anyone not looking at it. At opacity 0 all three stages stay in the accessibility tree
   and in the browser's find, in the order they are meant to be read.

   pointer-events off at the layer, back on per block while it is legible — otherwise
   dragging across the section selects three paragraphs nobody can see. */
.coat-text {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* THE DEPTH THE REVOLVE IS SEEN THROUGH. Without a perspective on the container, the
     rotateY on each block is an orthographic squash — the same flat non-effect that made
     the falling figure look like a cutout. The origin sits on the figure rather than in
     the middle of the box, so the two columns turn about HIM and the carousel has a
     centre worth going round. */
  perspective: 1100px;
  perspective-origin: 50% 45%;
  transform-style: preserve-3d;
}

/* POSITIONED IN VIEWPORT UNITS, NOT INSIDE .wrap, because the figure is.
   The copy used to live in the site's centred column while the figure's position was a
   fraction of the full-bleed canvas. On a 2560px monitor those are two different
   coordinate systems: the column's right edge sits at about 76% of the glass and the
   figure stands at 72% of it, so the words landed on his shoulder on exactly the widest
   screens. Both now measure from the same edge. */
.coat-beat {
  position: absolute;
  top: 50%;
  /* The resting transform. coat.js overwrites this every scroll frame with the same
     translate plus the revolve; this is what a reader sees before the script runs. */
  transform: translateY(-50%);
  backface-visibility: hidden;
  /* Narrowed when he moved to the centre: he now has a column on BOTH sides of him
     rather than one, so each gets less. */
  width: min(24vw, 340px);
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}
/* The side he is NOT on. Stamped by coat.js from its own table of stations rather than
   chosen by nth-child: he ends the section back where he started, so the first and last
   blocks share a side, and counting elements would put the closing paragraph on top of
   him. */
.coat-beat[data-side="left"]  { left: max(20px, 3.5vw);  text-align: left; }
.coat-beat[data-side="right"] { right: max(20px, 3.5vw); text-align: right; }

.coat-beat .k {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: 14px;
}
/* The stage's short name, after its number and quieter than it, on the same line. A second
   eyebrow underneath would put three labels above one headline. */
.coat-beat .k i { font-style: normal; color: var(--fg-muted); }
.coat-beat .k i::before { content: " · "; }

.coat-beat h2 {
  font-family: var(--font-display);
  font-size: clamp(24px, 3.1vw, 42px);
  line-height: 1.14;
  letter-spacing: -.02em;
  text-wrap: balance;
  margin: 0;
  /* Stated, not inherited: styles.css gives every h2 its own colour, and an element's own
     rule beats anything it would otherwise inherit. */
  color: var(--fg);
}
.coat-beat p {
  margin: 14px 0 0;
  color: var(--fg-muted);
  font-size: clamp(14px, 1.15vw, 16.5px);
  line-height: 1.65;
}

/* RULED, NOT BULLETED. Half of these lists sit against the right margin, and a bulleted
   list that is right-aligned leaves its markers stranded in the middle of the column. A
   hairline above each line separates them just as well and reads identically on either
   side. */
.coat-points {
  list-style: none;
  margin: 22px 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.coat-points li {
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--fg-muted);
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

/* A tall, narrow desktop window is the one shape where the two columns can still meet. The
   figure is fitted to the stage HEIGHT, so a 1000x1200 window draws him roughly three
   quarters of the page wide and he reaches across into the copy. Pull the copy in and let
   the headline shrink rather than let them touch. */
@media (min-width: 901px) and (max-aspect-ratio: 1/1) {
  .coat-beat { width: min(27vw, 340px); }
  .coat-beat h2 { font-size: clamp(20px, 2.4vw, 30px); }
}

/* A faint pool of light under the figure, following it across. Positioned by the script
   through two custom properties rather than by CSS, so it cannot drift from the figure. */
.coat-glow {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(38% 34% at calc(var(--coat-x, 0.5) * 100%) 46%,
    color-mix(in srgb, var(--coat-aura) 16%, transparent) 0%, transparent 72%);
  opacity: calc(0.35 + var(--coat-p, 0) * 0.4);
}

/* The one honest piece of chrome on a pinned section: without it a reader who cannot tell
   the page is still moving assumes it has hung. It matters more than it did — two thirds
   of this section is now spent deliberately not moving. */
.coat-rail {
  position: absolute;
  left: 8%; right: 8%;
  bottom: clamp(16px, 3.4vh, 34px);
  height: 2px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
}
.coat-rail i {
  display: block;
  height: 100%;
  width: calc(var(--coat-p, 0) * 100%);
  background: var(--coat-aura);
}

/* ---- the rider ----
   THE ONE THING ON THIS SITE THAT IS DELIBERATELY IN FRONT OF EVERYTHING. When the coat
   section lets go, the figure shrinks, drops to the middle and takes over the glowing head
   that rides down the experience timeline. A fixed layer is the only way to do that: the
   sticky stage is trapped inside its own section, and the timeline is two sections further
   down the page.

   Z-INDEX 90 IS A CHOSEN NUMBER, not a big one. Above the sticky site header at 60, so he
   genuinely passes in front of the site the way he was asked to. Below the search overlay
   at 200 and the modals at 300, so he can never land on top of something a reader is
   trying to use. And pointer-events are off, so the timeline underneath stays exactly as
   clickable as it was — a full-screen fixed layer that swallowed clicks would break every
   card he passes. */
.coat-rider {
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  display: none;
}
.coat-rider[data-on="1"] { display: block; }
/* IN FRONT FOR THE FALL, BEHIND THE WORDS IN THE SECTION. The same fixed layer serves
   both, because it is the same man: while he is standing in the section the copy belongs
   over him, and once he comes loose and falls he belongs over the whole site. z-index 0
   still clears the section canvas beneath him, which carries the smoke and the dust. */
.coat-rider[data-front="0"] { z-index: 0; }
/* BOTH CANVASES OCCUPY THE WHOLE LAYER, STACKED. The 2D one carries the pool of light
   under him (and the sprite, when there is no WebGL); the WebGL one carries the model over
   it. Left in flow they would sit one under the other and the glow would land a screen
   below the figure it belongs to. */
.coat-rider canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

/* HE REPLACES THE HEAD, NOT THE LINE. The glowing dot that rode the end of the spine is
   exactly the job he has taken over, so it goes; the drawn line stays, because that is now
   the trail he leaves behind him as he falls. Hidden by opacity rather than display so the
   line keeps its own geometry — the head is positioned from the spine bottom, and removing
   it from layout would move nothing but is one less thing to reason about. */
.fp-timeline[data-ridden="1"] .fp-spine::after { opacity: 0; }

/* Unpinned layouts get none of it: on a phone the coat section does not pin at all, so
   there is no moment of letting go for him to be handed over at. The blue head keeps its
   job there. */
@media (max-width: 900px), (prefers-reduced-motion: reduce) {
  .coat-rider { display: none !important; }
}

/* THE LENS BELOW TELLS THE SAME THREE STAGES, AND ONE OF THEM HAS TO GO.
   Both are rendered from the same array in founder-data.js, and both were on the page at
   once — the figure crossed straight down into a card repeating what he had just said.
   The lens is the fallback, not the duplicate: this section is display:none until a frame
   has actually decoded, so a deploy without the renders, a slow connection or a browser
   that will not take WebP still gets the content, laid out conventionally. The moment the
   figure is live, the fallback is what is redundant. */
.coat[data-coat-ready="1"] ~ .fp-lens { display: none; }

/* Touch and small screens: no travel, no pinning, no scheduling. A figure crossing a 390px
   page covers about two of his own shoulder widths, and a pinned stage fights the address
   bar resizing as you scroll. The figure sits above the copy, the blocks stack full width,
   and all three are on screen at once — coat.js checks this same breakpoint and stops
   writing opacity, so the stylesheet's values are the last word. */
@media (max-width: 900px) {
  .coat { min-height: 0; }
  .coat-pin { position: static; height: auto; }
  .coat-stage { position: static; height: min(62vh, 440px); margin-bottom: 18px; }
  .coat-text { position: static; padding: 0 20px; pointer-events: auto; }
  .coat-beat[data-side] {
    position: static;
    transform: none;
    width: auto;
    left: auto; right: auto;
    text-align: left;
    opacity: 1;
    pointer-events: auto;
    margin: 0 0 32px;
  }
  .coat-beat h2 { font-size: clamp(22px, 6.2vw, 30px); }
  .coat-rail { display: none; }
}

/* Reduced motion: one frame, no travel, every line readable at once. */
@media (prefers-reduced-motion: reduce) {
  .coat { min-height: 0; }
  .coat-pin { position: static; height: auto; }
  .coat-stage { position: static; height: min(60vh, 420px); margin-bottom: 18px; }
  .coat-text { position: static; pointer-events: auto; }
  .coat-beat[data-side] {
    position: static;
    transform: none;
    width: auto;
    left: auto; right: auto;
    text-align: left;
    opacity: 1;
    pointer-events: auto;
    margin: 0 0 32px;
  }
  .coat-rail { display: none; }
}
