/* Experimental features (branch ideas-preview). Each block is keyed to a switch in portfolio_source/features.py.
   Cut a feature: switch it off, rebuild, then delete its block here and in features.js. */

:root{--fx-amber:#FFB547;--fx-amber-2:#FFD08A;--fx-holo-2:#8fc1ff;--fx-edge:#cfd6e2;--fx-edge-ink:#5d6570;--fx-space:#06070a;--fx-led-bg:#070707;--fx-led-bg-2:#161616;--fx-led-label:#a07b47;--fx-led-dot:#5a4526;--fx-lbl:#cfd3da;--fx-lbl-2:#9aa0a9;--fx-lbl-3:#6c727b;--fx-star-ink:#9a9486;--fx-belt-ink:#6f695d;--fx-belt:#8d8676;--fx-holo-ink:#3f6fb0;--fx-amber-ink:#b8741f;--fx-red:#C62F1E;--fx-amber-rgb:255 181 71;--fx-amber-2-rgb:255 208 138;--fx-ember-rgb:255 120 40;--fx-black:#050506;--fx-white:#f4f2ec}
:root{--doto:"Doto","Geist Mono",monospace;--hud:var(--live)}
.fx-dn{font-family:"Handjet",var(--mono);font-variation-settings:"ELSH" 2,"ELGR" 2;font-weight:400;letter-spacing:.035em}   /* finer dot grid for numerals */

/* ---------- shared: text for screen readers only (split-flap, HUD, status pill) ---------- */
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}

/* ---------- placeholders (never ship) ---------- */
.ph{outline:1px dashed var(--live);outline-offset:3px}
p.ph,td.ph{color:var(--live)!important;font-style:italic}

/* ---------- status pill (status_pill) ---------- */
.fx-status{display:inline-flex;align-items:center;gap:8px;font:11px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--text-2);
  border:1px solid var(--line-2);border-radius:999px;padding:6px 12px;white-space:nowrap;margin-left:16px}
.fx-status::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--ok);box-shadow:0 0 8px color-mix(in srgb,var(--ok) 60%,transparent)}
@media (max-width:1240px){.fx-status{display:none}}

/* ---------- theme toggle (theme_1975) ---------- */
.fx-theme{all:unset;cursor:pointer;font:11px var(--mono);letter-spacing:.1em;color:var(--muted);padding:8px 6px;margin-left:12px;white-space:nowrap}
.fx-theme b{color:var(--text);font-weight:500}
.fx-theme{display:inline-flex;align-items:center;gap:6px;text-transform:uppercase}
.fx-theme .ic{width:14px;height:14px;flex:none;fill:none;stroke:var(--text);stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round}
.fx-theme .ic path[d^="M13.5"]{fill:var(--text);stroke:none}
.fx-theme:hover .ic,.fx-theme:focus-visible .ic{stroke:var(--live)}
/* theme change: the new theme grows out of the switch as a circle; the old one holds still underneath */
html.vt-theme::view-transition-old(root){animation:none;mix-blend-mode:normal}
html.vt-theme::view-transition-new(root){mix-blend-mode:normal;animation:vt-reveal .7s cubic-bezier(.4,0,.25,1) both}
@keyframes vt-reveal{from{clip-path:circle(0 at var(--vt-x) var(--vt-y))}to{clip-path:circle(var(--vt-r) at var(--vt-x) var(--vt-y))}}
.fx-theme .ic{animation:ic-in .5s cubic-bezier(.3,1.4,.5,1) both}   /* the sun or moon turns into place as it swaps */
@keyframes ic-in{from{transform:rotate(-90deg) scale(.4);opacity:0}to{transform:none;opacity:1}}
@media (prefers-reduced-motion:reduce){.fx-theme .ic{animation:none}}
.fx-theme:hover .ic path[d^="M13.5"],.fx-theme:focus-visible .ic path[d^="M13.5"]{fill:var(--live)}
.fx-theme:hover b,.fx-theme:focus-visible b{color:var(--live)}

/* ---------- hero dot field (dot_field) ---------- */
.fx-dotfield{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:var(--z-raise)}
@media (max-width:860px){.fx-dotfield{height:56svh}}

/* ---------- flight HUD (flight_hud, phosphor_hud) ---------- */
@property --alt{syntax:'<integer>';inherits:true;initial-value:0}
@property --tsec{syntax:'<integer>';inherits:true;initial-value:0}
.fx-hud{position:fixed;left:max(14px,env(safe-area-inset-left));bottom:max(14px,env(safe-area-inset-bottom));z-index:var(--z-nav);
  display:grid;gap:3px;font:10.5px/1.25 var(--mono);letter-spacing:.1em;color:var(--text-2);padding:9px 11px 10px;min-width:150px;
  background:color-mix(in srgb,var(--void) 78%,transparent);border:1px solid var(--line);backdrop-filter:blur(6px);pointer-events:none}
.fx-hud .h-ph{color:var(--text);font-weight:500}
.fx-hud .h-alt b::after{content:counter(alt)}
.fx-hud .h-t b::after{content:counter(tsec) " s"}
.fx-hud .h-alt b,.fx-hud .h-t b{font-weight:500;color:var(--text)}
.fx-hud .h-bar{display:block;height:2px;background:var(--line);margin-top:4px}.fx-hud .h-bar i{display:block;height:100%;width:100%;background:var(--live);transform-origin:left;transform:scaleX(0)}
.fx-hud{counter-reset:alt var(--alt) tsec var(--tsec)}
@supports (animation-timeline: scroll()){
  .fx-hud .h-bar i{animation:fx-bar linear both;animation-timeline:scroll(root)}
}
@keyframes fx-bar{to{transform:scaleX(1)}}
html.on-dot-numerals .fx-hud b{font-family:"Handjet",var(--mono);font-variation-settings:"ELSH" 2,"ELGR" 2;font-size:15px;font-weight:500;font-variant-numeric:tabular-nums;display:inline-block;min-width:3ch;text-align:right}
html.on-dot-numerals .fx-hud .h-t b{min-width:4.6ch}
html.on-phosphor-hud .fx-hud b{text-shadow:none}
html.on-phosphor-hud .fx-hud{color:var(--fx-amber);border-color:color-mix(in srgb,var(--fx-amber) 35%,transparent);background:rgb(var(--scrim-rgb) / .86);
  text-shadow:0 0 6px rgb(var(--fx-amber-rgb) / .55)}
html.on-phosphor-hud .fx-hud .h-ph,html.on-phosphor-hud .fx-hud b{color:var(--fx-amber-2)}
html.on-phosphor-hud .fx-hud::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(0deg,rgb(var(--shade-rgb) / .22) 0 1px,transparent 1px 3px)}
/* The HUD lives in the side gutter only: shown where the gutter is wide enough to hold it clear of the content. */
@media (max-width:1439px){.fx-hud{display:none}}
@media (min-width:1440px){.fx-hud{min-width:118px;padding:8px 9px 9px;left:12px}}

/* ---------- split-flap letters (split_flap) ---------- */
.flap-c{display:inline-block;text-align:center}
.flap-c.go{animation:fx-flap .08s steps(2) 3}
@keyframes fx-flap{50%{transform:scaleY(.2)}}

/* ---------- ticker (ticker, led_ticker): a flight-board strip that never stops ---------- */
.fx-ticker{overflow:hidden;border-block:1px solid var(--line);background:var(--panel);
  -webkit-mask:linear-gradient(90deg,transparent,var(--fx-black) 6%,var(--fx-black) 94%,transparent);mask:linear-gradient(90deg,transparent,var(--fx-black) 6%,var(--fx-black) 94%,transparent)}
