/* ===========================================================================
   STRATA — core.css
   Radical restraint. No webfonts, no chrome, no decoration.
   The only motion that exists is the descent and what the descent implies.
   =========================================================================== */

:root {
  --paper:      #f2f0ec;
  --paper-deep: #e9e6e0;
  --ink:        #12110f;
  --ink-soft:   #4a4741;
  --ink-faint:  #8d887e;
  --rule:       #cdc8bf;
  --rule-hair:  #dedad3;
  --oxide:      #a8412a;

  --serif: "Helvetica Neue", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --mono:  ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --rail: 68px;
  --gut:  clamp(1.5rem, 4vw, 5rem);
  --measure: 34rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Warm dark, not black and not the near-neutral charcoal either — a middle
       ground. Pure #000 gave the halftone nothing to sit against; a cold grey
       lost the warmth the light palette has. This ground is brown-leaning so
       the plate's skin tones belong to it. */
    --paper:      #211e1b;
    --paper-deep: #2a2521;
    --ink:        #f2eee7;
    --ink-soft:   #bab3a9;
    --ink-faint:  #8a837a;
    --rule:       #4a443c;
    --rule-hair:  #363029;
    --oxide:      #e07850;
  }
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; }

::selection { background: var(--oxide); color: var(--paper); }

.mono {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 400;
}

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink); color: var(--paper);
  padding: 0.75rem 1rem; z-index: 100;
}
.skip:focus { left: 0; }

/* ------------------------------------------------------------- the gl stage
   Full-bleed and fixed: the plates are the ground the type stands on, not an
   illustration beside it. Everything else sits above on z-index. */

.gl-stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  /* the marks resolve in; nothing pops */
  opacity: 0;
  transition: opacity 900ms ease;
}
.gl-stage[data-ready="true"] { opacity: 1; }
.gl-canvas {
  display: block; width: 100%; height: 100%;
  /* The vector plate is now the surface, so the grid must not draw there too —
     it was rendering the old halftone portrait straight through the new one.
     --cover is 1 at the surface and 0 through the record, so the shaft resolves
     exactly as the plate leaves. */
  opacity: calc(1 - var(--cover));
}

/* The 2026 plate is full bleed and the face is placed right, so this is no
   longer a mask — it is a light wash that keeps the type column calm without
   erasing the backdrop field behind it. An opaque block here was hiding the
   full-screen ground entirely and left a hard vertical edge mid-canvas. */
:root { --cover: 1; --textcol: 0.5; }
.gl-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* --textcol is measured in gl.js: the real right edge of the copy as a
     fraction of the viewport. The wash has to reach past it, or the plate runs
     under the last few words on a narrow window. */
  background: linear-gradient(92deg,
      var(--paper) 0%,
      color-mix(in srgb, var(--paper) 66%, transparent) calc(var(--textcol, 0.5) * 74%),
      rgba(0,0,0,0) calc(var(--textcol, 0.5) * 100% + 8%));
  opacity: calc(var(--cover) * 0.92);
}
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .gl-stage::after {
    background: linear-gradient(92deg, var(--paper) 0%,
                rgba(0,0,0,0) calc(var(--textcol, 0.5) * 100% + 8%));
  }
}
/* the same protection for the 1999 plate at bedrock */
:root { --bed: 0; }
.gl-stage::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background: linear-gradient(96deg,
      var(--paper) 0%, var(--paper) 40%,
      rgba(0,0,0,0) 76%);
  opacity: calc(var(--bed) * 0.92);
}
@media (max-width: 900px) {
  /* nowhere to put a plate beside the type — veil the whole field instead */
  .gl-stage::after,
  .gl-stage::before {
    background: var(--paper);
  }
  .gl-stage::after  { opacity: calc(var(--cover) * 0.72); }
  .gl-stage::before { opacity: calc(var(--bed) * 0.72); }
}

/* No WebGL2 — show the photograph plainly rather than nothing at all. */
.gl-fallback { display: none; }
.gl-stage[data-fallback="true"] {
  opacity: 1;
  display: grid;
  place-items: center;
}
.gl-stage[data-fallback="true"] .gl-fallback {
  display: block;
  width: min(52vh, 60vw);
  height: auto;
  filter: grayscale(1) contrast(1.06);
  opacity: 0.14;
}
.gl-stage[data-gl="true"] .gl-fallback { display: none; }

/* ---------------------------------------------------------------- the plate --
   The 2026 portrait sits in the same place the halftone one did — pushed right,
   type keeping the left column — but it is a cut-out, so there is no backdrop
   field to stand the page on. It stands on the paper instead.

   --plate is driven from core.js, NOT from gl.js's --cover. gl.js returns early
   when WebGL2 is missing, which leaves --cover pinned at its default of 1; a
   plate hung on that would sit over the entire record on any machine without
   WebGL. core.js always runs. */
