:root{--bg:#0c0a1a;--panel:#15122c;--panel2:#1c1838;--line:#2c2750;--line2:#3b3568;
    --ink:#ece9ff;--dim:#9b93c6;--pink:#ff6ec7;--cyan:#45e0ff;--mint:#4dffb0;--amber:#ffd86b;--purple:#a06bff}
  *{box-sizing:border-box}
  body{margin:0;height:100vh;overflow:hidden;background:var(--bg);color:var(--ink);
    font:14px/1.55 ui-sans-serif,system-ui,sans-serif;
    touch-action:pan-x pan-y}  /* modals still scroll; browser pinch-zoom of the PAGE never fires */
  /* THE STAR MAP: the whole viewport is the space; video plays underneath,
     stars + path float directly over the footage — no box, no panel. */
  #map{position:fixed;inset:0;width:100vw;height:100vh;z-index:1;cursor:crosshair;touch-action:none;
    user-select:none;-webkit-user-select:none}
  #map text{pointer-events:none}
  #map .cur{pointer-events:none}  /* the traveler is display-only: it never steals a waypoint grab */
  /* FLOATING GLYPHS (app/map/glyphs.js): faint alien station idents backfloating on the
     star map. z-index:0 sits ABOVE the demoscene/video canvases (z-index:-1) and
     BELOW the map SVG (#map, z-index:1) + all UI, so they drift behind the stars.
     Blurred + screen-blended for a soft watermark; each glyph's slow drift + fade
     is driven by compositor-only CSS transitions set inline (no flicker). */
  #glyphmap{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none;
    filter:blur(1.3px);mix-blend-mode:screen}
  #glyphmap .glyph{position:absolute;left:50%;top:50%;opacity:0;white-space:nowrap;line-height:1;
    will-change:transform,opacity;transform:translate(-50%,-50%);
    font-family:'VT323',ui-monospace,monospace;color:rgba(210,255,250,.72);
    text-shadow:0 0 16px rgba(120,255,255,.5)}
  /* the 3D star-cruise hides the map layers; the glyphs there are THREE.Sprites. */
  body.view-starcruise #glyphmap{display:none}
  .brand{position:fixed;top:.7rem;left:1rem;z-index:3;font-family:Orbitron,sans-serif;font-size:1.02rem;letter-spacing:.05em;margin:0;
    background:linear-gradient(90deg,var(--amber),var(--pink) 52%,var(--cyan));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
  .help{font-size:.7rem;padding:.1rem .5rem;border-radius:99px;vertical-align:middle;margin-left:.5rem;
    border:1px solid var(--line2);background:rgba(28,24,56,.6);color:var(--dim);cursor:pointer;-webkit-text-fill-color:var(--dim)}
  .help.on{border-color:var(--pink);color:var(--pink);-webkit-text-fill-color:var(--pink)}
  /* ABOUT (the ? layer): what stellate is + how to play + provenance. Rides the
     shared modal plumbing; anchored under the brand like the old .sub docs. */
  #about{position:absolute;top:3.1rem;left:1rem;width:min(430px,calc(100vw - 2rem));
    max-height:calc(100vh - 4rem);overflow:auto;background:rgba(12,10,26,.92)}
  #about h2{font-size:.72rem;color:var(--ink)}
  #about .ab-what{margin:.1rem 0 .7rem;font-size:.84rem;line-height:1.55}
  #about .ab-what b{color:var(--amber);font-weight:400}
  #about .ab-how{display:block;margin:.2rem 0 .9rem;padding:.5rem .7rem;border:1px solid var(--line2);
    border-radius:9px;font-family:Orbitron,sans-serif;font-size:.68rem;letter-spacing:.14em;
    text-transform:uppercase;text-decoration:none;color:var(--pink);
    background:linear-gradient(90deg,rgba(255,110,199,.12),rgba(69,224,255,.12))}
  #about .ab-how:hover{border-color:var(--pink)}
  #about .ab-h{font-family:Orbitron,sans-serif;font-size:.6rem;letter-spacing:.2em;
    text-transform:uppercase;color:var(--dim);margin:0 0 .35rem}
  #about .ab-play{margin:0 0 .8rem;color:var(--dim);font-size:.8rem;line-height:1.55}
  #about .ab-play b{color:var(--ink)}
  /* attribution: sits directly under the h2, so it wears a bottom rule as a
     header underline — not the top rule it had when it was the card's footer */
  #about .ab-foot{margin:0 0 .7rem;padding-bottom:.6rem;border-bottom:1px solid var(--line);
    color:var(--dim);font-size:.76rem}
  .card h2{cursor:pointer;user-select:none}
  .card.min{padding:.45rem .9rem}
  .card.min>:not(h2){display:none}
  .card{background:rgba(18,15,38,.62);backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px);
    border:1px solid var(--line);border-radius:12px;padding:.9rem}
  .card h2{font-family:Orbitron,sans-serif;font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;color:var(--dim);margin:0 0 .6rem}
  /* CONTROLS ARE MODAL: the sky is clean by default. Only the brand + three
     chips (playChip/npChip/cfgChip) float; each surface opens as a modal over
     the plane and closes on backdrop tap / its chip / esc. */
  .modal{position:fixed;inset:0;z-index:5;display:none;background:rgba(6,5,14,.44)}
  /* EXCLUSIVE FULL-SCREEN VIEWS: each is its own 100% view, and turning one on
     turns the star map off. A body class names the active view and the star map
     hides outside its own. The ⚙ settings modal (z-index 7 below) rides on top
     of every view; chips (z 6) stay on the bottom in all of them. */
  body.view-video #map, body.view-viz #map{display:none}
  /* the viz as a 100% VIEW: the modal wrap loses its dim backdrop and the card
     expands to the whole viewport (chips clearance at the bottom). */
  body.view-viz #insideWrap{display:block;background:var(--bg);overflow:hidden}  /* the viz zoom viewport: clips the scaled #inside */
  body.view-viz #inside{left:0;right:0;top:0;bottom:0;transform:none;width:auto;
    max-width:none;max-height:none;border:0;border-radius:0;
    padding:1rem 1.2rem 4.6rem;overflow-y:auto;touch-action:pan-y}  /* pan-y = native scroll but NO browser pinch-zoom of the viz */
  /* VIZ ZOOMED (starmap.js VIZ state): an inline CSS transform scales #inside about
     its top-left; transform-pan owns motion, so native scroll steps aside and the
     surface owns the pinch entirely (touch-action:none) — no iOS fall-through. */
  body.view-viz.viz-zoomed #inside{overflow:hidden;touch-action:none;transform-origin:0 0}
  #panelWrap{z-index:7}   /* settings above every view (map, video, viz) */
  #aboutWrap{z-index:7}
  .modal.open{display:block}
  /* the ⚙ panel pops up RIGHT-ALIGNED ABOVE the settings button (the chips row
     sits at bottom:.7rem, 48px tall), not at the top of the screen. It
     grows upward and scrolls if it ever gets tall. */
  #panel{position:absolute;bottom:4.2rem;right:.7rem;width:330px;max-height:calc(100vh - 5.6rem);overflow:auto}
  body.dragging{user-select:none;-webkit-user-select:none;cursor:crosshair}
  /* 61 stars: labels fade back — it's a star chart, constellation over caption */
  .anchor{font:11px VT323,monospace;fill:rgba(220,214,255,.42);text-shadow:0 0 6px #000;transition:fill .45s ease}
  .anchor.hot{fill:rgba(255,229,246,.95);font-size:12px}
  /* while a pointer works the map (drag/pinch/wheel, +600ms), labels light full
     white so you can read where you are; they ease back to dim when you let go */
  #map.itx .anchor{fill:#fff}
  .wlabel{font:11px VT323,monospace;fill:#4dffb0}
  .wpn{font:11px VT323,monospace;fill:#0c0a1a;font-weight:700}
  /* REGION titles: big goofy territory names washed behind the stars. Fill is set
     inline per-region (the territory color); the dark stroke keeps them legible
     over bright footage, and they sit faint so the constellation reads on top. */
  .region{font-family:VT323,monospace;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
    opacity:.5;paint-order:stroke;stroke:rgba(6,4,20,.6);stroke-width:3px;stroke-linejoin:round}
  /* the chips: the ONLY floating affordances (with the brand) */
  #chips{position:fixed;right:.7rem;bottom:.7rem;z-index:6;display:flex;gap:.5rem}
  /* ALIENS VIEW: the 3D canvas is a full-screen overlay (z 40) — float the chips ABOVE it
     (and above the VHS overlay at 44) so the ✦ view chip stays tappable to cycle out. */
  body.view-starcruise #chips{z-index:50}
  body.view-starcruise .brand{z-index:50;position:relative}
  /* the ⚙ settings + about modals must also ride ABOVE the 3D canvas (40), the
     VHS overlay (44), and the HUD (55) — else opening ⚙ in aliens view pops the
     panel behind the flight and it looks like nothing happened. */
  body.view-starcruise #panelWrap, body.view-starcruise #aboutWrap{z-index:60}
  .chip{width:48px;height:48px;border-radius:50%;font-size:1.25rem;line-height:1;display:grid;place-items:center;
    padding:0;border:1px solid var(--line2);color:var(--ink);cursor:pointer;
    background:rgba(18,15,38,.72);backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px)}
  .chip.on{border-color:var(--pink);color:var(--pink)}
  #playChip.live{background:linear-gradient(90deg,var(--pink),var(--purple));border-color:transparent;color:#0c081a;font-weight:700}
  /* now-playing lower-third: a bottom sheet inside its modal */
  #playhead{position:absolute;left:50%;transform:translateX(-50%);bottom:4.6rem;
    font:14px VT323,monospace;color:var(--mint);background:rgba(12,10,26,.9);border:1px solid var(--line);
    border-radius:12px;padding:.6rem .8rem;line-height:1.5;white-space:pre-wrap;
    width:min(560px,94vw);max-height:min(60vh,480px);overflow:auto}
  /* INSIDE THE SOUND: the "what's in this mix" readout — a bottom sheet.
     Live layers: genre BLEND bar, a FEEL radar, and a VOICE TIMELINE (a compact
     piano-roll of what each instrument is playing this bar). Same VT323/neon
     palette as every other readout. */
  #inside{position:absolute;left:50%;transform:translateX(-50%);bottom:4.6rem;
    width:min(560px,94vw);max-height:min(74vh,580px);overflow:auto;
    background:rgba(12,10,26,.94);border:1px solid var(--line)}
  #inside h2{font-family:Orbitron,sans-serif;font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;color:var(--dim);margin:0 0 .55rem}
  .vz-sec{margin:.35rem 0 1.25rem}
  .vz-lbl{font:14px VT323,monospace;letter-spacing:.12em;text-transform:uppercase;color:var(--cyan);opacity:.85;margin-bottom:.32rem}
  .vz-bar{display:flex;height:22px;border-radius:11px;overflow:hidden;background:rgba(255,255,255,.06);border:1px solid var(--line)}
  .vz-bar>div{height:100%;min-width:2px;transition:width .2s ease}
  .vz-leg{display:flex;flex-wrap:wrap;gap:.15rem .85rem;margin-top:.42rem;font:15px VT323,monospace;color:var(--ink)}
  .vz-g{display:inline-flex;align-items:center;gap:.35rem}
  .vz-g i{width:9px;height:9px;border-radius:2px;display:inline-block}
  .vz-g b{color:var(--mint);font-weight:400}
  .vz-info{margin-top:.42rem;font:14px VT323,monospace;color:var(--dim);line-height:1.4}
  .radar{display:block;margin:.25rem auto 0;max-width:400px}   /* 340 * 260/220 — holds the rose's on-screen size against the widened label bleed */
  .radar .rax{font:11px VT323,monospace;fill:var(--dim);letter-spacing:.04em}
  .vz-feelnums{text-align:center;font:14px VT323,monospace;color:var(--mint);opacity:.92;margin-top:.15rem}
  .vz-feelnums b{color:var(--dim);font-weight:400}
  /* MIND — the MUSIC-MIND axes: thin mint meters + the active moves line */
  .vz-mind{display:flex;flex-direction:column;gap:.16rem}
  .vz-mrow{display:flex;align-items:center;gap:.5rem;font:14px VT323,monospace;color:var(--ink)}
  .vz-mn{flex:0 0 76px;color:var(--dim);text-transform:uppercase;font-size:11px;letter-spacing:.1em}
  .vz-mbar{flex:1 1 auto;height:7px;border-radius:4px;background:rgba(255,255,255,.06);border:1px solid var(--line);overflow:hidden}
  .vz-mbar i{display:block;height:100%;background:var(--mint);opacity:.85}
  .vz-mrow b{flex:0 0 26px;text-align:right;color:var(--mint);font-weight:400}
  .vz-mmoves{font:14px VT323,monospace;color:var(--dim);margin-top:.12rem;line-height:1.45}
  .vz-mmoves b{color:var(--cyan);font-weight:400}
  /* the meter badge — floats over the radar corner */
  .vz-meter{float:right;font:16px VT323,monospace;letter-spacing:.1em;color:var(--cyan);
    border:1px solid var(--cyan);border-radius:4px;padding:.05rem .45rem;opacity:.85}
  .vz-in{display:flex;align-items:baseline;gap:.55rem;flex-wrap:wrap;font:16px VT323,monospace;margin:.16rem 0}
  .vz-ir{flex:0 0 46px;color:var(--dim);text-transform:uppercase;font-size:11px;letter-spacing:.1em}
  .vz-inm{color:var(--pink)}
  /* effects as tiny text UNDER each lane's roll — no stacked lozenges */
  /* fx tiny-text beneath the roll, indented to align under it (past the 128px head) */
  .vz-fxline{font-size:9px;line-height:1.4;letter-spacing:.02em;color:var(--dim);opacity:.72;
    margin:.1rem 0 0;white-space:normal}
  .vz-master .vz-fxline{color:var(--amber);opacity:.85;margin-left:0}
  .vz-fx{display:inline-flex;flex-wrap:wrap;gap:.28rem}
  .vz-fx i{font-style:normal;font-size:11px;line-height:1.5;letter-spacing:.02em;color:var(--cyan);
    background:rgba(69,224,255,.10);border:1px solid rgba(69,224,255,.28);border-radius:99px;padding:.02rem .42rem}
  .vz-master{margin-top:.45rem;padding-top:.4rem;border-top:1px solid var(--line)}
  .vz-master .vz-fx i{color:var(--amber);background:rgba(255,216,107,.10);border-color:rgba(255,216,107,.30)}
  .vz-found{margin-top:.4rem;font:14px VT323,monospace;color:var(--cyan);opacity:.85}
  /* the VOICE TIMELINE: a lane per instrument, a beat-gridded piano-roll of what
     it plays this bar. Header (name + fx) on the left, the roll on the right. */
  .vz-ruler{position:relative;height:13px;margin:0 0 .1rem;
    border-radius:4px 4px 0 0;background-color:rgba(255,255,255,.02)}
  .vz-ruler span{position:absolute;top:0;font:11px VT323,monospace;color:var(--dim);opacity:.7;padding-left:2px}
  /* TITLE ABOVE THE ROLL: each lane is a header row (name+role)
     ABOVE a full-width piano-roll, with its fx caption beneath; extra vertical
     breathing room between lanes. */
  .vz-tlrow{display:flex;flex-direction:column;gap:.24rem;margin:1.45rem 0}
  .vz-tlmain{display:flex;flex-direction:column;gap:.22rem}
  .vz-tlhead{display:flex;align-items:baseline;gap:.5rem;min-width:0}
  .vz-tlname{display:flex;align-items:center;gap:.32rem;font:19px VT323,monospace;color:var(--pink);
    line-height:1.05;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .vz-tlname i{flex:0 0 auto;width:9px;height:9px;border-radius:2px;display:inline-block}
  .vz-tlrole{font:10px VT323,monospace;text-transform:uppercase;letter-spacing:.12em;color:var(--dim);opacity:.8}
  .vz-roll{position:relative;width:100%;min-width:0;height:50px;border-radius:6px;
    border:1px solid var(--line);background-color:rgba(255,255,255,.03);overflow:hidden}
  /* THE UNIT IS ALWAYS 8: longer chord bars PAGE — one row per lane whose window
     slides to the next 8 beats when the live beat crosses a page edge (the old
     stacked fold rows read as duplicated bars). The pager strip
     is clipped by the roll; a flip is a fast slide, never a scroll. */
  .vz-pager{position:absolute;inset:0;display:flex;transition:transform .14s ease-out}
  .vz-page{position:relative;flex:0 0 auto;height:100%}
  /* the dead tail of a partial last page is hatched */
  .vz-dead{position:absolute;top:0;right:0;height:100%;pointer-events:none;
    background:repeating-linear-gradient(45deg,rgba(255,255,255,.05) 0 4px,transparent 4px 8px)}
  /* ONE shared live playhead across every lane (they share the beat grid): a
     thin pink beat cursor, lit by the ~10Hz ticker only while LIVE + ⓘ open */
  .vz-tl{position:relative}
  .vz-ph{position:absolute;top:0;bottom:0;left:0;right:0;pointer-events:none;display:none}
  .vz-ph.on{display:block}
  /* the playhead lights ONE ruler cell at a time and steps cell to cell — no
     stripe, no sweep: each BAR lights up as it progresses, and there is no
     vertical playhead stripe. Width set inline. */
  .vz-ph i{position:absolute;top:0;bottom:0;background:rgba(255,110,199,.17);
    box-shadow:inset 0 0 12px rgba(255,110,199,.2);opacity:.95}
  /* quiet page indicator: ·1/2 in the ruler's EMPTY left gutter (over the lane-
     header column) — at 420px the roll's last beat number owns the right edge */
  .vz-pgind{position:absolute;right:3px;top:0;font:10px VT323,monospace;
    color:var(--dim);opacity:.7;letter-spacing:.05em;white-space:nowrap}
  .vz-blk{position:absolute;height:14%;min-width:2px;border-radius:2px;transition:opacity .12s linear}
  /* a found BED: one sustained texture ribbon, not a hit */
  .vz-blk.vz-bed{height:44%;border-radius:3px}
  /* AUDIT-TRUTH: a lane the audit measured as EXPECTED-BUT-SILENT this bar — notes were
     scheduled but no audio was rendered (missing sample buffers, or a render-side mute).
     Red hatch over the whole roll; the header name goes red with a ✕ badge. */
  .vz-roll.vz-silent{border-color:rgba(255,64,80,.85)}
  .vz-roll.vz-silent::after{content:"";position:absolute;inset:0;pointer-events:none;border-radius:5px;
    background:repeating-linear-gradient(45deg,rgba(255,48,64,.34) 0 6px,rgba(255,48,64,.10) 6px 12px)}
  .vz-tlrow.vz-silent .vz-tlname{color:#ff5064}
  .vz-silbadge{font:9px VT323,monospace;color:#0c081a;background:#ff5064;border-radius:3px;
    padding:0 .28rem;margin-left:.3rem;letter-spacing:.04em;text-transform:uppercase}
  /* MIXING NODE GRAPH — the signal-flow topology beneath the rolls: voice boxes +
     insert chain → send curves (width/opacity = level) → reverb/delay bus → master
     → out. Replaces the master effects TEXT line. */
  .vz-graph{display:block;width:100%;max-width:470px;margin:.15rem auto 0;height:auto;overflow:visible}
  .vz-graph .gnode{fill:rgba(28,24,56,.42);stroke:var(--line2);stroke-width:1}   /* translucent — read the send curves beneath */
  .vz-graph .gins{fill:rgba(69,224,255,.07);stroke:rgba(69,224,255,.42);stroke-width:1}
  .vz-graph .grev{fill:rgba(69,224,255,.07);stroke:var(--cyan);stroke-width:1.2}
  .vz-graph .gdel{fill:rgba(255,216,107,.07);stroke:var(--amber);stroke-width:1.2}
  .vz-graph .gmaster{fill:rgba(77,255,176,.06);stroke:var(--mint);stroke-width:1.2}
  .vz-graph .gout{fill:rgba(255,110,199,.10);stroke:var(--pink);stroke-width:1.2}
  .vz-graph .gtx{font:13px VT323,monospace;fill:var(--ink)}
  .vz-graph .gsub{font:11px VT323,monospace;fill:var(--dim)}
  .vz-graph .gmix{font:11px VT323,monospace;fill:var(--cyan)}
  .vz-graph .gchip{font:13px VT323,monospace;fill:var(--ink)}   /* per-voice fx chip label (the full strip+insert chain) */
  .vz-graph .gdsub{font:11px VT323,monospace;fill:var(--amber)}
  .vz-graph .goutx{font:13px VT323,monospace;fill:var(--pink)}
  .vz-graph .ghead{font:10px VT323,monospace;fill:var(--dim);letter-spacing:.14em;text-transform:uppercase;opacity:.6}
  /* the chyron: music-video lower-third (namebank.js invents the band) */
  .chy{border-left:3px solid var(--pink);padding-left:.65rem}
  .chy-title{font-family:Orbitron,sans-serif;font-size:.9rem;letter-spacing:.09em;color:#fff}
  .chy-artist{font-size:1.2rem;color:var(--pink);line-height:1.25}
  .chy-album{color:var(--dim)}
  .chy-roster{margin-top:.35rem;color:var(--ink);opacity:.88}
  .chy-inst{color:var(--cyan)}
  .chy-join{color:var(--amber);margin-top:.15rem}
  .chy-tech{margin-top:.4rem;color:var(--mint);opacity:.8;font-size:12px;line-height:1.45}
  .chy-status{margin-top:.25rem;color:var(--cyan);font-size:12px}
  /* SETTINGS PANEL: grouped sections, aligned rows, no wrapping value labels. */
  .psec{margin:.2rem 0 .5rem;padding:.15rem 0 .45rem;border-bottom:1px solid var(--line)}
  .psec:last-of-type{border-bottom:none}
  .ptitle{font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);opacity:.7;margin:.1rem 0 .28rem}
  .row{display:flex;align-items:center;gap:.55rem;margin:.28rem 0}
  .row label{width:70px;flex:none;font-size:.72rem;color:var(--dim)}
  .row input[type=range]{flex:1;min-width:0;accent-color:var(--pink);margin:0}
  .row output{flex:none;min-width:60px;text-align:right;color:var(--mint);font-variant-numeric:tabular-nums;font-size:.72rem;white-space:nowrap}
  .row select{flex:1;min-width:0;background:rgba(28,24,56,.6);border:1px solid var(--line);border-radius:8px;color:var(--ink);padding:.28rem .4rem;font-size:.76rem}
  button{font:inherit;cursor:pointer;border-radius:9px;border:1px solid var(--line2);background:rgba(28,24,56,.6);color:var(--ink);padding:.45rem .8rem}
  button.go{background:linear-gradient(90deg,var(--pink),var(--purple));border:none;color:#0c081a;font-weight:700}
  button.mini{flex:none;padding:.3rem .55rem;font-size:.74rem;white-space:nowrap}
  .btns{display:grid;grid-template-columns:1fr 1fr;gap:.4rem;margin-top:.15rem}
  .btns button{padding:.5rem .4rem;font-size:.8rem;text-align:center;white-space:nowrap;
    display:flex;align-items:center;justify-content:center}
  .btns button:disabled{opacity:.4;cursor:default}
  .btns button.rec{background:linear-gradient(90deg,#c0305a,#7a2050);border-color:#c0305a;color:#fff;font-weight:600}
  /* export progress bar */
  .exprog{margin:.1rem 0 .6rem}
  .exbar{height:8px;border-radius:5px;background:rgba(255,255,255,.08);overflow:hidden}
  .exfill{height:100%;background:linear-gradient(90deg,var(--pink),var(--cyan));transition:width .2s ease}
  .exlabel{margin-top:.24rem;font-size:.68rem;color:var(--mint);font-variant-numeric:tabular-nums}
  .sc{display:flex;align-items:center;gap:.5rem;font-size:.7rem;margin:.16rem 0}
  .sc .g{width:78px;color:var(--dim)}
  .sc .bar{flex:1;height:6px;border-radius:4px;background:rgba(255,255,255,.07);overflow:hidden}
  .sc .f{height:100%;background:linear-gradient(90deg,var(--pink),var(--cyan))}
  .sc .v{width:28px;text-align:right;color:var(--mint);font-variant-numeric:tabular-nums}
  .seedin{width:90px;background:rgba(28,24,56,.6);border:1px solid var(--line);border-radius:8px;color:var(--ink);padding:.3rem .5rem}
  .hint{color:var(--dim);font-size:.7rem;margin-top:.45rem}
  /* MACROS: eight global axes — a compact block, VT323 poles either side of a
     centre-detented slider (the pink accent lights when an axis is off-zero) */
  .mac{margin:.55rem 0 .2rem;padding:.5rem .55rem;border:1px solid var(--line);border-radius:10px;
    background:rgba(28,24,56,.35)}
  .mac-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:.35rem}
  .mac-h span{font-family:Orbitron,sans-serif;font-size:.56rem;letter-spacing:.16em;text-transform:uppercase;color:var(--dim)}
  .mac-rst{padding:.18rem .5rem;font-size:.66rem;border-radius:7px}
  .mac-rst:disabled{opacity:.4;cursor:default}
  .mrow{display:grid;grid-template-columns:52px 1fr 52px;gap:.4rem;align-items:center;margin:.16rem 0}
  .mrow .ml{font-size:.66rem;color:var(--dim);text-align:right}
  .mrow .mr{font-size:.66rem;color:var(--dim)}
  .mrow input[type=range]{width:100%;accent-color:var(--line2);margin:0}
  .mrow.act input[type=range]{accent-color:var(--pink)}
  .mrow.act .ml,.mrow.act .mr{color:var(--mint)}
  a{color:var(--cyan)}
  /* BOOT PROGRESS: a chrome hairline pinned to the top edge (pixel-locked like
     the chips/brand — px, fixed, never scales with the map). Same pink→cyan
     the score bars use; a shimmer sweep marks an honest stall. */
  #boot{position:fixed;left:0;top:0;width:100%;z-index:8;pointer-events:none;
    opacity:0;transition:opacity .35s ease}
  #boot.on{opacity:1}
  #boot .btrack{position:relative;height:3px;width:100%;overflow:hidden;
    background:rgba(255,255,255,.06)}
  #boot .bfill{height:100%;width:0;background:linear-gradient(90deg,var(--pink),var(--cyan));
    box-shadow:0 0 8px var(--pink);transition:width .5s cubic-bezier(.4,0,.2,1)}
  #boot.ind .btrack::after{content:"";position:absolute;inset:0;width:38%;
    background:linear-gradient(90deg,transparent,rgba(255,255,255,.55),transparent);
    animation:bootshim 1.05s linear infinite}
  @keyframes bootshim{from{transform:translateX(-120%)}to{transform:translateX(330%)}}
  #boot .blabel{position:absolute;top:9px;left:50%;transform:translateX(-50%);
    font:12px VT323,monospace;letter-spacing:.14em;color:var(--cyan);
    text-shadow:0 0 6px #000;white-space:nowrap}
  @media(max-width:640px){
    #panel{left:.5rem;right:.5rem;top:auto;bottom:4.2rem;width:auto;max-height:46vh}
    #chips{right:.5rem;bottom:.5rem}
    #playhead{font-size:12px;bottom:4.2rem}
    .brand{font-size:.9rem}
  }

