/* ============================================================================
 * phantasm-ui.css — PhantasmUI (visual half) · v2.6.0
 * Versioned as a whole with phantasm-ui.js — see CHANGELOG.md beside this
 * file; bump the version + changelog on every kit change, and retag every
 * consumer's ?v= to match.
 * ----------------------------------------------------------------------------
 * Design tokens + every
 * reusable component's styling. Self-contained, no build step. Load BEFORE the
 * app's own stylesheet so the app can compose/override:
 *     <link rel="stylesheet" href="ui/phantasm-ui.css">
 * Behaviours live in ui/phantasm-ui.js (window.PhantasmUI); conventions and
 * component docs in ui/docs/STYLE_GUIDE.md. Accent tints derive from the tokens
 * via color-mix(), so re-theming = editing :root.
 * The host app defines --pw (side-panel width) or overrides .disp-pop's anchor.
 * ==========================================================================*/
:root{
    --void:#070a12;
    --void2:#0a0f1d;
    --panel:rgba(13,19,34,0.88);   /* pop-over glass — raised from 0.72 (2026-07-06): --muted/--faint text was hard to read over busy stages */
    --ink:#e9eefb;
    --muted:#7e8aab;
    --faint:#4a5577;
    --line:rgba(120,150,210,0.12);
    --accent:#f5b441;
    --cool:#5ad1ff;
    --edge:rgba(120,150,210,0.16);
    --sel:#3dffa0;                 /* THE selection colour (one meaning only); JS twin: SEL_GREEN */
    --ctl-fill:rgba(10,14,24,0.6); /* ONE form-control fill on a CARD — .fld / .dd / checkbox / number / switch-OFF all share it; .subcard redefines it (below) for controls on a sub-card. Two fills, no per-control variation. */
    /* ---- SURFACE ELEVATION (opaque/flat family) — each step is LIGHTER than the one below. The header
       carries no fill of its own, so it shows --base; a card sits ONE step above the base; a sub-card one
       step above the card. Use these roles for surfaces, not the raw --void/--void2 (which stay the palette,
       + dropdown-menu/tooltip fills). The translucent pop-over surface is --panel/.glass — a separate family. */
    --base:  var(--void);    /* app background — what the header shows */
    --card:  var(--void2);   /* THE card / side-panel back-colour — one elevation step lighter than --base */
    --subcard: color-mix(in srgb, var(--cool) 3.5%, transparent);   /* sub-card fill: a cool wash composited OVER --card -> lighter still (a card nested in a card) */
    /* ---- full-window POP-OUT layout (see the .pop-* block near the end + STYLE_GUIDE §12): a slim header
       over a left picker rail + a responsive card grid. Override these in your page to resize. */
    --pop-header-h:44px;     /* the slim pop-out header's height */
    --pop-rail-w:236px;      /* the left picker rail's width */
}

.mono{
    font-family:ui-monospace,"SF Mono","JetBrains Mono",Menlo,monospace;
    font-variant-numeric:tabular-nums;
    font-feature-settings:"tnum"
  }
/* gfx + sim rate readout: lives in the HEADER after the model name (the header is an opaque bar above the stage, so it can never collide with canvas content — axis ticks/labels, HUD, clouds — in any view/mode/panel state) */
.obs-cat{ font-size:11px;font-weight:600;color:var(--ink);letter-spacing:.02em; }
/* Observables sub-card: category header */
.obs-sublist{ margin-top:4px;font-size:11px;color:var(--muted);line-height:1.75;display:grid;grid-template-columns:1fr 48px 56px;align-items:baseline; }
/* the observables matrix under a category: name + a check column per variant (global | per type) */
.obs-sublist.off{ opacity:0.4; }
/* group toggled off -> its observables are unavailable */
.obs-colh{ font-size:8.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--cool);opacity:.85;text-align:center;align-self:end; }
/* matrix column headers: per type / system-wide */
.obs-chk{ color:var(--cool);font-weight:600;text-align:center; }
/* variant exists */
.obs-dash{ color:var(--muted);opacity:.45;text-align:center; }
.dd{                                               /* dropdown / select trigger — SAME box as .fld: radius 6, 30px control height (7px pad + 14px line-height), --edge border. Font stays 11.5 sans (labels), unlike .fld's 12 mono (values). */
    font-weight:400;
    appearance:none;
    -webkit-appearance:none;
    background:var(--ctl-fill);
    color:var(--ink);
    border:1px solid var(--edge);
    border-radius:6px;
    padding:7px 30px 7px 12px;
    font-size:11.5px;
    line-height:14px;                              /* pins the height to .fld's 30px (whose 12px 'normal' line box ≈ 14px), independent of the smaller label font */
    font-family:inherit;
    letter-spacing:.02em;
    cursor:pointer;
    transition:border-color .15s;
    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path d='M2 3.5 L5 6.5 L8 3.5' fill='none' stroke='%237e8aab' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat:no-repeat;
    background-position:right 11px center
  }
