/* ============ V22 ============
   Deep-navy drafting room, night shift. One red does every energetic job:
   thread, figure linework, chart fills, active states, tree connectors.
   Dark is primary; light is the same drawing printed on warm paper. */

@font-face{font-family:"Archivo";src:url("fonts/Archivo.woff2") format("woff2");font-weight:100 900;font-stretch:62% 125%;font-style:normal;font-display:swap}
@font-face{font-family:"Source Serif 4";src:url("fonts/SourceSerif4.woff2") format("woff2");font-weight:200 900;font-style:normal;font-display:swap}
@font-face{font-family:"Source Serif 4";src:url("fonts/SourceSerif4-Italic.woff2") format("woff2");font-weight:200 900;font-style:italic;font-display:swap}
@font-face{font-family:"IBM Plex Mono";src:url("fonts/PlexMono.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"IBM Plex Mono";src:url("fonts/PlexMono-Italic.woff2") format("woff2");font-weight:400;font-style:italic;font-display:swap}
@font-face{font-family:"IBM Plex Mono";src:url("fonts/PlexMono-Medium.woff2") format("woff2");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:"IBM Plex Mono";src:url("fonts/PlexMono-SemiBold.woff2") format("woff2");font-weight:600;font-style:normal;font-display:swap}

:root{
  --font-d:"Archivo",ui-sans-serif,"Helvetica Neue",Arial,sans-serif;
  --font-s:"Source Serif 4",Iowan Old Style,Georgia,serif;
  --font-m:"IBM Plex Mono",ui-monospace,"SF Mono",Menlo,monospace;
  --rail:clamp(22px,5.4vw,72px);
  --gutter:clamp(20px,5vw,56px);
  --maxw:1060px;
  --ease-draw:cubic-bezier(.22,1,.36,1);
  --ease-snap:cubic-bezier(.33,1,.68,1);
  --ease-pop:cubic-bezier(.34,1.45,.64,1);
}
html[data-theme="dark"]{
  --bg:#0D2652; --bg2:#102D5F; --plate:#15366B; --raised:#1A427B;
  --grid:rgba(93,158,239,.12); --grid-major:rgba(237,28,36,.18);
  --ink:#F2F6FF; --muted:#C0CEE5; --faint:#93A9CD;
  --line:rgba(242,246,255,.20); --line-soft:rgba(242,246,255,.10);
  --red:#ED1C24; --red-hi:#FF555A; --red-soft:rgba(237,28,36,.24);
  --blue:#62A8FF; --blue-soft:rgba(66,139,231,.22);
  --shadow:0 1px 2px rgba(2,12,31,.48),0 16px 44px rgba(2,12,31,.35);
  --scrim:rgba(13,38,82,.88);
  color-scheme:dark;
}
html[data-theme="light"]{
  --bg:#F7F5EF; --bg2:#F2EFE7; --plate:#FFFFFF; --raised:#FFFFFF;
  --grid:rgba(29,78,137,.07); --grid-major:rgba(211,26,32,.12);
  --ink:#102A57; --muted:#405779; --faint:#5C7192;
  --line:rgba(19,26,40,.17); --line-soft:rgba(19,26,40,.08);
  --red:#D31A20; --red-hi:#C4161C; --red-soft:rgba(211,26,32,.09);
  --blue:#1D4E89; --blue-soft:rgba(29,78,137,.08);
  /* navy-tinted, not neutral grey: the sheet is warm, the ink is navy, so the
     shadow it casts should belong to the same drawing */
  --shadow:0 1px 2px rgba(16,42,87,.07),0 12px 34px rgba(16,42,87,.10);
  --scrim:rgba(247,245,239,.86);
  color-scheme:light;
}
*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--font-s);font-size:1.0525rem;line-height:1.7;
  color:var(--ink);background:var(--bg);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
.gridpaper{
  position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(1100px 760px at 76% -12%, var(--blue-soft), transparent 62%),
    repeating-linear-gradient(to right, var(--grid) 0 1px, transparent 1px 28px),
    repeating-linear-gradient(to bottom, var(--grid) 0 1px, transparent 1px 28px),
    repeating-linear-gradient(to right, var(--grid-major) 0 1px, transparent 1px 140px),
    repeating-linear-gradient(to bottom, var(--grid-major) 0 1px, transparent 1px 140px),
    linear-gradient(var(--bg),var(--bg2));
}
::selection{background:var(--red);color:#fff}
a{color:var(--red-hi);text-decoration-color:color-mix(in srgb,var(--red) 40%,transparent);text-underline-offset:3px}
a:hover{text-decoration-color:var(--red-hi)}
img{max-width:100%;height:auto;display:block}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
.mono{font-family:var(--font-m)}
.skip{position:absolute;left:-9999px;top:0;z-index:200;background:var(--ink);color:var(--bg);padding:.6rem 1rem;font-family:var(--font-m);font-size:.8rem}
.skip:focus{left:8px;top:8px}
:focus-visible{outline:2px solid var(--red-hi);outline-offset:3px;border-radius:2px}

/* ---------- header ---------- */
.top{
  position:fixed;top:0;left:0;right:0;z-index:60;
  display:flex;align-items:center;gap:1rem;
  padding:.55rem var(--gutter);
  background:var(--scrim);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--line-soft);
}
.brand{display:flex;align-items:center;gap:.6rem;text-decoration:none;color:var(--ink)}
.brand b{font-family:var(--font-m);font-weight:600;font-size:.78rem;letter-spacing:.14em}
.brand span{font-family:var(--font-m);font-size:.66rem;color:var(--faint);letter-spacing:.14em}
.secnav{display:flex;gap:.25rem;margin-left:auto;position:relative;align-items:center}
.secnav a{
  font-family:var(--font-m);font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;padding:.45rem .8rem;border-radius:5px;
  border:1px solid transparent;transition:color .2s var(--ease-snap),border-color .2s var(--ease-snap);
}
.secnav a:hover{color:var(--ink);border-color:var(--line-soft)}
.secnav a[aria-current="page"]{color:var(--red-hi);border-color:color-mix(in srgb,var(--red) 42%,transparent)}
html[data-theme="light"] .secnav a[aria-current="page"]{color:var(--red-hi)}
.nav-pulse{
  position:absolute;bottom:-1px;height:2px;background:var(--red);border-radius:1px;
  transition:left .34s var(--ease-draw),width .34s var(--ease-draw);pointer-events:none;
}
#themeBtn{display:grid;place-items:center;width:34px;height:34px;border:1px solid var(--line);border-radius:50%;transition:border-color .2s}
/* Toggle is hidden for now, not removed: the theme itself still works end to end.
   Light mode is reachable via localStorage.setItem("v22-theme","light") + reload.
   Delete this one rule to put the control back in the header. */
#themeBtn{display:none}
#themeBtn:hover{border-color:var(--ink)}
#themeBtn svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2}
html[data-theme="light"] .sun{display:none} html[data-theme="dark"] .moon{display:none}
.progress{position:absolute;left:0;bottom:-1px;height:2px;width:100%;background:var(--red);transform-origin:0 50%;transform:scaleX(0);opacity:.85}

/* ---------- layout ---------- */
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter)}
#view{min-height:120svh}
main{padding-top:3.4rem}
.view-out{opacity:0;transform:translateY(10px);transition:opacity .26s var(--ease-snap),transform .26s var(--ease-snap)}
.view-in{animation:viewIn .4s var(--ease-draw)}
@keyframes viewIn{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}

/* ---------- hero ---------- */
/* The photograph is the field: it runs nearly the full width and the whole
   height, so `cover` barely has to crop and the swap station stays legible.
   The type is not a second column pushing the photo aside — it is a measured
   block laid over the left of that field, kept readable by a scrim. Boxing the
   photo into a narrow column instead forces cover to scale by height, which on
   a tall viewport crops away most of the frame. */
.hero{
  /* overflow stays visible: the wire's sparks and arcs fall past the hero's
     bottom edge and should spill into the next section, not shear off at it.
     The portrait clips itself (inset-bound box), body handles overflow-x. */
  min-height:calc(100svh - 3.4rem);position:relative;isolation:isolate;
  display:flex;flex-direction:column;justify-content:center;
  padding:clamp(2.5rem,7vh,5rem) 0;
  /* The type column, restated as a length the scrim can be built from. It is
     the same expression .wrap uses for its width, and .hero is full-bleed, so
     a percentage here resolves against the same box the wrap measures against.
     Binding the wash to this instead of to fixed viewport percentages is what
     lets it shrink away from the subject on wide screens: past ~1700px the
     column caps at 900px and keeps shrinking as a share of the frame, so the
     wash retreats while the photograph stays put. */
  --typecol:min(53%,900px);
}
.hero .wrap{
  position:relative;z-index:2;margin:0;max-width:none;
  width:min(53%,900px);
  padding:0 1rem 0 clamp(1.25rem,5vw,7rem);
  container-type:inline-size;
}
/* The source is cropped to the subject's alpha bounds (1277x856), so the
   station's right edge IS the image's right edge — anchored to right:0 it
   reaches the viewport. The uncropped file carried ~229px of transparent
   margin on the right, which is what left a navy gap no object-position
   could close.

   `contain`, not `cover`: cover always sacrifices one axis, and which axis
   depends on the viewport ratio — it ate the man's back on wide screens and
   the station's canopy on tall ones. Because the PNG's surround is
   transparent, contain costs nothing visually (no letterbox bars appear) and
   guarantees the frame is never cut on any ratio. right:0 keeps the station on
   the viewport edge.

   Vertically it is centred, not bottom-anchored: with bottom:0 the whole of
   the height cap's slack collected above the photo, so it sat flush on the
   floor under a thick band of empty navy. top/bottom:0 plus a definite height
   and `margin-block:auto` is the absolute-positioning centring trick — the
   leftover space is split evenly, top and bottom. object-position centres too,
   for the ratios where contain is width-limited and the image is shorter than
   its box. */