:root {
  --plate: 1;
  /* --head-h is the visible HEAD's target height — 57svh is the proportion a
     large display already showed once the old 860px cap bound. The svg element
     itself has to render TALLER than this: its own viewBox is the full artwork
     frame (head + every one of the 42 styles' decorative overlay + a margin
     verified, via getBBox() on every overlay group plus each blur filter's
     stdDeviation, to clear the single widest-reaching motif with room to
     spare), and the head occupies only 0.756 of that frame's height. Divide
     back up so the HEAD lands at --head-h regardless of how much frame
     surrounds it.

     getBBox() mattered here, not eyeballing a screenshot: measuring "visible
     content" by rendering into a viewBox and checking which pixels are
     non-transparent silently hides anything the viewBox itself was already
     clipping — it can never report content past whatever boundary you chose to
     test with. getBBox() reads the raw path geometry directly and is immune to
     that.

     --plate-w is the svg's own rendered width — the FULL frame, overlays
     included — so the type column starts clear of every treatment, not just
     clear of the tight head crop that used to clip them (that crop, and the
     partially-cut flower motif it produced, is what prompted this whole
     rework). */
  --head-h: min(57svh, 860px, calc(100svh - 11rem));
  --plate-h: calc(var(--head-h) / 0.756);
  --plate-w: calc(var(--plate-h) * 0.80142);
}
.plate {
  position: fixed;
  top: 50%;
  left: 0;
  right: 0;
  transform: translateY(-50%);
  z-index: 0;
  pointer-events: none;
  display: flex;
  align-items: center;
  /* MS 2026-08-18: the portrait moved to the LEFT and the type sits to its
     right, still left-aligned. The plate is fixed to the viewport while the
     copy lives inside .wrap (which is already inset by the gauge rail), so the
     plate clears the rail itself rather than inheriting that offset.

     It is centred on the viewport's true 50% — not on a top-anchored band —
     because .plate has no explicit height: translateY(-50%) centres it on
     WHATEVER height its content (.plate__art) turns out to be, on any screen.
     A band anchored at top:0 put the head's centre near half the band's own
     height instead of half the viewport, which on a display much taller than
     the 56rem band cap left the whole portrait sitting near the top third of
     the screen while the text (genuinely centred) sat 300px+ lower — the
     "misaligned" complaint. .surface below is centred the same true way, so
     the two halves now share one vertical centre by construction, not by
     coincidence of matching magic numbers. */
  justify-content: flex-start;
  /* MS 2026-08-18: nudged left off the full rail+gut inset (was the same
     inset .wrap uses for body text) to open more room before the text
     column starts — see .surface__body, which now accounts for this same
     reduced value rather than assuming the old full inset. */
  padding-left: calc(var(--rail) + var(--gut) * 0.6);
  opacity: var(--plate);
  will-change: opacity, transform;
}
.plate__art {
  height: var(--plate-h);
  width: auto;
  /* the morph rewrites 512 fills a frame and drives an svg filter; keep it off
     the main layer so a repaint here cannot reflow the page behind it */
  will-change: transform;
  /* --plate-w already IS this element's rendered width; the cap only guards
     the narrow end of the desktop range (just above the 900px breakpoint)
     where the full frame would otherwise crowd the type column */
  max-width: 60vw;
  /* seat it on the page rather than letting it hover as a sticker. resting the
     chin exactly on the viewport edge read as unresolved, so it is placed with
     air on both sides instead. */
  filter: drop-shadow(0 26px 34px rgba(18, 17, 15, 0.13));
  transition: opacity 280ms linear;
}
.plate__3d {
  position: absolute;
  top: 0;
  left: calc(var(--rail) + var(--gut) * 0.6);
  width: min(var(--plate-w), 60vw);
  height: var(--plate-h);
  opacity: 0;
  transition: opacity 280ms linear;
  filter: drop-shadow(0 26px 34px rgba(18, 17, 15, 0.18));
}
.plate.is-dimensional .plate__art { opacity: 0; visibility: hidden; }
/* MS 2026-09-12: on desktop the plate is a fixed layer at z 0 and .wrap sits over it at
   z 1, so the 3D head never received a press - only phones (plate in flow) could turn
   or tap it. Lift the plate while the head is up; the plate itself stays click-through
   and only the canvas takes the pointer, and not once the surface has faded away. */
