@font-face{font-family:'iA Writer Quattro S';src:url(/fonts/iAWriterQuattroS-Regular.woff2) format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'iA Writer Quattro S';src:url(/fonts/iAWriterQuattroS-Italic.woff2) format('woff2');font-weight:400;font-style:italic;font-display:swap}
@font-face{font-family:'iA Writer Quattro S';src:url(/fonts/iAWriterQuattroS-Bold.woff2) format('woff2');font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:'iA Writer Quattro S';src:url(/fonts/iAWriterQuattroS-BoldItalic.woff2) format('woff2');font-weight:700;font-style:italic;font-display:swap}
:root{
  /* Height of the sticky bar. Anything else that pins to the top of the
     viewport has to subtract it, because the bar sits at top:0 with z-index 30
     and never hides — so that band is never available to anything below it.
     Set from the bar's measured height at runtime; this value is what it
     measures on a desktop row, and is the fallback before script runs. */
  --bar-h:53px;
  --bg:#1b1814; --veil-rgb:27,24,20; --surface:#29241e; --surface-hover:#2e2821;
  --fg:#f6f0e6; --heading:#ece4d6; --prose:#a99f91; --muted:#978d80; --nav-muted:#978d80; --faint:#70675d;
  --line:rgba(246,240,230,.16); --line2:rgba(246,240,230,.09); --imgbg:#26211c;
  --barbg:rgba(27,24,20,.76); --barbg2:rgba(27,24,20,.94);
  --accent:#637bea; --radius:10px;
  --measure:680px; --wide:1104px;
  /* One value owns every section break. No block type contributes trailing
     space (see .chapter below), so this is the whole gap. Tune a single break
     with --break-adjust rather than changing this. */
  --break:clamp(72px,10vh,116px);
  --mono:'iA Writer Quattro S',ui-monospace,monospace;
  --display:'Archivo','Helvetica Neue',Helvetica,Arial,sans-serif;
  --body:-apple-system,BlinkMacSystemFont,'SF Pro Text','SF Pro Display','Helvetica Neue',Arial,sans-serif;
  color-scheme:dark light;
}
@media (prefers-color-scheme:light){
  :root{
    --bg:#f4f3ef; --veil-rgb:244,243,239; --surface:#fffefa; --surface-hover:#ffffff;
    --fg:#171715; --heading:#2e2a24; --prose:#5b564d; --muted:#726d65; --nav-muted:#6a655c; --faint:#a29b90;
    --line:rgba(35,31,25,.17); --line2:rgba(35,31,25,.09); --imgbg:#e7e3da;
    --barbg:rgba(244,243,239,.78); --barbg2:rgba(244,243,239,.94);
    --accent:#294dbd;
  }
}
*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{background:var(--bg);color:var(--fg);font-family:var(--body);min-height:100vh}
h1,h2,h3,h4,h5,h6{font-family:var(--display)}
::selection{background:var(--accent);color:#fff}
a{color:inherit;text-decoration:none}
button{border:none;background:none;cursor:pointer;font:inherit;color:inherit}
img,video{max-width:100%}
picture{display:contents}
a:focus-visible,button:focus-visible{outline:2px solid var(--accent);outline-offset:5px;border-radius:var(--radius)}

.mark{display:flex;flex-direction:row;align-items:baseline;gap:2px;width:max-content;line-height:.82;letter-spacing:-.03em;font-family:var(--display);font-size:22px}
.mk-a{font:600 1em/.82 var(--display);letter-spacing:-.03em;color:var(--fg)}
.mk-dot{font:600 1.2em/.82 var(--display);letter-spacing:-.03em;color:var(--accent)}
.mk-b{font:300 1em/.82 var(--display);letter-spacing:-.03em;color:var(--muted)}
.mk-a,.mk-dot,.mk-b{transition:color .18s ease}
.mark:hover .mk-a{color:var(--accent)}
.mark:hover .mk-b{color:var(--heading)}

.bar{position:sticky;top:0;z-index:30;background:linear-gradient(180deg,var(--barbg2),var(--barbg));backdrop-filter:saturate(140%) blur(14px);-webkit-backdrop-filter:saturate(140%) blur(14px);border-bottom:1px solid var(--line)}
.bar-in{display:flex;align-items:center;gap:16px;max-width:1240px;min-height:52px;margin:0 auto;padding:14px 48px}
.bar-nav{display:flex;align-items:center;gap:20px;margin-left:auto}
.bar-link{font:500 12px/1 var(--display);letter-spacing:.01em;color:var(--nav-muted);padding:6px 0;transition:color .2s ease}
.bar-link:hover{color:var(--heading)}
.bar-link[aria-current="true"]{color:var(--accent)}

/* ---------- intro ---------- */
.prose{max-width:var(--measure);margin:0 auto;padding:0 24px}
.intro-eyebrow{font:500 11px/1 var(--mono);letter-spacing:.2em;color:var(--muted);text-transform:uppercase;margin-bottom:26px}
.intro-eyebrow .n{color:var(--accent)}
.v2-h1{font:600 clamp(60px,9vw,116px)/.92 var(--display);letter-spacing:-.05em;color:var(--heading);margin-bottom:24px;text-wrap:pretty}
.v2-lede{font:600 clamp(24px,2.4vw,34px)/1.22 var(--display);letter-spacing:-.03em;color:var(--heading);max-width:24ch;text-wrap:balance}
.v2-lede .acc{display:block}
.v2-lede strong{color:var(--fg);font-weight:600}

.hero-full{width:100%;height:clamp(340px,43vw,560px);overflow:hidden;background:var(--imgbg);font-size:0}
.hero-full img{display:block;width:100%;height:100%;object-fit:cover;object-position:center}
body[data-artifact="amalgam"] .hero-full img{object-position:center 65%}
.v2-intro{padding:clamp(48px,8vh,88px) 0 0}

/* ---------- chapters ---------- */
.chapter{padding-top:calc(var(--break) + var(--break-adjust,0px));scroll-margin-top:64px}
/* A break is --break and nothing else. Blocks keep the bottom margin that
   spaces them from a following sibling, but the last one in a section gives it
   up — otherwise the gap depends on whether the section happens to end in a
   figure (52px), a paragraph (22px) or a diagram (15px). The second selector
   catches a margin collapsing out through a wrapper such as .prose. */
.chapter > :last-child, .chapter > :last-child > :last-child,
.hl > :last-child, .hl > :last-child > :last-child{margin-bottom:0}
/* The rail keeps its scroller padding so focus rings are not clipped, but that
   padding must not widen the break either. */
.hl > :last-child{margin-bottom:-10px}
/* Tuning one break by eye: a section owns the break above it, so set
   --break-adjust on the section that FOLLOWS the gap you want to change. Takes
   either sign, and leaves every other break alone:
     #the-result{--break-adjust:-24px}   pull that one break tighter
     #specs{--break-adjust:32px}         give that one more air  */
.ch-open{margin-bottom:28px}
.ch-eyebrow{display:flex;align-items:center;gap:14px;font:500 16px/1 var(--mono);letter-spacing:.14em;color:var(--fg);text-transform:uppercase;margin-bottom:20px}
.ch-eyebrow .n{color:var(--accent)}
.ch-eyebrow::before{content:'';width:26px;height:1px;background:var(--accent);flex:none}
.ch-title{position:relative;font:600 clamp(32px,3.6vw,44px)/1.04 var(--display);letter-spacing:-.04em;color:var(--heading);text-wrap:balance}
.ch-title[tabindex="-1"]:focus{outline:none}
.ch-title::before{content:'';position:absolute;left:-40px;top:.52em;width:26px;height:2px;background:var(--accent);transform:translateY(-50%)}
.ch-statement{font:400 clamp(20px,2vw,24px)/1.4 var(--body);letter-spacing:-.015em;color:var(--muted);max-width:40ch;margin:17px 0 0;text-wrap:balance}
.closer{font:600 clamp(24px,2.8vw,34px)/1.3 var(--display);letter-spacing:-.03em;color:var(--heading);text-wrap:balance;margin:44px 0 8px}
.closer strong{color:var(--fg)}
.body-p p{font:400 19px/1.72 var(--body);color:var(--prose);margin-bottom:22px;text-wrap:pretty}
.body-p p strong,.pin-beat p strong{color:var(--fg);font-weight:600}
.body-p p.intro{font-size:21px;line-height:1.66}
.body-p h4{font:600 23px/1.25 var(--display);letter-spacing:-.025em;color:var(--heading);margin:34px 0 14px}
.body-p a{border-bottom:1px solid var(--line);color:var(--fg)}
.body-p a:hover{color:var(--accent);border-bottom-color:var(--accent)}
.body-p code{font:400 .88em/1 var(--mono);color:var(--fg)}
.body-p ul{margin:0 0 22px 20px}
.body-p li{font:400 19px/1.72 var(--body);color:var(--prose);margin-bottom:6px}
.body-p em{color:var(--fg)}

/* ---------- figures ---------- */
figure{width:100%;max-width:var(--measure);margin:44px auto 52px;padding:0 24px}
figure.wide{max-width:var(--wide)}
figure.full{max-width:none;padding:0;margin:56px 0 64px}
.fig-frame{overflow:hidden;background:var(--imgbg);border-radius:var(--radius);aspect-ratio:16/9}
.fig-frame.auto{aspect-ratio:auto}
figure.full .fig-frame{border-radius:0;aspect-ratio:2/1!important}
.fig-expand{display:block;width:100%;height:100%;overflow:hidden;border-radius:inherit;font-size:0;cursor:zoom-in}
.fig-expand:focus-visible{outline:none}
.fig-frame img,.fig-frame video{display:block;width:100%;height:100%;object-fit:cover}
.fig-frame.auto img{height:auto}

/* ---------- highlights rail ---------- */
.hl{margin:clamp(44px,6.5vh,68px) 0 0}
.hl .prose{margin-bottom:26px}
.hl-scroller{display:flex;gap:18px;overflow-x:auto;overscroll-behavior-inline:contain;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;padding:4px max(24px,calc(50vw - 316px)) 10px;scroll-padding-inline:max(24px,calc(50vw - 316px));scrollbar-width:none}
.hl-scroller::-webkit-scrollbar{display:none}
.hl-card{flex:0 0 auto;width:min(78vw,440px);scroll-snap-align:start}
.hl-frame{aspect-ratio:3/2;border-radius:var(--radius);overflow:hidden;background:var(--imgbg);font-size:0}
.hl-frame img{display:block;width:100%;height:100%;object-fit:cover}
.hl-meta{padding:16px 10px 0}
.hl-k{font:500 9.5px/1 var(--mono);letter-spacing:.18em;color:var(--faint);text-transform:uppercase;margin-bottom:10px}
.hl-t{font:600 20px/1.25 var(--display);letter-spacing:-.025em;color:var(--heading);text-wrap:pretty}


/* ---------- v3: accent, bento, diagram ---------- */
.acc{color:var(--accent)}

.bento{display:grid;grid-template-columns:1.3fr 1fr;gap:18px;max-width:var(--wide);margin:44px auto 52px;padding:0 24px}
.bento-tile{position:relative;aspect-ratio:3/2;border-radius:calc(var(--radius) + 6px);overflow:hidden;background:var(--imgbg);font-size:0}
.bento-tile:first-child{grid-row:1 / span 2;aspect-ratio:auto}
.bento .bento-tile:nth-child(4){grid-column:1/-1;aspect-ratio:5/2}
.bento-2{grid-template-columns:1fr 1fr}
.bento-2 .bento-tile:first-child{grid-row:auto;aspect-ratio:3/2}
.bento-3{grid-template-columns:1fr 1fr}
.bento-3 .bento-tile:first-child{grid-row:auto;grid-column:1/-1;aspect-ratio:var(--tr,5/2)}
.bento-slot{position:absolute;inset:0;display:grid;place-items:center;font:500 10px var(--mono);letter-spacing:.22em;color:var(--faint)}
.bento-tile .fig-expand{border-radius:0}
.bento-tile img{display:block;width:100%;height:100%;object-fit:cover}
.bento-cap{position:absolute;left:0;right:0;bottom:0;z-index:1;padding:54px 15px 13px;background:linear-gradient(180deg,transparent,rgba(12,10,8,.58));pointer-events:none}
.bento-t{font:400 13px/1.35 var(--body);letter-spacing:0;color:rgba(246,240,230,.94);text-shadow:0 1px 6px rgba(0,0,0,.35);text-wrap:pretty}

.dg{max-width:var(--measure);margin:48px auto 15px;padding:0 24px}
.dg svg{display:block;width:100%;height:auto}
.dg .nd{fill:var(--surface);stroke:var(--line)}
.dg .ic{stroke:var(--muted);fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.dg .icf{fill:var(--muted);stroke:none}
.dg .ic-acc{stroke:var(--accent);fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.dg .enc{fill:none;stroke:var(--line);stroke-dasharray:2 7;stroke-linecap:round}
.dg .encl{font:500 9px var(--mono);letter-spacing:.22em;fill:var(--faint)}
.dg .port{fill:var(--bg);stroke:var(--muted);stroke-width:1.4}
.dg .slot{fill:var(--muted)}
.dg .ed{stroke:var(--faint);stroke-width:1.25;fill:none}
.dg .ar{fill:var(--faint)}
.dg .tk{font:500 10px var(--mono);letter-spacing:.16em;fill:var(--muted)}
.dg .tv{font:600 14px var(--display);letter-spacing:-.01em;fill:var(--heading)}
.dg .ts{font:500 9.5px var(--mono);letter-spacing:.1em;fill:var(--faint)}
.dg .el{font:500 9.5px var(--mono);letter-spacing:.12em;fill:var(--muted)}

/* ---------- exploded view: scroll-scrubbed frame sequence ---------- */
/* Runway height is set in script from the frame count, so scroll distance per
   frame stays fixed however many frames the sequence ships with. These media
   geometry defaults are the authenticated native-4K values now shared by the
   light and dark releases. Schema-5 manifests replace them on the element
   before sizing the runway. */
.xp{margin:0;
  --xp-frame-w:3840;--xp-frame-h:2160;--xp-safe-h:.944444444;--xp-viewport-clearance:75px;
  --xp-visible-w:.793489583;--xp-cad-center-shift:-2.5130208%;
  --xp-veil-t:2.0833333%;--xp-veil-b:3.6574074%;--xp-veil-l:8.984375%;--xp-veil-r:5.46875%;
}
.xp.xp-static{height:auto !important}
/* Back to a viewport-tall pinned block. Sizing it to the frame did remove the
   band of page above and below, but it also pinned the frame against the top of
   the window rather than centred in it, and left the prose below sliding up
   while the sequence was still scrubbing.

   The band was never really the problem: it only read as dead space around a
   box because the frame's backdrop painted a few levels off the page and the
   edge was therefore visible. That is fixed at the source now — see THEMES in
   build_scrub_stream.py — so the band is simply page, continuous with the
   frame's own empty backdrop, and the animation owns the screen while it runs. */
/* Pinned below the bar, not under it. The dynamic-viewport override lets the
   available box follow expanding browser chrome; vh/svh remain ordered
   fallbacks for older engines. The stage is centred inside this whole box, so
   its equal top and bottom clearances do not alter the sticky/runway geometry. */
.xp-sticky{position:sticky;top:var(--bar-h);height:calc(100vh - var(--bar-h));height:calc(100svh - var(--bar-h));height:calc(100dvh - var(--bar-h));display:flex;align-items:center;justify-content:center;overflow:hidden}
.xp.xp-static .xp-sticky{position:static;height:auto;padding:24px 0}
/* The frame ratio comes from the active release. In a short viewport the whole
   frame fits between the two 75px vertical clearances. In a tall viewport its
   authenticated visible-CAD union grows until that union has 75px side
   clearances; only seamless source backdrop is then clipped by this container.

   Width is 100% of the block rather than 100vw because 100vw includes the
   classic scrollbar on the platforms that still have one, which would put a
   horizontal scrollbar on the page to show a strip of backdrop.

   The height cap is the live viewport below the measured bar, less an explicit
   75px at each edge. max(100%, side-fit) means a very narrow window never makes
   the frame smaller than the old full-width layout. The independent translate
   centres the asymmetric CAD union while `transform` remains free for the
   labelled ending's scroll-driven pan. */
.xp-stage{position:relative;flex:none;
  width:min(max(100%, calc(max(0px, calc(100% - var(--xp-viewport-clearance) - var(--xp-viewport-clearance))) / var(--xp-visible-w))), calc(max(0px, calc(100vh - var(--bar-h) - var(--xp-viewport-clearance) - var(--xp-viewport-clearance))) / var(--xp-frame-h) * var(--xp-frame-w)));
  width:min(max(100%, calc(max(0px, calc(100% - var(--xp-viewport-clearance) - var(--xp-viewport-clearance))) / var(--xp-visible-w))), calc(max(0px, calc(100svh - var(--bar-h) - var(--xp-viewport-clearance) - var(--xp-viewport-clearance))) / var(--xp-frame-h) * var(--xp-frame-w)));
  width:min(max(100%, calc(max(0px, calc(100% - var(--xp-viewport-clearance) - var(--xp-viewport-clearance))) / var(--xp-visible-w))), calc(max(0px, calc(100dvh - var(--bar-h) - var(--xp-viewport-clearance) - var(--xp-viewport-clearance))) / var(--xp-frame-h) * var(--xp-frame-w)));
  aspect-ratio:var(--xp-frame-w) / var(--xp-frame-h);
  translate:var(--xp-cad-center-shift) 0;
}
/* object-fit is stated rather than inherited. The two elements have different
   UA defaults — video is contain, img is fill — so any disagreement between the
   stage's ratio and the asset's used to stretch the poster while letterboxing
   the video, and the two swapped at reveal. */
.xp-poster,.xp-video,.xp-still{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain}
/* An opaque video's flat backdrop cannot be made to match a CSS colour. The
   encode round-trips through BT.709 limited-range 4:2:0 and lands a couple of
   levels off on every edge of every frame. Separate source-backdrop sweeps for
   the light and dark releases minimized that offset on Safari, but neither CSS
   triplet is exactly representable on the video lattice. On a wide-gamut
   display it can be further still, since the BT.709 video and the sRGB page
   colour are managed through different transfer curves.

   Painted rather than masked. A mask asks the video's own pixels to fade, which
   a browser may not honour once it promotes video to a hardware overlay plane;
   an element on top forces the ordinary compositing path, and its outermost
   pixel is var(--bg) itself, so the boundary equals the page colour by
   construction. Everything from .xp up to body is transparent, so that is the
   colour actually behind the frame.

   Smoothstep, not linear. A linear ramp has a kink in its slope at both ends
   and the eye amplifies exactly that, which is why 12px of linear feather still
   showed an edge that a 1-2 level step should have hidden. These stops follow
   3t^2-2t^3, leaving and arriving with zero slope.

   Widths are per-edge percentages of the frame, so they scale with it — a fixed
   px feather would eat content where one CSS pixel covers several source
   pixels. The manifest derives each value from the measured alpha clearance of
   every delivered sequence and hover state; the defaults above are the shared
   native-4K contract. */
/* Stills use layers 1–3; being last in the DOM does not put the veil above them. */
.xp-veil{position:absolute;inset:0;z-index:4;pointer-events:none;
  --f-t:var(--xp-veil-t);--f-b:var(--xp-veil-b);--f-l:var(--xp-veil-l);--f-r:var(--xp-veil-r);
  background:
    linear-gradient(to right,rgba(var(--veil-rgb),1) 0,rgba(var(--veil-rgb),0.957) calc(var(--f-l) * .125),rgba(var(--veil-rgb),0.844) calc(var(--f-l) * .250),rgba(var(--veil-rgb),0.684) calc(var(--f-l) * .375),rgba(var(--veil-rgb),0.5) calc(var(--f-l) * .500),rgba(var(--veil-rgb),0.316) calc(var(--f-l) * .625),rgba(var(--veil-rgb),0.156) calc(var(--f-l) * .750),rgba(var(--veil-rgb),0.043) calc(var(--f-l) * .875),rgba(var(--veil-rgb),0) var(--f-l)),
    linear-gradient(to left,rgba(var(--veil-rgb),1) 0,rgba(var(--veil-rgb),0.957) calc(var(--f-r) * .125),rgba(var(--veil-rgb),0.844) calc(var(--f-r) * .250),rgba(var(--veil-rgb),0.684) calc(var(--f-r) * .375),rgba(var(--veil-rgb),0.5) calc(var(--f-r) * .500),rgba(var(--veil-rgb),0.316) calc(var(--f-r) * .625),rgba(var(--veil-rgb),0.156) calc(var(--f-r) * .750),rgba(var(--veil-rgb),0.043) calc(var(--f-r) * .875),rgba(var(--veil-rgb),0) var(--f-r)),
    linear-gradient(to bottom,rgba(var(--veil-rgb),1) 0,rgba(var(--veil-rgb),0.957) calc(var(--f-t) * .125),rgba(var(--veil-rgb),0.844) calc(var(--f-t) * .250),rgba(var(--veil-rgb),0.684) calc(var(--f-t) * .375),rgba(var(--veil-rgb),0.5) calc(var(--f-t) * .500),rgba(var(--veil-rgb),0.316) calc(var(--f-t) * .625),rgba(var(--veil-rgb),0.156) calc(var(--f-t) * .750),rgba(var(--veil-rgb),0.043) calc(var(--f-t) * .875),rgba(var(--veil-rgb),0) var(--f-t)),
    linear-gradient(to top,rgba(var(--veil-rgb),1) 0,rgba(var(--veil-rgb),0.957) calc(var(--f-b) * .125),rgba(var(--veil-rgb),0.844) calc(var(--f-b) * .250),rgba(var(--veil-rgb),0.684) calc(var(--f-b) * .375),rgba(var(--veil-rgb),0.5) calc(var(--f-b) * .500),rgba(var(--veil-rgb),0.316) calc(var(--f-b) * .625),rgba(var(--veil-rgb),0.156) calc(var(--f-b) * .750),rgba(var(--veil-rgb),0.043) calc(var(--f-b) * .875),rgba(var(--veil-rgb),0) var(--f-b));
}
/* A <video poster> is dropped at loadeddata, long before the whole file is
   buffered — which would flash an unpainted element. The poster is a real
   sibling instead, and the video is revealed only once a frame has actually
   been presented. */
.xp-video{opacity:0}
.xp-poster{transition:opacity .2s ease}
.xp.is-ready .xp-video{opacity:1}
.xp.is-ready .xp-poster{opacity:0}
/* One neutral still and one per part, layered above the video and below the
   veil. Hover cuts between parts and fades only to/from the opaque neutral. */
.xp-part-still{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;opacity:0;transition:opacity .22s ease}
.xp-part-still.on{opacity:1}
/* Visual ownership follows the slide, not the bitmap cache's release timer.
   Cut every layer at center, even a fading part or a neutral decoded late. */
.xp:not(.xp-stills-active) .xp-part-still{opacity:0;transition:none}
/* A released source must never expose the browser's missing-image outline. */
.xp-part-still:not([src]){visibility:hidden}
/* Set for one reflow while a covered layer is taken off screen, so the
   removal lands instantly instead of fading out from under its cover. */
.xp-part-still.xp-cut{transition:none}
/* ---------- exploded view: the build stack, named ---------- */
/* Out of flow so the animation begins centred. The runtime positions this
   sibling at a fixed perceived gap from the translated CAD edge. It can sit
   inside the media box where that box contains only seamless source backdrop.
   The device gate makes it measurable before sizing, and visibility handles the
   reveal without changing that measured width. */
/* The vertical padding is hit slop, not spacing: it is what an overshoot past
   the last row travels through before it counts as leaving the list. Vertical
   only — width feeds the distance the frame slides. */
.xp-parts{position:absolute;top:50%;left:0;z-index:1;display:none;width:var(--xp-parts-w,180px);padding:20px 0;transform:translateY(-50%);opacity:0;visibility:hidden;transition:opacity .3s ease,visibility 0s .3s}
.xp.xp-parts-enabled .xp-parts{display:block}
.xp.is-parted .xp-parts{opacity:1;visibility:visible;transition:opacity .3s ease}
.xp.xp-static .xp-parts{display:none}
.xp-parts-list{display:flex;flex-direction:column}
.xp-part{display:flex;flex-direction:column;text-align:left;padding:13px 0 13px 20px}
.xp-part+.xp-part{border-top:1px solid var(--line2)}
.xp-part-k{position:relative;display:block;font:600 15px/1.25 var(--display);letter-spacing:-.02em;color:var(--heading);transition:color .2s ease,transform .22s ease}
.xp-part-k::before{content:"";position:absolute;left:-20px;top:50%;transform:translateY(-50%);width:2px;height:.9em;border-radius:1px;background:var(--accent);opacity:0;transition:opacity .18s ease}
.xp-part.on .xp-part-k{color:var(--accent)}
.xp-part.on .xp-part-k::before{opacity:1}
.xp-part-s{display:block;font:400 12.5px/1.45 var(--body);color:var(--muted);margin-top:3px;transition:transform .22s ease}
/* Keep the promotion through the slide and its reversal grace period. It is
   released with the decoded stills, rather than when the labels fade out. */
.xp.xp-warm .xp-stage{will-change:transform}
.xp-part.on .xp-part-k,.xp-part.on .xp-part-s{transform:translateX(-5px)}
/* ---------- board plates: pill switcher over a drawing sheet ---------- */
.plate{max-width:var(--wide);margin:44px auto 52px;padding:0 24px}
.plate-switch{display:flex;justify-content:center;gap:10px;flex-wrap:wrap;margin-bottom:20px}
.plate-switch-in{position:relative;isolation:isolate;display:flex;gap:4px;background:var(--surface);border:1px solid var(--line2);border-radius:999px;padding:4px}
.plate-switch-in.has-selection::before{content:'';position:absolute;left:0;top:4px;bottom:4px;width:var(--plate-selection-width);transform:translateX(var(--plate-selection-x));border-radius:999px;background:var(--accent);pointer-events:none;transition:transform .18s cubic-bezier(.2,.72,.25,1),width .18s cubic-bezier(.2,.72,.25,1)}
.plate-pill{position:relative;z-index:1;padding:10px 18px;border-radius:999px;font:500 10px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--muted);transition:color .18s ease}
.plate-pill:hover{color:var(--heading)}
.plate-pill[aria-checked="true"]{background:var(--accent);color:#fff}
.plate-switch-in.has-selection .plate-pill[aria-checked="true"]{background:transparent}
.plate-sheet{border:1px solid var(--line);border-radius:calc(var(--radius) + 6px);overflow:hidden;background:var(--surface);box-shadow:0 18px 50px rgba(0,0,0,.14)}
.plate-panel:not([hidden]){animation:plate-in .4s ease}
@keyframes plate-in{from{opacity:0}}
.plate-view{position:relative;aspect-ratio:var(--pr,3/2);background:var(--imgbg);font-size:0}
.plate-view .fig-expand{border-radius:0}
.plate-view img{display:block;width:100%;height:100%;object-fit:cover}

/* ---------- layout anatomy: photo + legend, lit one region at a time ---------- */
.anat{display:grid;grid-template-columns:minmax(0,1fr) max-content;align-items:stretch;column-gap:40px;max-width:var(--wide);margin:44px auto 52px;padding:0 24px}
.anat-media{display:contents}
/* Fill the grid column instead of allowing intrinsic image width to size the frame. */
.anat-frame{position:relative;grid-column:1;width:100%;min-width:0;aspect-ratio:16/9;border-radius:var(--radius);overflow:hidden;background:var(--imgbg);font-size:0}
.anat-frame img{display:block;width:100%;height:100%;object-fit:cover}
/* Both overlays are sized by JS to the painted image box, so their coordinates
   stay percentages of the photo however the frame happens to crop it. */
.anat-spot,.anat-hits{position:absolute;top:0;left:0;pointer-events:none}
.anat-spot g{opacity:0;transition:opacity .35s ease}
.anat-spot g.on{opacity:1}
.anat-hit{position:absolute;pointer-events:auto;cursor:zoom-in}
.anat-side{grid-column:2;display:flex;min-width:0;min-height:0}
.anat-list{display:flex;flex-direction:column;width:100%}
.anat-item{flex:1 1 0;display:flex;flex-direction:column;justify-content:center;min-height:0;white-space:nowrap;text-align:left;padding:14px 0 14px 20px}
.anat-item+.anat-item{border-top:1px solid var(--line2)}
.anat-k{position:relative;display:block;font:600 16px/1.25 var(--display);letter-spacing:-.02em;color:var(--heading);transition:color .2s ease,transform .22s ease}
.anat-k::before{content:"";position:absolute;left:-20px;top:50%;transform:translateY(-50%);width:2px;height:.9em;border-radius:1px;background:var(--accent);opacity:0;transition:opacity .18s ease}
.anat-item.on .anat-k::before{opacity:1}
.anat-item.on .anat-k{color:var(--accent)}
.anat-s{display:block;font:400 13px/1.5 var(--body);color:var(--muted);margin-top:4px;transition:transform .22s ease}
@media (min-width:1120px) and (prefers-reduced-motion:no-preference){
  .anat-item.on .anat-k,.anat-item.on .anat-s{transform:translateX(-5px)}
}
@media (max-width:1119px){
  .anat{display:block}
  .anat-side{margin-top:18px}
  .anat-item{flex:none;white-space:normal}
}

@media (max-width:920px){
  .bento{display:flex;max-width:none;overflow-x:auto;overscroll-behavior-inline:contain;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;padding:4px 24px 10px;scroll-padding-inline:24px;scrollbar-width:none}
  .bento::-webkit-scrollbar{display:none}
  .bento-tile,.bento-tile:first-child,.bento-3 .bento-tile:first-child,.bento .bento-tile:nth-child(4){flex:0 0 auto;width:min(78vw,440px);grid-row:auto;grid-column:auto;aspect-ratio:3/2;scroll-snap-align:start}
}

/* ---------- stats ---------- */
.stats{display:flex;justify-content:space-between;gap:28px;max-width:860px;margin:64px auto;padding:40px 24px;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.stat{flex:1;min-width:0}
.stat-v{font:600 clamp(30px,4.2vw,52px)/1 var(--display);letter-spacing:-.035em;color:var(--heading);white-space:nowrap}
.stat-k{font:500 10px/1.5 var(--mono);letter-spacing:.16em;color:var(--muted);text-transform:uppercase;margin-top:10px}

/* ---------- pinned sequence ---------- */
.pin{display:flex;gap:56px;max-width:1168px;margin:48px auto;padding:0 24px}
.pin-copy{flex:0 0 320px;min-width:0}
.pin-beat{min-height:64vh;display:flex;flex-direction:column;justify-content:center;opacity:.3;transition:opacity .45s ease}
.pin-beat.on{opacity:1}
.pin-beat p{font:400 18px/1.7 var(--body);color:var(--prose);margin-bottom:16px;text-wrap:pretty}
.pin-beat-fig{display:none}
.pin-media{flex:1;min-width:0}
.pin-stage{position:sticky;top:calc(50vh - 31vh);height:62vh;border-radius:var(--radius);overflow:hidden;background:var(--imgbg)}
.pin-img{position:absolute;inset:0;opacity:0;transition:opacity .55s ease;pointer-events:none}
.pin-img.on{opacity:1;pointer-events:auto}
.pin-img .fig-expand{border-radius:0}
.pin-img img{display:block;width:100%;height:100%;object-fit:cover}

/* ---------- video slot ---------- */
.vslot{max-width:var(--wide);margin:52px auto 52px;padding:0 24px}
.vslot-frame{position:relative;border-radius:var(--radius);overflow:hidden;background:var(--imgbg);aspect-ratio:16/9}
.vslot-frame img{display:block;width:100%;height:100%;object-fit:cover;filter:brightness(.42) saturate(.8)}
.vslot-frame video{display:block;width:100%;height:100%;object-fit:cover}
.vslot-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:18px}
.vslot-play{display:grid;place-items:center;width:74px;height:74px;border:1px solid rgba(246,240,230,.5);border-radius:50%}
.vslot-play::before{content:'';display:block;width:0;height:0;margin-left:5px;border-style:solid;border-width:11px 0 11px 18px;border-color:transparent transparent transparent rgba(246,240,230,.92)}
.vslot-t{font:500 12px/1 var(--mono);letter-spacing:.22em;color:rgba(246,240,230,.92);text-transform:uppercase}
.vslot-s{font:500 9.5px/1 var(--mono);letter-spacing:.18em;color:rgba(246,240,230,.5);text-transform:uppercase}

/* ---------- spec sheet ---------- */
.specs-wrap{max-width:860px;margin:0 auto;padding:0 24px}
.specs{border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);padding:10px 36px;box-shadow:0 18px 50px rgba(0,0,0,.14)}
.spec{display:grid;grid-template-columns:minmax(120px,180px) 1fr;gap:28px;align-items:baseline;padding:20px 0}
.spec+.spec{border-top:1px solid var(--line2)}
.spec-k{font:500 10px/1.4 var(--mono);letter-spacing:.16em;color:var(--muted);text-transform:uppercase}
.spec-v{font:400 16px/1.6 var(--body);color:var(--fg)}

/* ---------- next artifact ---------- */
.next{display:flex;align-items:stretch;gap:0;max-width:812px;margin:clamp(88px,13vh,150px) auto 0;border:1px solid var(--line2);border-radius:calc(var(--radius) + 8px);background:var(--surface);overflow:hidden;transition:background-color .25s ease,border-color .25s ease,transform .25s ease}
.next-txt{flex:1;display:flex;flex-direction:column;justify-content:center;gap:14px;padding:44px 48px}
.next-eyebrow{font:500 10px/1 var(--mono);letter-spacing:.18em;color:var(--muted);text-transform:uppercase}
.next-eyebrow .n{color:var(--accent)}
.next-name{font:600 clamp(34px,4vw,52px)/1 var(--display);letter-spacing:-.04em;color:var(--heading);transition:color .2s ease}
.next-sum{font:400 16px/1.5 var(--body);color:var(--prose)}
.next-cta{font:500 13px/1 var(--body);color:var(--muted);margin-top:8px;transition:color .2s ease}
.next-img{flex:0 0 44%;min-height:280px;background:var(--imgbg);font-size:0}
.next-img img{display:block;width:100%;height:100%;object-fit:cover}
.next-soon{cursor:default}
.next-soon .next-img img{filter:blur(clamp(6px,.7vw,9px)) saturate(.72);transform:scale(1.25)}
.next-soon .next-name{color:var(--muted)}
.next-soon .next-cta{align-self:flex-start;font:500 10px/1 var(--mono);letter-spacing:.14em;color:var(--faint);text-transform:uppercase;border:1px solid var(--line);border-radius:999px;padding:9px 13px;margin-top:4px}
@media (min-width:921px) and (hover:hover) and (pointer:fine){
  .next:not(.next-soon):hover{background:var(--surface-hover);border-color:var(--line);transform:translateY(-2px)}
  .next:not(.next-soon):hover .next-name{color:var(--accent)}
  .next:not(.next-soon):hover .next-cta{color:var(--accent)}
}

.foot{border-top:1px solid var(--line);margin-top:clamp(88px,12vh,140px)}
.foot-in{display:flex;align-items:center;justify-content:center;gap:20px;flex-wrap:wrap;padding:44px 48px}
.foot-t{font:500 11px/1.7 var(--mono);letter-spacing:.1em;color:var(--muted);text-transform:uppercase}
.foot-t a{transition:color .2s ease}
.foot-t a:hover{color:var(--accent)}
.foot-dot{width:3px;height:3px;border-radius:50%;background:var(--faint);flex:none}

/* ---------- reveal on scroll ---------- */
.rv{opacity:0;transform:translateY(16px);transition:opacity .7s ease,transform .7s cubic-bezier(.2,.6,.2,1)}
.rv.in{opacity:1;transform:none}
.rail-reveal>[data-rail-item]{opacity:0;transform:translateY(30px);transition:opacity .9s cubic-bezier(.455,.03,.515,.955),transform .7s cubic-bezier(.455,.03,.515,.955);transition-delay:calc(var(--rail-item-index,0)*150ms)}
.rail-reveal.in>[data-rail-item]{opacity:1;transform:none}

/* ---------- lightbox ---------- */
body.lightbox-open{overflow:hidden}
.lightbox{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:48px;background:rgba(12,10,8,.92);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);opacity:0;visibility:hidden;transition:opacity .22s ease,visibility .22s ease;cursor:zoom-out}
.lightbox[hidden]{display:none}
.lightbox.is-open{opacity:1;visibility:visible}
.lightbox-image{display:block;flex:none;max-width:none;max-height:none;width:0;height:0;border-radius:var(--radius);box-shadow:0 28px 90px rgba(0,0,0,.42);opacity:0;transform:translate(0,0);transition:opacity .22s ease;cursor:zoom-in}
.lightbox.is-open .lightbox-image.is-ready{opacity:1}
.lightbox-image.is-zoomed{cursor:zoom-out;touch-action:none}
.lightbox-image.is-dragging{cursor:grabbing}
.lightbox-close{position:fixed;top:22px;right:22px;z-index:1;display:grid;place-items:center;width:44px;height:44px;border:1px solid rgba(255,255,255,.22);border-radius:50%;background:rgba(27,24,20,.78);color:#fff;font:300 28px/1 var(--body);transition:color .2s ease,background-color .2s ease,border-color .2s ease,transform .2s ease}
.lightbox-close:focus-visible{outline:none}
.lightbox-close:hover{color:var(--accent);background:var(--surface);border-color:var(--accent);transform:scale(1.04)}

/* Big displays: hold the prose measure, let the media canvas breathe */
@media (min-width:1600px){
  :root{--wide:1320px}
  .pin{max-width:1384px}
}
@media (max-width:1023px){
  .bar-nav{display:none}
}
@media (max-width:920px){
  .bar-in{padding:14px 24px}
  .v2-intro{padding-top:44px}
  .hero-full{height:300px}
  .chapter{padding-top:72px}
  figure{margin:32px auto 44px}
  figure.full .fig-frame{aspect-ratio:3/2!important}
  .stats{flex-wrap:wrap;gap:24px;margin:44px auto;padding:28px 24px}
  .stat{flex:1 1 38%}
  .pin{display:block;margin:32px auto}
  .pin-copy{max-width:var(--measure);margin:0 auto}
  .pin-media{display:none}
  .pin-beat{min-height:0;opacity:1;display:block;margin-bottom:40px}
  .pin-beat-fig{display:block;margin-bottom:18px;border-radius:var(--radius);overflow:hidden;background:var(--imgbg);aspect-ratio:3/2;font-size:0}
  .pin-beat-fig .fig-expand{border-radius:0}
  .pin-beat-fig img{display:block;width:100%;height:100%;object-fit:cover}
  .specs{padding:8px 22px}
  .spec{grid-template-columns:minmax(0,1fr);gap:7px;align-items:start;padding:18px 0}
  .next{flex-direction:column-reverse;margin-top:72px}
  .next-txt{padding:28px 24px 32px}
  .next-img{min-height:0;aspect-ratio:3/2}
  .foot-in{padding:36px 24px}
  .lightbox{padding:16px}
  .lightbox-close{top:14px;right:14px}
}
@media (max-width:860px){
  .next{margin-left:24px;margin-right:24px}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .plate-switch-in.has-selection::before{transition:none}
  *,*::before,*::after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}
}
@media (hover:none), (pointer:coarse){
  .fig-expand,.lightbox-close{-webkit-tap-highlight-color:transparent}
}