.hero-portrait{
  position:absolute;z-index:0;right:0;top:0;bottom:0;
  width:min(92vw,1750px);height:min(92%,calc(100% - 2.5rem));
  margin-block:auto;pointer-events:none;opacity:.96;filter:saturate(1.12) contrast(1.04);
}
/* One full-frame asset serves both layouts. The transparent edge treatment is
   baked into that asset, so responsive CSS must not add another fade or select
   the cropped solid-bottom derivative. */
.hero-portrait img{width:100%;height:100%;object-fit:contain;object-position:right center}
/* Scrim rides the hero, not the photo: bound to the photo's box it ends on a
   hard vertical edge, and being opaque it blanks the grid paper inside that
   box only — a visible rectangle. Full-bleed and never fully opaque, it reads
   as one wash across the plate and the grid survives underneath. z-index 1
   sits it over the photo and under .wrap; .hero-svg is a child at the same
   level, so the ECG trace still draws on top.

   Shaped on two axes, not one. A single left-to-right wall had to stay heavy
   all the way to 68% of the frame to protect the last words of the name — and
   the subject stands at 34-58% of it, so the wall crossed him at full strength
   and laid ~45% of page navy over his face at every desktop width.

   Measured, the conflict turns out to be smaller than the wall assumed. Down
   the frame the type occupies 27-72% of the hero; his head clears it above
   (bottom at 21.7%, 25.4% at the narrowest width here) and his shoes clear it
   below (top at 87%, 82.5% narrowest). Only the torso genuinely shares space
   with the type. So the wash is masked to the band that has type in it and is
   simply absent everywhere else: the face is outside the mask at every width,
   not merely lightly washed. The ramps (25->34, 70->82) are long enough that
   it reads as a glow gathered behind the type — the same language the phone
   breakpoint already spoke — rather than as a band with edges.

   Across the frame it now runs out at the edge of the type column instead of
   at a fixed 68%, and the legibility it used to buy in the overlap is carried
   by a halo on the type itself, which hugs the glyphs instead of painting a
   rectangle over his shirt. */