/* ACCESSIBLE-VERSION skip link: the star map is a pure-visual SVG instrument, so
   a screen-reader user landing here is offered the text version first thing. Off
   screen until focused (keyboard Tab reveals it); a11y best practice. */
.a11y-skip{position:absolute;left:.5rem;top:.5rem;z-index:1000;
  background:#0b0e17;color:#eef2ff;border:2px solid #6ea8ff;border-radius:.4rem;
  padding:.6rem 1rem;font:600 14px/1 system-ui,sans-serif;text-decoration:none;
  transform:translateY(-160%);transition:transform .15s}
.a11y-skip:focus{transform:none;outline:3px solid #ffd23f}

/* the view chip's SPINNER state: rides while the next view warms (video layer
   coming up); cleared by applyBg the moment the layer is genuinely enabled. */
.chip.spin{animation:chipspin 1s linear infinite}
@keyframes chipspin{to{transform:rotate(360deg)}}

/* ── THE STANDING CREDIT ────────────────────────────────────────────────────
   "made by Paul Ford at Aboard", always on screen, never in the way: bottom-LEFT
   (the chips own bottom-right, #playhead owns bottom-centre), dim VT323, and
   pointer-events only on the two links so the star map keeps the whole viewport
   to drag on. Hidden inside the 3D star-cruise, which draws its own world. */
.credit{position:fixed;left:.9rem;bottom:.8rem;z-index:6;margin:0;pointer-events:none;
  font:13px/1 VT323,monospace;letter-spacing:.06em;color:var(--dim);opacity:.82;
  text-shadow:0 0 4px #06040f,0 0 10px rgba(6,4,20,.95)}
.credit a{pointer-events:auto;color:var(--dim);text-decoration:none;border-bottom:1px dotted var(--line2)}
.credit a:hover{color:var(--cyan);border-bottom-color:var(--cyan)}
.credit:hover{opacity:1}
body.view-starcruise .credit, body.view-viz .credit{display:none}
@media(max-width:640px){ .credit{font-size:11px;left:.5rem;bottom:.45rem} }

/* HONEST BOOT FAILURE (panels.js bootFailWatch): when the engine can't start at
   all — no WebAudio, no WASM, a blocked worklet — the warm-up hairline stops
   pretending and turns amber with the real reason, instead of silently vanishing
   and leaving a 400px embed looking merely broken. */
#boot.fail .bfill{background:linear-gradient(90deg,var(--amber),var(--pink));box-shadow:0 0 8px var(--amber)}
#boot.fail .blabel{color:var(--amber)}

/* ── EMBED MODE (embed.html) ─────────────────────────────────────────────────
   The SAME app, in a 400px box on someone else's page. Nothing here forks the
   engine or the map: `body.embed` just suppresses the surfaces that make no
   sense in an embed (settings, about, the viz/aliens views, the lower-third)
   and shrinks the two that do (the brand and the ▶ chip). The modal DOM still
   exists — panels.js binds to it at load — it is simply never openable. */
body.embed .modal{display:none!important}
body.embed #cfgChip, body.embed #viewChip, body.embed .help{display:none}
body.embed #playhead{display:none}
/* the drifting alien-ident glyphs are ambient wallpaper at 1200px and a smear at
   400px — they are drawn at absolute sizes, so in a small box they swallow the
   map. Off in embeds (the layer keeps running elsewhere, untouched). */
body.embed #glyphmap{display:none}
body.embed .credit{opacity:.85}
body.embed .brand{font-size:.8rem;top:.5rem;left:.6rem}
body.embed #chips{right:.5rem;bottom:.5rem}
body.embed .chip{width:40px;height:40px;font-size:1.05rem}
body.embed .credit{left:.6rem;bottom:.5rem;font-size:11px}
/* the escape hatch: every embed carries ONE link back to the full instrument
   (target=_blank, because we are inside someone else's frame). */
.embed-open{position:fixed;right:.6rem;top:.5rem;z-index:6;
  font:12px/1 VT323,monospace;letter-spacing:.1em;text-transform:uppercase;
  color:var(--dim);text-decoration:none;border:1px solid var(--line2);border-radius:99px;
  padding:.32rem .6rem;background:rgba(18,15,38,.72);
  backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px)}
.embed-open:hover{color:var(--cyan);border-color:var(--cyan)}
/* THE PLAY AFFORDANCE. An embed must never autoplay (browsers block it and it
   is rude), so the box opens with a big, obvious, keyboard-reachable invitation
   over the map; the first tap is the user gesture that unlocks audio. */
#embedPlay{position:fixed;inset:0;z-index:7;display:grid;place-items:center;
  border:0;width:100%;cursor:pointer;color:var(--ink);
  /* the scrim has to actually WIN over a field of genre labels — the first pass
     was translucent enough that "tap to play" read as part of the star map. */
  background:radial-gradient(circle at 50% 44%,rgba(80,40,140,.60),rgba(6,5,14,.90) 66%),rgba(6,5,14,.55);
  backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}