.plate.is-dimensional { z-index: 2; }
.plate-gone .plate.is-dimensional .plate__3d { pointer-events: none; }
.plate.is-dimensional .plate__3d { opacity: 1; pointer-events: auto; cursor: grab; touch-action: none; }
.plate.is-dimensional .plate__3d:active { cursor: grabbing; }
.plate.is-dimensional .plate__3d:focus-visible { outline: 1px solid currentColor; outline-offset: -3px; }
@media (prefers-color-scheme: dark) {
  /* The ground is close to the HAIR in value, not the beard — the crown was
     dissolving into it. A whisper of light behind the silhouette separates it
     without reading as a glow. */
  .plate__art {
    filter: drop-shadow(0 0 46px rgba(242, 238, 231, 0.13))
            drop-shadow(0 22px 30px rgba(0, 0, 0, 0.45));
  }
}
@media (max-width: 900px) {
  /* There is no column to sit beside, so the two stop competing for the same
     band: the portrait takes the top of the screen (ABOVE) and the type starts
     beneath it. Running the lede across his face at half opacity read as a
     mistake rather than a layering.

     "Elastic, fills the full width, never cropped": .plate goes from `fixed`
     to `static`, which takes it OUT of viewport-overlay mode and INTO normal
     document flow — .wrap simply follows wherever it ends up. Combined with
     width:100% + height:auto on the image below (whose viewBox is the full
     artwork frame, overlays included — see :root), the browser derives the
     rendered height purely from the frame's own intrinsic aspect ratio, and
     reserves exactly that much real space automatically. Nothing is cut off at
     any width, because nothing constrains height independently of width; and
     nothing needs a guessed svh figure to clear it, because the layout isn't
     guessing — the image's true rendered size IS the space reserved for it. */
  .plate {
    position: relative;
    top: auto; left: auto; right: auto; transform: none;
    display: block;
    padding-left: 0;
  }
  .plate__art {
    display: block;
    width: 100%;
    height: auto;
    max-width: none;
    margin: 0;
    filter: drop-shadow(0 14px 22px rgba(18, 17, 15, 0.16));
  }
  .plate__3d {
    left: 0;
    width: 100%;
    height: auto;
    aspect-ratio: 674 / 841;
    filter: drop-shadow(0 14px 22px rgba(18, 17, 15, 0.18));
  }
}
@media (max-width: 900px) and (prefers-color-scheme: dark) {
  .plate__art {
    filter: drop-shadow(0 0 30px rgba(242, 238, 231, 0.12))
            drop-shadow(0 14px 22px rgba(0, 0, 0, 0.45));
  }
}
@media (prefers-reduced-motion: reduce) {
  .plate { transition: none; }
  .plate__art, .plate__3d { transition: none; }
}

.gauge, .wrap { position: relative; z-index: 1; }

/* The record has to stay readable over the shaft, but the two plates must not
   be veiled at all. gl.js drives --veil: 0 at the portrait, 1 through the
   record, 0 again at bedrock. */
:root { --veil: 0; }
.wrap::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--paper);
  opacity: calc(var(--veil) * 0.80);
}

/* ---------------------------------------------------------------- the gauge */

.gauge {
  position: fixed;
  inset: 0 auto 0 0;
  width: var(--rail);
  padding: clamp(1.5rem, 3vw, 2.5rem) 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  z-index: 20;
  border-right: 1px solid var(--rule-hair);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  user-select: none;
}
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .gauge { background: var(--paper); }
}

.gauge__cap,
.gauge__foot { font-family: var(--mono); font-size: 0.58rem; letter-spacing: 0.16em; color: var(--ink-faint); }

/* the core column: one hairline, one tick per stratum, one travelling marker */
.gauge__col {
  position: relative;
  flex: 1;
  width: 100%;
  min-height: 0;
}
.gauge__col::before {
  content: "";
  position: absolute;
  left: 50%; top: 0; bottom: 0;
  width: 1px;
  background: var(--rule);
  transform: translateX(-0.5px);
}

.tick {
  position: absolute;
  left: 50%;
  width: 22px;
  height: 12px;               /* generous hit target, hairline visual */
  margin: -6px 0 0 -11px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: block;
}
.tick::after {
  content: "";
  position: absolute;
  left: 3px; right: 3px; top: 50%;
  height: 1px;
  background: var(--rule);
  transition: background 140ms linear, left 140ms linear, right 140ms linear;
}
.tick:hover::after,
.tick:focus-visible::after { left: 0; right: 0; background: var(--ink-soft); }
.tick[aria-current="true"]::after { left: 0; right: 0; background: var(--ink); height: 2px; }
.tick[data-sealed="true"]::after { background: var(--oxide); opacity: 0.55; }
.tick:focus-visible { outline: 1px solid var(--oxide); outline-offset: 2px; }

/* On a touch device the tick is the ONLY way to step, so it has to be a real
   target. The hairline stays 1px — only the hit area grows. */
@media (pointer: coarse) {
  .tick { height: 24px; margin-top: -12px; width: 30px; margin-left: -15px; }
}