.hero::before{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(90deg,
    color-mix(in srgb,var(--bg) 80%,transparent) 0,
    color-mix(in srgb,var(--bg) 56%,transparent) calc(var(--typecol)*.30),
    color-mix(in srgb,var(--bg) 22%,transparent) calc(var(--typecol)*.56),
    color-mix(in srgb,var(--bg) 7%,transparent) calc(var(--typecol)*.76),
    transparent calc(var(--typecol)*.98));
  -webkit-mask-image:linear-gradient(180deg,transparent 0 25%,#000 34% 70%,transparent 82%);
  mask-image:linear-gradient(180deg,transparent 0 25%,#000 34% 70%,transparent 82%);
}
/* The halo the wash above no longer carries. It travels with the text, so the
   only thing that ever darkens the photograph where the two overlap is the
   shape of the letters themselves. var(--bg) keeps it correct in both themes. */
.hero .wrap{
  text-shadow:0 1px 20px var(--bg),0 0 6px color-mix(in srgb,var(--bg) 74%,transparent);
}
html[data-theme="light"] .hero-portrait{opacity:.82;filter:saturate(1.02) contrast(.96)}
.hero-rule{font-family:var(--font-m);font-size:.68rem;letter-spacing:.24em;text-transform:uppercase;color:var(--faint);display:flex;align-items:center;gap:.7rem;margin-bottom:1.5rem;
  /* The one line that needed its own halo. It sits at the very top of the type
     block, so it catches the wash's upper ramp at part strength, it is set in
     --faint rather than --ink, and at .68rem the wrap's 18px blur spreads to
     nothing across a hairline stroke. On the narrowest two-column widths its
     tail ("est. 1998") lands on the white of his sleeve, and faint blue-grey on
     white is the worst contrast pairing on the page. A tight opaque core plus
     one soft outer pass carries it without widening the mark on the photo. */
  text-shadow:0 0 3px var(--bg),0 1px 7px var(--bg),0 0 16px color-mix(in srgb,var(--bg) 76%,transparent)}
.hero-rule::before{content:"";width:34px;height:1px;background:var(--red)}
h1.name{
  font-family:var(--font-d);font-variation-settings:"wdth" 121;
  font-weight:850;text-transform:uppercase;
  /* 10.6cqw keeps "SOERJONOTO" (~8.97em wide in Archivo at wdth 121) inside its
     own column at every width, so the nowrap on .l2 can never overflow. */
  font-size:clamp(1.9rem,10.6cqw,6.2rem);line-height:.95;letter-spacing:.002em;
  margin:0 0 1.5rem;
  /* Scaled to the type: at 6rem the wrap's 18px halo is a rim, not a backing.
     This is the line that actually reaches across the subject, so it is the
     one that has to hold on its own. */
  text-shadow:0 2px 34px var(--bg),0 0 12px color-mix(in srgb,var(--bg) 60%,transparent);
}
/* .l2 is drawn as a stroke over a near-transparent fill, and text-shadow works
   off the glyph silhouette rather than the paint — inherited, the halo above
   would flood the counters of every letter with solid navy and read as a
   filled word. Kept, but reduced to a rim that sits just outside the stroke. */
h1.name .l2{display:block;white-space:nowrap;color:color-mix(in srgb,var(--red) 8%,transparent);-webkit-text-stroke:1.5px var(--red-hi);text-shadow:0 0 9px color-mix(in srgb,var(--bg) 66%,transparent)}
.hero-line{font-size:clamp(1.18rem,2.3vw,1.5rem);font-style:italic;line-height:1.55;max-width:44ch}
.hero-line em{font-style:normal;color:var(--red-hi)}
.hero-svg{position:absolute;z-index:1;inset:auto 0 0 0;height:38svh;width:100%;pointer-events:none;overflow:visible}
/* the hero wire speaks the same language as the thread below it: red line on a
   red glow, white-hot arcs and tip. Only the .fx classes style it. */
.hero-svg .t{stroke-width:2.4}
.hero-svg .t-glow{stroke-width:9;opacity:.2}
/* hero surges mutate geometry constantly — filters would re-rasterize every
   frame, so the hero's pulse cores run bare over their red under-band */
.fx.hero-svg .surge{filter:none}
/* the heartbeat at the dominant peak: lit as each pulse passes through */
.hero-svg .peak-core{fill:#fff;filter:drop-shadow(0 0 5px var(--red-hi)) drop-shadow(0 0 12px var(--red));pointer-events:none}
html[data-theme="light"] .hero-svg .peak-core{fill:var(--red-hi);filter:none}
.hero-svg .peak-halo{fill:var(--red);pointer-events:none}
/* after-images: the arc's recent past trailing behind it */
.hero-svg .trail{stroke:var(--red);stroke-width:1.3;fill:none;stroke-linecap:round;stroke-linejoin:round}
.hero-svg .trail-1{opacity:.26}
.hero-svg .trail-2{opacity:.11}
html.rm .hero-svg .trail{display:none}
/* tesla tendrils: thin white forks re-struck with the trunk */
.hero-svg .branch{
  stroke:#fff;stroke-width:1.1;fill:none;opacity:.6;
  stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 0 3px var(--red-hi)) drop-shadow(0 0 7px var(--red));
}
html[data-theme="light"] .hero-svg .branch{stroke:var(--red-hi);filter:none}
/* On paper the outlined surname went washed-out: a 1.5px hairline over a pale
   fill has nothing to hold against a bright sheet. Thicker stroke, thinner fill
   — it reads as drawn outline rather than a pink ghost. */
html[data-theme="light"] h1.name .l2{
  color:color-mix(in srgb,var(--red) 5%,transparent);
  -webkit-text-stroke:2.2px var(--red-hi);
}
/* the ECG trace is emitted light in dark mode and ink in light mode: pull back
   the blur layers that exist only to fake a glow */
html[data-theme="light"] .hero-svg{opacity:.52}
/* The cue is a drawn mark now, not a caption: a hairline stem that gains ink
   as it descends, closed by a 45deg-rotated corner for the head. Same
   vocabulary as the rest of the plate — 1px rules, red doing the pointing —
   so it reads as part of the drawing rather than an icon dropped on top. */
.scrollcue{
  position:absolute;left:50%;bottom:1.3rem;transform:translateX(-50%);z-index:1;
  display:flex;flex-direction:column;align-items:center;gap:.5rem;
  text-decoration:none;padding:.45rem .7rem;
  color:var(--red);opacity:.85;
  transition:opacity .25s var(--ease-snap),color .25s var(--ease-snap);
  /* Stacked, the cue lands on the photo — red on the bike's red bodywork, and
     close enough to the ECG trace to be mistaken for it. A halo in the page
     colour separates the mark from whatever is behind it without adding a
     chip or a box. */
  filter:drop-shadow(0 0 4px var(--bg)) drop-shadow(0 1px 3px rgba(2,12,31,.55));
}
.scrollcue span{display:none}
.scrollcue::before{
  content:"";width:1px;height:34px;
  background:linear-gradient(transparent,currentColor);
}
.scrollcue::after{
  content:"";width:8px;height:8px;margin-top:-.62rem;
  border-right:1.4px solid currentColor;border-bottom:1.4px solid currentColor;
  transform:rotate(45deg);
}
.scrollcue:hover,.scrollcue:focus-visible{opacity:1;color:var(--red-hi)}
html.js .scrollcue{animation:cueFloat 2.6s ease-in-out infinite}
@keyframes cueFloat{0%,100%{transform:translateX(-50%) translateY(0)}50%{transform:translateX(-50%) translateY(6px)}}
/* on the two-column hero the cue belongs under the type, not over the photo */
@media(min-width:881px){
  /* left-aligned under the type column, but the stem and head still share an
     axis — flex-start would hang the 8px head off a 1px stem */
  .scrollcue{left:clamp(1.25rem,5vw,7rem);transform:none}
  html.js .scrollcue{animation:cueFloatL 2.6s ease-in-out infinite}
  @keyframes cueFloatL{0%,100%{transform:translateY(0)}50%{transform:translateY(6px)}}
}

/* ---------- section intro ---------- */
/* This padding lands directly under the hero's own bottom padding, so the two
   stack into one oversized void between the photograph and "LIFE". Scaled with
   the viewport instead of a flat 3.4rem: generous on a desktop where the hero
   is wide, tight on a phone where that void ate most of a screen. */
.sec-intro{display:flex;align-items:baseline;gap:1rem;flex-wrap:wrap;padding:clamp(1.6rem,4.5vh,3.4rem) 0 .4rem}
.sec-intro h2{font-family:var(--font-d);font-variation-settings:"wdth" 118;font-weight:820;text-transform:uppercase;font-size:clamp(1.7rem,4vw,2.6rem);letter-spacing:.004em}
.sec-intro p{color:var(--muted);max-width:62ch;flex-basis:100%}
.sec-count{font-family:var(--font-m);font-size:.68rem;letter-spacing:.14em;color:var(--faint);border:1px solid var(--line);border-radius:4px;padding:.24rem .55rem}

/* ---------- era ---------- */
.era-family{
  margin-top:2.6rem;padding-top:1.25rem;
  border-top:1px solid var(--line);
}
.era-family-head{padding:.25rem 0 .1rem}
.era-family-kicker{
  font-family:var(--font-m);font-size:.64rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--faint);
}
.era-family-title{
  margin:.28rem 0 0;font-family:var(--font-d);font-variation-settings:"wdth" 116;
  font-weight:840;text-transform:uppercase;font-size:clamp(1.75rem,4vw,2.65rem);
  line-height:1.02;scroll-margin-top:4.75rem;
}
.era-family>.era:first-of-type{padding-top:1.65rem}
.era{position:relative;padding:2.6rem 0 1.4rem}
.era-head{margin-bottom:1.8rem;scroll-margin-top:4.25rem}
.era-card{
  border:1px solid var(--line);border-left:3px solid var(--red);border-radius:8px;
  background:var(--plate);box-shadow:var(--shadow);
  padding:1.2rem 1.4rem;display:flex;gap:1.4rem;align-items:center;justify-content:space-between;
}
.era-kicker{font-family:var(--font-m);font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:var(--red-hi)}
.era-title{font-family:var(--font-d);font-variation-settings:"wdth" 114;font-weight:800;text-transform:uppercase;font-size:clamp(1.5rem,3.4vw,2.2rem);line-height:1.05;margin:.3rem 0 .45rem}
.era-intro{color:var(--muted);font-size:.98rem;max-width:62ch}
.era-art{flex:0 0 auto;width:110px;opacity:.9}
.era-art svg{width:100%;height:auto;display:block}
.era-art .ea{stroke:var(--red);fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.era-art .ea2{stroke:var(--blue);fill:none;stroke-width:1;opacity:.7}

/* the thread: rail + fill + node dots */
.flow{position:relative;padding-left:var(--rail)}
.flow-rail{position:absolute;left:calc(var(--rail)*.38);top:0;bottom:0;width:2px;background:var(--line-soft);border-radius:1px;overflow:hidden}
.flow-rail::after{content:"";position:absolute;left:0;top:0;width:100%;height:var(--rail-fill,0%);background:var(--red);border-radius:1px}
html.rm .flow-rail::after{height:100%}
.node::before{
  content:"";position:absolute;left:calc(-1*var(--rail) + var(--rail)*.38 - 4px);top:1.35rem;
  width:10px;height:10px;border-radius:50%;
  background:var(--bg);border:2px solid var(--red);
  transition:background .4s var(--ease-snap),box-shadow .4s var(--ease-snap);
}
.node.lit::before{
  background:var(--red);
  box-shadow:0 0 0 4px var(--red-soft),0 0 18px 3px color-mix(in srgb,var(--red) 78%,transparent),
             0 0 34px 6px color-mix(in srgb,var(--red) 40%,transparent);
}
html.js .node.lit::before{animation:nodePop .5s var(--ease-pop)}
@keyframes nodePop{0%{transform:scale(.4)}50%{transform:scale(2)}72%{transform:scale(.9)}100%{transform:scale(1)}}
/* discharge ring: a shockwave thrown off the node as the current hits it */
.node::after{
  content:"";position:absolute;left:calc(-1*var(--rail) + var(--rail)*.38 - 4px);top:1.35rem;
  width:10px;height:10px;border-radius:50%;border:2px solid var(--red-hi);
  opacity:0;pointer-events:none;
}
html.js .node.lit::after{animation:nodeRing .72s var(--ease-draw) forwards}
@keyframes nodeRing{0%{opacity:.9;transform:scale(1)}100%{opacity:0;transform:scale(4.6)}}
html.rm .node.lit::after{animation:none;opacity:0}
/* era-varied thread lines (V16 system, electrified): a JS-built svg replaces
   the flat rail. svg is the flow's first child at z-index:0; .ev/.grp are
   position:relative, so cards paint above the line in DOM order.
   Glow is a wide translucent under-stroke, not a filter — blur filters over
   flow-sized bboxes re-rasterize every dashoffset frame. */
.thread-svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:0}
.flow.has-thread>.flow-rail{display:none}
.fx .t{stroke:var(--red);stroke-width:2.2;fill:none;stroke-linecap:round;stroke-linejoin:round}
.fx .t-glow{stroke:var(--red);stroke-width:7.5;opacity:.16;fill:none;stroke-linecap:round;stroke-linejoin:round}
.fx .t--echo{stroke-width:1.2;opacity:.55}
.fx .via{
  fill:var(--bg);stroke:var(--red);stroke-width:1.4;opacity:0;
  transition:opacity .25s;transform-box:fill-box;transform-origin:center;
}
.fx .via.on{opacity:1;animation:viaPop .45s var(--ease-pop)}
@keyframes viaPop{0%{transform:scale(.4)}60%{transform:scale(1.75)}100%{transform:scale(1)}}
/* the live tip: white-hot arc head, forking bolts, flying sparks */
.fx .tip{opacity:0}
.fx .tip-core{fill:#fff;filter:drop-shadow(0 0 5px var(--red-hi)) drop-shadow(0 0 11px var(--red))}
/* On paper a white-hot core is invisible (#FFF3F3 on a #F7F5EF sheet), and the
   glow it leaned on is exactly what light mode has to drop. Solid ink instead. */
html[data-theme="light"] .fx .tip-core{fill:var(--red-hi);filter:none}
.fx .tip-halo{fill:var(--red);opacity:.3}
.fx .tip-halo2{fill:var(--red-hi);opacity:.18}
.fx .tip-bolt{
  stroke:#fff;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 0 3px var(--red-hi)) drop-shadow(0 0 7px var(--red));
}
html[data-theme="light"] .fx .tip-bolt{stroke:var(--red-hi)}
.fx .spark{stroke:#fff;stroke-width:1.8;stroke-linecap:round;filter:drop-shadow(0 0 4px var(--red))}
html[data-theme="light"] .fx .spark{stroke:var(--red-hi)}
/* venom arcs: jagged forks that crackle off the live wire */
.fx .arc{
  stroke:#fff;fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 0 3px var(--red-hi)) drop-shadow(0 0 8px var(--red));
}
html[data-theme="light"] .fx .arc{stroke:var(--red-hi)}
.fx .arc-wide{stroke:var(--red);opacity:.32;stroke-width:5;fill:none;stroke-linecap:round;stroke-linejoin:round}
/* speed-force surge: bright current racing down the drawn wire */
.fx .surge{stroke:#fff;fill:none;stroke-width:2.6;stroke-linecap:round;opacity:.9;filter:drop-shadow(0 0 4px var(--red-hi)) drop-shadow(0 0 10px var(--red))}
html[data-theme="light"] .fx .surge{stroke:var(--red-hi)}
.fx .surge-wide{stroke:var(--red);fill:none;stroke-width:7;stroke-linecap:round;opacity:.3}
html.rm .fx .tip,html.rm .fx .spark,
html.rm .fx .arc,html.rm .fx .arc-wide,
html.rm .fx .surge,html.rm .fx .surge-wide{display:none}
html.rm .fx .via{opacity:1;animation:none}
html.rm .node.lit::before{animation:none}

/* ---------- light mode: glow becomes ink ----------
   Dark mode draws with emitted light — halos, drop-shadows, wide translucent
   under-strokes. None of that exists on paper: spread red over a warm sheet
   reads as a smudge, not as energy. So on light the same marks go tighter,
   more opaque, and smaller, and the drawing stays crisp instead of foggy. */
html[data-theme="light"] .fx .t-glow{opacity:.10;stroke-width:5}
html[data-theme="light"] .fx .t--echo{opacity:.42}
html[data-theme="light"] .fx .arc-wide{opacity:.15;stroke-width:3.5}
html[data-theme="light"] .fx .surge-wide{opacity:.14;stroke-width:5}
html[data-theme="light"] .fx .tip-halo{opacity:.15}
html[data-theme="light"] .fx .tip-halo2{opacity:.09}
html[data-theme="light"] .fx .tip-bolt,
html[data-theme="light"] .fx .arc,
html[data-theme="light"] .fx .surge{filter:none}
html[data-theme="light"] .fx .spark{filter:none;stroke-width:1.6}
/* the node was a three-layer bloom; on paper it is a drawn ring */
html[data-theme="light"] .node.lit::before{
  box-shadow:0 0 0 3px rgba(211,26,32,.16),0 0 0 4.5px rgba(211,26,32,.07);
}

/* ---------- event cards (major) ---------- */
.ev{position:relative;margin:0 0 2.5rem;max-width:70ch}
html.js .ev{opacity:0;transform:translateY(14px);transition:opacity .38s var(--ease-snap),transform .42s var(--ease-pop)}
html.js .ev.lit{opacity:1;transform:none}
.ev-date{font-family:var(--font-m);font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--red-hi);display:flex;flex-wrap:wrap;gap:.7rem;align-items:baseline}
.ev-place{color:var(--faint);letter-spacing:.08em}
.ev-title{font-family:var(--font-d);font-variation-settings:"wdth" 112;font-weight:760;font-size:clamp(1.12rem,2vw,1.34rem);line-height:1.2;letter-spacing:.008em;margin:.4rem 0 .5rem}
.ev-body{color:var(--ink);font-size:1rem;line-height:1.68}
.ev-org-head,.pd-org-head{
  display:grid;grid-template-columns:3.7rem minmax(0,1fr);gap:.9rem;align-items:center;
  margin:0 0 .55rem;
}
.ev-org-copy{min-width:0}
.ev-org-head .ev-title,.pd-org-head h3{margin-bottom:0}
.ev-note{position:relative;margin-top:.55rem;padding-left:1.15rem;font-size:.88rem;line-height:1.58;color:var(--muted)}
.ev-note::before{content:"";position:absolute;left:.1rem;top:.5rem;width:.46rem;height:.46rem;border:1.4px solid var(--red);transform:rotate(45deg)}
.ev-links{margin-top:.55rem;font-family:var(--font-m);font-size:.76rem}
.mark{font-family:var(--font-m);font-size:.58rem;font-weight:500;letter-spacing:.12em;border:1px solid var(--line);border-radius:3px;padding:.08rem .35rem;color:var(--faint);white-space:nowrap}
.mark.a{color:var(--blue);border-color:color-mix(in srgb,var(--blue) 45%,transparent)}
.chip{
  display:inline-block;font-family:var(--font-m);font-size:.58rem;font-weight:500;
  letter-spacing:.14em;text-transform:uppercase;vertical-align:.12em;
  border:1px solid var(--line);border-radius:3px;padding:.1rem .4rem;
  color:var(--muted);white-space:nowrap;
}
.chip--p{color:var(--red-hi);border-color:color-mix(in srgb,var(--red) 45%,transparent)}
.chip--t{color:var(--blue);border-color:color-mix(in srgb,var(--blue) 45%,transparent)}
.merged-badge{font-family:var(--font-m);font-size:.6rem;letter-spacing:.1em;color:var(--blue);border:1px dashed color-mix(in srgb,var(--blue) 45%,transparent);border-radius:3px;padding:.08rem .4rem}

/* ---------- umbrella groups ---------- */
.grp{position:relative;margin:0 0 2.5rem;max-width:76ch}
html.js .grp{opacity:0;transform:translateY(14px);transition:opacity .38s var(--ease-snap),transform .42s var(--ease-pop)}
html.js .grp.lit{opacity:1;transform:none}
/* group children now PLAY on reveal: they used to be exempt (opacity locked
   at 1) from the era when opening was manual — with scroll choreography the
   cards inside an opening group stagger in like everything else. Subgroups
   and nested groups stay exempt; the lead ev is head furniture. */
html.js .subgrp,html.js .grp .grp{opacity:1;transform:none}
.grp-head{
  width:100%;text-align:left;display:block;position:relative;
  border:1px solid var(--line);border-radius:8px;background:var(--plate);box-shadow:var(--shadow);
  padding:1rem 3.2rem 1rem 1.2rem;
  transition:border-color .25s var(--ease-snap),background .25s var(--ease-snap);
}
.grp-head:hover{border-color:color-mix(in srgb,var(--red) 45%,transparent)}
.grp[data-open]>.grp-head{border-color:color-mix(in srgb,var(--red) 55%,transparent);border-bottom-left-radius:0;border-bottom-right-radius:0}
.grp-identity{
  display:grid;grid-template-columns:4.25rem minmax(0,1fr);gap:1rem;align-items:center;
}
.grp-head-copy{min-width:0}
.grp-kicker{font-family:var(--font-m);font-size:.64rem;letter-spacing:.18em;text-transform:uppercase;color:var(--red-hi);display:flex;gap:.7rem;flex-wrap:wrap}
.grp-name{font-family:var(--font-d);font-variation-settings:"wdth" 114;font-weight:800;text-transform:uppercase;font-size:clamp(1.25rem,2.6vw,1.7rem);letter-spacing:.006em;margin:.3rem 0 .3rem}
.grp-sum{color:var(--muted);font-size:.95rem;line-height:1.55;max-width:64ch}
.grp-count{font-family:var(--font-m);font-size:.62rem;letter-spacing:.1em;color:var(--faint)}
.grp-caret{
  position:absolute;right:1rem;top:1.1rem;width:26px;height:26px;border:1px solid var(--line);border-radius:50%;
  display:grid;place-items:center;color:var(--red-hi);
  transition:transform .34s var(--ease-pop),border-color .2s;
}
.grp-caret svg{width:12px;height:12px;stroke:currentColor;stroke-width:2.2;fill:none}
.grp[data-open]>.grp-head>.grp-caret{transform:rotate(180deg);border-color:color-mix(in srgb,var(--red) 45%,transparent)}
.org-logo{
  display:grid;place-items:center;width:4.25rem;height:3.75rem;padding:0;
  overflow:visible;border:0;border-radius:0;background:transparent;box-shadow:none;
}
.org-logo img{
  display:block;width:100%;height:100%;max-width:100%;max-height:100%;
  min-width:0;min-height:0;
  object-fit:contain;object-position:center;
  filter:drop-shadow(0 3px 8px rgba(2,8,18,.22));
}
.org-logo--event{width:3.7rem;height:3.45rem}
.org-logo--compact{width:2.85rem;height:2.65rem}
.org-logo--tiny{width:1.85rem;height:1.85rem}
.grp-body{
  display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .38s var(--ease-draw);
}
.grp[data-open]>.grp-body{grid-template-rows:1fr}
.grp-body-in{
  overflow:hidden;min-height:0;
  border:1px solid transparent;border-top:0;border-radius:0 0 8px 8px;
  opacity:0;transform:translateY(-6px);
  transition:opacity .3s var(--ease-snap) .05s,transform .3s var(--ease-draw) .05s,border-color .2s;
}
.grp[data-open]>.grp-body>.grp-body-in{opacity:1;transform:none;border-color:color-mix(in srgb,var(--red) 30%,transparent)}
html.rm .grp-body,html.rm .grp-body-in{transition:none}
/* choreography's instant flips: no transition while the class is on */
.grp.no-anim .grp-body,.grp.no-anim .grp-body-in,
.pj-grp.no-anim .grp-body,.pj-grp.no-anim .grp-body-in{transition:none!important}
.grp-lead{padding:1.1rem 1.2rem .4rem;border-left:2px solid var(--red);margin-left:-1px}
.grp-lead .ev{margin-bottom:1.2rem}
html.js .grp-lead .ev{opacity:1;transform:none}
.grp-kids{padding:.5rem 1.2rem 1.1rem;position:relative}
.grp-kids::before{content:"";position:absolute;left:calc(1.2rem + 3px);top:0;bottom:.9rem;width:1.5px;background:color-mix(in srgb,var(--red) 55%,transparent)}
.grp-kids>.ev{
  max-width:none;margin:.8rem 0 1rem 1.5rem;padding:1rem 1.05rem;
  border:1px solid var(--line);border-left:2px solid var(--red);border-radius:6px;
  background:color-mix(in srgb,var(--plate) 86%,transparent);box-shadow:var(--shadow);
}
.grp-kids>.ev::before{
  content:"";position:absolute;left:-1.5rem;top:1.35rem;width:1.5rem;height:1.5px;
  background:color-mix(in srgb,var(--red) 55%,transparent);
}
.subgrp .grp-kids>.ev{margin-left:1.5rem;padding:.85rem .9rem}
.kid{position:relative;padding:.5rem 0 .5rem 1.5rem}
/* scroll-linked reveal: each kid row pops when IT crosses the reveal band,
   one by one in either scroll direction — never a timed volley. scan()
   toggles .on per row; leaving the viewport rewinds it for the next pass. */
html.js .grp[data-open] .grp-kids .kid{
  opacity:0;transform:translateY(10px);
  transition:opacity .28s var(--ease-snap),transform .34s var(--ease-pop);
}
html.js .grp[data-open] .grp-kids .kid.on{opacity:1;transform:none}
html.rm .grp[data-open] .grp-kids .kid{opacity:1;transform:none;transition:none}
.kid::before{content:"";position:absolute;left:4px;top:1.35rem;width:.95rem;height:1.5px;background:color-mix(in srgb,var(--red) 55%,transparent)}
/* minor-technical: an engineering log line */
.kid--mt{font-family:var(--font-m)}
.kid--mt .kid-date{font-size:.64rem;letter-spacing:.1em;color:var(--red-hi);text-transform:uppercase}
.kid--mt .kid-title{font-size:.85rem;font-weight:600;letter-spacing:.02em;color:var(--ink);margin:.1rem 0 .15rem}
.kid--mt .kid-body{font-size:.8rem;line-height:1.62;color:var(--muted)}
.kid--mt::after{content:"";position:absolute;left:1.02rem;top:1.12rem;width:7px;height:7px;border:1.5px solid var(--red);background:var(--bg)}
/* minor-non-technical: softer serif, service tone */
.kid--mnt .kid-date{font-family:var(--font-m);font-size:.64rem;letter-spacing:.1em;color:var(--faint);text-transform:uppercase}
.kid--mnt .kid-title{font-family:var(--font-s);font-style:italic;font-weight:600;font-size:1.02rem;color:var(--ink);margin:.08rem 0 .12rem}
.kid--mnt .kid-body{font-family:var(--font-s);font-size:.92rem;line-height:1.62;color:var(--muted)}
.kid--mnt::after{content:"";position:absolute;left:1rem;top:1.1rem;width:7px;height:7px;border:1.4px solid var(--faint);transform:rotate(45deg);border-radius:1px;background:var(--bg)}
.kid-org-head{
  display:grid;grid-template-columns:2.85rem minmax(0,1fr);gap:.7rem;align-items:center;
  margin:.1rem 0 .45rem;
}
.kid-org-copy{min-width:0}
.kid .kid-note{font-size:.78rem;color:var(--faint);margin-top:.15rem;line-height:1.5}
.kid .plates{margin:.7rem 0 .3rem}
/* subgroup inside an umbrella */
.subgrp{margin:.7rem 0 .7rem 1.5rem;border:1px solid var(--line-soft);border-left:2px solid color-mix(in srgb,var(--red) 55%,transparent);border-radius:6px;background:color-mix(in srgb,var(--plate) 62%,transparent)}
.subgrp>.grp-head{border:0;background:transparent;box-shadow:none;padding:.7rem 2.6rem .6rem .9rem;border-radius:6px}
.subgrp .grp-name{font-size:1.02rem}
.subgrp .grp-caret{top:.6rem;right:.7rem;width:22px;height:22px}
.subgrp .grp-kids{padding:.2rem .9rem .7rem}
.subgrp .grp-kids::before{left:calc(.9rem + 3px)}
.subgrp .grp-lead{padding:.6rem .9rem .2rem}

/* ---------- plates (photo framing law: frame follows image, never crop) ---------- */
.plates{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(250px,100%),1fr));gap:1.2rem;margin:1.4rem 0 .4rem;max-width:66ch}
.plate{
  background:var(--plate);border:1px solid var(--line);border-radius:6px;
  box-shadow:var(--shadow);padding:.6rem;position:relative;cursor:zoom-in;
}
.plate::before,.plate::after{
  content:"";position:absolute;top:-4px;width:8px;height:8px;border-radius:50%;
  background:var(--bg2);border:1.5px solid var(--line);
}
.plate::before{left:14px}.plate::after{right:14px}
.plate img{
  width:100%;height:auto;border-radius:3px;border:1px solid var(--line-soft);
  background:var(--bg2);
  filter:saturate(.6) contrast(.98);
  transition:filter .8s var(--ease-snap);
}
.ev.lit .plate img,.plate:hover img,.grp .plate img{filter:saturate(1) contrast(1)}
.plate figcaption{font-size:.84rem;line-height:1.5;color:var(--muted);padding:.55rem .15rem .15rem}
.figno{font-family:var(--font-m);font-size:.6rem;font-weight:500;letter-spacing:.16em;text-transform:uppercase;color:var(--red-hi);margin:.1rem 0 .5rem .1rem}

/* ---------- figures ---------- */
.specfig{margin:1.6rem 0 .6rem;border:1px solid var(--line);border-radius:6px;background:var(--plate);box-shadow:var(--shadow);padding:1.1rem 1.1rem .8rem;max-width:66ch}
.specfig svg{width:100%;height:auto;display:block}
.specfig figcaption{font-size:.84rem;color:var(--muted);padding-top:.65rem;line-height:1.55}
.specfig text{font-family:var(--font-m);fill:var(--muted)}
.specfig .lbl{font-size:10px;letter-spacing:.04em}
.specfig .big{fill:var(--ink);font-weight:600}
.specfig .rlbl{fill:var(--red-hi)}
.specfig .draw{stroke:var(--ink);fill:none;stroke-width:1.4}
.specfig .drawthin{stroke:var(--muted);fill:none;stroke-width:1}
.specfig .red{stroke:var(--red)}
.specfig .dim{stroke:var(--faint);fill:none;stroke-width:.8}
.specfig .fill-red{fill:var(--red);stroke:none}
.statgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));gap:.9rem;margin:1.5rem 0 .5rem;max-width:66ch}
.stat{
  border:1px solid var(--line);border-radius:6px;background:var(--plate);
  padding:.95rem 1rem .85rem;box-shadow:var(--shadow);position:relative;overflow:hidden;
}
.stat::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:linear-gradient(90deg,var(--red),transparent 75%)}
.stat b{
  display:block;font-family:var(--font-d);font-variation-settings:"wdth" 110;
  font-weight:800;font-size:clamp(1.5rem,2.6vw,2rem);line-height:1.05;
  font-variant-numeric:tabular-nums;
}
.stat>span{display:block;font-size:.85rem;color:var(--muted);margin-top:.35rem;line-height:1.45}
.stat>.chip{margin:.5rem 0 0}
.ba{margin:1.5rem 0 .5rem;max-width:560px}
.ba .row{display:grid;grid-template-columns:86px 1fr 84px;align-items:center;gap:.8rem;margin:.5rem 0}
.ba .row b{font-family:var(--font-m);font-weight:500;font-size:.66rem;letter-spacing:.1em;color:var(--muted);text-transform:uppercase}
.ba .bar{height:12px;border-radius:3px;background:var(--bg2);border:1px solid var(--line-soft);overflow:hidden}
.ba .bar i{display:block;height:100%;background:var(--red);width:0;transform-origin:0 50%;transition:width 1s var(--ease-draw)}
.ba .row.alt .bar i{background:var(--blue)}
.ba .val{font-family:var(--font-m);font-size:.76rem;font-variant-numeric:tabular-nums;text-align:right}
.ba .cap{font-size:.84rem;color:var(--muted);margin-top:.5rem;line-height:1.5}
html.rm .ba .bar i{transition:none}
.commitfig{margin:1.6rem 0 .6rem;border:1px solid var(--line);border-radius:6px;background:var(--plate);box-shadow:var(--shadow);padding:1.1rem;max-width:66ch}
.phases{display:flex;gap:.4rem;flex-wrap:wrap;margin:.8rem 0 .6rem}
.phases span{font-family:var(--font-m);font-size:.58rem;letter-spacing:.12em;color:var(--muted);border:1px solid var(--line-soft);border-radius:3px;padding:.12rem .42rem}
.phases span+span::before{content:"→ ";color:var(--faint)}
.strip{display:flex;gap:5px;align-items:flex-end;height:110px}
.strip .day{flex:1;display:flex;flex-direction:column-reverse;gap:2px;height:100%}
.strip .day i{display:block;height:4px;border-radius:1px;background:var(--red);opacity:0;transform:scaleX(.2)}
html.js .strip.lit .day i{animation:tick .34s var(--ease-pop) forwards}
@keyframes tick{55%{opacity:1;transform:scaleX(1.4)}to{opacity:.92;transform:scaleX(1)}}
html:not(.js) .strip .day i,html.rm .strip .day i{opacity:.92;transform:none;animation:none}
.striplabels{display:flex;gap:5px;margin-top:.45rem}
.striplabels span{flex:1;text-align:center;font-family:var(--font-m);font-size:.54rem;color:var(--faint)}
.commitfig figcaption{font-size:.84rem;color:var(--muted);margin-top:.8rem;line-height:1.5}
.fanviz{margin:1.5rem 0 .4rem;max-width:620px}
.fanviz svg{width:100%;height:auto;display:block;overflow:visible}
.fanviz .fanline{stroke:var(--red);stroke-width:1.5;fill:none;opacity:.85}
.fanviz .cap{font-family:var(--font-m);font-size:.64rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);margin-top:.45rem}