.fx-ticker-in{display:flex;width:max-content;animation:fx-marquee 70s linear infinite}
.tk-run{display:flex;white-space:nowrap}
@keyframes fx-marquee{to{transform:translateX(-50%)}}
.tk{display:inline-flex;align-items:baseline;gap:12px;padding:11px 26px;font:11px var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--text)}
.tk::after{content:"";width:4px;height:4px;border-radius:50%;background:var(--line-2);margin-left:26px;align-self:center}
.tk i{font-style:normal;color:var(--muted);font-size:9.5px}
.tk b{font-weight:inherit}
.fx-ticker.led{background:var(--fx-led-bg)}
.fx-ticker.led .tk{font-family:var(--doto);font-weight:700;font-size:15px;letter-spacing:.1em;color:var(--fx-amber);text-shadow:0 0 6px rgb(var(--fx-amber-rgb) / .55);padding-block:9px}
.fx-ticker.led .tk i{font-family:var(--mono);font-weight:400;font-size:9.5px;letter-spacing:.16em;color:var(--fx-led-label);text-shadow:none}   /* 5.2:1 on var(--fx-led-bg) */
.fx-ticker.led .tk::after{background:var(--fx-led-dot)}

/* ---------- spec strips on tiles (spec_strips) ---------- */
.fx-spec{display:block;margin-top:8px;font:11px/1.4 var(--mono);letter-spacing:.04em;color:var(--text-2)}
html.on-dot-numerals .fx-spec{font-family:"Handjet",var(--mono);font-variation-settings:"ELSH" 2,"ELGR" 2;font-size:16px;font-weight:400;letter-spacing:.04em}
.tile{position:relative}

/* ---------- telemetry dot plot (telemetry, off until real data exists) ---------- */
.fx-telemetry{margin:28px 0 0;border:1px solid var(--line);padding:16px;background:var(--panel)}
.fx-telemetry svg{width:100%;height:auto;display:block}
.fx-telemetry .grid line{stroke:var(--line-2);stroke-width:.6;stroke-dasharray:2 3}
.fx-telemetry .dots circle{fill:var(--live);opacity:0;transition:opacity .2s}
.fx-telemetry.in .dots circle{opacity:1;transition-delay:calc(var(--i,0) * 6ms)}
.fx-telemetry figcaption{font:11.5px/1.5 var(--mono);color:var(--muted);margin-top:10px}
.fx-telemetry figcaption b{color:var(--live)}

/* ---------- build log (build_log) ---------- */
.fx-buildlog{margin-top:22px;border-top:1px solid var(--line);padding-top:14px}
.fx-buildlog ol{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:7px}
.fx-buildlog li{display:grid;grid-template-columns:80px 1fr;gap:12px;font-size:14px;color:var(--text-2)}
.fx-buildlog .bl-d{font:11.5px var(--mono);color:var(--muted);padding-top:2px}

/* ---------- credentials (credentials) ---------- */
.fx-creds{margin-top:40px;display:grid;grid-template-columns:3fr 2fr;gap:28px}
.cr-g ul{list-style:none;margin:10px 0 0;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));border-top:1px solid var(--line);border-left:1px solid var(--line)}
.cr{position:relative;display:flex;flex-direction:column;gap:6px;padding:16px 16px 18px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);min-height:128px;transition:background .2s}
.cr:hover{background:var(--panel)}
.cr-ic{width:26px;height:26px;color:var(--text-2);margin-bottom:6px}
.cr:hover .cr-ic{color:var(--live)}
.cr-n{font:600 17px/1.1 var(--disp);letter-spacing:.05em;text-transform:uppercase;color:var(--text)}
.cr-i{font:11px/1.45 var(--mono);letter-spacing:.04em;color:var(--muted)}
@media (max-width:760px){.fx-creds{grid-template-columns:1fr}.cr-g ul{grid-template-columns:1fr 1fr}.cr{min-height:112px;padding:14px}}

/* ---------- case notes + next thumbnails (case_notes, next_thumbs) ---------- */
.fx-notes{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:48px;padding-top:22px;border-top:1px solid var(--line)}
.fx-notes p{margin-top:8px;color:var(--text-2)}
@media (max-width:700px){.fx-notes{grid-template-columns:1fr}}
.fx-nthumb{width:min(220px,100%);aspect-ratio:16/9;object-fit:cover;display:block;margin-bottom:10px;border:1px solid var(--line)}
nav.next a:last-child .fx-nthumb{margin-left:auto}

/* ---------- halftone reveal (halftone): features.js draws a real halftone of the photo on a canvas, then cross-fades ---------- */
.gallery figure.ht-wait img{opacity:0}
.gallery figure.ht-run img{opacity:1;transition:opacity .35s ease .3s,transform .5s ease,filter .3s}
.ht-cv{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;transition:opacity .3s ease}
.ht-cv.out{opacity:0}

/* ---------- dot-matrix numerals (dot_numerals) ---------- */
html.on-dot-numerals .readouts .v,html.on-dot-numerals .tl-strip .sd .v,html.on-dot-numerals .specs .sd .v,html.on-dot-numerals .badge .bx{
  font-family:"Handjet",var(--mono);font-variation-settings:"ELSH" 2,"ELGR" 2;font-weight:500;letter-spacing:.035em}

/* ---------- easter egg (easter_egg) ---------- */
.fx-rocket{position:fixed;z-index:var(--z-lightbox);width:22px;height:48px;pointer-events:none}
.fx-rocket svg{width:100%;height:100%}
.fx-count{position:fixed;left:50%;top:40%;transform:translate(-50%,-50%);z-index:var(--z-lightbox);font:700 72px var(--doto);color:var(--live);
  text-shadow:0 0 18px color-mix(in srgb,var(--live) 60%,transparent);pointer-events:none}

/* ---------- viewer buttons in their on state (Explode) ---------- */
.viewer .views button.on{color:var(--live);border-color:var(--live)}

/* ---------- review page ---------- */
.fx-review{width:100%;border-collapse:collapse;margin-top:28px;font-size:14px}
.fx-review th{font:10.5px var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--muted);text-align:left;padding:8px;border-bottom:1px solid var(--line-2)}
.fx-review td{padding:10px 8px;border-bottom:1px solid var(--line);color:var(--text-2);vertical-align:top}
.fx-review td:first-child a{color:var(--text)}
.fx-review tr.off td{opacity:.45}
.fx-review code{font:11px var(--mono);color:var(--muted)}

/* ---------- one format for both modes (Sterling, 2026-09-28): Helvetica headings in sentence case ---------- */
:root{--sans:"Helvetica Neue",Helvetica,Arial,sans-serif;--disp:"Helvetica Neue",Helvetica,Arial,sans-serif}
.disp{font-weight:700;letter-spacing:-.01em;text-transform:none}
:is(h1,h2,h3,h4):not(.label),:is(.proof3 b,.ev-t){text-transform:none;letter-spacing:-.01em}   /* small mono labels stay caps */

/* ---------- R13: 1975 theme = the light mode (paper white, NASA-manual red); colors only ---------- */
html[data-theme="1975"]{
  --void:#F3F2EE;--panel:#ECEAE4;--panel-2:#E4E1D9;--line:#D6D3CA;--line-2:#BFBBB0;
  --text:var(--fx-led-bg-2);--text-2:#3C3C3C;--muted:#5E5E5E;--faint:#A29E94;--dim:#7C7C7C;--live:var(--fx-red);--done:var(--fx-led-bg-2);
  --shade-rgb:60 50 40;--panel-rgb:236 234 228;color-scheme:light}
/* Book spines and covers are artwork, not page chrome: they keep the standard theme's type and colors in 1975 too,
   so every book looks the same in both modes (and long titles fit on a phone). */
:is(.book,.cover){--disp:"Barlow Condensed","Arial Narrow",system-ui,sans-serif;--sans:"Geist",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif}
html[data-theme="1975"] :is(.book,.cover){
  --text:#ECECEA;--text-2:#B4B5B2;--muted:#85878A;--line:#232426;--line-2:#2E3033;--live:#E3A23B;
  --shade-rgb:4 4 5;--glint-rgb:250 250 248;color:var(--text)}
/* 1975 sky: the same stars and rare objects as STD, drawn in ink. Inverting the (transparent) canvases turns light
   points into dark ones; the 180 degree hue turn keeps amber amber and blue blue. */