/* --- the bands, on the rail ---
   Depth on this page means orders of design, so the rail has to show them: a
   boundary where each layer begins, and the order's numeral at its midpoint.
   The column is 68px wide, so the numeral is the whole visible label and the
   accessible name carries the rest. */

.gauge__bound {
  position: absolute;
  left: 18%; right: 18%;
  height: 1px;
  background: var(--ink-soft);
  opacity: 0.55;
}

.gauge__band {
  position: absolute;
  left: 50%;
  z-index: 2;                  /* above the ticks, or a hairline strikes the numeral */
  transform: translate(-50%, -50%);
  padding: 0.35rem 0.2rem;
  border: 0;
  background: var(--paper);
  cursor: pointer;
  font-family: var(--mono);
  font-size: 0.5rem;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
  line-height: 1;
  white-space: nowrap;
}
.gauge__band:hover, .gauge__band:focus-visible { color: var(--oxide); }
.gauge__band:focus-visible { outline: 1px solid var(--oxide); outline-offset: 1px; }

/* the marker: the only continuously moving element on the page.
   It carries its own year, the way a depth gauge carries its reading — the
   number belongs to the position, not to a caption parked at the bottom. */
.gauge__marker {
  position: absolute;
  left: 50%;
  width: 34px; height: 1px;
  margin-left: -17px;
  /* No rule drawn. With the reading sitting on the needle, a line through it
     read as a strike-through — the year IS the marker now. */
  background: none;
  transition: transform 180ms cubic-bezier(.22,.61,.36,1);
  will-change: transform;
}
/* The reading sits ON the needle rather than parked beside it — that is what
   lets the rail be narrow. The paper chip keeps the line from striking through
   the digits while the needle still shows at either end. */
.gauge__marker #gaugeYear {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.04em;
  color: var(--oxide);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  line-height: 1;
}
@media (prefers-reduced-motion: reduce) { .gauge__marker { transition: none; } }

/* ------------------------------------------------------------------ content */

.wrap {
  margin-left: var(--rail);
  padding: 0 var(--gut);
}

/* --- surface --- */

.surface {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: clamp(4rem, 12vh, 9rem);
  max-width: 60rem;
}

/* The copy sits to the RIGHT of the portrait and stays left-aligned. Only the
   BODY moves — the rule and the two mono lines break back out and run the full
   width of the frame, under the head and the copy both, which is what pins the
   composition together instead of leaving the portrait floating beside a column.

   MS 2026-08-18: `.surface__body` and `.surface__foot` are now `position:fixed`,
   not `absolute` — they are PART OF THE SAME PINNED, FADING GROUP as `.plate`,
   not a separate scrolling element that happens to be centred on it. Before,
   the text scrolled away in normal flow the instant the reader moved, while the
   portrait stayed put and faded slowly over the next ~62% of a viewport height
   — a visible mismatch, and the fixed portrait could still show through
   whatever had scrolled up underneath it while it finished fading. Now all
   three share `opacity: var(--plate)`, the exact variable core.js already
   drives off scroll position, so head, text and rule move and fade as one
   unit and are fully gone (and `pointer-events:none`, so click-through) well
   before the record beneath needs to be interacted with. */
@media (min-width: 901px) {
  .surface { max-width: none; position: relative; }

  .surface__body {
    position: fixed;
    top: 50svh;
    transform: translateY(-50%);
    /* MS 2026-08-18: `.plate`'s own padding-left already insets the SVG by
       rail+gut before --plate-w even starts — this calc was missing that same
       inset, so text was landing ~125px further left than the portrait's real
       right edge, eating into what should have been clearance. That is what
       let the widest overlay motifs (soviet's sunburst rays, reaching further
       right than the head's own silhouette) run into the text. Restored the
       inset AND grown the gap and shrunk the portrait's own inset a little on
       top of it, so there is real, deliberate air between them, not just the
       bare minimum that happens not to clip. */
    left: calc(var(--rail) + var(--gut) * 0.6 + var(--plate-w) + clamp(2.5rem, 4.5vw, 6rem));
    right: var(--gut);
    max-width: 46rem;
    opacity: var(--plate);
    pointer-events: none;
    will-change: opacity;
  }
}

/* On mobile .plate goes `position: static` (see above), so it now occupies
   REAL space in normal document flow — .wrap simply follows it. No manual
   padding-top guess is needed to clear it; a small guessed svh figure here
   would have doubled the gap on top of the plate's own real height. This rule
   still has to sit AFTER the base .surface rule above: `padding-block` is a
   shorthand and resets both edges, so an earlier media query at equal
   specificity would lose to it. */
@media (max-width: 900px) {
  .surface { padding-block-start: clamp(1.5rem, 4svh, 2.5rem); }
}