/* ---------- projects ---------- */
.pj-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(300px,100%),1fr));gap:1.1rem;margin:1.6rem 0 3rem}
.pj{
  border:1px solid var(--line);border-radius:8px;background:var(--plate);box-shadow:var(--shadow);
  display:flex;flex-direction:column;overflow:hidden;text-align:left;position:relative;
  transition:transform .25s var(--ease-snap),border-color .25s var(--ease-snap);
}
html.js .pj{opacity:0;transform:translateY(14px)}
html.js .pj.lit{opacity:1;transform:none;transition:opacity .55s var(--ease-snap),transform .55s var(--ease-pop),border-color .25s var(--ease-snap)}
html.js .pj.lit:hover{transform:translateY(-3px);border-color:color-mix(in srgb,var(--red) 50%,transparent)}
.pj-top{display:flex;align-items:center;gap:.55rem;padding:.7rem .9rem;border-bottom:1px solid var(--line-soft)}
.pj-top svg{width:15px;height:15px;stroke:var(--red-hi);fill:none;stroke-width:1.6;flex:0 0 auto}
.pj-top .org-logo--tiny{flex:0 0 1.85rem}
.pj-name{font-family:var(--font-m);font-weight:600;font-size:.8rem;letter-spacing:.03em;color:var(--ink);overflow-wrap:anywhere}
.pj-year{margin-left:auto;font-family:var(--font-m);font-size:.66rem;color:var(--faint);letter-spacing:.1em}
.pj-thumb{height:150px;background:var(--bg2);border-bottom:1px solid var(--line-soft);display:grid;place-items:center;overflow:hidden}
.pj-thumb img{width:100%;height:100%;object-fit:contain;filter:saturate(.75)}
.pj:hover .pj-thumb img{filter:saturate(1)}
.pj-thumb svg{width:44px;height:44px;stroke:color-mix(in srgb,var(--red) 55%,transparent);fill:none;stroke-width:1.3}
.pj-desc{padding:.75rem .9rem .2rem;font-size:.9rem;line-height:1.55;color:var(--muted)}
.pj-foot{margin-top:auto;display:flex;flex-wrap:wrap;gap:.4rem;align-items:center;padding:.7rem .9rem .8rem}
.tag{font-family:var(--font-m);font-size:.56rem;letter-spacing:.12em;text-transform:uppercase;color:var(--blue);border:1px solid color-mix(in srgb,var(--blue) 40%,transparent);border-radius:10px;padding:.1rem .5rem}
.pj-foot .chip{margin:0}
.pj-links{margin-left:auto;display:flex;gap:.5rem;font-family:var(--font-m);font-size:.68rem}
.pj-grp{grid-column:1/-1;max-width:none;margin:0;border:1px solid var(--line);border-radius:8px;background:color-mix(in srgb,var(--plate) 80%,transparent);box-shadow:var(--shadow)}
.pj-grp>.grp-head{border:0;box-shadow:none;background:transparent}
.pj-grp .pj-grid{margin:.2rem 1rem 1rem;grid-template-columns:repeat(auto-fill,minmax(min(270px,100%),1fr))}
html.js .pj-grp{opacity:0;transform:translateY(14px);transition:opacity .55s var(--ease-snap),transform .55s var(--ease-draw)}
html.js .pj-grp.lit{opacity:1;transform:none}
/* project cards inside groups play their reveal too (was exempt pre-choreo) */