html[data-theme="1975"] .fx-rare{filter:invert(1) hue-rotate(180deg)}   /* the page and shelf stars draw their own ink colors (site.js starRGB) */
/* 1975 bookshelf: a warm paper glow instead of the dark steel night sky, and a lighter dim on the books not picked */
html[data-theme="1975"] .shelf-wrap{background:radial-gradient(120% 90% at 50% 0%,#FFFDF6 0%,#F1EEE6 55%,var(--void) 100%)}
html[data-theme="1975"] .shelf:has(.book.on) .book:not(.on){filter:brightness(.88) saturate(.9)}
html[data-theme="1975"] img.invert{filter:none}
html[data-theme="1975"] .nav .brand .mk{border-color:var(--live);color:var(--live)}
html[data-theme="1975"] .btn.solid{background:var(--live);border-color:var(--live);color:var(--fx-white)}
html[data-theme="1975"] .fx-ticker.led{background:var(--fx-led-bg-2)}
html[data-theme="1975"] ::selection{background:var(--fx-red);color:var(--fx-white)}
html[data-theme="1975"] .plate-dwg img{filter:invert(1) brightness(.55) contrast(1.4)}   /* white line art becomes ink on paper */
html[data-theme="1975"] .sol-star{fill:var(--fx-star-ink)}
html[data-theme="1975"] .sol-belt{stroke:var(--fx-belt-ink)}
html[data-theme="1975"] .sol-orbit.hot{stroke:var(--live)}

/* ---------- hero resolve (hero_resolve): every page load, ~1.8 s, never blocks the page ----------
   hr-play (set before first paint) holds the start state; hr-run (set by the script once the page is really on screen
   and the photo has loaded) starts the clock, so a slow first paint never eats the animation */
html.hr-play .hero-photo::after{content:"";position:absolute;inset:0;background:var(--void);z-index:0;transition:opacity .6s ease}   /* the photo paints at once underneath (largest paint); this cover hides it until the reveal */
html.hr-play .hero-photo.hr-done::after{opacity:0}html.hr-play .hero-photo.hr-now::after{transition:none}
html.hr-play .hero-photo::before{z-index:var(--z-raise-2)}   /* edge gradient stays over the dot canvas during the reveal */
.hr-cv{position:absolute;inset:0;width:100%;height:100%;display:block;filter:saturate(.92) contrast(1.04);pointer-events:none;z-index:var(--z-raise)}
@media (min-width:761px){html.anim .hero-photo .hr-cv{transform:scale(1.08)}}
@supports (animation-timeline: scroll()){@media (min-width:761px){html.anim .hero-photo .hr-cv{animation:hero-drift linear both;animation-timeline:scroll(root);animation-range:0 120vh}}}
.hr-c{display:inline-block;text-align:center;clip-path:inset(-.25em 0)}   /* each letter stays in its slot */
.hr-c.scr{font-family:'Doto',var(--mono);font-weight:700;color:var(--flame-3)}   /* scrambling glyphs in dot-matrix, settling into the display face */
html.hr-play .hero h1{contain:layout style}   /* the per-frame letter swaps stay inside the headline: no whole-page relayout */
html.hr-play .hr-line:not(.hr-go){visibility:hidden}   /* hidden until the decode starts; the gate's failsafe un-hides it if the script never runs */
html.hr-play .hero-copy>:nth-child(n+3){animation:none;opacity:0}
html.hr-play .nav{animation:fx-navin .6s .1s cubic-bezier(.2,.8,.2,1) both}   /* the nav fades in at once, never waits */
html.hr-run .hero-copy>:nth-child(n+3){animation:heroIn .7s 1.45s cubic-bezier(.2,.8,.2,1) both}   /* motto, lede and buttons wait for the name */
html.hr-run .hero-copy>:nth-child(4){animation-delay:1.55s}html.hr-run .hero-copy>:nth-child(5){animation-delay:1.65s}
@keyframes fx-navin{from{opacity:0;transform:translateY(-10px)}}
@media (prefers-reduced-motion:reduce){html.hr-play .hero-photo::after{display:none}html.hr-play .nav,html.hr-play .hero-copy>*{opacity:1;animation:none}}

/* ---------- animated project icons (project_icons): same line language as the role icons, inside the tile text ---------- */
.tile .tb-top{display:flex;justify-content:space-between;align-items:flex-start;gap:10px}
.tile-ic{flex:none;width:46px;height:46px;color:var(--text-2);margin:-6px -6px -8px 0;transition:color .2s}
.tile-ic .glyph{width:100%;height:100%;overflow:visible}
.tile:hover .tile-ic{color:var(--text)}
.glyph .pi-det{transform-box:view-box;transform-origin:24px 24px;animation:gspin 1.1s linear infinite}
.glyph .pi-vh{transform-box:view-box;transform-origin:24px 12px;animation:pi-vh 4s ease-in-out infinite}
@keyframes pi-vh{0%,8%{transform:scaleX(1)}16%,58%{transform:scaleX(.14)}66%,100%{transform:scaleX(1)}}
.glyph .pi-flow{animation:pi-flowx .6s linear infinite,pi-flowo 4s ease-in-out infinite}
@keyframes pi-flowx{to{transform:translateX(6px)}}
@keyframes pi-flowo{0%,12%{opacity:0}20%,56%{opacity:1}64%,100%{opacity:0}}
.glyph .pi-led{animation:pi-led 4s steps(1) infinite}
@keyframes pi-led{0%{opacity:.2}16%{opacity:1}62%{opacity:.2}}
.glyph .pi-whl{transform-box:view-box;animation:gspin 1.6s linear infinite}
.glyph .pi-bob{animation:pi-bob .8s ease-in-out infinite alternate}
@keyframes pi-bob{to{transform:translateY(-.7px)}}
.glyph .pi-ground{animation:pi-ground 1.2s linear infinite}
@keyframes pi-ground{to{stroke-dashoffset:10}}
.glyph .pi-fan{transform-box:view-box;animation:gspin .5s linear infinite}
.glyph .pi-exh{stroke-dasharray:2 2;animation:pi-exh .35s linear infinite}
@keyframes pi-exh{to{stroke-dashoffset:-4}}
.glyph .pi-hover{animation:pi-hover 1.6s ease-in-out infinite alternate}
@keyframes pi-hover{to{transform:translateY(-1.3px)}}
.glyph .pi-flame{transform-box:view-box;transform-origin:24px 36.5px;animation:pi-flame .12s steps(2) infinite alternate}
@keyframes pi-flame{to{transform:scaleY(.78)}}
.glyph .pi-smoke circle{transform-box:fill-box;transform-origin:center;animation:pi-smoke 2.4s ease-out infinite}
@keyframes pi-smoke{from{transform:scale(.4);opacity:.9}to{transform:translateY(1px) scale(2.4);opacity:0}}
/* SpaceX mark: launch, booster catch, ship catch on one 14 s loop */
.glyph.xl .sx2-b{animation:sx2b 14s infinite}
.glyph.xl .sx2-s{animation:sx2s 14s infinite}
.glyph.xl .sx2-arms{transform-box:view-box;transform-origin:29px 41px;animation:sx2arms 14s ease-in-out infinite}
.glyph.xl .sx2-asc{opacity:0;transform-box:fill-box;transform-origin:50% 0;animation:sx2asc 14s linear infinite}
.glyph.xl .sx2-lb{opacity:0;animation:sx2lb 14s linear infinite}
.glyph.xl .sx2-ls{opacity:0;animation:sx2ls 14s linear infinite}
.glyph.xl .sx2-smoke circle{fill:currentColor;opacity:0;transform-box:fill-box;transform-origin:50% 50%;animation:sx2smoke 14s ease-out infinite}
@keyframes sx2b{0%,14%{transform:none;opacity:1;animation-timing-function:cubic-bezier(.55,0,.85,.55)}32%{transform:translateY(-120px);opacity:1}33%,35%{transform:translateY(-110px);opacity:0}36%{transform:translateY(-110px);opacity:1;animation-timing-function:cubic-bezier(.2,.6,.3,1)}50%,100%{transform:none;opacity:1}}
@keyframes sx2s{0%,14%{transform:none;opacity:1;animation-timing-function:cubic-bezier(.55,0,.85,.55)}32%{transform:translateY(-120px);opacity:1}33%,59%{transform:translateY(-110px);opacity:0}60%{transform:translateY(-110px);opacity:1;animation-timing-function:cubic-bezier(.2,.6,.3,1)}76%,100%{transform:none;opacity:1}}
@keyframes sx2arms{0%,8%{transform:none}12%,45%{transform:rotate(-38deg)}50%,100%{transform:none}}
@keyframes sx2arms2{0%,8%{transform:none}12%,71%{transform:rotate(-38deg)}76%,100%{transform:none}}
.glyph.xl .sx2-arms2{transform-box:view-box;transform-origin:29px 17px;animation:sx2arms2 14s ease-in-out infinite}
@keyframes sx2asc{0%,11%{opacity:0;transform:scaleY(.2)}13%{opacity:1;transform:scaleY(.7)}15%,31%{opacity:1;transform:scaleY(1)}32%,100%{opacity:0}}
@keyframes sx2lb{0%,36%{opacity:0}38%,43%{opacity:1}46%,100%{opacity:0}}
@keyframes sx2ls{0%,60%{opacity:0}62%,69%{opacity:1}72%,100%{opacity:0}}
@keyframes sx2smoke{0%,12%{opacity:0;transform:scale(.4)}17%{opacity:.5}26%{opacity:.25;transform:scale(2.4)}32%,100%{opacity:0;transform:scale(2.8)}}
@media (prefers-reduced-motion:reduce){.glyph.xl [class*="sx2-"],.glyph.xl .sx2-smoke circle{animation:none}.glyph.xl .sx2-asc,.glyph.xl .sx2-lb,.glyph.xl .sx2-ls{opacity:0}}
.glyph .pi-fhplume{transform-box:view-box;transform-origin:45px 54px;animation:pi-fhplume .14s steps(2) infinite alternate}
@keyframes pi-fhplume{from{transform:scale(.94,.9)}to{transform:scale(1.03,1.06)}}
.glyph .pi-fhspark{animation:pi-fhspark 1.2s linear infinite}
@keyframes pi-fhspark{from{transform:translateX(-8px);opacity:0}30%{opacity:1}to{transform:translateX(10px);opacity:0}}
/* rocket96 */
.glyph .pi-rlift{transform-box:view-box;animation:pi-rlift 3s linear infinite}.glyph .pi-rflame{transform-box:view-box;transform-origin:52px 76.5px;animation:pi-rflame 3s linear infinite}@keyframes pi-rlift{0%,10%{transform:translateY(0);opacity:1}60%{transform:translateY(-30px);opacity:1}75%{transform:translateY(-75px);opacity:0}76%,88%{transform:translateY(0);opacity:0}100%{transform:translateY(0);opacity:1}}@keyframes pi-rflame{0%,8%{opacity:0;transform:scaleY(.3)}12%{opacity:1;transform:scaleY(1)}30%{transform:scaleY(1.12)}45%{transform:scaleY(.9)}60%{transform:scaleY(1.06)}72%{opacity:1;transform:scaleY(1)}78%,100%{opacity:0;transform:scaleY(.3)}}
/* valve96 */
.glyph .kx-flow{stroke-dasharray:2 4;animation:kx-dash .5s linear infinite,kx-run 5s linear infinite}
@keyframes kx-dash{to{stroke-dashoffset:-6}}
@keyframes kx-run{0%,8%{opacity:0}12%,86%{opacity:1}90%,100%{opacity:0}}
.glyph .kx-sv{animation:kx-sv 5s steps(1) infinite}
@keyframes kx-sv{0%,8%{opacity:.15}9%,88%{opacity:1}89%,100%{opacity:.15}}
.glyph .kx-fire{transform-box:view-box;transform-origin:66px 50px;animation:kx-fire 5s ease-out infinite}
@keyframes kx-fire{0%,14%{opacity:0;transform:scaleX(.1)}18%{opacity:1;transform:scaleX(.6)}24%,86%{opacity:1;transform:scaleX(1)}92%,100%{opacity:0;transform:scaleX(.3)}}
.glyph .kx-flick{transform-box:view-box;transform-origin:66px 50px;animation:kx-flick .13s steps(2) infinite alternate}
@keyframes kx-flick{from{transform:scale(.97,.93)}to{transform:scale(1.02,1.05)}}
.glyph .kx-dia{animation:kx-dia .5s ease-in-out infinite alternate}
@keyframes kx-dia{from{opacity:.55}to{opacity:1}}
.glyph .kx-glow{animation:kx-run 5s linear infinite}
@keyframes sr2-belt{to{stroke-dashoffset:-5}}
.glyph .sr2-rot{transform-box:view-box;transform-origin:52px 45px;animation:gspin .45s linear infinite}
.glyph .sr2-p1{transform-box:view-box;transform-origin:39px 21px;animation:gspin 1.2s linear infinite}
.glyph .sr2-p2{transform-box:view-box;transform-origin:9px 58px;animation:gspin 1.2s linear infinite}
.glyph .sr2-p3{transform-box:view-box;transform-origin:76px 46px;animation:gspin .3s linear infinite}
.glyph .sr2-rock{animation:sr2-rock 3s infinite}
@keyframes sr2-rock{0%{transform:translate(0,0);opacity:0;animation-timing-function:linear}6%{opacity:1}72%{transform:translate(29px,-34px);animation-timing-function:cubic-bezier(.5,0,1,.6)}96%{transform:translate(38px,-22px);opacity:1}100%{transform:translate(38px,-20px);opacity:0}}
.glyph .sr2-fine{animation:sr2-fine 2.4s infinite}
@keyframes sr2-fine{0%{transform:translate(0,0);opacity:0;animation-timing-function:cubic-bezier(.5,0,1,.6)}5%{opacity:1}18%{transform:translate(0,9px);animation-timing-function:linear}78%{transform:translate(30px,9px);animation-timing-function:cubic-bezier(.3,0,1,.6)}96%{transform:translate(35px,21px);opacity:1}100%{transform:translate(35px,22px);opacity:0}}
@keyframes ue-turn{0%{transform:scaleX(1)}25%{transform:scaleX(.3)}50%{transform:scaleX(-1)}75%{transform:scaleX(-.3)}100%{transform:scaleX(1)}}
.glyph .ue-marks{stroke-dasharray:1.2 5;animation:ue-marks 6s linear infinite}
@keyframes ue-marks{to{stroke-dashoffset:-62.3}}
.glyph .ue-fringe{animation:ue-fringe .9s linear infinite}
@keyframes ue-fringe{from{transform:translateY(0)}to{transform:translateY(4px)}}
.glyph .ue-flash{animation:ue-flash 1.5s steps(1) infinite}
@keyframes ue-flash{0%,70%{opacity:1}71%,100%{opacity:.35}}
/* rover96 */
.glyph .rv-rock{animation:rv-rock 6s linear infinite}
@keyframes rv-rock{from{transform:translateX(30px)}to{transform:translateX(-70px)}}
.glyph .rv-gnd{stroke-dasharray:3 5;animation:rv-gnd .48s linear infinite}
@keyframes rv-gnd{to{stroke-dashoffset:8}}
.glyph .rv-whl{transform-box:fill-box;transform-origin:50% 50%;animation:gspin 1.13s linear infinite}
.glyph .rv-front{transform-box:view-box;transform-origin:34px 70px;animation:rv-front 6s ease-in-out infinite}
@keyframes rv-front{0%,22%{transform:none}30%{transform:rotate(-6.3deg)}38%,100%{transform:none}}
.glyph .rv-rock2{transform-box:view-box;transform-origin:70px 78px;animation:rv-rocker 6s ease-in-out infinite}
@keyframes rv-rocker{0%,46%{transform:none}54%{transform:rotate(3.2deg)}62%,70%{transform:none}78%{transform:rotate(3.2deg)}86%,100%{transform:none}}
.glyph .rv-mid{transform-box:view-box;transform-origin:22px 78px;animation:rv-mid 6s ease-in-out infinite}
@keyframes rv-mid{0%,46%{transform:none}54%{transform:rotate(-9.5deg)}62%,100%{transform:none}}
.glyph .rv-rear{transform-box:view-box;transform-origin:46px 78px;animation:rv-rear 6s ease-in-out infinite}
@keyframes rv-rear{0%,70%{transform:none}78%{transform:rotate(9.5deg)}86%,100%{transform:none}}
.glyph .sp-nail{transform-box:view-box;transform-origin:44px 50px;animation:sp-cos 1.6s infinite;animation-delay:-.12s}
@keyframes sp-cos{0%{transform:scaleX(1);animation-timing-function:cubic-bezier(.36,0,.64,.5)}25%{transform:scaleX(0);animation-timing-function:cubic-bezier(.36,.5,.64,1)}50%{transform:scaleX(-1);animation-timing-function:cubic-bezier(.36,0,.64,.5)}75%{transform:scaleX(0);animation-timing-function:cubic-bezier(.36,.5,.64,1)}100%{transform:scaleX(1)}}
.glyph .sp-worm{stroke-dasharray:1 1.6;animation:sp-worm .25s linear infinite}
@keyframes sp-worm{to{stroke-dashoffset:-2.6}}
.glyph .sp-gear{stroke-dasharray:1 1.4;animation:sp-worm 1.6s linear infinite}
@keyframes gn-roll{0%{transform:translateX(0);animation-timing-function:linear}10%{transform:translateX(-12px);animation-timing-function:cubic-bezier(.2,.6,.35,1)}70%,100%{transform:translateX(-48px)}}
.glyph .gn-fin{transform-box:view-box;transform-origin:30px 75px;animation:gn-fin 5s ease-in-out infinite}
@keyframes gn-fin{0%,10%{transform:none}22%{transform:rotate(12deg)}38%{transform:rotate(5deg)}52%{transform:rotate(-2deg)}66%,100%{transform:none}}
.glyph .gn-trace{stroke-dasharray:100;animation:gn-trace 5s linear infinite}
@keyframes gn-trace{0%{stroke-dashoffset:100}70%,92%{stroke-dashoffset:0;opacity:1}100%{stroke-dashoffset:0;opacity:0}}
.glyph .gn-flame{transform-box:fill-box;transform-origin:50% 0;animation:flick .12s steps(2) infinite alternate}
/* jet96 */
.glyph .ja-c{transform-box:view-box;transform-origin:26px 62px;animation:gspin 1.2s linear infinite}
.glyph .ja-t{transform-box:view-box;transform-origin:70px 62px;animation:gspin 1.2s linear infinite}
.glyph .ja-flow{stroke-dasharray:3 4;animation:ja-flow .9s linear infinite}
@keyframes ja-flow{to{stroke-dashoffset:-14}}
.glyph .ja-flame{transform-box:fill-box;transform-origin:50% 100%;animation:flick .14s steps(2) infinite alternate}
/* spin96 */
.glyph .sp-rot{transform-box:view-box;transform-origin:44px 50px;animation:sp-cos 1.6s infinite}
.glyph .sp-band{transform-box:view-box;animation:sp-band 1.6s infinite;animation-delay:-.12s}
@keyframes sp-band{0%{transform:translateX(-8px);animation-timing-function:cubic-bezier(.36,0,.64,.5)}25%{transform:translateX(0)}50%{transform:translateX(8px);animation-timing-function:cubic-bezier(.36,0,.64,.5)}75%{transform:translateX(0)}100%{transform:translateX(-8px)}}
@keyframes sp-cos{0%{transform:scaleX(1);animation-timing-function:cubic-bezier(.36,0,.64,.5)}25%{transform:scaleX(0);animation-timing-function:cubic-bezier(.36,.5,.64,1)}50%{transform:scaleX(-1);animation-timing-function:cubic-bezier(.36,0,.64,.5)}75%{transform:scaleX(0);animation-timing-function:cubic-bezier(.36,.5,.64,1)}100%{transform:scaleX(1)}}
.glyph .sp-worm{stroke-dasharray:1 1.6;animation:sp-worm .25s linear infinite}
@keyframes sp-worm{to{stroke-dashoffset:-2.6}}
.glyph .sp-gear{stroke-dasharray:1 1.4;animation:sp-worm 1.6s linear infinite}
@keyframes sr2-belt{to{stroke-dashoffset:-5}}
.glyph .sr2-rot{transform-box:view-box;transform-origin:52px 45px;animation:gspin 1.4s linear infinite}
.glyph .sr2-p1{transform-box:view-box;transform-origin:39px 21px;animation:gspin 3.2s linear infinite}
.glyph .sr2-p2{transform-box:view-box;transform-origin:9px 58px;animation:gspin 3.2s linear infinite}
.glyph .sr2-p3{transform-box:view-box;transform-origin:76px 46px;animation:gspin .9s linear infinite}
.glyph .sr2-rock{animation:sr2-rock 7.5s infinite}
@keyframes sr2-rock{0%{transform:translate(0,0);opacity:0;animation-timing-function:linear}6%{opacity:1}72%{transform:translate(29px,-34px);animation-timing-function:cubic-bezier(.5,0,1,.6)}96%{transform:translate(38px,-22px);opacity:1}100%{transform:translate(38px,-20px);opacity:0}}
.glyph .sr2-fine{animation:sr2-fine 6s infinite}
@keyframes sr2-fine{0%{transform:translate(0,0);opacity:0;animation-timing-function:cubic-bezier(.5,0,1,.6)}5%{opacity:1}18%{transform:translate(0,9px);animation-timing-function:linear}78%{transform:translate(30px,9px);animation-timing-function:cubic-bezier(.3,0,1,.6)}96%{transform:translate(35px,21px);opacity:1}100%{transform:translate(35px,22px);opacity:0}}
/* piv96 */
.glyph .pv-p{stroke-dasharray:0 6;animation:pv-p 1.8s linear infinite}
@keyframes pv-p{to{stroke-dashoffset:-12}}
.glyph .pv-sheet{animation:pv-sheet 3s infinite}
@keyframes pv-sheet{0%,1%{opacity:.5}2.5%,7%{opacity:0}8%,9%{opacity:.5}10.5%,100%{opacity:0}}
.glyph .pv-vec{animation:pv-vec 3s infinite}
@keyframes pv-vec{0%,12%{opacity:0}18%,80%{opacity:1}90%,100%{opacity:0}}
/* fin96 */
.glyph .gn-ring{stroke-dasharray:4 3;animation:gn-ring 6s infinite}
@keyframes gn-ring{0%{stroke-dashoffset:0;opacity:1;animation-timing-function:linear}20%{stroke-dashoffset:-28;animation-timing-function:cubic-bezier(.15,.6,.35,1)}70%{stroke-dashoffset:-56;opacity:1}80%,92%{stroke-dashoffset:-56;opacity:.15}100%{stroke-dashoffset:-56;opacity:1}}
.glyph .gn-fl{transform-box:view-box;transform-origin:36px 64px;animation:gn-fl 6s ease-in-out infinite}
.glyph .gn-fr{transform-box:view-box;transform-origin:60px 64px;animation:gn-fr 6s ease-in-out infinite}
@keyframes gn-fl{0%,16%{transform:none}28%,44%{transform:rotate(-14deg)}66%,100%{transform:none}}
@keyframes gn-fr{0%,16%{transform:none}28%,44%{transform:rotate(14deg)}66%,100%{transform:none}}
.glyph .gn-flame{transform-box:fill-box;transform-origin:50% 0;animation:flick .12s steps(2) infinite alternate}
/* blade96 */
.glyph .ut2-b{stroke-linecap:butt;animation:6s linear infinite}
@keyframes ut2-b1{to{stroke-dashoffset:-28.776}}
@keyframes ut2-b2{to{stroke-dashoffset:-32.085}}
.glyph .ut2-hub{transform-box:view-box;transform-origin:48px 52px;animation:ut2-hub 6s linear infinite}
@keyframes ut2-hub{to{transform:rotate(360deg)}}
/* hopper96 */
.glyph .sr3-belt{stroke-dasharray:2 3;animation:sr3-belt 1.6s linear infinite}
@keyframes sr3-belt{to{stroke-dashoffset:-5}}
.glyph .sr3-rot{transform-box:view-box;transform-origin:51px 47px;animation:gspin 1.4s linear infinite}
.glyph .sr3-rock{animation:sr3-rock 6s infinite}
@keyframes sr3-rock{0%{transform:translate(0,0);opacity:0;animation-timing-function:linear}5%{opacity:1}70%{transform:translate(34px,-38px);animation-timing-function:ease-out}80%{transform:translate(39px,-40px);animation-timing-function:ease-in}90%{transform:translate(42px,-31px);opacity:1}93%,100%{transform:translate(42px,-29px);opacity:0}}
.glyph .sr3-fine{animation:sr3-fine 6s infinite}
@keyframes sr3-fine{0%{transform:translate(0,0);opacity:0;animation-timing-function:ease-in}4%{opacity:1}14%{transform:translate(0,8px);animation-timing-function:linear}82%{transform:translate(33px,8px);animation-timing-function:ease-in}94%{transform:translate(37px,15px);opacity:1}100%{transform:translate(37px,16px);opacity:0}}
@media (prefers-reduced-motion:reduce){.glyph.xl *{animation:none!important}}

.glyph .pi-det96{transform-box:view-box;transform-origin:48px 48px;animation:gspin 1.6s linear infinite}
.glyph .pi-pipe{stroke-dasharray:2 5;animation:pi-pipe .7s linear infinite}
@keyframes pi-pipe{to{stroke-dashoffset:-7}}
@media (prefers-reduced-motion:reduce){.glyph [class^="pi-"],.glyph [class^="pi-"] circle{animation:none}}

/* ---------- timeline details (timeline_fx) ---------- */
html.on-timeline-fx .tl-strip .bar::after{content:"";position:absolute;right:-1px;top:-3px;bottom:-3px;width:3px;background:var(--flame-1);
  box-shadow:0 0 10px 2px rgb(var(--fx-amber-rgb) / .85),0 0 22px 6px rgb(var(--fx-ember-rgb) / .35);opacity:0;pointer-events:none}
html.anim.on-timeline-fx .tl-strip.in .bar::after{animation:tl-ember .8s ease-out both;animation-delay:calc(var(--d,0) * 110ms + 60ms)}
@keyframes tl-ember{0%,65%{opacity:1}100%{opacity:0}}
.btk{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .2s;
  background:repeating-linear-gradient(90deg,transparent 0 calc(100% / var(--mo) - 1.5px),var(--void) calc(100% / var(--mo) - 1.5px) calc(100% / var(--mo)))}
.bw{position:absolute;left:0;bottom:calc(100% + 5px);font:10px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--live);white-space:nowrap;
  background:var(--void);padding:2px 4px 2px 0;opacity:0;transform:translateY(3px);transition:opacity .2s,transform .2s;pointer-events:none}
.tl-strip .bar:hover .btk,.tl-strip .bar:focus-visible .btk{opacity:1}
.tl-strip .bar:hover .bw,.tl-strip .bar:focus-visible .bw{opacity:1;transform:none}
html.on-timeline-fx .tl-strip .lane:hover .bar:not(:hover){opacity:.35}
@media (max-width:600px),(hover:none){.bw,.btk{display:none}}   /* hover-only details; on phones they would only widen the page */
html.on-timeline-fx .tl-strip .bar{transition:background .15s,opacity .2s}
html.anim.on-timeline-fx .tl-strip .bar{transition:transform .6s cubic-bezier(.2,.8,.2,1) calc(var(--d,0) * 110ms + 60ms),background .15s,opacity .2s}
html.on-timeline-fx .tl-strip .now::before{content:"";position:absolute;top:0;bottom:0;right:0;width:140px;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgb(var(--fx-amber-rgb) / .13));opacity:0}
html.anim.on-timeline-fx .tl-strip.in .now::before{animation:tl-sweep 1.5s ease both .05s}
@keyframes tl-sweep{0%{opacity:0}8%,82%{opacity:1}100%{opacity:0}}
html.on-timeline-fx .tl-strip .now::after{content:"";position:absolute;top:-3.5px;left:-4px;width:7px;height:7px;border-radius:50%;background:var(--live);
  box-shadow:0 0 0 0 rgb(var(--fx-amber-rgb) / .6);animation:tl-ping 2.4s ease-out infinite 1.5s}