.surface h1 {
  font-size: clamp(2.6rem, 6.4vw, 6.4rem);
  line-height: 0.9;
  letter-spacing: -0.045em;
  font-weight: 600;
  margin: 0 0 0.35em;
}
.surface h1 span {
  display: block;
  font-size: 0.2em;
  letter-spacing: 0.2em;
  font-weight: 400;
  color: var(--ink-faint);
  margin-top: 1.1em;
  font-family: var(--mono);
  text-transform: uppercase;
}

.lede {
  font-size: clamp(1.02rem, 1.7vw, 1.28rem);
  line-height: 1.45;
  max-width: 34rem;
  margin: 0 0 1.6rem;
  color: var(--ink);
  letter-spacing: -0.011em;
}
.lede + .lede { color: var(--ink-soft); }

.surface__foot {
  margin-top: clamp(2.5rem, 8vh, 5rem);
  border-top: 1px solid var(--rule);
  padding-top: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  max-width: 34rem;
  flex-wrap: wrap;
}

/* The rule and the two mono lines run the FULL width of the frame, under the
   head and the copy both. This has to sit after the rule above: `max-width` and
   `margin-top` are set there, and an earlier media query loses on source order
   at equal specificity — the same trap the mobile padding hit.

   MS 2026-08-18, corrected: a plain `margin-top` (what this was) still lives
   inside .surface's flex column alongside .surface__body, and ANY shared
   column still centres body+foot together as one block — so body's own centre
   stays offset from the true 50% by roughly half of whatever the foot adds,
   regardless of whether that "whatever" is an auto margin or a plain one. And
   independently: once .plate's frame grew to hold every style's decoration
   (not just the head), the plate became TALLER than the text column, so two
   things centred on the same point can still overlap — centring never implied
   clearance.

   Both problems go away by taking the foot out of the flex column entirely and
   anchoring it to a position that's provably clear: .plate's own bottom edge
   is `50svh + var(--plate-h)/2`, a real CSS length, not an estimate. Anchoring
   the foot below THAT — rather than below wherever .surface__body's text
   happened to end — guarantees no overlap by construction at any screen size,
   independent of how tall the plate or the text block happen to be. */
@media (min-width: 901px) {
  .surface__foot {
    /* fixed, not absolute, and fading with the same --plate variable as the
       portrait and .surface__body — see the note above .surface__body: this
       is one pinned group, not three independently-behaving pieces. Because
       the containing block changes from .surface's own (already rail+gut
       inset) padding box to the raw viewport, left/right have to restate that
       inset explicitly — .plate does the same thing via padding-left. */
    position: fixed;
    top: calc(50svh + var(--plate-h) / 2 + 1.5rem);
    /* matches .plate's own (reduced) inset so the rule's left edge still lines
       up with the portrait's left edge now that the portrait nudged left */
    left: calc(var(--rail) + var(--gut) * 0.6);
    right: var(--gut);
    max-width: none;
    margin-top: 0;
    opacity: var(--plate);
    pointer-events: none;
    will-change: opacity;
  }
}

/* --- the argument ---
   Five beats between the surface plate and the record. Wide measure, generous
   air: this is the part that is read standing up, before anyone descends. */

.argument {
  padding: clamp(2rem, 8vh, 5rem) 0 clamp(1rem, 4vh, 3rem);
  border-top: 1px solid var(--rule);
}

.beat {
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr);
  gap: clamp(1rem, 3vw, 2.5rem);
  padding: clamp(1.8rem, 5vh, 3.2rem) 0;
  border-bottom: 1px solid var(--rule-hair);
  align-items: baseline;
}

.beat__n {
  color: var(--oxide);
  padding-top: 0.55em;
}

.beat__body {
  font-size: clamp(1.06rem, 1.9vw, 1.42rem);
  line-height: 1.42;
  letter-spacing: -0.016em;
  color: var(--ink);
  margin: 0;
  max-width: 40rem;
}

/* The closing line of the transfer beat. Without an explicit column it would be
   auto-placed into the 11rem label track and read as a caption. Space above
   rather than a rule — the beats already carry bottom borders and a second
   hairline inside one reads as clutter. */
.beat__coda {
  grid-column: 2;
  margin-top: 1.4rem;
}

.beat__cite {
  grid-column: 2;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-faint);
  border-bottom: 1px solid transparent;
  justify-self: start;
  padding-bottom: 0.25rem;
  margin-top: 1.2rem;
}
.beat__cite:hover, .beat__cite:focus-visible { color: var(--oxide); border-bottom-color: var(--oxide); }

@media (max-width: 900px) {
  .beat { grid-template-columns: minmax(0, 1fr); gap: 0.9rem; }
  .beat__n { padding-top: 0; }
  .beat__coda { grid-column: 1; margin-top: 0.6rem; }
  .beat__cite { grid-column: 1; margin-top: 0.9rem; }
}