/* project detail overlay */
.pd{position:fixed;inset:0;z-index:80;display:none;background:color-mix(in srgb,var(--bg) 78%,transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);overflow-y:auto;overscroll-behavior:contain}
.pd.open{display:block}
.pd-in{
  max-width:820px;margin:4.2rem auto 3rem;background:var(--plate);
  border:1px solid var(--line);border-top:3px solid var(--red);border-radius:10px;box-shadow:var(--shadow);
  padding:1.6rem clamp(1.1rem,3.5vw,2.2rem) 2rem;position:relative;
}
html.js .pd.open .pd-in{animation:viewIn .32s var(--ease-draw)}
.pd-close{position:absolute;top:.9rem;right:.9rem;font-family:var(--font-m);font-size:.66rem;letter-spacing:.12em;color:var(--muted);border:1px solid var(--line);border-radius:4px;padding:.3rem .55rem}
.pd-close:hover{color:var(--ink);border-color:var(--ink)}
.pd .ev-date{margin-top:.2rem}
.pd h3{font-family:var(--font-d);font-variation-settings:"wdth" 114;font-weight:800;font-size:clamp(1.4rem,3vw,2rem);line-height:1.1;margin:.45rem 0 .7rem}
.pd .tags{display:flex;flex-wrap:wrap;gap:.4rem;margin:.2rem 0 .9rem}
.pd .ev-body{font-size:1.02rem}
.pd .plates{max-width:none}