@keyframes tl-ping{0%{box-shadow:0 0 0 0 rgb(var(--fx-amber-rgb) / .65)}70%,100%{box-shadow:0 0 0 12px rgb(var(--fx-amber-rgb) / 0)}}
html.on-timeline-fx .tl-strip .trk:first-of-type .line:last-child::after{content:"";position:absolute;top:-2px;left:0;width:100%;height:6px;pointer-events:none;
  background:radial-gradient(circle at 3px 3px,var(--live) 2.4px,transparent 3.2px) no-repeat;filter:drop-shadow(0 0 4px var(--live));animation:tl-run 3.2s linear infinite 1.5s;opacity:0}
@keyframes tl-run{0%{transform:translateX(-3px);opacity:0}10%,85%{opacity:1}100%{transform:translateX(calc(100% - 3px));opacity:0}}   /* transform only: no per-frame layout */
html.anim.on-timeline-fx .tl-strip.in .pmk i{animation:tl-mark 1s ease-out both;animation-delay:calc(var(--d,0) * 70ms + 300ms)}
@keyframes tl-mark{0%{box-shadow:0 0 0 0 rgb(var(--fx-amber-rgb) / .7)}100%{box-shadow:0 0 0 10px rgb(var(--fx-amber-rgb) / 0)}}
@media (prefers-reduced-motion:reduce){html.on-timeline-fx .tl-strip .now::after,html.on-timeline-fx .tl-strip .trk .line::after,html.on-timeline-fx .tl-strip .bar::after{animation:none}}