/* --- band heading ---
   The layer, and the argument the layer makes. Heavier than an era rule,
   because on this page depth means orders of design and this is where an
   order begins. */

.band {
  padding: clamp(4rem, 11vh, 8rem) 0 1.1rem;
  border-bottom: 2px solid var(--ink);
  margin-bottom: 0.2rem;
}
.band__name {
  margin: 0 0 0.7rem;
  display: flex;
  align-items: baseline;
  gap: 1rem;
  flex-wrap: wrap;
  font-weight: 600;
  letter-spacing: -0.03em;
  font-size: clamp(1.7rem, 4.2vw, 2.9rem);
  line-height: 1;
}
.band__order {
  color: var(--oxide);
  font-size: 0.66rem;          /* .mono sizing, held against the h2 font-size */
  letter-spacing: 0.16em;
  text-transform: uppercase;
  flex: 0 0 auto;
}
.band__note {
  margin: 0;
  max-width: 42rem;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink-soft);
  letter-spacing: -0.006em;
}

/* --- era heading --- */

.era {
  display: flex;
  align-items: baseline;
  gap: 1.25rem;
  flex-wrap: wrap;
  padding: clamp(3rem, 7vh, 5.5rem) 0 0.9rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 0.2rem;
}
/* An era directly under its band is the dating of that layer, not a new start —
   it should not carry the full inter-era gap. */
.band + .era { padding-top: clamp(1.2rem, 3vh, 2rem); }

.era__org {
  font-size: clamp(1rem, 1.5vw, 1.18rem);
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0;
}
.era__span { font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.14em; color: var(--oxide); }
.era__role {
  font-size: 0.78rem;
  color: var(--ink-faint);
  margin-left: auto;
  text-align: right;
  max-width: 30rem;
  line-height: 1.35;
}

/* --- a stratum ---
   Compression is the argument: --c runs 0 at the surface to 1 at bedrock.
   Deeper strata are physically tighter — less air, smaller type, heavier rule. */

.stratum {
  --c: 0;
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(0.75rem, 2.5vw, 2.5rem);
  align-items: baseline;
  padding-block: calc((2.45rem - (1.72rem * var(--c))));
  border-bottom: 1px solid var(--rule-hair);
  text-decoration: none;
  color: inherit;
  position: relative;
}

a.stratum::before {
  /* the reveal: a hairline that fills from the left on hover. */
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 260ms cubic-bezier(.22,.61,.36,1);
}
a.stratum:hover::before,
a.stratum:focus-visible::before { transform: scaleX(1); }
a.stratum:focus-visible { outline: none; }
a.stratum:focus-visible .stratum__title { text-decoration: underline; text-underline-offset: 0.18em; }

@media (prefers-reduced-motion: reduce) {
  a.stratum::before { transition: none; }
}

.stratum__year {
  font-family: var(--mono);
  font-size: calc(0.82rem - (0.12rem * var(--c)));
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  padding-top: 0.32em;
}
a.stratum:hover .stratum__year { color: var(--oxide); }

.stratum__title {
  font-size: calc(2.05rem - (0.86rem * var(--c)));
  line-height: 1.06;
  letter-spacing: calc(-0.03em + (0.012em * var(--c)));
  font-weight: 500;
  margin: 0 0 0.34em;
  display: block;
}

.stratum__kind {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
  display: block;
}

.stratum__summary {
  font-size: calc(0.92rem - (0.07rem * var(--c)));
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 0;
  letter-spacing: -0.006em;
}

.stratum__state {
  font-family: var(--mono);
  font-size: 0.56rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  display: inline-block;
  margin-top: 0.7rem;
  color: var(--ink-faint);
}
a.stratum .stratum__state { color: var(--ink); }
a.stratum:hover .stratum__state { color: var(--oxide); }

/* sealed — visible, labelled, locked. The newest work is the closed part. */
.stratum--sealed { cursor: default; }
.stratum--sealed .stratum__title { color: var(--ink-soft); }
.stratum--sealed .stratum__state { color: var(--oxide); }
.stratum--sealed .stratum__year::after {
  content: " ▪";
  color: var(--oxide);
}
.stratum--sealed::after {
  /* hatch: the seal, drawn not imaged */
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px; height: 1px;
  background: repeating-linear-gradient(90deg,
    var(--oxide) 0 5px, transparent 5px 10px);
  opacity: 0.5;
}

.stratum--record .stratum__title { color: var(--ink-soft); }

/* --- bedrock --- */