.dd:hover{border-color:rgba(120,150,210,0.4)}
.dd:focus{
    outline:none;
    border-color:var(--cool)
  }
.dd option{
    background:#0a0f1d;
    color:var(--ink)
  }
.dd optgroup{
    background:#0a0f1d;
    color:var(--faint);
    font-style:normal;
    font-weight:700;
    letter-spacing:.08em
  }
/* .fld = text inputs / textareas: same dark-edge treatment + electric-blue focus as .dd (no yellow UA ring) */
.fld{                                              /* THE text input. Complete recipe — style, height, font — lives HERE:
                                                      never re-pad or re-font .fld inline. 7px/12px padding = the same 30px
                                                      control height as .dd; the 12px mono face is the design system's
                                                      "values are mono" rule (labels stay sans). Code/JSON areas: .fld-code. */
    background:var(--ctl-fill);
    color:var(--ink);
    border:1px solid var(--edge);
    border-radius:6px;
    padding:7px 12px;
    font:12px ui-monospace,"SF Mono","JetBrains Mono",Menlo,monospace;
    transition:border-color .15s;
  }
.fld:hover{ border-color:rgba(120,150,210,0.4); }
.fld:focus{
    outline:none;
    border-color:var(--cool);
  }
/* checkboxes: themed box matching .dd/.fld, with an electric-blue check when ticked */
input[type=checkbox]{
    -webkit-appearance:none;
    appearance:none;
    width:15px;
    height:15px;
    flex:none;
    margin:0;
    border:1px solid var(--edge);
    border-radius:4px;
    background:var(--ctl-fill);
    cursor:pointer;
    position:relative;
    transition:border-color .15s, background .15s;
  }
input[type=checkbox]:hover{ border-color:rgba(120,150,210,0.4); }
input[type=checkbox]:checked{
    border-color:var(--cool);
    background:color-mix(in srgb, var(--cool) 14%, transparent);
  }
input[type=checkbox]:checked::after{
    content:'';
    position:absolute;
    left:3.5px;
    top:0px;
    width:3.5px;
    height:8px;
    border:solid var(--cool);
    border-width:0 2px 2px 0;
    transform:rotate(45deg);
  }
input[type=checkbox]:focus-visible{
    outline:none;
    border-color:var(--cool);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--cool) 14%, transparent);
  }
/* iOS-style on/off switch (a themed checkbox): used for per-rule enable in Simulation */
.switch{
    position:relative;
    display:inline-block;
    width:34px;
    height:20px;
    flex:none;
    cursor:pointer;
  }
.switch>input{
    position:absolute;
    inset:0;
    width:100%;
    height:100%;
    margin:0;
    opacity:0;
    cursor:pointer;
    z-index:1;
  }
.switch>.sw-bg{
    position:absolute;
    inset:0;
    box-sizing:border-box;
    border-radius:999px;
    border:1px solid var(--cool);
    background:var(--ctl-fill);                      /* OFF = the shared control fill (was --edge); ON = --cool below */
    transition:background .15s;
  }
/* electric-blue border kept in both states */
.switch>input:checked + .sw-bg{ background:var(--cool); }
.switch>.sw-bg::after{
    content:'';
    position:absolute;
    top:1px;
    left:1px;
    width:16px;
    height:16px;
    border-radius:50%;
    background:#fff;
    box-shadow:0 1px 2px rgba(0,0,0,0.35);
    transition:transform .15s;
  }
/* top/left:1px centres the knob inside the 1px border (box-sizing:border-box) */
.switch>input:checked + .sw-bg::after{ transform:translateX(14px); }
.seg button:disabled{
    opacity:.4;
    cursor:not-allowed;
  }
.hud{
    position:absolute;
    top:14px;
    left:14px;
    width:320px;                                    /* matches the View & Interaction popover (was 222 -> 290 -> 320, 2026-07-06) */
    border-radius:12px;
    padding:0;
    overflow:hidden;                                /* clips the window bar to the rounded corners */
    pointer-events:none;
  }
.row{
    font-weight:400;
    display:flex;
    justify-content:space-between;
    align-items:baseline;
    margin:5px 0;
    font-size:12px
  }
.row .k{color:var(--muted)}
.row .v{
    font-weight:400;font-size:13px}
.seg{                                              /* segmented control: full-width by default, buttons SPLIT the width evenly (a horizontal .seg must never leave its options left-clustered). Opt out with .seg.pill for a compact, fit-to-content header rendition. */
    display:flex;
    border:1px solid var(--edge);
    border-radius:9px;
    overflow:hidden
  }
.seg button{
    appearance:none;
    border:0;
    background:transparent;
    color:var(--muted);
    padding:8px 14px;
    font-size:12px;
    font-weight:600;
    cursor:pointer;
    letter-spacing:.01em;
    transition:background .15s,color .15s;
    flex:1 1 0;                                     /* each option takes an EQUAL share of the control's width (min-width:0 lets long labels shrink) */
    min-width:0;
  }