/* ---------- solar system site map (solar_system) ---------- */
.fx-sol{margin:56px auto 0;max-width:1100px;border-top:1px solid var(--line);padding-top:14px}
.sol-head{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap}
.sol-hint{color:var(--muted)}
.sol-stage{position:relative;overflow:hidden}
.sol-fallback{list-style:none;margin:14px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px 22px;font:12px var(--mono);letter-spacing:.08em;text-transform:uppercase}
.sol-fallback span{color:var(--muted);text-transform:none;letter-spacing:.02em}
.fx-sol.ready .sol-fallback{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
.fx-sol.ready .sol-fallback:focus-within{position:static;width:auto;height:auto;overflow:visible;clip-path:none}   /* keyboard users get the planet links as a visible list */
.sol-svg{display:block;width:100%;height:auto;overflow:hidden;font-family:var(--mono)}
.sol-orbit{fill:none;stroke:var(--line-2);stroke-width:1;stroke-dasharray:1 5;stroke-linecap:round;transition:stroke .3s}
.sol-orbit.hot{stroke:rgb(var(--fx-amber-2-rgb) / .55);stroke-dasharray:none}
.sol-belt{fill:none;stroke:var(--fx-belt);stroke-linecap:round;stroke-width:1.3;opacity:.55}
.sol-belt.b1{stroke-dasharray:.1 9;animation:sol-belt 70s linear infinite}
.sol-belt.b2{stroke-dasharray:.1 13;animation:sol-belt 95s linear infinite reverse;opacity:.35}
.sol-belt.b3{stroke-dasharray:.1 7;animation:sol-belt 120s linear infinite;opacity:.25}
@keyframes sol-belt{to{stroke-dashoffset:-400}}
.sol-star{fill:var(--fx-white)}
.sol-star.tw{animation:sol-tw 3.4s ease-in-out infinite alternate}
@keyframes sol-tw{from{opacity:.15}to{opacity:.9}}
.sol-corona{animation:sol-breathe 5s ease-in-out infinite alternate;transform-box:fill-box;transform-origin:center}
@keyframes sol-breathe{to{transform:scale(1.12);opacity:.8}}
.sol-p{cursor:pointer;outline:none}
.sol-lbls{pointer-events:none}
.sol-lb .lbl{font-size:11px;letter-spacing:.14em;text-transform:uppercase;fill:var(--text-2);transition:fill .2s}
.sol-lb .det{font:14px "Handjet",var(--mono);font-variation-settings:"ELSH" 2,"ELGR" 2;letter-spacing:.05em;fill:var(--muted);opacity:0;transition:opacity .25s}
.sol-lb.hot .lbl{fill:var(--flame-2)}
.sol-lb.hot .det{opacity:1}
.sol-p .hit{fill:transparent}
.sol-p .body{transition:transform .25s}
.sol-p:hover .body,.sol-p:focus-visible .body{transform:scale(1.3)}
.sol-p:focus-visible .ring-f{stroke:var(--flame-2)}
.sol-trail circle{fill:currentColor}
.sol-comet{pointer-events:none}
@media (max-width:640px){.sol-hint{display:none}.sol-lb .lbl{font-size:10px}.sol-lb .det{font-size:12px}}
@media (prefers-reduced-motion:reduce){.sol-belt,.sol-star.tw,.sol-corona{animation:none}}

/* ---------- civilization megastructures (solar_system): blueprint scaffold while building, then the finished structure ---------- */
.sol-civ{color:var(--flame-3);order:2;flex-basis:100%}
.mg:not(.mg-build):not(.mg-done){display:none}
.mg-scf{fill:none;stroke:var(--fx-holo-2);stroke-width:.8;stroke-opacity:.9;transition:opacity 1.2s ease}
.mg-scf *{stroke-dasharray:1;stroke-dashoffset:calc(1 - var(--p,0));transition:stroke-dashoffset 1s linear}
.mg-fin{transition:opacity 1.6s ease}
.mg-build .mg-fin{opacity:0}
.mg-done .mg-scf{opacity:0}
.mg-ringworld.mg-build .mg-fin{opacity:1}
.mg-ringworld .mg-fin g,.mg-ringworld-f g{transition:opacity 1.4s ease}
.mg-blink{animation:mg-blink 1.2s steps(2) infinite}
@keyframes mg-blink{50%{opacity:.15}}
.mg-drill{animation:mg-drill .9s steps(2) infinite}
@keyframes mg-drill{50%{opacity:.12}}
.mg-ping{transform-box:fill-box;transform-origin:center;opacity:0;animation:mg-ping 3.3s ease-out infinite}
@keyframes mg-ping{0%{transform:scale(.3);opacity:.9}100%{transform:scale(3.2);opacity:0}}
.mg-stream{stroke-dasharray:3 4;animation:mg-stream .45s linear infinite}
@keyframes mg-stream{to{stroke-dashoffset:-7}}
.mg-jet,.mg-jetc{animation:mg-jet 1.1s ease-in-out infinite alternate}
@keyframes mg-jet{from{opacity:.6}to{opacity:1}}
html[data-theme="1975"] .sol-civ{color:var(--live)}
html[data-theme="1975"] .mg-fin [stroke="var(--fx-edge)"]{stroke:var(--fx-edge-ink)}
html[data-theme="1975"] .mg-swarm rect,html[data-theme="1975"] .sol-svg rect[fill="#ffe2a8"]{fill:var(--fx-amber-ink)}
html[data-theme="1975"] .mg-scf{stroke:var(--fx-holo-ink)}
@media (prefers-reduced-motion:reduce){.mg-blink,.mg-drill,.mg-ping,.mg-stream,.mg-jet,.mg-jetc{animation:none}.mg-ping{opacity:0}}

/* ---------- rare sky (rare_sky): an unusual object drifts through the background now and then ---------- */
.fx-rare{position:fixed;inset:0;width:100%;height:100%;height:100lvh;z-index:var(--z-behind);pointer-events:none}
.fx-rare-cap{position:fixed;z-index:var(--z-behind);font:10px var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--muted);white-space:nowrap;opacity:0;transition:opacity 1.4s ease;pointer-events:none}
.fx-rare-cap.on{opacity:.9}
@media print{.fx-rare,.fx-rare-cap{display:none}}