.bedrock {
  /* room for the 1999 plate to reassemble before you reach the contact line */
  min-height: 96svh;
  padding: clamp(4rem, 12vh, 8rem) 0 clamp(3rem, 8vh, 6rem);
  border-top: 2px solid var(--ink);
  margin-top: clamp(3rem, 8vh, 6rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.bedrock__plate {
  color: var(--oxide);
  margin: 0 0 1.6rem;
  max-width: 34rem;
  line-height: 1.5;
}
.bedrock h2 {
  font-size: clamp(1.6rem, 4vw, 2.6rem);
  letter-spacing: -0.035em;
  font-weight: 600;
  margin: 0 0 0.6rem;
  line-height: 1;
}
.bedrock p { max-width: 34rem; color: var(--ink-soft); margin: 0 0 1.6rem; }
.bedrock .contact, .bedrock .bedrock__awards {
  max-width: 34rem;
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0 0 1.8rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule);
}

.colophon { max-width: 40rem; }

.contact {
  display: flex;
  flex-wrap: wrap;
  gap: 0 2.5rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule);
}
.contact a {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.85rem 0;
  border-bottom: 1px solid transparent;
}
.contact a:hover, .contact a:focus-visible { border-bottom-color: var(--oxide); color: var(--oxide); }

.bedrock__awards {
  max-width: 34rem;
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0 0 1.8rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule);
}

.colophon {
  margin-top: clamp(3rem, 8vh, 5rem);
  padding-top: 1rem;
  border-top: 1px solid var(--rule-hair);
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  color: var(--ink-faint);
  text-transform: uppercase;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding-bottom: 3rem;
}

/* ------------------------------------------------------------- narrow media */

@media (max-width: 1100px) {
  /* Two columns: the year keeps its gutter, title and summary stack beneath it. */
  .stratum { grid-template-columns: 5rem minmax(0, 1fr); row-gap: 0.55rem; }
  .stratum__aside { grid-column: 2; }
  .era__role { margin-left: 0; text-align: left; max-width: none; flex-basis: 100%; }
}

@media (max-width: 640px) {
  :root { --rail: 46px; }
  .gauge__cap, .gauge__foot { display: none; }
  .gauge__marker #gaugeYear { font-size: 0.52rem; }
  .stratum { grid-template-columns: 3.4rem minmax(0, 1fr); }
  .surface h1 { letter-spacing: -0.035em; }
}

/* ------------------------------------------------------------ teaching seam
   A world graticule, not an atlas: markers are plotted from real coordinates
   (x = (lon+180)/360, y = (90-lat)/180) so the placement is verifiable. */

.edu { padding-bottom: clamp(3rem, 8vh, 5rem); }
.edu .lede { max-width: 40rem; margin-top: 1.6rem; }

.edu__grid2 {
  display: grid;
  grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
}

.edu__map { display: block; width: 100%; height: auto; overflow: visible; }

.edu__grid line { stroke: var(--rule-hair); stroke-width: 1; vector-effect: non-scaling-stroke; }
.edu__grid line.edu__axis { stroke: var(--rule); }

.edu__arc {
  fill: none;
  stroke: var(--oxide);
  stroke-width: 1.2;
  stroke-dasharray: 3 4;
  vector-effect: non-scaling-stroke;
  opacity: 0.85;
}

.edu__mark { cursor: pointer; }
.edu__mark:focus-visible { outline: none; }
.edu__hit { fill: transparent; }
.edu__dot { fill: var(--ink); transition: fill 140ms linear, r 140ms linear; }
.edu__ring {
  fill: none; stroke: var(--ink); stroke-width: 1;
  vector-effect: non-scaling-stroke; opacity: 0.45;
}
.edu__label {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  fill: var(--ink-faint);
  transition: fill 140ms linear;
}
.edu__mark:hover .edu__dot,
.edu__mark.is-on .edu__dot { fill: var(--oxide); }
.edu__mark:hover .edu__label,
.edu__mark.is-on .edu__label,
.edu__mark:focus-visible .edu__label { fill: var(--ink); }
.edu__mark.is-on .edu__ring { stroke: var(--oxide); opacity: 1; }
.edu__mark:focus-visible .edu__dot { fill: var(--oxide); }

.edu__panel { border-top: 1px solid var(--rule); padding-top: 1rem; min-height: 16rem; }
.edu__where { font-size: 1.02rem; margin: 0 0 0.7rem; letter-spacing: -0.01em; }
.edu__lived { color: var(--oxide); }
.edu__note { font-size: 0.9rem; line-height: 1.5; color: var(--ink-soft); margin: 0 0 1rem; max-width: 26rem; }

.edu__list { list-style: none; margin: 0; padding: 0; }
.edu__list li {
  display: flex; gap: 0.85rem; align-items: flex-start;
  padding: 0.7rem 0; border-bottom: 1px solid var(--rule-hair);
}
.edu__logo {
  width: 30px; height: 30px; flex: 0 0 30px;
  object-fit: contain; margin-top: 0.1rem;
  filter: grayscale(1); opacity: 0.75;
}
.edu__logo--none { border: 1px solid var(--rule-hair); }
.edu__inst { display: flex; flex-direction: column; gap: 0.18rem; }
.edu__inst b { font-weight: 500; font-size: 0.92rem; line-height: 1.3; }
.edu__level, .edu__courses {
  font-family: var(--mono); font-size: 0.56rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint);
}
.edu__courses { color: var(--ink-soft); letter-spacing: 0.08em; text-transform: none; font-size: 0.7rem; }