.seg button + button{border-left:1px solid var(--edge)}
.seg.vert{ flex-direction:column }                 /* stacked variant: options fill the width, sit at their natural height (no vertical stretch), left-aligned */
.seg.vert button{ flex:0 0 auto; text-align:left }
.seg.vert button + button{ border-left:0; border-top:1px solid var(--edge) }
.seg.vert button.on{ box-shadow:inset 2px 0 0 var(--cool) }
.seg.pill{ display:inline-flex; border-color:rgba(120,150,210,0.28); }   /* the GLOBAL/header rendition: joined pill, FIT-to-content (not full-width), selected = cool tint fill (no underline). Use for top-chrome selectors (e.g. the view switcher); the default .seg stays the full-width in-panel rendition. */
.seg.pill button{
    color:var(--ink);
    padding:7px 15px;
    font-size:11.5px;
    letter-spacing:.02em;
    flex:0 0 auto;                                  /* compact: buttons fit their label, the pill sizes to content */
  }
.seg.pill button.on{
    background:color-mix(in srgb, var(--cool) 10%, transparent);
    color:var(--cool);
    box-shadow:none;
  }
.seg.pill button.on:hover{ background:color-mix(in srgb, var(--cool) 16%, transparent); }
.seg button.on{
    background:transparent;
    color:var(--cool);
    box-shadow:inset 0 -2px 0 var(--cool)
  }
.seg button:not(.on):hover{
    color:var(--ink);
    background:rgba(120,150,210,0.07)
  }
.seg button:disabled{
    opacity:.35;
    cursor:not-allowed
  }
.slider{
    display:flex;
    flex-direction:column;
    gap:5px;
    min-width:130px
  }
.slider .top{                                      /* THE slider header row: name LEFT-justified (the label), live value RIGHT-justified (.num, 12px mono) on the same line — space-between does the justification; the track sits below. Markup: .slider > .top(label + .num) + input[type=range]. */
    display:flex;
    justify-content:space-between;
    align-items:baseline
  }
.slider label{
    font-weight:400;
    font-size:10.5px;
    letter-spacing:.16em;
    text-transform:uppercase;
    color:var(--faint)
  }
.slider .num{
    font-weight:400;
    font-size:12px;
    color:var(--ink)
  }
input[type=range]{
    -webkit-appearance:none;
    appearance:none;
    display:block;
    width:100%;
    height:3px;
    border-radius:3px;
    background:rgba(120,150,210,0.22);
    outline:none;
    cursor:pointer;
  }
input[type=range]::-webkit-slider-thumb{
    -webkit-appearance:none;
    box-sizing:border-box;
    width:14px;
    height:14px;
    border-radius:50%;
    background:var(--ink);
    border:2px solid var(--cool);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--cool) 12%, transparent)
  }
input[type=range]::-moz-range-thumb{
    box-sizing:border-box;
    width:14px;
    height:14px;
    border-radius:50%;
    background:var(--ink);
    border:2px solid var(--cool);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--cool) 12%, transparent)
  }
.trackwrap{position:relative}
.trackwrap.has-sp{
    margin-bottom:26px;
    isolation:isolate;
  }
/* room below for labels; isolate so the dot z-index stays scoped to this track */
.trackwrap.has-sp input[type=range]{
    position:relative;
    z-index:2;
    pointer-events:none;
  }
/* lift the track above the dots; the bare track ignores clicks... */
.trackwrap.has-sp input[type=range]::-webkit-slider-thumb{ pointer-events:auto; }
/* ...but the THUMB stays grabbable and sits above the dots -> thumb wins any overlap */
.trackwrap.has-sp input[type=range]::-moz-range-thumb{ pointer-events:auto; }
.smartpt{
    position:absolute;
    top:50%;
    transform:translate(-50%,-50%);
    width:10px;
    height:10px;
    border-radius:50%;
    background:var(--cool);
    background-clip:padding-box;
    opacity:.92;
    /* clip fill inside the border so the cyan doesn't bleed into/under the bezel */
    border:2px solid rgba(120,150,210,0.6);
    /* bezel = slider-axis hue at a visible strength (exact 0.22 match is invisible against the dot) */
    margin:0;
    padding:0;
    z-index:1;
    cursor:pointer;
    /* clickable to snap, but sits below the lifted track + thumb */
    -webkit-appearance:none;
    appearance:none;
    transition:box-shadow .12s, opacity .12s;
  }
.smartpt .sp-label{
    font-weight:400;
    position:absolute;
    left:50%;
    top:21px;
    transform:translateX(-50%);
    font-size:11px;
    letter-spacing:.05em;
    color:var(--cool);
    opacity:.9;
    white-space:nowrap;
    cursor:pointer;
    transition:opacity .12s;
  }
.smartpt:hover{
    opacity:1;
    box-shadow:0 0 0 3px color-mix(in srgb, var(--cool) 22%, transparent), 0 0 8px color-mix(in srgb, var(--cool) 60%, transparent);
  }
.smartpt:hover .sp-label{ opacity:1; }