/* ---------- footer ---------- */
.ft{border-top:1px solid var(--line);padding:2.4rem 0 7rem}
.ft-in{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter);display:flex;flex-direction:column;gap:.9rem}
.ft-line{font-size:.74rem;letter-spacing:.05em;color:var(--muted)}
/* social icons: 36px hit targets, nudged left so the first glyph's optical
   edge lines up with the contact line above it */
.ft-social{display:flex;align-items:center;gap:.3rem;list-style:none;padding:0;margin:0 0 0 -9px}
.ft-social a{
  display:grid;place-items:center;width:36px;height:36px;border-radius:6px;
  color:var(--muted);transition:color .25s var(--ease-snap),background .25s var(--ease-snap);
}
.ft-social a:hover,.ft-social a:focus-visible{color:var(--red-hi);background:var(--red-soft)}
.ft-social svg{width:18px;height:18px;display:block;fill:currentColor}
.ft-social .ic-stroke{fill:none;stroke:currentColor;stroke-width:1.9;stroke-linejoin:round}
.ft-social .ic-stroke .ic-fill{fill:currentColor;stroke:none}
html.rm .ft-social a{transition:none}

/* ---------- lightbox ---------- */
.lb{position:fixed;inset:0;z-index:90;display:none;place-items:center;background:color-mix(in srgb,var(--bg) 88%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}
.lb.open{display:grid}
.lb figure{max-width:min(92vw,1100px);max-height:88svh;display:flex;flex-direction:column;gap:.6rem}
.lb img{max-width:100%;max-height:78svh;width:auto;height:auto;object-fit:contain;margin:0 auto;border:1px solid var(--line);border-radius:4px;background:var(--bg2)}
.lb figcaption{font-family:var(--font-m);font-size:.72rem;color:var(--muted);text-align:center;line-height:1.6;padding:0 1rem}
.lb-close{position:absolute;top:1rem;right:1rem;font-family:var(--font-m);font-size:.68rem;letter-spacing:.12em;color:var(--muted);border:1px solid var(--line);border-radius:4px;padding:.4rem .7rem}
.lb-close:hover{color:var(--ink);border-color:var(--ink)}
.lb-nav{position:absolute;top:50%;transform:translateY(-50%);font-size:1.7rem;color:var(--muted);padding:1rem;line-height:1}
.lb-nav:hover{color:var(--red-hi)}
.lb-prev{left:.4rem}.lb-next{right:.4rem}

/* ---------- archive-empty ---------- */
.era-empty{font-family:var(--font-m);font-size:.76rem;color:var(--faint);letter-spacing:.06em;padding:.4rem 0 .2rem}

/* ---------- reveals / reduced motion ---------- */
html.rm .ev,html.rm .grp,html.rm .pj,html.rm .pj-grp{opacity:1!important;transform:none!important;transition:none!important}
html.rm .scrollcue{animation:none}
html.rm .view-in,html.rm .view-out{animation:none;transition:none;opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
  html.js .ev,html.js .grp,html.js .pj,html.js .pj-grp{opacity:1;transform:none;transition:none}
  html.js .scrollcue{animation:none}
  html.js .strip .day i{opacity:.92;transform:none;animation:none}
  .ba .bar i{transition:none}
  .grp-body,.grp-body-in{transition:none}
  *{scroll-behavior:auto!important}
}

/* ---------- noscript ---------- */
.ns{max-width:var(--maxw);margin:0 auto;padding:2rem var(--gutter)}
.ns h1{font-family:var(--font-d);font-weight:850;text-transform:uppercase;margin-bottom:.8rem}
.ns-register{margin:1.4rem 0 0 1.2rem;display:grid;gap:.55rem}
.ns-register li span{font-family:var(--font-m);font-size:.8em;color:var(--red-hi);margin-right:.4rem}

/* ---------- responsive ---------- */
@media(max-width:880px){
  :root{--rail:26px}
  main{padding-top:3.1rem}
  .brand b{font-size:.68rem}
  .brand span{display:none}
  .secnav a{padding:.4rem .55rem;font-size:.64rem}
  .era-card{flex-direction:column;align-items:flex-start;gap:.8rem}
  .era-art{width:88px}
  h1.name{font-variation-settings:"wdth" 106}
  .pd-in{margin:2.6rem .7rem 2rem}
}
/* ---------- stacked hero: narrow screens only ---------- */
/* Window shape is not device identity. A tall desktop window must keep the
   desktop composition; only genuinely narrow viewports use the stacked hero. */
@media(max-width:880px){
  /* Too narrow to lay type over the photo — stack instead: type up top and the
     original full-frame photograph across the foot of the screen. */
  .hero{justify-content:flex-start;padding:clamp(1.4rem,3.5vh,2.6rem) 0 0;
    /* What is left of the screen once the photo has taken its floor: the hero
       minus the chrome, the padding and 100vw/1.4918 of photograph. Sizing the
       type off the measure alone is right until the frame approaches square,
       where the photo's floor eats the page and the type spills past the fold —
       77px over at an aspect of 0.90, 187px at 1.00. Capping against this
       budget binds only inside that band and leaves every taller frame on the
       measure. The max() guards the one stacked case that is not portrait, a
       phone held sideways, where the expression would go negative. */
    --tb:max(9rem,calc(100svh - 128px - 67.04vw))}
  /* The <figure> precedes the type in the markup — it is the LCP element and
     wants to be discoverable first. That was free while the photo was
     absolutely positioned, but in flow it puts the photograph above the type.
     Order restores the reading without touching the source order. */
  .hero .wrap{width:auto;padding:0 var(--gutter);flex:0 0 auto;order:1;
    /* the type and the photograph met flush once the photo became a flex item;
       this is the only thing separating them now */
    margin-bottom:clamp(.9rem,2.2vh,2.2rem)}
  /* Stacked, the type has the full width of the page instead of a 53% column,
     and it was not using it: the name capped out at 6.2rem and filled 69% of
     the measure at 1400px, the lede was locked to a 44ch line and filled 41%.
     Between them they left the top right corner of the page empty.

     Sized off the container instead of off a fixed ceiling, the name fills the
     measure at every stacked width. The coefficient is per width-axis regime
     because it is calibrated against the ink: "SOERJONOTO" measures 8.96em at
     wdth 121, and 7.97em at the wdth 106 the narrow block sets, so one number
     cannot serve both. 10.8cqw puts it at 97% of the measure here. The ceiling
     stays only to stop absurd sizes on very large portrait screens — the
     container sizing is what guarantees the nowrap can never overflow. */
  h1.name{--namecq:10.8cqw;font-size:clamp(1.9rem,min(var(--namecq),calc(.245 * var(--tb))),13rem)}
  /* The lede grows with the page rather than stopping at 1.5rem. The measure
     widens a little too, but most of the fill has to come from size: at 1400px
     a 46ch line only reaches 87% of the width if the type is ~48px, and 46ch is
     already at the top of what stays comfortable to read. */
  .hero-line{font-size:clamp(1.18rem,min(3.1vw,calc(.076 * var(--tb))),2.7rem);max-width:46ch}
  /* Stacked runs `cover`, not the desktop `contain`. Fitting the whole frame
     into a phone's width caps it at width/1.492 — short, and short leaves a
     dead band above it that no type push can fully close. cover fills the box
     instead and lets the frame run off both edges, which is the intended
     reading here: the photo is a field the page sits on, not a picture of a
     complete scene. Desktop keeps contain — there the frame is the subject.

     The photo is a flex item now, not an absolutely positioned one pinned to
     the floor at a percentage height. Pinned, it could only guess how much room
     the type left it, and on a tall viewport it guessed short — 17% of the hero
     opened up as dead navy between the last line of type and the top of the
     photograph. As a flex item it takes exactly what the type does not, at
     every aspect ratio, and the gap cannot exist by construction.

     cover crops on whichever axis is tight, so the box aspect decides which.
     Below 1.492 (the frame's) it trims the sides — wanted, the frame runs off
     both edges. Above it, it trims top and bottom instead, which eats the
     station's canopy and his head. Flooring the height at 100vw/1.492 keeps the
     box at or under the frame's aspect however little room the type leaves, so
     the crop can only ever be horizontal. */
  .hero-portrait{
    position:relative;inset:auto;margin:0;width:100%;overflow:hidden;order:2;
    flex:1 1 auto;min-height:calc(100vw / 1.4918);
    opacity:1;isolation:isolate;
  }
  /* Framing is set by the horizontal crop, which tightens as the viewport gets
     taller — the photo grows to fill and cover scales by height, so less of the
     frame's width survives. At the extreme (880x1620) only 642 of 1277 source
     px remain. He occupies 240-545 of those, so the window has to start at or
     before 240: that is a position of 37.8% there, 35.9% at 430 wide, 37.3% at
     390. 34% clears the tightest of them with margin and holds him whole at
     every stacked size, at the cost of the bike's tail rather than his arm. */
  .hero-portrait img{position:absolute;inset:0;z-index:0;width:100%;height:100%;object-fit:cover;object-position:34% 38%;opacity:.82}
  /* Mobile keeps the exact V25 composition. No overlay is painted over the
     portrait, motorcycle or lower edge. */
  .hero::before{background:none;-webkit-mask-image:none;mask-image:none}
  /* Restore the original tonal wash behind the type only. Its box ends where
     the photograph begins, so it cannot darken the head, station or bike. */
  .hero .wrap{isolation:isolate}
  .hero .wrap::before{
    content:"";position:absolute;z-index:-1;pointer-events:none;
    left:0;right:0;
    top:calc(-1 * clamp(1.4rem,3.5vh,2.6rem));
    bottom:calc(-1 * clamp(.9rem,2.2vh,2.2rem));
    background:linear-gradient(180deg,
      color-mix(in srgb,var(--bg) 86%,transparent) 0,
      color-mix(in srgb,var(--bg) 72%,transparent) 34%,
      color-mix(in srgb,var(--bg) 60%,transparent) 64%,
      color-mix(in srgb,var(--bg) 36%,transparent) 88%,
      transparent 97%,transparent 100%);
  }
  /* Soften only the exposed station-roof edge to the right of the head. The
     angled left boundary keeps every subject pixel untouched. */
  .hero-portrait::before{
    content:"";position:absolute;top:0;height:clamp(1.75rem,6vw,2.5rem);
    left:0;right:0;z-index:1;pointer-events:none;
    clip-path:polygon(36% 0,100% 0,100% 100%,50% 100%);
    background:linear-gradient(180deg,
      var(--bg) 0,
      color-mix(in srgb,var(--bg) 90%,transparent) 18%,
      color-mix(in srgb,var(--bg) 68%,transparent) 42%,
      color-mix(in srgb,var(--bg) 35%,transparent) 68%,
      color-mix(in srgb,var(--bg) 10%,transparent) 88%,
      transparent 100%);
  }
  html[data-theme="light"] .hero-portrait{opacity:1}
  html[data-theme="light"] .hero-portrait img{opacity:.7}
}
/* The 880 block sets wdth 106, which narrows the glyphs so the same font-size
   draws a shorter word — 10.8cqw only reaches 86% of the measure there. It has
   to be restated after the stacked block rather than inside the 880 one,
   because the two selectors are equally specific and the stacked block is
   later, so it would otherwise win. Phones are excluded: they get their own
   coefficient below, calibrated for the .84em .l2. */
@media(min-width:561px) and (max-width:880px){
  h1.name{--namecq:12.1cqw}
}
@media(max-width:560px){
  body{font-size:1rem}
  /* Phones land here, not in the 880 block — this rule is what actually sets
     their top padding, and at 9vh it was stranding ~75px of dead navy under
     the navbar while the type/photo met almost flush below. Matched to the
     880 block so the type starts near the top on every stacked width. */
  .hero{padding-top:clamp(1.4rem,3.5vh,2.6rem)}
  .hero-rule{font-size:.58rem;letter-spacing:.18em;margin-bottom:1.1rem}
  /* .l2 is set at .84em here so the longer word clears a phone's measure, which
     drops the effective ink to 6.54em of the base size — hence a third
     coefficient. Held to 94% rather than 97%: at this size the last letter
     sitting hard against the gutter reads as an accident. */
  h1.name{line-height:.91;margin-bottom:1.15rem;font-size:clamp(1.9rem,14.4cqw,13rem)}
  h1.name .l2{font-size:.84em;letter-spacing:-.018em}
  /* 30ch left ~143px of the gutter-to-gutter width unused on a 481pt screen
     and cost an extra line. 40ch fills the measure on a phone (the container
     caps it below that anyway) and buys a line back, which lifts the text
     clear of the photo — and lets the wash above stop higher. */
  .hero-line{font-size:clamp(1.05rem,5.4vw,1.28rem);line-height:1.46;max-width:40ch}
  /* The wash reached 72% of the hero to keep type legible where it lands on
     the photo — but on a phone the head sits at 42-51%, so protecting the type
     that way meant washing his face. Carry the legibility on the type itself
     (a halo in the page colour, so it is correct in both themes) and the wash
     can stop just past the photo's top edge instead: it softens the join and
     leaves the face alone. Short phones, where the text does still overlap the
     photo, stay readable because the halo travels with the text rather than
     with the band.

     The halo this rule introduced is the page-wide default now — every width
     leans on it, not just phones. Only the name's is re-tuned here: its blur
     is scaled for 6rem type, and on a phone the same figure at ~2.3rem closes
     the counters. */
  h1.name{text-shadow:0 1px 16px var(--bg),0 0 6px color-mix(in srgb,var(--bg) 62%,transparent)}
  h1.name .l2{text-shadow:0 0 6px color-mix(in srgb,var(--bg) 66%,transparent)}
  /* The percentage height this rule used to carry is gone — the photo is a flex
     item now and takes whatever the type leaves, which is what the 54%->60%
     nudge was reaching for by hand. Only the opacity and framing stay. */
  .hero-portrait{opacity:1}
  /* 44% was framed for the old fixed-percentage height. The photo is taller now
     and the window narrower, and 44% would cut into his arm — match the shared
     stacked framing. */
  .hero-portrait img{object-position:34% 36%;opacity:.78}
  html[data-theme="light"] .hero-portrait{opacity:1}
  html[data-theme="light"] .hero-portrait img{opacity:.66}
  .hero-svg{height:30svh;opacity:.82}
  .scrollcue{bottom:.55rem;gap:.35rem;color:var(--red-hi);opacity:1}
  .scrollcue span{
    display:block;order:1;white-space:nowrap;
    font-family:var(--font-s);font-size:clamp(.92rem,4vw,1.05rem);line-height:1.2;
    text-shadow:0 0 2px var(--bg),0 0 6px var(--bg),0 1px 14px var(--bg);
  }
  .scrollcue::before{order:2}
  .scrollcue::after{order:3}
  .grp-head{padding:.85rem 2.7rem .85rem .95rem}
  .grp-identity{grid-template-columns:3.45rem minmax(0,1fr);gap:.72rem}
  .org-logo{width:3.45rem;height:3.25rem;padding:0}
  .org-logo--event{width:3.25rem;height:3.05rem}
  .org-logo--compact{width:2.6rem;height:2.45rem}
  .ev-org-head,.pd-org-head{grid-template-columns:3.25rem minmax(0,1fr);gap:.72rem}
  .kid-org-head{grid-template-columns:2.6rem minmax(0,1fr);gap:.6rem}
  .grp-lead{padding:.9rem .85rem .3rem}
  .grp-kids{padding:.4rem .85rem .9rem}
  .grp-kids::before{left:calc(.85rem + 3px)}
  .grp-kids>.ev{padding:.85rem .8rem}
  .subgrp{margin-left:.7rem}
  .plates{grid-template-columns:1fr 1fr;gap:.8rem}
  .plates:has(.plate:only-child){grid-template-columns:1fr}
  .ba .row{grid-template-columns:64px 1fr 70px;gap:.5rem}
  .striplabels span:nth-child(even){visibility:hidden}
  .pj-grp .pj-grid{margin:.2rem .6rem .8rem}
  /* Project artwork is predominantly 3:2. The fixed desktop-height track made
     those images keep their intrinsic height on phones, then clipped the
     overflow, so some thumbnails appeared small and pushed down. Give mobile
     cards a stable full-width frame and make the image fill that frame. */
  .pj-thumb{height:auto;aspect-ratio:3/2;place-items:stretch}
  .pj-thumb img{min-width:0;min-height:0;object-fit:cover;object-position:center}
}
@media(max-width:400px){
  .top{gap:.35rem}
  .brand{gap:.35rem}
  .brand b{font-size:.58rem;letter-spacing:.1em}
  .secnav{gap:.1rem}
  .secnav a{padding:.38rem .35rem;font-size:.58rem;letter-spacing:.12em}
}
/* ---------- V30 event-local evidence drawers ---------- */
.evidence-drawer{
  margin-top:1rem;
  border:1px solid var(--line);
  border-radius:7px;
  background:color-mix(in srgb,var(--plate) 82%,transparent);
  overflow:hidden;
}
.evidence-drawer>summary{
  list-style:none;
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  gap:.7rem;
  align-items:center;
  min-height:44px;
  padding:.65rem .8rem;
  cursor:pointer;
  color:var(--muted);
  transition:background .2s var(--ease-snap),color .2s var(--ease-snap);
}
.evidence-drawer>summary::-webkit-details-marker{display:none}
.evidence-drawer>summary:hover,
.evidence-drawer>summary:focus-visible{
  color:var(--ink);
  background:color-mix(in srgb,var(--red-soft) 44%,transparent);
  outline:none;
}
.evidence-summary-label{
  font-family:var(--font-m);
  font-size:.63rem;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--red-hi);
}
.evidence-summary-count{
  min-width:0;
  font-family:var(--font-m);
  font-size:.62rem;
  letter-spacing:.04em;
  line-height:1.45;
  color:var(--faint);
}
.evidence-summary-caret{
  display:grid;
  place-items:center;
  width:24px;
  height:24px;
  border:1px solid var(--line);
  border-radius:50%;
  color:var(--red-hi);
  font-family:var(--font-m);
  font-size:1rem;
  line-height:1;
  transition:transform .28s var(--ease-pop),border-color .2s;
}
.evidence-drawer[open]>summary{
  border-bottom:1px solid var(--line);
  background:color-mix(in srgb,var(--red-soft) 28%,transparent);
}
.evidence-drawer[open]>summary .evidence-summary-caret{
  transform:rotate(45deg);
  border-color:color-mix(in srgb,var(--red) 45%,transparent);
}
.evidence-grid{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:.8rem;
  padding:.8rem;
}
.evidence-item{
  min-width:0;
  margin:0;
  border:1px solid var(--line-soft);
  border-radius:6px;
  background:var(--bg2);
  overflow:hidden;
}
.evidence-kind{
  margin:0;
  padding:.48rem .6rem;
  border-bottom:1px solid var(--line-soft);
  font-family:var(--font-m);
  font-size:.56rem;
  letter-spacing:.13em;
  text-transform:uppercase;
  color:var(--red-hi);
}
.evidence-image-link{
  display:block;
  background:#05080d;
}
.evidence-item--image img,
.evidence-item--video video{
  display:block;
  width:100%;
  height:auto;
  max-height:28rem;
  object-fit:contain;
  background:#05080d;
}
.evidence-item figcaption{
  display:grid;
  gap:.35rem;
  padding:.62rem .68rem .72rem;
  font-family:var(--font-m);
  font-size:.64rem;
  line-height:1.55;
  color:var(--muted);
}
.evidence-context{
  padding-top:.35rem;
  border-top:1px solid var(--line-soft);
  color:var(--faint);
  font-size:.58rem;
}
.evidence-item--code,
.evidence-item--record{padding-bottom:.72rem}
.evidence-item--code h4,
.evidence-item--record h4{
  margin:.72rem .72rem .2rem;
  font-family:var(--font-d);
  font-size:1rem;
  line-height:1.25;
}
.evidence-meta{
  margin:0 .72rem .6rem;
  font-family:var(--font-m);
  font-size:.59rem;
  line-height:1.5;
  color:var(--faint);
}
.evidence-item--code pre{
  margin:.65rem 0 0;
  padding:.75rem;
  max-height:24rem;
  overflow:auto;
  border-block:1px solid var(--line-soft);
  background:#060a10;
  color:#dce8f5;
  tab-size:2;
  font:500 .66rem/1.55 var(--font-m);
  white-space:pre;
}
.evidence-item--code pre:focus-visible{
  outline:2px solid var(--blue);
  outline-offset:-2px;
}
.evidence-item--record ul{
  margin:.65rem .9rem .25rem 1.65rem;
  padding:0;
  color:var(--ink);
  font-size:.78rem;
  line-height:1.55;
}
.evidence-item--record li+li{margin-top:.24rem}
.evidence-caption{
  margin:.65rem .72rem 0;
  font-family:var(--font-m);
  font-size:.61rem;
  line-height:1.55;
  color:var(--muted);
}
.kid .evidence-drawer{margin-right:.2rem}
.kid .evidence-grid{grid-template-columns:1fr}
.pd .evidence-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
html.rm .evidence-drawer>summary,
html.rm .evidence-summary-caret{transition:none}