/* ---------- 3D site map (solar3d.js): a dark viewscreen in both themes, labels are real links laid over the canvas ---------- */
.fx-sol[data-three3d]:not(.ready) .sol-stage{min-height:min(600px,52vw)}
@media (max-width:640px){.fx-sol[data-three3d]:not(.ready) .sol-stage{min-height:85vw}}
.sol3-wrap{position:relative;margin-top:12px;border:1px solid var(--line);background:var(--fx-space);overflow:hidden}
.sol3-wrap canvas{display:block;width:100%}
.sol3-labels{position:absolute;inset:0;pointer-events:none}
.sol3-lbl{position:absolute;left:0;top:0;pointer-events:auto;display:flex;flex-direction:column;align-items:center;gap:1px;text-decoration:none;
  font:11px var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--fx-lbl);white-space:nowrap;text-shadow:0 1px 3px var(--fx-black),0 0 8px var(--fx-black);will-change:transform}
.sol3-lbl .d{font:14px "Handjet",var(--mono);font-variation-settings:"ELSH" 2,"ELGR" 2;letter-spacing:.05em;text-transform:none;color:var(--fx-lbl-2);opacity:0;transition:opacity .25s}
.sol3-lbl.hot .n{color:var(--fx-amber-2)}.sol3-lbl.hot .d{opacity:1}
.sol3-lbl:focus-visible{outline:1px solid var(--fx-amber-2);outline-offset:3px}
.sol3-hint{position:absolute;right:12px;bottom:10px;color:var(--fx-lbl-3);pointer-events:none}
@media (max-width:640px){.sol3-lbl{font-size:10px}.sol3-hint{display:none}}