.btn{
    appearance:none;
    border:1px solid var(--edge);
    background:transparent;
    color:var(--ink);
    padding:8px 16px;
    border-radius:9px;
    font-size:12px;
    font-weight:600;
    cursor:pointer;
    letter-spacing:.04em;
    --press-glow:var(--cool);                      /* the press-flash ring colour; each COLOURED variant overrides it to match itself */
    transition:background .15s,border-color .15s,transform .09s ease,filter .09s ease,box-shadow .12s ease;
  }
.btn:hover{
    background:rgba(120,150,210,0.08);
    border-color:var(--muted)
  }
/* PRESS FEEDBACK ("electric pop") — a pressed ACTION button brightens, flashes a 3px ring in its OWN
   colour (`--press-glow`, set per variant/control), and dips a hair of scale, springing back on release.
   SHARED by every action button: `.btn` (+ variants), the header icon buttons (`.view-gear`), the window
   close (`.pop-x`), and the card delete (`.subcard-x`). Deliberately NOT on selectors (`.seg` buttons,
   `.cp-tab`) — their meaning is "chosen state", not "fired action". */
.btn:active, .view-gear:active, .pop-x:active, .subcard-x:active{
    transform:scale(0.97);
    filter:brightness(1.15);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--press-glow) 42%, transparent);
  }
@media (prefers-reduced-motion:reduce){
    .btn:active, .view-gear:active, .pop-x:active, .subcard-x:active{ transform:none; }   /* keep the brighten + ring, drop the motion */
  }
.btn.is-green{
    background:#34c06a;
    border-color:#34c06a;
    color:#06210f;
    --press-glow:#34c06a                            /* the glow matches the button — a green pop, not a cyan one */
  }
.btn.is-green:hover{
    background:#3ed079;
    border-color:#3ed079
  }
.btn.on{
    background:var(--accent);
    border-color:var(--accent);
    color:#1a1205;
    --press-glow:var(--accent)
  }
.btn.on:hover{
    background:#f7c45f;
    border-color:#f7c45f
  }
.btn.is-yellow{
    background:#f1c84b;
    border-color:#f1c84b;
    color:#2a1f00;
    --press-glow:#f1c84b
  }
.btn.is-yellow:hover{
    background:#f7d566;
    border-color:#f7d566
  }
.btn.is-red{
    background:#dc4a4a;
    border-color:#dc4a4a;
    color:#fff;
    --press-glow:#dc4a4a                            /* a red pop for destructive buttons */
  }
.btn.is-red:hover{
    background:#e85d5d;
    border-color:#e85d5d
  }
/* LABEL PLACEMENT — the system's default: the field NAME (a .vis-label) sits on its own line ABOVE
   the widget (text box, dropdown, seg, …). .vis-group is the canonical stacked wrapper; .slider is the
   same shape with the value readout sharing the label line. Inline LEFT labels (64px) are reserved for
   dense editor-card rows; checkboxes/switches put their label AFTER the control (.chk-row). */
.vis-group{
    display:flex;
    flex-direction:column;
    gap:6px
  }
.dd-full{width:100%}
.vis-label{
    font-weight:400;
    font-size:10.5px;
    letter-spacing:.16em;
    text-transform:uppercase;
    color:var(--faint)
  }
input[type=color]{
    -webkit-appearance:none;
    appearance:none;
    width:46px;
    height:26px;
    padding:2px;
    border:1px solid var(--edge);
    border-radius:7px;
    background:transparent;
    cursor:pointer;
  }
input[type=color]::-webkit-color-swatch-wrapper{padding:0}
input[type=color]::-webkit-color-swatch{
    border:none;
    border-radius:5px
  }
input[type=color]::-moz-color-swatch{
    border:none;
    border-radius:5px
  }
.btn.primary{min-width:74px}
/* control-panel tab bar: floats over the section flow at the panel's bottom (post-launch only) */
.cp-tabs{
    position:absolute;
    left:0; right:0; bottom:0;
    z-index:6;
    display:flex;
    flex-direction:column;                           /* icon row on top; an optional status line (e.g. the fps readout) may sit under it */
    align-items:stretch;
    padding:9px 10px 8px;
    background:var(--card);                           /* shares the card back-colour it floats over */
    border-top:1px solid var(--line);
    box-shadow:0 -12px 22px rgba(0,0,0,0.45);
  }
.cp-tab-row{
    display:flex;
    justify-content:space-evenly;
    align-items:center;
  }
.cp-tab{
    background:none;
    border:1px solid transparent;
    border-radius:9px;
    padding:7px 12px;
    cursor:pointer;
    color:var(--muted);
    display:flex;
    transition:color .15s, background .15s, border-color .15s;
  }