.edu__subjects {
  margin-top: clamp(2rem, 5vh, 3rem);
  padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: 6rem minmax(0, 1fr);
  gap: 1.2rem;
}
.edu__subject {
  display: inline-block;
  font-size: 0.85rem;
  color: var(--ink-soft);
  margin: 0 1.4rem 0.5rem 0;
}

@media (max-width: 900px) {
  .edu__grid2 { grid-template-columns: minmax(0, 1fr); }
  .edu__panel { min-height: 0; }
  .edu__subjects { grid-template-columns: minmax(0, 1fr); gap: 0.6rem; }
  .edu__label { font-size: 15px; }
}

/* --------------------------------------------------------------- coastlines */
.edu__land path {
  fill: none;                      /* land as outline, like everything else here */
  stroke: var(--rule);
  stroke-width: 1;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.edu__leader { stroke: var(--rule); stroke-width: 1; vector-effect: non-scaling-stroke; }
.edu__home { fill: none; stroke: var(--oxide); stroke-width: 1.4; vector-effect: non-scaling-stroke; }
.edu__place + .edu__place { margin-top: 1.4rem; padding-top: 1.2rem; border-top: 1px solid var(--rule); }
.edu__kinds { display: inline-flex; gap: 0.4rem; margin-left: 0.6rem; }
.edu__kind {
  font-family: var(--mono); font-size: 0.5rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-faint);
  border: 1px solid var(--rule); padding: 0.15em 0.4em;
}
.edu__kind--home, .edu__kind--taught { color: var(--oxide); border-color: var(--oxide); }
.edu__when { margin: 0 0 0.6rem; }

/* ------------------------------------------------------------------- flash */

.flash { margin: 1.8rem 0 2.4rem; max-width: 72rem; }
.flash__stage {
  position: relative;
  width: 100%;
  background: var(--paper-deep);
  border: 1px solid var(--rule-hair);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.flash__run {
  display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
  background: none; border: 0; cursor: pointer; color: inherit;
  font-family: var(--mono); padding: 2rem;
}
.flash__play { font-size: 1.6rem; color: var(--oxide); line-height: 1; }
.flash__runlabel { font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase; }
.flash__note { font-size: 0.56rem; letter-spacing: 0.1em; color: var(--ink-faint); max-width: 24rem; text-align: center; line-height: 1.5; }
.flash__run:hover .flash__runlabel, .flash__run:focus-visible .flash__runlabel { color: var(--oxide); }
.flash__player { width: 100%; height: 100%; display: block; }
.flash__stage.is-running { background: #000; }

/* The Saint Xavier mark was supplied white-on-black; every other logo sits on
   white. Invert it on paper so the row reads as one set, leave it alone on ink. */
.edu__logo--inv { filter: grayscale(1) invert(1); }
@media (prefers-color-scheme: dark) { .edu__logo--inv { filter: grayscale(1); } }

/* Marker labels sit directly beside their dot and appear only for the marker in
   focus. Ten markers — four of them clustered over North America — cannot all
   carry a permanent label without being pushed so far from their dot that they
   read as plotted in the wrong place. The dot is the data; the panel names it. */
.edu__label { opacity: 0; transition: opacity 120ms linear; }
.edu__mark:hover .edu__label,
.edu__mark:focus-visible .edu__label,
.edu__mark.is-on .edu__label { opacity: 1; }

.edu__mark[aria-pressed="true"] .edu__dot { fill: var(--oxide); }

/* Default panel: an index of places. Expanding every institution at once made
   the list a screen and a half long, which buried everything after Toronto. */
.edu__index { list-style: none; margin: 0; padding: 0; }
.edu__index li {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem; padding: 0.6rem 0;
  border-bottom: 1px solid var(--rule-hair);
  cursor: pointer;
}
.edu__index li:hover .edu__ixcity,
.edu__index li:focus-visible .edu__ixcity { color: var(--oxide); }
.edu__index li:focus-visible { outline: 1px solid var(--oxide); outline-offset: 3px; }
.edu__ixcity { font-size: 0.95rem; letter-spacing: -0.01em; }
.edu__ixcity b { font-weight: 600; }
.edu__ixmeta {
  font-family: var(--mono); font-size: 0.54rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-faint); white-space: nowrap;
}
.edu__mark.is-hi .edu__dot { fill: var(--oxide); }
.edu__mark.is-hi .edu__label { opacity: 1; }