/* ---------- story timeline: life entries on demand (life_toggle) ---------- */
.fx-life{display:inline-flex;margin:28px 0 -24px;padding:10px 14px;border:1px solid var(--line-2);background:none;color:var(--text);cursor:pointer;min-height:44px;align-items:center}
.fx-life:hover{border-color:var(--text-2)}
.fx-life .off,.fx-life[aria-expanded="true"] .on{display:none}.fx-life[aria-expanded="true"] .off{display:inline}
.chrono.hide-life .ev.k-life,.chrono.hide-life .yr-row.only-life{display:none}

/* ---------- project tiles: the lead project large, the other four in a 2 x 2 beside it ---------- */
@media (min-width:1061px){
  .tiles{grid-template-columns:1.35fr 1fr 1fr}
  .tiles>.tile:first-child{grid-row:span 2}
  .tiles>.tile:first-child .img{aspect-ratio:auto;flex:1;min-height:340px}
  .tiles>.tile:first-child h3{font-size:30px}
  .tiles>.tile:first-child p{font-size:15px}
  .tiles>.tile:not(:first-child) .img{aspect-ratio:16/9}
}
/* Site map, 2026-10-10: one plain line on what it is{margin:6px 0 4px;font-size:14px;color:var(--text);max-width:62ch}
.fx-sol[data-three3d]:not(.ready) .sol-stage{min-height:min(440px,40vw)}

/* ---------- design lab picks (2026-10-16) ---------- */
/* smooth scroll (Lenis): its required rules; Lenis eases wheel scrolling itself, so CSS smooth scrolling is off while it runs */
html.lenis,html.lenis body{height:auto}
html.lenis{scroll-behavior:auto}
.lenis:not(.lenis-autoToggle).lenis-stopped{overflow:clip}
.lenis [data-lenis-prevent],.lenis .ov,.lenis .tw{overscroll-behavior:contain}
.lenis.lenis-smooth iframe{pointer-events:none}

/* cursor labels */
.fx-cursor{position:fixed;left:0;top:0;z-index:var(--z-overlay);pointer-events:none;opacity:0;transition:opacity .2s;
  font:500 11px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;white-space:nowrap;
  color:var(--text);background:var(--void);border:1px solid var(--line-2);padding:6px 8px}
.fx-cursor.on{opacity:1}
body.modal .fx-cursor{opacity:0}

/* bracket borders: 10 px amber corners with 1 px arms, on the 3D viewer only (they read as broken on pill buttons) */
.on-brackets .viewer{--bk:var(--live)}
.on-brackets .viewer::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:var(--z-raise-3);
  background:
   linear-gradient(var(--bk),var(--bk)) 0 0/10px 1px no-repeat,linear-gradient(var(--bk),var(--bk)) 0 0/1px 10px no-repeat,
   linear-gradient(var(--bk),var(--bk)) 100% 0/10px 1px no-repeat,linear-gradient(var(--bk),var(--bk)) 100% 0/1px 10px no-repeat,
   linear-gradient(var(--bk),var(--bk)) 0 100%/10px 1px no-repeat,linear-gradient(var(--bk),var(--bk)) 0 100%/1px 10px no-repeat,
   linear-gradient(var(--bk),var(--bk)) 100% 100%/10px 1px no-repeat,linear-gradient(var(--bk),var(--bk)) 100% 100%/1px 10px no-repeat}