.cp-tab:hover{ color:var(--ink); background:rgba(120,150,210,0.10); }
.cp-tab.on{ color:var(--cool); border-color:var(--cool); background:color-mix(in srgb, var(--cool) 10%, transparent); }
.cp-tab svg{ width:22px; height:22px; display:block; }
.cp-tab.pulse{ animation:cpTabPulse 1.1s ease-out 2; }
/* view switched -> the eye tab flashes twice: "this view's render options live here" */
@keyframes cpTabPulse{
    0%{ box-shadow:0 0 0 0 color-mix(in srgb, var(--cool) 55%, transparent); color:var(--cool); }
    70%{ box-shadow:0 0 0 9px rgba(90,209,255,0); color:var(--cool); }
    100%{ box-shadow:0 0 0 0 rgba(90,209,255,0); }
  }
.view-gear{                                                           /* header view selector's Display-settings shortcut */
    background:none;
    border:1px solid rgba(120,150,210,0.28);
    border-radius:7px;
    width:26px; height:26px;
    display:flex; align-items:center; justify-content:center;
    color:var(--muted);
    cursor:pointer;
    padding:0;
    flex:none;
    --press-glow:var(--cool);                                          /* press feedback (shared .btn:active rule) — cool glow */
    transition:color .15s, border-color .15s, background .15s, transform .09s ease, filter .09s ease, box-shadow .12s ease;
  }
.view-gear:hover{ color:var(--cool); border-color:var(--cool); background:color-mix(in srgb, var(--cool) 8%, transparent); }
.view-gear.on{ color:var(--cool); border-color:var(--cool); background:color-mix(in srgb, var(--cool) 12%, transparent); }
.view-gear.pulse{ animation:cpTabPulse 1.1s ease-out 2; }
.view-gear svg{ width:15px; height:15px; display:block; }
.disp-pop{                                                            /* compact floating Display panel (view-gear popover): holds the ACTIVE view's Display sections, reparented in while open. Persistent: the gear or its ✕ closes it. */
    position:absolute;
    top:14px;
    right:calc(var(--pw) + 14px);                                       /* upper-right of the VISIBLE viewport — mirrors the Statistics HUD's upper-left anchor. The loop OVERRIDES this inline, riding the panel's slide tween (panelW*(1-panelP)+14) so the popover glides with the panel edge. */
    z-index:6;
    width:320px;
    max-height:min(72vh, 640px);
    display:flex;
    flex-direction:column;
    overflow:hidden;                                                    /* the BODY scrolls, not the box -> the scrollbar stops below the header and the rounded corners clip it */
    border-radius:12px;
    box-shadow:0 18px 48px rgba(0,0,0,.6);
  }
.disp-pop-body{ flex:1 1 auto; min-height:0; overflow-y:auto; padding-top:8px; }
/* the scroll region: starts BELOW the window bar. padding-top clears the bar the way .hud-body's 11px does
   — the reparented .sec's own header is hidden here, so its 3px sec-inner top alone reads too tight (8+3≈11). */
.disp-pop-body::-webkit-scrollbar{ width:9px; }
.disp-pop-body::-webkit-scrollbar-thumb{ background:rgba(120,150,210,0.18); border-radius:5px; }
.pop-head, .disp-pop-head, .hud-head{                                             /* the shared pop-over window bar (title + ✕); sits OUTSIDE the scroll region so it is always in front */
    flex:0 0 auto;
    display:flex; justify-content:space-between; align-items:center;
    padding:10px 12px 8px 14px;
    background:rgba(13,19,34,0.96);                                      /* a step above --panel */
    border-bottom:1px solid var(--edge);
  }
.pop-head .t, .disp-pop-head .t, .hud-head .t{
    font-weight:400; font-size:9.5px; letter-spacing:.22em; text-transform:uppercase; color:var(--faint); }