@media(max-width:720px){
  .evidence-drawer>summary{
    grid-template-columns:auto minmax(0,1fr) auto;
    gap:.5rem;
    padding:.62rem .68rem;
  }
  .evidence-summary-count{font-size:.57rem}
  .evidence-grid,
  .pd .evidence-grid{grid-template-columns:1fr;padding:.62rem;gap:.62rem}
  .evidence-item--image img,
  .evidence-item--video video{max-height:72svh}
}

/* ---------- V36 country flags in the Oyika record ---------- */
.flag{
  display:inline-grid;place-items:center;
  width:24px;height:16px;border-radius:2px;overflow:hidden;
  outline:1px solid var(--line);outline-offset:-1px;
  flex:none;
}
.flag svg{display:block;width:100%;height:100%}
.grp-flags{
  display:inline-flex;gap:.35rem;align-items:center;
  margin:.15rem 0 .1rem;
}
.grp-flags .flag{width:21px;height:14px}
.era-flags{
  margin-top:1rem;padding-top:.85rem;
  border-top:1px dashed var(--line);
}
.era-flags-kicker{
  font-family:var(--font-m);font-size:.62rem;
  letter-spacing:.18em;text-transform:uppercase;
  color:var(--red-hi);margin:0 0 .55rem;
}
.era-flags-row{display:flex;flex-wrap:wrap;gap:.5rem}
.flag-chip{
  display:inline-flex;align-items:center;gap:.5rem;
  padding:.35rem .6rem;border:1px solid var(--line);border-radius:6px;
  background:color-mix(in srgb,var(--plate) 82%,transparent);
}
.flag-copy{display:grid;line-height:1.25}
.flag-name{
  font-family:var(--font-m);font-size:.68rem;font-weight:600;
  letter-spacing:.05em;color:var(--ink);
}
.flag-note{
  font-family:var(--font-m);font-size:.6rem;
  letter-spacing:.04em;color:var(--faint);
}
@media (max-width:560px){
  .era-flags-row{gap:.4rem}
  .flag-chip{padding:.3rem .5rem;gap:.4rem}
}