#embedPlay.gone{display:none}
#embedPlay .ep-in{display:grid;justify-items:center;gap:.55rem;pointer-events:none}
#embedPlay .ep-disc{width:66px;height:66px;border-radius:50%;display:grid;place-items:center;
  font-size:1.7rem;color:#0c081a;background:linear-gradient(90deg,var(--pink),var(--purple));
  box-shadow:0 0 30px rgba(255,110,199,.45)}
#embedPlay .ep-t{font-family:Orbitron,sans-serif;font-size:.72rem;letter-spacing:.2em;text-transform:uppercase;
  background:linear-gradient(90deg,var(--amber),var(--pink) 52%,var(--cyan));
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
#embedPlay .ep-s{font:13px VT323,monospace;letter-spacing:.06em;color:var(--dim);
  max-width:min(84%,320px);text-align:center}
#embedPlay:focus-visible{outline:3px solid var(--amber);outline-offset:-6px}

/* ── THE EMBED SNIPPET (⚙ panel) ─────────────────────────────────────────────
   A readonly <textarea> holding the ready-to-paste <iframe>, next to a copy
   button that behaves exactly like ↗ share (clipboard, legacy fallback, a
   status line). The snippet always carries THIS view — same seed/path/measure
   URL builder the share link uses. */
/* the "preview ↗" link sits beside a button.mini and must read as its twin */
a.mini{flex:none;padding:.3rem .55rem;font-size:.74rem;white-space:nowrap;
  border-radius:9px;border:1px solid var(--line2);background:rgba(28,24,56,.6);
  color:var(--ink);text-decoration:none;line-height:1.45}
a.mini:hover{border-color:var(--cyan);color:var(--cyan)}
.embedbox{width:100%;margin:.15rem 0 .3rem;resize:vertical;min-height:4.6rem;
  font:11px/1.45 ui-monospace,SFMono-Regular,Menlo,monospace;
  background:rgba(8,6,20,.72);color:var(--mint);border:1px solid var(--line);
  border-radius:8px;padding:.45rem .55rem;-webkit-user-select:text;user-select:text}
.embedbox:focus{outline:1px solid var(--cyan)}

/* node-drag duration tooltip (starmap durTipShow — the path's own time at x1
   plus the dialed multiple's effective time; follows the pointer, no events) */
#durTip{position:fixed;z-index:60;display:none;pointer-events:none;white-space:nowrap;
  font:15px VT323,monospace;color:var(--mint);background:rgba(12,10,26,.92);
  border:1px solid var(--line);border-radius:9px;padding:.28rem .55rem;
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