.pop-head, .disp-pop-head, .hud-head{ cursor:grab; user-select:none; -webkit-user-select:none; }
.pop-head:active, .disp-pop-head:active, .hud-head:active{ cursor:grabbing; }
.hud-head{ pointer-events:auto; }
/* drag handle inside the otherwise click-transparent HUD */
.pop-x{                                                                /* shared ✕ close (the lattice-preview pk-close look) */
    background:none; border:none;
    color:var(--muted,#8b97b4);
    cursor:pointer;
    font-size:14px; line-height:1;
    padding:0 2px;
    pointer-events:auto;
    border-radius:5px;                                                  /* so the press ring/scale reads as a tidy rounded flash */
    --press-glow:var(--cool);                                          /* press feedback (shared .btn:active rule) — window buttons pop too */
    transition:color .15s, transform .09s ease, filter .09s ease, box-shadow .12s ease;
  }
.pop-x:hover{ color:var(--ink); }
.hud-body{ padding:11px 14px 12px; }
/* the HUD's content (the box itself is padding-less so the window bar spans edge-to-edge) */
.hud-sys{ font-size:10px; color:var(--muted); margin:-2px 0 9px; }
/* ensemble: the shown system's index, under the window bar */
.disp-pop .vis-label, .disp-pop .slider label{ color:var(--muted); }
/* contrast over the glass: lift the --faint control labels to the HUD's --muted key colour */
.disp-pop .hint{ color:var(--muted); }
.tip{                                                /* floating tooltip (see JS attachTip): body-appended + position:fixed so it ESCAPES a card's overflow:hidden; JS sets left/top (centred above the anchor, viewport-clamped). Was .cp-tab-tip (an absolutely-positioned child, clipped by the panel). */
    position:fixed;
    z-index:1100;                                    /* on top of everything: above pop-overs (880), the fullscreen panel peek (900), and dd menus (1000) */
    font-weight:400;
    background:var(--void2);                          /* a floating menu/tooltip surface — raw palette, not a card */
    border:1px solid var(--line);
    border-radius:7px;
    padding:5px 10px;
    font-size:10.5px;
    letter-spacing:.02em;
    color:var(--ink);
    white-space:nowrap;
    pointer-events:none;
    opacity:0;
    transition:opacity .12s;
    box-shadow:0 8px 22px rgba(0,0,0,0.5);
  }
.tip.show{ opacity:1; }
/* room for the floating tab bar: the last section can scroll fully above it */
.sec{ border-bottom:1px solid var(--line); }
.sec-head{
    width:100%;
    display:flex;
    align-items:center;
    justify-content:space-between;
    background:none;
    border:0;
    cursor:pointer;
    color:var(--accent);
    padding:14px 18px 13px;
    font-family:inherit;
    font-size:11px;
    font-weight:700;
    letter-spacing:.18em;
    text-transform:uppercase;
    transition:color .15s;
  }
.sec-head:hover{ color:var(--accent); }
.sec.fixed .sec-head{ cursor:default; }
.sec.fixed .sec-head:hover{ color:var(--accent); }
.sec-head .chev{
    width:7px;
    height:7px;
    border-right:1.5px solid currentColor;
    border-bottom:1.5px solid currentColor;
    transform:rotate(45deg);
    transition:transform .25s;
    opacity:.8;
    margin-bottom:3px;
  }
.sec.collapsed .sec-head .chev{
    transform:rotate(-45deg);
    margin-bottom:0;
  }
.sec-body{
    overflow:hidden;
    transition:height .28s ease;
  }
.sec.collapsed .sec-body{ height:0; }              /* CSS backstop: a collapsed section stays shut even if its inline height (set by toggleSec's animation) is later cleared. Inline height wins DURING the animation, so this never fights the transition. */
.sec-inner{
    display:flex;
    flex-direction:column;
    gap:15px;
    padding:3px 18px 20px;
  }
.sec-stack{ display:flex; flex-direction:column; gap:15px; }
/* CONVENTION: a wrapper div nested inside a .sec-inner (grouping sliders/rows so they can be toggled
   together) is a plain block by default, which COLLAPSES the section's inter-control rhythm to 0. Give it
   .sec-stack so its children keep the same 15px vertical gap as the control panel. Applies everywhere,
   pop-out windows included (their sections reparent the same .sec-inner markup). */
/* Overlay scrollbar (PhantasmUI.overlayScroll): a floating thumb over the scroller's right edge —
   never steals layout width, so content doesn't reflow/jitter when it starts or stops overflowing.
   .ovscroll hides the scroller's native bar; the thumb is drawn into the scroller's positioned parent
   and rides over its right-hand padding gutter (keep >= the bar's width of right padding on content). */
.ovscroll{ scrollbar-width:none; }                         /* Firefox: hide native */
.ovscroll::-webkit-scrollbar{ width:0; height:0; }         /* WebKit: hide native (the overlay thumb replaces it) */
.ovscroll-bar{
    position:absolute;
    right:3px;
    width:8px;
    z-index:4;                                             /* above the scroller's in-flow content, below floating footer bars (e.g. a tab/action bar at z:6) */
    pointer-events:none;                                   /* the track is transparent; only the thumb catches the pointer */
  }
.ovscroll-thumb{
    position:absolute;
    top:0; right:0;
    width:100%; height:0;
    border-radius:5px;
    background:rgba(120,150,210,0.18);                     /* the --line/--edge blue-grey family; mirrors the native thumb it replaces */
    pointer-events:auto;
    cursor:default;
    transition:background .15s;
  }
.ovscroll-thumb:hover{ background:rgba(120,150,210,0.32); }
.sec-inner .slider{ min-width:0; }
/* the LM-launcher source-toggle wrappers would otherwise collapse the gap between their sliders/hints; match .sec-inner's 15px */
.sec-inner .seg button{ padding:8px 6px; }   /* in-panel: tighter horizontal padding (the base .seg already handles full-width + even split + the .vert stack) */
.sec-inner .btn{ width:100%; }
.subcard{
    border:1px solid var(--edge);
    border-radius:11px;
    background:var(--subcard);                       /* sub-card surface role (a cool wash over the --card behind it — one elevation step lighter than the card) */
    padding:13px 13px 15px;
    display:flex;
    flex-direction:column;
    gap:13px;
    --ctl-fill:rgba(13,21,32,0.6);                  /* controls on a sub-card = the card fill shifted by the sub-card's own 3.5% cool wash: lighter than the card fill (no dark hole on the brighter surface) yet still a hair DARKER than the sub-card (a subtle recess, never raised). Same surface-relationship a card control has to the card. */
  }
.subcard-x{
    font-weight:400;                               /* THE reusable delete button: a red-tinted square ×. Un-scoped from .subcard so it works anywhere a
                                                      remove control is needed (sub-card corners, editor/list rows, pop-out rows). In a .subcard's first row
                                                      `margin-left:auto` pins it upper-right; in a grid/flex row it sits in its cell. Pairs with the optional
                                                      .subcard-title — a card may carry either, both, or neither. */
    width:26px;
    height:26px;
    flex:none;
    margin-left:auto;
    border-radius:6px;
    border:1px solid var(--edge);
    background:rgba(255,90,90,0.12);
    color:#ff8a8a;
    cursor:pointer;
    font-size:15px;
    line-height:1;
    --press-glow:#ff5a5a;                          /* press feedback (shared .btn:active rule) — a RED pop for the delete × */
    transition:background .15s,border-color .15s,transform .09s ease,filter .09s ease,box-shadow .12s ease;
  }
.subcard-x:hover{ background:rgba(255,90,90,0.22); border-color:rgba(255,90,90,0.45); }
.subcard .subcard-title{
    font-weight:400;
    font-size:9.5px;
    letter-spacing:.2em;
    text-transform:uppercase;
    color:var(--cool);
    opacity:.9;
  }
.hint{
    font-weight:400;
    font-size:10.5px;
    color:var(--faint);
    line-height:1.5;
  }
.hint.warn-amber{ color:#e0b341; }
.hint.warn-red{ color:#ff6b6b; }
.hint.q-filling{ color:#f5b441; }
.hint.q-full{ color:#34c06a; }

/* ---- statistics listing (label->value rows use .row/.k/.v; these add the grouped per-item chips) ---- */
.statchips{
    font-weight:400;                                         /* a wrapping line of per-type value chips under a group header */
    display:flex;
    flex-wrap:wrap;
    font-size:11px;
    color:var(--ink);
  }
.statchips .chip{
    display:inline-flex;
    align-items:center;
    gap:4px;
    margin:1px 8px 1px 0;
  }
.swatch{                                            /* the small colour-key square (stats chips, legend rows); set its background inline — colour is data */
    display:inline-block;
    width:8px;
    height:8px;
    border-radius:2px;
    flex:none;
  }

/* ---- numeric stepper (upgradeNumber wraps an <input type=number>) ---- */
.numfld{
    position:relative;
    display:inline-flex;
    align-items:stretch;
  }
.numfld input.fld{
    padding-right:26px;                              /* room for the stepper column; everything else = the standard .fld recipe (30px, 12px mono) */
    width:100%;
    -moz-appearance:textfield;
  }
.numfld input.fld::-webkit-outer-spin-button,
.numfld input.fld::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0; }
.numfld .steps{
    position:absolute;
    top:1px; right:1px; bottom:1px;
    width:22px;
    display:flex;
    flex-direction:column;
    border-left:1px solid var(--edge);
  }
.numfld .steps button{
    font-weight:400;
    flex:1;
    appearance:none;
    border:0;
    padding:0;
    background:transparent;
    color:var(--muted);
    cursor:pointer;
    font-size:8px;
    line-height:1;
    transition:color .12s, background .12s;
  }
.numfld .steps button:hover{ color:var(--cool); background:color-mix(in srgb, var(--cool) 10%, transparent); }
.numfld .steps button:first-child{ border-bottom:1px solid var(--edge); border-radius:0 5px 0 0; }
.numfld .steps button:last-child{ border-radius:0 0 5px 0; }

/* ---- kit additions (2026-07): shared utilities ---- */
.glass{                                             /* the pop-over glass surface (compose with a window class) */
  background:var(--panel);
  backdrop-filter:blur(9px);
  -webkit-backdrop-filter:blur(9px);
  border:1px solid var(--edge);
}
.dd-menu::-webkit-scrollbar{ width:9px; }
.dd-menu::-webkit-scrollbar-thumb{ background:color-mix(in srgb, var(--cool) 14%, transparent); border-radius:5px; }
.fld-code{                                          /* code/JSON textarea (Import / Export) */
  width:100%;
  height:150px;
  resize:vertical;
  font:11px ui-monospace,Menlo,monospace;
  padding:8px;
  box-sizing:border-box;
}
.chk-row{
    font-weight:400;                                           /* checkbox + wrapped label line */
  display:flex;
  align-items:flex-start;
  gap:7px;
  font-size:11.5px;
  line-height:15px;
  color:var(--muted,#8b97b4);
  cursor:pointer;
}

/* ============================================================================================
   FULL-WINDOW POP-OUT LAYOUT (STYLE_GUIDE §12) — a self-contained editor that opens in its OWN
   browser tab/window (launched by a main app), NOT an in-app floating window (.disp-pop / .hud).
   Anatomy:
       <header class="pop-header"> brand · divider · page-name · spacer · unsaved </header>
       <div class="pop-main">                          a grid:  [rail] [content]
         <div class="pop-col"><nav class="pop-rail"> …picker items… </nav></div>
         <div class="pop-col"><div class="pop-content"><div class="pop-cards"> …cards… </div></div></div>
       </div>
   The PAGE supplies html/body height + base font (host chrome — see STYLE_GUIDE §2); the classes below
   own the layout. Wire overlayScroll() on .pop-rail and .pop-content (their .pop-col parent hosts the
   floating thumb). Content inside cards uses the SAME kit widgets/rows as everywhere else.
   ============================================================================================ */
/* the slim header — a deliberately lighter variant of the main app header (a pop-out is compact) */
.pop-header{ display:flex; align-items:center; gap:10px; height:var(--pop-header-h); padding:0 12px; border-bottom:1px solid var(--line); background:var(--base); }
.pop-header .brand{ font-size:13px; font-weight:600; letter-spacing:.14em; text-transform:uppercase; color:var(--ink); white-space:nowrap; }   /* == the app header brand (h1) — the ONLY thing that differs from the main header is the bar HEIGHT */
.pop-header .brand b{ font-weight:inherit; color:inherit; }                       /* keep the wordmark MONOCHROME like the main-header brand (no --cool accent word) */
.pop-header .page-name{ font-size:12px; font-weight:500; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); white-space:nowrap; }   /* == the app header's .model-name (muted uppercase) */
.pop-header .divider{ width:1px; height:18px; align-self:center; flex:none; border-radius:1px; background:linear-gradient(180deg,transparent,var(--accent) 22%,var(--accent) 78%,transparent); opacity:.85; }   /* the amber header divider (as the main header's .head-divider), sized for the slim bar */
.pop-header .spacer{ flex:1; }
.pop-header .unsaved{ font-size:10px; font-weight:400; letter-spacing:.18em; text-transform:uppercase; color:var(--accent); white-space:nowrap; }   /* amber = attention (unsaved changes) */
/* the body grid: rail | content, filling the space under the header */
.pop-main{ display:grid; grid-template-columns:var(--pop-rail-w) 1fr; height:calc(100% - var(--pop-header-h)); }
.pop-col{ position:relative; overflow:hidden; min-height:0; }                     /* a positioned, non-scrolling host for overlayScroll's floating thumb */
/* the LEFT PICKER RAIL — a vertical list of objects; click one to load it into the cards */
.pop-rail{ height:100%; overflow-y:auto; border-right:1px solid var(--line); background:var(--card); padding:8px 12px 8px 8px; display:flex; flex-direction:column; gap:4px; }
.rail-item{ display:flex; flex-direction:column; align-items:flex-start; gap:1px; width:100%; padding:7px 10px; border:1px solid transparent; border-radius:8px; background:transparent; color:var(--ink); font:inherit; text-align:left; cursor:pointer; }
.rail-item:hover{ background:color-mix(in srgb, var(--cool) 7%, transparent); }
.rail-item.on{ border-color:var(--cool); background:color-mix(in srgb, var(--cool) 12%, transparent); }   /* the SELECTED object = the kit's active language (--cool), like an active tab — the one open in the editor (--sel green stays a transient "inspect this" marker) */
.rail-label{ font-size:13px; }                                                    /* the object name (primary) */
.rail-sub{ font-size:10.5px; color:var(--muted); }                               /* a secondary id/stats line — add `mono` for data */
/* the RIGHT CONTENT + responsive CARD GRID */
.pop-content{ height:100%; overflow-y:auto; padding:14px 16px 40px; background:var(--base); }
.pop-cards{ display:grid; grid-template-columns:repeat(auto-fit, minmax(280px, 1fr)); gap:12px; max-width:1100px; }   /* cards in a row match the tallest (grid stretch) */
.pop-card{ border:1px solid var(--edge); border-radius:10px; background:var(--card); padding:14px; display:flex; flex-direction:column; gap:15px; align-items:stretch; }   /* a SECTION rendered as a card: --card surface (one step up from --base), accent title, the 15px .sec-inner rhythm */
.pop-card .card-title{ font-size:11px; font-weight:700; letter-spacing:.18em; text-transform:uppercase; color:var(--accent); margin:0; }   /* the kit section-heading voice (== .sec-head), un-collapsable */
.card-stack{ display:flex; flex-direction:column; gap:12px; }                    /* two cards stacked in one grid cell keep the grid's gap */
/* a dense EDITOR ROW — the inline-left label placement (STYLE_GUIDE §1): fixed label + control + an
   optional trailing action (e.g. a .subcard-x remove). `--ed-label-w` tunes the label column. */
.ed-row{ display:grid; grid-template-columns:var(--ed-label-w, 96px) minmax(0, 1fr) auto; align-items:center; gap:8px; }
.ed-row + .ed-row{ margin-top:6px; }
.ed-row>label{ color:var(--faint); font-size:10.5px; font-weight:400; letter-spacing:.16em; text-transform:uppercase; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }   /* EXACTLY the .vis-label voice (10.5px · 400 · .16em · uppercase · faint) so every widget label matches */