.grp-flag{font-family:"Apple Color Emoji","Segoe UI Emoji",sans-serif}
.grp-flags{display:inline-flex;align-items:center;gap:.18rem;margin-left:auto;margin-right:.2rem}
.grp-flag{font-size:.9rem;line-height:1}

@media (max-width:700px){
  .grp-flags{margin-left:.35rem;margin-right:0}
}

/* ---------- V36 synthesis: evidence source links ---------- */
.evidence-sources{
  display:grid;
  gap:.38rem;
  margin:.72rem;
}
.evidence-sources a{
  width:fit-content;
  color:var(--blue-hi);
  font-family:var(--font-m);
  font-size:.62rem;
  line-height:1.45;
  text-decoration-thickness:1px;
  text-underline-offset:.2em;
}
.evidence-sources a:hover{color:var(--red-hi)}

/* ---------------- V37: era rail (skim navigation) ---------------- */
.era-rail{position:fixed;left:max(10px,calc(50vw - 46rem));top:50%;transform:translateY(-50%);z-index:40;display:none;flex-direction:column;gap:.35rem;font-size:.62rem;letter-spacing:.07em;text-transform:uppercase;max-width:8rem}
.era-rail a{color:var(--ink-soft,#8a8f98);text-decoration:none;display:flex;gap:.45rem;align-items:baseline;padding:.14rem 0;border-left:2px solid transparent;padding-left:.55rem;transition:color .15s ease,border-color .15s ease}
.era-rail a:hover,.era-rail a.is-active{color:var(--ink,#e8eaed);border-left-color:currentColor}
.era-rail .rail-n{font-variant-numeric:tabular-nums;opacity:.6}
.era-rail .rail-top{margin-bottom:.5rem;font-weight:600}
.era-rail{opacity:0;pointer-events:none;transition:opacity .25s ease}
body.rail-on .era-rail{opacity:1;pointer-events:auto}
@media (min-width:1240px){.era-rail{display:flex}}
.pj-name{overflow-wrap:anywhere}


/* ---------------- V38: media tiers ---------------- */
.plates .plate-pair,.plates .plate-thumbs{grid-column:1 / -1}
.plate-pair{display:grid;grid-template-columns:1fr 1fr;gap:10px;align-items:stretch}
.plate-pair .plate{margin:0;display:flex;flex-direction:column}
.plate-pair .plate img{height:100%;max-height:420px;object-fit:cover}
.plate-thumbs{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px}
.plate-thumbs .plate--thumb{width:118px;margin:0;min-height:0;height:auto;padding:5px;align-self:flex-start}
.plate-thumbs .plate--thumb::before,.plate-thumbs .plate--thumb::after{display:none}
.plate-thumbs .plate--thumb img{width:100%;height:84px;object-fit:cover;border-radius:3px;display:block}
.plate-thumbs .plate--thumb figcaption{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.plate-thumbs .plate--thumb{position:relative}
@media (max-width:640px){.plate-pair{grid-template-columns:1fr}.plate-pair .plate img{max-height:60vh}}

/* V40 reader-state hardening */
.sr-only { position:absolute!important; width:1px!important; height:1px!important; padding:0!important; margin:-1px!important; overflow:hidden!important; clip:rect(0,0,0,0)!important; white-space:nowrap!important; border:0!important; }
.grp-toggle { position:absolute; inset:0; z-index:2; width:100%; border:0; border-radius:inherit; background:transparent; color:inherit; cursor:pointer; }
.grp-toggle:focus-visible { outline:2px solid var(--red-hi); outline-offset:3px; }
.grp[data-open] > .grp-head .grp-caret { transform:rotate(180deg); border-color:color-mix(in srgb,var(--red) 45%,transparent); }
.pj-open { position:absolute; inset:0; z-index:1; width:100%; border:0; border-radius:inherit; background:transparent; cursor:pointer; }
.pj:has(.pj-open:focus-visible) { outline:2px solid var(--red-hi); outline-offset:3px; }
.pj-links { position:relative; z-index:2; }
.pd h2 { font-family:var(--font-d); font-variation-settings:"wdth" 114; font-weight:800; font-size:clamp(1.4rem,3vw,2rem); line-height:1.1; margin:.45rem 0 .7rem; }
.load-state { min-height:70vh; display:grid; align-content:center; max-width:46rem; padding:8rem 0; }
.load-state h1 { margin:0 0 1rem; font-family:var(--sans); font-size:clamp(2.4rem,7vw,5.5rem); line-height:.9; }
.load-state p { margin:0; max-width:38rem; font-size:1.15rem; color:var(--muted); }