.on-brackets .case-hero .titleblock{position:relative;margin-bottom:6px}
.on-brackets .case-hero .titleblock::after{content:"";position:absolute;left:0;right:0;bottom:-14px;height:1px;
  background:repeating-linear-gradient(90deg,var(--live) 0 4px,transparent 4px 7px)}

/* project zoom: the tile photo grows into the case hero, slowly enough to follow */
::view-transition-group(case-hero){animation-duration:.75s;animation-timing-function:cubic-bezier(.67,0,.23,1)}
::view-transition-old(case-hero),::view-transition-new(case-hero){animation-duration:.75s;height:100%;object-fit:cover;overflow:clip}
::view-transition-old(root),::view-transition-new(root){animation-duration:.45s}
@media (prefers-reduced-motion:reduce){::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none!important}}

/* topographic contours (Tools and methods) and flow field (PERL title band): faint, behind the content */
.fx-topo,.fx-case{position:relative;isolation:isolate}
.fx-topo>.fx-amb,.fx-case>.fx-amb{position:absolute;inset:0;width:100%;height:100%;z-index:var(--z-behind);pointer-events:none}
.fx-case>.fx-amb{-webkit-mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent)}

/* exploded spinner: part names beside each part while it is out */
.viewer{overflow:hidden}
.viewer .vcall{position:absolute;left:0;top:0;pointer-events:none;opacity:0;z-index:var(--z-raise-2);margin:-9px 0 0 10px;font:500 10px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;white-space:nowrap;color:var(--text);background:color-mix(in srgb,var(--void) 75%,transparent);border:1px solid var(--line-2);padding:4px 6px}

/* Spinfield build stages: three columns on desktop, one per row on phones; figures reuse the case .figs style */
.build-stages{list-style:none;margin:18px 0 0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px}
.build-stages li{display:flex;flex-direction:column;gap:8px;min-width:0;border-top:1px solid var(--line);padding-top:12px}
.build-stages li>b{font:600 22px/1.1 var(--disp);text-transform:uppercase}
.build-stages figure{margin:0}
.build-stages figure img{aspect-ratio:4/3;object-fit:cover;width:100%}
.build-stages p{margin:0;color:var(--text);font-size:15px}
@media (max-width:760px){.build-stages{grid-template-columns:1fr}}

/* ---------- smoothness round (2026-10-17) ---------- */
/* SVG icon animations repaint on the main thread; while the page scrolls they pause so smooth scroll keeps its frames.
   html.scrolling is set by features.js only while the page is moving. */
html.scrolling .glyph,html.scrolling .glyph *{animation-play-state:paused!important}
/* a repaint inside a project photo stays inside it */
.sc-media{contain:layout paint}
/* flames flicker smoothly instead of in two hard steps (read as low frame rate) */
html .glyph .pi-flame{animation:pi-flame .45s ease-in-out infinite alternate}
html .glyph .g-plume2 .p-out{animation:flick .42s ease-in-out infinite alternate}
html .glyph .g-plume2 .p-in{animation:flick .34s ease-in-out infinite alternate-reverse}
html .glyph .g-plume2 .p-mid{animation:flick .38s ease-in-out infinite alternate}
/* ticker: half the speed, and its own compositing layer so the masked strip is not repainted every frame */
html .fx-ticker-in{animation-duration:150s;will-change:transform}
html .fx-ticker{contain:paint}
/* a Previous / Next card for a case without photos shows its project glyph in the thumbnail frame */
.fx-nglyph{display:grid;place-items:center;background:var(--panel);color:var(--text-2)}
.fx-nglyph .glyph{width:44%;height:auto}
/* Spinfield wiring diagram: + wires red in both themes */
:root{--wire-pos:#D9443A}
/* Spinfield progression strip photo: its own wide shape, not the 4:3 gallery crop or the paper box */
.figs img[src$="spinfield-stages.jpg"]{aspect-ratio:auto;height:auto;object-fit:cover}
/* Spinfield glyph: the horseshoe magnet turns (narrows and widens about its shaft) and its field pulses below it */
.glyph .g-mag{transform-box:fill-box;transform-origin:50% 0;animation:gmag 1.4s ease-in-out infinite}
.glyph .g-field{animation:gfield 1.4s ease-in-out infinite}
@keyframes gmag{50%{transform:scaleX(.14)}}
@keyframes gfield{50%{opacity:.25}}
/* On the bench (redesign 2026-10-17): one full-width card per build: glyph panel, text, and a stage track. Theme tokens
   only, so dark and 1975 both read. */
html .benches{grid-template-columns:1fr}
html .bench{grid-template-columns:200px minmax(0,1.5fr) minmax(170px,1fr)}
.bench .gtile{display:grid;place-items:center;background:var(--panel);color:var(--text-2);transition:color .2s}
.bench .gtile>span{width:104px;height:104px;display:block}
.bench .gtile .glyph{width:100%;height:100%}
.bench:hover .gtile{color:var(--text)}
.bench .bb{padding:22px 24px;gap:8px}
.bench h3{font-size:clamp(24px,2.4vw,30px)}
.bench-track{list-style:none;margin:0;padding:22px 24px;display:flex;flex-direction:column;justify-content:center;gap:14px;border-left:1px solid var(--line);counter-reset:st}
.bench-track li{counter-increment:st;display:flex;align-items:center;gap:10px;font:11px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.bench-track li::before{content:counter(st,decimal-leading-zero);width:22px;color:var(--muted)}
.bench-track li::after{content:"";flex:1;height:1px;background:var(--line)}
.bench-track li.st-done{color:var(--text-2)}
.bench-track li.st-now{color:var(--live)}
.bench-track li.st-now::before{color:var(--live)}
.bench-track li.st-now::after{background:var(--live);opacity:.5}
@media (max-width:860px){
  html .bench{grid-template-columns:104px minmax(0,1fr)}
  .bench .gtile>span{width:64px;height:64px}
  .bench-track{grid-column:1/-1;flex-direction:row;flex-wrap:wrap;gap:8px 16px;border-left:0;border-top:1px solid var(--line);padding:14px 18px}
  .bench-track li::after{display:none}
}

/* ---------- audit fixes (2026-10-17) ---------- */
/* The lightbox sits on a near-black scrim in both themes, so it keeps the dark text tokens in 1975 (arrows were 1.02:1) */
html[data-theme="1975"] .lb{--text:#ECECEA;--text-2:#B4B5B2;--muted:#85878A;--line:#232426;--line-2:#2E3033;color:var(--text)}
/* Previous / Next cards: shrink inside their column and stack on phones (they pushed case pages 28-104 px wider than 375) */
.next a{min-width:0}
.next .t{overflow-wrap:anywhere}
@media (max-width:600px){
  .next{grid-template-columns:1fr}
  .next a+a{border-left:0;border-top:1px solid var(--line);text-align:left}
  nav.next a:last-child .fx-nthumb{margin-left:0}
}
/* 1975 contrast fixes (audit 2026-10-17): surfaces that stay dark keep the dark text tokens, and amber hover text on
   the light panels becomes ink (it measured 4.2:1) */
html[data-theme="1975"] .viewer{--text:#ECECEA;--text-2:#B4B5B2;--muted:#85878A}
html[data-theme="1975"] .kxr-nav a:hover .go,html[data-theme="1975"] .itin a.stop:hover b{color:var(--text)}
.sc-media figure.vid figcaption{color:rgb(var(--glint-rgb))}
html[data-theme="1975"] .hr-c.scr{color:var(--live)}
/* tap targets at least 24 px tall (WCAG 2.5.8): timeline markers and the name link in the nav */
.pmk{min-height:28px}
.nav .brand{min-height:24px}
