/* ── Soundinator ────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --land-light: 255, 244, 222;   /* the melody landscape's ledges: warm white, an RGB triplet for canvas alpha */
  --walk-light: 214, 226, 255;   /* the melody walker and its odds: a cool white, apart from the land's warm one (DESIGN-1 B) */
  --knob-ring: #0b0d10;          /* the dark ring every draggable knob on a picture wears */
  /* Compose · the instrument face (docs/ui-overhaul-2/compose/FACE.md §7; kit: web/static/face/). Every one is a
     house token or a mix of one. The melody's three lights: the mover (cool), the place (warm), home (violet). */
  --ae-walk: rgb(var(--walk-light));
  --ae-walk-60: rgba(var(--walk-light), 0.6);
  --ae-walk-25: rgba(var(--walk-light), 0.25);
  --ae-walk-10: rgba(var(--walk-light), 0.10);
  --ae-land: rgb(var(--land-light));
  --ae-land-60: rgba(var(--land-light), 0.6);
  --ae-land-25: rgba(var(--land-light), 0.25);
  --ae-land-08: rgba(var(--land-light), 0.08);
  --ae-home: var(--rootc);
  --ae-home-30: color-mix(in srgb, var(--rootc) 30%, transparent);
  --ae-hair: color-mix(in srgb, var(--text) 5.5%, transparent);    /* a pitch row's hairline */
  --ae-hair2: color-mix(in srgb, var(--text) 10%, transparent);    /* a stable row's */
  --ae-well: color-mix(in srgb, var(--display) 88%, black);         /* the face's ground, a shade under the house well */
  --ae-accent-15: color-mix(in srgb, var(--accent) 15%, transparent);
  --face-quiet: color-mix(in srgb, var(--text2) 60%, var(--text3)); /* all secondary text: 5.3:1 on the well, 4.9:1 on the page */
  --face-tick: color-mix(in srgb, var(--text3) 75%, transparent);
  --face-tick-major: color-mix(in srgb, var(--text2) 60%, transparent);
  --face-base: color-mix(in srgb, var(--text3) 55%, transparent);
  --face-deck: color-mix(in srgb, var(--surface) 62%, transparent);
  --face-deck-edge: color-mix(in srgb, var(--border2) 80%, transparent);
  --face-chip: color-mix(in srgb, var(--surface) 86%, transparent);
  --face-sel: var(--accent);                                         /* selected, and nothing else, inside a face */
  --face-sel-60: color-mix(in srgb, var(--accent) 60%, transparent);
  --face-slip: var(--text2);                                         /* the neutral group's colour */
  --face-seg: var(--display);
  --face-surp-glow: color-mix(in srgb, var(--surp) 85%, transparent);
  --face-chord: var(--chordc);                                       /* the chord in force, as Harmony draws it */
  --face-thumb-w: 24px;
  /* Percussion hit colour is keyed by sound family, never by hit number (D-22, D-29): perc-family.js holds the hsl equivalents */
  --hit-drum: color-mix(in srgb, var(--spc), var(--metroc));                  /* kicks, toms, low drums: teal */
  --hit-snare: color-mix(in srgb, var(--chordc), var(--bodyc));               /* snares, claps, rims: orchid */
  --hit-metal: color-mix(in srgb, var(--text2), rgb(var(--walk-light)));      /* hats, cymbals, bells, the rest: silver */
  --face-line: color-mix(in srgb, var(--border2) 75%, transparent);   /* the head's hairline (D-30 names it --line; no house token of that name) */
  --mls-section: rgba(255, 255, 255, 0.022);   /* the quiet ground of one section of a picture */
  /* Compose · Harmony's route (harmony-route.js): tints derived from the chord and root hues and the text grey */
  /* Compose · Rhythm · the feel (feel-ruler.js; D-17): swing is the app's own accent, on its control only.
     Triplets for canvas alpha: --fr-swing-rgb is --accent, --fr-click-rgb is --metroc. */
  --fr-swing-rgb: 245, 166, 35;
  --fr-click-rgb: 143, 191, 216;
  --fr-well: rgba(255, 255, 255, 0.02);   /* the take band's ground */
  --fr-hit: 30px;                          /* a knob's hit area on a fine pointer (44 px on a coarse one, below) */
  /* Compose · Rhythm · where notes fall (fall-dice.js; D-16, D-17): starts and sounds in the landscape's lamp; repeats in
     --acc; silence a neutral (= --text2), hollow, never red (red is a limit or wall, as in How loud). Triplets for canvas alpha. */
  --fd-repeat-rgb: 160, 220, 50;           /* = --acc */
  --fd-rest-rgb: 154, 160, 171;            /* = --text2 */
  --fd-grid: rgba(255, 255, 255, 0.06);    /* a place line */
  --fd-grid-strong: rgba(255, 255, 255, 0.16);   /* a beat line, a fader's rail */
  --fd-well: rgba(255, 255, 255, 0.025);   /* a plot's recess */
  --fd-row-lit: rgba(255, 255, 255, 0.06); /* a take row of the chosen phrase */
  --fd-line: rgba(255, 255, 255, 0.55);    /* a chance's line at rest */
  --fd-hatch: rgba(255, 255, 255, 0.07);   /* the zone under a chance's line */
  --fd-hit: 30px;                          /* a knob's hit square on a fine pointer (44 px on a coarse one, below) */
  /* Compose · Rhythm · how notes join (join-rule.js; D-16): what a join did, named as the Sound fan names it (natural = the
     lamp's cream, slide = --surp, detached = --text2); the rule a neutral white; the old note's tail the fan's faint cream. */
  --jr-rule: rgba(255, 255, 255, 0.78);
  --jr-tail: rgba(var(--land-light), 0.30);
  --jr-tail-edge: rgba(var(--land-light), 0.80);
  /* Compose · Percussion · the phrase wheel (percussion-wheel.js): the wheel's disc, spokes, rim track and ticks; the
     seam at 1 and the playhead in the landscape's lamp; a phrase that runs long in --surp (a triplet for canvas alpha) */
  --pw-well: rgba(255, 255, 255, 0.018);
  --pw-spoke: rgba(255, 255, 255, 0.045);
  --pw-track: rgba(255, 255, 255, 0.16);
  --pw-tick: rgba(255, 255, 255, 0.10);
  --pw-seam: rgba(var(--land-light), 0.55);
  --pw-surp-rgb: 56, 189, 248;             /* = --surp */
  --pw-hit: 30px;                          /* a rail's hit height on a fine pointer (44 px on a coarse one, below) */
  /* Sound · how long it rings (ring-view.js): who owns each stretch of a note. The level arc is the excitor's amber
     (--exc), the ring the resonator's blue (--res), the recording the sampletron's magenta (--smp); the damper a pale
     blue, a measured table a tan, an unread control a grey. The rest are the picture's own greys. */
  --own-env: var(--exc);
  --own-ring: var(--res);
  --own-damp: #7fc4ff;
  --own-fit: #b8a37a;
  --own-fit-dim: rgba(184, 163, 122, 0.28);
  --own-sample: var(--smp);
  --own-none: #6a717d;
  --rk-evidence: #e8eaee;                  /* the rendered note's dots (= --text) */
  --rk-key: #cfd5df;                       /* the key-down span and the key-up line */
  --rk-grid: rgba(255, 255, 255, 0.05);
  --rk-grid2: rgba(255, 255, 255, 0.10);
  --rk-link: rgba(255, 255, 255, 0.07);    /* a row and its grip, lit together */
  --rk-text3: #8a919c;                     /* the picture's tick labels and unread names: --text3 lifted to AA */
  --rk-shadow-pop: 0 1px 0 rgba(0, 0, 0, 0.35);
  --rk-tab-lit: #cfe3ff;                   /* the open Envelope tab, as the column's lit tab (.td-tab.active) */
  --rk-tab-lit-bg: rgba(61, 157, 246, 0.13);
  --rk-tab-lit-edge: #2b5892;
  /* Sound · how a note starts (attack-view.js): three kinds of event at a start, one hue each (colour = meaning): a
     sound beside the tone in the excitor's amber (--exc), a change to the tone itself in the landscape's warm white
     (--land-light), the pitch track in a pale cool grey no other unit uses (gate G). Triplets, for canvas alpha. */
  --atk-beside-rgb: 232, 153, 74;          /* = --exc */
  --atk-shape-rgb: var(--land-light);
  --atk-pitch-rgb: 196, 206, 222;
  --atk-veil: rgba(16, 18, 22, 0.86);      /* --display at 86 %, behind labels drawn over data */
  --atk-grid: rgba(255, 255, 255, 0.055);
  --atk-grid2: rgba(255, 255, 255, 0.11);
  --atk-text3: var(--rk-text3);            /* tick labels: --text3 lifted to AA */
  /* Compose · Rhythm · How loud (dynamics-ladder.js): the rule and its notes in the landscape's lamp; the
     instrument's measured level in the resonator's blue and its tone in the body's violet (triplets for canvas
     alpha: --dl-level-rgb is --res, --dl-tone-rgb is --bodyc); a note on a wall in the meter's clip red. */
  --dl-lamp-rgb: var(--land-light);
  --dl-level-rgb: 61, 157, 246;
  --dl-tone-rgb: 157, 123, 240;
  --dl-level: var(--res);
  --dl-tone: var(--bodyc);
  --dl-cut: var(--meter-hot);
  --dl-surp: var(--surp);
  --dl-grid: rgba(255, 255, 255, 0.06);
  --dl-grid-strong: rgba(255, 255, 255, 0.16);
  --dl-fill: rgba(255, 255, 255, 0.022);    /* a column's well */
  --dl-zone: rgba(255, 255, 255, 0.022);    /* every other dynamic zone, carried across the wells */
  --dl-outside: rgba(0, 0, 0, 0.26);        /* the rule's ground outside the band */
  --dl-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);
  --hm-chord-fill: color-mix(in srgb, var(--chordc) 22%, transparent);   /* a chord's shape on its clock */
  --hm-chord-soft: color-mix(in srgb, var(--chordc) 45%, transparent);   /* the selected clock's outline */
  --hm-cloud: color-mix(in srgb, var(--text2) 55%, transparent);         /* a share of routes that is not the take's */
  --hm-ring: color-mix(in srgb, var(--text2) 30%, transparent);          /* the scale's clock face */
  --hm-grid: color-mix(in srgb, var(--text2) 14%, transparent);          /* a bar's empty track */
  --hm-root-soft: color-mix(in srgb, var(--rootc) 40%, transparent);     /* the lean-in band, a switch that is on */
  --hm-hot: color-mix(in srgb, var(--accent) 9%, transparent);           /* one chord lit wherever it is drawn */
  --hm-held: 0.5;                                                        /* the picture held while a slow take composes */
  /* FabFilter-inspired shell (docs/UI_DIRECTION.md): near-monochrome
     blue-charcoal chrome; vivid hues belong to the DATA layers only. */
  --bg:       #16181d;
  --display:  #101216;   /* visualiser wells — darkest surface */
  --surface:  #1c1f25;
  --surface2: #24272e;
  --border:   #2b2f37;
  --border2:  #363b45;
  --text:     #e8eaee;
  --text2:    #9aa0ab;
  --text3:    #5d636e;
  --accent:   #f5a623;
  --accent2:  #ffc768;
  /* Data-layer hues (match visualiser LAYER_COLORS in app.js) */
  --gen:      #f5a623;
  --acc:      #a0dc32;
  --surp:     #38bdf8;
  --rootc:    #8b7cf6;
  --blue:     #3b82f6;
  --green:    #22c55e;
  --red:      #ef4444;
  /* Chord guide identity (WP H5, docs/PROBABILISTIC_HARMONY_DESIGN.md §13.1).
     A dusky rose, and the chord lane's ONE hue: its spans, placement glyphs,
     active pip, thread flag and ownership chip all read from here, so nothing
     on that surface carries a literal. Chosen to sit clear of --rootc violet
     (the tonic, drawn in the guide DIRECTLY above it, where a near-miss would
     be worst), well clear of --acc green and --surp blue, and lower in
     saturation than the --eff rack rose, which belongs to the sub-note
     effects rack and never appears on the producer page. */
  --chordc:   #d8788c;
  /* Record identity. A hotter, more saturated red than --red, which is the
     DANGER colour (delete, over-unity gain) — recording is not a warning, and
     the two must not read as the same state. --metroc is the metronome's own
     dim cyan, deliberately a quieter relative of the loop toggle's teal: they
     sit side by side in the transport and neither should shout. */
  --recc:     #ff3b47;
  --recc-dim: #7a1f26;
  --metroc:   #8fbfd8;
  /* Stage identity hues (2026-07-08 redesign): each CHORDA stage owns a
     hue used for its card, glow, thumbnail stroke and data in the field. */
  --exc:      #e8994a;   /* excitor — amber-orange   */
  --res:      #3d9df6;   /* resonator — signal blue  */
  --bodyc:    #9d7bf0;   /* body — violet            */
  --eff:      #e5688f;   /* effects — rack rose       */
  --spc:      #4fc47f;   /* space — stage green      */
  /* FE-40: the SAMPLETRON module's identity, one hue for all three of its
     pages. Hue 303. The five above sit at 30 / 211 / 258 / 341 / 146, and when
     a sampletron patch is loaded its module replaces the first three — so the
     only hues on the rail beside it are --eff (341) and --spc (146). 303 is
     38 degrees off the rose and nowhere near the green, which is the widest
     free arc there is. Deliberately not a teal: the SPACE card already renders
     at #58d6a9 and a teal module would have put two greens on one rail. */
  --smp:      #cc63c6;   /* sampletron — tape magenta */
  --smp-tip:  #f3b9ee;   /* its knob pointer, as --accent2 is to --accent */
  /* The "cool" rotary arc. Named here so the knob's focus ring can be drawn
     in the knob's OWN colour without a second literal; the value is the twin
     of `_KNOB_TONES.cool` in app.js, which keeps it as a constant because
     `knobArcs` runs once per drag frame and must not read computed style. */
  --knob-cool: #4f8dd4;
  /* Imported audio (docs/AUDIO_IMPORT_AND_EDITING_DESIGN.md). A cool slate
     blue: the one arc left between the resonator's signal blue and the
     surprise cyan, and deliberately desaturated — an audio take is somebody
     else's recording sitting in our room, and it should not shout. */
  --aud:      #7f93c4;
  --aud-tip:  #b9c7ec;
  --exc-dim:  #e8994a33;
  --res-dim:  #3d9df633;
  --bodyc-dim:#9d7bf033;
  --eff-dim:  #e5688f33;
  --spc-dim:  #4fc47f33;
  --smp-dim:  #cc63c633;
  --aud-dim:  #7f93c433;
  /* Studio surface language (owner 2026-08-27, docs/FRONTEND_DESIGN_STANDARD.md).
     These eight values were the producer's, written as inline hex literals in
     the 2026-07-08 audit pass. That pass is why the producer reads better than
     the other three pages — opaque grounds separate cleanly, one inset
     highlight is the whole elevation system, one hairline weight — but because
     they were literals the treatment could not be pointed anywhere else.
     Named here, they are the shared language of every panelled surface. */
  --shell:          #11141a;                  /* the box the app sits in     */
  --panel:          #151922;                  /* an opaque panel on the shell */
  --well:           rgba(9, 12, 17, 0.42);    /* a recess inside a panel      */
  --hairline:       rgba(82, 91, 108, 0.58);  /* panel edge                   */
  --hairline-soft:  rgba(58, 66, 80, 0.62);   /* edge inside a panel          */
  --control-bg:     #0f131a;                  /* input / select ground        */
  --control-border: rgba(73, 82, 98, 0.72);
  --elev-1:         inset 0 -1px 0 rgba(255,255,255,0.03), 0 1px 0 rgba(0,0,0,0.35);
  --elev-float:     0 10px 28px rgba(0,0,0,0.6), 0 0 0 1px rgba(82, 91, 108, 0.58);   /* a layer over the page */
  --control-h:      26px;                     /* one control height          */
  /* ── Fader (FE-13, owner 2026-08-28; groove re-purposed FE-36 2026-08-29) ─
     There is ONE fader in this app, in two orientations, and it is sized
     entirely from here. The cap is neutral silver so it reads against any
     track/layer hue.

     FE-36, owner: "the horizontal faders should have the response display in
     the fader. I dont need the coloured in slider showing the level." So on
     the HORIZONTAL fader the groove is the METER — it paints the live signal
     and nothing else — and the cap alone carries the set level. The
     identity-hue fill and the --red over-unity leg that used to live in the
     groove are gone from it; over-unity now marks the CAP, which is where
     position lives. The vertical fader's slot is not a meter (its channel has
     its own tall meter canvas beside it), so it keeps the leg. */
  --fader-track:      8px;    /* horizontal groove thickness              */
  --fader-cap-w:      13px;   /* horizontal cap: size ALONG travel        */
  --fader-cap-h:      18px;   /* horizontal cap: size ACROSS the groove   */
  --fader-v-track:    6px;    /* vertical slot thickness                  */
  --fader-v-cap-w:    15px;   /* vertical cap: short axis (along travel)  */
  --fader-v-cap-h:    28px;   /* vertical cap: the wide ridged grip       */
  --fader-min-travel: 96px;   /* under this a fader is a nudge, not a level control */
  --fader-cap:        #e2e7ee;
  --fader-cap-2:      #9aa5b3;
  --fader-cap-3:      #6b7683;
  --fader-ridge:      rgba(22, 26, 32, 0.55);
  --fader-centre:     rgba(255, 255, 255, 0.85);
  --fader-tick:       rgba(232, 234, 238, 0.62);
  --fader-slot:       rgba(4, 6, 10, 0.72);
  --fader-scale:      rgba(154, 160, 171, 0.5);
  /* Meter colours. Promoted out of the `.fader-lvl` rule, where they were raw
     hex literals, because the groove paints them now (FE-36). Three bands:
     green up to −12 dBFS, warm to −3, hot inside the last 3 dB of headroom. */
  --meter-green:      #4fae72;
  --meter-warm:       #d4a24a;
  --meter-hot:        #d45f5f;
  --meter-peak:       rgba(255, 255, 255, 0.92);  /* the ~2 s peak-hold tick */
  --scrollbar-w: 10px;   /* the width the global ::-webkit-scrollbar rule sets */
  /* The amber scroller pair, in circulation since 2026-07 as a repeated
     literal. Named here because FE-38 needs to put it back on one element. */
  --scroll-thumb: rgba(245,166,35,0.42);
  --scroll-track: rgba(10,14,20,0.55);
  --radius:   10px;
  --radius-sm: 6px;
  /* FE-D 2 — ⚑ OWNER DECISION, made 2026-08-28, easy to reverse.
     This stack named 'Inter' first with NO @font-face and no webfont link, so
     the app rendered in Inter on machines that happened to have it installed
     and in the system UI face everywhere else — two different products, and
     nobody chose either. The two honest options were "self-host Inter" or
     "own the system face". Inter is dropped, because self-hosting means
     shipping a font binary this repo does not carry, and because every screen
     in the app was laid out and eyeballed against the system face (the design
     standard §1.4 says to judge spacing that way). If you want Inter, add a
     self-hosted @font-face here and put it back at the head of the stack —
     do not re-add the name on its own. */
  --font:     -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --mono:     'SF Mono', 'Fira Code', Consolas, monospace;
  font-size: 15px;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  line-height: 1.6;
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
}

/* Windows/Linux parity (owner 2026-07-15): macOS draws overlay scrollbars
   (zero width), but Windows Chrome gives every unstyled scroller a classic
   ~16px bar that SUBTRACTS from content width — panels reflowed, clipped, or
   grew stray horizontal bars there. Give every scroller a slim themed bar by
   default; the narrowly-scoped ::-webkit-scrollbar rules elsewhere still win.
   (Deliberately NOT scrollbar-width/scrollbar-color: in current Chrome those
   would override and disable all the existing webkit scrollbar styling — and
   worse, they hand the scroller back to the platform, which on macOS means an
   OVERLAY bar that paints straight over the content. That is FE-38.)
   The width is a token so a scroller that has to reserve its own gutter can
   reserve exactly this much and not a repeated literal. */
::-webkit-scrollbar { width: var(--scrollbar-w); height: var(--scrollbar-w); }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(120,130,150,0.30);
  border-radius: 5px;
  border: 2px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background-color: rgba(120,130,150,0.5); }
::-webkit-scrollbar-corner { background: transparent; }

/* ── Layout ──────────────────────────────────────────────── */

#app {
  max-width: 820px;
  margin: 0 auto;
  padding: 2rem 1.5rem 4rem;
}

/* Persistent authorship credit — a faint watermark pinned to the very bottom
   of the viewport, present on every view. pointer-events:none so it never
   blocks the UI beneath it (owner 2026-07-15). */
.app-credit {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 1px;
  z-index: 2147483000;
  text-align: center;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 9px;
  line-height: 1;
  letter-spacing: 0.05em;
  /* The app is always dark-themed (bg ~#050810) regardless of OS preference,
     so this stays a light, faint watermark. */
  color: rgba(158, 170, 186, 0.34);
  pointer-events: none;
  user-select: none;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
}

.view { animation: fadeIn 0.25s ease-out; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ── Boot mark ───────────────────────────────────────────────
   Authored in index.html so it paints with the stylesheet, before app.js has
   parsed; the first render replaces #app wholesale and takes it with it. It
   says the name and that something is happening — nothing more, because it is
   on screen for about two seconds and must not compete with the studio that
   follows it. */
.boot-splash {
  position: fixed; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px;
  background: var(--shell);
}
.boot-splash-name {
  font-size: clamp(1.4rem, 3.4vw, 2.1rem);
  font-weight: 750;
  letter-spacing: 0.34em;
  text-indent: 0.34em;          /* letter-spacing trails the last glyph */
  color: var(--text);
}
.boot-splash-note {
  font-size: 0.72rem; letter-spacing: 0.08em;
  color: var(--text3);
}
.boot-splash-bar {
  width: clamp(120px, 18vw, 190px); height: 2px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
  position: relative;
}
.boot-splash-bar::after {
  content: ""; position: absolute; inset: 0;
  width: 40%;
  border-radius: inherit;
  background: var(--accent);
  animation: bootSweep 1.15s ease-in-out infinite;
}
@keyframes bootSweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(250%); }
}
@media (prefers-reduced-motion: reduce) {
  /* Hold the bar as a static, partly-filled rule: still reads as "loading",
     with no travelling element. */
  .boot-splash-bar::after { animation: none; width: 100%; opacity: 0.45; }
}

/* ── Typography ──────────────────────────────────────────── */

h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.03em; line-height: 1.2; }
h2 { font-size: 1.25rem; font-weight: 600; letter-spacing: -0.01em; }
h3 { font-size: 1rem; font-weight: 600; }
p  { color: var(--text2); }
.text-sm { font-size: 0.85rem; }
.text-xs { font-size: 0.75rem; }
.text-muted { color: var(--text3); }
.text-accent { color: var(--accent); }
.text-center { text-align: center; }

/* ── Card / Panel ────────────────────────────────────────── */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
}
.card + .card { margin-top: 1rem; }

/* ── Buttons ─────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  padding: 0.6rem 1.4rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-family: inherit; font-size: 0.9rem; font-weight: 600;
  cursor: pointer; transition: all 0.15s;
  text-decoration: none; white-space: nowrap;
}
.btn:disabled { opacity: 0.35; cursor: not-allowed; }
.btn-primary {
  background: var(--accent); color: #000; border-color: var(--accent);
}
.btn-primary:hover:not(:disabled) { background: var(--accent2); border-color: var(--accent2); }
.btn-secondary {
  background: var(--surface2); color: var(--text); border-color: var(--border2);
}
.btn-secondary:hover:not(:disabled) { background: var(--border); border-color: var(--border2); }
.btn-ghost {
  background: transparent; color: var(--text2); border-color: transparent;
}
.btn-ghost:hover:not(:disabled) { color: var(--text); background: var(--surface2); }
.btn-lg { padding: 0.85rem 2rem; font-size: 1rem; border-radius: var(--radius); }
.btn-sm { padding: 0.35rem 0.8rem; font-size: 0.8rem; }
.btn-block { width: 100%; }

/* ── Landing page ────────────────────────────────────────── */

.landing-header { text-align: center; margin-bottom: 2.5rem; padding-top: 3rem; }
.landing-header h1 { margin-bottom: 0.5rem; }
.landing-header p { max-width: 520px; margin: 0 auto; font-size: 1.05rem; }

.landing-cards {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem;
  max-width: 640px; margin: 0 auto;
}
/* Three balanced entry points read as a complete row rather than one lonely
   card floating on the left. */
.landing-cards-3 {
  grid-template-columns: repeat(3, 1fr);
  max-width: 960px;
}
@media (max-width: 860px) { .landing-cards-3 { grid-template-columns: 1fr; max-width: 420px; } }
@media (max-width: 580px) { .landing-cards { grid-template-columns: 1fr; } }

/* The community card is the way in when locked — give it a quiet accent edge. */
.landing-card-featured { border-color: rgba(245,166,35,0.35); }
.landing-card-featured .badge { color: #000; background: var(--accent); border-color: var(--accent); }

.landing-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 2rem 1.5rem;
  text-align: center;
  cursor: pointer;
  transition: all 0.2s;
  text-decoration: none; color: inherit;
}
.landing-card:hover {
  border-color: var(--accent);
  background: var(--surface2);
  transform: translateY(-2px);
  box-shadow: 0 8px 30px rgba(0,0,0,0.3);
}
.landing-card .icon { font-size: 2.2rem; margin-bottom: 0.75rem; display: block; }
.landing-card h2 { margin-bottom: 0.4rem; }
.landing-card p { font-size: 0.88rem; }
.landing-card .badge {
  display: inline-block; margin-top: 0.8rem;
  font-size: 0.75rem; color: var(--accent);
  background: rgba(245,166,35,0.1); border: 1px solid rgba(245,166,35,0.2);
  border-radius: 20px; padding: 0.2rem 0.8rem;
}

/* ── Progress bar (study) ────────────────────────────────── */

.progress-bar {
  display: flex; align-items: center; gap: 0.8rem;
  margin-bottom: 1.5rem; font-size: 0.82rem; color: var(--text2);
}
.progress-track {
  flex: 1; height: 4px; background: var(--border); border-radius: 2px; overflow: hidden;
}
.progress-fill {
  height: 100%; background: var(--accent); border-radius: 2px;
  transition: width 0.3s ease-out;
}
.progress-label { white-space: nowrap; }

/* ── Study views ─────────────────────────────────────────── */

.study-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 1.25rem;
}
.study-header h2 { font-size: 1rem; color: var(--text2); }
.study-instruction {
  font-size: 1.15rem; color: var(--text); line-height: 1.5;
  margin-bottom: 1.5rem;
}

/* Consent / demographics form fields */
.form-group { margin-bottom: 1.25rem; }
.form-group label { display: block; font-weight: 500; margin-bottom: 0.4rem; font-size: 0.9rem; }
.form-group .hint { font-size: 0.78rem; color: var(--text3); margin-top: 0.2rem; }

.form-input,
.form-select {
  width: 100%; padding: 0.55rem 0.75rem;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border2); border-radius: var(--radius-sm);
  font-family: inherit; font-size: 0.9rem;
  transition: border-color 0.15s;
}
.form-input:focus, .form-select:focus {
  outline: none; border-color: var(--accent);
}
.form-select { cursor: pointer; }

.form-check {
  display: flex; align-items: flex-start; gap: 0.6rem; cursor: pointer;
}
.form-check input[type="checkbox"] {
  width: 18px; height: 18px; margin-top: 2px; cursor: pointer;
  accent-color: var(--accent);
}
.form-check span { font-size: 0.88rem; line-height: 1.4; }

.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 500px) { .form-row { grid-template-columns: 1fr; } }

/* ── Slider trial ────────────────────────────────────────── */

.trial-slider-wrap {
  padding: 1.5rem;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 1.25rem;
}
.trial-slider-labels {
  display: flex; justify-content: space-between;
  font-size: 0.78rem; color: var(--text3); margin-top: 0.3rem;
}
.trial-slider-value {
  text-align: center; font-size: 1.6rem; font-weight: 700;
  color: var(--accent); margin-bottom: 0.75rem; font-family: var(--mono);
}

/* ── Pairwise trial ──────────────────────────────────────── */

.pairwise-row {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem;
  align-items: center; margin-bottom: 1.5rem;
}
.pairwise-or { color: var(--text3); font-size: 0.85rem; text-align: center; }
.pairwise-option {
  background: var(--surface2);
  border: 2px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
  text-align: center;
  transition: all 0.15s;
}
.pairwise-option.playing { border-color: var(--accent); }
.pairwise-option .label { font-size: 1.4rem; font-weight: 700; margin-bottom: 0.6rem; }

.pairwise-choices {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;
}

/* ── Range slider (shared between study + explore) ───────── */

/* Thin precision sliders: monochrome widget, data-hued fill (set inline by
   updateSliderFill). The value readout is the star, not the thumb. */
input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 3px;
  background: var(--border); border-radius: 2px;
  outline: none; cursor: pointer;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 13px; height: 13px;
  background: #cfd4dc; border-radius: 50%;
  border: 2px solid var(--bg);
  transition: box-shadow 0.12s, background 0.12s;
}
input[type="range"]::-webkit-slider-thumb:hover {
  background: #eef0f4;
  box-shadow: 0 0 0 4px rgba(207,212,220,0.12);
}
input[type="range"]::-moz-range-thumb {
  width: 12px; height: 12px;
  background: #cfd4dc; border-radius: 50%;
  border: 2px solid var(--bg);
}
input[type="range"]:focus::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px rgba(207,212,220,0.22);
}

/* ── Metered fader (owner 2026-08-21) ─────────────────────────────────────
   A level slider that shows what it is passing, the way a channel fader does
   in other software: the groove behind the thumb IS the meter (green → amber
   past −12 dB → red inside the last 3 dB of headroom), with a thin ~2 s
   peak-hold tick. The thumb still reads the gain, so one control answers both
   "how loud have I set this" and "is it sounding". */
.fader-meter {
  position: relative;
  display: inline-flex; align-items: center;
  flex: 0 1 auto; min-width: 0;
}
/* FE-36 (owner 2026-08-29): "the horizontal faders should have the response
   display in the fader. I dont need the coloured in slider showing the level."
   FE-13 had read two earlier versions of that sentence as "make the FILL
   follow the dB law" and "add a meter strip", which left every horizontal
   fader carrying TWO indicators — a coloured groove showing the set level and
   a separate 4px strip under it showing the signal — with the wrong one inside
   the groove. The strip is gone. The groove itself is the meter now (painted
   by the `.fader--h` track rules below, from the custom properties this
   element carries), and the cap alone reads the level.

   `.fader-lvl` survives as the METER'S HANDLE, not as a mark: `wireFaderMeters`
   keys the per-frame read off it and `data-fader-lvl` names the source. It
   paints nothing. */
.fader-lvl { display: none; }
/* The input is the whole control now; nothing sits behind it. The background
   reset stays because several panels still set an inline groove fill on
   `input[type=range]` generally, and that would fight the meter. */
.fader-meter input[type="range"] { position: relative; background: transparent !important; }

/* ── The fader (FE-13, owner 2026-08-28) ──────────────────────────────────
   "Everywhere there is a volume fader we need to fix it. Vertical faders
   should look like actual faders."  Before this, every pane had invented its
   own: a 7px slab in the mixer, a 13px dot on the layer rows, a bare rotated
   slider for the master, a hand-rolled <div> on the dashboard. This is the
   one component, in two orientations, and nothing else may draw a level.

   Modelled on the two Logic faders the owner attached:
     --h  rounded groove, fill to a rounded silver cap with a soft shadow,
          a --red segment for the travel past unity, a bright tick at max.
     --v  a wide RIDGED cap with a bright centre line riding in a narrow
          slot, with a numbered dB scale beside it (.fader-scale).

   Two JS-set custom properties drive it, both written by updateFaderFill():
     --fader-pct    the cap's position, 0–100 % of travel
     --fader-unity  where gain 1.0 sits in this fader's range
   The selectors carry BOTH classes on purpose: the base range rule above is
   (0,1,1) and `.explore-dashboard input[type="range"]` is (0,2,1) and later
   in this sheet, so anything less specific loses the height to them. */
input[type="range"].fader.fader--h,
input[type="range"].fader.fader--v {
  --fader-pct: 0%;
  --fader-unity: 100%;
  /* The signal, written per frame by _tickFaderMeters onto the .fader-meter
     wrapper and inherited from there. A fader with no meter source never gets
     them and so reads EMPTY — the groove must not invent a level it cannot
     see (FE-36). */
  --meter-pct: 0%;
  --meter-col: var(--meter-green);
  --meter-hold: 0%;
  --meter-peak-col: transparent;   /* the hold tick appears only once held */
  /* Over-unity now marks the CAP, because the cap is the only thing left that
     talks about position. `.over-unity` is toggled by updateFaderFill(). */
  --fader-cap-line: var(--fader-ridge);
  --fader-cap-ring: transparent;
  -webkit-appearance: none; appearance: none;
  margin: 0; padding: 0;
  background: transparent;
  border-radius: 0;
  outline: none;
  cursor: ew-resize;
}
input[type="range"].fader.fader--h:focus-visible,
input[type="range"].fader.fader--v:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
input[type="range"].fader.fader--h:disabled,
input[type="range"].fader.fader--v:disabled { opacity: 0.45; cursor: default; }

/* ─ horizontal ─ */
input[type="range"].fader.fader--h { height: var(--fader-cap-h); }
/* THE GROOVE IS THE METER (FE-36). Reading top layer down:
     1. the max-headroom tick at the right end;
     2. the unity (0 dB) mark — the track's one statement about POSITION, and
        the reference the cap is read against now that there is no coloured
        leg past it;
     3. the ~2 s peak-hold tick, over the fill it rides on;
     4. the live signal, green → warm past −12 dBFS → hot in the last 3 dB;
     5. the empty groove. */
input[type="range"].fader.fader--h::-webkit-slider-runnable-track {
  height: var(--fader-track);
  border-radius: calc(var(--fader-track) / 2);
  background:
    linear-gradient(90deg, transparent calc(100% - 2px), var(--fader-tick) calc(100% - 2px)),
    linear-gradient(90deg, transparent calc(var(--fader-unity) - 0.5px),
                            var(--fader-scale) calc(var(--fader-unity) - 0.5px),
                            var(--fader-scale) calc(var(--fader-unity) + 0.5px),
                            transparent calc(var(--fader-unity) + 0.5px)),
    linear-gradient(90deg, transparent calc(var(--meter-hold) - 0.5px),
                            var(--meter-peak-col) calc(var(--meter-hold) - 0.5px),
                            var(--meter-peak-col) calc(var(--meter-hold) + 0.5px),
                            transparent calc(var(--meter-hold) + 0.5px)),
    linear-gradient(90deg, var(--meter-col) var(--meter-pct), transparent var(--meter-pct)),
    var(--well);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5);
}
input[type="range"].fader.fader--h::-moz-range-track {
  height: var(--fader-track);
  border-radius: calc(var(--fader-track) / 2);
  background:
    linear-gradient(90deg, transparent calc(100% - 2px), var(--fader-tick) calc(100% - 2px)),
    linear-gradient(90deg, transparent calc(var(--fader-unity) - 0.5px),
                            var(--fader-scale) calc(var(--fader-unity) - 0.5px),
                            var(--fader-scale) calc(var(--fader-unity) + 0.5px),
                            transparent calc(var(--fader-unity) + 0.5px)),
    linear-gradient(90deg, transparent calc(var(--meter-hold) - 0.5px),
                            var(--meter-peak-col) calc(var(--meter-hold) - 0.5px),
                            var(--meter-peak-col) calc(var(--meter-hold) + 0.5px),
                            transparent calc(var(--meter-hold) + 0.5px)),
    linear-gradient(90deg, var(--meter-col) var(--meter-pct), transparent var(--meter-pct)),
    var(--well);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5);
}
input[type="range"].fader.fader--h::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: var(--fader-cap-w); height: var(--fader-cap-h);
  border: none;
  border-radius: calc(var(--fader-cap-w) / 2);
  margin-top: calc((var(--fader-track) - var(--fader-cap-h)) / 2);
  background:
    linear-gradient(90deg, transparent calc(50% - 0.5px), var(--fader-cap-line) calc(50% - 0.5px),
                            var(--fader-cap-line) calc(50% + 0.5px), transparent calc(50% + 0.5px)),
    linear-gradient(180deg, var(--fader-cap), var(--fader-cap-2) 64%, var(--fader-cap-3));
  box-shadow: 0 2px 5px rgba(0,0,0,0.55), inset 0 1px 0 rgba(255,255,255,0.4),
              inset 0 0 0 1px rgba(0,0,0,0.35), 0 0 0 1.5px var(--fader-cap-ring);
  transition: filter 0.12s;
}
input[type="range"].fader.fader--h::-moz-range-thumb {
  width: var(--fader-cap-w); height: var(--fader-cap-h);
  border: none;
  border-radius: calc(var(--fader-cap-w) / 2);
  background:
    linear-gradient(90deg, transparent calc(50% - 0.5px), var(--fader-cap-line) calc(50% - 0.5px),
                            var(--fader-cap-line) calc(50% + 0.5px), transparent calc(50% + 0.5px)),
    linear-gradient(180deg, var(--fader-cap), var(--fader-cap-2) 64%, var(--fader-cap-3));
  box-shadow: 0 2px 5px rgba(0,0,0,0.55), 0 0 0 1.5px var(--fader-cap-ring);
}
input[type="range"].fader.fader--h:hover::-webkit-slider-thumb { filter: brightness(1.14); }
/* Past unity the cap wears the fact: its centre line turns --red and it gains
   a thin red rim. This replaces FE-13's coloured leg in the groove, which the
   meter now owns — the unity mark on the track says WHERE the boundary is,
   the cap says which side of it you are on. */
input[type="range"].fader.over-unity {
  --fader-cap-line: var(--red);
  --fader-cap-ring: rgba(212, 95, 95, 0.85);
}

/* ─ vertical ─
   A horizontal slider rotated −90°, which is the only construction that gives
   reliable full-height travel in every engine we ship to. Everything inside
   the thumb is therefore drawn in UNROTATED space: the grip ridges and the
   centre line are vertical lines here and land horizontal on screen. The
   element's `height` becomes the fader's on-screen WIDTH; its `width` (set in
   JS, or fixed in CSS where the slot has a known height) becomes the travel. */
input[type="range"].fader.fader--v {
  height: var(--fader-v-cap-h);
  transform: rotate(-90deg);
  cursor: ns-resize;
}
input[type="range"].fader.fader--v::-webkit-slider-runnable-track {
  height: var(--fader-v-track);
  border-radius: calc(var(--fader-v-track) / 2);
  /* A channel fader's slot stays a slot: the cap read against the scale is
     the value, which is why the Logic reference has no fill in it. The only
     thing painted is the leg PAST unity, because that is a fact worth
     seeing from across the room. */
  background:
    linear-gradient(90deg, transparent var(--fader-unity), var(--red) var(--fader-unity),
                            var(--red) var(--fader-pct), transparent var(--fader-pct)),
    var(--fader-slot);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.65), inset 0 1px 2px rgba(0,0,0,0.5);
}
input[type="range"].fader.fader--v::-moz-range-track {
  height: var(--fader-v-track);
  border-radius: calc(var(--fader-v-track) / 2);
  /* A channel fader's slot stays a slot: the cap read against the scale is
     the value, which is why the Logic reference has no fill in it. The only
     thing painted is the leg PAST unity, because that is a fact worth
     seeing from across the room. */
  background:
    linear-gradient(90deg, transparent var(--fader-unity), var(--red) var(--fader-unity),
                            var(--red) var(--fader-pct), transparent var(--fader-pct)),
    var(--fader-slot);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.65);
}
input[type="range"].fader.fader--v::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: var(--fader-v-cap-w); height: var(--fader-v-cap-h);
  border: none;
  border-radius: 3px;
  margin-top: calc((var(--fader-v-track) - var(--fader-v-cap-h)) / 2);
  background:
    linear-gradient(90deg, transparent calc(50% - 1px), var(--fader-centre) calc(50% - 1px),
                            var(--fader-centre) calc(50% + 1px), transparent calc(50% + 1px)),
    repeating-linear-gradient(90deg, var(--fader-ridge) 0 1px, transparent 1px 4px),
    linear-gradient(90deg, var(--fader-cap-3), var(--fader-cap) 42%, var(--fader-cap-2));
  box-shadow: 0 3px 7px rgba(0,0,0,0.6), inset 0 0 0 1px rgba(0,0,0,0.42),
              0 0 0 1.5px var(--fader-cap-ring);
  transition: filter 0.12s;
}
input[type="range"].fader.fader--v::-moz-range-thumb {
  width: var(--fader-v-cap-w); height: var(--fader-v-cap-h);
  border: none;
  border-radius: 3px;
  background:
    linear-gradient(90deg, transparent calc(50% - 1px), var(--fader-centre) calc(50% - 1px),
                            var(--fader-centre) calc(50% + 1px), transparent calc(50% + 1px)),
    repeating-linear-gradient(90deg, var(--fader-ridge) 0 1px, transparent 1px 4px),
    linear-gradient(90deg, var(--fader-cap-3), var(--fader-cap) 42%, var(--fader-cap-2));
  box-shadow: 0 3px 7px rgba(0,0,0,0.6), 0 0 0 1.5px var(--fader-cap-ring);
}
input[type="range"].fader.fader--v:hover::-webkit-slider-thumb { filter: brightness(1.14); }

@media (prefers-reduced-motion: reduce) {
  input[type="range"].fader.fader--h::-webkit-slider-thumb,
  input[type="range"].fader.fader--v::-webkit-slider-thumb { transition: none; }
}

/* ─ the dB scale beside a vertical fader ─
   Ticks are placed at their TRUE dB positions by the JS that builds the
   column (faderScaleHTML), never evenly spaced in gain: "don't mark dB's
   unless they are accurate". */
.fader-scale {
  position: relative; flex: none;
  width: 26px; align-self: stretch;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.48rem; color: var(--text3);
  user-select: none; pointer-events: none;
}
/* The cap centre cannot reach the last half-cap at either end, so the scale
   is inset by exactly that much — otherwise every tick is a few pixels off
   the value it claims to mark. */
.fader-scale-in {
  position: absolute;
  top: calc(var(--fader-v-cap-w) / 2); bottom: calc(var(--fader-v-cap-w) / 2);
  left: 0; right: 0;
}
.fader-scale i {
  position: absolute; left: 0; width: 5px; height: 1px;
  background: var(--fader-scale);
}
.fader-scale i.unity { width: 8px; background: var(--fader-tick); }
.fader-scale b {
  position: absolute; left: 7px;
  font-weight: 400; line-height: 1; transform: translateY(-50%);
}
.fader-scale b.unity { color: var(--text2); font-weight: 600; }

/* ── Explore mode ────────────────────────────────────────── */

.explore-top {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 1.5rem;
}

.controls-grid { display: grid; gap: 0.9rem; }

.control-row {
  display: grid; grid-template-columns: 140px 1fr 60px;
  align-items: center; gap: 0.6rem;
}
.control-row .label { font-size: 0.85rem; color: var(--text2); }
.control-row output {
  font-family: var(--mono); font-size: 0.82rem;
  color: var(--accent); text-align: right;
  font-variant-numeric: tabular-nums;
}

.control-selects {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0.8rem;
  margin-top: 0.5rem;
}
.control-selects label { font-size: 0.82rem; color: var(--text2); }
.control-selects select {
  width: 100%; margin-top: 0.3rem;
  padding: 0.4rem 0.5rem;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border2); border-radius: var(--radius-sm);
  font-family: inherit; font-size: 0.85rem; cursor: pointer;
}
.control-selects select:focus { outline: none; border-color: var(--accent); }

/* Transport */
.transport {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 1rem 0;
}
.transport .spacer { flex: 1; }

/* Visualiser canvas */
.visualiser-wrap {
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  position: relative;
}
.visualiser-wrap canvas { display: block; width: 100%; height: 200px; }
.visualiser-badge {
  position: absolute; top: 8px; right: 10px;
  font-size: 0.7rem; color: var(--text3);
  background: rgba(0,0,0,0.4); border-radius: 4px; padding: 1px 6px;
}

/* Preset bar */
.preset-bar {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.8rem 0;
}
.preset-bar input[type="text"] {
  flex: 1; padding: 0.45rem 0.6rem;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border2); border-radius: var(--radius-sm);
  font-family: inherit; font-size: 0.85rem;
}
.preset-bar input[type="text"]:focus { outline: none; border-color: var(--accent); }

/* Rating */
.rating-row {
  display: flex; align-items: center; gap: 0.8rem;
  padding: 0.5rem 0;
}
.rating-row .label { font-size: 0.85rem; color: var(--text2); white-space: nowrap; }
.rating-row input[type="range"] { flex: 1; }
.rating-row output {
  font-family: var(--mono); font-size: 0.85rem; color: var(--accent);
  min-width: 2rem; text-align: right;
}

/* ── Library (presets) ───────────────────────────────────── */

.tabs {
  display: flex; gap: 0; margin-bottom: 0.75rem;
  border-bottom: 1px solid var(--border);
}
.tab {
  padding: 0.5rem 1rem;
  background: none; border: none; border-bottom: 2px solid transparent;
  color: var(--text3); font-family: inherit; font-size: 0.85rem; font-weight: 500;
  cursor: pointer; transition: all 0.15s;
}
.tab:hover { color: var(--text2); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }

.preset-list { min-height: 60px; }

.preset-item {
  display: flex; align-items: center; gap: 0.8rem;
  padding: 0.65rem 0.5rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.85rem;
}
.preset-item:last-child { border-bottom: none; }
.preset-item .name { font-weight: 500; flex: 1; }
.preset-item .meta { color: var(--text3); font-size: 0.78rem; }
.preset-item .score {
  font-family: var(--mono); font-size: 0.78rem; color: var(--accent);
  min-width: 28px; text-align: right;
}
.preset-item .actions { display: flex; gap: 0.3rem; }

.empty-state {
  text-align: center; padding: 2rem 1rem;
  color: var(--text3); font-size: 0.88rem;
}

/* ── Contribution prompt ─────────────────────────────────── */

.contribute-prompt {
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  margin-top: 1rem;
}
.contribute-prompt h3 { margin-bottom: 0.5rem; }
.contribute-prompt p { font-size: 0.85rem; margin-bottom: 1rem; }
.contribute-fields { display: grid; gap: 0.75rem; }
.contribute-fields input,
.contribute-fields textarea {
  width: 100%; padding: 0.45rem 0.6rem;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border2); border-radius: var(--radius-sm);
  font-family: inherit; font-size: 0.85rem;
}
.contribute-fields textarea { resize: vertical; min-height: 60px; }

/* ── Headphone check ─────────────────────────────────────── */

.headphone-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.8rem;
  margin: 1.25rem 0;
}
.headphone-btn {
  padding: 1rem;
  background: var(--surface2);
  border: 2px solid var(--border);
  border-radius: var(--radius);
  color: var(--text); font-family: inherit; font-size: 0.95rem; font-weight: 500;
  cursor: pointer; transition: all 0.15s; text-align: center;
}
.headphone-btn:hover { border-color: var(--blue); background: var(--border); }
.headphone-btn.correct { border-color: var(--green); background: rgba(34,197,94,0.08); }
.headphone-btn.wrong { border-color: var(--red); background: rgba(239,68,68,0.08); }

/* ── Study complete ──────────────────────────────────────── */

.complete-hero { text-align: center; padding: 3rem 1rem; }
.complete-hero .icon { font-size: 3rem; margin-bottom: 1rem; }
.complete-hero h1 { margin-bottom: 0.5rem; }

/* ── Info / consent boxes ────────────────────────────────── */

.info-box {
  background: var(--surface2);
  border-left: 3px solid var(--blue);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 1rem 1.25rem;
  margin: 1rem 0;
}
.info-box p { font-size: 0.88rem; color: var(--text2); }

.consent-text {
  max-height: 260px; overflow-y: auto;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1rem; margin-bottom: 1rem;
  font-size: 0.85rem; color: var(--text2); line-height: 1.65;
}
.consent-text h3 { color: var(--text); margin: 0.75rem 0 0.25rem; font-size: 0.9rem; }
.consent-text ul { padding-left: 1.5rem; margin: 0.3rem 0; }

/* ── Utility ─────────────────────────────────────────────── */

.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.5rem; }
.mt-4 { margin-top: 2rem; }
.mb-1 { margin-bottom: 0.5rem; }
.mb-2 { margin-bottom: 1rem; }
.mb-3 { margin-bottom: 1.5rem; }
.flex { display: flex; }
.flex-col { flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.justify-center { justify-content: center; }
.hidden { display: none !important; }

/* ── Note grid ───────────────────────────────────────────── */

.note-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0.75rem 0;
}
.note-cell {
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text3);
  cursor: pointer;
  transition: all 0.12s;
  user-select: none;
}
.note-cell:hover { border-color: var(--text3); background: var(--surface2); }
.note-cell.in-scale {
  border-color: var(--blue);
  color: var(--text);
  background: rgba(59, 130, 246, 0.1);
}
.note-cell.in-sub {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(245, 158, 11, 0.15);
  font-weight: 700;
}

.note-grid-legend {
  display: flex;
  gap: 1rem;
  font-size: 0.72rem;
  color: var(--text3);
  margin-top: 0.4rem;
}
.legend-item { display: flex; align-items: center; gap: 0.3rem; }
.legend-dot {
  width: 10px; height: 10px;
  border-radius: 2px;
  border: 2px solid;
}
.legend-dot.off { border-color: var(--border); }
.legend-dot.scale { border-color: var(--blue); background: rgba(59, 130, 246, 0.1); }
.legend-dot.sub { border-color: var(--accent); background: rgba(245, 158, 11, 0.15); }

/* ── Formant chips ───────────────────────────────────────── */

.formant-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0.5rem 0;
}
.formant-chip {
  padding: 0.3rem 0.85rem;
  border: 1px solid var(--border2);
  border-radius: 20px;
  background: var(--bg);
  color: var(--text3);
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.12s;
}
.formant-chip:hover { border-color: var(--text3); color: var(--text2); }
.formant-chip.active {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(245, 158, 11, 0.1);
}

/* ── Mode toggle buttons ─────────────────────────────────── */

.mode-btns {
  display: flex;
  gap: 4px;
  margin: 0.4rem 0;
}
.mode-btn {
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text3);
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.12s;
}
.mode-btn:hover { border-color: var(--text3); color: var(--text2); }
.mode-btn.active {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(245, 158, 11, 0.1);
}

.mode-btn:disabled,
.formant-chip:disabled,
.param-select:disabled,
.mode-disabled input,
.mode-disabled select,
.mode-disabled button:not(.mode-btn) {
  cursor: not-allowed;
}

/* ── Dimension checkboxes ────────────────────────────────── */

.dimension-checks {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.25rem;
  margin: 0.5rem 0;
}
.dim-check {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: var(--text2);
  cursor: pointer;
}
.dim-check input { accent-color: var(--accent); cursor: pointer; }

.feature-check {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--text2);
  font-size: 0.72rem;
  cursor: pointer;
}

.feature-check input {
  accent-color: var(--accent);
}

.feature-surprise {
  margin-top: 0.34rem;
  padding-top: 0.32rem;
  border-top: 1px solid rgba(136,153,170,0.12);
}

.feature-surprise .control-row {
  margin-top: 0.22rem;
}

.micro-note {
  margin-top: 0.2rem;
  color: var(--text3);
  font-size: 0.58rem;
  line-height: 1.25;
}

.dist-canvas-tall,
.formant-canvas {
  width: 100%;
  display: block;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.formant-weight-circle {
  display: block;
  width: 164px;
  height: 116px;
  margin: 0.4rem auto 0.1rem;
  overflow: visible;
}
.vowel-pad .vp-well {
  fill: var(--display);
  stroke: var(--border);
  stroke-width: 1;
}
.vowel-pad .vp-axis {
  fill: var(--text3);
  font-family: var(--mono);
  font-size: 5.5px;
  letter-spacing: 0.08em;
}
.vowel-pad .fw-poly {
  fill: none !important;
  stroke: rgba(154,160,171,0.25);
  stroke-width: 0.8;
  stroke-dasharray: 2 3;
}
.formant-weight-circle .fw-ring {
  fill: none;
  stroke: rgba(136,153,170,0.14);
  stroke-width: 0.6;
}
.formant-weight-circle .fw-spoke {
  stroke: rgba(136,153,170,0.18);
  stroke-width: 0.6;
}
.formant-weight-circle .fw-poly {
  fill: rgba(245,166,35,0.18);
  stroke: var(--accent);
  stroke-width: 1.2;
  stroke-linejoin: round;
  transition: points 0.08s linear;
}
.formant-weight-circle .fw-dot {
  fill: var(--accent);
}
.formant-weight-circle .fw-dot.inactive {
  fill: var(--text3);
  opacity: 0.4;
}
.formant-weight-circle .fw-label {
  fill: var(--text2);
  font-family: var(--mono);
  font-size: 8px;
  text-anchor: middle;
  dominant-baseline: middle;
}
.formant-weight-circle .fw-label.inactive {
  fill: var(--text3);
  opacity: 0.45;
}

.formant-weight-controls {
  display: grid;
  gap: 0.12rem;
  margin-top: 0.32rem;
}

.formant-weight {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) 34px;
  align-items: center;
  gap: 0.2rem;
  color: var(--text3);
  font-family: var(--mono);
  font-size: 0.58rem;
}

.formant-weight.disabled {
  opacity: 0.38;
}

.formant-weight output {
  color: var(--accent);
  text-align: right;
}

.formant-weight input[type="range"] {
  height: 3px;
}

.formant-axis-controls {
  margin-top: 0.35rem;
  padding-top: 0.35rem;
  border-top: 1px solid rgba(136,153,170,0.12);
}

.formant-focus-row {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0.24rem;
  margin-bottom: 0.32rem;
}

.formant-focus {
  min-width: 0;
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text3);
  font-family: inherit;
  font-size: 0.64rem;
  font-weight: 650;
  padding: 0.18rem 0.24rem;
  cursor: pointer;
}

.formant-focus.active {
  border-color: var(--accent);
  color: var(--accent2);
  background: rgba(245,166,35,0.1);
}

.surprise-weight-list {
  margin-top: 0.5rem;
  padding-top: 0.45rem;
  border-top: 1px solid rgba(136,153,170,0.12);
}

.surprise-weight-head {
  color: var(--text3);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  margin-bottom: 0.3rem;
}

/* ── Percussion layers ──────────────────────────────────── */

.perc-layers { display: grid; gap: 0.75rem; }
.perc-layer {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.75rem;
}
.perc-header {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text2);
  margin-bottom: 0.5rem;
}
.perc-controls { display: grid; gap: 0.6rem; }
.perc-select {
  width: 100%;
  padding: 0.35rem 0.5rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: 0.82rem;
  cursor: pointer;
}
.perc-select:focus { outline: none; border-color: var(--accent); }

/* ── Control descriptions ────────────────────────────────── */

.control-desc {
  font-size: 0.72rem;
  color: var(--text3);
  line-height: 1.4;
  padding: 0 0 0.3rem 0;
}
.controls-grid .control-desc {
  grid-column: 1 / -1;
  margin-top: -0.4rem;
  padding-left: 0;
}

/* ── Distribution displays ──────────────────────────────── */

.dist-display {
  margin-top: 0.75rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.dist-canvas {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg);
  display: block;
}
.dist-label {
  font-size: 0.7rem;
  color: var(--text3);
  white-space: nowrap;
}

/* ── Root note grid ─────────────────────────────────────── */

.root-note-grid .note-grid { margin: 0.5rem 0; }
.root-card .root-note-grid .note-grid { margin: 0.25rem 0; }
.root-card .note-grid-legend { display: none; }
.note-cell.is-root,
.root-cell.is-root {
  border-color: var(--green);
  color: var(--green);
  background: rgba(34, 197, 94, 0.15);
  font-weight: 700;
}
.root-cell.disabled {
  opacity: 0.25;
  cursor: not-allowed;
}
.legend-dot.root {
  border-color: var(--green);
  background: rgba(34, 197, 94, 0.15);
}

/* ── Section label ───────────────────────────────────────── */

.section-label {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text3);
  margin-bottom: 0.6rem;
}

/* ── Engine state display ────────────────────────────────── */

.engine-state {
  display: flex;
  gap: 1.5rem;
  padding: 0.4rem 0.75rem;
  font-size: 0.78rem;
  font-family: var(--mono);
  color: var(--text3);
  margin-bottom: 0.75rem;
}
.engine-state .stat { display: flex; gap: 0.3rem; }
.engine-state .stat-val { color: var(--accent); }

/* ── Scale options ───────────────────────────────────────── */

.scale-preset-row { margin: 0.5rem 0; }
.scale-preset-row label { font-size: 0.85rem; color: var(--text2); }
.scale-preset-row select { margin-left: 0.5rem; }

.edo-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.5rem 0;
}
.edo-input {
  width: 60px;
  padding: 0.35rem 0.5rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  font-family: var(--mono);
  font-size: 0.85rem;
  text-align: center;
}
.edo-input:focus { outline: none; border-color: var(--accent); }
.edo-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* FE-34: the divisions row carries what the deleted 12-tone/N-EDO switch used
   to imply — how wide a step is, and one click back to the standard 12. */
.edo-hint {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: var(--text3);
  white-space: nowrap;
}
.edo-reset {
  margin-left: auto;
  min-height: 22px;
  padding: 0.15rem 0.45rem;
  background: var(--surface2);
  color: var(--text2);
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.7rem;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s;
}
.edo-reset:hover { color: var(--accent2); border-color: var(--accent); }
.edo-reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (prefers-reduced-motion: reduce) { .edo-reset { transition: none; } }

/* ── Explore dashboard: image-mockup-inspired compact view ── */

body.explore-mode {
  overflow: auto;
}

body.explore-mode #app {
  width: 100%;
  max-width: none;
  min-height: 100dvh;
  margin: 0;
  padding: 8px;
}

body.explore-mode .view {
  min-height: calc(100dvh - 16px);
  animation: none;
  /* Q12 QA: a flex child defaults to min-width auto, which let the grid's
     intrinsic width push the page into hidden horizontal overflow at
     ≤1280 px. Let the dashboard shrink to its column floors instead. */
  min-width: 0;
}

.explore-dashboard {
  min-height: calc(100dvh - 16px);
  display: grid;
  /* Q12: first column is user-resizable (drag the divider); floors keep
     every column readable */
  grid-template-columns: var(--dash-c1, 230px) repeat(4, minmax(210px, 1fr));
  grid-template-rows: 62px 210px minmax(360px, auto) minmax(250px, auto) minmax(190px, auto);
  gap: 8px;
  overflow: visible;
  position: relative;
}

/* Q12: panel dividers */
.dash-vsplit {
  position: absolute;
  top: 44px; /* below the transport row */
  bottom: 6px;
  left: calc(var(--dash-c1, 260px) - 2px);
  width: 7px;
  cursor: col-resize;
  z-index: 5;
  border-radius: 3px;
}
.dash-vsplit:hover { background: rgba(245,166,35,0.18); }
/* The dashboard column divider only maps to a real column boundary in the
   classic 5-column dashboard. The Macro / Sub-note / Scale-Lab workspaces are
   absolute overlay cards with their own rail+inspector layout, so here the
   divider resizes a hidden grid column (no visible effect) and its hover
   highlight merely paints a bar across the panels — hide it in those modes.
   (owner 2026-07-10) */
.macro2-workspace-mode .dash-vsplit,
.subnote-workspace-mode .dash-vsplit { display: none; }
.ch-vsplit {
  flex: none;
  width: 7px;
  margin: 0 -3px;
  cursor: col-resize;
  border-radius: 3px;
  z-index: 3;
}
.ch-vsplit:hover { background: rgba(245,166,35,0.18); }
/* Horizontal divider above the LAYERS/BROWSER strip — drag to resize that
   panel's height (owner 2026-07-15; reworked 2026-08-11: the old 8 px bar
   with a 34 px grip hid below the field's hint line and nobody could find
   it). Now a full-width tinted bar with a wide grip, and an oversized
   invisible hit zone so a near-miss still grabs it. */
.ch-hsplit {
  flex: none;
  height: 12px;
  margin: 3px 0 1px;
  cursor: row-resize;
  border-radius: 5px;
  z-index: 3;
  position: relative;
  background: rgba(120, 130, 150, 0.09);
  border: 1px solid var(--border);
  transition: background 120ms ease, border-color 120ms ease;
}
.ch-hsplit::before {
  content: "";
  position: absolute;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 72px; height: 4px; border-radius: 2px;
  background: rgba(120, 130, 150, 0.45);
  transition: background 120ms ease;
}
.ch-hsplit::after {
  /* fat hit zone — grabs a near-miss without stealing real estate */
  content: "";
  position: absolute;
  left: 0; right: 0; top: -5px; bottom: -5px;
}
.ch-hsplit:hover, .ch-hsplit:active {
  background: rgba(245, 166, 35, 0.12);
  border-color: rgba(245, 166, 35, 0.45);
}
.ch-hsplit:hover::before, .ch-hsplit:active::before { background: rgba(245, 166, 35, 0.7); }
/* Content-sized by default; an inline height (set by the divider drag) makes it
   fixed. LAYERS and BROWSER sit side by side so each gets the panel's full
   height instead of cramming half each; they stack again when narrow. */
.chorda-bottom {
  flex: none;
  min-height: 170px;
  height: 300px; /* sensible default — the divider drag's inline height overrides */
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 0.6rem;
  overflow: hidden;
}
.chorda-bottom-left {
  /* scales with the pane instead of holding a fixed 400px: the rows stay
     readable on a narrow window and never starve the browser beside them */
  flex: 0 1 clamp(250px, 32%, 420px);
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  overflow-y: auto;
}
.chorda-bottom-right {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden; /* the library list scrolls inside itself */
}
@media (max-width: 760px) {
  .chorda-bottom { flex-direction: column; overflow-y: auto; }
  .chorda-bottom-left { flex: none; min-width: 0; overflow-y: visible; }
}

.explore-dashboard .card {
  min-height: 0;
  min-width: 0; /* Q12 QA: grid items default min-width auto → page-wide overflow */
  padding: 0.58rem;
  overflow: auto;
  scrollbar-color: rgba(245,166,35,0.42) rgba(10,14,20,0.55);
}

.explore-dashboard .visual-card {
  min-height: 0;
  min-width: 0; /* Q12 QA: the full-row hero card was forcing 1440 px at a 1280 viewport */
  padding: 0.58rem;
  overflow: hidden;
}

.explore-dashboard .card::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.explore-dashboard .card::-webkit-scrollbar-track {
  background: rgba(10,14,20,0.55);
  border-radius: 8px;
}

.explore-dashboard .card::-webkit-scrollbar-thumb {
  background: rgba(245,166,35,0.42);
  border-radius: 8px;
}

.explore-dashboard .card + .card {
  margin-top: 0;
}

.explore-top {
  grid-column: 1 / -1;
  grid-row: 1;
  margin: 0;
  padding: 0 0.2rem;
}

.explore-top #backHome {
  display: none;
}

.explore-top h1 {
  font-size: 1.25rem;
  letter-spacing: -0.02em;
}

.workspace-tabs {
  display: flex;
  /* Q12 QA: one row at full label width — the strip may overflow its grid
     cell into the free space before the transport buttons, which beats
     either overlapping labels (min-width 0) or clipped wrapping (the
     transport row is only 38 px tall) */
  flex-wrap: nowrap;
  width: max-content;
  position: relative;
  z-index: 4;
  gap: 0.25rem;
  margin-top: 0.25rem;
}

.workspace-tab {
  /* Q12 QA: never shrink below the label — squished tabs overlapped their
     neighbours at narrow transport widths */
  min-width: max-content;
  white-space: nowrap;
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text3);
  font-family: inherit;
  font-size: 0.65rem;
  font-weight: 650;
  padding: 0.16rem 0.42rem;
  cursor: pointer;
}

.workspace-tab.active {
  border-color: var(--accent);
  background: rgba(245, 158, 11, 0.1);
  color: var(--accent2);
}

.transport-card {
  grid-column: 2 / 6;
  grid-row: 1;
  display: grid;
  grid-template-columns: minmax(320px, 1fr) minmax(260px, 0.9fr) 175px;
  align-items: center;
  gap: 0.5rem;
  margin-left: 0;
}

.transport-card .transport {
  padding: 0;
}

.transport-card .controls-grid {
  gap: 0;
}

.top-save-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.45rem;
}

.top-save-bar input[type="text"] {
  width: 100%;
  min-height: 0;
  padding: 0.34rem 0.48rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: 0.75rem;
}

.tempo-grid .control-row {
  grid-template-columns: 54px minmax(0, 1fr) 54px;
}

.explore-dashboard .controls-grid {
  gap: 0.32rem;
}

.visual-card {
  grid-column: 2 / 6;
  grid-row: 2;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.scale-card {
  grid-column: 1;
  grid-row: 2 / 4;
}

.melody-card {
  grid-column: 2;
  grid-row: 3;
}

.tuning-card {
  grid-column: 3;
  grid-row: 3;
}

.rhythm-card {
  grid-column: 4;
  grid-row: 3;
}

.dynamics-card {
  grid-column: 5;
  grid-row: 3;
}

.surprise-card {
  grid-column: 2 / 4;
  grid-row: 4;
}

.register-card {
  grid-column: 4;
  grid-row: 4;
}

.motif-card {
  grid-column: 5;
  grid-row: 4;
}

.percussion-card {
  grid-column: 1 / 4;
  grid-row: 5;
}

.rating-card {
  grid-column: 4;
  grid-row: 5;
}

.library-card {
  grid-column: 5;
  grid-row: 5;
}

.subnote-full-card {
  display: none;
}

.subnote-workspace-mode .subnote-full-card {
  /* Space audit 07-07: the sub-note workspace owns the ENTIRE plugin area
     below the transport row — previously it shared the grid with implicit
     rows (the bottom notes) and lost ~180px to them while empty space
     showed elsewhere. Absolute fill; a small bottom margin keeps the
     palette-edit / research-note strip visible — see --ws-bottom, which
     only reserves that strip when one of them is actually on screen. */
  display: block;
  position: absolute;
  top: 44px;
  left: 3px;
  right: 3px;
  bottom: var(--ws-bottom);
  z-index: 2;
  overflow: hidden;
}
/* …and the bottom strips pin to the reserved bottom band instead of
   floating into the vacated grid rows */
/* (Compose too: a palette patch's scale is edited on Compose › Scale & Root, and the strip sat behind the rail there) */
.subnote-workspace-mode .palette-edit-banner,
.macro2-workspace-mode .palette-edit-banner {
  position: absolute;
  left: 3px;
  bottom: 3px;
  z-index: 3;
  margin: 0;
  max-width: 60%;
  padding: 0.3rem 0.6rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.subnote-workspace-mode .research-note {
  position: absolute;
  right: 3px;
  bottom: 8px;
  z-index: 3;
  margin: 0;
}

.subnote-workspace-mode .visual-card,
.subnote-workspace-mode .scale-card,
.subnote-workspace-mode .melody-card,
.subnote-workspace-mode .root-card,
.subnote-workspace-mode .tuning-card,
.subnote-workspace-mode .dynamics-card,
.subnote-workspace-mode .register-card,
.subnote-workspace-mode .rhythm-card,
.subnote-workspace-mode .surprise-card,
.subnote-workspace-mode .motif-card,
.subnote-workspace-mode .percussion-card,
.subnote-workspace-mode .rating-card,
.subnote-workspace-mode .library-card {
  display: none;
}

#contributeArea {
  display: none;
}

#contributeArea:not(:empty) {
  display: block;
  position: fixed;
  right: 8px;
  bottom: 8px;
  z-index: 10;
  width: min(360px, calc(100vw - 16px));
  max-height: min(260px, calc(100dvh - 24px));
  min-height: 0;
  overflow: auto;
  box-shadow: 0 16px 50px rgba(0,0,0,0.42);
}

.subnote-workspace-mode #contributeArea:not(:empty) {
  display: none;
}

.explore-dashboard .section-label {
  margin-bottom: 0.32rem;
  color: var(--accent2);
}

.explore-dashboard .control-row {
  grid-template-columns: minmax(62px, 0.9fr) minmax(58px, 1fr) 36px;
  gap: 0.28rem;
  min-height: 19px;
}

.explore-dashboard .control-row .label,
.explore-dashboard .control-row output {
  font-size: 0.72rem;
}

.explore-dashboard input[type="range"] {
  height: 3px;
}

.explore-dashboard input[type="range"]::-webkit-slider-thumb {
  width: 12px;
  height: 12px;
}

.explore-dashboard .btn {
  min-height: 0;
  padding: 0.3rem 0.58rem;
  font-size: 0.72rem;
}

.explore-dashboard .btn-sm {
  padding: 0.3rem 0.58rem;
}

.visualiser-wrap {
  height: calc(100% - 38px);
}

.visualiser-wrap canvas {
  height: 100%;
}

.engine-state {
  height: 30px;
  align-items: center;
  justify-content: center;
  margin: 6px 0 0;
  padding: 0;
}

.engine-state .stat {
  background: rgba(255,255,255,0.035);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.28rem 0.55rem;
}

.mode-btns {
  margin: 0.3rem 0;
}

.mode-btn,
.formant-chip {
  padding: 0.2rem 0.45rem;
  font-size: 0.68rem;
}

.scale-preset-row,
.edo-row {
  margin: 0.35rem 0;
}

.scale-preset-row label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.scale-preset-row select,
.edo-input,
.perc-select,
.param-select,
.preset-bar input[type="text"],
.contribute-fields input,
.contribute-fields textarea {
  min-height: 0;
  padding: 0.3rem 0.45rem;
  font-size: 0.75rem;
}

.explore-dashboard .scale-preset-row select {
  width: 108px !important;
  margin-left: 0 !important;
}

.note-grid {
  gap: 3px;
  margin: 0.45rem 0;
}

.note-cell {
  width: 25px;
  height: 23px;
  font-size: 0.6rem;
  border-width: 1px;
}

.note-grid-legend {
  gap: 0.42rem;
  font-size: 0.63rem;
  margin-top: 0.25rem;
  flex-wrap: wrap;
}

.legend-dot {
  width: 8px;
  height: 8px;
  border-width: 1px;
}

.formant-chips {
  gap: 4px;
  margin: 0.35rem 0;
}

.dist-display {
  margin-top: 0.36rem;
  gap: 0;
}

.dist-display:has(.accuracy-canvas) {
  display: block;
}

.dist-canvas {
  width: 100%;
  max-width: none;
  height: 30px;
}

.accuracy-canvas {
  height: 220px !important;
  min-height: 190px;
}

.dist-label {
  display: none;
}

.melody-card .controls-grid {
  gap: 0.18rem;
}

.melody-card .control-row {
  min-height: 16px;
}

.melody-card .control-row .label,
.melody-card .control-row output {
  font-size: 0.66rem;
}

.melody-card .dist-display {
  margin-top: 0.2rem;
}

.melody-card #cvInterval {
  height: 22px;
}

.melody-card .accuracy-canvas {
  height: 220px !important;
}

.dimension-checks {
  gap: 0.35rem 0.65rem;
  margin: 0.42rem 0;
}

.dim-check {
  font-size: 0.7rem;
}

.subnote-full-layout {
  height: 100%;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 278px;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 0.55rem;
}

.harmonic-stage,
.formant-stage {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* The tone builder (chain + print) is taller than the old signature
   display — it scrolls within its row instead of spilling over the
   band-scoped editor strip below. */
.harmonic-stage {
  overflow-y: auto;
  overflow-x: hidden;
}
/* Space audit 07-07: the CHORDA stage FILLS its grid cell so the tone
   print + inspector take all remaining height — previously the stage
   sized to content and only looked right because the (since-moved)
   envelope block propped the inspector up. */
.harmonic-stage.chorda {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}
/* the editors never collapse below usable — the stage scrolls instead */
.harmonic-stage.chorda .ch-main { min-height: 200px; }
.harmonic-editor {
  max-height: 170px;
  overflow-y: auto;
}

.formant-stage {
  grid-column: 1;
  grid-row: 1 / 3;
}

.subnote-full-card.is-formant-mode .harmonic-editor {
  display: none;
}

.formant-stage .formant-axis-controls {
  display: grid;
  grid-template-columns: minmax(180px, 0.7fr) minmax(280px, 1fr);
  gap: 0.5rem 0.8rem;
  align-items: end;
  margin: 0 0 0.45rem;
  padding: 0;
  border-top: 0;
}

.formant-stage .formant-focus-row {
  grid-column: 1;
  margin: 0;
}

.formant-stage .feature-check {
  grid-column: 1;
  align-self: center;
}

.formant-stage .controls-grid {
  grid-column: 2;
  grid-row: 1 / 3;
  gap: 0.25rem;
}

.formant-stage .accuracy-canvas {
  flex: 1;
  min-height: 280px;
  height: 100% !important;
}

.subnote-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.8rem;
  margin-bottom: 0.35rem;
}

.subnote-head h2 {
  font-size: 1rem;
  color: var(--text);
  margin-top: -0.2rem;
}

.signature-legend {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.3rem 0.5rem;
  color: var(--text3);
  font-size: 0.66rem;
}

.signature-legend span {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

.legend-line,
.legend-bar,
.legend-band {
  display: inline-block;
  width: 16px;
  height: 3px;
  border-radius: 3px;
}

.legend-line.quiet { background: rgba(148,163,184,0.8); }
.legend-line.loud { background: rgba(34,197,94,0.85); }
.legend-line.mean { background: rgba(245,166,35,0.9); }
.legend-line.sample { background: rgba(34,197,94,0.9); }
.legend-line.acc { background: rgba(255,190,30,0.9); }
.legend-line.surp { background: rgba(56,189,248,0.9); }
.legend-bar.mean { height: 10px; width: 8px; background: rgba(245,166,35,0.72); }
.legend-band.spread { height: 10px; width: 8px; background: rgba(59,130,246,0.28); }
.signature-legend .legend-dot.sample {
  width: 7px;
  height: 7px;
  border: 0;
  border-radius: 50%;
  background: rgba(226,232,240,0.78);
}

#cvHarmonicSignature {
  flex: 1;
  min-height: 0;
  width: 100%;
  height: 100%;
  display: block;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.subnote-side {
  grid-column: 2;
  /* row 1 only: a 1/3 span let this column's content inflate the auto row
     and steal ~150px from the stage — it scrolls internally instead */
  grid-row: 1;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 0.25rem;
  scrollbar-color: rgba(245,166,35,0.42) rgba(10,14,20,0.55);
}

.sound-source-section {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.sound-source-modes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.3rem;
}

.sound-source-modes .mode-btn {
  justify-content: center;
  min-height: 24px;
}

.mode-disabled {
  opacity: 0.32;
  filter: grayscale(0.35) saturate(0.45);
}

.harmonic-stage.mode-disabled,
.harmonic-editor.mode-disabled,
.subnote-side-section.mode-disabled {
  position: relative;
}

.harmonic-stage.mode-disabled::after,
.harmonic-editor.mode-disabled::after,
.subnote-side-section.mode-disabled::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-sm);
  pointer-events: none;
  background: rgba(10,14,20,0.18);
}

.subnote-side::-webkit-scrollbar,
.harmonic-editor::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.subnote-side::-webkit-scrollbar-track,
.harmonic-editor::-webkit-scrollbar-track {
  background: rgba(10,14,20,0.55);
  border-radius: 8px;
}

.subnote-side::-webkit-scrollbar-thumb,
.harmonic-editor::-webkit-scrollbar-thumb {
  background: rgba(245,166,35,0.42);
  border-radius: 8px;
}

.subnote-side .controls-grid {
  gap: 0.18rem;
}

.subnote-side .control-row {
  grid-template-columns: minmax(74px, 0.95fr) minmax(64px, 1fr) 42px;
  gap: 0.26rem;
  min-height: 17px;
}

.subnote-side .control-row .label,
.subnote-side .control-row output {
  font-size: 0.62rem;
}

.subnote-side-section {
  margin-top: 0.42rem;
  padding-top: 0.38rem;
  border-top: 1px solid var(--border);
}

.envelope-dist-controls {
  display: grid;
  gap: 0.12rem;
  margin-top: 0.22rem;
}

.env-dist-head,
.env-dist-row {
  display: grid;
  grid-template-columns: 48px minmax(42px, 1fr) 36px minmax(42px, 1fr) 36px;
  align-items: center;
  gap: 0.18rem;
  min-width: 0;
}

.env-dist-head {
  color: var(--text3);
  font-size: 0.56rem;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.env-dist-row {
  font-family: var(--mono);
  font-size: 0.58rem;
  color: var(--text3);
}

.env-param-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.env-dist-row output {
  color: var(--accent);
  text-align: right;
  white-space: nowrap;
}

.env-dist-row input[type="range"] {
  min-width: 0;
  height: 3px;
}

.env-dist-row input[type="range"]::-webkit-slider-thumb {
  width: 10px;
  height: 10px;
}

.envelope-canvas {
  width: 100%;
  height: 104px;
  display: block;
  margin-top: 0.34rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.vibrato-canvas {
  width: 100%;
  height: 54px;
  display: block;
  margin-top: 0.28rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.harmonic-editor {
  grid-column: 1;
  grid-row: 2;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  grid-auto-rows: minmax(0, 1fr);
  gap: 0.24rem;
  overflow: auto;
  padding-right: 0.18rem;
  scrollbar-color: rgba(245,166,35,0.42) rgba(10,14,20,0.55);
}

.harmonic-control {
  min-width: 0;
  display: grid;
  grid-template-rows: auto repeat(4, minmax(0, 1fr));
  gap: 0.04rem;
  padding: 0.12rem 0.18rem;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text3);
  font-family: var(--mono);
  font-size: 0.55rem;
  line-height: 1.1;
}

.harmonic-control .h-head {
  display: flex;
  justify-content: space-between;
  color: var(--text3);
}

.harmonic-control .h-head span:first-child {
  color: var(--accent2);
  font-weight: 700;
}

.harmonic-control label {
  display: grid;
  grid-template-columns: 15px minmax(0, 1fr) 27px;
  align-items: center;
  gap: 0.12rem;
}

.harmonic-control label span {
  color: var(--text3);
}

.harmonic-control output {
  color: var(--accent);
  text-align: right;
}

.harmonic-control input[type="range"] {
  height: 3px;
}

.harmonic-control input[type="range"]::-webkit-slider-thumb {
  width: 10px;
  height: 10px;
  box-shadow: 0 0 0 1px rgba(245,166,35,0.18);
}

.perc-layers {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.45rem;
}

.percussion-card {
  display: flex;
  flex-direction: column;
}

.performance-tabs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.25rem;
  margin-bottom: 0.35rem;
}

.perf-tab {
  min-width: 0;
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text3);
  font-family: inherit;
  font-size: 0.66rem;
  font-weight: 650;
  padding: 0.2rem 0.35rem;
  cursor: pointer;
}

.perf-tab.active {
  border-color: var(--accent);
  background: rgba(245, 158, 11, 0.1);
  color: var(--accent2);
}

.perf-panel {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.subnote-grid {
  height: 100%;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.45rem;
}

.perf-section {
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

.perf-section .section-label {
  margin-bottom: 0.28rem;
}

.perf-section .control-row {
  grid-template-columns: minmax(40px, 0.8fr) minmax(40px, 1fr) 32px;
  gap: 0.22rem;
  min-height: 18px;
}

.perf-section .control-row .label,
.perf-section .control-row output {
  font-size: 0.62rem;
}

.subnote-grid .controls-grid {
  gap: 0.16rem;
}

.subnote-grid .control-row {
  grid-template-columns: minmax(38px, 0.75fr) minmax(38px, 1fr) 34px;
  min-height: 15px;
}

.subnote-grid .control-row .label,
.subnote-grid .control-row output {
  font-size: 0.58rem;
}

.param-select {
  width: 100%;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  font-family: inherit;
  cursor: pointer;
  margin-bottom: 0.22rem;
}

.mini-canvas {
  display: block;
  width: 100%;
  height: 26px;
  margin-top: 0.22rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.perf-panel[data-panel="breaks"] .controls-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.24rem 0.42rem;
}

.perf-panel[data-panel="breaks"] .mini-canvas {
  height: 58px;
}

.perf-panel[data-panel="space"] .controls-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.24rem 0.42rem;
}

.perf-panel[data-panel="space"] .mini-canvas {
  height: 46px;
}

.percussion-section .perc-layers {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.42rem;
}

.perc-layer {
  padding: 0.5rem;
}

.perc-header {
  font-size: 0.72rem;
  margin-bottom: 0.32rem;
}

.perc-controls {
  gap: 0.38rem;
}

.perc-layer .control-row {
  grid-template-columns: minmax(42px, 0.8fr) minmax(42px, 1fr) 30px;
  gap: 0.22rem;
}

.perc-layer .control-row .label,
.perc-layer .control-row output {
  font-size: 0.64rem;
}

.rating-row {
  gap: 0.45rem;
  padding: 0;
}

.rating-row .label {
  font-size: 0.72rem;
}

.preset-bar {
  padding: 0.45rem 0 0;
}

.tabs {
  margin-bottom: 0.35rem;
}

.tab {
  padding: 0.32rem 0.75rem;
  font-size: 0.76rem;
}

.preset-list {
  min-height: 0;
  max-height: 74px;
  overflow: auto;
}

.preset-item {
  padding: 0.42rem 0.35rem;
  font-size: 0.74rem;
}

.preset-item .meta {
  display: none;
}

.empty-state {
  padding: 0.65rem;
  font-size: 0.76rem;
}

.contribute-prompt {
  height: 100%;
  margin: 0;
  padding: 0.7rem;
}

.contribute-prompt p {
  display: none;
}

.contribute-fields {
  gap: 0.45rem;
}

.contribute-fields textarea {
  min-height: 42px;
}

/* ── Reworked instrument layout ───────────────────────────── */

body.explore-mode {
  overflow: hidden;
}

.explore-dashboard {
  width: 100%;
  max-width: 1440px;
  height: calc(100dvh - 16px);
  min-height: 640px;
  margin: 0 auto;
  grid-template-columns: minmax(205px, 235px) minmax(0, 1fr) minmax(260px, 320px);
  grid-template-rows: 62px 176px minmax(0, 1fr) 172px;
  gap: 8px;
  overflow: hidden;
}

.explore-top {
  grid-column: 1;
  grid-row: 1;
  min-width: 0;
}

.transport-card {
  grid-column: 2 / 4;
  grid-row: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(190px, 0.62fr) minmax(190px, 0.78fr) minmax(170px, 0.66fr) 164px;
  gap: 0.5rem;
  align-items: center;
}

.transport-card .transport {
  min-width: 0;
  gap: 0.45rem;
}

.top-rating-row {
  min-width: 0;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) 38px;
  align-items: center;
  gap: 0.35rem;
}

.top-rating-row .label,
.top-rating-row output {
  color: var(--text3);
  font-size: 0.68rem;
}

.visual-card {
  grid-column: 2 / 4;
  grid-row: 2;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  transition: border-color 160ms ease, box-shadow 160ms ease, background 160ms ease;
}

.visual-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.visual-card-head .section-label {
  margin: 0;
}

.visual-card-head .visualiser-badge {
  position: static;
  white-space: nowrap;
}

.visualiser-wrap {
  flex: 1;
  height: auto;
  min-height: 0;
  border-radius: var(--radius-sm);
}

.visualiser-wrap canvas {
  height: 100%;
}

.visual-card.surprise-flash {
  animation: surprisePulse 560ms ease-out;
}

@keyframes surprisePulse {
  0% {
    border-color: rgba(96,165,250,0.95);
    box-shadow: 0 0 0 1px rgba(96,165,250,0.42), 0 0 32px rgba(96,165,250,0.34);
    background: linear-gradient(180deg, rgba(59,130,246,0.13), rgba(255,255,255,0.03));
  }
  100% {
    border-color: var(--border);
    box-shadow: none;
    background: var(--surface);
  }
}

.scale-card {
  grid-column: 1;
  grid-row: 2 / 4;
  min-width: 0;
}

.root-controls {
  margin-top: 0.65rem;
}

.macro-card {
  grid-column: 2;
  grid-row: 3 / 5;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.macro-card-head,
.production-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.45rem;
}

.macro-tabs {
  min-width: min(360px, 45%);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.25rem;
}

.macro-tab {
  min-width: 0;
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text3);
  font-family: inherit;
  font-size: 0.66rem;
  font-weight: 650;
  padding: 0.24rem 0.28rem;
  cursor: pointer;
}

.macro-tab.active {
  border-color: var(--accent);
  background: rgba(245,166,35,0.1);
  color: var(--accent2);
}

.macro-panel {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(190px, 220px) minmax(0, 1fr);
  gap: 0.65rem;
}
/* Owner 07-07: the preset bar was silently eating the first grid cell in
   the duration/dynamics panels, shunting the controls right and the
   distribution display to the wrong side. It spans the full row. */
.macro-panel > .panel-presets { grid-column: 1 / -1; }

.macro-controls {
  min-width: 0;
  min-height: 0;
  overflow: auto;
  padding-right: 0.2rem;
}

.macro-controls .feature-surprise {
  margin-top: 0.55rem;
  padding-top: 0.45rem;
  border-top: 1px solid var(--border);
}

.macro-monitor {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.macro-monitor .accuracy-canvas {
  width: 100%;
  flex: 1;
  min-height: 260px;
  height: auto !important;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.melody-monitor .accuracy-canvas {
  min-height: 230px;
}

.compact-dist {
  margin-top: 0;
}

.compact-dist .dist-canvas {
  height: 46px;
}

.register-strip {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.2rem;
}

.register-strip #cvRegister {
  width: 100%;
  height: 56px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.duration-monitor .accuracy-canvas {
  flex: 0 0 230px;
}

.breaks-block {
  min-height: 0;
  padding-top: 0.2rem;
  border-top: 1px solid var(--border);
}

.breaks-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.2rem 0.45rem;
}

.breaks-grid .control-row {
  grid-template-columns: minmax(72px, 0.9fr) minmax(58px, 1fr) 42px;
}

.breaks-block .mini-canvas {
  height: 58px;
}

.structure-card {
  grid-column: 3;
  grid-row: 3;
  min-width: 0;
}

.sequence-divider {
  height: 1px;
  background: var(--border);
  margin: 0.65rem 0 0.5rem;
}

.structure-card .surprise-weight-list {
  margin-top: 0.5rem;
}

.production-card {
  grid-column: 3;
  grid-row: 4;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.production-head {
  margin-bottom: 0.35rem;
}

.production-tabs {
  width: 168px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 0;
}

.production-panel {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

.production-panel .perc-layers {
  grid-template-columns: 1fr;
  gap: 0.35rem;
}

.production-panel .perc-layer {
  padding: 0.35rem;
}

.library-card {
  grid-column: 1;
  grid-row: 4;
  min-width: 0;
  min-height: 0;
}

.library-card .preset-list {
  max-height: 106px;
}

.subnote-workspace-mode .visual-card {
  display: none;
}

.subnote-workspace-mode .subnote-full-card {
  display: block;
  grid-column: 1 / -1;
  grid-row: 2 / 5;
  min-width: 0;
  min-height: 0;
}

.subnote-workspace-mode .scale-card,
.subnote-workspace-mode .macro-card,
.subnote-workspace-mode .structure-card,
.subnote-workspace-mode .production-card,
.subnote-workspace-mode .output-card,
.subnote-workspace-mode .library-card {
  display: none;
}

.subnote-full-layout {
  min-width: 0;
  grid-template-columns: minmax(0, 1fr) minmax(230px, 260px);
  grid-template-rows: minmax(0, 1fr) 150px;
  gap: 0.45rem;
}

.subnote-side {
  min-width: 0;
}

.harmonic-editor {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: minmax(68px, 1fr);
  gap: 0.2rem;
}

.harmonic-control {
  padding: 0.1rem 0.14rem;
  font-size: 0.5rem;
}

.harmonic-control label {
  grid-template-columns: 13px minmax(0, 1fr) 25px;
}

#cvHarmonicSignature {
  max-width: 100%;
}

@media (max-width: 1050px) {
  .explore-dashboard {
    grid-template-columns: minmax(190px, 220px) minmax(0, 1fr) minmax(245px, 270px);
  }
  /* Q12: the resizable-column divider only matches the wide layout */
  .dash-vsplit { display: none; }
  .transport-card {
    grid-template-columns: minmax(160px, 0.8fr) minmax(170px, 1fr) minmax(150px, 0.8fr);
  }
  .tempo-grid {
    display: none;
  }
  .macro-panel {
    grid-template-columns: minmax(175px, 200px) minmax(0, 1fr);
  }
  .macro-tabs {
    min-width: 300px;
  }
  .subnote-full-layout {
    grid-template-columns: minmax(0, 1fr) 235px;
  }
}

/* ── Responsive ──────────────────────────────────────────── */

@media (max-width: 600px) {
  #app { padding: 1.25rem 1rem 3rem; }
  h1 { font-size: 1.5rem; }
  .landing-header { padding-top: 1.5rem; }
  .control-row { grid-template-columns: 100px 1fr 50px; }
  .pairwise-row { grid-template-columns: 1fr; }
  .pairwise-or { display: none; }
  .headphone-grid { grid-template-columns: 1fr; }
  .note-cell { width: 32px; height: 32px; font-size: 0.65rem; }
  .engine-state { flex-wrap: wrap; gap: 0.75rem; }
}

/* ── Benchmark plugin skin ───────────────────────────────── */

body.explore-mode {
  margin: 0;
  padding: 0;
  background: #050810;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100vw;
  height: 100dvh;
  overflow: hidden;
}

body.explore-mode #app {
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.explore-dashboard {
  width: 1440px;
  height: 790px;
  min-height: 790px;
  max-height: 790px;
  /* Q12: left column adjustable via the drag divider — the plugin canvas
     stays 1440 (scaled to the viewport), so widening the left column
     narrows the middle one */
  grid-template-columns: var(--dash-c1, 260px) 1fr 320px;
  grid-template-rows: 38px 148px 1fr 155px;
  gap: 3px;
  padding: 3px;
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(19,30,40,0.96), rgba(7,11,16,0.98)),
    radial-gradient(circle at 50% 0%, rgba(59,130,246,0.12), transparent 42%);
  border: 1px solid #1f3444;
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.025), 0 20px 70px rgba(0,0,0,0.48);
}

.explore-dashboard .card,
.visual-card {
  background:
    linear-gradient(180deg, rgba(18,29,38,0.96), rgba(9,15,21,0.98));
  border: 1px solid rgba(49,69,86,0.92);
  border-radius: 8px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.035),
    inset 0 -16px 38px rgba(0,0,0,0.13);
}

.explore-dashboard .section-label {
  color: #b6c0cb;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  margin-bottom: 2px;
}

.section-subhead {
  margin: 0.25rem 0 0.2rem;
  color: #aab5c2;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.explore-top {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 6px;
  padding: 0 6px;
  background: transparent;
  border-right: 1px solid rgba(49,69,86,0.35);
  /* Must stay visible: the account dropdown hangs below this 46px strip.
     Width pressure is handled by letting the title/pill shrink instead. */
  overflow: visible;
  min-width: 0;
}

.explore-top .explore-title { min-width: 0; }
/* The pill never shrinks — the title's version tail truncates first
   (the handle is actionable; the build number is not). */
.explore-top .account-bar { flex-shrink: 0; }
.explore-top .acct-pill.signin {
  display: block; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.explore-top h1 {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #e5e7eb;
  text-shadow: 0 0 18px rgba(226,232,240,0.22);
  white-space: nowrap;
  flex-shrink: 0;
}

.studio-subtitle {
  display: none;
}

/* ── Tone builder: the signal chain is the layout (tone v2 T6) ── */
.tone-chain {
  display: grid;
  grid-template-columns: 1.05fr 16px 1.15fr 16px 1fr 16px 0.7fr;
  align-items: stretch;
  gap: 0;
  margin: 0.5rem 0 0.65rem;
}
.tone-stage {
  border: 1px solid var(--border);
  border-radius: 7px;
  background: rgba(10, 13, 17, 0.5);
  padding: 0.45rem 0.55rem 0.5rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.tone-stage.ts-active { border-color: #6b4c22; }
.ts-head { display: flex; align-items: baseline; gap: 0.45rem; flex-wrap: wrap; }
.ts-n {
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  color: var(--gen, #f5a623);
  white-space: nowrap;
}
.tone-stage.ts-cool .ts-n { color: #4f8dd4; }
.ts-d { font-size: 0.58rem; color: var(--text3); }
.ts-flow { display: flex; align-items: center; justify-content: center; color: #3d4756; font-size: 0.85rem; }
.tone-stage-grid { margin-top: 0; }
.tone-stage .control-row label { min-width: 58px; }
.body-mini {
  width: 100%;
  height: 40px;
  display: block;
  background: var(--display);
  border: 1px solid var(--border);
  border-radius: 5px;
  margin-top: 0.25rem;
}
.ts-space-note { font-size: 0.68rem; color: var(--text2); }
.ts-space-link { font-size: 0.58rem; color: var(--text3); margin-top: auto; line-height: 1.4; }
@media (max-width: 1180px) {
  .tone-chain { grid-template-columns: 1fr 1fr; }
  .ts-flow { display: none; }
}

/* ── CHORDA tone designer (owner-chosen direction 2026-07-07) ── */
.chorda { gap: 0.35rem; }
.ch-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.ch-readout { font-size: 0.68rem; color: var(--text3); font-variant-numeric: tabular-nums; }
.ch-readout b { color: var(--text); font-weight: 600; }

.ch-rail { display: flex; gap: 4px; align-items: stretch; }
.ch-sep { display: flex; align-items: center; color: #3d4756; font-size: 0.8rem; }
.ch-card {
  flex: 1;
  min-width: 0;
  background: rgba(10, 13, 17, 0.5);
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 5px 8px 4px;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.ch-card-head { display: flex; justify-content: space-between; align-items: center; }
.ch-card-n { font-size: 0.6rem; letter-spacing: 0.14em; color: var(--text2); }
.ch-dot { width: 6px; height: 6px; border-radius: 50%; }
.ch-excitor .ch-dot { background: #f5a623; }
.ch-resonator .ch-dot { background: #58a6ff; }
.ch-body .ch-dot { background: #b48ede; }
.ch-space .ch-dot { background: #58d6a9; }
.ch-excitor.active { border-color: #6b4c22; }
.ch-resonator.active { border-color: #2b5892; }
.ch-body.active { border-color: #5b3f80; }
.ch-space.active { border-color: #2b6e57; }
.ch-card.active .ch-card-n { color: var(--text); }
.ch-thumb { width: 100%; height: 34px; display: block; background: var(--display); border-radius: 4px; }
.ch-card-sum { font-size: 0.58rem; color: var(--text3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }

.ch-main { display: flex; gap: 0.5rem; min-height: 0; flex: 1; }
.ch-inspector {
  width: 218px;
  flex: none;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--panel);
  box-shadow: var(--elev-1);
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  overflow-y: auto;
  /* Q12: never clip — the inspector scrolls itself when short on height
     (the BODY inspector used to clip at 271 px) */
  min-height: 0;
  max-height: none;
}
.ch-inspector.ch-excitor { border-color: #4a3517; }
.ch-inspector.ch-resonator { border-color: #223f63; }
.ch-inspector.ch-body { border-color: #3f2d58; }
.ch-inspector.ch-space { border-color: #224d3e; }
.ch-ins-head { display: flex; flex-direction: column; gap: 1px; }
.ch-ins-d { font-size: 0.6rem; color: var(--text3); }
.ch-caption { font-size: 0.62rem; color: var(--text3); line-height: 1.5; margin-top: auto; }
.ch-inspector .body-mini { height: 46px; }
.ch-string {
  width: 100%;
  height: 46px;
  display: block;
  background: var(--display);
  border: 1px solid var(--border);
  border-radius: 5px;
}
.ch-inspector .space-pad { width: 100%; height: 110px; }

.ch-field-wrap { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 4px; overflow-y: auto; }
.ch-field-wrap::-webkit-scrollbar { width: 7px; }
.ch-field-wrap::-webkit-scrollbar-thumb { background: rgba(245,166,35,0.35); border-radius: 4px; }
.ch-field-pos { position: relative; }
.ch-focus-row { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
.ch-focus-label, .ch-lens-label { font-size: 0.58rem; letter-spacing: 0.14em; color: var(--text3); margin-right: 2px; }
.ch-chip {
  background: none;
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text3);
  font: inherit;
  font-size: 0.62rem;
  padding: 2px 8px;
  cursor: pointer;
}
.ch-chip.active { color: #5fd4c8; border-color: #2c5b56; background: rgba(95, 212, 200, 0.07); }
.ch-focus-sum { font-size: 0.62rem; color: var(--text2); font-variant-numeric: tabular-nums; }

#cvTonePrint { flex: none; }
/* The pinned partial's readout: one line along the display's TOP RIGHT,
   inside the band the plot keeps clear for it (PIN_BAND in drawTonePrint).
   Absolute, so showing and hiding it never reflows the section. */
.ch-pin {
  position: absolute; top: 7px; right: 9px; z-index: 4;
  display: inline-flex; align-items: center; gap: 5px;
  max-width: calc(100% - 18px); min-width: 0;
  background: rgba(14, 24, 34, 0.9);
  border: 1px solid #2c5b56;
  border-radius: 6px;
  padding: 2px 6px;
  font-size: 0.62rem;
  line-height: 1.4;
  color: var(--text2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}
.ch-pin[hidden] { display: none; }
.ch-pin b { color: var(--text); font-weight: 600; }
.ch-pin-head {
  color: #5fd4c8; font-weight: 700; letter-spacing: 0.06em;
  background: rgba(95, 212, 200, 0.15); padding: 0 5px; border-radius: 3px;
}
.ch-pin-x {
  background: none; border: none; color: var(--text3);
  cursor: pointer; font-size: 0.8rem; line-height: 1; padding: 0 1px;
}
.ch-pin-x:hover { color: #ffd28a; }
/* The focus summary reads the lens, so it sits under it. */
.ch-focus-sumrow { display: flex; justify-content: flex-end; padding: 2px 2px 0; }

/* The lens shares the print's exact x-range, so its canvas must share the
   print's exact box (owner 2026-08-11): the inline LENS label was pushing
   it 37px right, so brushed bands never lined up with the stems above.
   The label now floats over the strip instead of taking width from it. */
.ch-lens-row { position: relative; display: block; flex: none; }
.ch-lens-label {
  position: absolute; left: 7px; top: 50%; transform: translateY(-50%);
  z-index: 2; pointer-events: none; margin: 0;
}
/* `ew-resize` over the whole strip promised an edge to drag even when there
   was no band. The gesture is a brush, so rest is a crosshair; the script
   swaps in ew-resize / grab over a band's edges and body. */
#cvLens {
  width: 100%; box-sizing: border-box;
  height: 26px; background: var(--display);
  border: 1px solid var(--border); border-radius: 5px;
  cursor: crosshair; display: block;
  transition: border-color 120ms ease, background 120ms ease;
}
#cvLens:hover { border-color: rgba(95, 212, 200, 0.55); }

.ch-strip { display: flex; gap: 6px; overflow-x: auto; min-height: 30px; flex: none; padding-bottom: 2px; }
.harmonic-stage::-webkit-scrollbar { width: 7px; }
.harmonic-stage::-webkit-scrollbar-thumb { background: rgba(245,166,35,0.3); border-radius: 4px; }
.ch-ch {
  flex: 0 0 128px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: rgba(10, 13, 17, 0.55);
  padding: 5px 7px;
  font-size: 0.6rem;
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}
.ch-ch.pinned { border-color: #2c5b56; }
.ch-ch-name { color: var(--text); font-size: 0.66rem; }
.ch-ch-name span { color: var(--text3); font-size: 0.58rem; margin-left: 3px; }
.ch-ch-hz { color: var(--text3); margin-bottom: 3px; }
.ch-ch-row { display: flex; align-items: center; gap: 4px; margin-top: 2px; }
.ch-ch-row input[type="range"] { flex: 1; min-width: 0; height: 10px; }
.ch-ch-row i {
  display: block; height: 3px; background: rgba(88, 166, 255, 0.6); border-radius: 2px; flex: none;
  max-width: 56px;
}
.ch-ch-row span { width: 20px; }
.ch-ch-row output { margin-left: auto; }
.ch-ch-link { margin-top: 3px; color: #5fd4c8; }
.ch-ch-link.muted { color: var(--text3); }

.ch-status {
  display: flex; justify-content: space-between; gap: 1rem;
  font-size: 0.6rem; color: var(--text3); padding-top: 2px;
  border-top: 1px solid var(--border);
}
.ch-status b { color: var(--text2); font-weight: 600; }

/* ── Tone chain rotary knobs + segmented excite (T-Q5 polish) ── */
.knob-row {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  align-items: flex-start;
  justify-content: flex-start;
}
.knob-cell {
  width: 62px;
  text-align: center;
  cursor: ns-resize;
  user-select: none;
  padding: 2px 0 1px;
  border-radius: 6px;
  /* The knob drag is vertical, which is exactly the gesture the browser wants
     for a page pan. Nothing else hands the stroke to Pointer Events: a
     `preventDefault` inside a move handler arrives after the pan has already
     been claimed. Without this line every knob in the app is dead on touch. */
  touch-action: none;
}
.knob-cell:hover { background: rgba(255, 255, 255, 0.03); }
/* Keyboard focus. A knob is a `role="slider"` with a tabindex now, so it has
   to say where the arrow keys will land — and the ring takes the module's own
   colour, because a magenta sampletron panel with an amber focus ring is the
   same disagreement between a control and its value that `knobToneColours`
   exists to prevent. */
.knob-cell:focus-visible {
  outline: 2px solid var(--knob-focus, var(--accent));
  outline-offset: -1px;
  background: rgba(255, 255, 255, 0.05);
}
.knob-cell.cool:focus-visible { --knob-focus: var(--knob-cool); }
.knob-cell.tone-smp:focus-visible { --knob-focus: var(--smp); }
/* Fine mode. On a mouse ⇧ is its own announcement, but a finger has covered
   the knob and moved sideways for a reason it can no longer see, so the
   readout brightens to confirm the stroke is now an eighth-rate one. */
.knob-cell.knob-fine .knob-out {
  color: var(--knob-focus, var(--accent));
  transition: color 90ms linear;
}
@media (prefers-reduced-motion: reduce) {
  .knob-cell.knob-fine .knob-out { transition: none; }
}
.knob-cell.cool.knob-fine { --knob-focus: var(--knob-cool); }
.knob-cell.tone-smp.knob-fine { --knob-focus: var(--smp); }
.knob-svg { width: 44px; height: 44px; display: block; margin: 0 auto; }
.knob-label {
  font-size: 0.56rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text2);
  margin-top: -2px;
  white-space: nowrap;
}
.knob-out {
  display: block;
  font-size: 0.6rem;
  color: var(--text3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Typed values (basics audit #8). A readout that takes a typed value says so
   on hover with the text cursor; while typing, the field sits exactly over
   it, in the readout's own face, and the old value hides underneath. */
output.typed-ok { cursor: text; }
output.typed-ok:hover,
.explore-dashboard .control-row output.typed-ok:hover { color: var(--text); }
output.typing { position: relative; color: transparent !important; }
.typed-entry {
  position: absolute; top: -1px; bottom: -1px; right: -1px;
  min-width: calc(100% + 2px); width: 9ch; box-sizing: border-box;
  padding: 0 4px; margin: 0;
  font: inherit; font-variant-numeric: tabular-nums;   /* the readout's own face: no jump on opening */
  text-align: right; color: var(--text);
  background: var(--display); border: 1px solid var(--accent); border-radius: var(--radius-sm);
  outline: none; z-index: 5;
}
.knob-out .typed-entry { right: auto; left: 50%; transform: translateX(-50%); text-align: center; }
/* Inside the studio the field takes the dashboard's own text-input look;
   only the unreadable state must beat that rule's :focus border. */
output.typing > input.typed-entry[aria-invalid="true"],
output.typing > input.typed-entry[aria-invalid="true"]:focus { border-color: var(--red); }
/* What went wrong, in words, under the field (review 2, S4): a hover-only
   title reached neither a keyboard user nor a screen reader. */
.typed-entry-msg {
  position: fixed; z-index: 9000;
  width: max-content; max-width: 240px; padding: 4px 7px;
  font: 500 11px/1.35 var(--font); letter-spacing: 0; text-align: left; white-space: normal;
  color: var(--text); background: var(--surface2); border: 1px solid var(--red); border-radius: var(--radius-sm);
}
/* A readout is now a tap target: 44 px tall under a finger (standard §1.7),
   grown invisibly around it rather than by moving the layout. */
@media (pointer: coarse) {
  /* A slider row's readout takes taps across its row's full height in
     script (the row's own click, inside the readout's column), so nothing
     covers the track. A knob's readout takes the lower part of its own
     cell, never reaching another cell (re-check N6, N7). */
  .knob-cell { position: relative; }
  .knob-cell > output.typed-ok:not(.typing) { position: static; }
  .knob-cell > output.typed-ok::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 30px; }
}
.seg-control {
  display: flex;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  width: fit-content;
  margin-bottom: 0.2rem;
}
.seg-btn {
  background: none;
  border: none;
  border-right: 1px solid var(--border);
  color: var(--text3);
  font: inherit;
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  padding: 3px 9px;
  cursor: pointer;
}
.seg-btn:last-child { border-right: none; }
.seg-btn.active { color: var(--gen, #f5a623); background: rgba(245, 166, 35, 0.1); }
.ts-body-row { display: flex; gap: 10px; align-items: flex-start; }
.knob-col { display: flex; flex-direction: column; gap: 2px; }
.space-pad {
  flex: 1;
  min-width: 0;
  height: 96px;
  background: var(--display);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: crosshair;
}
.body-select { flex: 1; min-width: 0; }
.editor-hint {
  font-size: 0.66rem;
  color: var(--text3);
  padding: 0.5rem 0.2rem;
  line-height: 1.5;
}

/* ── T7 tone print ── */
#cvTonePrint {
  display: block;
  width: 100%;
  /* 150px of plot + the 36px band kept clear along the top for the pinned
     readout, so the plot area is unchanged and the readout always has room */
  height: 186px;
  background: var(--display);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: crosshair;
}
.ch-field-pos { position: relative; }
.print-bands { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
.print-hint { font-size: 0.58rem; color: var(--text3); margin-right: 6px; }
.print-band {
  background: none;
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text3);
  font: inherit;
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  padding: 2px 8px;
  cursor: pointer;
}
.print-band.active { color: var(--gen, #f5a623); border-color: #6b4c22; background: rgba(245,166,35,0.07); }
.print-readout {
  margin-top: 0.35rem;
  font-size: 0.68rem;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
  min-height: 1.1em;
}

.build-tag {
  font-size: 0.62em;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--text3, #64707e);
  vertical-align: 1px;
  white-space: nowrap;
}

.workspace-tabs {
  margin: 0;
  padding: 2px;
  background: #070c12;
  border: 1px solid rgba(49,69,86,0.86);
  border-radius: 4px;
  box-shadow: inset 0 0 8px rgba(0,0,0,0.5);
  display: flex;
  gap: 0;
  flex-shrink: 1;
  min-width: 0;
}

.workspace-tab {
  min-height: 22px;
  padding: 0 6px;
  border: 0;
  border-radius: 3px;
  background: transparent;
  color: #8c97a5;
  font-size: 0.55rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
}

.workspace-tab.active {
  background: linear-gradient(180deg, rgba(245,166,35,0.20), rgba(245,166,35,0.07));
  box-shadow: inset 0 -2px 0 rgba(245,166,35,0.65), 0 0 18px rgba(245,166,35,0.13);
  color: var(--accent2);
}

.transport-card {
  grid-column: 2 / -1;
  grid-row: 1;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  background: transparent;
  border: 0;
  box-shadow: none;
  overflow: hidden;
}

.transport-card .tempo-grid {
  display: none;
}

.transport-card .transport {
  display: flex;
  align-items: center;
  gap: 6px;
}

.transport-round {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #2b3d4d;
  border-radius: 50%;
  background: linear-gradient(180deg, #192531, #101216);
  color: #d6dde7;
  font-size: 0.58rem;
  font-weight: 800;
  text-transform: uppercase;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05), 0 0 0 2px rgba(0,0,0,0.18);
  cursor: pointer;
  flex-shrink: 0;
}

.transport-play {
  width: 36px;
  height: 36px;
  border-color: rgba(72,187,120,0.82);
  color: #fff;
  box-shadow:
    0 0 0 2px rgba(34,197,94,0.22),
    0 0 12px rgba(245,166,35,0.22),
    inset 0 0 0 1px rgba(245,166,35,0.58);
}

.transport-stop {
  color: #9aa7b5;
}

/* Grouped transport + icon-only secondary actions (owner 2026-07-10): keeps the
   header compact. The play button is the single play/stop toggle. */
.transport-cluster { display: flex; align-items: center; gap: 5px; }
.tc-spacer { flex: 1 1 auto; min-width: 6px; }
.transport-icon {
  color: #aeb9c6;
  font-size: 0.92rem;
  font-weight: 600;
  text-transform: none;
}
.transport-icon:hover { color: #fff; border-color: var(--border2); }
.transport-icon.rand-icon { color: var(--blue); }
.transport-icon.rand-icon:hover { color: #cfe0ff; }
.transport-icon.studio-tour-btn { color: #9aa7b5; flex-shrink: 0; }
.transport-icon.studio-tour-btn:hover { color: var(--accent); }

.rand-btn {
  min-height: 28px;
  padding: 0 8px;
  border-color: #314252;
  border-radius: 4px;
  background: linear-gradient(180deg, #15212c, #101216);
  color: #b8c2cf;
  font-size: 0.6rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.rand-btn::before {
  content: "◇";
  color: var(--blue);
  font-size: 1rem;
}

.seed-box {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  color: #91a0af;
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.seed-box #seedBtn {
  min-height: 24px;
  margin: 0;
  padding: 0 6px;
  border: 1px solid #314252;
  border-radius: 3px;
  background: #101216;
  color: #d7dee8;
  font-family: var(--mono);
  font-size: 0.68rem;
}

.top-save-bar {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: none; /* keep its own space in the crowded transport row (the row scrolls) */
}

.top-save-bar input[type="text"] {
  min-height: 26px;
  flex: none;       /* never squish the name field (owner 2026-07-09) */
  width: 130px;
  padding: 0 6px;
  border-color: #314252;
  border-radius: 3px;
  background: #101216;
  color: #d8e0ea;
  font-size: 0.65rem;
  font-weight: 650;
}

.top-save-bar #saveBtn {
  min-height: 26px;
  padding: 0 8px;
  background: transparent;
  color: var(--accent);
  border-color: #314252;
  border-radius: 3px;
  text-transform: uppercase;
  font-size: 0.6rem;
}

/* Save collapsed into a popover (owner 2026-07-10) — keeps the header compact */
.top-save { position: relative; flex: none; }
.top-save-toggle { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.top-save-toggle .caret { font-size: 0.6rem; opacity: 0.8; }
.save-pop {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 70;
  min-width: 232px;
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px; border-radius: 9px;
  background: rgba(12, 16, 22, 0.98); border: 1px solid var(--border2);
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.55);
}
.save-pop[hidden] { display: none; }
.save-pop-row { display: flex; align-items: center; gap: 8px; }
.save-pop-row > span {
  flex: none; width: 54px; font-size: 0.58rem; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text3);
}
.save-pop-row input[type="text"], .save-pop-row select {
  flex: 1; min-width: 0; min-height: 28px; padding: 0 8px;
  border: 1px solid var(--border); border-radius: 6px;
  background: #101216; color: var(--text); font-size: 0.72rem;
}
.save-pop #saveBtn { min-height: 30px; text-transform: none; }

.top-rating-row {
  display: flex;
  align-items: center;
  gap: 4px;
}

.top-rating-row .label {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.56rem;
  white-space: nowrap;
}

.top-rating-row input[type="range"] {
  width: 50px;
}

.top-rating-row output {
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.62rem;
}

.top-library-actions {
  display: flex;
  align-items: center;
  gap: 4px;
}

.top-action-btn {
  min-height: 24px;
  padding: 0 6px;
  border: 1px solid #314252;
  border-radius: 3px;
  background: linear-gradient(180deg, #16222d, #0a1016);
  color: #aeb8c5;
  font-size: 0.55rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
}

.visual-card {
  grid-column: 1 / -1;
  grid-row: 2;
  display: grid;
  grid-template-columns: 120px minmax(0, 1fr) 260px;
  grid-template-rows: 1fr;
  align-items: stretch;
  gap: 8px;
  padding: 6px 10px;
}

.visual-status {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 5px;
  padding-top: 2px;
  color: #aeb8c5;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.status-dot {
  width: 9px;
  height: 9px;
  display: inline-block;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 12px rgba(34,197,94,0.8);
}

.surprise-status {
  color: var(--accent);
}

.surprise-status::before {
  content: "*";
  display: inline-block;
  margin-right: 7px;
}

/* Frequency-response view-mode switcher */
.vis-mode-switch {
  /* Owner 07-07: these stack vertically */
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  margin-top: 3px;
  width: max-content;
}
.vis-mode-btn {
  flex: 1 1 0;
  min-width: 0;
  min-height: 17px;
  padding: 1px 2px;
  border: 1px solid #2f4050;
  border-radius: 3px;
  background: #101216;
  color: #8f9baa;
  font-size: 0.5rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.vis-mode-btn:hover { color: #c3cedb; border-color: #3d5366; }
.vis-mode-btn.active {
  background: rgba(245,166,35,0.14);
  color: var(--accent2, #f5a623);
  border-color: rgba(245,166,35,0.5);
  box-shadow: inset 0 0 0 1px rgba(245,166,35,0.22);
}

/* Lanes ⇄ Roll reads as ONE segmented switch (exactly one side is always on);
   Spec reads as an independent on/off toggle with an indicator dot — it
   underlays the chosen view rather than replacing it. */
.vis-seg { display: inline-flex; }
.vis-seg .vis-mode-btn { border-radius: 0; }
.vis-seg .vis-mode-btn:first-child { border-radius: 3px 0 0 3px; }
.vis-seg .vis-mode-btn:last-child { border-radius: 0 3px 3px 0; margin-left: -1px; }
.vis-spec-toggle {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  min-height: 17px; padding: 1px 7px 1px 5px;
  border: 1px dashed #2f4050; border-radius: 999px; background: #101216;
  color: #8f9baa; font-size: 0.5rem; font-weight: 700; letter-spacing: 0.02em;
  text-transform: uppercase; cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.vis-spec-dot { width: 6px; height: 6px; border-radius: 50%; background: #2f4050;
  transition: background 0.15s, box-shadow 0.15s; }
.vis-spec-toggle:hover { color: #c3cedb; border-color: #3d5366; }
.vis-spec-toggle.active { color: var(--accent2, #f5a623);
  border-color: rgba(245,166,35,0.5); border-style: solid; }
.vis-spec-toggle.active .vis-spec-dot { background: var(--accent2, #f5a623);
  box-shadow: 0 0 6px rgba(245,166,35,0.7); }
.m2-chips .vis-spec-toggle { margin-left: 4px; }

.visualiser-wrap {
  border: 0;
  border-radius: 0;
  background: #0b1219;
  box-shadow: inset 0 0 0 1px rgba(59,130,246,0.08);
}

.engine-state {
  height: auto;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  margin: 0;
  border-left: 1px solid rgba(49,69,86,0.65);
}

.engine-state .stat {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  border: 0;
  border-right: 1px solid rgba(49,69,86,0.42);
  border-radius: 0;
  background: transparent;
  color: #aeb8c5;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.72rem;
}

.engine-state .stat-val {
  display: block;
  color: var(--blue);
  font-family: var(--mono);
  font-size: clamp(1rem, 2vw, 1.5rem);
  line-height: 1;
  letter-spacing: 0;
  text-shadow: 0 0 18px rgba(59,130,246,0.34);
}

.engine-state .stat:first-child .stat-val {
  color: var(--green);
  text-shadow: 0 0 18px rgba(34,197,94,0.30);
}

.engine-state .stat:last-child .stat-val {
  color: var(--accent);
  text-shadow: 0 0 18px rgba(245,166,35,0.30);
}

.scale-card {
  grid-column: 1;
  grid-row: 3;
  padding: 8px 10px;
  overflow-y: auto;
  overflow-x: hidden;
}

.mode-btns {
  padding: 2px;
  background: #101216;
  border: 1px solid #2f4050;
  border-radius: 4px;
}

.mode-btn {
  min-height: 24px;
  border: 0;
  border-radius: 3px;
  background: transparent;
  color: #8f9baa;
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.mode-btn.active {
  background: rgba(245,166,35,0.13);
  color: var(--accent2);
  box-shadow: inset 0 -2px 0 rgba(245,166,35,0.68);
}

.scale-preset-row select,
.param-select,
.perc-select {
  min-height: 26px;
  border-color: #2f4050;
  background: #101216;
  font-size: 0.65rem;
}

.note-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 5px;
  margin: 6px 0;
}

.note-cell {
  width: 100%;
  height: 32px;
  border-color: #2f4050;
  border-radius: 4px;
  background: linear-gradient(180deg, #151f29, #0a1016);
  font-size: 0.72rem;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}

.note-cell.in-scale {
  background: linear-gradient(180deg, rgba(59,130,246,0.62), rgba(29,78,216,0.38));
  color: #dceaff;
  box-shadow: inset 0 0 0 1px rgba(96,165,250,0.35), 0 0 16px rgba(59,130,246,0.14);
}

.note-cell.in-sub {
  background: linear-gradient(180deg, rgba(245,166,35,0.70), rgba(146,64,14,0.44));
  color: #fff7da;
}

.note-cell.is-root {
  background: linear-gradient(180deg, rgba(34,197,94,0.60), rgba(21,128,61,0.45));
  color: #e6ffe9;
}

.note-grid-legend {
  display: flex;
  justify-content: center;
}

.root-controls {
  margin-top: 0.35rem;
}

.scale-card #cvRoot {
  height: 50px;
  background: #101216;
  border: 1px solid #273747;
}

.macro-card {
  grid-column: 2;
  grid-row: 3;
  padding: 0;
  overflow: hidden;
}

.macro-card-head {
  min-height: 34px;
  margin: 0;
  border-bottom: 1px solid rgba(49,69,86,0.82);
}

.macro-card-head > div:first-child {
  display: flex;
  align-items: center;
  min-width: 180px;
  padding: 0 10px;
}

.macro-tabs {
  flex: 1;
  min-width: 0;
  height: 34px;
  gap: 0;
}

.macro-tab {
  border: 0;
  border-left: 1px solid rgba(49,69,86,0.6);
  border-radius: 0;
  background: rgba(13,20,28,0.6);
  font-size: 0.64rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.macro-tab.active {
  background: linear-gradient(180deg, rgba(245,166,35,0.22), rgba(245,166,35,0.04));
  box-shadow: inset 0 -2px 0 rgba(245,166,35,0.9), 0 0 18px rgba(245,166,35,0.12);
}

.macro-panel {
  grid-template-columns: minmax(180px, 260px) minmax(0, 1fr);
  gap: 0;
  min-height: 0;
  overflow: hidden;
}

.macro-controls {
  padding: 8px 10px;
  border-right: 1px solid rgba(49,69,86,0.78);
  overflow-y: auto;
}

.macro-controls .control-row,
.structure-card .control-row,
.production-card .control-row {
  grid-template-columns: minmax(80px, 1fr) minmax(60px, 0.7fr) 38px;
  min-height: 24px;
  gap: 4px;
}

.macro-controls .control-row .label,
.structure-card .control-row .label,
.production-card .control-row .label {
  color: #aeb8c5;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.macro-controls .control-row output,
.structure-card .control-row output,
.production-card .control-row output {
  min-height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0 4px;
  border: 1px solid rgba(49,69,86,0.72);
  border-radius: 3px;
  background: rgba(6,10,15,0.72);
  color: var(--accent);
  font-family: var(--mono);
  /* Standard §1.4: these are live readouts a drag moves, so the digits must
     not change width under the pointer. The rule had --mono only. */
  font-variant-numeric: tabular-nums;
  font-size: 0.62rem;
}

.macro-monitor {
  padding: 8px 10px;
  overflow-y: auto;
}

.monitor-title {
  color: #aeb8c5;
  font-size: 0.76rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-align: center;
  text-transform: uppercase;
}

.macro-monitor .accuracy-canvas {
  min-height: 0;
  border: 0;
  background: #0b1219;
  box-shadow: inset 0 0 0 1px rgba(59,130,246,0.08);
}

.melody-monitor .accuracy-canvas {
  min-height: 0;
  flex: 1;
}

.compact-dist,
.register-strip {
  display: none;
}

.prob-legend {
  margin-top: 18px;
  padding: 12px;
  border: 1px solid rgba(49,69,86,0.72);
  border-radius: 6px;
  color: #aeb8c5;
  font-size: 0.68rem;
  display: grid;
  gap: 8px;
}

.prob-legend > div {
  display: flex;
  align-items: center;
  gap: 10px;
}

.legend-bracket {
  width: 36px;
  height: 8px;
  display: inline-block;
  border-bottom: 1px solid #aeb8c5;
  border-left: 1px solid #aeb8c5;
  border-right: 1px solid #aeb8c5;
}

.feature-check {
  min-height: 32px;
  color: #aeb8c5;
  font-size: 0.68rem;
  font-weight: 750;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.structure-card {
  grid-column: 3;
  grid-row: 3;
  padding: 8px 10px;
  overflow-y: auto;
  overflow-x: hidden;
}

.structure-card .section-label:nth-of-type(2) {
  margin-top: 12px;
}

.surprise-weight-list {
  padding-top: 12px;
}

.production-card {
  grid-column: 1 / 3;
  grid-row: 4;
  padding: 0;
  overflow: hidden;
  min-height: 0;
}

.production-head {
  min-height: 30px;
  margin: 0;
  padding-left: 10px;
  border-bottom: 1px solid rgba(49,69,86,0.82);
}

.production-head > div:first-child {
  display: flex;
  align-items: center;
}

.production-head .micro-note {
  display: none;
}

.production-tabs {
  width: 180px;
  height: 30px;
  gap: 0;
}

.perf-tab {
  border: 0;
  border-left: 1px solid rgba(49,69,86,0.62);
  border-radius: 0;
  background: rgba(13,20,28,0.72);
  color: #8f9baa;
  font-size: 0.56rem;
  text-transform: uppercase;
}

.perf-tab.active {
  background: linear-gradient(180deg, rgba(245,166,35,0.22), rgba(245,166,35,0.04));
  color: var(--accent2);
  box-shadow: inset 0 -2px 0 rgba(245,166,35,0.9);
}

.production-panel {
  padding: 4px 8px;
  overflow: auto;
}

/* Owner 07-08: Beat / Motif / Downbeat stack vertically — three columns
   squeezed the selects and sliders in the narrow inspector. */
.production-panel .perc-layers {
  grid-template-columns: 1fr;
  gap: 8px;
}

.production-panel .perc-layer {
  padding: 8px;
  border: 1px solid rgba(49,69,86,0.72);
  border-radius: 7px;
  background: rgba(8,14,20,0.55);
}

.perc-header {
  color: #aeb8c5;
  font-size: 0.56rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  margin-bottom: 2px;
}

.production-card .perc-select {
  min-height: 24px;
  font-size: 0.58rem;
}

.production-panel-split {
  display: grid;
  grid-template-columns: 420px 1fr;
  gap: 14px;
  height: 100%;
  align-items: stretch;
}

.production-panel-split .perf-section {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.production-panel-split .space-section {
  border-right: 1px solid rgba(49,69,86,0.55);
  padding-right: 14px;
}

.perf-section-title {
  color: #aeb8c5;
  font-size: 0.56rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 2px;
}

.production-panel-split .space-section .param-select {
  margin-bottom: 2px;
  min-height: 22px;
}

.production-panel-split .space-section .controls-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 16px;
}

.production-panel-split .control-row {
  min-width: 0;
}

.production-panel-split .control-row input[type="range"] {
  min-width: 0;
}

.production-panel-split .space-section .mini-canvas {
  height: 20px;
  margin-top: 3px;
}

.production-panel-split .percussion-section .perc-layers {
  align-content: start;
}

.output-card {
  grid-column: 3;
  grid-row: 4;
  min-width: 0;
  min-height: 0;
  padding: 6px 8px;
  overflow: hidden;
}

.output-layout {
  height: calc(100% - 18px);
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(55px, 1fr) minmax(50px, 0.78fr) minmax(42px, 0.55fr);
  gap: 6px;
  align-items: stretch;
}

.output-card .section-label {
  margin-bottom: 4px;
  font-size: 0.72rem;
}

.meter-stack {
  position: relative;
  min-height: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-left: 24px;
}

.meter-pair {
  height: 100%;
  min-height: 72px;
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.meter-pair span {
  width: 16px;
  height: 88%;
  border-radius: 2px;
  background:
    linear-gradient(180deg, #f5a623 0 12%, #22c55e 12% 72%, #14532d 72% 100%);
  box-shadow: 0 0 12px rgba(34,197,94,0.24);
}

.meter-pair span:last-child {
  height: 96%;
}

.meter-labels {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #6f7b89;
  font-family: var(--mono);
  font-size: 0.62rem;
}

.master-strip,
.limiter-strip {
  min-width: 0;
  display: grid;
  justify-items: center;
  align-content: start;
  gap: 4px;
  border-left: 1px solid rgba(49,69,86,0.55);
}

/* FE-13: the dashboard master was a hand-rolled <div> with a <span> for a
   thumb — no keyboard, no role, no ARIA, and a fifth distinct fader look. It
   is a real `input[type=range].fader--v` now (rotated −90°, so its CSS width
   is the travel) and this is only the slot that reserves its height. */
.master-fader-slot {
  position: relative;
  width: 34px;
  height: 62px;
  display: flex; align-items: center; justify-content: center;
}
.master-fader-slot .fader--v { position: absolute; width: 62px; }

.master-strip output {
  padding: 4px 7px;
  border: 1px solid rgba(49,69,86,0.72);
  border-radius: 5px;
  background: #101216;
  color: #dbe2ea;
  font-family: var(--mono);
}

.limiter-btn {
  min-width: 48px;
  min-height: 30px;
  margin-top: 10px;
  border: 1px solid rgba(49,69,86,0.72);
  border-radius: 6px;
  background: rgba(245,166,35,0.09);
  color: var(--accent2);
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
}

.library-card {
  display: none;
  position: fixed;
  right: 16px;
  top: 104px;
  z-index: 20;
  width: min(420px, calc(100vw - 32px));
  max-height: 380px;
  box-shadow: 0 24px 80px rgba(0,0,0,0.62);
}

.library-card.is-open {
  display: block;
}

.explore-dashboard #contributeArea:not(:empty) {
  display: none;
}

/* ── VST Aesthetic Polish Layer ─────────────────────────── */

/* ─ Surface & depth treatment ─ */
.explore-dashboard {
  background:
    linear-gradient(180deg, rgba(13,20,30,0.97), rgba(8,12,18,0.99)),
    radial-gradient(ellipse at 50% 0%, rgba(245,166,35,0.04), transparent 60%);
  border: 1px solid rgba(30,44,58,0.8);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.02),
    0 0 0 1px rgba(0,0,0,0.5),
    0 24px 80px rgba(0,0,0,0.55);
}

.explore-dashboard .card,
.explore-dashboard .visual-card {
  background: linear-gradient(180deg, rgba(14,22,30,0.96) 0%, rgba(9,14,20,0.98) 100%);
  border: 1px solid rgba(35,50,65,0.75);
  border-radius: 5px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.025),
    0 1px 3px rgba(0,0,0,0.25);
  transition: border-color 0.2s;
}

/* ─ Precision slider tracks (filled via JS inline gradient) ─ */
.explore-dashboard input[type="range"] {
  height: 3px;
  background: rgba(43,47,55,0.95);
  border-radius: 2px;
  transition: box-shadow 0.12s;
}

/* ─ Neutral precision thumbs: chrome stays monochrome; the data-hued
   fill (generation/accuracy/surprise) carries the colour. ─ */
.explore-dashboard input[type="range"]::-webkit-slider-thumb {
  width: 12px;
  height: 12px;
  background: #cfd4dc;
  border: 2px solid var(--bg);
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4);
  cursor: pointer;
  transition: box-shadow 0.12s, background 0.12s;
}

.explore-dashboard input[type="range"]::-webkit-slider-thumb:hover {
  background: #eef0f4;
  box-shadow: 0 0 0 4px rgba(207,212,220,0.12), 0 1px 3px rgba(0,0,0,0.4);
}

.explore-dashboard input[type="range"]::-moz-range-thumb {
  width: 11px;
  height: 11px;
  background: #cfd4dc;
  border: 2px solid var(--bg);
  border-radius: 50%;
}

.explore-dashboard input[type="range"]:active::-webkit-slider-thumb {
  background: #ffffff;
  box-shadow: 0 0 0 5px rgba(207,212,220,0.18), 0 1px 3px rgba(0,0,0,0.4);
}

/* ─ LED-style checkboxes ─ */
.explore-dashboard input[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  min-width: 14px;
  border: 1.5px solid rgba(45,62,78,0.9);
  border-radius: 3px;
  background: #0d0f13;
  cursor: pointer;
  position: relative;
  transition: all 0.15s;
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.4);
}

.explore-dashboard input[type="checkbox"]:hover {
  border-color: rgba(245,166,35,0.35);
}

.explore-dashboard input[type="checkbox"]:checked {
  background: rgba(245,166,35,0.12);
  border-color: rgba(245,166,35,0.65);
  box-shadow:
    0 0 8px rgba(245,166,35,0.35),
    inset 0 0 4px rgba(245,166,35,0.15);
}

.explore-dashboard input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  right: 2px;
  bottom: 2px;
  background: radial-gradient(circle, #ffc768, #f5a623);
  border-radius: 1.5px;
  box-shadow: 0 0 4px rgba(245,166,35,0.6);
}

/* ─ Select dropdowns ─ */
.explore-dashboard select {
  -webkit-appearance: none;
  appearance: none;
  background-color: #0d0f13;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23667788'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  padding-right: 28px;
  border: 1px solid rgba(40,55,70,0.85);
  border-radius: 4px;
  color: #c8d2dc;
  font-family: inherit;
  font-size: 0.72rem;
  transition: border-color 0.15s;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.3);
}

.explore-dashboard select:hover {
  border-color: rgba(245,166,35,0.3);
}

.explore-dashboard select:focus {
  outline: none;
  border-color: rgba(245,166,35,0.55);
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.3), 0 0 6px rgba(245,166,35,0.15);
}

/* ─ Text inputs ─ */
.explore-dashboard input[type="text"],
.explore-dashboard input[type="number"] {
  background: #0d0f13;
  border: 1px solid rgba(40,55,70,0.85);
  color: #d6dde7;
  border-radius: 4px;
  transition: border-color 0.15s;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.3);
}

.explore-dashboard input[type="text"]:focus,
.explore-dashboard input[type="number"]:focus {
  outline: none;
  border-color: rgba(245,166,35,0.55);
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.3), 0 0 6px rgba(245,166,35,0.15);
}

/* ─ Section labels ─ */
.explore-dashboard .section-label {
  color: #94a3b5;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
  margin-bottom: 2px;
}

/* ─ Control row labels & outputs ─ */
.explore-dashboard .control-row .label {
  color: #8b99a8;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.explore-dashboard .control-row output {
  min-height: 18px;
  padding: 0 4px;
  border: 1px solid rgba(35,50,65,0.8);
  border-radius: 3px;
  background: rgba(5,8,12,0.85);
  color: #f5a623;
  font-family: var(--mono);
  font-size: 0.58rem;
  font-weight: 600;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.35);
  text-shadow: 0 0 8px rgba(245,166,35,0.3);
}

/* ─ Transport polish ─ */
.transport-play {
  width: 36px;
  height: 36px;
  background: linear-gradient(180deg, #1a3024 0%, #0b1a14 100%);
  border-color: rgba(34,197,94,0.7);
  color: #fff;
  font-weight: 800;
  box-shadow:
    0 0 0 2px rgba(34,197,94,0.18),
    0 0 12px rgba(34,197,94,0.2),
    inset 0 0 0 1px rgba(34,197,94,0.2),
    inset 0 1px 0 rgba(255,255,255,0.06);
  text-shadow: 0 0 8px rgba(34,197,94,0.5);
  transition: all 0.2s;
}

.transport-play:hover {
  box-shadow:
    0 0 0 3px rgba(34,197,94,0.25),
    0 0 28px rgba(34,197,94,0.35),
    0 0 50px rgba(34,197,94,0.12),
    inset 0 0 0 2px rgba(34,197,94,0.3),
    inset 0 1px 0 rgba(255,255,255,0.08);
  border-color: rgba(34,197,94,0.9);
}

.transport-round {
  transition: all 0.15s;
  font-weight: 800;
  letter-spacing: 0.05em;
}

.transport-round:hover {
  border-color: rgba(148,163,181,0.5);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 0 12px rgba(148,163,181,0.1);
}

.transport-stop:hover {
  color: #d6dde7;
}

/* ─ Randomise button ─ */
.rand-btn {
  font-weight: 700;
  font-size: 0.58rem;
  transition: all 0.15s;
  min-height: 28px;
  padding: 0 8px;
}

.rand-btn:hover {
  border-color: rgba(59,130,246,0.4);
  box-shadow: 0 0 10px rgba(59,130,246,0.12);
  color: #d6dde7;
}

/* ─ Title area ─ */
.explore-top h1 {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  background: linear-gradient(180deg, #f0f2f5, #b8c4d0);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  text-shadow: none;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.3));
  white-space: nowrap;
  flex-shrink: 0;
  /* When the column is tight the version tail truncates; the brand never
     scrolls off-screen (the old overflow:hidden header could be shoved
     left by click-focus on the account pill). */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ─ Workspace tabs ─ */
.workspace-tabs {
  background: rgba(5,8,12,0.85);
  border: 1px solid rgba(35,50,65,0.7);
  border-radius: 4px;
  box-shadow: inset 0 1px 4px rgba(0,0,0,0.5);
  padding: 2px;
}

.workspace-tab {
  font-size: 0.52rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  min-height: 22px;
  height: 22px;
  padding: 0 6px;
  transition: all 0.15s;
  border-radius: 3px;
  white-space: nowrap;
  /* buttons and the Producer LINK share identical metrics — the link used
     to float above its siblings (owner: "ugly and misaligned") */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  text-decoration: none;
  vertical-align: middle;
}
.workspace-tabs { align-items: center; }

.workspace-tab:hover:not(.active) {
  color: #b8c4d0;
  background: rgba(255,255,255,0.03);
}

.workspace-tab.active {
  background: linear-gradient(180deg, rgba(245,166,35,0.18), rgba(245,166,35,0.06));
  box-shadow: inset 0 -2px 0 rgba(245,166,35,0.7), 0 0 12px rgba(245,166,35,0.1);
  color: #ffc768;
  text-shadow: 0 0 10px rgba(245,166,35,0.3);
}

/* ─ Frequency response area ─ */
.visual-card {
  background: linear-gradient(180deg, rgba(12,18,26,0.97), rgba(8,12,18,0.99));
}

.visualiser-wrap {
  background: #0d0f13;
  border: 1px solid rgba(25,38,52,0.6);
  border-radius: 3px;
  box-shadow: inset 0 1px 4px rgba(0,0,0,0.4);
}

.visual-status {
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.status-dot {
  width: 8px;
  height: 8px;
  box-shadow: 0 0 8px rgba(34,197,94,0.7), 0 0 3px rgba(34,197,94,0.5);
}

.surprise-status {
  color: #e8a308;
  text-shadow: 0 0 8px rgba(245,166,35,0.2);
}

/* ─ Engine state counters ─ */
.engine-state .stat {
  font-size: 0.52rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: #7a8a9a;
}

.engine-state .stat-val {
  font-weight: 700;
  font-size: clamp(0.9rem, 1.6vw, 1.3rem);
}

/* ─ Scale card ─ */
.mode-btns {
  display: flex;
  gap: 3px;
  background: rgba(5,8,12,0.85);
  border: 1px solid rgba(35,50,65,0.7);
  border-radius: 3px;
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.4);
  padding: 2px;
}

.mode-btn {
  flex: 1 1 0;
  text-align: center;
  font-weight: 700;
  transition: all 0.15s;
}

.mode-btn:hover:not(.active) {
  color: #b8c4d0;
  background: rgba(255,255,255,0.03);
}

.mode-btn.active {
  background: rgba(245,166,35,0.12);
  color: #ffc768;
  box-shadow: inset 0 -2px 0 rgba(245,166,35,0.7);
  text-shadow: 0 0 8px rgba(245,166,35,0.2);
}

/* ─ Note grid ─ */
.note-cell {
  height: 30px;
  border: 1px solid rgba(35,50,65,0.7);
  border-radius: 3px;
  background: linear-gradient(180deg, rgba(15,22,30,0.95), rgba(8,12,18,0.98));
  font-size: 0.66rem;
  font-weight: 700;
  color: #556677;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.03);
  transition: all 0.12s;
}

.note-cell:hover {
  border-color: rgba(100,120,140,0.5);
}

.note-cell.in-scale {
  background: linear-gradient(180deg, rgba(59,130,246,0.55), rgba(29,78,216,0.35));
  border-color: rgba(59,130,246,0.45);
  color: #d4e4ff;
  box-shadow:
    inset 0 1px 0 rgba(96,165,250,0.2),
    0 0 10px rgba(59,130,246,0.12);
  text-shadow: 0 0 6px rgba(59,130,246,0.3);
}

.note-cell.in-sub {
  background: linear-gradient(180deg, rgba(245,166,35,0.65), rgba(180,83,9,0.40));
  border-color: rgba(245,166,35,0.5);
  color: #fff5d4;
  box-shadow:
    inset 0 1px 0 rgba(251,191,36,0.2),
    0 0 10px rgba(245,166,35,0.12);
  text-shadow: 0 0 6px rgba(245,166,35,0.3);
}

.note-cell.is-root {
  background: linear-gradient(180deg, rgba(34,197,94,0.55), rgba(21,128,61,0.40));
  border-color: rgba(34,197,94,0.5);
  color: #d4ffd8;
  box-shadow:
    inset 0 1px 0 rgba(34,197,94,0.2),
    0 0 10px rgba(34,197,94,0.12);
  text-shadow: 0 0 6px rgba(34,197,94,0.3);
}

/* ─ Macro tabs ─ */
.macro-tab {
  color: #6b7a8a;
  font-weight: 700;
  transition: all 0.15s;
}

.macro-tab:hover:not(.active) {
  color: #94a3b5;
  background: rgba(255,255,255,0.02);
}

.macro-tab.active {
  color: #ffc768;
  text-shadow: 0 0 10px rgba(245,166,35,0.25);
}

/* ─ Macro card head ─ */
.macro-card-head {
  border-bottom: 1px solid rgba(35,50,65,0.7);
}

/* ─ Macro sub-tabs (GEN / ACC / SURP) ─ */
.macro-sub-tabs {
  display: flex;
  gap: 2px;
  margin-bottom: 4px;
  padding: 2px;
  background: rgba(10,18,25,0.5);
  border-radius: 4px;
}
.macro-sub-tabs .sub-tab {
  flex: 1;
  padding: 3px 0;
  font: 700 0.52rem/1 'SF Mono', 'Fira Code', monospace;
  letter-spacing: 0.08em;
  text-align: center;
  color: rgba(130,150,170,0.5);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  cursor: pointer;
  transition: all 0.15s;
}
.macro-sub-tabs .sub-tab:hover {
  color: rgba(180,200,220,0.7);
  background: rgba(30,45,60,0.3);
}
.macro-sub-tabs .sub-tab.active {
  color: rgba(245,180,30,0.9);
  background: rgba(245,180,30,0.08);
  border-color: rgba(245,180,30,0.2);
}

/* ─ Macro subsections ─ */
.macro-subsection {
  padding: 2px 0;
  transition: opacity 0.2s;
}
.macro-subsection.surprise-disabled {
  opacity: 0.45;
}
.macro-subsection .subsection-label {
  font: 700 0.5rem/1 'SF Mono', 'Fira Code', monospace;
  letter-spacing: 0.1em;
  color: rgba(130,150,170,0.45);
  text-transform: uppercase;
  margin-bottom: 2px;
}
.macro-subsection.active .subsection-label {
  color: rgba(245,180,30,0.65);
}

/* A section's own footnote: what a control is really doing when that differs
   from what it was set to. Sentence case, not the label's tracked caps — it is
   a sentence, and it earns its space only when there is something to say. */
.macro-subsection .subsection-note {
  font: 400 0.62rem/1.35 var(--mono);
  color: var(--text3);
  margin-top: 5px;
  max-width: 34ch;
}
/* It is always in the DOM so one text node can be refreshed live; with nothing
   to say it takes no space at all. */
.macro-subsection .subsection-note:empty {
  display: none;
}

/* ─ Register mini plot ─ */
.register-mini-section {
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid rgba(35,50,65,0.4);
}
.register-mini-section .subsection-label {
  font: 700 0.5rem/1 'SF Mono', 'Fira Code', monospace;
  letter-spacing: 0.1em;
  color: rgba(130,150,170,0.45);
  text-transform: uppercase;
  margin-bottom: 4px;
  /* the 8va buttons sit in the label row — flex keeps them inside it
     instead of floating over the sliders below */
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
}
.register-mini-canvas {
  width: 100%;
  height: 40px;
  background: rgba(5,10,8,0.5);
  border-radius: 3px;
  margin-top: 2px;
}

/* ─ Macro monitor ─ */
.monitor-title {
  color: #7a8a9a;
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.07em;
}

/* ─ CRT LED display screen ─ */
.macro-monitor .accuracy-canvas {
  background: #050a08;
  border-radius: 5px;
  box-shadow:
    inset 0 2px 8px rgba(0,0,0,0.6),
    inset 0 0 0 1px rgba(20,35,28,0.5),
    0 0 8px rgba(34,197,94,0.04),
    0 1px 3px rgba(0,0,0,0.5);
  outline: 1px solid rgba(30,45,38,0.3);
  outline-offset: 1px;
}

/* One vertical rhythm for every macro probability display.  The macro
   inspector is narrow, so it gets a compact height while the larger legacy
   macro panel keeps enough room for the CRT labels and live-note trace. */
.macro-monitor {
  --macro-display-height: 220px;
}

.macro-monitor .accuracy-canvas,
.melody-monitor .accuracy-canvas,
.duration-monitor .accuracy-canvas {
  display: block;
  width: 100%;
  height: var(--macro-display-height) !important;
  min-height: var(--macro-display-height);
  max-height: var(--macro-display-height);
  flex: 0 0 var(--macro-display-height);
}

.m2-inspector .macro-monitor {
  --macro-display-height: 150px;
  flex: none;
  overflow: visible;
}

/* ─ Structure / Markov card ─ */
.structure-card .section-label {
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}

/* ─ Production card ─ */
.production-head {
  border-bottom: 1px solid rgba(35,50,65,0.7);
}

.perf-tab {
  color: #6b7a8a;
  font-weight: 700;
  transition: all 0.15s;
}

.perf-tab:hover:not(.active) {
  color: #94a3b5;
  background: rgba(255,255,255,0.02);
}

.perf-tab.active {
  color: #ffc768;
  text-shadow: 0 0 10px rgba(245,166,35,0.25);
}

.production-panel .perc-layer {
  border: 1px solid rgba(30,45,58,0.7);
  border-radius: 5px;
  background: rgba(6,10,16,0.65);
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.2);
}

.perc-header {
  color: #7a8a9a;
  font-size: 0.52rem;
  font-weight: 800;
  letter-spacing: 0.05em;
}

/* ─ Output card ─ */
.output-card {
  background: linear-gradient(180deg, rgba(14,22,30,0.97), rgba(9,14,20,0.99));
}

.output-card .section-label {
  color: #8b99a8;
  font-size: 0.58rem;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}

/* ─ VU meters: segmented LED style ─ */
.meter-pair span {
  width: 18px;
  border-radius: 2px;
  background:
    repeating-linear-gradient(
      180deg,
      transparent 0px,
      transparent 1px,
      rgba(0,0,0,0.5) 1px,
      rgba(0,0,0,0.5) 3px
    ),
    linear-gradient(
      180deg,
      #ef4444 0%,
      #f5a623 8%,
      #f5a623 15%,
      #22c55e 15%,
      #22c55e 65%,
      #15803d 65%,
      #0a3d1e 100%
    );
  box-shadow:
    0 0 8px rgba(34,197,94,0.2),
    inset 0 0 4px rgba(34,197,94,0.1);
}

.meter-labels {
  color: #4a5968;
  font-size: 0.58rem;
  font-weight: 700;
}

/* ─ Master fader: see .fader--v at the top of this sheet ─ */

.master-strip output {
  font-size: 0.6rem;
  font-weight: 700;
  border: 1px solid rgba(35,50,65,0.7);
  background: #060a10;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.4);
  text-shadow: 0 0 6px rgba(200,210,220,0.15);
}

/* ─ Limiter button ─ */
.limiter-btn {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  background: rgba(245,166,35,0.1);
  border: 1px solid rgba(245,166,35,0.35);
  color: #ffc768;
  box-shadow: 0 0 8px rgba(245,166,35,0.1);
  transition: all 0.15s;
  text-shadow: 0 0 6px rgba(245,166,35,0.25);
}

.limiter-btn:hover {
  background: rgba(245,166,35,0.15);
  border-color: rgba(245,166,35,0.5);
  box-shadow: 0 0 12px rgba(245,166,35,0.2);
}

/* ─ Save button ─ */
.top-save-bar #saveBtn {
  font-weight: 800;
  letter-spacing: 0.06em;
  color: #f5a623;
  transition: all 0.15s;
  text-shadow: 0 0 8px rgba(245,166,35,0.2);
}

.top-save-bar #saveBtn:hover {
  border-color: rgba(245,166,35,0.4);
  background: rgba(245,166,35,0.06);
  box-shadow: 0 0 10px rgba(245,166,35,0.12);
}

/* ─ Library/Preset action buttons ─ */
.top-action-btn {
  font-weight: 800;
  transition: all 0.15s;
  color: #8b99a8;
}

.top-action-btn:hover {
  border-color: rgba(148,163,181,0.4);
  background: linear-gradient(180deg, #1a2836, #0c1420);
  color: #b8c4d0;
}

/* ─ Seed box ─ */
.seed-box #seedBtn {
  font-weight: 700;
  transition: border-color 0.15s;
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.3);
}

.seed-box #seedBtn:hover {
  border-color: rgba(148,163,181,0.4);
}

/* ─ Scrollbar refinement ─ */
.explore-dashboard .card::-webkit-scrollbar {
  width: 5px;
}

.explore-dashboard .card::-webkit-scrollbar-track {
  background: rgba(5,8,12,0.5);
}

.explore-dashboard .card::-webkit-scrollbar-thumb {
  background: rgba(45,60,78,0.6);
  border-radius: 3px;
}

.explore-dashboard .card::-webkit-scrollbar-thumb:hover {
  background: rgba(60,80,100,0.7);
}

/* ─ Feature check labels ─ */
.feature-check {
  font-size: 0.65rem;
  font-weight: 700;
  color: #8b99a8;
  letter-spacing: 0.05em;
  transition: color 0.15s;
}

.feature-check:hover {
  color: #b8c4d0;
}

/* ─ Probability legend ─ */
.prob-legend {
  border: 1px solid rgba(30,45,58,0.6);
  background: rgba(5,8,12,0.4);
  border-radius: 4px;
  color: #7a8a9a;
  font-weight: 600;
}

/* ─ Rating slider ─ */
.top-rating-row .label {
  color: #7a8a9a;
  font-size: 0.62rem;
  font-weight: 800;
}

.top-rating-row output {
  font-weight: 700;
  text-shadow: 0 0 8px rgba(245,166,35,0.25);
}

/* ─ Surprise weight list ─ */
.surprise-weight-list .control-row output {
  text-shadow: 0 0 6px rgba(245,166,35,0.2);
}

/* ─ Global transitions ─ */
.explore-dashboard button,
.explore-dashboard .btn {
  transition: all 0.15s ease;
}

/* ─ Canvas containers ─ */
.scale-card #cvRoot {
  background: #070c12;
  border: 1px solid rgba(25,38,52,0.6);
  border-radius: 3px;
  box-shadow: inset 0 1px 4px rgba(0,0,0,0.4);
}

/* ─ Section divider refinement ─ */
.explore-top {
  border-right: 1px solid rgba(35,50,65,0.45);
}

.engine-state {
  border-left: 1px solid rgba(35,50,65,0.5);
}

.engine-state .stat {
  border-right: 1px solid rgba(35,50,65,0.35);
}

.macro-controls {
  border-right: 1px solid rgba(35,50,65,0.6);
}

.master-strip,
.limiter-strip {
  border-left: 1px solid rgba(35,50,65,0.45);
}

/* ─ Toggle switch style for feature-check checkboxes ─ */
.explore-dashboard .feature-check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

.explore-dashboard .feature-check input[type="checkbox"] {
  width: 36px;
  height: 20px;
  min-width: 36px;
  border-radius: 10px;
  border: 1.5px solid rgba(45,62,78,0.9);
  background: #0a1018;
  box-shadow: inset 0 1px 4px rgba(0,0,0,0.5);
  position: relative;
  cursor: pointer;
  transition: all 0.2s ease;
}

.explore-dashboard .feature-check input[type="checkbox"]::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: linear-gradient(180deg, #4a5568, #2d3748);
  box-shadow: 0 1px 3px rgba(0,0,0,0.4);
  transition: all 0.2s ease;
}

.explore-dashboard .feature-check input[type="checkbox"]:checked {
  background: rgba(245,166,35,0.2);
  border-color: rgba(245,166,35,0.6);
  box-shadow: inset 0 1px 4px rgba(0,0,0,0.3), 0 0 8px rgba(245,166,35,0.2);
}

.explore-dashboard .feature-check input[type="checkbox"]:checked::after {
  left: calc(100% - 16px);
  background: radial-gradient(circle at 40% 35%, #fcd34d, #f5a623);
  box-shadow: 0 0 6px rgba(245,166,35,0.6), 0 1px 3px rgba(0,0,0,0.3);
}

/* ─ Transport icon styling ─ */
.transport-play {
  font-size: 1.3rem;
  letter-spacing: -0.05em;
}

.transport-play.is-playing {
  font-size: 1.1rem;
  letter-spacing: 0.1em;
}

.transport-stop {
  font-size: 1.1rem;
  color: #7a8a9a;
}

.transport-stop:hover {
  color: #b8c4d0;
}

/* ─ Preset navigation in transport ─ */
.top-save-bar input[type="text"] {
  font-size: 0.76rem;
  letter-spacing: 0.02em;
}

/* ─ Section label refinement matching mockup ─ */
.structure-card > .section-label:first-child {
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(35,50,65,0.4);
  margin-bottom: 10px;
}

/* ─ Surprise section separator ─ */
.structure-card .section-label + .section-label,
.structure-card .section-label:nth-of-type(2) {
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid rgba(35,50,65,0.4);
}

/* ─ Surprise weight labels ─ */
.surprise-weight-list {
  padding-top: 8px;
}

.surprise-weight-list .section-subhead {
  color: #7a8a9a;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  margin-bottom: 6px;
}

/* ─ Full note grid showing all 12 notes ─ */
.note-grid {
  gap: 4px;
  margin: 4px 0;
}

/* ─ Production section - more compact ─ */
.production-panel .perc-layers {
  gap: 5px;
}

.production-panel .perc-layer {
  padding: 4px 6px;
}

/* ─ Macro panel register controls visible ─ */
.macro-controls .section-subhead {
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid rgba(35,50,65,0.3);
}

/* ─ Density improvements ─ */
.explore-dashboard .controls-grid {
  gap: 3px;
}

.explore-dashboard .control-row {
  min-height: 22px;
  gap: 0.2rem;
}

/* Scale to fit viewport if smaller than fixed plugin size */
@media (max-width: 1460px), (max-height: 810px) {
  body.explore-mode,
  body.explore-mode #app {
    align-items: flex-start;
    justify-content: flex-start;
  }
  .explore-dashboard {
    transform-origin: top left;
    /* Q12 QA: the original `transform: scale(min(calc(100vw / 1446), …))`
       was INVALID CSS — scale() takes a number, calc(100vw/1446) is a
       length — so the scale-to-fit design silently never applied and
       small viewports just clipped the right of the plugin. The scale is
       now computed in JS (fitStudioScale in app.js). */
  }
}

/* ── Output meters + limiter state ─────────────────────────── */
.meter-pair span {
  transform-origin: bottom center;
  transition: transform 0.06s linear;
}
.limiter-btn { cursor: pointer; transition: background 0.15s, color 0.15s, box-shadow 0.15s; }
.limiter-btn.active {
  background: rgba(34,197,94,0.14);
  color: var(--green, #22c55e);
  box-shadow: inset 0 0 0 1px rgba(34,197,94,0.4);
}
.limiter-btn:not(.active) {
  background: rgba(49,69,86,0.18);
  color: #6f7b89;
  box-shadow: none;
}

/* ── Welcome / research opt-in ───────────────────────────── */

/* The welcome card floats over the studio on first visit instead of taking
   a row in the fixed-height dashboard grid (which squashed the workspace
   to nothing). Audit P0 / phase-01 render: compact centred choice card —
   audition strip + Just Play / Share Ratings / Load Demo. */
.welcome-card {
  border-color: var(--border2);
  background: linear-gradient(180deg, var(--surface2), var(--surface));
  position: fixed;
  inset: 0;
  z-index: 60;
  margin: auto;
  width: min(680px, calc(100vw - 48px));
  height: fit-content;
  max-height: calc(100dvh - 48px);
  overflow: auto;
  padding: 1.4rem 1.6rem !important;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.55);
  text-align: center;
}

.welcome-card::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: rgba(4, 6, 10, 0.62);
}

.welcome-card h2 {
  font-size: 1.5rem;
  letter-spacing: -0.02em;
}

.welcome-card p {
  color: var(--text2);
  font-size: 0.92rem;
  max-width: 60ch;
  margin: 0 auto;
}

.welcome-hero {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.7rem;
}

/* The Soundinator marks: the street organ, themed to the UI's ink. The wide
   lockup goes where there's horizontal room; the square icon fits corners. */
.app-mark-bg { fill: var(--display); stroke: var(--text2); stroke-linecap: round; stroke-linejoin: round; }
.app-mark-art { fill: var(--surface2); stroke: var(--text2); stroke-linecap: round; stroke-linejoin: round; }
.app-mark-detail { fill: none; stroke: var(--text2); stroke-linecap: round; stroke-linejoin: round; }
.app-mark-fill { fill: var(--text2); }
.app-icon .app-mark-bg, .app-icon .app-mark-art { stroke-width: 24; }
.app-icon .app-mark-detail { stroke-width: 14; }
.app-logo .app-mark-bg, .app-logo .app-mark-art { stroke-width: 6; }
.app-logo .app-mark-detail { stroke-width: 3; }
.app-icon { width: 26px; height: 26px; flex: none; vertical-align: middle; overflow: visible; }
.app-icon.sm { width: 20px; height: 20px; }
.app-logo { width: 86px; height: 30px; flex: none; vertical-align: middle; overflow: visible; }
.app-logo.lg { width: 126px; height: 44px; }
/* The wordmark rows centre everything on one line — mark, name, build tag,
   and the account pill all share a baseline (owner 2026-07-15). */
.explore-top { align-items: center; }
.explore-title { min-width: 0; flex: 1 1 auto; }
/* The header column is user-resizable and often narrow: the brand name and
   the account pill's name BOTH shrink, so neither vanishes outright. */
.explore-top .account-bar { flex: 0 1 auto; min-width: 0; }
.explore-top .account-bar .acct-pill { min-width: 0; max-width: 100%; }
.explore-top .account-bar .acct-name { flex: 0 1 auto; min-width: 2ch; }
.explore-title h1 { display: flex; align-items: center; gap: 8px; margin: 0; white-space: nowrap; min-width: 0; }
/* The wordmark takes a rounded face wherever it sits beside the machine
   marks — matching the artwork's fat round line-caps. */
:root { --brand-font: ui-rounded, "SF Pro Rounded", "Hiragino Maru Gothic ProN", "Quicksand", "Comfortaa", var(--font); }
.explore-title .app-name { overflow: hidden; text-overflow: ellipsis; min-width: 0;
  font-family: var(--brand-font); font-weight: 800; letter-spacing: .02em; }
.welcome-hero h2 { font-family: var(--brand-font); font-weight: 800; letter-spacing: .02em; }
.auth-modal header h3 { font-family: var(--brand-font); font-weight: 800; letter-spacing: .02em; }
.landing-header h1 { font-family: var(--brand-font); font-weight: 800; letter-spacing: .02em; }
.explore-title .build-tag { flex: none; }
/* The header column is user-resizable, so the wordmark responds to the
   COLUMN's width, not the window's: full lockup when roomy, then the build
   tag yields, then the name — the machine logo alone carries the brand in a
   tight corner. */
.explore-top { container-type: inline-size; }
@container (max-width: 560px) { .explore-title .build-tag { display: none; } }
@container (max-width: 400px) { .explore-title .app-name { display: none; } }
.daw-title { display: inline-flex; align-items: center; gap: 7px; }

.welcome-rule {
  position: relative;
  height: 1px;
  margin: 0.9rem auto 0.8rem;
  width: min(340px, 80%);
  background: linear-gradient(90deg, transparent, var(--border2), transparent);
}
.welcome-rule i {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: var(--accent);
}

.welcome-tagline {
  font-size: 0.95rem;
  margin-bottom: 1rem;
}

.welcome-audition {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  background: var(--display);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.55rem 0.8rem;
  margin-bottom: 1rem;
}
.welcome-wave {
  flex: 1;
  height: 32px;
  min-width: 0;
  color: #5b8fd4;
}
.welcome-wave rect { fill: currentColor; }
.welcome-audition-play {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--border2);
  background: var(--surface2);
  color: var(--accent);
  font-size: 0.85rem;
  cursor: pointer;
  flex-shrink: 0;
  transition: all 0.15s;
}
.welcome-audition-play:hover { border-color: var(--accent); background: #f5a62318; }

.welcome-choices {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.8rem;
  align-items: stretch;
}
@media (max-width: 640px) { .welcome-choices { grid-template-columns: 1fr; } }

.welcome-choice {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding: 0.9rem 0.8rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.015);
}
.welcome-choice h3 { font-size: 0.95rem; }
.welcome-choice p { font-size: 0.78rem; line-height: 1.45; }
.welcome-choice-featured {
  border-color: rgba(34, 197, 94, 0.45);
  box-shadow: 0 0 24px rgba(34, 197, 94, 0.08) inset;
}

.welcome-choice-icon {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  font-size: 1.15rem;
}
.wc-amber  { color: var(--accent); background: #f5a62318; }
.wc-green  { color: var(--green);  background: #22c55e18; }
.wc-purple { color: var(--rootc);  background: #8b7cf618; }

.welcome-cta {
  margin-top: auto;
  width: 100%;
  border: none;
  border-radius: 8px;
  padding: 0.5rem 0.6rem;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  transition: filter 0.15s;
}
.welcome-cta:hover { filter: brightness(1.12); }
.cta-amber  { background: var(--accent); color: #16181d; }
.cta-green  { background: var(--green);  color: #08130b; }
.cta-purple { background: var(--rootc);  color: #0d0a1c; }

.welcome-scale {
  display: flex;
  justify-content: center;
  gap: 0.3rem;
  font-size: 0.72rem;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
}
.welcome-scale span {
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
}
.welcome-scale span.on {
  border: 1px solid var(--green);
  border-radius: 50%;
  color: var(--green);
}
.welcome-scale-ends {
  display: flex;
  justify-content: space-between;
  width: 100%;
  font-size: 0.62rem;
  color: var(--text3);
}

.welcome-share-step p { font-size: 0.85rem; }

.welcome-anon {
  margin-top: 1rem;
  font-size: 0.85rem;
  color: var(--text2);
}

.welcome-demographics {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem 2rem;
  margin: 0.9rem 0;
}

.welcome-demographics label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.88rem;
  color: var(--text2);
}

.welcome-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
  margin: 0.4rem 0 0.6rem;
}

.welcome-smallprint {
  font-size: 0.78rem;
  color: var(--text3);
}

.research-note {
  margin-top: 1.2rem;
  text-align: center;
  font-size: 0.82rem;
  color: var(--text3);
}

.link-btn {
  background: none;
  border: none;
  color: var(--blue);
  cursor: pointer;
  font: inherit;
  text-decoration: underline;
  padding: 0;
}

/* ── Modular preset sections ─────────────────────────────── */

.top-save-bar select {
  background: var(--surface2);
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.3rem 0.4rem;
  font-size: 0.66rem;
  flex: none;
  max-width: 90px; /* "Everything" doesn't need 130px — keep the row compact */
}

.section-chip {
  display: inline-block;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  font-size: 0.68rem;
  letter-spacing: 0.02em;
  border: 1px solid var(--border2);
  color: var(--accent2);
  background: rgba(245, 158, 11, 0.08);
  white-space: nowrap;
}

.section-chip.chip-full {
  color: var(--text3);
  background: rgba(136, 153, 170, 0.08);
}

/* ── Preset browser: section filters + in-context preview ── */

.library-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.7rem 0 0.9rem;
}

.filter-chip {
  background: var(--surface2);
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.18rem 0.7rem;
  font-size: 0.7rem;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: border-color 0.12s, color 0.12s;
}

.filter-chip:hover { border-color: var(--border2); color: var(--text); }

.filter-chip.active {
  color: var(--accent2);
  border-color: rgba(245,166,35,0.5);
  background: rgba(245,166,35,0.08);
}

.preview-btn { min-width: 2rem; }

.preview-btn.previewing {
  color: var(--surp);
  border-color: rgba(56,189,248,0.5);
  background: rgba(56,189,248,0.1);
}

/* ── Display hover readout ───────────────────────────────── */

.dist-readout {
  position: fixed;
  z-index: 60;
  pointer-events: none;
  background: rgba(16,18,22,0.94);
  border: 1px solid var(--border2);
  border-radius: 6px;
  padding: 0.25rem 0.55rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  color: var(--text2);
  display: flex;
  gap: 0.55rem;
  align-items: baseline;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0,0,0,0.45);
}

.dist-readout strong { color: var(--text); font-weight: 600; margin-right: 0.15rem; }
.dist-readout .dr-gen  { color: var(--gen); }
.dist-readout .dr-acc  { color: var(--acc); }
.dist-readout .dr-surp { color: var(--surp); }

/* ── Per-panel preset bars ───────────────────────────────── */

.panel-presets {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.3rem 0 0.55rem;
}

.panel-presets select {
  flex: 1;
  min-width: 0;
  background: var(--surface2);
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.22rem 0.4rem;
  font-size: 0.72rem;
}

.panel-presets .btn {
  flex: none;
  white-space: nowrap;
}

.panel-preset-control { align-items: stretch; }
.panel-preset-picker { flex: 1; min-width: 0; }
.panel-preset-display { min-height: 34px; box-sizing: border-box; }
.panel-preset-name-input {
  flex: 1; min-width: 0; width: 100%; box-sizing: border-box;
  border: 0; outline: 0; background: transparent; color: var(--text);
  font: inherit; font-weight: 600; padding: 0;
}
.panel-preset-save:disabled {
  opacity: 0.34; cursor: not-allowed; filter: grayscale(0.75);
}
.panel-preset-save:not(:disabled) {
  border-color: rgba(245,166,35,0.58); color: #ffd28a;
  background: rgba(245,166,35,0.08);
}

/* ── Instrument library tab ──────────────────────────────── */

.instrument-actions {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 0.6rem;
}

/* ── Producer mode ───────────────────────────────────────── */

.produce-view { display: flex; flex-direction: column; gap: 10px; }

.produce-top {
  display: flex; align-items: center; justify-content: space-between;
}
.produce-top h1 { font-size: 1.25rem; letter-spacing: 0.05em; }
.produce-actions { display: flex; gap: 0.5rem; }

.produce-browser .produce-sources {
  display: flex; flex-wrap: wrap; gap: 0.45rem;
}

.source-chip {
  background: var(--surface2);
  color: var(--text);
  border: 1px solid var(--border2);
  border-radius: 8px;
  padding: 0.45rem 0.9rem;
  font-size: 0.8rem;
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s;
}
.source-chip:hover { border-color: var(--accent); background: rgba(245,166,35,0.08); }
.source-chip.chip-factory { color: var(--text2); }

.timeline-grid { display: flex; flex-direction: column; gap: 4px; overflow-x: auto; }

.tl-row {
  display: grid;
  grid-template-columns: 130px repeat(16, minmax(38px, 1fr));
  gap: 3px;
  align-items: stretch;
}

.tl-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.3rem;
  padding: 0.25rem 0.5rem;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.72rem;
  color: var(--text);
  overflow: hidden;
}
.tl-head span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tl-remove {
  background: none; border: none; color: var(--text3);
  cursor: pointer; font-size: 0.85rem; line-height: 1;
}
.tl-remove:hover { color: var(--red); }

.tl-cell {
  min-height: 34px;
  background: var(--display);
  border: 1px solid var(--border);
  border-radius: 5px;
  cursor: pointer;
  transition: border-color 0.1s;
}
.tl-cell:hover { border-color: var(--accent); }

.tl-region {
  min-height: 34px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(245,166,35,0.16);
  border: 1px solid rgba(245,166,35,0.55);
  border-radius: 5px;
  cursor: pointer;
  font-size: 0.62rem;
}
.tl-region.selected {
  border-color: var(--surp);
  box-shadow: 0 0 0 1px rgba(56,189,248,0.5);
}
.tl-seed { color: var(--accent2); font-family: var(--mono); }

.region-toolbar {
  display: flex; gap: 0.5rem; align-items: center;
  margin-top: 0.7rem;
}
.toolbar-hint { color: var(--text3); font-size: 0.78rem; }

.workspace-link { text-decoration: none; }

/* ── Formant detail disclosure ───────────────────────────── */

.formant-detail { margin-top: 0.6rem; }
.formant-detail summary {
  cursor: pointer;
  font-size: 0.72rem;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  user-select: none;
}
.formant-detail summary:hover { color: var(--text2); }
.formant-detail[open] summary { color: var(--text2); margin-bottom: 0.5rem; }

/* ── Producer session bar ────────────────────────────────── */

.session-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 1.4rem;
  align-items: center;
}

.session-controls label {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.74rem;
  color: var(--text2);
}

.session-controls input[type="range"] { width: 110px; }

.session-controls select {
  background: var(--surface2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.2rem 0.35rem;
  font-size: 0.74rem;
}

.session-controls output {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--accent2);
  min-width: 2.2ch;
}

/* ── Arrangement playhead ────────────────────────────────── */

.tl-cell.playhead { border-color: var(--surp); background: rgba(56,189,248,0.06); }
.tl-region.playhead {
  border-color: var(--surp);
  box-shadow: 0 0 0 1px rgba(56,189,248,0.6), 0 0 10px rgba(56,189,248,0.25);
}

/* ── Producer v2: region length, track gain ──────────────── */

.tl-len {
  margin-left: 0.35rem;
  color: var(--text2);
  font-family: var(--mono);
  font-size: 0.6rem;
}

.tl-head .tl-gain {
  width: 46px;
  flex: none;
}

/* ── Touch ergonomics: coarse pointers get bigger targets ── */

@media (pointer: coarse) {
  input[type="range"] { height: 6px; }
  input[type="range"]::-webkit-slider-thumb {
    width: 22px;
    height: 22px;
  }
  input[type="range"]::-moz-range-thumb {
    width: 20px;
    height: 20px;
  }
  .explore-dashboard input[type="range"]::-webkit-slider-thumb {
    width: 20px;
    height: 20px;
  }
  /* FE-13: a fader is a drag target, so it takes the full 44px on a coarse
     pointer. The groove and its meter stay pinned to the box's centre line
     (see .fader-meter above), so only the grabbable area grows. */
  input[type="range"].fader.fader--h { height: 44px; }
  input[type="range"].fader.fader--h::-webkit-slider-thumb { width: 20px; height: 30px; }
  input[type="range"].fader.fader--h::-moz-range-thumb { width: 20px; height: 30px; }
  input[type="range"].fader.fader--v { height: 44px; }
  input[type="range"].fader.fader--v::-webkit-slider-thumb { width: 22px; height: 40px; }
  input[type="range"].fader.fader--v::-moz-range-thumb { width: 22px; height: 40px; }
  .btn, .filter-chip, .m-chip, .tab, .workspace-tab {
    min-height: 38px;
  }
  .preset-item .actions .btn { padding: 0.5rem 0.9rem; }
  /* FE-34: the divisions field and its 12 quick-pick are ordinary tap
     targets, so they join the block rather than bypassing it. */
  .edo-input, .edo-reset { min-height: 38px; }
  /* A knob is now a real drag target on touch, so it takes the full 44 px in
     both axes. The base cell is 62 px wide and about 62 tall (44 arc + label +
     readout), but the packed variants shrink it — .patch-engine-knobs to 46 px
     and .mod-row's arc to 38 — and those are the ones a thumb has to hit.
     Only the box grows; the arc and its label keep their own sizes, so no
     panel reflows on a desktop. */
  .knob-cell { min-width: 44px; min-height: 44px; }
}

/* ── Baked-region piano roll ─────────────────────────────── */

.roll-panel { margin-top: 0.8rem; }

.roll-panel canvas {
  display: block;
  width: 100%;
  height: 240px;
  background: var(--display);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
}

.roll-readout {
  margin-top: 0.45rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
}

/* ── DAW shell (producer v2 P1) ──────────────────────────── */

.daw {
  display: flex;
  flex-direction: column;
  height: calc(100dvh - 20px);
  gap: 0;
}

.daw-transport {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex-wrap: wrap;
  padding: 0.45rem 0.7rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 6px;
}

.daw-title {
  font-weight: 700;
  letter-spacing: 0.06em;
  font-size: 0.85rem;
  margin-right: 0.4rem;
}

.daw-sep {
  width: 1px;
  height: 22px;
  background: var(--border2);
}

.daw-ctx {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.7rem;
  color: var(--text2);
}
.daw-ctx input[type="range"] { width: 84px; }
.daw-ctx select {
  background: var(--surface2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.16rem 0.3rem;
  font-size: 0.7rem;
}
.daw-ctx output {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--accent2);
}

.daw-main {
  /* Grid so the library (left) spans full height and rises to the top, while
     the transport/edit bar sits only over the track area (top-right). The
     first column track is set inline from dawLayout.leftW. */
  display: grid;
  grid-template-rows: auto 1fr;
  grid-template-columns: 250px 6px 1fr;
  grid-template-areas:
    "left vsplit regionbar"
    "left vsplit center";
  flex: 1;
  min-height: 0;
}
.daw-main > .daw-left { grid-area: left; min-height: 0; width: auto; }
.daw-main > .daw-vsplit { grid-area: vsplit; height: auto; }
.daw-main > .daw-center { grid-area: center; min-height: 0; }
/* The region edit bar (Stop loop / Bake / Reroll / seed / Split) sits at the
   top of the track column — starting after the left library pane — while the
   main transport stays full-width across the top. */
.daw-main > .region-toolbar {
  grid-area: regionbar;
  min-height: 40px;
  margin: 0 0 6px;
  padding: 6px 10px;
  gap: 8px;
  flex-wrap: wrap;
  background: linear-gradient(180deg, rgba(26,31,41,0.98), rgba(17,21,29,0.98));
  border: 1px solid rgba(66,75,91,0.82);
  border-radius: 8px;
}
.daw-main > .region-toolbar .btn-sm { min-height: 28px; padding: 0.3rem 0.66rem; border-radius: 6px; }

.daw-left {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem;
  overflow-y: auto;
  flex: none;
  transition: width 0.15s ease;
}
.daw-left.collapsed { padding: 0.6rem 0.15rem; overflow: hidden; }
.daw-left .produce-sources { flex-direction: column; align-items: stretch; display: flex; }
.daw-left .source-chip { text-align: left; }

/* FE-8/FE-4: the collapse control moves off the header row (where it painted
   over the Community pill) and onto the panel's own trailing edge, vertically
   centred — the edge is where a collapse belongs, and it is the one strip of
   this panel that never holds content. */
.daw-collapse {
  position: absolute;
  top: 50%;
  right: -1px;
  transform: translateY(-50%);
  width: 12px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--well);
  border: 1px solid var(--hairline-soft);
  border-right: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  color: var(--text3);
  cursor: pointer;
  font-size: 0.62rem;
  line-height: 1;
  padding: 0;
  opacity: 0;
  transition: opacity 0.12s, color 0.12s;
  z-index: 4;
}
.daw-left:hover .daw-collapse,
.daw-collapse:focus-visible { opacity: 1; }
.daw-left.collapsed .daw-collapse { opacity: 1; }
.daw-collapse:hover { color: var(--text); }
.daw-collapse:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* The splitter advertises itself: a grip on hover, and it is now also the
   double-click collapse target (see wireDawLayout). */
.daw-vsplit::before {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 2px; height: 30px;
  border-radius: 1px;
  background: rgba(154,160,171,0.42);
  opacity: 0;
  transition: opacity 0.12s;
}
.daw-vsplit { position: relative; }
.daw-vsplit:hover::before { opacity: 1; }
.daw-vsplit:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; border-radius: 3px; }

/* Community leaves the header and joins the filter row, off the accent. */
.browser-filters-sep {
  width: 1px;
  align-self: stretch;
  min-height: 16px;
  margin: 0 2px;
  background: var(--hairline-soft);
  flex: none;
}
.browser-community-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 22px;
  padding: 0.14rem 0.5rem;
  border: 1px solid var(--control-border);
  border-radius: 999px;
  background: var(--control-bg);
  color: var(--text2);
  font: inherit;
  font-size: 0.68rem;
  white-space: nowrap;
  cursor: pointer;
}
.browser-community-btn:hover { color: var(--text); border-color: var(--hairline); }
.browser-community-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.daw-vsplit {
  width: 6px;
  cursor: col-resize;
  flex: none;
}
.daw-vsplit:hover { background: rgba(154,160,171,0.15); border-radius: 3px; }

/* Horizontal splitter between the Browser and Palette panes in the library. */
.daw-lsplit {
  height: 6px;
  cursor: row-resize;
  flex: none;
  margin: 1px 0;
  border-radius: 3px;
}
.daw-lsplit:hover { background: rgba(154,160,171,0.2); }

.daw-center {
  flex: 1;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.7rem;
  overflow: auto;
  /* owner 07-07: the region toolbar pins to the bottom instead of
     floating mid-workspace over an empty gap */
  display: flex;
  flex-direction: column;
}
.daw-center .timeline-grid { flex: 1 1 auto; }
.daw-center .region-toolbar { flex: none; margin-top: auto; }

.daw-hsplit {
  height: 6px;
  cursor: row-resize;
  flex: none;
}
.daw-hsplit:hover { background: rgba(154,160,171,0.15); border-radius: 3px; }

.daw-editor {
  flex: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem 0.7rem;
  overflow: auto;
}
.daw-editor.collapsed { border: none; padding: 0; }
.daw-editor .roll-panel { margin-top: 0; }

/* ── Producer browser + palette (v2 P2) ──────────────────── */

.daw-left-content { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.daw-browser { flex: 1 1 60%; min-height: 0; display: flex; flex-direction: column; }
.daw-browser input[type="search"] {
  width: 100%;
  background: var(--display);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.35rem 0.55rem;
  font-size: 0.78rem;
  margin: 0.35rem 0 0.45rem;
}
.browser-filters { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 0.5rem; }
.browser-cards { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; padding-right: 2px; }

/* Owner 07-07: compact browser rows — many patches visible at once */
.browser-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.14rem 0.4rem;
  border: 1px solid transparent;
  border-radius: 5px;
  cursor: grab;
}
.browser-row:hover { background: var(--surface2); border-color: var(--border); }
.br-name { flex: 1; font-size: 0.72rem; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.br-kind { font-size: 0.55rem; color: var(--text3); white-space: nowrap; letter-spacing: 0.03em; }
.br-btn {
  width: 20px;
  height: 18px;
  padding: 0;
  background: none;
  color: var(--text3);
  border: 1px solid transparent;
  border-radius: 4px;
  font-size: 0.62rem;
  cursor: pointer;
  flex: none;
}
.br-btn:hover { color: var(--text); border-color: var(--border2); }
.br-btn.on { color: var(--surp); }

.browser-card {
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.45rem 0.55rem;
  cursor: grab;
}
.browser-card:hover { border-color: var(--border2); }
.bc-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.4rem; }
.bc-name { font-size: 0.78rem; color: var(--text); font-weight: 600; }
.bc-kind {
  font-size: 0.62rem;
  color: var(--accent2);
  border: 1px solid rgba(245,166,35,0.35);
  border-radius: 999px;
  padding: 0.02rem 0.4rem;
  white-space: nowrap;
}
.bc-desc { font-size: 0.68rem; color: var(--text3); margin-top: 0.15rem; }
.bc-actions { display: flex; gap: 0.35rem; margin-top: 0.35rem; }

.pal-btn {
  background: var(--surface);
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.14rem 0.5rem;
  font-size: 0.68rem;
  cursor: pointer;
}
.pal-btn:hover { color: var(--text); border-color: var(--border2); }

.daw-palette { flex: 1 1 40%; min-height: 90px; margin-top: 0.6rem; border-top: 1px solid var(--border); padding-top: 0.5rem; display: flex; flex-direction: column; }
.daw-palette.drop-target { outline: 1px dashed var(--accent); outline-offset: 3px; border-radius: 6px; }
.palette-rack { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 0.3rem; }
.palette-item {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--surface2);
  border: 1px solid var(--border2);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  padding: 0.3rem 0.45rem;
  cursor: grab;
}
.pal-name { flex: 1; font-size: 0.75rem; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pal-kind { font-size: 0.6rem; color: var(--text3); white-space: nowrap; }
.pal-actions { display: flex; gap: 0.25rem; }

/* ── Q1: patch transparency badges + module halves ───────── */
.palette-item { flex-wrap: wrap; }
.palette-item.half-armed { border-color: rgba(245,166,35,0.55); box-shadow: 0 0 0 1px rgba(245,166,35,0.25); }
.palette-item.drop-target { outline: 1px dashed var(--accent); outline-offset: 2px; }
.pb-row { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: 0.2rem; margin-top: 0.15rem; }
.pb-chip {
  font-size: 0.58rem;
  color: var(--text3);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.02rem 0.4rem;
  white-space: nowrap;
}
.pb-chip.pb-surprise { color: var(--surp); border-color: rgba(56,189,248,0.45); }
.pb-chip.pb-off { opacity: 0.55; }
.pal-half { flex-basis: 100%; display: flex; gap: 0; margin-top: 0.25rem; }
.pal-half-btn {
  flex: 1;
  background: var(--surface);
  color: var(--text3);
  border: 1px solid var(--border);
  padding: 0.08rem 0.3rem;
  font-size: 0.55rem;
  letter-spacing: 0.05em;
  cursor: pointer;
}
.pal-half-btn:first-child { border-radius: 5px 0 0 5px; }
.pal-half-btn:last-child { border-radius: 0 5px 5px 0; }
.pal-half-btn.active {
  color: var(--accent2);
  border-color: rgba(245,166,35,0.5);
  background: rgba(245,166,35,0.1);
}
.splits-filter {
  background: var(--surface2);
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.14rem 0.5rem;
  font-size: 0.68rem;
  cursor: pointer;
}
.tl2-badges {
  position: absolute;
  left: 4px;
  bottom: 2px;
  right: 4px;
  overflow: hidden;
  pointer-events: none;
}
.tl2-badges .pb-row { flex-wrap: nowrap; margin-top: 0; }
.tl2-badges .pb-chip { background: rgba(10,14,20,0.65); }

/* ── FE-3: the Harmonic guide collapsed to one thread (owner 2026-08-27) ───
   Collapsed used to render `.tl2-rowfill` — literally nothing — so closing the
   guide discarded every trace of where the key changes. It is one continuous
   line now, cut and recoloured at each change point, with the change points as
   draggable diamonds. The same handles are overlaid on the expanded canvas, so
   there is one drag implementation for both views. */
/* FE-11: the collapsed lane IS the key. One line per playable note, stacked in
   scale order with the tonic at the bottom; the non-playable divisions are the
   gaps between them. Taller than the old single thread because it now has to
   hold up to a dozen lines and still be countable. */
/* Owner 2026-08-28: one stripe, bands touching, star and name ABOVE it. The
   lane is therefore two zones — a label/star band on top, the stripe on the
   bottom — rather than one field with things floating in it. */
.gs-thread {
  position: relative;
  height: 30px;
  flex: none;
}
.gs-thread.off { opacity: 0.42; }
.gs-span {
  position: absolute;
  top: 0;
  bottom: 0;
}
/* The stripe: contiguous bands, no gaps, every band the same width. Its
   thickness is the key's size — a 5-note scale and a 12-note one are the same
   height but banded differently, so what changes at a key change is the
   PATTERN, which is the thing worth seeing at a glance. */
.gs-stripe {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2px;
  height: 11px;
  border-radius: 2px;
  overflow: hidden;
}
.gs-band {
  position: absolute;
  left: 0;
  right: 0;
  background: var(--hg-c, var(--text2));
}
/* The tonic band is the one the others are heard against, so it reads at full
   strength; the rest sit back a little so the tonic is findable in the stack. */
.gs-band-root { filter: none; }
.gs-band-sub { opacity: 0.92; }
.gs-band-scale { opacity: 0.62; }
.gs-name {
  position: absolute;
  /* Clear of the star. The star is 15px wide and centred ON the span's start
     (the change point), so it occupies -7.5..+7.5px of this box — a name at
     7px had its first letter drawn straight through, which is the same
     overprint as before wearing a different hat. 16px puts the text past the
     spokes with a little air. */
  left: 16px;
  top: 1px;
  font-size: 0.5rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text3);
  white-space: nowrap;
  pointer-events: none;
}
/* The star sits ON the lane, over the lines it describes. */
.gs-star { display: block; overflow: visible; }
.gs-handle .gs-star { filter: drop-shadow(0 0 3px rgba(6, 9, 14, 0.9)); }
/* The handle: a small diamond ON the line, inside a 44px transparent target so
   it is reachable on a coarse pointer without drawing a 44px control. */
/* The star sits ABOVE the stripe, in the label band — it marks the moment the
   stripe changes, so it belongs over the join, not buried in the colour. */
.gs-handle {
  position: absolute;
  top: 9px;
  width: 44px;
  height: 30px;
  transform: translate(-50%, -50%);
  padding: 0;
  border: 0;
  background: none;
  cursor: ew-resize;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
}
.gs-handle.first { cursor: default; }
.gs-handle > .gs-star {
  transition: transform 0.12s;
  transform-origin: 50% 50%;
}
.gs-handle:hover > .gs-star { transform: scale(1.3); }
.gs-handle.sel > .gs-star { transform: scale(1.15); }
.gs-handle.sel::after {
  content: "";
  position: absolute;
  width: 21px; height: 21px;
  border-radius: 50%;
  border: 1px solid var(--text);
  opacity: 0.55;
}
.gs-handle.first > .gs-star { opacity: 0.78; }
/* FE-31: `.gs-handle.plain` and `.gs-grip` are gone. The expanded view wore
   them while the star was withheld from it (FE-11); the owner has since asked
   for the star in both views, so nothing renders them and dead CSS is worse
   than none. */
.gs-handle:focus-visible { outline: 2px solid var(--accent); outline-offset: -14px; border-radius: 8px; }
/* HG-B3 (owner 2026-08-29): the wrap is the CANVAS's box and nothing else. It
   used to be 18px taller than the canvas, with the canvas pushed down by that
   much, to open a band for the stars; because the band was a gap in the lane it
   showed `.gs-strip`'s near-black ground, and the owner read it as a black
   strip that should not be there. The stars moved up into `.hg-head` — the row
   that already carries the scale's name — which is where the collapsed lane has
   always kept them relative to its stripe. Same guarantee, one surface fewer:
   the spokes cannot reach the division grid because a whole label row stands
   between them. */
.gs-canvas-wrap { position: relative; }
.gs-canvas-wrap.open { box-sizing: border-box; }
.gs-canvas-wrap.open > #gsCanvas { display: block; }
@media (prefers-reduced-motion: reduce) {
  .gs-handle > .gs-star { transition: none; }
}

/* ── Q5: global scale strip ──────────────────────────────── */
.tl2-gs-row { min-height: 20px; }
.gs-head { display: flex; align-items: center; gap: 0.3rem; padding: 0 0.3rem; }
.gs-chevron {
  background: none;
  border: none;
  color: var(--text3);
  font-size: 0.6rem;
  letter-spacing: 0.05em;
  cursor: pointer;
  white-space: nowrap;
}
.gs-chevron:hover { color: var(--text); }
.gs-strip {
  position: relative;
  min-height: 20px;
  background: var(--surface2);
  /* Outline drawn INSIDE the box: a real border would inset the canvas by
     1px and knock the guide out of alignment with the ruler and lanes. */
  border: 0;
  box-shadow: inset 0 0 0 1px var(--border);
  border-radius: 4px;
}
.gs-strip.off { opacity: 0.45; }
.gs-strip.open { min-height: 42px; }
#gsCanvas { display: block; cursor: pointer; border-radius: 4px; }
.gs-flag {
  position: absolute;
  top: 0;
  font-size: 0.66rem;
  color: var(--accent2);
  cursor: pointer;
  line-height: 20px;
  padding: 0 2px;
}
.gs-flag.sel { color: #fff; text-shadow: 0 0 6px rgba(245,166,35,0.9); }
.gs-flag-label { font-size: 0.5rem; color: var(--text3); margin-left: 1px; }
.gs-add {
  position: absolute;
  top: 1px;
  width: 16px;
  height: 16px;
  padding: 0;
  border-radius: 50%;
  border: 1px dashed var(--border2);
  background: none;
  color: var(--text3);
  font-size: 0.6rem;
  cursor: pointer;
  line-height: 1;
}
.gs-add:hover { color: var(--accent2); border-color: rgba(245,166,35,0.5); }
.gs-editor {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.4rem;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 4px;
  margin-bottom: 4px;
}
.gs-editor-title { font-size: 0.6rem; color: var(--text3); white-space: nowrap; }
.gs-roll { display: flex; gap: 2px; flex-wrap: wrap; }
.gs-cell {
  width: 22px;
  height: 20px;
  padding: 0;
  border-radius: 3px;
  border: 1px solid var(--border);
  font-size: 0.58rem;
  cursor: pointer;
  background: var(--surface);
  color: var(--text3);
}
/* Role colours match the old Scale Lab's: violet root, green
   sub-scale, neutral in-scale — distinguishable without red/green. */
.gs-cell.gs-scale { background: rgba(190,205,220,0.16); color: #cfd8e3; border-color: rgba(190,205,220,0.5); }
.gs-cell.gs-sub { background: rgba(76,175,125,0.24); color: #7fd6a6; border-color: #4caf7d; }
.gs-cell.gs-root { background: rgba(139,124,246,0.3); color: #c3bafb; border-color: var(--rootc); }
.tl2-gsbtn.on { color: #b8d8ff; border-color: rgba(148,196,255,0.5); }

/* ── H5: the Chord guide strip ────────────────────────────────────────────
   docs/PROBABILISTIC_HARMONY_DESIGN.md §13.1. The Harmonic guide's faster
   sibling, and deliberately built on the same skeleton: the two lanes must
   read as one stack (one family, three rates — key, sub-scale, chords).

   Its own namespace, though. `.gs-*` means "global scale"; extending it here
   would make the next person editing a `.gs-` rule change two lanes at once.

   Three laws copied verbatim from the guide, each of which cost a bug there:
     · the lane outline is an INSET box-shadow, never a border — a border
       insets the content by 1px and knocks the lane out of beat alignment;
     · the leading gap comes from the shared `--tl-lead` row rule, never from
       padding of its own;
     · when the lane is inactive the STRIP dims, never the row (opacity on the
       row creates a stacking context that buries the head, styles.css:10763). */
.tl2-chord-row { min-height: 16px; }
.tl2-chord-row:not(.open) .gs-head { min-height: 18px; padding: 0 5px; }
.tl2-chord-row:not(.open) .gs-chevron { font-size: 0.58rem; line-height: 1; }
.chord-chevron { display: flex; align-items: center; gap: 5px; }
/* The glyph's box matches `.saem-icon.compact` (40 × 25) so all three strip
   labels start on the same vertical line — measured at 315px against this
   row's 289.5px before the box existed. */
.chord-headicon {
  width: 40px;
  height: 25px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.chord-chevron .tl2-flag-svg { width: 15px; height: 15px; flex: none; color: var(--text3); }
.chord-chevron.chord-active { color: #f3f5f7; }
.chord-chevron.chord-active .tl2-flag-svg { color: var(--chordc); }
.chord-onpip { color: var(--chordc); font-size: 0.72em; margin-left: 4px; vertical-align: 1px; }

/* Two zones, as the collapsed guide has: a LABEL ROW carrying the placement
   glyph and the chord's name, and the block of tone bands under it. HG-B3
   (owner 2026-08-29) made the expanded lane obey that too — it used to ADD an
   18px glyph band above a 42px lane, which is the separate strip the owner
   asked to be rid of in the guide above. `--chord-band` is now the height of
   the label row INSIDE the lane (CHORD_LABEL_BAND in app.js): the ticks and the
   empty state start below it, and the tone stack is sized to leave it free. */
.chord-thread {
  position: relative;
  height: 30px;
  flex: none;
  --chord-band: 0px;
  /* Two more pixels than the guide's 11px stripe. That stripe stacks its bands
     contiguously, so 11px is plenty; these are POSITIONED by pitch class, and
     at 11px over 12 divisions the 2px minimum band swallows the gaps that carry
     the chord's shape. */
  --chord-stack-h: 13px;
}
.chord-strip {
  position: relative;
  flex: none;
  box-sizing: border-box;
  background: var(--surface2);
  border: 0;
  box-shadow: inset 0 0 0 1px var(--border);
  border-radius: 4px;
  /* 22 in a 42px lane, so the top 18px are the label row the glyph and the
     chord name share (HG-B3). It was 30 while the glyphs had a band of their
     own above the lane; keeping 30 here would put a 15px glyph through the
     stack's top edge, which is the collision that band existed to prevent. */
  --chord-stack-h: 22px;
}
.chord-thread.off,
.chord-strip.off { opacity: 0.45; }

/* One chord, one span. The tones are bands at their PITCH CLASS rather than
   stacked contiguously the way the guide's scale stripe is: a chord's identity
   is which degrees it holds and where the gaps between them fall, so the gaps
   have to be drawn as gaps. */
.chord-span {
  position: absolute;
  /* The span owns the whole lane height, label row included — the name is part
     of the span and hangs above its stack (HG-B3). The stack's own height is
     what leaves the label row clear, in both views. */
  top: 0;
  bottom: 0;
  cursor: pointer;
}
/* A dark WELL with rose bands in it, not a rose block: the first pass gave the
   stack a 9%-rose ground and the lane read as a row of pink boxes with the
   tones barely visible inside them — colour as decoration, which is exactly
   what §1.2's "chrome is monochrome, colour belongs to data" forbids. The
   ground is the house recess token; only the tones carry the hue. */
.chord-stack {
  position: absolute;
  left: 0;
  right: 2px;      /* a hairline of ground between chords, so each is countable */
  bottom: 2px;
  height: var(--chord-stack-h, 11px);
  border-radius: 2px;
  overflow: hidden;
  background: var(--well);
}
.chord-tone {
  position: absolute;
  left: 0;
  right: 0;
  min-height: 2px;
  background: var(--chordc);
  opacity: 0.72;
}
/* The bass is the tone the chord is heard against — the anchor of the
   bass-anchored model (§2.3) — so it reads first. */
.chord-tone-bass { opacity: 1; min-height: 3px; }

/* PREDICTED versus PINNED is drawn in FORM, not in a second colour: the lane
   already sits under one carrying three role hues, and a fourth and fifth here
   would be unreadable at 11px. The encoding mirrors the one the timeline
   already teaches — a generative take is soft-edged, a frozen one is square. */
.chord-span-drawn .chord-stack {
  border-radius: 2px 5px 5px 2px;
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 64%, rgba(0,0,0,0.32) 100%);
  mask-image: linear-gradient(90deg, #000 0%, #000 64%, rgba(0,0,0,0.32) 100%);
}
.chord-span-pinned .chord-stack {
  border-radius: 0;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--chordc) 65%, transparent);
}
/* Selection is a LIFT, not an outline: a placement owns many spans, and
   outlining every one of them (the first attempt) drew a box round the whole
   lane and swallowed the pinned/drawn distinction that the outline encodes. */
.chord-span.sel .chord-stack { background: color-mix(in srgb, var(--chordc) 13%, var(--well)); }
.chord-span.sel .chord-tone { opacity: 0.92; }
.chord-span.sel .chord-tone-bass { opacity: 1; }
.chord-span:hover .chord-stack { background: color-mix(in srgb, var(--chordc) 14%, var(--well)); }

/* The reading, always relative to the key in force (owner law, §3.3): a state
   name, or a bass degree in mono digits. Never an absolute note name. */
.chord-name {
  position: absolute;
  /* Clear of the 15px glyph centred on the span's start, exactly as `.gs-name`
     clears the star: at 7px the first letter is drawn through the dots. */
  left: 16px;
  /* Anchored to the STACK, not to the span's top: the two views have
     different stack heights, and a fixed `top` put the name's descenders
     through the stack's top edge in the taller one (measured: −3px). */
  bottom: calc(var(--chord-stack-h, 11px) + 5px);
  line-height: 1;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.5rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text3);
  white-space: nowrap;
  pointer-events: none;
}
.chord-tick {
  position: absolute;
  top: var(--chord-band, 0px);
  bottom: 0;
  width: 1px;
  background: rgba(154, 160, 171, 0.12);
  pointer-events: none;
}
/* Empty, expanded: the `.hg-empty` idiom — same box, --text3, italic, and an
   imperative that names where a progression comes from. */
.chord-empty {
  position: absolute;
  left: 10px;
  right: 10px;
  top: var(--chord-band, 0px);
  bottom: 0;
  display: flex;
  align-items: center;
  color: var(--text3);
  font-style: italic;
  font-size: 0.6rem;
  pointer-events: none;
}

/* ── Harmony REGIONS (owner 2026-09-21) ───────────────────────────────────
   Design plan (standard §1.8) —
   Colour: `--chordc` only, mixed into `--border` for the frame at rest and
     pure when selected; no new token, and the frame stays a hairline so the
     hue still belongs to the chord tones (§1.2 cue 2).
   Type: nothing new — the region's name and span read through the existing
     mono/tabular `.chord-editor-title` and the glyph's label.
   Layout: one frame per region UNDER its chord spans, so the lane reads as
     objects with gaps between them rather than a continuous ribbon; the edges
     are the take's `.tl2-resize` grip, on both ends, revealed on hover. */
.chord-region {
  position: absolute;
  top: 0;
  bottom: 0;
  box-sizing: border-box;
  border-radius: 3px;
  background: color-mix(in srgb, var(--chordc) 7%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--chordc) 45%, var(--border));
  cursor: grab;
  touch-action: none;
}
.chord-region:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--chordc) 70%, var(--border)); }
.chord-region.sel,
.chord-region.resizing { box-shadow: inset 0 0 0 1px var(--chordc); }
.chord-span { cursor: grab; touch-action: none; }
.chord-edge {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 8px;
  padding: 0;
  border: 0;
  background: none;
  cursor: ew-resize;
  z-index: 4;
  touch-action: none;
}
.chord-edge-l { left: 0; border-left: 2px solid transparent; }
.chord-edge-r { right: 0; border-right: 2px solid transparent; }
.chord-region:hover .chord-edge-l, .chord-region.sel .chord-edge-l { border-left-color: color-mix(in srgb, var(--chordc) 60%, transparent); }
.chord-region:hover .chord-edge-r, .chord-region.sel .chord-edge-r { border-right-color: color-mix(in srgb, var(--chordc) 60%, transparent); }
.chord-edge-l:hover, .chord-edge-l:focus-visible { border-left-color: var(--chordc) !important; }
.chord-edge-r:hover, .chord-edge-r:focus-visible { border-right-color: var(--chordc) !important; }
.chord-edge:focus-visible { outline: 2px solid var(--chordc); outline-offset: -2px; }
@media (pointer: coarse) { .chord-edge { width: 22px; } }
/* Open, this head fell back to `.tl2-head`'s 0.5rem side padding while its two
   neighbours hold 5px — which put "Chord guide" 2.5px right of the labels above
   and below it (measured 315 / 317.5 / 315). Found on the clean branch build. */
.tl2-chord-row.open > .gs-head { padding-left: 5px; padding-right: 5px; }

/* The placement glyph, in a 44px transparent target so it is reachable on a
   coarse pointer without drawing a 44px control — the guide's star pad. */
.chord-handle {
  position: absolute;
  top: 9px;
  width: 44px;
  height: 30px;
  transform: translate(-50%, -50%);
  padding: 0;
  border: 0;
  background: none;
  cursor: ew-resize;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
}
.chord-glyph {
  display: block;
  overflow: visible;
  filter: drop-shadow(0 0 3px rgba(6, 9, 14, 0.9));
  transition: transform 0.12s;
  transform-origin: 50% 50%;
}
.chord-handle:hover > .chord-glyph { transform: scale(1.3); }
.chord-handle.sel > .chord-glyph { transform: scale(1.15); }
.chord-handle.sel::after {
  content: "";
  position: absolute;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  border: 1px solid var(--chordc);
  opacity: 0.7;
}
.chord-handle:focus-visible { outline: 2px solid var(--chordc); outline-offset: -14px; border-radius: 8px; }
@media (prefers-reduced-motion: reduce) {
  .chord-glyph { transition: none; }
}

/* A drop lights BOTH lane classes, so the answer is the same whether the guide
   is open or closed. */
.tl2-chord-row.drop-target .chord-chevron,
.tl2-chord-row.drop-target .chord-thread,
.tl2-chord-row.drop-target .chord-strip { outline: 1px dashed var(--chordc); outline-offset: 2px; }
.tl2-chord-row.drop-reject .chord-chevron,
.tl2-chord-row.drop-reject .chord-thread,
.tl2-chord-row.drop-reject .chord-strip {
  outline: 1px dashed color-mix(in srgb, #e0524d 70%, var(--border));
  outline-offset: 2px;
  cursor: not-allowed;
}

/* ── HG-B3: the floating editor panel (owner 2026-08-29) ──────────────────
   "the chord guide settings, harmonic guide settings and global space settings
    boxes should be floating pop-up boxes that don't displace the other rows,
    and be movable."

   ONE container, three call sites (`floatPanelHTML` in app.js). It is fixed
   rather than absolute for the reason the smart-combo popover is: the strips
   live in a horizontal scroller, and an absolutely-positioned panel inside it
   slides sideways with the arrangement and is clipped by its overflow. Fixed
   also means it takes no room in the flow, which is the whole ask — an editor
   used to be a `.tl2-row` between two lanes, so opening one moved the lanes.

   Elevation is `.sp-designer`'s existing pair, not a third shadow invented for
   this panel (standard §1.3, one elevation system). No transitions: nothing
   here moves except under the pointer, so there is no motion to reduce. */
.fp-panel {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 2400;
  display: flex;
  flex-direction: column;
  gap: 6px;
  box-sizing: border-box;
  max-width: calc(100vw - 16px);
  max-height: calc(100vh - 16px);
  overflow: auto;
  padding: 6px 8px 8px;
  border: 1px solid var(--border2);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 18px 44px -12px rgba(0, 0, 0, 0.72), 0 0 0 1px rgba(0, 0, 0, 0.35);
}
/* Widths are the ones each editor was already clamped to, now stated once
   rather than computed into an inline style at every render. */
#gsFloat { max-width: min(560px, calc(100vw - 16px)); }
#chordFloat { width: min(528px, calc(100vw - 16px)); }
/* The settings panel is a page of controls rather than one line of them, and it
   gave up its own 14/16px padding to the container above — so the container
   gives it back here rather than letting ten sliders touch the hairline. */
#spFloat { width: min(620px, calc(100vw - 16px)); padding: 8px 14px 14px; }
.fp-bar { display: flex; align-items: center; gap: 6px; }
/* The grab zone is its own control, so a drag can never start on a slider or a
   picker inside the editor (standard §2.4). It is a button because it is also
   keyboard-movable — arrow keys nudge the panel while it has focus. */
.fp-grip {
  flex: none;
  width: 22px;
  height: 18px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface2);
  color: var(--text3);
  font-size: 0.7rem;
  line-height: 1;
  cursor: grab;
}
.fp-grip:hover { color: var(--text2); border-color: var(--border2); }
.fp-grip:active,
.fp-panel.fp-dragging .fp-grip { cursor: grabbing; }
.fp-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text3);
  font-size: 0.54rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
}
.fp-close {
  flex: none;
  width: 20px;
  height: 18px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface2);
  color: var(--text2);
  font-size: 0.8rem;
  line-height: 1;
  cursor: pointer;
}
.fp-close:hover { color: var(--text); border-color: var(--border2); }
.fp-grip:focus-visible,
.fp-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* The wrapped editors keep every control they had and give up only their own
   panel chrome — ground, hairline, elevation and placement belong to the
   container now, and having both drew a box inside a box. */
.fp-panel > .gs-editor,
.fp-panel > .chord-editor,
.fp-panel > .sp-designer {
  position: static;
  margin: 0;
  padding: 0;
  width: auto;
  max-width: none;
  background: none;
  border: 0;
  box-shadow: none;
}
/* The space designer brought its own header. The bar above it already names the
   panel and already closes it, so the duplicate eyebrow and the second × go —
   the room name and the blurb, which say something the bar does not, stay. */
.fp-panel .spd-eyebrow,
.fp-panel .spd-close { display: none; }

/* The editor: the guide's `.gs-editor` in two lines rather than one, because
   it carries a picker, a seed pair and two settings and a single row would
   scatter them. It floats over the lane now (HG-B3) rather than sitting in a
   row beneath the placement it belongs to. */
.chord-editor {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 5px 7px;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 4px;
  margin-bottom: 4px;
  flex: 0 0 auto;
  align-self: flex-start;
  box-shadow: var(--elev-1);
}
.chord-editor-line { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.chord-editor-title {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.58rem;
  color: var(--text3);
  white-space: nowrap;
}
.chord-editor .smart-combo { flex: 1 1 150px; min-width: 130px; }
.chord-editor .smart-combo-btn { min-height: 22px; font-size: 0.62rem; }
.chord-editor .btn { padding: 2px 7px; font-size: 0.58rem; }
.chord-select {
  height: 22px;
  padding: 1px 4px;
  background: var(--control-bg);
  color: var(--text);
  border: 1px solid var(--control-border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: 0.6rem;
  cursor: pointer;
}
.chord-select:focus-visible { outline: 2px solid var(--chordc); outline-offset: 1px; }
/* Harmony 2 regions (HARMONY-2.md §9): a plan region's floating panel — its name is editable in place, a sentence says
   what the region plays, the way into the editor; a shared plan says so. */
.chord-plan-name {
  flex: 1 1 150px; min-width: 120px; height: 22px; padding: 1px 6px;
  background: var(--control-bg); color: var(--text); border: 1px solid var(--control-border); border-radius: var(--radius-sm);
  font: inherit; font-size: 0.62rem;
}
.chord-plan-name:focus-visible { outline: 2px solid var(--chordc); outline-offset: 1px; }
.chord-plan-facts { margin: 0; max-width: 34em; font-size: 0.6rem; line-height: 1.4; color: var(--text2); }
.chord-plan-shared, .harmony-editor-shared { font-size: 0.58rem; color: var(--text2); white-space: nowrap; }
/* the progression face in the producer's editor pane: the pane scrolls it; the face keeps its own spacing */
.editor-body-harmony .harmony-editor-face { min-width: 0; }
.editor-body-harmony .fp-harmony2 { padding-top: 0; }
/* the pane's topbar already names what is open, so the face's eyebrow row goes; its sentence stays, a step smaller */
.editor-body-harmony .fp-h2-solo .fh-top { display: none; }
.editor-body-harmony .fp-h2-solo .fh { margin: 0 2px 12px; padding-bottom: 10px; }
.editor-body-harmony .fp-h2-solo .fh-h1 { font-size: 15px; line-height: 1.45; }
@media (pointer: coarse) { .chord-plan-name { height: 44px; } }
.chord-seed-chip {
  padding: 1px 5px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border));
  border-radius: 3px;
  background: rgba(8, 10, 14, 0.55);
  color: var(--accent2);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.58rem;
  white-space: nowrap;
  cursor: help;
}
.chord-ctl { display: flex; align-items: center; gap: 5px; flex: 1 1 150px; min-width: 138px; }
.chord-ctl-select { flex: 0 0 auto; min-width: 0; }
.chord-ctl-label {
  font-size: 0.5rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text3);
  white-space: nowrap;
}
.chord-ctl input[type="range"] { flex: 1 1 auto; min-width: 54px; }
.chord-ctl-out {
  min-width: 30px;
  text-align: right;
  color: var(--chordc);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.58rem;
}
.chord-del { margin-left: auto; }

/* The thread flag's on-state and the inspector's ownership line take the same
   hue, so "this is the chord lane" is one colour wherever it is claimed. */
.tl2-flag-svg .stem { fill: none; stroke: currentColor; stroke-width: 1; opacity: 0.45; }
.tl2-flag-chord.on {
  border-color: color-mix(in srgb, var(--chordc) 55%, var(--border));
  background: color-mix(in srgb, var(--chordc) 14%, transparent);
  color: color-mix(in srgb, var(--chordc) 85%, var(--text));
}
.patch-chord-line {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 5px;
  padding-top: 5px;
  border-top: 1px solid var(--border);
  font-size: 0.6rem;
  color: var(--text2);
}
.patch-chord-line.superseded .patch-chord-what { color: var(--text3); }
.patch-chord-block .superseded-note { color: color-mix(in srgb, var(--chordc) 62%, var(--text3)); }
.patch-chord-line .module-owner-chip {
  border-color: color-mix(in srgb, var(--chordc) 45%, var(--border));
  background: color-mix(in srgb, var(--chordc) 12%, transparent);
  color: color-mix(in srgb, var(--chordc) 80%, var(--text));
}

/* ── Q10: MIDI recording ─────────────────────────────────── */
.tl2-arm { color: var(--text3); }
.tl2-arm.on { color: #ff5d5d; border-color: rgba(255,93,93,0.6); background: rgba(255,93,93,0.12); }
.midi-rec-dot { color: #ff5d5d; font-size: 0.8rem; animation: midiPulse 1.2s ease-in-out infinite; }
@keyframes midiPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* ── Q9: producer remainders ─────────────────────────────── */
.tl2-hue {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: none;
}
.tl2-db { font-size: 0.55rem; color: var(--text3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.tl2-head { position: relative; }
.tl2-band {
  position: fixed;
  z-index: 40;
  display: none;
  background: rgba(245,166,35,0.08);
  border: 1px dashed rgba(245,166,35,0.55);
  pointer-events: none;
}
.roll-add-on { color: var(--accent2); border-color: rgba(245,166,35,0.5); }
.roll-keys { font-size: 0.55rem; color: var(--text3); letter-spacing: 0.08em; margin-left: 0.5rem; }
.shortcut-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(6,8,12,0.6);
}
.shortcut-card {
  background: var(--surface);
  border: 1px solid var(--border2);
  border-radius: 10px;
  padding: 1rem 1.2rem;
  max-width: 560px;
  box-shadow: 0 12px 40px rgba(0,0,0,0.5);
}
.shortcut-close { float: right; font-size: 0.6rem; color: var(--text3); text-transform: none; letter-spacing: 0; }
.shortcut-cols { display: flex; gap: 1.5rem; }
.shortcut-cols dl { display: grid; grid-template-columns: auto 1fr; gap: 0.25rem 0.7rem; margin: 0.6rem 0 0; }
.shortcut-cols dt { font-size: 0.68rem; color: var(--accent2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.shortcut-cols dd { font-size: 0.68rem; color: var(--text2); margin: 0; }
.tour-card p { font-size: 0.78rem; color: var(--text2); line-height: 1.5; margin: 0.6rem 0; }
.tour-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }

/* ── Studio tour: spotlight coach marks (audit P0 — non-blocking) ── */
/* The container ignores pointer events so the app stays usable while the
   tour runs; only the tooltip card is interactive. The dim comes from the
   ring's giant box-shadow, which never captures clicks. */
#studioTour { position: fixed; inset: 0; z-index: 70; pointer-events: none; }
#audTour { position: fixed; inset: 0; z-index: 5300; pointer-events: none; }
#studioTour .tour-ring, #audTour .tour-ring {
  position: fixed;
  border: 2px solid var(--accent);
  border-radius: 10px;
  box-shadow: 0 0 0 200vmax rgba(4, 6, 10, 0.55), 0 0 18px rgba(245, 166, 35, 0.35);
  transition: all 0.25s ease;
}
#studioTour .tour-pop, #audTour .tour-pop {
  position: fixed;
  width: min(330px, calc(100vw - 24px));
  pointer-events: auto;
  background: linear-gradient(180deg, var(--surface2), var(--surface));
  border: 1px solid var(--border2);
  border-radius: 10px;
  padding: 0.8rem 0.9rem;
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.5);
  transition: left 0.25s ease, top 0.25s ease;
}
#studioTour .tour-pop p, #audTour .tour-pop p {
  font-size: 0.78rem;
  color: var(--text2);
  line-height: 1.5;
  margin: 0.5rem 0 0.6rem;
}

/* Basics audit #7 — a control's explanation on keyboard focus. The tour
   card's surface at a smaller size: one bubble, reused, never interactive.
   Above modals, because a control inside a dialog needs its words too. */
.focus-tip {
  position: fixed; z-index: 6000; pointer-events: none;
  max-width: min(300px, calc(100vw - 16px)); padding: 6px 9px;
  background: linear-gradient(180deg, var(--surface2), var(--surface));
  border: 1px solid var(--border2); border-radius: var(--radius-sm);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.5);
  color: var(--text); font-size: 12px; line-height: 1.4;
}
.focus-tip[hidden] { display: none; }

.studio-tour-btn { color: var(--text3); white-space: nowrap; }
.studio-tour-btn:hover { color: var(--accent2); }
.app-topbar .studio-tour-btn .tb-ico { width: 14px; height: 14px; }

/* The inspector is a flex column with overflow-y auto: children must not
   flex-shrink into nothing when content exceeds the panel height (the
   Bow/Pluck/Strike/Blow segment was crushed to 2 px). */
.ch-inspector > * { flex-shrink: 0; }
.ch-inspector .ch-string { max-width: 100%; }

/* Space audit 07-07: the envelope has a proper home in the right column */
.env-side-section .envelope-canvas { max-width: 100%; height: auto; }

/* ── Q7: layered subnote modules ─────────────────────────── */
.layer-strip {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.5rem;
  border-top: 1px solid var(--border);
  margin-top: 0.4rem;
}
.layer-strip-label { font-size: 0.58rem; letter-spacing: 0.08em; color: var(--text3); }
/* ONE cap for the whole layer band, in --layer-band-h. The rows and the
   sync panel derive their own from it, so a rule that shortens the band can
   never leave its children taller than it: they used to hold a hardcoded
   162px while a later rule clamped the band to 18vh, and on any window under
   ~900px tall the extra rows painted straight over the BROWSER strip below. */
.layer-area {
  --layer-band-h: 170px;
  --layer-band-inset: 0.6rem;   /* this element's 0.2rem + 0.4rem padding */
  display: flex; gap: 0.6rem; align-items: flex-start;
  padding: 0.2rem 0.5rem 0.4rem;
  max-height: var(--layer-band-h);
  min-height: 0;
  overflow: hidden;             /* the band never paints outside itself */
}
/* Space audit 07-07: the rows never crowd the editors — they cap with the
   band and scroll (the whole CHORDA area shares one fixed canvas) */
.layer-rows {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  max-height: calc(var(--layer-band-h) - var(--layer-band-inset));
  overflow-y: auto;
  /* FE-38 (owner 2026-08-29): "the scrollbar still gets in the way of the
     effects in the layer view." This scroller used to carry
     `scrollbar-color`, and that one property was the whole bug: it opts the
     element out of the sheet's ::-webkit-scrollbar styling and back to the
     platform bar — on macOS an OVERLAY that reserves nothing and paints over
     the row's right edge (measured: clientWidth === offsetWidth === 415 while
     the list was scrolling), and on Windows a classic bar that instead eats
     10px of the effects row. Styling the thumb the webkit way keeps the amber
     look AND keeps the bar in the layout; `stable` then holds that gutter
     open when the list is too short to scroll, so the effects chips end at
     the same x in both states.

     `auto` rather than simply dropping the declaration: `scrollbar-color` is
     an INHERITED property and `.explore-dashboard .card` sets it four levels
     up, so this scroller was taking the platform bar by inheritance. It has
     to be turned off here, not just left unset. */
  scrollbar-color: auto;
  scrollbar-gutter: stable;
}
.layer-rows::-webkit-scrollbar-thumb { background-color: var(--scroll-thumb); }
.layer-rows::-webkit-scrollbar-track { background: var(--scroll-track); border-radius: 5px; }
/* …but `scrollbar-color` INHERITS, and the effects strip inside each row is
   itself a horizontal scroller (`.layer-fx`, `overflow-x: auto`, 17 px tall).
   Letting it inherit `auto` gave it a classic 10 px bar and grew every row by
   10 px — measured: offsetHeight 27 against clientHeight 17. A strip that
   short has to keep the overlay bar, so it gets the pair back explicitly. */
.layer-rows .layer-fx,
.layer-rows .prod-layer-fx { scrollbar-color: var(--scroll-thumb) var(--scroll-track); }
/* Set by wireLayerRowsFade() only while rows remain below the fold, so the
   partly-shown row reads as "there is more" instead of as clipped text. */
.layer-rows.more-below {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
}
/* In the sub-note bottom pane LAYERS owns a full-height resizable column, so
   the old 170px/18vh band cap (from when the rows sat under the editors) just
   clipped the rows and left dead space below them. The column is the cap. */
.chorda-bottom-left .layer-area {
  max-height: none;
  flex: 1 1 auto;
  min-height: 0;
  padding-bottom: 0.2rem;
  /* stretch, not flex-start: otherwise the rows box takes its CONTENT height
     and gets clipped by this element instead of scrolling inside it */
  align-items: stretch;
}
/* The rows scroll inside whatever height the pane has, so every layer stays
   reachable when the pane is short (owner 2026-08-11). */
.chorda-bottom-left .layer-rows {
  max-height: none;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
.layer-solo.on {
  color: #ffd28a;
  border-color: rgba(245,166,35,0.6);
  background: rgba(245,166,35,0.15);
}
.layer-edit-tag { color: var(--accent2); text-transform: none; letter-spacing: 0; }
/* FE-13 (owner 2026-08-28): ".layer-meter" is gone. "There are multiple fader
   displays in the layer pane of subnote" — the row carried Vol as a metered
   fader AND this bar on the line beneath it, both painted from the SAME
   layerSignalLevels() read (app.js: wireFaderMeters vs updateLayerMeters),
   so it was one number shown twice with neither authoritative. The fader's
   own meter wins, because it is attached to the control it describes. */

/* Per-layer octave placement: a compact −2…+2 select beside Vol. */
.layer-oct select {
  background: var(--display);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 0.68rem;
  padding: 1px 2px;
}
.layer-oct select:hover { border-color: var(--border2); }

.layer-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* NEVER shrink: as a flex child of a height-capped column the row was
     squeezed to 52px while its content needed ~62px, so the envelope line
     painted over the row beneath it (owner 2026-08-11). */
  flex: none;
  min-height: 52px;
  padding: 0.25rem 0.5rem;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-left: 3px solid hsl(var(--layer-hue), var(--layer-sat, 70%), 55%);
  border-radius: 6px;
  cursor: pointer;
}
.layer-row.sel {
  border-color: hsla(var(--layer-hue), var(--layer-sat, 70%), 55%, 0.7);
  box-shadow: 0 0 8px hsla(var(--layer-hue), var(--layer-sat, 70%), 55%, 0.25);
}
.layer-row-tag {
  width: 18px;
  text-align: center;
  font-size: 0.7rem;
  color: hsl(var(--layer-hue), var(--layer-sat, 70%), 68%);
  font-weight: 700;
}
.layer-minipad { width: 40px; height: 40px; flex: none; border-radius: 50%; }
.layer-row-lines { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; }
/* Narrow-column row layout (owner 2026-08-11): buttons live in the name row,
   Vol + oct share the controls line, the meter is a slim full-width bar
   underneath — nothing wraps into overlap in the 280–400px LAYERS column. */
.layer-row-space { display: flex; align-items: center; gap: 0.45rem; flex-wrap: wrap; min-width: 0; }
.layer-row .sp-ctl { min-width: 0; }
/* FE-13: the Vol fader keeps a real travel and `oct` wraps below it when the
   LAYERS column is too narrow for both — the label drops, not the fader. */
.layer-row-space > .sp-ctl { flex: 1 1 auto; }
.layer-row-space > .layer-oct { flex: 0 0 auto; }
.layer-row .sp-ctl input[type=range] { width: 100%; min-width: var(--fader-min-travel); }
.layer-row input[type="range"].fader { --fader-h: var(--layer-hue, 210); }
.layer-row-btns { display: flex; align-items: center; gap: 4px; flex: none; }
.layer-row-btns .pal-btn { padding: 0.1rem 0.36rem; line-height: 1.25; }
.layer-env {
  font-size: 0.6rem;
  color: var(--text3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.layer-ownhead { white-space: nowrap; }
/* Per-layer EFFECTS tags on the layer row (docs/EFFECTS_CONTRACT.md) */
.layer-fx { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 1px; }
.layer-fx.off { opacity: 0.5; }
.layer-fx-tag {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--surface2); border: 1px solid var(--border);
  border-left: 2px solid var(--eff); border-radius: 4px; padding: 1px 4px 1px 5px;
}
.layer-fx-tag.off { border-left-color: var(--text3); opacity: 0.55; }
.layer-fx-name {
  background: none; border: none; cursor: pointer; padding: 0;
  font-size: 0.6rem; color: var(--text2); white-space: nowrap;
}
.layer-fx-tag:not(.off) .layer-fx-name { color: var(--text); }
.layer-fx-wet { width: 34px; height: 10px; }
/* Editable layer titles (double-click to rename) */
.layer-name-row { display: flex; align-items: center; gap: 5px; margin-bottom: 1px; min-width: 0; }
.layer-name {
  font-size: 0.72rem; font-weight: 600; color: var(--text);
  cursor: text; border-radius: 3px; padding: 0 2px;
  flex: 1 1 auto; min-width: 0;   /* yield to the buttons instead of pushing them out */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.layer-name:hover { background: var(--surface2); box-shadow: inset 0 0 0 1px var(--border); }
.layer-name-edit {
  font-size: 0.72rem; font-weight: 600; color: var(--text);
  background: var(--bg); border: 1px solid var(--accent); border-radius: 3px;
  padding: 0 3px; width: 140px; font-family: inherit;
}
/* the synchronised-variation panel sits to the RIGHT of the rows — and
   scrolls internally rather than squeezing the editors above (the whole
   layer band is height-capped) */
.layer-sync {
  flex: none;
  width: 230px;
  min-height: 0;
  max-height: calc(var(--layer-band-h) - var(--layer-band-inset));
  overflow-y: auto;
  padding: 0.4rem 0.55rem;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  scrollbar-color: rgba(245,166,35,0.42) rgba(10,14,20,0.55);
}
.layer-sync .layer-env-sync { margin-left: 0; }
.layer-sync-body.off { opacity: 0.35; pointer-events: none; }
.layer-add {
  width: 26px;
  height: 20px;
  border-radius: 4px;
  border: 1px dashed var(--border2);
  background: none;
  color: var(--text3);
  cursor: pointer;
}
.layer-add:hover { color: var(--accent2); border-color: rgba(245,166,35,0.5); }
.layer-env-sync {
  margin-left: auto;
  font-size: 0.6rem;
  color: var(--text3);
  display: flex;
  align-items: center;
  gap: 0.3rem;
  cursor: pointer;
}
.layer-strip { flex-wrap: wrap; }

/* Owner 07-07: the scale is a circle — one octave per turn, degree 0 at
   12 o'clock; tuned nodes slide around the ring by their cents. */
.note-circle {
  position: relative;
  margin: 0.4rem auto;
}
.note-circle-ring {
  position: absolute;
  border: 1px solid rgba(90,110,130,0.3);
  border-radius: 50%;
  pointer-events: none;
}
.note-circle .note-cell {
  position: absolute;
  transform: translate(-50%, -50%);
  width: var(--note-node-size, 28px);
  height: var(--note-node-size, 28px);
  border-radius: 50%;
  font-size: var(--note-node-font, 0.58rem);
  flex-direction: column;
  line-height: 1;
  gap: 1px;
}
.note-circle .note-cell.tuned { border-style: dashed; }
.note-cents {
  font-size: 0.48rem;
  color: var(--accent2);
  font-variant-numeric: tabular-nums;
}
.oct-btns { display: inline-flex; gap: 0.25rem; flex: none; }

/* Owner 07-07: the strips are their own panel — pinned above the
   timeline (vertical scrolling never moves them), horizontally mirrored
   to the timeline's scrollLeft by wireStripsPanel. */
.strips-panel {
  flex: none;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
  padding-bottom: 2px;
}
.strips-tl2 { padding-bottom: 0; }
/* Holds the strips' scroll range equal to the timeline's — see wireStripsPanel. */
.strips-scroll-spacer { height: 0; pointer-events: none; }

/* ── Q6: global space designer ───────────────────────────── */
.tl2-sp-row { min-height: 20px; }
/* Owner 07-07 layout: cross-section + params live in the track-parameter
   column (left, sticky); the cylinder fills the lane column beat-aligned */
/* Width comes from .tl2-head and must NOT be restated here — this column is
   what pushes the cylinder into beat alignment with the lanes, so a private
   copy of the number silently drifts the whole global-space strip off the
   timeline the moment the head width changes (owner 2026-08-21: it was still
   190px against the head's 200px, and the cylinder sat 10px left of the lanes). */
.sp-left {
  flex-direction: column;
  align-items: stretch;
  gap: 0.3rem;
  overflow: visible;
}
.sp-params { display: flex; flex-direction: column; gap: 0.25rem; }
.sp-cyl-wrap { position: relative; }
#spSection, #spCylinder {
  background: var(--surface);
  /* Inset outline, not a border: a border would shift the cylinder 1px right
     of the lanes it is supposed to be beat-aligned with. */
  border: 0;
  box-shadow: inset 0 0 0 1px var(--border);
  border-radius: 4px;
  cursor: crosshair;
}
/* Fixed CSS sizes are LOAD-BEARING: these canvases redraw per animation
   frame — without a CSS size matching the attribute size, backing-store
   resizing feeds back into clientWidth and the canvas doubles forever
   (the "global space is completely broken" bug: it reached 634,882 px
   wide). Both now draw with plain contexts at their attribute size; the
   cylinder's width is set inline per render (beat-aligned to the lanes). */
#spSection { width: 170px; height: 150px; flex: none; }
#spCylinder { cursor: ns-resize; }
.sp-head-panel { display: flex; flex-direction: column; gap: 0.3rem; min-width: 170px; }
.sp-ctl {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
  font-size: 0.62rem;
  color: var(--text3);
}
.sp-ctl select, .sp-ctl input[type=range]:not(.fader) { max-width: 110px; }
.sp-ctl select {
  background: var(--surface);
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 0.62rem;
  padding: 0.1rem 0.25rem;
}

/* ── Q3: baked-note performance drill-down (roll drawer) ─── */
.roll-perf {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1rem;
  margin-top: 0.3rem;
  padding-top: 0.3rem;
  border-top: 1px solid var(--border);
}
.roll-perf-row { display: inline-flex; gap: 0.35rem; align-items: baseline; }
.roll-perf-key {
  font-size: 0.58rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text3);
}
.roll-perf-val { font-size: 0.68rem; color: var(--text2); font-variant-numeric: tabular-nums; }
.roll-perf-missing { font-size: 0.66rem; color: var(--text3); font-style: italic; margin-top: 0.3rem; }

/* ── Producer v2 P3: beat-based timeline ─────────────────── */

.tl2 { overflow-x: auto; padding-bottom: 4px; }

.tl2-row { display: flex; align-items: stretch; margin-bottom: 4px; }

/* Looks only — position, width and the gutter band live in one place at the
   foot of this file (`.tl2-row > .tl2-head`). Do not restate them here. */
.tl2-head {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.5rem;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 6px;
  margin-right: 6px;
  font-size: 0.72rem;
  overflow: hidden; /* owner 07-07: controls must never spill onto the lanes */
}
/* two-row track head: identity on top, mix controls underneath */
.tl2-track-head { flex-direction: column; align-items: stretch; justify-content: center; gap: 0.15rem; }
.tl2-track-head.sp-sel { border-color: rgba(56,189,248,0.55); }
.tl2-head-top { display: flex; align-items: center; gap: 0.3rem; min-width: 0; }
.tl2-head-ctl { display: flex; align-items: center; gap: 0.25rem; min-width: 0; flex-wrap: wrap; }
/* FE-13: 24px of travel between an arm button and a space dot is not a level
   control. The fader takes the head's own line; the buttons above it wrap. */
.tl2-head-ctl .tl-gain { flex: 1 1 100%; min-width: 0; order: 9; }
.tl2-name { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
.tl2-corner { border: none; overflow: visible; }

/* ── One horizontal ruler for every timeline row (owner 2026-08-21) ───────
   Every cell in a row keeps the width it was given. The lanes, the ruler and
   the harmonic-guide / global-space strips are all beat-aligned to the same
   pixels-per-beat, so a flex-shrink on any one of them silently rescales that
   one against the others: the strips were shrinking to the VISIBLE width while
   the lanes kept the whole arrangement's width, so nothing lined up
   horizontally and the strips had no overflow left to scroll — which made the
   scrollLeft mirror in wireStripsPanel a no-op.
   The heads are sticky ABOVE the lanes, so they must OCCLUDE them: at 0.96
   alpha the regions scrolling underneath ghosted through, and the 6px gutter
   between a head and its lane let them through completely. A solid box-shadow
   paints that gutter — unlike a pseudo-element it is not clipped by the head's
   own overflow:hidden. */
.tl2-row > * { flex: none; }
/* A row must be as wide as the arrangement, not as wide as the window. As a
   block-level flex container it took the scroller's width and let its cells
   overflow — and `position: sticky` clamps to its containing block, so the
   head could only stay pinned for (rowWidth − headWidth) of scroll and then
   slid away off the left edge. On a wide window the scroll range never
   reached that limit, which is why this looked fine here and broken on a
   narrower one; the narrower the window, the sooner the whole head column
   came unstuck (owner 2026-08-21). */
.tl2-row { min-width: max-content; }
/* The "＋8 bars" button hangs past the end of the lanes on the ruler, and an
   absolutely positioned child extends the SCROLL extent without widening any
   row. That last stretch of travel is past every row's right edge, where
   sticky has nothing left to hold onto — so the column came unstuck for the
   final scroll. A trailing margin puts the overhang inside the row's own
   width; it does not touch the ruler's rendered width or its bar grid. */
.tl2-ruler { margin-right: 120px; }
.tl2-corner { background: var(--lane-backdrop, #171b23); }
/* The strips have NO scrollbar of their own — the timeline is the one place
   the arrangement scrolls, and the strips mirror it. This rule used to sit
   before `.tl2 { overflow-x: auto }` at equal specificity and lost, so the
   strips came with a second scrollbar you could drag out of beat with the
   lanes below (owner 2026-08-21). */
.tl2.strips-tl2 { overflow: hidden; }
.tl2-addbars {
  position: absolute;
  top: -1px;
  height: 22px;
  padding: 0 0.6rem;
  white-space: nowrap;
  background: var(--surface2);
  color: var(--text3);
  border: 1px dashed var(--border2);
  border-radius: 5px;
  font-size: 0.62rem;
  cursor: pointer;
}
.tl2-addbars:hover { color: var(--accent2); border-color: rgba(245,166,35,0.5); }
.tl2-ph-handle {
  position: absolute;
  top: 0;
  width: 11px;
  height: 100%;
  margin-left: -5px;
  cursor: ew-resize;
  z-index: 4;
}
.tl2-ph-handle::after {
  content: "";
  position: absolute;
  left: 2px;
  top: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 7px solid var(--surp);
}

.tl2-ruler {
  position: relative;
  height: 22px;
  flex: none;
  background:
    repeating-linear-gradient(to right,
      rgba(154,160,171,0.18) 0, rgba(154,160,171,0.18) 1px,
      transparent 1px, transparent 56px),
    repeating-linear-gradient(to right,
      rgba(154,160,171,0.07) 0, rgba(154,160,171,0.07) 1px,
      transparent 1px, transparent 14px),
    var(--display);
  border: 1px solid var(--border);
  border-radius: 5px;
}
.tl2-bar {
  position: absolute;
  top: 2px;
  font-family: var(--mono);
  font-size: 0.6rem;
  color: var(--text3);
  padding-left: 3px;
}
.tl2-playhead {
  position: absolute;
  top: 0;
  bottom: -600px;
  width: 1.5px;
  background: var(--surp);
  box-shadow: 0 0 6px rgba(56,189,248,0.6);
  z-index: 2;
  pointer-events: none;
}

.tl2-lane {
  position: relative;
  flex: none;
  /* Fill the row height (set by the taller two-row head) so there's no dead
     gap below each lane, and give regions a generous floor (owner 2026-07-09). */
  align-self: stretch;
  min-height: 60px;
  background:
    repeating-linear-gradient(to right,
      rgba(154,160,171,0.12) 0, rgba(154,160,171,0.12) 1px,
      transparent 1px, transparent 56px),
    repeating-linear-gradient(to right,
      rgba(154,160,171,0.045) 0, rgba(154,160,171,0.045) 1px,
      transparent 1px, transparent 14px),
    var(--display);
  border: 1px solid var(--border);
  border-radius: 5px;
}
.tl2-lane.drop-target { border-color: var(--accent); }

.tl2-region {
  position: absolute;
  top: 3px;
  bottom: 3px;
  background: linear-gradient(180deg, rgba(245,166,35,0.28), rgba(245,166,35,0.16));
  border: 1px solid rgba(245,166,35,0.6);
  border-radius: 4px;
  cursor: grab;
  display: flex;
  align-items: center;
  overflow: hidden;
}
.tl2-region.baked {
  background: linear-gradient(180deg, rgba(56,189,248,0.22), rgba(56,189,248,0.12));
  border-color: rgba(56,189,248,0.55);
}
.tl2-region.selected { box-shadow: 0 0 0 1.5px rgba(232,234,238,0.7); }
.tl2-region-label {
  font-size: 0.62rem;
  color: var(--text);
  padding: 0 0.35rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
.tl2-resize {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 7px;
  cursor: ew-resize;
  border-right: 2px solid rgba(232,234,238,0.35);
}
.tl2-resize:hover { border-right-color: rgba(232,234,238,0.8); }

.tl2-newtrack {
  flex: none;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 0 0.8rem;
  color: var(--text3);
  font-size: 0.72rem;
  border: 1px dashed var(--border2);
  border-radius: 5px;
}
.tl2-newtrack.drop-target { border-color: var(--accent); color: var(--text2); }
.tl2-gs-row.drop-target .gs-chevron,
.tl2-gs-row.drop-target .gs-strip { outline: 1px dashed var(--accent); outline-offset: 2px; }

/* FE-13: sizing only — the look is `.fader` at the top of this sheet. */
.tl2-head .tl-gain { width: auto; flex: 1 1 100%; }

/* ── Palette edit banner (producer v2 P6) ────────────────── */

.palette-edit-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  flex-wrap: wrap;
  border-color: rgba(245,166,35,0.5);
  background: linear-gradient(180deg, rgba(245,166,35,0.08), var(--surface));
  font-size: 0.82rem;
  color: var(--text2);
}
.palette-edit-banner strong { color: var(--accent2); }
.peb-actions { display: flex; gap: 0.45rem; flex-wrap: wrap; }

/* ── Pointer drag ghost (v2.1 U0) ────────────────────────── */

.drag-ghost {
  position: fixed;
  z-index: 100;
  pointer-events: none;
  background: var(--surface2);
  color: var(--text);
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 0.25rem 0.6rem;
  font-size: 0.72rem;
  box-shadow: 0 6px 18px rgba(0,0,0,0.5);
  opacity: 0.92;
}
body.dragging { cursor: grabbing; user-select: none; }

/* ── Track mute/solo (v2.1 U2) ───────────────────────────── */

.tl2-ms {
  flex: none;
  width: 18px;
  height: 18px;
  padding: 0;
  font-size: 0.6rem;
  font-weight: 700;
  background: var(--surface);
  color: var(--text3);
  border: 1px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
}
.tl2-ms.on { background: rgba(245,166,35,0.25); color: var(--accent2); border-color: rgba(245,166,35,0.6); }
.tl2-ms.tl2-solo.on { background: rgba(56,189,248,0.22); color: var(--surp); border-color: rgba(56,189,248,0.55); }
.tl2-head.inaudible .tl2-name { opacity: 0.4; }

/* ── Zoom/snap controls + rename (v2.1 U5-U7) ───────────── */

.daw-ctx-select {
  background: var(--surface2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.16rem 0.3rem;
  font-size: 0.7rem;
}

.tl2-rename {
  flex: 1;
  min-width: 0;
  background: var(--display);
  color: var(--text);
  border: 1px solid var(--accent);
  border-radius: 4px;
  font-size: 0.72rem;
  padding: 0.1rem 0.3rem;
}

/* ── Loop ticks + spatial target (v2.1 U9, U10) ─────────── */

.tl2-looptick {
  position: absolute;
  top: 2px;
  bottom: 2px;
  width: 1px;
  background: rgba(232,234,238,0.3);
  pointer-events: none;
}
/* Generative-region motif boundaries: a light dashed vertical line per motif
   length (owner 2026-07-09 — restored). */
.tl2-motiftick {
  position: absolute;
  top: 3px;
  bottom: 3px;
  width: 0;
  border-left: 1px dashed rgba(232,234,238,0.28);
  pointer-events: none;
  z-index: 1;
}

/* Compact spatial target that replaces the old L/R pan slider. */
.tl2-head .tl-space-dot {
  width: 26px; height: 26px; flex: none;
  border-radius: 50%;
  background: rgba(10,14,20,0.5);
  border: 1px solid rgba(58,66,80,0.65);
  cursor: grab;
  touch-action: none;
}
.tl2-head .tl-space-dot:hover { border-color: rgba(90,104,124,0.9); }
.tl2-head .tl-space-dot:active { cursor: grabbing; }

/* One compact spatial target everywhere a source can be placed. The dot is
   angle + physical distance together; the text is a readout, not a second
   control. */
.space-target-control {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  color: var(--text3);
  font: 0.56rem/1.15 ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.compact-space-target {
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border-radius: 50%;
  border: 1px solid rgba(58,66,80,0.65);
  background: rgba(10,14,20,0.5);
  cursor: grab;
  touch-action: none;
}
.compact-space-target:hover { border-color: rgba(104,124,148,0.95); }
.compact-space-target:active { cursor: grabbing; }
.patch-space-target { margin-right: 2px; }
.layer-space-target { flex: 0 0 auto; }
.layer-space-target > span { display: none; }

/* ── Region gain (v2.1 U12) ──────────────────────────────── */

.region-gain-label {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.7rem;
  color: var(--text2);
}
.region-gain-label input[type="range"] { width: 70px; }

/* Producer v3 transport (block A) */
.daw-pos {
  font-size: 0.72rem;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  background: var(--display);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 2px 8px;
  min-width: 44px;
  text-align: center;
  cursor: pointer;
}
.daw-saved { font-size: 0.58rem; color: #58d6a9; min-width: 32px; }
#arrLoop.loop-on { color: #5fd4c8; border-color: #2c5b56; background: rgba(95,212,200,0.08); }

/* ── Record + metronome ──────────────────────────────────────────────────
   The record button is a transport verb and looks like one: at rest it is the
   same neutral round as ⏹ and ⟳, and it only wears --recc once it is doing
   something. An always-red record button is a button that has stopped saying
   anything. */
.transport-rec { position: relative; }
.transport-rec:hover { color: var(--recc); border-color: var(--recc-dim); }
.transport-rec.rec-on {
  color: var(--recc);
  border-color: var(--recc);
  background: rgba(255,59,71,0.12);
  animation: rec-pulse 1.9s ease-in-out infinite;
}
/* Counting in: lit but not yet capturing, so it holds still and shows how
   many beats are left rather than pretending to be armed. */
.transport-rec.rec-count { color: var(--accent); border-color: var(--accent); }
.rec-count-badge {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 0.62rem;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--bg);
  pointer-events: none;
}
.transport-rec.rec-count .rec-count-badge { background: var(--accent); border-radius: 50%; }
.transport-rec:not(.rec-count) .rec-count-badge { display: none; }
/* Light playback (live-budget.js): a state pip on Play, not a control —
   overlaid like the count badge above, so it never takes toolbar width. Amber
   is the accent's state colour; the ring in the bar's ground separates it from
   Play's own green ring. Present only while live playback is thinning. */
.transport-play { position: relative; }
.transport-light {
  position: absolute; top: 0; right: 0;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 2px var(--bg);
  pointer-events: none;
}
.transport-light[hidden] { display: none; }
@keyframes rec-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,59,71,0.42); }
  50%      { box-shadow: 0 0 0 4px rgba(255,59,71,0); }
}
@media (prefers-reduced-motion: reduce) {
  .transport-rec.rec-on { animation: none; box-shadow: 0 0 0 2px rgba(255,59,71,0.42); }
}
#arrMetro.metro-on {
  color: var(--metroc);
  border-color: #3b525e;
  background: rgba(143,191,216,0.09);
}

/* ── Stacked takes ───────────────────────────────────────────────────────
   A thread holding overlapping takes grows a row per stack index. The
   disclosure sits before the thread name, carrying the count, so a collapsed
   stack still says how much is under it — a fold that hides its own size is
   how you forget a take exists. */
.tl2-stack-toggle {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex: none;
  padding: 0 4px;
  height: 15px;
  font-size: 0.58rem;
  line-height: 1;
  color: var(--text2);
  background: rgba(154,160,171,0.10);
  border: 1px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
}
.tl2-stack-toggle:hover { color: var(--text); border-color: hsl(var(--track-h, 210) 60% 50%); }
.tl2-stack-toggle.open { color: hsl(var(--track-h, 210) 70% 66%); border-color: hsl(var(--track-h, 210) 55% 42%); }
.tl2-stack-n { font-variant-numeric: tabular-nums; font-weight: 600; }
/* ONE ROW'S PITCH, declared once. `.tl2-lane`'s own `min-height` is what
   actually sets an unstacked lane's height (the later `height: 38px/32px`
   rules never win), so the stack must be built from the same number or an
   expanded thread would use a different row height from a collapsed one. */
.tl2-lane { --stack-row-h: 60px; }
/* Both selectors, and that is not belt-and-braces: `.timeline-grid .tl2-lane`
   further down sets a height at the SAME specificity as `.tl2-lane.stacked`
   and wins on source order, which left an expanded stack clamped to one row
   with its takes overflowing. */
.tl2-lane.stacked,
.timeline-grid .tl2-lane.stacked {
  height: calc(var(--stack-row-h) * var(--stack-rows, 1));
  /* Expanded, the row bands are drawn so a take's row is readable at a glance
     rather than inferred from where it happens to sit. */
  background-image:
    repeating-linear-gradient(to bottom,
      rgba(154,160,171,0.13) 0, rgba(154,160,171,0.13) 1px,
      transparent 1px, transparent var(--stack-row-h)),
    repeating-linear-gradient(to right, rgba(154,160,171,0.16) 0, rgba(154,160,171,0.16) 1px, transparent 1px, transparent 56px),
    repeating-linear-gradient(to right, rgba(154,160,171,0.055) 0, rgba(154,160,171,0.055) 1px, transparent 1px, transparent 14px);
}
.tl2-lane.stacked .tl2-region {
  top: calc(var(--stack-row-h) * var(--stack-row, 0) + 5px);
  bottom: auto;
  height: calc(var(--stack-row-h) - 10px);
}

/* THE HEAD STAYS WITH THE TOP ROW (owner 2026-08-30) so a stack reads as
   unfolding DOWNWARDS from the thread, rather than as the thread itself
   growing. Without this the head stretches — `.tl2-row` is a stretch flex —
   and three stacked takes gave a 144px header with its controls marooned at
   the top of an empty box. */
.tl2-row.has-stack > .tl2-head { align-self: flex-start; }
.zoom-slider { width: 74px; height: 12px; }
.tl2-loop-range {
  position: absolute;
  top: 0;
  height: 42%;
  background: rgba(95,212,200,0.18);
  border: 1px solid rgba(95,212,200,0.55);
  border-radius: 3px;
  pointer-events: none;
}
.tl2-loop-range.dim { opacity: 0.35; }

/* Producer v3 block B */
.tl2-region.muted { opacity: 0.35; }
.tl2-seed {
  position: absolute;
  right: 14px;
  top: 2px;
  font-size: 0.54rem;
  color: rgba(148,196,255,0.75);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.tl2-gain-tag {
  position: absolute;
  left: 3px;
  bottom: 2px;
  font-size: 0.56rem;
  color: #ffe3b0;
  background: rgba(10,13,17,0.75);
  border: 1px solid rgba(245,166,35,0.4);
  border-radius: 3px;
  padding: 0 4px;
  cursor: ns-resize;
  font-variant-numeric: tabular-nums;
}

.ch-head-mid { display: flex; gap: 10px; align-items: center; flex: 1; justify-content: center; min-width: 0; }
.ch-head-mid .param-select { max-width: 150px; }
.ch-mix { display: flex; gap: 5px; align-items: center; font-size: 0.6rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text3); }
.ch-mix input { width: 70px; height: 12px; }
.ch-mix output { font-size: 0.62rem; color: var(--text2); }

/* CH-B1 articulated body block inside the inspector */
.ch-artic { display: flex; flex-direction: column; gap: 6px; }
.ch-artic .formant-weight-circle, .ch-artic .vowel-pad { max-width: 100%; }
.ch-artic .controls-grid { gap: 0.2rem; }

/* drop preview + roll head */
.tl2-drop-preview {
  position: fixed;
  z-index: 40;
  display: none;
  pointer-events: none;
  background: rgba(95,212,200,0.14);
  border: 1.5px dashed rgba(95,212,200,0.8);
  border-radius: 4px;
}
.roll-head { display: flex; justify-content: space-between; align-items: center; padding: 2px 4px; }
.roll-meta { font-size: 0.64rem; color: var(--text3); font-variant-numeric: tabular-nums; }
.roll-meta b { color: var(--text2); font-weight: 600; }
.roll-dyncheck { font-size: 0.62rem; color: var(--text3); display: flex; gap: 4px; align-items: center; text-transform: uppercase; letter-spacing: 0.08em; }

.roll-panel.dyn canvas { height: 300px; }

/* BODY bands: chip strip + per-band EQ editor (preset-then-editable) */
.body-band-strip { display: flex; flex-wrap: wrap; gap: 4px; margin: 8px 0 2px; }
.body-band-strip .band-chip { font-size: 10.5px; letter-spacing: 0.02em; }
.body-band-strip .band-chip.artic { border-color: rgba(236, 142, 200, 0.45); color: rgba(236, 168, 210, 0.9); }
.body-band-strip .band-chip.artic.active { background: rgba(236, 142, 200, 0.18); }
.body-band-strip .band-chip.active { border-color: rgba(255, 214, 140, 0.7); color: rgba(255, 222, 160, 0.95); }
.body-band-strip .band-reset { opacity: 0.75; }
.body-band-edit { display: flex; align-items: center; gap: 8px; margin: 4px 0 6px; }
.body-band-edit .body-band-name { font-size: 10.5px; color: var(--ch-dim, #8b9aa8); white-space: nowrap; }
.body-band-edit input[type=range] { flex: 1; min-width: 80px; }
.body-band-edit .body-band-out { font-size: 11px; font-variant-numeric: tabular-nums; color: rgba(255, 214, 140, 0.9); min-width: 44px; text-align: right; }

/* Melody pattern segmented control (walk / arp) */
.pattern-row { display: flex; gap: 4px; margin: 2px 0 8px; }
.pattern-row .seg-btn { flex: 1; }

.arp-surprise-note { font-size: 11.5px; color: var(--ch-dim, #8b9aa8); line-height: 1.5; padding: 4px 2px 6px; }

/* CH-B2: EXCITOR performance drawer + liftable envelope/vibrato blocks */
.ch-perf { margin: 8px 0 2px; border: 1px solid rgba(140, 160, 180, 0.14); border-radius: 8px; padding: 2px 8px 8px; }
.ch-perf summary { cursor: pointer; font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--ch-dim, #8b9aa8); padding: 6px 0; }
.ch-perf .perf-envelope-block, .ch-perf .perf-vibrato-block { margin-top: 6px; }
.ch-perf .envelope-canvas.adsr-edit { cursor: grab; width: 100%; }
.ch-perf .envelope-canvas.adsr-edit:active { cursor: grabbing; }
.ch-perf .vibrato-canvas { width: 100%; }

/* P2: family starter tags + filter chips */
.family-tag { font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.06em; padding: 1px 6px; border-radius: 8px; border: 1px solid rgba(245, 158, 11, 0.35); color: rgba(245, 190, 100, 0.9); white-space: nowrap; }

/* P3: note-connection control */
.connection-row { display: flex; align-items: center; gap: 6px; margin: 8px 0 4px; }
.connection-row .connection-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ch-dim, #8b9aa8); margin-right: 2px; }
.connection-row .seg-btn { flex: 0 0 auto; }

/* ── Room designer + ear models (owner 07-07 round 3) ─────────── */
.ear-model-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}
.ear-model-row select {
  flex: 1;
  min-width: 0;
  background: rgba(16, 20, 26, 0.9);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 5px;
  font-size: 11px;
  padding: 3px 6px;
}
.room-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(52px, 1fr));
  gap: 5px;
}
.room-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 4px 2px 3px;
  background: rgba(16, 20, 26, 0.7);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  color: var(--text-dim);
}
.room-tile:hover { border-color: rgba(148, 196, 255, 0.5); color: var(--text); }
.room-tile.sel {
  border-color: #58d6a9;
  box-shadow: 0 0 6px rgba(88, 214, 169, 0.35);
  color: var(--text);
}
.room-tile canvas { display: block; }
.room-tile span {
  font-size: 8px;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  max-width: 100%;
}
/* The room designer's old flex rule lived here. It is GONE rather than
   overridden (owner 2026-08-27): `.sp-designer-ctls` and `.room-tiles` are no
   longer emitted at all, and the leftovers it kept feeding the new rule cost
   two debugging rounds — `align-items: flex-start` shrink-wrapped the section
   grid to one column, then `flex-wrap: wrap` blew the drawer's height out.
   Equal specificity only overrides the properties you actually restate, so a
   half-dead rule on a live selector is a trap. The live rule is the single
   block further down, next to the head-column panel it has to clear. */
.sp-room-btn {
  background: rgba(16, 20, 26, 0.8);
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text);
  font-size: 10px;
  padding: 3px 7px;
  cursor: pointer;
  text-align: left;
}
.sp-room-btn:hover { border-color: rgba(88, 214, 169, 0.6); }
.sp-room-blurb { color: var(--text-dim); font-style: italic; white-space: normal !important; }

/* ════════════════════════════════════════════════════════════════
   V2 REDESIGN — 2026-07-08 (audit/ui-audit-2026-07-08 + owner renders)
   Tone Designer · Spatial Stage · Scale Lab · Macro Explorer
   Stage hues: --exc (amber) --res (blue) --bodyc (violet) --spc (green)
   ════════════════════════════════════════════════════════════════ */

/* ── Stage rail v2: big waveform cards with power + subtitle ── */
.ch-rail { gap: 10px; }
.ch-sep { color: #46536a; font-size: 1rem; }
.ch-card {
  border-radius: 12px;
  padding: 8px 11px 7px;
  gap: 5px;
  border: 1px solid var(--border);
  background: linear-gradient(180deg, rgba(20,24,31,0.9), rgba(13,16,21,0.95));
  transition: border-color 0.15s, box-shadow 0.15s;
  position: relative;
}
.ch-card-head { align-items: center; }
.ch-card-n {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: none;
}
.ch-excitor   .ch-card-n { color: #efc188; }
.ch-resonator .ch-card-n { color: #9ec9f8; }
.ch-body      .ch-card-n { color: #c3aef5; }
.ch-space     .ch-card-n { color: #9ad9b4; }
.ch-thumb { height: 56px; border-radius: 7px; }
.ch-card-sum { font-size: 0.62rem; color: var(--text2); }
.ch-card .ch-headline {
  font-size: 0.68rem;
  color: var(--text2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ch-excitor          { border-color: #4a3517; }
.ch-resonator        { border-color: #223f63; }
.ch-body             { border-color: #3f2d58; }
.ch-effects          { border-color: #542740; }
.ch-space            { border-color: #224d3e; }
.ch-excitor.active   { border-color: var(--exc);   box-shadow: 0 0 0 1px var(--exc),   0 0 22px -4px var(--exc); }
.ch-resonator.active { border-color: var(--res);   box-shadow: 0 0 0 1px var(--res),   0 0 22px -4px var(--res); }
.ch-body.active      { border-color: var(--bodyc); box-shadow: 0 0 0 1px var(--bodyc), 0 0 22px -4px var(--bodyc); }
.ch-effects.active   { border-color: var(--eff);   box-shadow: 0 0 0 1px var(--eff),   0 0 22px -4px var(--eff); }
.ch-space.active     { border-color: var(--spc);   box-shadow: 0 0 0 1px var(--spc),   0 0 22px -4px var(--spc); }
.ch-power {
  background: none; border: none; cursor: pointer; padding: 2px;
  color: var(--text3); line-height: 0; border-radius: 50%;
}
.ch-power svg { width: 15px; height: 15px; display: block; }
.ch-power.on { color: inherit; }
.ch-excitor   .ch-power.on { color: var(--exc); }
.ch-resonator .ch-power.on { color: var(--res); }
.ch-body      .ch-power.on { color: var(--bodyc); }
.ch-effects   .ch-power.on { color: var(--eff); }
.ch-space     .ch-power.on { color: var(--spc); }
.ch-power.always { opacity: 0.45; cursor: default; }
.ch-card.stage-off .ch-thumb, .ch-card.stage-off .ch-headline { opacity: 0.35; }

/* ── Inspector v2: grouped knob sections ── */
.ins-group { border-top: 1px solid var(--border); padding-top: 7px; margin-top: 2px; }
.ins-group:first-of-type { border-top: none; margin-top: 0; }
.ins-group-label {
  font-size: 0.62rem; font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text2); margin-bottom: 4px;
}
.ins-group .knob-row { justify-content: space-around; gap: 2px 6px; }
.ch-inspector .knob-svg { width: 52px; height: 52px; }
.ch-inspector .knob-cell { width: 72px; }

/* ── SG2 v2: T vs S must never be guessed — TONE is part of the note,
   NOISE is a source beside it. PINNED knobs scale measured data. ── */
.ins-group.tone-group  { border-left: 2px solid var(--exc, #d49a4a); padding-left: 7px; }
.ins-group.noise-group { border-left: 2px dashed var(--text2); padding-left: 7px; }
.ins-group.noise-group .ins-group-label { color: var(--text2); font-style: italic; }
.knob-cell.pin .knob-label::after {
  content: " · measured"; font-style: italic; font-weight: 400;
  opacity: 0.7; letter-spacing: 0;
}
/* A pinned knob is a SCALE over fitted data, not a shaper — it must not
   look like the free knobs beside it: dotted ring, amber-tinted output,
   and a faint measured backplate. */
.knob-cell.pin .knob-svg {
  outline: 1px dotted var(--exc, #d49a4a); outline-offset: 2px;
  border-radius: 50%;
  background: radial-gradient(circle, hsla(36, 60%, 45%, 0.10) 0 60%, transparent 62%);
}
.knob-cell.pin .knob-out {
  color: var(--exc, #d49a4a); font-style: italic;
  border-bottom: 1px dotted hsla(36, 60%, 55%, 0.5);
}
.ch-illus { width: 100%; max-width: 420px; display: block; margin: 4px 0 6px; opacity: 0.9; }

/* ── Field header: "STAGE — Partial Field" ── */
.td-field-head {
  display: flex; align-items: baseline; gap: 10px;
}
.td-field-title { font-size: 0.86rem; font-weight: 600; color: var(--text); }
.td-field-title .td-stage-word { color: var(--text2); font-weight: 400; }
.ch-excitor-word   { color: var(--exc)  !important; }
.ch-resonator-word { color: var(--res)  !important; }
.ch-body-word      { color: var(--bodyc) !important; }
.ch-effects-word   { color: var(--eff)  !important; }
.ch-space-word     { color: var(--spc)  !important; }

/* ══ EFFECTS stage — three-panel rack (docs/EFFECTS_CONTRACT.md) ══════════
   The shell (browser + rack) stays flat/monochrome like the app; each effect
   FACE brings its own skeuomorphic design language from its module. */
.fxs-stage {
  flex: 1; min-height: 0; display: grid;
  grid-template-columns: 232px minmax(0, 1fr) 268px;
  gap: 0.5rem;
}
.fxs-browser, .fxs-rack {
  display: flex; flex-direction: column; min-height: 0;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface); overflow: hidden;
}
.fxs-panel-head {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 11px; font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.11em; text-transform: uppercase; color: var(--text2);
  border-bottom: 1px solid var(--border); flex: none;
}
.fxs-count {
  font-size: 0.6rem; color: var(--text3); background: var(--surface2);
  border-radius: 20px; padding: 1px 7px; font-weight: 600;
}
.fxs-panel-head .fxs-mini { margin-left: auto; }
.fxs-mini {
  font-size: 0.62rem; letter-spacing: 0.04em; color: var(--text2);
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: 5px; padding: 3px 8px; cursor: pointer;
}
.fxs-mini:hover { color: var(--text); border-color: var(--border2); }

/* ── Browser: raised header bars over recessed list wells (Logic-style) ── */
.fxs-browser-list { overflow-y: auto; padding: 0; flex: 1; background: var(--display); }
.fxs-cat { border-bottom: 1px solid var(--border); }
.fxs-cat-head {
  width: 100%; display: flex; align-items: center; gap: 8px;
  padding: 8px 11px; cursor: pointer; text-align: left;
  color: var(--text); font-size: 0.7rem; font-weight: 700; letter-spacing: 0.03em;
  border: none; border-radius: 0;
  background: linear-gradient(180deg, var(--surface2), var(--surface));
  position: sticky; top: 0; z-index: 2;
  box-shadow: 0 1px 0 var(--border);
}
.fxs-cat.open .fxs-cat-head { color: var(--eff); }
.fxs-cat-head:hover { background: linear-gradient(180deg, var(--border2), var(--surface2)); }
.fxs-cat-caret { width: 9px; color: var(--text3); font-size: 0.58rem; transition: color 0.1s; }
.fxs-cat.open .fxs-cat-caret { color: var(--eff); }
.fxs-cat-name { flex: 1; }
.fxs-cat-n {
  font-size: 0.58rem; color: var(--text3); background: var(--bg);
  border: 1px solid var(--border); border-radius: 20px; padding: 0 6px; font-weight: 600;
}
/* the expanded list is a recessed well, visually distinct from its header */
.fxs-cat-body {
  padding: 4px; background: var(--display);
  box-shadow: inset 0 2px 4px -3px rgba(0,0,0,0.9);
}
.fxs-eff {
  padding: 5px 8px 5px 20px; border-radius: 5px; cursor: grab;
  border: 1px solid transparent; display: block; overflow: hidden;
}
.fxs-eff:hover { background: var(--surface2); border-color: var(--border); }
.fxs-eff:active { cursor: grabbing; }
.fxs-eff-name { display: block; font-size: 0.75rem; color: var(--text); font-weight: 500; }
.fxs-eff-desc {
  display: block; font-size: 0.65rem; color: var(--text3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── Rack (stack) ── */
.fxs-rack-list { overflow-y: auto; padding: 6px; flex: 1; display: flex; flex-direction: column; gap: 5px; }
.fxs-rack-list.fxs-droptarget { outline: 1px dashed var(--eff); outline-offset: -3px; border-radius: 8px; }
.fxs-rack-empty, .fxs-face-empty-sub { color: var(--text3); font-size: 0.7rem; padding: 10px; line-height: 1.5; }
.fxs-slot {
  display: flex; align-items: center; gap: 6px; padding: 6px 7px;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: 7px; border-left: 3px solid var(--eff);
}
.fxs-slot.sel { border-color: var(--eff); box-shadow: 0 0 0 1px var(--eff-dim); }
.fxs-slot.off { opacity: 0.5; border-left-color: var(--text3); }
.fxs-slot.fxs-dragging { opacity: 0.4; }
.fxs-slot-grip { color: var(--text3); cursor: grab; font-size: 0.7rem; letter-spacing: -2px; }
.fxs-slot-power { background: none; border: none; cursor: pointer; color: var(--text3); padding: 0; line-height: 0; }
.fxs-slot-power svg { width: 13px; height: 13px; }
.fxs-slot-power.on { color: var(--eff); }
.fxs-slot-name { flex: 1; font-size: 0.74rem; color: var(--text); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fxs-slot-wet { display: flex; align-items: center; gap: 4px; }
.fxs-slot-wet input { width: 54px; }
.fxs-slot-wetv { font-size: 0.6rem; color: var(--text3); font-family: var(--mono); width: 30px; text-align: right; }
.fxs-slot-x { background: none; border: none; color: var(--text3); cursor: pointer; font-size: 1rem; line-height: 1; padding: 0 2px; }
.fxs-slot-x:hover { color: var(--red); }
.fxs-rack-foot { padding: 7px 11px; font-size: 0.62rem; color: var(--text3); border-top: 1px solid var(--border); flex: none; }

/* ── Face column (the effect's own panel mounts here) ── */
.fxs-face-col {
  display: flex; flex-direction: column; min-height: 0;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--display); overflow: hidden;
}
.fxs-face-head {
  display: flex; align-items: center; gap: 9px; padding: 8px 11px;
  border-bottom: 1px solid var(--border); flex: none;
}
.fxs-face-name { font-size: 0.82rem; font-weight: 600; color: var(--text); }
.fxs-face-cat { font-size: 0.62rem; color: var(--text3); text-transform: uppercase; letter-spacing: 0.08em; }
.fxs-face-tools { margin-left: auto; display: flex; align-items: center; gap: 7px; }
.fxs-face-preset {
  font-size: 0.66rem; background: var(--surface2); color: var(--text2);
  border: 1px solid var(--border); border-radius: 5px; padding: 2px 5px;
}
.fxs-face-mount { flex: 1; min-height: 0; position: relative; }
.fxs-face-empty {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 6px; color: var(--text2); text-align: center;
}
.fxs-face-empty-mark { font-size: 2.4rem; color: var(--text3); opacity: 0.5; }
.fxs-stage-off .fxs-face-col, .fxs-stage-off .fxs-rack { opacity: 0.6; }

/* ── Expanded overlay: face floats large, subnote page faintly visible ── */
.fxs-stage.fxs-expanded .fxs-face-col {
  position: fixed; inset: 3.5vh 3.5vw; z-index: 400;
  border: 1px solid var(--eff);
  box-shadow: 0 24px 80px -20px rgba(0,0,0,0.8);
}
.fxs-stage.fxs-expanded::after {
  content: ""; position: fixed; inset: 0; z-index: 399;
  background: rgba(10,11,14,0.55); backdrop-filter: blur(1px); -webkit-backdrop-filter: blur(1px);
}

/* ── Right column: Envelope / Modulation panel ── */
.td-side {
  width: 252px; flex: none;
  border: 1px solid var(--border); border-radius: 10px;
  background: rgba(10, 13, 17, 0.5);
  padding: 9px 11px;
  display: flex; flex-direction: column; gap: 8px;
  overflow-y: auto; min-height: 0;
}
.td-side::-webkit-scrollbar { width: 7px; }
.td-side::-webkit-scrollbar-thumb { background: rgba(120,130,150,0.3); border-radius: 4px; }
.td-tabs {
  display: flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden;
}
.td-tab {
  flex: 1; background: none; border: none; color: var(--text3);
  font: inherit; font-size: 0.7rem; font-weight: 600; padding: 5px 0;
  cursor: pointer; letter-spacing: 0.03em;
}
.td-tab.active { color: #cfe3ff; background: rgba(61, 157, 246, 0.13); box-shadow: inset 0 0 0 1px #2b5892; border-radius: 6px; }
.td-side .envelope-canvas { width: 100%; height: 128px; background: var(--display); border: 1px solid var(--border); border-radius: 7px; }
.adsr-readouts {
  display: grid; grid-template-columns: repeat(4, 1fr); text-align: center;
  font-variant-numeric: tabular-nums; margin-top: 2px;
}
.adsr-readouts .adsr-k { font-size: 0.66rem; color: var(--text3); font-weight: 600; }
.adsr-readouts output { font-size: 0.72rem; color: var(--text); display: block; }
.td-side .env-dist-row input[type=range] { height: 12px; }
.mod-list { display: flex; flex-direction: column; gap: 6px; }
.mod-row {
  display: flex; align-items: center; gap: 8px;
  border: 1px solid var(--border); border-radius: 8px;
  background: rgba(18, 22, 29, 0.85);
  padding: 5px 4px 5px 9px;
}
.mod-row-icon { width: 20px; height: 14px; flex: none; }
.mod-row-main { flex: 1; min-width: 0; }
.mod-row-name { font-size: 0.72rem; font-weight: 600; color: var(--text); line-height: 1.3; }
.mod-row-sub { font-size: 0.62rem; color: var(--text3); line-height: 1.2; }
.mod-row .knob-cell { width: 56px; padding: 0; }
.mod-row .knob-svg { width: 38px; height: 38px; }
.mod-row .knob-label { font-size: 0.52rem; }

/* (The bottom instrument cards retired 07-08 — the browser strip is the
   one selection surface in the sub-note view; .m2-preset.sel marks the
   active recipe there.) */

/* V2: the sub-note right column moved inside the chain (td-side), so the
   two-column workspace grid collapses to a single stacked flow. */
.subnote-full-layout { display: flex; flex-direction: column; min-height: 0; gap: 0.45rem; }
@media (max-width: 1050px) {
  .subnote-full-layout { display: flex; }
}
/* td-side children must never flex-shrink into nothing; the column itself scrolls */
.td-side > * { flex: none; }
.ch-card { min-height: 0; }

/* SPACE editor: the right column carries the ear response (arrival + colouring
   stacked vertically) instead of Envelope/Modulation (owner 2026-07-10) */
/* Scrolls like the inspector and field columns do — in a short window the
   three ear bands stay reachable instead of being clipped (owner 2026-07-15). */
.td-side-ears { overflow-y: auto; }
.ears-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; flex: none; }
.ears-head-title { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.09em; color: var(--text); }
.ears-head-sum { font-size: 0.56rem; color: var(--text3); }
.ears-head-sum b { color: var(--text2); font-weight: 700; }
/* min-height keeps all three bands legible; the column scrolls when the
   window can't give them that much height. */
.td-side-ears > .ears-slot { flex: 1 1 auto; min-height: 340px; position: relative; }
.td-side-ears canvas#cvSpaceField { width: 100%; height: 100%; display: block; }

/* ── V2 Spatial Stage (render phase-04) ── */
.stage-sources {
  display: flex; gap: 7px; align-items: center; flex-wrap: wrap; flex: none;
}
.stage-src {
  display: flex; align-items: center; gap: 6px;
  border: 1px solid hsl(var(--src-hue, 36), 45%, 32%);
  border-radius: 8px;
  background: rgba(14, 18, 24, 0.85);
  padding: 4px 8px;
  cursor: pointer;
  font-size: 0.66rem; color: var(--text2);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.stage-src.sel {
  border-color: hsl(var(--src-hue, 36), 70%, 55%);
  box-shadow: 0 0 0 1px hsl(var(--src-hue, 36), 70%, 55%), 0 0 14px -6px hsl(var(--src-hue, 36), 70%, 55%);
  color: var(--text);
}
.src-num {
  width: 17px; height: 17px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid hsl(var(--src-hue, 36), 70%, 58%);
  color: hsl(var(--src-hue, 36), 75%, 65%);
  font-size: 0.6rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.src-name { font-weight: 600; }
.src-pos { font-variant-numeric: tabular-nums; color: var(--text3); }
.stage-src .layer-solo { margin-left: 2px; }
.stage-src-hint { margin-left: auto; font-size: 0.6rem; color: var(--text3); }

#cvStageBig { display: block; background: var(--display); border: 1px solid var(--border); border-radius: 8px; cursor: crosshair; }

.stage-readouts {
  display: flex; gap: 0; flex: none;
  border: 1px solid var(--border); border-radius: 8px;
  background: rgba(10, 13, 17, 0.6);
  padding: 5px 0;
}
.stage-ro {
  flex: 1; text-align: center;
  display: flex; flex-direction: column; gap: 1px;
  border-right: 1px solid var(--border);
}
.stage-ro:last-child { border-right: none; }
.stage-ro-k { font-size: 0.58rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text3); }
.stage-ro-v { font-size: 0.82rem; color: var(--text); font-variant-numeric: tabular-nums; }

.head-model-list { display: flex; flex-direction: column; gap: 4px; }
.head-model-row {
  display: flex; flex-direction: column; gap: 0;
  text-align: left; font: inherit; cursor: pointer;
  background: rgba(14, 18, 24, 0.85);
  border: 1px solid var(--border); border-radius: 7px;
  padding: 4px 8px; color: var(--text2);
}
.head-model-row:hover { border-color: var(--border2); }
.head-model-row.sel { border-color: var(--spc); box-shadow: 0 0 0 1px var(--spc); color: var(--text); }
.hm-name { font-size: 0.68rem; font-weight: 600; }
.hm-sub { font-size: 0.58rem; color: var(--text3); font-variant-numeric: tabular-nums; }
/* the stage flexes to whatever height the workspace can give it */
.ch-field-pos.stage-pos { flex: 1; min-height: 190px; display: flex; }
#cvStageBig { width: 100%; height: 100%; flex: 1; }
.layer-strip-note { font-size: 0.62rem; color: var(--text3); }

/* (The V2 Scale Lab's rules went with that page, 2026-10-10: it was folded into Compose › Scale & Root, face/scale-face.css.) */
/* §1.7 floor: every splitter is focusable now (arrow keys resize it), so it
   needs a visible focus state. One rule for all three studio bar classes —
   and for the producer's two that had none, now that all eight run on the one
   `wireSplitter` mechanism §2.4 asks for. `.daw-vsplit` keeps its own rule
   above (offset -1px, to sit inside a 6px grid gutter). */
.m2-vsplit:focus-visible, .m2-hsplit:focus-visible,
.dash-vsplit:focus-visible, .ch-vsplit:focus-visible, .ch-hsplit:focus-visible,
.daw-lsplit:focus-visible, .daw-hsplit:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* Every splitter is dragged with Pointer Events, and a splitter's stroke is
   exactly the stroke the browser wants for a page pan. Without this the drag
   is dead on any touch device — the pan is claimed before a move handler can
   object, and `preventDefault` in the handler arrives too late to take it
   back. The eight bars are listed rather than given a shared class because
   their classes are what the layout rules already key on. */
.m2-vsplit, .m2-hsplit, .dash-vsplit, .ch-vsplit, .ch-hsplit,
.daw-vsplit, .daw-lsplit, .daw-hsplit { touch-action: none; }
.m2-vsplit.splitting::before, .m2-hsplit.splitting::before { background: rgba(245,166,35,0.85); }
/* The producer's bars show their hover tint while a drag is live, so a finger
   that has covered the bar still gets the confirmation a cursor gets. */
.daw-vsplit.splitting, .daw-hsplit.splitting { background: rgba(154,160,171,0.15); border-radius: 3px; }
.daw-lsplit.splitting { background: rgba(154,160,171,0.2); }

/* ── V2 Macro Explorer (render phase-02) ── */
.macro2-card { display: none; }
.macro2-workspace-mode .macro2-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  position: absolute;
  top: 44px; left: 3px; right: 3px; bottom: var(--ws-bottom);
  z-index: 2;
  overflow: hidden;
}
.macro2-workspace-mode .library-card,
.macro2-workspace-mode .output-card { display: none; }
.macro2-workspace-mode .research-note {
  position: absolute; right: 3px; bottom: 8px; z-index: 3; margin: 0;
}

.m2-main { display: flex; gap: 10px; flex: 1; min-height: 0; align-items: stretch; }
/* Rail: ONE button wide, full height (owner 2026-08-11). Labels drop away —
   the icon plus a tooltip carries it — and the subtle grouping stays as a
   bordered block with its own heading rule. */
/* FE-6 (owner 2026-08-27, "this set of buttons is also ugly"). Four things were
   wrong and they compounded:
     1. THREE frames deep. Every button had its own border+radius+gradient, four
        of them were then wrapped in a bordered .m2-rail-group, and that sat in
        the rail's own bordered box — in a 112px column.
     2. TWO heights. Grouped buttons were overridden to 44px against the
        standalone 54px, so membership was expressed by shrinking the members,
        which reads as "less important" rather than "belongs together".
     3. COLOURED CHROME. .m2-rail-icon took its lane hue at rest, so the column
        read amber/blue/blue/green before you touched anything. The system puts
        colour on data; the active ring already carries the hue correctly.
     4. WRAPPING LABELS. "Sequence & Surprise" broke to two lines at 112px, so
        heights varied even where min-height matched.
   Now: one flat list, one height, resting state is a well, grouping is a
   hairline under a micro-label, hue arrives only on hover/active. */
.m2-rail {
  width: 126px; flex: none;
  display: flex; flex-direction: column; gap: 4px;
  border: 1px solid var(--hairline); border-radius: var(--radius);
  background: var(--panel);
  box-shadow: var(--elev-1);
  padding: 7px 6px;
  overflow-y: auto;
}
.m2-rail-btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  background: var(--well);
  border: 1px solid transparent; border-radius: var(--radius-sm);
  color: var(--text2); font: inherit; font-size: 0.7rem; font-weight: 600;
  letter-spacing: 0.01em; text-align: center;
  padding: 8px 4px 7px; cursor: pointer; line-height: 1.2;
  min-height: 52px;
  /* The rail is a flex COLUMN that scrolls. Without this the buttons shrink to
     fit instead of overflowing, and they shrink unevenly — the four inside
     .m2-rail-group are one flex item between them, so they compressed at a
     different rate than their standalone neighbours. That, not min-height, is
     where the rail's two button heights actually came from (FE-6). */
  flex: none;
  transition: border-color 0.15s, box-shadow 0.15s, color 0.15s, background-color 0.15s;
}
.m2-rail-btn:hover { border-color: var(--hairline); color: var(--text); background: var(--control-bg); }
.m2-rail-btn:focus-visible { outline: 2px solid var(--rail-c, var(--accent)); outline-offset: 1px; }
.m2-rail-btn.active {
  border-color: var(--rail-c, var(--gen)); color: var(--text);
  box-shadow: 0 0 0 1px var(--rail-c, var(--gen)), 0 0 16px -8px var(--rail-c, var(--gen));
}
/* Monochrome at rest — the hue is the ACTIVE signal, not the label. */
.m2-rail-icon { color: var(--text3); display: block; transition: color 0.15s; }
.m2-rail-btn.active .m2-rail-icon,
.m2-rail-btn:hover .m2-rail-icon { color: var(--rail-c, var(--text)); }
.m2-rail-icon svg { width: 20px; height: 20px; display: block; }
/* One line. At 126px every label in the rail fits; the title carries the full
   name for the one ("Sequence & Surprise") that is shortened in the markup. */
.m2-rail-label { display: block; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The group is a rule and a label, not a box around a box. */
.m2-rail-group {
  border: 0; border-top: 1px solid var(--hairline-soft);
  border-radius: 0; margin-top: 3px;
  padding: 5px 0 0; display: flex; flex-direction: column; gap: 4px;
  flex: none;
}
.m2-rail-grid { display: flex; flex-direction: column; gap: 4px; }
.m2-rail-head {
  font-size: 0.55rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text3); padding: 0 2px 4px; text-align: center;
  line-height: 1.25;
}

/* Settings pane: wider by default and drag-resizable; runs the full height
   beside the rail. The centre column carries the display AND the browser. */
.macro2-workspace-mode .m2-inspector {
  /* never so wide that the display falls under about 360 px (review L-2) */
  width: max(280px, min(var(--m2-insp-w, 460px), calc(100vw - 540px)));
  flex: none; min-height: 0;
}
.m2-vsplit {
  flex: none; width: 8px; margin: 0 -2px; cursor: col-resize;
  border-radius: 4px; position: relative; z-index: 3;
}
/* §1.7: an 8px bar is not a target. Widen the HIT area without widening the
   bar, the same way .m2-hsplit already does vertically. */
.m2-vsplit::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: -6px; right: -6px;
}
.m2-vsplit::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 3px; height: 42px; border-radius: 2px;
  background: rgba(120,130,150,0.32);
}
.m2-vsplit:hover::before { background: rgba(245,166,35,0.55); }
.m2-hsplit {
  flex: none; height: 12px; margin: 3px 0 1px; cursor: row-resize;
  border-radius: 5px; position: relative; z-index: 3;
  background: rgba(120, 130, 150, 0.09);
  border: 1px solid var(--border);
  transition: background 120ms ease, border-color 120ms ease;
}
.m2-hsplit::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 72px; height: 4px; border-radius: 2px;
  background: rgba(120, 130, 150, 0.45);
}
.m2-hsplit::after {
  content: ""; position: absolute; left: 0; right: 0; top: -5px; bottom: -5px;
}
.m2-hsplit:hover { background: rgba(245,166,35,0.12); border-color: rgba(245,166,35,0.45); }
.m2-hsplit:hover::before { background: rgba(245,166,35,0.7); }
/* the docked browser at the foot of the centre column */
.m2-lib-dock {
  flex: none; height: var(--m2-lib-h, 240px);
  min-height: 96px; display: flex; flex-direction: column; overflow: hidden;
}
.m2-lib-dock .m2-lib { flex: 1 1 0; min-height: 0; }
.m2-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }

/* ── searchable scale combo: 12-tone presets + world tunings in one list ── */
.scale-combo { position: relative; flex: 1; min-width: 0; }
.scale-combo-btn {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 6px;
  background: rgba(14, 18, 24, 0.85); border: 1px solid var(--border); border-radius: 7px;
  color: var(--text); font: inherit; font-size: 0.72rem; font-weight: 600;
  padding: 6px 9px; cursor: pointer; text-align: left;
}
.scale-combo-btn:hover { border-color: var(--border2); }
.scale-combo-caret { color: var(--text3); font-size: 0.6rem; }
.scale-combo-pop {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 60;
  background: rgba(12, 16, 22, 0.98); border: 1px solid var(--border2); border-radius: 9px;
  box-shadow: 0 10px 32px rgba(0,0,0,0.55);
  padding: 6px; display: flex; flex-direction: column; gap: 5px;
}
.scale-combo-search {
  width: 100%; box-sizing: border-box;
  background: rgba(20, 26, 34, 0.9); border: 1px solid var(--border); border-radius: 6px;
  color: var(--text); font: inherit; font-size: 0.7rem; padding: 5px 8px;
}
.scale-combo-list { max-height: 240px; overflow-y: auto; display: flex; flex-direction: column; }
.scale-combo-group {
  font-size: 0.56rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text3); padding: 6px 6px 3px;
}
.scale-combo-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: none; border: none; border-radius: 5px;
  color: var(--text2); font: inherit; font-size: 0.72rem;
  text-align: left; padding: 5px 7px; cursor: pointer;
}
.scale-combo-opt:hover { background: rgba(255,255,255,0.05); color: var(--text); }
.scale-combo-opt.sel { color: var(--gen); }
.scale-combo-note { font-style: normal; font-size: 0.58rem; color: var(--text3); }

/* ── smart-combo: reusable searchable dropdown (docs/SMART_DROPDOWN_SPEC.md) ── */
.smart-combo { position: relative; flex: 1; min-width: 0; }
.smart-combo-btn {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 6px;
  background: rgba(14, 18, 24, 0.85); border: 1px solid var(--border); border-radius: 7px;
  color: var(--text); font: inherit; font-size: 0.72rem; font-weight: 600;
  padding: 6px 9px; cursor: pointer; text-align: left;
}
.smart-combo-btn:hover { border-color: var(--border2); }
.smart-combo-btn-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.smart-combo-caret { color: var(--text3); font-size: 0.6rem; flex: none; }
.smart-combo-pop {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 60;
  background: rgba(12, 16, 22, 0.98); border: 1px solid var(--border2); border-radius: 9px;
  box-shadow: 0 10px 32px rgba(0,0,0,0.55);
  padding: 6px; display: flex; flex-direction: column; gap: 5px;
}
/* the `hidden` attribute must win over the display:flex above (author rules
   beat the UA [hidden] rule, so an explicit attribute selector is required) */
.smart-combo-pop[hidden] { display: none; }
/* fall UP when there isn't room below (set by wireSmartCombos, owner 2026-07-10) */
.smart-combo-pop.smart-combo-pop-up { top: auto; bottom: calc(100% + 4px); }
.smart-combo-search {
  width: 100%; box-sizing: border-box;
  background: rgba(20, 26, 34, 0.9); border: 1px solid var(--border); border-radius: 6px;
  color: var(--text); font: inherit; font-size: 0.7rem; padding: 5px 8px;
}
.smart-combo-list { max-height: 240px; overflow-y: auto; display: flex; flex-direction: column; }
.smart-combo-group {
  font-size: 0.56rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text3); padding: 6px 6px 3px;
}
/* A typed filter hides options with [hidden]; the display rules below would
   otherwise override it and hide nothing (review 12-3g, Y1). */
.smart-combo-opt[hidden], .smart-combo-group[hidden] { display: none; }
.smart-combo-empty { color: var(--text2); font-size: 0.72rem; padding: 6px 7px; }   /* --text3 measured ~3:1 here (review 12-3i) */
.smart-combo-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: none; border: none; border-radius: 5px;
  color: var(--text2); font: inherit; font-size: 0.72rem;
  text-align: left; padding: 5px 7px; cursor: pointer;
}
.smart-combo-opt-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.smart-combo-opt:hover { background: rgba(255,255,255,0.05); color: var(--text); }
.smart-combo-opt.sel { color: var(--gen); }
.smart-combo-note { font-style: normal; font-size: 0.58rem; color: var(--text3); flex: none; }
.smart-combo-empty { color: var(--text3); font-size: 0.68rem; padding: 8px 7px; }

/* ── percussion v2: enable toggle + editable layer list (owner 2026-07-10) ── */
.perc-enable-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.perc-enable-toggle {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text);
}
.perc-enable-toggle input { accent-color: var(--gen); width: 15px; height: 15px; cursor: pointer; }
.perc-enable-hint { font-size: 0.64rem; color: var(--text3); }
.perc-body { display: flex; flex-direction: column; gap: 9px; transition: opacity 0.15s ease; }
.perc-body.perc-disabled { opacity: 0.4; pointer-events: none; filter: grayscale(0.5); }
.perc-list { display: flex; flex-direction: column; gap: 8px; }
.perc-empty { color: var(--text3); font-size: 0.7rem; padding: 10px 2px; }
.perc-lyr {
  display: flex; flex-direction: column; gap: 7px; padding: 9px 10px;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid hsl(var(--layer-hue, 32) var(--layer-sat, 70%) 55%); border-radius: 8px;
}
.perc-lyr-head { display: flex; align-items: center; gap: 8px; }
.perc-lyr-role {
  flex: none; background: rgba(14, 18, 24, 0.85); border: 1px solid var(--border);
  border-radius: 6px; color: var(--text); font: inherit; font-size: 0.72rem; font-weight: 600;
  padding: 5px 8px; cursor: pointer;
}
.perc-lyr-remove { margin-left: auto; }
.perc-lyr-sound { display: flex; min-width: 0; }
/* One line per hit: position pad + volume (+ every/pitch) share the row. */
/* FE-13: the row wraps rather than crushing the fader — 28px of travel was
   a nudge control. Something else drops before the level control does. */
.perc-lyr-ctls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.perc-lyr-ctls .sp-ctl { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.perc-lyr-ctls .sp-ctl input[type="range"] { flex: 1 1 auto; min-width: var(--fader-min-travel); width: auto; }
.perc-add {
  align-self: flex-start; background: rgba(14, 18, 24, 0.7); border: 1px dashed var(--border2);
  border-radius: 7px; color: var(--text2); font: inherit; font-size: 0.72rem; font-weight: 600;
  padding: 6px 12px; cursor: pointer;
}
.perc-add:hover { color: var(--text); border-color: var(--gen); }

.m2-center { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.m2-chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.m2-chip {
  font-size: 0.66rem; color: var(--text2);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 3px 9px; background: rgba(14, 18, 24, 0.7);
}
.m2-chip b { color: var(--text); font-weight: 600; }
.m2-chip-link { cursor: pointer; color: var(--rootc); border-color: #3f3766; font: inherit; font-size: 0.66rem; }
.m2-chip-link:hover { background: rgba(139,124,246,0.1); }
.m2-chips .vis-mode-switch { margin-left: auto; }
.m2-visual { flex: 1; min-height: 0; position: relative; }
.m2-visual #vis { width: 100%; height: 100%; display: block; }
/* Display trimmed on every axis (owner 2026-08-11): the wider settings pane
   takes width, the docked browser takes height, and this caps what is left
   so the field never balloons on a tall window. */
.macro2-workspace-mode .m2-visual { max-height: 46vh; }
/* Layers view replaces the roll/lanes canvas with an HTML panel */
.visualiser-wrap.vis-mode-layers #vis { display: none; }
.m2-layers-panel {
  position: absolute; inset: 0; overflow-y: auto;
  background: var(--display); border-radius: 8px; padding: 10px 12px;
}
.prod-layers-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.prod-layers-title { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text); }
.prod-layers-note { font-size: 0.64rem; color: var(--text3); }
.prod-layers-list { display: flex; flex-direction: column; gap: 6px; }
.prod-layers-empty { color: var(--text3); font-size: 0.7rem; padding: 8px 2px; }
.prod-layer-row {
  display: flex; align-items: center; gap: 10px; padding: 7px 9px;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--layer-hue, var(--eff)); border-radius: 7px;
  flex-wrap: wrap;
}
.prod-layer-row.base { border-left-color: var(--accent); background: var(--surface2); }
.prod-layer-row.perc-row { border-left-color: hsl(32 70% 55%); background: color-mix(in srgb, hsl(32 70% 55%) 5%, var(--surface)); }
.prod-layer-row.perc-row.dim { opacity: 0.62; }
.prod-layer-row.perc-row .prod-layer-tag { background: color-mix(in srgb, hsl(var(--layer-hue, 172) var(--layer-sat, 45%) 55%) 60%, transparent); }
.prod-layer-tag {
  width: 20px; height: 20px; flex: none; display: grid; place-items: center;
  border-radius: 50%; font-size: 0.62rem; color: var(--text);
  background: color-mix(in srgb, hsl(var(--layer-hue, 210) var(--layer-sat, 60%) 55%) 55%, transparent);
}
.prod-layer-name { font-size: 0.74rem; font-weight: 600; color: var(--text); width: 62px; flex: none; }
.prod-layer-ctls { display: flex; align-items: center; gap: 8px; }
.prod-ctl { display: flex; align-items: center; gap: 4px; font-size: 0.6rem; color: var(--text3); text-transform: uppercase; letter-spacing: 0.04em; }
.prod-ctl input { width: 66px; }
.prod-ctl input[type="range"].fader.fader--h { width: var(--fader-min-travel); }
.prod-ctl-mute { color: var(--text3); font-style: italic; }
.prod-layer-fx { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; margin-left: auto; }
.prod-fx-none { font-size: 0.62rem; color: var(--text3); font-style: italic; }
.prod-fx-tag {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--surface2); border: 1px solid var(--border);
  border-left: 2px solid var(--eff); border-radius: 4px; padding: 1px 3px 1px 5px;
}
.prod-fx-tag.off { border-left-color: var(--text3); opacity: 0.55; }
.prod-fx-name { background: none; border: none; cursor: pointer; padding: 0; font-size: 0.62rem; color: var(--text); white-space: nowrap; }
.prod-fx-tag.off .prod-fx-name { color: var(--text2); }
.prod-fx-wet { width: 40px; height: 11px; }
.prod-fx-x { background: none; border: none; color: var(--text3); cursor: pointer; font-size: 0.85rem; line-height: 1; padding: 0 1px; }
.prod-fx-x:hover { color: var(--red); }
.prod-fx-add {
  font-size: 0.62rem; background: var(--surface2); color: var(--text2);
  border: 1px solid var(--border); border-radius: 5px; padding: 2px 5px;
}
.macro2-card .engine-state { flex: none; }

.m2-inspector {
  width: 300px; flex: none;
  border: 1px solid var(--hairline); border-radius: var(--radius);
  background: var(--panel);
  box-shadow: var(--elev-1);
  padding: 10px 12px;
  overflow-y: auto; min-height: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.m2-inspector::-webkit-scrollbar { width: 7px; }
.m2-inspector::-webkit-scrollbar-thumb { background: rgba(120,130,150,0.3); border-radius: 4px; }
.m2-inspector .macro-panel { display: flex; flex-direction: column; gap: 8px; }
.m2-inspector .note-circle { margin: 0 auto; }

.m2-presets {
  display: flex; gap: 8px; align-items: stretch; flex: none;
  border: 1px solid var(--border); border-radius: 10px;
  background: rgba(10, 13, 17, 0.45);
  padding: 7px 9px;
  overflow-x: auto;
  position: relative;
  /* The rail has always scrolled, but with macOS overlay scrollbars it showed
     no thumb until you were already dragging — so the last card looked hard
     clipped by the panel edge and the fastest route to a good sound read as
     shorter than it is. A reserved gutter is the honest affordance: the thumb
     renders only when there IS more to reach, so it never promises content
     that isn't there.
     Styled with ::-webkit-scrollbar and deliberately NOT with
     `scrollbar-width` — setting the standard property makes Chrome drop the
     pseudo-elements, and `thin` alone stays an overlay scrollbar that is
     invisible at rest, which is the state being fixed.
     The scrollbar only answers it once it appears, so the edge fade carries
     the at-rest cue: the last card softens into the panel instead of being
     guillotined by it, which is what made the rail read as the whole set. The
     mask paints on the padding box and so stays put while the cards move. */
  -webkit-mask-image: linear-gradient(to right, black 0, black calc(100% - 30px), transparent 100%);
  mask-image: linear-gradient(to right, black 0, black calc(100% - 30px), transparent 100%);
}
.m2-presets::-webkit-scrollbar { height: 7px; }
.m2-presets::-webkit-scrollbar-track { background: transparent; }
.m2-presets::-webkit-scrollbar-thumb {
  background: var(--border); border-radius: 4px;
}
.m2-presets:hover::-webkit-scrollbar-thumb { background: var(--text3); }
/* Favourites toggle: a labelled button at the right end of the tag row
   (owner 2026-08-11). Deliberately NOT chip-styled — it switches a whole
   section on and off, so it carries the teal "view" accent rather than the
   amber the tag filters use. */
.m2-strip-toggle {
  margin-left: auto; flex: none;
  background: rgba(95, 212, 200, 0.07);
  border: 1px solid rgba(95, 212, 200, 0.35);
  border-radius: 6px;
  color: #8fded4; font: inherit; font-size: 0.6rem; font-weight: 600;
  letter-spacing: 0.02em;
  padding: 3px 9px; cursor: pointer; white-space: nowrap;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.m2-strip-toggle:hover { background: rgba(95, 212, 200, 0.14); border-color: rgba(95, 212, 200, 0.6); color: #b6ece5; }
.m2-strip-toggle.on { background: rgba(95, 212, 200, 0.16); color: #cdf3ee; }
.m2-presets-label {
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-size: 0.56rem; letter-spacing: 0.14em; color: var(--text3);
  text-align: center; flex: none;
}
/* ~30% smaller than the original 150px card (owner 2026-08-11) so more
   favourites fit on one row. */
.m2-preset {
  flex: 0 0 105px;
  display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  background: linear-gradient(180deg, rgba(24,29,37,0.9), rgba(15,18,24,0.95));
  border: 1px solid var(--border); border-radius: 7px;
  padding: 4px 6px; cursor: pointer; font: inherit; color: var(--text2);
  transition: border-color 0.15s;
}
.m2-preset:hover { border-color: var(--gen); }
.m2-preset.sel { border-color: var(--res); box-shadow: 0 0 0 1px var(--res), 0 0 18px -6px var(--res); }
/* Sub-note preview (owner 2026-07-09): the card being auditioned */
.m2-preset { position: relative; }
.m2-preset.previewing { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 0 20px -6px var(--accent); }
/* FE-17 (owner 2026-08-28): "there should be a visualiser animation on the
   chip's icon using the existing icons graphic but glowing and animated when it
   is previewing."
   The card already draws its own signature into a <canvas> — that IS the
   icon graphic, so nothing new is drawn. While the card is the one sounding,
   that canvas lifts to full strength and breathes: a slow accent glow that
   says "this is what you are hearing right now" without inventing a second
   indicator beside the badge. Everything here is compositing only (opacity,
   filter) so it stays off the layout and off the audio thread's back. */
/* FE-17 (owner 2026-08-28). A pulsing glow was the lazy answer — it says
   "something is happening" without saying what, and any card could have worn
   it. The chip's canvas already draws that sound's own signature, so the
   animation belongs IN the drawing: a playhead sweeps the signature while it
   auditions, lighting the part that has sounded. It is the sound's own picture
   playing, which no other card can be mistaken for. Driven by
   `animateM2PreviewArt` in app.js — nothing here but the resting state. */
.m2-preset canvas { transition: opacity 0.18s ease; }
.m2-preset.previewing canvas { opacity: 1; }
/* Centred on the chip, which puts it over the waveform canvas — the only band
   with room for it. At `top/right: 5px` the badge is 57 px wide in a 112 px
   chip and was painted straight over the last 14 px of `.m2-preset-name`:
   the name is shrink-to-fit, so it measures as fitting (scrollWidth ==
   clientWidth), never ellipsises, and the badge simply covers its tail.
   Reserving a gutter instead would truncate a 56 px name to ~36 px. */
.m2-preview-badge {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  /* Anchored at left:50% its available width is only half the chip, which wraps
     "▶ PREVIEW" onto a second line and grows it into the LOAD button. */
  white-space: nowrap;
  font-size: 0.5rem; font-weight: 700; letter-spacing: 0.06em;
  color: var(--bg); background: var(--accent); border-radius: 3px; padding: 1px 4px;
}
.m2-preset-name {
  font-size: 0.6rem; font-weight: 600; color: var(--text);
  max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m2-preset canvas { width: 100%; height: 24px; background: var(--display); border-radius: 4px; }
.m2-preset-fam { font-size: 0.48rem; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text3); }
/* in the macro2 chips row the vis switch lies flat */
.m2-chips .vis-mode-switch { flex-direction: row; margin-top: 0; }
/* Modulation tab back to the classic blocks: sliders + the wobble trace */
.td-side .vibrato-canvas { width: 100%; height: 54px; background: var(--display); border: 1px solid var(--border); border-radius: 7px; }
.td-side .perf-vibrato-block .control-row { grid-template-columns: 92px 1fr 44px; }

/* ── V2.1 macro lanes: header overlay, key popovers, analysis tiles ── */
.m2-visual { position: relative; }
.m2-lane-heads {
  position: absolute; top: 0; left: 0; width: 190px;
  pointer-events: none;
}
.m2-lane-head {
  position: absolute; left: 0; width: 100%;
  display: flex; align-items: flex-start; gap: 7px;
  padding: 8px 10px 0 12px;
  pointer-events: auto;
}
.m2-lane-n {
  font-size: 0.76rem; font-weight: 700; font-family: var(--mono);
  opacity: 0.9; line-height: 1.2;
}
.m2-lane-tt { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.m2-lane-title {
  font-size: 0.54rem;
  font-weight: 750;
  letter-spacing: 0.04em;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.m2-lane-sub {
  font-size: 0.51rem;
  color: var(--text3);
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.m2-lane-info {
  width: 15px; height: 15px; flex: none; margin-left: 3px;
  border-radius: 50%; border: 1px solid var(--border2);
  background: rgba(14, 18, 24, 0.85); color: var(--text2);
  font: italic 700 0.6rem Georgia, serif; line-height: 1;
  cursor: pointer;
}
.m2-lane-info:hover { color: var(--text); border-color: var(--text3); }

.m2-lane-key {
  position: absolute; z-index: 6; width: 210px;
  background: rgba(13, 18, 25, 0.97);
  border: 1px solid var(--border2); border-radius: 9px;
  padding: 8px 10px;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
}
.m2-key-head {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 0.72rem; font-weight: 700; color: var(--text);
  margin-bottom: 6px;
}
.m2-key-close {
  background: none; border: none; color: var(--text3);
  font: inherit; font-size: 0.9rem; cursor: pointer; line-height: 1;
}
.m2-key-close:hover { color: var(--text); }
.m2-key-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 0.64rem; color: var(--text2); padding: 2.5px 0;
}
.k-sw { width: 26px; height: 10px; flex: none; position: relative; }
.k-line-amber::after, .k-line-amber-dash::after, .k-line-gray-dash::after, .k-line-teal::after {
  content: ""; position: absolute; left: 0; right: 0; top: 4px; border-top: 2px solid;
}
.k-line-amber::after { border-color: #f5a623; }
.k-line-amber-dash::after { border-color: rgba(245,166,35,0.8); border-top-style: dashed; }
.k-line-gray-dash::after { border-color: rgba(180,190,205,0.6); border-top-style: dashed; }
.k-line-teal::after { border-color: rgba(95,212,200,0.9); }
.k-band { background: rgba(245,166,35,0.12); border-top: 1px dashed rgba(245,166,35,0.5); border-bottom: 1px dashed rgba(245,166,35,0.5); }
.k-heat { background: radial-gradient(ellipse at center, rgba(255,110,40,0.55), rgba(255,110,40,0)); }
.k-heat-blue { background: linear-gradient(90deg, rgba(80,150,255,0.5), rgba(80,150,255,0)); }
.k-onset { background: linear-gradient(90deg, transparent 11px, #60a5fa 11px, #60a5fa 14px, transparent 14px); }
.k-dur { background: rgba(96,165,250,0.5); border-radius: 2px; }
.k-dur-dash { border: 1px dashed rgba(96,165,250,0.7); border-radius: 2px; }
.k-rest { border: 1px solid rgba(229,72,77,0.75); border-radius: 2px; }
.k-gap { background: rgba(95,212,200,0.55); height: 4px; margin-top: 3px; }
.k-tag, .k-tag-cyan, .k-tag-cyan-dash {
  border-radius: 3px; font: 700 7px var(--mono); text-align: center; line-height: 10px;
}
.k-tag { border: 1px solid #f5a623; color: #ffd28a; background: rgba(58,38,10,0.9); }
.k-tag::before { content: "P"; }
.k-tag-cyan { border: 1px solid rgba(56,189,248,0.85); color: #8ee3ff; background: rgba(14,24,34,0.9); }
.k-tag-cyan::before { content: "R"; }
.k-tag-cyan-dash { border: 1px dashed rgba(56,189,248,0.6); color: #8ee3ff; background: rgba(14,24,34,0.9); }
.k-tag-cyan-dash::before { content: "risk"; }
.k-block-green { border: 1px solid #4caf7d; border-radius: 3px; }
.k-block-amber-dash { border: 1px dashed #e5a53a; border-radius: 3px; }
.k-diamond { background: #ffe07a; width: 8px; height: 8px; margin: 1px 9px; transform: rotate(45deg); }

/* The display and its readouts are ONE object (owner 2026-08-11): the canvas
   sits in the frame's top, the readout strip is its footer, sharing one
   border. Individually boxed tiles read as a row of buttons. */
.m2-display {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: 10px;
  background: rgba(10, 13, 17, 0.5);
  overflow: hidden;
}
/* FE-23 — this used to read `max-height: 52vh` and it was the inversion the
   owner reported ("the bottom of the browser shortens and lengthens OPPOSITE
   to the direction of expanding the frame").
   .m2-center is a column of: chips (auto) · display (flex:1) · splitter ·
   browser dock (flex:none, height --m2-lib-h). The display was the ONLY item
   that could absorb slack, and the cap stopped it absorbing any past 52vh —
   so the leftover opened as a hole BELOW the dock, growing at 0.48 px per px
   of window height. Measured: window 900 → 45.8 px of dead panel under the
   browser; window 1100 → 141.8 px. Uncapped: 0 px at both.
   --m2-lib-h itself was cleared of suspicion — it has exactly one consumer
   (.m2-lib-dock's `height`) and is read as a height, not an inset. */
.macro2-workspace-mode .m2-display { max-height: none; }
.m2-display .m2-visual { flex: 1; min-height: 0; border: none; border-radius: 0; background: none; }
.macro2-workspace-mode .m2-display .m2-visual { max-height: none; }

.m2-bottom {
  display: flex; align-items: center; gap: 10px; flex: none;
  border-top: 1px solid var(--border);
  background: rgba(8, 11, 16, 0.55);
  padding: 5px 12px;
}
.m2-status-chip {
  display: flex; align-items: center; flex: none;
  border: none; padding: 0 10px 0 2px;
  font-size: 0.6rem; color: var(--text3);
  white-space: nowrap; max-width: 240px;
  border-right: 1px solid var(--border);
}
.m2-status-chip.playing { color: #ffd28a; background: none; border-color: var(--border); }
.m2-tiles { display: flex; gap: 6px; flex: 1; }
/* readouts, not buttons: no box, a hairline between neighbours only */
.m2-tiles .stat {
  flex: 1; display: flex; flex-direction: column-reverse; align-items: center; gap: 1px;
  border: none; border-radius: 0; background: none;
  padding: 2px 10px; font-size: 0.46rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text3); text-align: center;
  min-width: 0;
}
.m2-tiles .stat + .stat { box-shadow: inset 1px 0 0 rgba(120, 130, 150, 0.13); }
.m2-tiles .stat-val {
  font-size: 0.76rem; color: var(--text);
  font-variant-numeric: tabular-nums; letter-spacing: 0; line-height: 1.15;
}

/* ── Producer access: first-class mode pill (audit: access clarity) ── */
.workspace-tab-sep { width: 1px; align-self: stretch; margin: 2px 4px; background: var(--border2); }
.producer-pill {
  border: 1px solid rgba(245,166,35,0.55) !important;
  border-radius: 7px;
  color: #ffd28a !important;
  background: rgba(245,166,35,0.07);
  font-weight: 700;
}
.producer-pill:hover { background: rgba(245,166,35,0.16); color: #ffe3b0 !important; }

/* ── V2 Producer pass (audit P0/P1 + target render) ── */
/* labelled creation actions — no more 18px "+" (audit hit-target P0) */
.br-btn.br-add {
  padding: 3px 9px;
  min-height: 24px;
  font-weight: 600;
  color: #ffd28a;
  border: 1px solid rgba(245,166,35,0.45);
  border-radius: 6px;
  background: rgba(245,166,35,0.06);
  white-space: nowrap;
}
.br-btn.br-add:hover { background: rgba(245,166,35,0.15); }
.pal-track-btn {
  font-weight: 600;
  color: #ffd28a !important;
  border-color: rgba(245,166,35,0.45) !important;
  background: rgba(245,166,35,0.06) !important;
  padding: 2px 8px !important;
  white-space: nowrap;
}
.pal-track-btn:hover { background: rgba(245,166,35,0.15) !important; }

/* first-run guidance under the empty timeline */
.tl2-empty-guide {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: 22px 12px;
  border: 1px dashed var(--border2); border-radius: 10px;
  background: rgba(10, 13, 17, 0.4);
}
.tl2-guide-steps { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: center; }
.tl2-guide-step {
  font-size: 0.72rem; color: var(--text2);
  border: 1px solid var(--border); border-radius: 7px;
  padding: 6px 12px; background: rgba(20, 25, 32, 0.8);
}
.tl2-guide-step b {
  display: inline-flex; width: 16px; height: 16px; margin-right: 6px;
  border-radius: 50%; border: 1px solid var(--gen); color: var(--gen);
  align-items: center; justify-content: center; font-size: 0.6rem;
}
.tl2-guide-arrow { color: var(--text3); }
.factory-session-picker { width:min(760px,100%); display:flex; flex-direction:column; gap:6px; }
.factory-session-label { color:var(--text3); font-size:.62rem; font-weight:700; letter-spacing:.1em; text-align:left; text-transform:uppercase; }
.factory-session-list { display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:5px; }
.factory-session-card { min-width:0; min-height:48px; padding:6px 7px; border:1px solid var(--border); border-radius:6px; background:var(--surface2); color:var(--text2); cursor:pointer; text-align:left; }
.factory-session-card:hover { border-color:color-mix(in srgb,var(--accent) 65%,var(--border)); background:color-mix(in srgb,var(--accent) 8%,var(--surface2)); color:var(--text); }
.factory-session-card b,.factory-session-card span { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }.factory-session-card b { font-size:.65rem; }.factory-session-card span { margin-top:3px; color:var(--text3); font-size:.54rem; }
@media (max-width: 760px) { .factory-session-list { grid-template-columns:repeat(2,minmax(0,1fr)); } }

/* region truth: generative = dashed sketch, baked = amber committed (target) */
.tl2-region {
  background: linear-gradient(180deg, rgba(32,38,48,0.92), rgba(23,28,36,0.94));
  border: 1px dashed rgba(148,163,184,0.5);
}
.tl2-region.baked {
  background: linear-gradient(180deg, rgba(72,53,16,0.95), rgba(48,36,12,0.96));
  border: 1px solid rgba(245,166,35,0.75);
}
.tl2-seed-chip {
  flex: none;
  font-family: var(--mono); font-size: 0.56rem; font-variant-numeric: tabular-nums;
  color: #ffd28a;
  border: 1px solid rgba(245,166,35,0.4); border-radius: 4px;
  background: rgba(20, 16, 6, 0.75);
  padding: 0 4px; margin-right: 4px;
  align-self: center;
}
.tl2-baked-tag { font-weight: 700; color: #ffd28a; margin-left: 5px; letter-spacing: 0.04em; }

/* Note editor header (target render) */
.roll-title { font-size: 0.82rem; font-weight: 700; color: var(--text); white-space: nowrap; }
.roll-region { font-size: 0.66rem; color: var(--text2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.roll-legend { display: inline-flex; align-items: center; gap: 6px; font-size: 0.6rem; color: var(--text3); white-space: nowrap; }
.roll-leg-intended { width: 18px; height: 9px; border: 1.5px dashed rgba(95,212,200,0.8); border-radius: 2px; }
.roll-leg-realised { width: 18px; height: 9px; background: rgba(245,166,35,0.85); border-radius: 2px; margin-left: 8px; }
.roll-head { flex-wrap: wrap; gap: 6px 10px; }
/* the producer pill lives in the transport now — the header column was
   too narrow and the pill was being covered by the transport's buttons */
.transport .producer-pill {
  display: inline-flex; align-items: center;
  padding: 5px 12px; text-decoration: none;
  font-size: 0.74rem;
}
.workspace-tab-sep { display: none; }

/* ── Producer audit pass 2026-07-08: professional production surface ── */
.daw {
  /* FE-24 — this was `height: calc(100dvh - 14px)`, which reserved the
     watermark lane by SHORTENING THE SHELL. Measured in a 1440x900 window:
     .daw ran (0,0)-(1440,886), so the page ground (#050810) showed as a 14 px
     black band across the bottom and nowhere else — the "unsymmetrical black
     border" in the report. The lane is still reserved, but as padding INSIDE
     the shell, so the shell fills the viewport on all four edges and
     .app-credit sits on --shell instead of on the page behind it. */
  height: 100dvh;
  padding-bottom: 14px;
  gap: 6px;
  background: var(--shell);
  /* FE-24 REOPENED (owner 2026-08-29): the pass above fixed the bottom edge
     and missed the RIGHT one, because at 1440x900 the shell's content happened
     to be wider than the window. Measured at 1680x900 with the timeline zoomed
     out to a 384 px lane: `.daw` came out **1322.42 px** wide against a
     1680 px viewport, and the 358 px to its right painted `.view`'s page
     ground rgb(5,8,16) — the black band in the report, on the right this time.
     Cause: `.view` is a flex ROW and `.daw` was `flex: 0 1 auto`, so its main
     size was its CONTENT width. A short arrangement made a narrow app. The
     lane still ends where the arrangement ends; the shell around it no longer
     does. `max-width: 100%` still stops a long arrangement from stretching the
     shell past the window (owner 2026-07-09) — wide content scrolls in its own
     panel. */
  width: 100%;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
}

.daw-transport {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 5px;
  padding: 5px 6px;
  margin-bottom: 0;
  background: var(--panel);
  border-color: var(--hairline);
  border-radius: 8px;
  box-shadow: var(--elev-1);
}

.daw-cluster {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 34px;
  padding: 4px 7px;
  background: var(--well);
  border: 1px solid var(--hairline-soft);
  border-radius: 7px;
  min-width: 0;
}

.daw-cluster-arrangement { flex: 1 1 380px; }
.daw-cluster-playback { flex: 0 0 auto; }
.daw-cluster-context { flex: 1 1 310px; }
.daw-cluster-edit { flex: 0 1 260px; }
.daw-cluster-io { flex: 0 1 330px; }

.daw-cluster .btn-sm {
  min-height: 26px;
  padding: 0.26rem 0.56rem;
  font-size: 0.72rem;
  border-radius: 6px;
}

.daw-cluster-playback .btn-sm {
  width: 30px;
  padding-left: 0;
  padding-right: 0;
}

.daw-cluster-playback #arrPlayBtn {
  width: 40px;
  box-shadow: 0 0 0 1px rgba(255,199,104,0.22), 0 8px 18px rgba(245,166,35,0.16);
}

.daw-title {
  color: var(--text);
  letter-spacing: 0.02em;
  min-width: max-content;
}

.daw-title .build-tag {
  color: rgba(154,160,171,0.62);
  font-weight: 500;
}

.daw-ctx-select,
.daw-cluster select,
.daw-cluster input[type="search"] {
  min-height: 26px;
  background: var(--control-bg);
  border-color: var(--control-border);
  color: var(--text);
  border-radius: 6px;
}

/* The name lives in the double-click-to-rename title; the select is a compact
   caret-only switcher (owner 2026-07-09). */
.daw-cluster-arrangement #arrSelect,
.daw-arr-switch {
  flex: none; width: 22px; max-width: 22px; min-height: 26px; padding: 0;
  -webkit-appearance: none; appearance: none;
  color: transparent; font-size: 0; text-indent: -999px; /* hide the option text */
  background: var(--surface2) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M3 4.5l3 3 3-3' fill='none' stroke='%239aa0ab' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>") no-repeat center / 12px;
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
}
.daw-arr-switch:hover { border-color: var(--border2); background-color: var(--surface); }
.daw-arr-name {
  color: var(--text); font-weight: 600; font-size: 0.78rem;
  max-width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding: 3px 7px; border-radius: 5px; cursor: text; letter-spacing: 0.01em;
}
.daw-arr-name:hover { background: var(--surface2); box-shadow: inset 0 0 0 1px var(--border); }
.daw-arr-rename {
  min-height: 26px; width: 150px; box-sizing: border-box;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--accent); border-radius: 5px; padding: 0 7px;
  font: inherit; font-size: 0.78rem; font-weight: 600;
}

.daw-ctx {
  min-height: 26px;
  color: rgba(232,234,238,0.72);
  font-size: 0.68rem;
  white-space: nowrap;
}

.daw-ctx input[type="range"] { width: 86px; }
.daw-ctx output { color: #ffd28a; }

.daw-pos {
  min-height: 26px;
  min-width: 55px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #0b0f15;
  border-color: rgba(73,82,98,0.8);
  color: #f3f5f7;
  font-weight: 700;
}

.zoom-slider { width: 68px; }
.daw-saved { color: #63d69a; }

.daw-main { gap: 0; }

.daw-left,
.daw-center,
.daw-editor {
  background: #171b23;
  border-color: rgba(66, 75, 91, 0.72);
  border-radius: 8px;
}
/* The head column's shared values: how wide it is, what it paints over the
   lanes scrolling beneath it, and the pane its heads sit on. Consumed by
   `.tl2-row > .tl2-head` and the pane rule beside it. */
.daw-center {
  --lane-backdrop: #171b23;
  --tl-head-w: 200px;
  --tl-head-pane: #1b2029;
  /* FE-33 (owner 2026-08-28): "a very light gap at the start of the track when
     scrolled back to the start so it doesn't look like there's still more to
     scroll back to." ONE value, on the ancestor of BOTH horizontally synced
     scrollers (#stripsScroll and the .tl2 inside #timelineGrid), so beat 0
     cannot land at two different x's. Never restate it per element. */
  --tl-lead: 10px;
}
/* The inset goes on the element AFTER the head — the lane, the ruler, the
   guide, the space cylinder — and NOT as extra margin on the head itself. The
   head is `position: sticky`, so a gutter widened there would be permanent;
   a margin on the lane scrolls away with the lane, which is exactly the
   asked-for behaviour (visible at scrollLeft 0, gone once you move forward).
   It also keeps every `clientX − rect.left → beat` conversion correct for
   free: those all measure the lane/ruler/canvas element, whose own rect moves
   with the margin. */
.tl2-row > .tl2-head + * { margin-left: var(--tl-lead, 0px); }

/* Producer editor panel: switcher + body (owner 2026-07-09) */
.editor-panel-wrap { display: flex; flex-direction: column; height: 100%; min-height: 0; gap: 6px; }
.editor-topbar { display: flex; align-items: center; gap: 10px; flex: none; }
/* The mode switcher sits right in BOTH modes, so it never moves under you. */
.editor-topbar-actions { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; }
.editor-topbar .editor-region-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.editor-switch { display: inline-flex; gap: 2px; background: var(--display); border: 1px solid var(--border); border-radius: 7px; padding: 2px; }
.editor-tab {
  font-size: 0.66rem; font-weight: 600; padding: 3px 11px; border-radius: 5px;
  background: none; border: none; color: var(--text2); cursor: pointer;
}
.editor-tab.active { background: var(--surface2); color: var(--text); box-shadow: inset 0 0 0 1px var(--border2); }
.editor-tab:hover:not(.active) { color: var(--text); }
.editor-region-label { font-size: 0.66rem; color: var(--text3); }
.editor-body { flex: 1; min-height: 0; overflow: auto; position: relative; }
/* the region layers panel renders inline here, not as a positioned overlay */
.editor-body .m2-layers-panel { position: static; inset: auto; height: auto; background: transparent; padding: 0; }
.editor-body-roll .roll-panel { margin-top: 0; }

/* Bake overlay: a blank roll behind a prompt */
.roll-bake-prompt { position: relative; }
.roll-blank {
  width: 100%; height: 180px; display: block; border-radius: 6px; opacity: 0.5;
  background:
    repeating-linear-gradient(to right, rgba(154,160,171,0.07) 0 1px, transparent 1px 56px),
    repeating-linear-gradient(to bottom, rgba(154,160,171,0.06) 0 1px, transparent 1px 20px),
    var(--display);
}
.roll-bake-overlay {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px; text-align: center;
}
.roll-bake-msg { font-size: 0.78rem; color: var(--text2); max-width: 440px; line-height: 1.5; }

/* ── Mixer view (owner 2026-07-09) ─────────────────────────────────────── */
/* FE-8: .mixer-toggle's `position: fixed` bottom-right floater is gone — the
   control is now #mixerToggle.daw-mixer-btn, a view tool in the producer
   transport beside undo and zoom (see .daw-mixer-btn below). */
.daw-mixer-btn { gap: 5px; }
.daw-mixer-btn.active {
  color: var(--accent2);
  border-color: rgba(245,166,35,0.55);
  background: rgba(245,166,35,0.12);
}

/* One title bar shared with the patch inspector, so "what am I looking at and
   how do I leave" reads the same in both editor modes. */
.mixer-shell { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.mixer-titlebar {
  display: flex; align-items: baseline; gap: 9px; flex: none;
  min-height: 30px; padding: 4px 10px;
  border-bottom: 1px solid var(--hairline-soft);
}
.mixer-title {
  color: var(--text2); font-size: 0.6rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
}
.mixer-title-sub { color: var(--text3); font-size: 0.6rem; font-variant-numeric: tabular-nums; }
.mixer-titlebar .patch-close { margin-left: auto; align-self: center; }

.mixer-panel { display: flex; gap: 8px; height: 100%; min-height: 0; width: 100%; max-width: 100%; overflow: hidden; }
.mixer-tracks { display: flex; gap: 6px; overflow-x: auto; overflow-y: hidden; flex: 1 1 0; min-width: 0; padding-bottom: 4px; }
.mixer-empty { color: var(--text3); font-size: 0.72rem; padding: 20px; }
.mixer-track {
  /* FE-13: 124px left the strip's fader ~40px of travel once the label and
     the readout had taken their share. 148 gives it the owner's "appropriate
     horizontal space" — the strip scrolls, so width here is cheap. */
  flex: 0 0 148px; display: flex; flex-direction: column; gap: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-top: 2px solid hsl(var(--track-h, 210) 65% 52%); border-radius: 7px;
  padding: 7px; min-height: 0;
}
.mixer-track-head { display: flex; align-items: center; gap: 6px; }
.mixer-track-hue { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.mixer-track-name { font-size: 0.72rem; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* FE-8: `flex: 1 1 auto` made the region list eat every spare pixel, so a
   channel with one region showed a screen of empty strip between its name and
   its space map. It takes the room it needs and scrolls past that; the strip
   is then as tall as its content, not as tall as the panel. */
.mixer-region-stack { display: flex; flex-direction: column; gap: 5px; overflow-y: auto; flex: 0 1 auto; min-height: 0; }
.mixer-no-regions { font-size: 0.62rem; color: var(--text3); font-style: italic; padding: 2px; }
.mixer-region-row { display: flex; align-items: center; gap: 5px; }
/* Tabular numerals: these readouts move while audio runs, and proportional
   digits make the column jitter under a changing value. */
/* FE-13: the readout carries its unit now (fmtDb), so it needs the room. */
.mixer-db { font-size: 0.56rem; color: var(--text3); font-family: var(--mono); font-variant-numeric: tabular-nums; width: 48px; text-align: right; flex: none; white-space: nowrap; }
/* ── The region level BLOCK (owner 2026-07-09; restored 2026-08-28) ───────
   "Put the patch levels back to the old filled in block with the name of the
   patch, the track volume being the level of how filled in it is."

   This is deliberately NOT the fader: a named block that fills is a different
   kind of control from a cap in a groove, and the strip has one of each.

   Two things are not as they were.
   · WIDTH. It was `width: 60px; flex: none` in a 110px strip, so it read as a
     small swatch rather than a level — "make sure it fills the proper width".
     It now takes the strip.
   · GEOMETRY. It carried a 1px `border`, and with the global `border-box` the
     fill (absolutely positioned, so laid out against the PADDING box) spanned
     58 of the block's 60px while the drag read its fraction off the 60px
     border box. The two disagreed by a pixel at each end and the fill could
     never reach the edge. The border is an inset shadow now, so the box the
     pointer measures and the box the fill paints are the same box. */
.mixer-vol-block {
  position: relative; flex: 1 1 auto; min-width: 0; height: 22px;
  background: var(--well);
  border: none;
  box-shadow: inset 0 0 0 1px var(--hairline-soft);
  border-radius: var(--radius-sm); overflow: hidden;
  cursor: ew-resize; user-select: none; touch-action: none;
}
.mixer-vol-block:hover { box-shadow: inset 0 0 0 1px var(--control-border); }
.mixer-vol-block:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mixer-vol-fill {
  position: absolute; left: 0; top: 0; bottom: 0;
  background: linear-gradient(90deg, hsl(var(--track-h,210) 55% 42%), hsl(var(--track-h,210) 62% 56%));
}
.mixer-vol-name {
  position: absolute; left: 6px; top: 50%; right: 5px;
  transform: translateY(-50%);
  font-size: 0.58rem; font-weight: 600; line-height: 1.1; color: #eef2f6;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-shadow: 0 1px 2px rgba(0,0,0,0.75); pointer-events: none;
}

/* horizontal faders (drag left/right) */
/* ── FE-8: a fader groove is not a meter (owner 2026-08-27) ────────────────
   "The track volumes look like they have signal when it is paused."
   They did, and they could not have meant anything: the groove was filled
   edge-to-edge with the track's hue, and the MASTER groove with
   `linear-gradient(90deg, #4ade80, #eab308 78%, #ef4444)` — green→amber→red,
   the universal level ramp — painted at full saturation whether or not audio
   was running. A control that always looks the same cannot indicate anything.

   Worse, a REAL meter was already in the same strip: .fader-meter (top of this
   sheet) tracks the signal green → amber past −12 dB → red in the last 3 dB of
   headroom, with a 2s peak-hold tick. Two meter-looking objects per channel,
   and the loud one was the fake. (FE-36 finished the thought: that meter is
   the groove itself now, and there is no second object at all.)

   So the groove goes to a neutral recess and the level ramp belongs to the
   meter alone.

   FE-13 (2026-08-28) finishes the job: the groove is now the VALUE fill in
   the track's hue, the meter is the 3px strip under it, and the look, the
   cap and the sizing all come from `.fader` at the top of this sheet. All
   that is left here is how much room the fader takes in the strip. */
.mixer-fader { flex: 1 1 auto; min-width: 0; width: auto; }

.mixer-space-wrap { display: flex; flex-direction: column; align-items: center; gap: 3px; flex: none; }
.mixer-space-cv { width: 108px; height: 108px; background: var(--display); border: 1px solid var(--border); border-radius: 6px; cursor: crosshair; }
.mixer-additive { display: flex; align-items: center; gap: 4px; font-size: 0.6rem; color: var(--text2); }
/* ── FE-13: the squeeze (owner 2026-08-28) ────────────────────────────────
   "space-saving horizontal ones need to have appropriate horizontal space
   (mixer faders are squished)."  They were: `flex: 1` in a 108px content box
   shared with a 34px TRACK label and a 32px readout left about 40px of
   travel — a nudge control, not a level control. The label and the readout
   move ABOVE the fader (which is how a channel strip is laid out anyway), so
   the fader gets the strip's full width and neither text can squeeze it. */
.mixer-track-master {
  display: flex; flex-direction: column; align-items: stretch; gap: 2px;
  padding-top: 4px; border-top: 1px solid var(--border);
}
.mixer-tm-top { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.mixer-track-master .fader-meter { display: flex; width: 100%; min-width: var(--fader-min-travel); }
.mixer-track-master .fader-meter input[type="range"] { width: 100%; }
.mixer-tm-label {
  font-size: 0.55rem; letter-spacing: 0.08em; color: var(--text3);
  flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mixer-tm-top .mixer-db { margin-left: auto; }

.mixer-master {
  flex: none; width: 108px; display: flex; flex-direction: column; align-items: center; gap: 6px;
  background: var(--surface2); border: 1px solid var(--border2); border-radius: 7px; padding: 8px 7px;
}
.mixer-master-label { font-size: 0.55rem; letter-spacing: 0.1em; font-weight: 700; color: var(--text2); flex: none; }
/* FE-8: "the master fader is a weird disconnected pin". It was two siblings
   8px apart — a meter <canvas> and, separately, a range input rotated −90°.
   A bare rotated slider draws no groove, so all that was left of it was a
   thumb floating in space next to an unrelated dark rectangle. They are one
   control now: a single recessed well holds the meter and the fader with no
   gap between them, and the fader gets a visible groove (below) so there is
   something for the thumb to sit ON. */
.mixer-master-body {
  flex: 1; min-height: 40px;
  display: flex; gap: 0; align-items: stretch; justify-content: center;
  padding: 5px 4px;
  background: var(--well);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--radius-sm);
}
.mixer-master-meter { width: 22px; height: 100%; background: var(--display); border-radius: 3px; }
.mixer-master .mixer-db { width: auto; text-align: center; flex: none; font-variant-numeric: tabular-nums; }
/* FE-13: the master is now the `.fader--v` component — a ridged cap in a slot
   with the numbered dB scale beside it, as in the Logic channel fader the
   owner attached. The slot's length is still set to the well's height in JS
   (the element is rotated −90°, so its `width` is the travel). */
.mixer-fader-slot {
  position: relative; width: 30px; height: 100%; min-height: 60px; flex: none;
  display: flex; align-items: center; justify-content: center;
}
.mixer-master-fader { position: absolute; }
.mixer-master .fader-scale { margin-left: 1px; }
/* Too short for a numbered scale: hide it and take the width back. */
.mixer-master.no-scale .fader-scale { display: none; }
.mixer-master.no-scale { width: 82px; }

.daw-left {
  padding: 8px;
  box-shadow: inset -1px 0 0 rgba(255,255,255,0.025);
}

.daw-center {
  padding: 8px 10px 10px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.025);
}

.daw .section-label {
  color: rgba(205,214,226,0.74);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-align: center;
  margin-bottom: 0.48rem;   /* ~20% tighter than the 0.6rem base */
  margin-top: 0;
}
.section-label-row { display:flex; align-items:center; gap:4px; }
.section-label-row .section-label-title { flex:1; text-align:center; }
.pal-collapse { background:none; border:none; color:var(--text3); cursor:pointer; font-size:0.7rem; line-height:1; padding:0 2px; }
.pal-collapse:hover { color:var(--text); }
.pal-info { font-size:0.95rem; }
.pal-info.on { color:var(--accent); }
.pal-info.on:hover { color:var(--accent2); }
/* Minimised palette: patches collapse to a browser-row-sized strip (icons +
   name + actions only); the parts/detail block hides until expanded. */
.daw-palette.min .pal-module-names,
.daw-palette.min .pal-draft-note,
.daw-palette.min .pal-kind { display:none; }
.daw-palette.min .palette-item { padding:4px 7px; }

.daw-browser input[type="search"] {
  min-height: 30px;
  margin: 0.4rem 0 0.45rem;
  background: #0d1117;
  border-color: rgba(64,73,88,0.78);
}

.browser-filters { gap: 4px; }

.browser-row {
  min-height: 30px;
  padding: 4px 6px;
  border-color: rgba(54,61,74,0.45);
  border-radius: 6px;
  background: rgba(12, 16, 22, 0.28);
}

.browser-row:hover {
  background: rgba(35, 42, 54, 0.88);
  border-color: rgba(82, 93, 112, 0.84);
}

.br-name {
  font-size: 0.73rem;
  color: rgba(242,244,247,0.92);
}

.br-kind {
  color: rgba(154,160,171,0.78);
  max-width: 72px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.br-btn {
  width: 24px;
  height: 24px;
  background: rgba(10,13,18,0.7);
  border-color: rgba(58,66,80,0.72);
}

.br-btn.br-add {
  width: auto;
  min-width: 56px;
  height: 24px;
  padding: 3px 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.daw-palette {
  margin-top: 6px;
  padding-top: 6px;
  border-top-color: rgba(66,75,91,0.82);
}

.palette-rack { gap: 5px; }

.palette-item {
  gap: 5px;
  padding: 7px 7px 6px;
  background: rgba(23,28,37,0.9);
  border-color: rgba(70,82,101,0.72);
  border-left-width: 3px;
  border-radius: 7px;
}

.pal-name {
  font-size: 0.74rem;
  color: rgba(244,246,249,0.94);
}

.pal-actions { gap: 4px; }

.pal-btn {
  min-height: 22px;
  border-radius: 5px;
  background: rgba(11, 15, 21, 0.72);
}

.pal-half {
  margin-top: 4px;
  background: #0e1218;
  border: 1px solid rgba(55,63,76,0.72);
  border-radius: 5px;
  overflow: hidden;
}

.pal-half-btn {
  border: 0;
  border-left: 1px solid rgba(55,63,76,0.72);
  border-radius: 0;
  background: transparent;
  min-height: 21px;
}

.pal-half-btn:first-child { border-left: 0; }

.pal-half-btn.active {
  background: rgba(245,166,35,0.14);
  color: #ffd28a;
}

.strips-panel {
  margin-bottom: 6px;
  padding: 2px 0 5px;
  border-bottom-color: rgba(66,75,91,0.82);
}

.gs-head {
  min-height: 24px;
  background: #151a22;
  border-color: rgba(58,66,80,0.72);
}

.gs-chevron {
  width: 100%;
  text-align: left;
  color: rgba(213,220,232,0.78);
  font-size: 0.61rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.gs-chevron:hover { color: #f3f5f7; }

/* Global scale/space active indicators (owner 2026-07-09) */
.gs-chevron.gs-active { color: #f3f5f7; }
.gs-onpip { color: var(--acc); font-size: 0.72em; margin-left: 4px; vertical-align: 1px; }
/* Harmonic-guide + Global-space headers share one layout: icon → label → pip
   on the left, the collapse caret pinned to the right edge, so the two rows
   line up (owner 2026-07-15). */
.gs-head-label { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gs-caret { margin-left: auto; flex: none; padding: 0 4px 0 6px; text-align: right; }
/* Global space is a toggle button that GLOWS when on */
.sp-toggle { flex: 1 1 auto; width: auto; }
.sp-toggle.sp-active { color: #eaf6ff; text-shadow: 0 0 10px rgba(56,189,248,0.6); }
.sp-onpip { color: #38bdf8; font-size: 0.72em; margin-left: 4px; vertical-align: 1px; text-shadow: 0 0 8px rgba(56,189,248,0.9); }
.sp-expand { flex: 0 0 auto; width: auto !important; padding: 0 4px 0 6px; text-align: right; }
/* Collapsed slim cylinder — sits in the button row, top aligned with it. The
   box must shrink to the slim canvas (override .sp-cyl-wrap's 105px floor). */
.tl2-sp-row.sp-collapsed-row { align-items: flex-start; }
.sp-cyl-wrap.sp-cyl-collapsed {
  min-height: 0;
  /* Inset outline again — a border here shifted the slim cylinder 1px off the
     lanes it is beat-aligned with. */
  border: 0;
  border-radius: 5px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(56,189,248,0.26),
              inset 0 0 16px -7px rgba(56,189,248,0.45);
}

.gs-strip {
  background: #0c1117;
  box-shadow: inset 0 0 0 1px rgba(58,66,80,0.72);
}

.tl2 { padding-bottom: 6px; }

.tl2-row { margin-bottom: 5px; }

.tl2-head {
  border-radius: 6px;
  border-color: rgba(58,66,80,0.72);
}

.tl2-track-head {
  min-height: 48px;
  padding: 6px 7px;
  /* Opaque: this cell sits over the lane it scrolls above (see .tl2-head). */
  background:
    linear-gradient(90deg, hsla(var(--track-h, 36), 76%, 56%, 0.88) 0 3px, transparent 3px),
    linear-gradient(180deg, rgb(31,37,48), rgb(20,25,33));
  border-color: rgba(68,78,96,0.82);
}

.tl2-track-head.sp-sel {
  border-color: hsla(var(--track-h, 36), 80%, 68%, 0.88);
}

.tl2-head-top { gap: 5px; }

.tl2-hue {
  width: 11px;
  height: 11px;
  border-radius: 4px;
  box-shadow: 0 0 0 1px rgba(255,255,255,0.14), 0 0 10px hsla(var(--track-h, 36), 70%, 55%, 0.22);
}

.tl2-name {
  font-size: 0.74rem;
  font-weight: 700;
  color: rgba(244,246,249,0.94);
}

.tl2-db {
  color: rgba(204,214,229,0.66);
  font-size: 0.56rem;
}

.tl2-head-ctl { gap: 4px; }

.tl2-ms {
  width: 21px;
  height: 21px;
  border-radius: 5px;
  background: rgba(10,13,18,0.72);
  border-color: rgba(64,73,88,0.78);
}

.tl2-ms.on {
  color: #ffd28a;
  border-color: hsla(var(--track-h, 36), 76%, 58%, 0.66);
  background: hsla(var(--track-h, 36), 72%, 45%, 0.16);
}

.tl2-head .tl-gain {
  min-width: 0;
}

.tl2-ruler {
  height: 26px;
  background:
    repeating-linear-gradient(to right, rgba(154,160,171,0.24) 0, rgba(154,160,171,0.24) 1px, transparent 1px, transparent 56px),
    repeating-linear-gradient(to right, rgba(154,160,171,0.075) 0, rgba(154,160,171,0.075) 1px, transparent 1px, transparent 14px),
    #0c1117;
  border-color: rgba(58,66,80,0.82);
}

.tl2-bar {
  top: 3px;
  color: rgba(205,214,226,0.62);
}

.tl2-lane {
  height: 48px;
  background:
    repeating-linear-gradient(to right, rgba(154,160,171,0.16) 0, rgba(154,160,171,0.16) 1px, transparent 1px, transparent 56px),
    repeating-linear-gradient(to right, rgba(154,160,171,0.055) 0, rgba(154,160,171,0.055) 1px, transparent 1px, transparent 14px),
    #0c1117;
  border-color: rgba(42,49,62,0.96);
  border-radius: 4px;
}

.tl2-region {
  top: 5px;
  bottom: 5px;
  min-width: 26px;
  background:
    linear-gradient(180deg, hsla(var(--track-h, 36), 54%, 34%, 0.44), hsla(var(--track-h, 36), 52%, 22%, 0.42)),
    linear-gradient(180deg, rgba(25,31,40,0.96), rgba(16,21,29,0.96));
  border: 1px dashed hsla(var(--track-h, 36), 80%, 63%, 0.72);
  border-radius: 6px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.055), inset 0 -1px 0 rgba(0,0,0,0.42);
}

.tl2-region::after {
  content: "";
  position: absolute;
  left: 12px;
  right: 10px;
  top: 50%;
  height: 17px;
  transform: translateY(-36%);
  opacity: 0.36;
  background:
    repeating-linear-gradient(to right,
      transparent 0 9px,
      hsla(var(--track-h, 36), 86%, 68%, 0.9) 9px 15px,
      transparent 15px 25px);
  -webkit-mask-image: repeating-linear-gradient(to bottom, transparent 0 3px, #000 3px 5px, transparent 5px 8px);
  mask-image: repeating-linear-gradient(to bottom, transparent 0 3px, #000 3px 5px, transparent 5px 8px);
  pointer-events: none;
}

.tl2-region.baked {
  background:
    linear-gradient(180deg, hsla(var(--track-h, 36), 62%, 36%, 0.55), hsla(var(--track-h, 36), 55%, 22%, 0.5)),
    #121821;
  border-style: solid;
  border-color: hsla(var(--track-h, 36), 86%, 68%, 0.84);
}

.tl2-region.selected {
  border-color: rgba(241,245,249,0.96);
  box-shadow:
    0 0 0 1px rgba(241,245,249,0.62),
    0 0 0 3px hsla(var(--track-h, 36), 82%, 58%, 0.18),
    inset 0 1px 0 rgba(255,255,255,0.08);
}

.tl2-region-label,
.tl2-seed-chip,
.tl2-baked-tag,
.tl2-gain-tag,
.tl2-badges,
/* Keep these above the shape SVG, but DON'T override their absolute
   positioning (the resize handle must stay pinned to the region's right edge
   so the ew-resize cursor is grabbable; loop ticks sit at their `left`). */
.tl2-resize,
.tl2-looptick {
  z-index: 2;
}

.tl2-region-label {
  font-size: 0.64rem;
  font-weight: 650;
  color: rgba(244,246,249,0.93);
  text-shadow: 0 1px 2px rgba(0,0,0,0.65);
}

.tl2-seed-chip {
  color: #ffe0a3;
  border-color: hsla(var(--track-h, 36), 80%, 63%, 0.62);
  background: rgba(8, 10, 14, 0.78);
  box-shadow: 0 0 0 1px rgba(0,0,0,0.22);
}

.tl2-gain-tag {
  border-color: hsla(var(--track-h, 36), 80%, 63%, 0.48);
}

.tl2-resize {
  width: 9px;
  border-right-color: rgba(241,245,249,0.42);
}

.tl2-newtrack,
.tl2-empty-guide {
  background: rgba(10,14,20,0.52);
  border-color: rgba(76,86,104,0.7);
}

.daw-center .region-toolbar {
  min-height: 52px;
  margin-top: 8px;
  padding: 8px 10px;
  gap: 8px;
  flex-wrap: wrap;
  background: linear-gradient(180deg, rgba(26,31,41,0.98), rgba(17,21,29,0.98));
  border: 1px solid rgba(66,75,91,0.82);
  border-radius: 8px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}

.daw-center .region-toolbar .btn-sm {
  min-height: 30px;
  padding: 0.34rem 0.72rem;
  border-radius: 6px;
}

.daw-center .region-toolbar .btn-primary {
  box-shadow: 0 8px 18px rgba(245,166,35,0.14);
}

.daw-center .toolbar-hint {
  color: rgba(205,214,226,0.72);
  font-size: 0.73rem;
}

.region-gain-label {
  min-height: 30px;
  padding: 0 6px;
  background: rgba(10,13,18,0.52);
  border: 1px solid rgba(58,66,80,0.72);
  border-radius: 6px;
}

@media (max-width: 1120px) {
  .daw-cluster-arrangement { flex-basis: 360px; }
  .daw-cluster-context { flex-basis: 290px; }
  .daw-cluster-io { flex-basis: 300px; }
  .daw-left { padding: 7px; }
  /* A narrow window buys the lanes back some room by narrowing the column.
     Set the VARIABLE, never `.tl2-head { width }` — the panel behind the
     heads reads the same variable, and a private copy here put the two out of
     register the moment either changed (owner 2026-08-21). */
  .daw-center { --tl-head-w: 190px; }
  .daw-center .region-toolbar {
    gap: 5px;
    padding: 7px 8px;
  }
  .daw-center .region-toolbar .btn-sm {
    padding: 0.3rem 0.58rem;
  }
  .region-gain-label {
    padding: 0 5px;
    gap: 0.24rem;
  }
  .region-gain-label input[type="range"] {
    width: 56px;
  }
}

/* ── V2.2 macro browser (one preset surface, collapsed ↔ expanded) ── */
.m2-lib { display: flex; flex-direction: column; gap: 6px; flex: none; }
/* Sub-note page: the browser is docked like any other pane — cards on top,
   the library list always underneath, scrolling in place. */
.m2-lib.docked { flex: 1 1 0; min-height: 0; position: relative; }
.m2-lib.docked .m2-presets { flex: none; }
.m2-lib.open {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 58%;
  z-index: 7;
  background: rgba(13, 17, 23, 0.98);
  border: 1px solid var(--border2); border-radius: 12px 12px 10px 10px;
  box-shadow: 0 -14px 40px rgba(0, 0, 0, 0.55);
  padding: 8px 10px;
}
/* Row 1 — SOURCE + SEARCH: never wraps. The source tabs are a segmented
   control (one shared border, no gaps) so they read as "pick one place",
   distinct from the filter pills on row 2. Search takes the slack. */
.m2-lib-head { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; min-width: 0; }
.m2-lib-title {
  font-size: 0.56rem; letter-spacing: 0.14em; color: var(--text3); font-weight: 600;
  flex: none;
}
.m2-lib-chip {
  background: none; border: 1px solid var(--border); border-radius: 6px;
  color: var(--text2); font: inherit; font-size: 0.62rem; padding: 3px 9px; cursor: pointer;
  white-space: nowrap;
}
.m2-lib-chip:hover { border-color: var(--border2); color: var(--text); }
.m2-lib-chip.active { border-color: var(--gen); color: #ffd28a; background: rgba(245,166,35,0.08); }
.m2-lib-expand { border-color: rgba(245,166,35,0.5); color: #ffd28a; font-weight: 600; }
.m2-lib-fav.active { border-color: #e5484d; color: #ff9a9e; background: rgba(229,72,77,0.08); }

.m2-lib-tabs {
  display: inline-flex; flex: none;
  border: 1px solid var(--border); border-radius: 7px; overflow: hidden;
  background: rgba(10, 13, 17, 0.5);
}
.m2-lib-tabs .m2-lib-chip {
  border: none; border-radius: 0; padding: 3px 11px;
  border-right: 1px solid var(--border);
}
.m2-lib-tabs .m2-lib-chip:last-child { border-right: none; }
.m2-lib-tabs .m2-lib-chip.active {
  background: rgba(245, 166, 35, 0.14); color: #ffd28a;
}
.m2-lib-search {
  background: var(--display); border: 1px solid var(--border); border-radius: 6px;
  color: var(--text); font: inherit; font-size: 0.66rem; padding: 4px 9px;
  flex: 1 1 auto; min-width: 90px; max-width: 300px;
}
.m2-lib-search:focus { outline: none; border-color: rgba(245, 166, 35, 0.5); }

/* Row 2 — the family pills alone (macro only). Hearted moved up to row 1. */
.m2-lib-filters {
  display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
  padding-top: 1px;
}
/* Hearted sits beside the search, before the favourites toggle. */
.m2-lib-head .m2-lib-fav { flex: none; margin-left: 2px; }
.m2-lib-save { display: inline-flex; align-items: center; gap: 5px; margin-left: auto; }
.m2-lib-save input[type=text] {
  background: var(--display); border: 1px solid var(--border); border-radius: 6px;
  color: var(--text); font: inherit; font-size: 0.68rem; padding: 3px 8px; width: 130px;
}
.m2-lib-save select { font-size: 0.66rem; }
.m2-lib-list {
  flex: 1; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: 3px;
  border-top: 1px solid var(--border); padding-top: 6px;
}
.m2-lib-list::-webkit-scrollbar { width: 7px; }
.m2-lib-list::-webkit-scrollbar-thumb { background: rgba(120,130,150,0.3); border-radius: 4px; }
.m2-lib-row {
  display: flex; align-items: center; gap: 9px;
  padding: 4px 8px; border-radius: 6px;
  font-size: 0.72rem; color: var(--text);
}
.m2-lib-row:hover { background: rgba(255,255,255,0.03); }
.m2-lib-name { flex: 0 1 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.m2-lib-tags { flex: 1; display: flex; gap: 4px; overflow: hidden; }
.m2-tag {
  font-style: normal; font-size: 0.58rem; color: var(--text3);
  border: 1px solid var(--border); border-radius: 4px; padding: 1px 6px; white-space: nowrap;
}
/* layered presets: base sound + N sub-note sources */
.m2-tag-layers { color: #8ee3ff; border-color: rgba(56,189,248,0.35); }
/* browser presets drag onto the LAYERS strip */
[data-m2-drag] { cursor: grab; }
[data-m2-drag]:active { cursor: grabbing; }
.layer-strip.drop-ok, .layer-area.drop-ok {
  outline: 1px dashed rgba(56,189,248,0.7);
  outline-offset: -1px;
  background: rgba(56,189,248,0.07);
}
/* floating drop zone: appears while dragging a preset, so a layer target is
   always in view even when the expanded library covers the LAYERS strip */
.m2-drop-layer {
  position: fixed;
  top: 64px; left: 50%;
  transform: translateX(-50%);
  z-index: 400;
  padding: 16px 28px;
  border: 2px dashed rgba(56,189,248,0.65);
  border-radius: 12px;
  background: rgba(10, 16, 24, 0.94);
  color: #8ee3ff;
  font-size: 0.78rem; font-weight: 600;
  white-space: nowrap;
  box-shadow: 0 8px 30px rgba(0,0,0,0.5);
}
.m2-drop-layer.drop-ok {
  border-color: #38bdf8;
  background: rgba(56,189,248,0.16);
  color: #d9f3ff;
}
.m2-drop-layer[hidden] { display: none; }
.m2-lib-stars { flex: none; font-size: 0.66rem; color: #ffd28a; font-variant-numeric: tabular-nums; width: 52px; }
.m2-lib-heart {
  background: none; border: none; cursor: pointer;
  color: rgba(148,163,184,0.4); font-size: 0.85rem; line-height: 1; padding: 2px 4px;
}
.m2-lib-heart:hover { color: rgba(255,154,158,0.8); }
.m2-lib-heart.on { color: #e5484d; }

/* ── Studio sections audit pass 2026-07-08: Macro / Sub-note / Scale Lab ── */
.explore-dashboard {
  background:
    linear-gradient(180deg, rgba(17,25,34,0.98), rgba(6,10,15,0.99)),
    linear-gradient(90deg, rgba(245,166,35,0.025), rgba(56,189,248,0.025));
  border-color: rgba(57, 78, 96, 0.96);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.035),
    inset 0 18px 42px rgba(255,255,255,0.018),
    0 20px 70px rgba(0,0,0,0.54);
}

.explore-dashboard .card,
.explore-dashboard .visual-card {
  background:
    linear-gradient(180deg, rgba(20,29,39,0.98), rgba(8,13,19,0.99));
  border-color: rgba(63, 83, 101, 0.9);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.045),
    inset 0 -18px 42px rgba(0,0,0,0.16);
}

.explore-dashboard .section-label,
.m2-rail-head,
.m2-presets-label,
.ch-focus-label,
.ch-lens-label,
.print-hint {
  color: rgba(205, 216, 228, 0.74);
  font-weight: 750;
}

.explore-top {
  border-right-color: rgba(63, 83, 101, 0.56);
}

.explore-top h1 {
  color: rgba(245, 248, 251, 0.96);
  letter-spacing: 0.07em;
}

.build-tag {
  color: rgba(150, 162, 177, 0.72);
}

.workspace-tabs {
  background: rgba(5, 8, 13, 0.9);
  border-color: rgba(70, 88, 106, 0.92);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.025),
    inset 0 -8px 16px rgba(0,0,0,0.35);
}

.workspace-tab {
  color: rgba(172, 184, 198, 0.74);
}

.workspace-tab:hover:not(.active) {
  color: rgba(235, 241, 247, 0.9);
  background: rgba(255,255,255,0.035);
}

.workspace-tab.active {
  color: #ffd690;
  background: linear-gradient(180deg, rgba(245,166,35,0.26), rgba(245,166,35,0.08));
  box-shadow:
    inset 0 -2px 0 rgba(245,166,35,0.82),
    0 0 20px rgba(245,166,35,0.12);
}

.transport-card .transport-round,
.transport-card .btn,
.transport-card .seed-box,
.top-save-bar input[type="text"],
.top-save-bar select,
.top-rating-row {
  border-color: rgba(62, 79, 96, 0.84);
}

.transport-card .btn-secondary,
.transport-card .transport-stop,
.transport-card .seed-box,
.top-rating-row {
  background: rgba(11, 16, 23, 0.68);
}

.transport-card .producer-pill {
  background: rgba(245,166,35,0.09);
  border-color: rgba(245,166,35,0.62) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}

.macro2-card,
.subnote-full-card {
  border-color: var(--hairline) !important;
}

/* FE-1 (owner 2026-08-27): "the pages macro, subnote and scale lab … don't
   match the colours and basic design elements for panels and surfaces of the
   producer tab, which is aesthetically more pleasing."
   This block was the reason. It gave the three studio pages a THIRD surface
   language — a two-stop gradient with its own border and its own inset — while
   the producer's 2026-07-08 audit pass used flat opaque grounds. Two different
   answers to "what is a panel", neither of them named, so neither could be
   pointed at the other. Both now read from the tokens in :root, so the
   producer and the studio pages are the same surface by construction. */
.m2-rail,
.m2-inspector,
.m2-presets,
.ch-inspector,
.td-side,
.ch-card,
.ch-ch,
.tone-stage {
  background: var(--panel);
  border-color: var(--hairline);
  box-shadow: var(--elev-1);
}

/* A rail button at rest is a recess in the panel — no border, no gradient.
   Its hue is reserved for hover and active (FE-6). */
.m2-rail-btn {
  background: var(--well);
  border-color: transparent;
  color: var(--text2);
}

.m2-rail-btn:hover {
  border-color: var(--hairline);
  background: var(--control-bg);
  color: var(--text);
}

.m2-rail-btn.active {
  color: var(--text);
  background: color-mix(in srgb, var(--rail-c, var(--accent)) 12%, var(--control-bg));
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--rail-c, var(--accent)) 72%, transparent),
    inset 3px 0 0 var(--rail-c, var(--accent)),
    0 0 18px -8px var(--rail-c, var(--accent));
}

.m2-inspector {
  border-left: 2px solid rgba(245,166,35,0.28);
}

.m2-chip,
.scale-combo-btn,
.ch-chip,
.print-band,
.seg-control,
.pb-chip {
  background: rgba(8, 12, 18, 0.72);
  border-color: rgba(59, 75, 92, 0.84);
}

.m2-chip b,
.ch-readout b {
  color: rgba(244,247,250,0.96);
}

.visualiser-wrap,
#cvTonePrint,
#cvLens,
.space-pad,
.body-mini,
.ch-string,
.ch-thumb {
  background: #080d13;
  border-color: rgba(58,75,92,0.88);
}

.m2-presets {
  padding: 8px 10px;
}

.m2-preset {
  background: linear-gradient(180deg, rgba(25,32,42,0.96), rgba(10,14,20,0.98));
  border-color: rgba(58,75,92,0.86);
}

.m2-preset:hover {
  border-color: rgba(245,166,35,0.78);
  box-shadow: 0 0 0 1px rgba(245,166,35,0.16);
}

.m2-preset.sel {
  border-color: rgba(61,157,246,0.92);
  box-shadow: 0 0 0 1px rgba(61,157,246,0.68), 0 0 20px -8px rgba(61,157,246,0.9);
}

.m2-preset-name,
.m2-lib-name {
  color: rgba(244,247,250,0.94);
}

.m2-bottom,
.engine-state,
.stat,
.m2-status-chip {
  border-color: rgba(58,75,92,0.72);
}

.ch-card {
  min-height: 68px;
}

.ch-card:hover {
  border-color: rgba(120, 141, 163, 0.86);
}

.ch-card.active {
  background: linear-gradient(180deg, rgba(28,35,46,0.96), rgba(10,15,21,0.98));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04), 0 0 18px -10px currentColor;
}

.ch-excitor.active { border-color: rgba(245,166,35,0.88); }
.ch-resonator.active { border-color: rgba(88,166,255,0.88); }
.ch-body.active { border-color: rgba(180,142,222,0.88); }
.ch-space.active { border-color: rgba(88,214,169,0.88); }

.ch-card-n,
.td-field-title {
  color: rgba(237,243,249,0.94);
}

.ch-card-sum,
.ch-ins-d,
.ch-caption {
  color: rgba(150, 164, 180, 0.78);
}

.td-tabs,
.pal-half,
.seg-control {
  background: rgba(7, 11, 17, 0.78);
}

.td-tab.active,
.seg-btn.active,
.print-band.active,
.ch-chip.active {
  box-shadow: inset 0 -2px 0 currentColor;
}

.ch-status {
  color: rgba(154,168,184,0.82);
  border-top-color: rgba(58,75,92,0.78);
}

.layer-row,
.m2-lib-row {
  background: rgba(10,14,20,0.38);
  border-color: rgba(58,75,92,0.35);
}

.layer-row:hover,
.m2-lib-row:hover {
  background: rgba(34, 43, 56, 0.78);
  border-color: rgba(82, 101, 121, 0.84);
}

.m2-lib.open {
  background: rgba(10, 14, 20, 0.985);
  border-color: rgba(75, 94, 114, 0.95);
}

.m2-lib-title {
  color: rgba(205, 216, 228, 0.74);
}

/* Studio responsive shell 2026-07-08: native panels, no scaled canvas. */
body.explore-mode {
  align-items: stretch;
  justify-content: stretch;
}

body.explore-mode #app,
body.explore-mode .view {
  width: 100vw;
  height: 100dvh;
  min-height: 0;
  align-items: stretch;
  justify-content: stretch;
}

body.explore-mode .view {
  display: flex;
}

.explore-dashboard {
  width: 100%;
  height: 100dvh;
  min-height: 0;
  max-height: none;
  transform: none !important;
  transform-origin: top left !important;
  grid-template-columns:
    clamp(190px, var(--dash-c1, 260px), 430px)
    minmax(0, 1fr)
    clamp(230px, 22vw, 360px);
  grid-template-rows:
    40px
    minmax(96px, 18vh)
    minmax(0, 1fr)
    minmax(112px, 19vh);
  gap: 4px;
  padding: 4px;
}

.dash-vsplit {
  display: block;
  top: 44px;
  bottom: 6px;
  left: clamp(190px, var(--dash-c1, 260px), 430px);
}

.transport-card,
.macro2-card,
.subnote-full-card,
.m2-main,
.m2-center,
.subnote-full-layout,
.ch-main {
  min-width: 0;
  min-height: 0;
}

.macro2-workspace-mode .macro2-card,
.subnote-workspace-mode .subnote-full-card {
  top: 44px;
  left: 4px;
  right: 4px;
  bottom: var(--ws-bottom);
}

.macro2-workspace-mode .research-note,
.subnote-workspace-mode .research-note {
  right: 4px;
  bottom: 7px;
}

.m2-main {
  gap: clamp(6px, 0.8vw, 10px);
}

/* The rail is one button wide at every size now — only its padding and
   button height flex. Its width and the settings pane's width are owned by
   the base rules (and, for the pane, the --m2-insp-w drag var). */
.m2-rail {
  padding: clamp(5px, 0.6vw, 7px);
}

.m2-rail-grid {
  gap: clamp(3px, 0.45vw, 4px);
}

.m2-rail-btn {
  min-height: clamp(48px, 6.5vh, 58px);
  padding: 7px 4px 6px;
}
/* FE-6: the grouped buttons no longer get a shorter height. Membership of
   "Macro Probability" is said by the rule and the label above them, not by
   making the members smaller than their neighbours. */

.m2-presets {
  max-height: clamp(92px, 17vh, 142px);
}

.m2-preset {
  flex-basis: clamp(84px, 7.7vw, 112px);
}

.harmonic-stage.chorda .ch-main {
  min-height: clamp(150px, 26vh, 230px);
}

.ch-inspector {
  width: clamp(180px, var(--ch-w, 218px), 460px);
}

.td-side {
  width: clamp(210px, 20vw, 292px);
}

.td-side .envelope-canvas {
  height: clamp(94px, 16vh, 128px);
}

/* Shorten the band on short viewports by moving the ONE variable — setting
   max-height directly here is what used to desync it from its children.
   The floor is two whole rows (58px each + the 4px gap + the band's 9px of
   padding); the old 110px fell 20px short, so on any window under ~720px tall
   the second row was sliced through its own name — which is exactly the "two
   rows tall and scroll" this band exists to give. */
.layer-area {
  --layer-band-h: clamp(130px, 18vh, 165px);
}

@media (max-width: 980px) {
  .explore-dashboard {
    grid-template-columns:
      clamp(170px, var(--dash-c1, 220px), 280px)
      minmax(0, 1fr)
      clamp(188px, 28vw, 245px);
    grid-template-rows:
      40px
      minmax(84px, 16vh)
      minmax(0, 1fr)
      minmax(96px, 17vh);
  }

  .dash-vsplit {
    left: clamp(170px, var(--dash-c1, 220px), 280px);
  }

  .m2-inspector {
    padding: 8px;
  }

  .m2-rail-btn {
    font-size: 0.68rem;
  }

  .td-side {
    width: clamp(188px, 32vw, 238px);
  }
}

@media (max-width: 700px) {
  .ch-main {
    gap: 5px;
  }

  .ch-inspector {
    width: clamp(156px, var(--ch-w, 180px), 186px);
    padding: 7px;
  }

  .td-side {
    width: clamp(154px, 28vw, 174px);
    padding: 8px;
  }
}

/* Macro inspector polish 2026-07-08: Duration + top strip cleanup. */
.explore-dashboard {
  grid-template-rows:
    46px
    minmax(96px, 18vh)
    minmax(0, 1fr)
    minmax(112px, 19vh);
}

.dash-vsplit {
  top: 50px;
}

.macro2-workspace-mode .macro2-card,
.subnote-workspace-mode .subnote-full-card {
  top: 50px;
}

.explore-top {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 8px;
  /* Visible, not hidden: the account dropdown hangs below this strip and
     was being clipped to a 4px sliver. The title truncates via its own
     overflow instead. */
  overflow: visible;
  background: linear-gradient(180deg, rgba(15,22,31,0.84), rgba(7,11,17,0.66));
  border: 1px solid rgba(58,75,92,0.72);
  border-radius: 7px;
}

.explore-top h1 {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.68rem;
  letter-spacing: 0.13em;
}

.studio-subtitle {
  display: none;
}

.workspace-tabs {
  flex: none;
  margin-top: 0;
  padding: 3px;
  border-radius: 7px;
}

.workspace-tab {
  min-height: 26px;
  height: 26px;
  padding: 0 9px;
  border-radius: 5px;
}

.transport-card {
  height: 100%;
  padding: 0 8px;
  gap: 8px;
  overflow-x: auto;
  overflow-y: hidden;
  border-left: 1px solid rgba(58,75,92,0.55);
  scrollbar-width: none;
}

.transport-card::-webkit-scrollbar {
  display: none;
}

.transport-card .transport {
  flex: 1 1 auto;
  min-width: max-content;
  gap: 8px;
}

.transport-card .transport > * {
  flex: none;
}

.transport-card .producer-pill {
  min-height: 34px;
  padding: 0 15px;
  border-radius: 7px;
  font-size: 0.82rem;
}

.transport-card .transport-round {
  width: 36px;
  height: 36px;
}

.transport-card .transport-play {
  width: 42px;
  height: 42px;
}

.transport-card .btn-secondary,
.transport-card .rand-btn,
.transport-card #regenBtn {
  min-height: 32px;
  padding: 0 12px;
  border-radius: 7px;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
}

.transport-card .seed-box,
.transport-card .top-rating-row {
  min-height: 32px;
  padding: 0 8px;
  border: 1px solid rgba(62,79,96,0.84);
  border-radius: 7px;
  background: rgba(8,12,18,0.72);
}

.transport-card .seed-box {
  gap: 6px;
}

.top-rating-row {
  display: grid;
  grid-template-columns: auto 46px auto;
  align-items: center;
  gap: 5px;
  flex: none;
}

.top-rating-row .label {
  margin: 0;
  color: rgba(174,187,201,0.82);
  font-size: 0.58rem;
}

.top-rating-row input[type="range"] {
  width: 46px;
}

.top-rating-row output {
  min-width: 32px;
  text-align: right;
  color: #ffd28a;
}

.m2-inspector .macro-card-head {
  min-height: 26px;
  margin-bottom: 0;
  padding-bottom: 7px;
  border-bottom-color: rgba(58,75,92,0.72);
  /* label left, panel dice right */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

.m2-inspector .macro-card-head > div:first-child {
  min-width: 0;
  padding: 0;
}

.m2-inspector .macro-card-head .section-label {
  margin-bottom: 0;
  line-height: 1.25;
}

.m2-inspector .macro-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow: visible;
  min-height: auto;
}

.m2-inspector .macro-panel > .panel-presets {
  flex: none;
  margin: 0;
  padding: 0 0 9px;
  border-bottom: 1px solid rgba(58,75,92,0.62);
}

.m2-inspector .panel-presets select {
  min-height: 34px;
  font-size: 0.72rem;
}

.m2-inspector .panel-presets .btn {
  min-height: 32px;
}

.m2-inspector .macro-controls {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: none;
  overflow: visible;
  padding: 0;
  border-right: 0;
}

.m2-inspector .macro-subsection {
  padding: 8px 0 0;
  border-top: 1px solid rgba(58,75,92,0.42);
}

.m2-inspector .macro-subsection:first-child {
  padding-top: 0;
  border-top: 0;
}

.m2-inspector .macro-subsection .subsection-label {
  margin-bottom: 6px;
  font-size: 0.55rem;
}

/* Subtle panel dice — sits at the right of the panel header, quiet by default
   (dimmed, no chrome), brightens on hover. Kept small so it reads as an
   affordance, not a primary control. */
.m2-inspector .panel-rand-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin: -3px -2px -3px 6px;
  padding: 0;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: rgba(140,160,180,0.55);
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.m2-inspector .panel-rand-btn:hover {
  color: rgba(225,235,245,0.95);
  background: rgba(140,160,180,0.14);
}
.m2-inspector .panel-rand-btn:active { transform: translateY(0.5px); }
.m2-inspector .panel-rand-btn .tb-ico { width: 15px; height: 15px; }

.m2-inspector .macro-controls .control-row,
.m2-inspector .breaks-grid .control-row {
  grid-template-columns: minmax(112px, 1fr) minmax(72px, 0.84fr) 52px;
  min-height: 30px;
  gap: 6px;
}

.m2-inspector .macro-controls .control-row .label,
.m2-inspector .breaks-grid .control-row .label {
  min-width: 0;
  white-space: normal;
  line-height: 1.1;
  overflow-wrap: anywhere;
}

.m2-inspector .macro-controls .control-row input[type="range"],
.m2-inspector .breaks-grid .control-row input[type="range"] {
  min-width: 0;
}

.m2-inspector .macro-controls .control-row output,
.m2-inspector .breaks-grid .control-row output {
  min-width: 0;
  width: 100%;
  justify-content: flex-end;
  font-size: 0.66rem;
}

.m2-inspector .macro-monitor {
  --macro-display-height: clamp(154px, 20vh, 188px);
  flex: none;
  gap: 8px;
  overflow: visible;
  padding: 0;
}

.m2-inspector .macro-inline-monitor {
  padding: 5px 0 2px;
}

.m2-inspector .duration-monitor {
  padding-top: 2px;
  border-top: 1px solid rgba(58,75,92,0.42);
}

.m2-inspector .monitor-title {
  text-align: left;
  font-size: 0.66rem;
  letter-spacing: 0.08em;
}

.m2-inspector .duration-monitor .accuracy-canvas {
  flex-basis: var(--macro-display-height);
}

.m2-inspector .breaks-block {
  padding-top: 10px;
}

.m2-inspector .breaks-grid {
  grid-template-columns: minmax(0, 1fr);
  gap: 7px;
}

.m2-inspector .connection-row {
  flex-wrap: wrap;
  gap: 6px;
  margin: 9px 0 6px;
}

.m2-inspector .connection-row .connection-label {
  flex: 0 0 100%;
  margin-right: 0;
}

.m2-inspector .connection-row .seg-btn {
  flex: 1 1 0;
  min-height: 28px;
}

.m2-inspector .breaks-block .mini-canvas {
  width: 100%;
  height: 62px;
}

@media (max-width: 980px) {
  .explore-dashboard {
    grid-template-rows:
      46px
      minmax(84px, 16vh)
      minmax(0, 1fr)
      minmax(96px, 17vh);
  }

  .transport-card {
    gap: 6px;
    padding: 0 6px;
  }

  .transport-card .producer-pill {
    padding: 0 11px;
  }

  .transport-card .btn-secondary,
  .transport-card .rand-btn,
  .transport-card #regenBtn {
    padding: 0 10px;
  }

  .top-rating-row {
    grid-template-columns: auto 44px auto;
  }

  .top-rating-row input[type="range"] {
    width: 44px;
  }
}

/* Producer cleanup 2026-07-09: compact file menu, region actions, note editor. */
.daw {
  gap: 4px;
}

.daw-transport {
  align-items: center;
  gap: 4px;
  padding: 4px 6px;
}

.daw-cluster {
  min-height: 30px;
  padding: 3px 6px;
  gap: 4px;
}

.daw-cluster-arrangement {
  flex: 1 1 340px;
}

.daw-cluster-context {
  flex: 0 1 260px;
}

.daw-cluster-edit {
  flex: 0 1 235px;
}

.daw-cluster-io {
  flex: 0 0 auto;
}

.daw-cluster-region {
  flex: 1 1 430px;
  margin-top: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}

.daw-cluster-region::-webkit-scrollbar {
  display: none;
}

.daw-file-menu {
  min-width: 132px;
}

.daw-cluster-region .btn-sm,
.daw-cluster-io .btn-sm {
  min-height: 26px;
  padding: 0.24rem 0.56rem;
}

.daw-cluster-region .toolbar-hint {
  white-space: nowrap;
  font-size: 0.68rem;
}

.daw-cluster-region .toolbar-keyhint {
  color: rgba(154,160,171,0.62);
}

.daw-center {
  padding: 6px 8px;
}

.daw-center .timeline-grid {
  flex: 1 1 auto;
  min-height: 0;
}

.strips-panel {
  margin-bottom: 3px;
  padding: 1px 0 3px;
}

.strips-panel .tl2-row {
  margin-bottom: 2px;
}

.tl2-gs-row,
.tl2-sp-row {
  min-height: 16px;
}

.tl2-gs-row:not(.open) .gs-head,
.tl2-sp-row .gs-head {
  min-height: 18px;
  padding: 0 5px;
}

.tl2-gs-row:not(.open) .gs-chevron,
.tl2-sp-row .gs-chevron {
  font-size: 0.58rem;
  line-height: 1;
}

/* HG-B3 (owner 2026-08-29: "big vertical gap between the harmonic guide row
   and the chord guide row"). The gap was not between the rows — they are 2px
   apart — it was INSIDE the expanded row's head cell, which stretches to the
   lane's full height and centred a 24px label in it. With the guide open that
   put "Harmonic guide" 30px below the scale name it labels and 30px above the
   next row's label, and the three strips stopped reading as a stack.
   The label now sits on the lane's own label row: top-aligned, with the
   padding that centres it on that row rather than on the whole cell. */
.tl2-gs-row.open > .gs-head,
.tl2-chord-row.open > .gs-head {
  align-items: flex-start;
}
.tl2-gs-row.open > .gs-head { padding-top: 5px; }

/* Dim the STRIP, never the row. `opacity < 1` creates a stacking context, and
   a non-positioned one paints below every positioned sibling — so with the
   dim on the row, these two rows' heads were sealed inside it and the head
   panel (z 5) covered them no matter what z-index they carried. That is what
   made the Harmonic-guide and Global-space rows disappear while the undimmed
   track heads were fine (owner 2026-08-21: "you broke the collapsible lanes
   for harmony and space"). */
.tl2-sp-row .sp-cyl-wrap { opacity: 0.86; }

.tl2-head {
  min-height: 0;
}

.tl2-track-head {
  gap: 0.1rem;
  padding: 5px 7px;
}

.tl2-lane {
  height: 38px;
}

.tl2-row {
  margin-bottom: 3px;
}

.roll-panel {
  margin-top: 0;
}

.roll-head {
  justify-content: flex-start;
  align-items: center;
  gap: 5px 9px;
  padding: 1px 2px 5px;
}

.roll-title {
  font-size: 0.78rem;
}

.roll-region,
.roll-meta,
.roll-keys,
.roll-legend {
  font-size: 0.6rem;
}

.roll-dyncheck {
  order: -2;
  margin-right: 2px;
  color: rgba(154,160,171,0.72);
  font-size: 0.56rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.roll-dyncheck input {
  width: 12px;
  height: 12px;
  opacity: 0.75;
}

.roll-panel canvas {
  height: 210px;
}

.roll-panel.dyn canvas {
  height: 258px;
}

.roll-readout {
  margin-top: 0.3rem;
  font-size: 0.66rem;
}

.daw-editor {
  padding: 6px 8px;
}

@media (max-width: 1180px) {
  .daw-cluster-region {
    flex-basis: 360px;
  }

  .daw-title .build-tag,
  .daw-cluster-region .toolbar-keyhint {
    display: none;
  }
}

/* Producer compact lanes + global-space pass 2026-07-09. */
.timeline-grid > .tl2-row {
  margin-bottom: 1px;
}

.timeline-grid .tl2-track-head {
  min-height: 32px;
  padding: 4px 6px;
  gap: 1px;
}

.timeline-grid .tl2-head-top {
  gap: 4px;
}

.timeline-grid .tl2-head-ctl {
  gap: 3px;
}

.timeline-grid .tl2-ms {
  width: 16px;
  height: 16px;
  font-size: 0.54rem;
}

.timeline-grid .tl2-head .tl-gain {
  --fader-cap-h: 13px;
  --fader-track: 6px;
}

.timeline-grid .tl2-lane {
  height: 32px;
}

.timeline-grid .tl2-region {
  top: 2px;
  bottom: 2px;
  align-items: flex-end;
  min-width: 22px;
  padding: 0 4px 3px;
  border-radius: 5px;
}

.timeline-grid .tl2-region::after {
  display: none;
}

.tl2-mini-roll,
.tl2-prob-curve {
  position: absolute;
  inset: 4px 7px;
  z-index: 0;
  pointer-events: none;
}

.tl2-mini-roll {
  opacity: 0.9;
  background:
    repeating-linear-gradient(to bottom,
      transparent 0 4px,
      hsla(var(--track-h, 36), 58%, 76%, 0.11) 4px 5px,
      transparent 5px 8px);
}

.tl2-mini-roll.empty {
  background:
    linear-gradient(90deg,
      transparent 0,
      hsla(var(--track-h, 36), 72%, 68%, 0.26) 46%,
      hsla(var(--track-h, 36), 72%, 68%, 0.26) 54%,
      transparent 100%);
  opacity: 0.45;
}

.tl2-mini-note {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  height: 3px;
  border-radius: 2px;
  background: hsla(var(--track-h, 36), 92%, 69%, var(--a));
  box-shadow: 0 0 5px hsla(var(--track-h, 36), 80%, 58%, calc(var(--a) * 0.32));
}
/* FE-9: a repeated pass of a baked loop. Same shape, same place, hollow — it
   is the same material sounding again, not notes anyone placed. Drawn with an
   inset ring rather than a border so the glyph keeps its exact geometry and
   stays pixel-aligned with the pass it repeats. */
.tl2-mini-note.repeat {
  /* Owner 2026-08-28: "the outlined notes on looping are too faint."
     They were. The glyph is 3px tall, so a 1px INSET ring had roughly one
     pixel of visible edge, and then `calc(var(--a) * 0.72)` attenuated even
     that by the note's velocity — a quiet repeated note came out at about a
     fifth of the strength of the solid one it repeats. Now: a real (if
     dimmer) fill so the bar has body at 3px, plus a full-strength edge drawn
     OUTSIDE the box, which does not have to fit within the 3px. Velocity
     still shades the fill, because that is real information, but it no longer
     multiplies the outline away. */
  background: hsla(var(--track-h, 36), 92%, 69%, calc(var(--a) * 0.34));
  box-shadow: 0 0 0 1px hsla(var(--track-h, 36), 95%, 76%, 0.85);
}

.tl2-prob-curve {
  overflow: visible;
  opacity: 0.84;
}

.tl2-prob-shadow,
.tl2-prob-line {
  fill: none;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tl2-prob-shadow {
  stroke: hsla(var(--track-h, 36), 86%, 58%, 0.24);
  stroke-width: 7;
}

.tl2-prob-line {
  stroke: hsla(var(--track-h, 36), 92%, 70%, 0.82);
  stroke-width: 1.8;
}

.timeline-grid .tl2-region-label,
.timeline-grid .tl2-seed-chip,
.timeline-grid .tl2-gain-tag,
.timeline-grid .tl2-badges,
.timeline-grid .tl2-resize,
.timeline-grid .tl2-looptick {
  z-index: 2;
}

.timeline-grid .tl2-region-label {
  min-width: 0;
  max-width: 62%;
  padding: 0 0.2rem;
  font-size: 0.56rem;
  line-height: 1.1;
  opacity: 0.88;
}

.timeline-grid .tl2-seed-chip {
  margin-right: 2px;
  padding: 0 3px;
  font-size: 0.5rem;
  line-height: 1.35;
  opacity: 0.82;
}

.timeline-grid .tl2-badges {
  transform: scale(0.84);
  transform-origin: right center;
}

.sp-panel-row {
  align-items: stretch;
}

/* Neither `position` nor `width` belongs here: both are .tl2-head's job. This
   row's head is the only one that ever overrode them, and it paid for both —
   `relative` cost it the sticky pinning every other head has, so expanding
   Global space and scrolling carried the cross-section off the left edge. */
.sp-left {
  height: 105px;
  min-height: 105px;
  padding: 0;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

#spSection {
  width: 132px;
  height: 105px;
}

.sp-cyl-wrap {
  min-height: 105px;
}

#spCylinder {
  height: 105px;
  display: block;
}

/* A slim label that fades up out of the cross-section instead of a floating
   boxed overlay — seamless with the canvas above (owner 2026-07-10). */
.sp-settings-toggle {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 5px;
  min-height: 17px;
  padding: 6px 8px 4px;
  overflow: hidden;
  color: rgba(214,224,236,0.68);
  text-align: left;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.54rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  background: linear-gradient(to top, rgba(8,11,16,0.9) 30%, rgba(8,11,16,0));
  border: 0;
  border-radius: 0;
  box-shadow: none;
  cursor: pointer;
  transition: color 0.15s ease;
}

.sp-settings-toggle:hover {
  color: #ffe0a3;
}

/* ── Global-space settings drawer (owner 2026-08-27) ──────────────────────
   It renders OUTSIDE #stripsScroll (see globalSpaceRoomDrawerHTML), so it is
   full panel width and does not slide sideways with the arrangement. z-index
   clears the sticky head-column panel: this is chrome that sits OVER the
   column, like the heads, not content that scrolls under it — without this the
   Room select sat beneath the panel and could not be clicked at all. */
/* ── Global-space settings (owner 2026-08-27) ─────────────────────────────
   A PANEL, not a strip. It floats over the timeline instead of pushing it
   down: the old drawer expanded inline, so opening it shunted every lane
   several hundred pixels and you could never leave it open — which made the
   collapse control pay for a problem it created. Anchored to the gear that
   opens it, sized to its own content, and opaque, so nothing of the sticky
   head column shows through it.

   Palette is the project's, not a new one: chrome from the shell tokens, and
   ONE accent — --spc, the Space stage's own hue — carrying fill, selection
   and focus. Vivid hues belong to the data layer (docs/UI_DIRECTION.md), and
   this panel is the Space layer's. */
.sp-designer {
  position: absolute;
  z-index: 40;
  top: calc(100% - 4px);
  left: 10px;
  width: min(620px, calc(100vw - 40px));
  display: flex;
  flex-direction: column;
  align-items: stretch;
  flex-wrap: nowrap;
  gap: 12px;
  padding: 14px 16px 15px;
  border: 1px solid var(--border2);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: 0 18px 44px -12px rgba(0, 0, 0, 0.72), 0 0 0 1px rgba(0, 0, 0, 0.35);
}

.spd-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 2px 10px;
}
.spd-title { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.spd-eyebrow {
  color: var(--text3);
  font-size: 0.54rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.14em;
}
.spd-room { color: var(--text); font-size: 0.92rem; font-weight: 700; letter-spacing: 0.01em; }
.spd-blurb {
  grid-column: 1; margin: 0;
  color: var(--text2); font-size: 0.66rem; line-height: 1.4;
}
.spd-close {
  grid-row: 1 / span 2; grid-column: 2; align-self: start;
  width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface2); color: var(--text2);
  font-size: 0.9rem; line-height: 1; cursor: pointer;
  transition: color 0.12s, border-color 0.12s;
}
.spd-close:hover { color: var(--text); border-color: var(--border2); }

/* The room picker: ten pictures, one choice, ALL OF THEM VISIBLE. This was a
   scrolling row, which bought nothing and cost plenty — the scrollbar sat over
   the tile labels, and six of the ten rooms were hidden behind a drag you had
   to discover (owner 2026-08-27: "I don't like this scroll bar"). Ten items is
   not a list to page through, it is a palette to look at. Two rows of five,
   fewer per row as the panel narrows, no scroll track anywhere. */
/* FE-10 (owner 2026-08-28): "the space overlay should be a scrollable zone only
   2.5 rows deep."
   The room grid grew a row with every measured space added, pushing Room and
   Listener — the controls you came for — further down the dialog each time.
   It is a fixed-depth scroller now. The HALF row is the point: a grid cut
   cleanly at two rows looks complete, so nobody scrolls. Depth is computed
   from the tile height rather than typed as a magic pixel value, so adding a
   room, or changing the tile, cannot quietly break the 2.5. */
.spd-rooms {
  --spd-tile-h: 62px;
  --spd-gap: 6px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  gap: var(--spd-gap);
  max-height: calc(var(--spd-tile-h) * 2.5 + var(--spd-gap) * 2);
  overflow-y: auto;
  /* Don't hand the scroll to the dialog behind once the grid bottoms out. */
  overscroll-behavior: contain;
  padding-right: 2px;
}
.spd-rooms::-webkit-scrollbar { width: 7px; }
.spd-rooms::-webkit-scrollbar-track { background: transparent; }
.spd-rooms::-webkit-scrollbar-thumb { background: rgba(120,130,150,0.3); border-radius: 4px; }
.spd-tile {
  min-width: 0;
  height: var(--spd-tile-h, 62px);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  padding: 6px 6px 5px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--display); color: var(--text2);
  font-size: 0.55rem; letter-spacing: 0.03em; white-space: nowrap;
  cursor: pointer;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.spd-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.spd-tile canvas { display: block; opacity: 0.62; transition: opacity 0.12s; }
.spd-tile:hover { border-color: var(--border2); color: var(--text); }
.spd-tile:hover canvas { opacity: 0.85; }
/* Selection is stated three ways — ring, ground and label weight — so it
   survives both themes and a glance. */
.spd-tile.is-on {
  border-color: var(--spc);
  background: color-mix(in srgb, var(--spc) 13%, var(--display));
  color: var(--text);
  font-weight: 700;
  box-shadow: 0 0 0 1px var(--spc), 0 0 14px -4px var(--spc);
}
.spd-tile.is-on canvas { opacity: 1; }

.spd-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 14px 26px;
  align-items: start;
  align-content: start;
}
.spd-col { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.spd-col h4 {
  margin: 0 0 1px;
  color: var(--text3);
  font-size: 0.52rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.13em;
}
.spd-col h4.spd-sub { margin-top: 8px; }

/* label | control | value — three columns, so the sliders share one edge and
   the numbers share another. */
.spd-row {
  display: grid;
  grid-template-columns: 66px minmax(0, 1fr) 46px;
  align-items: center;
  gap: 10px;
  min-height: 22px;
  color: var(--text2);
  font-size: 0.63rem;
}
.spd-lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spd-val {
  color: var(--text);
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 0.6rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* The fill is the feedback: a bare grey groove tells you nothing about where
   in its range a control is sitting. --fill is written by the wiring on every
   input, so it tracks the thumb live. */
/* [type=range] on purpose: the shell's own `input[type="range"]` rule is
   (0,1,1) and a bare `.spd-slider` is only (0,1,0), so the flat grey ground
   won and this gradient was thrown away. The attribute puts it at (0,2,0). */
.spd-slider[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 4px;
  border-radius: 2px;
  background: linear-gradient(to right,
    var(--spc) var(--fill, 0%), var(--border) var(--fill, 0%));
  outline: none; cursor: pointer;
}
.spd-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 12px; height: 12px; border-radius: 50%;
  background: #eef2f6; border: 2px solid var(--surface);
  box-shadow: 0 1px 3px rgba(0,0,0,0.6);
  transition: box-shadow 0.12s, transform 0.12s;
}
.spd-slider::-moz-range-thumb {
  width: 12px; height: 12px; border-radius: 50%;
  background: #eef2f6; border: 2px solid var(--surface);
}
.spd-slider:hover::-webkit-slider-thumb { transform: scale(1.12); }
.spd-slider:focus-visible::-webkit-slider-thumb,
.spd-slider:active::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--spc) 34%, transparent);
}

.spd-select {
  width: 100%;
  background: var(--display);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 5px;
  font-size: 0.62rem;
  padding: 2px 4px;
  cursor: pointer;
}
.spd-select:hover { border-color: var(--border2); }
.spd-select:focus-visible { outline: 2px solid color-mix(in srgb, var(--spc) 55%, transparent); outline-offset: 1px; }

.spd-note {
  margin: 0;
  padding-top: 2px;
  border-top: 1px solid var(--border);
  color: var(--text3);
  font-size: 0.58rem; font-style: italic; line-height: 1.4;
}

@media (prefers-reduced-motion: reduce) {
  .spd-tile, .spd-close, .spd-slider::-webkit-slider-thumb { transition: none; }
}

/* Sub-note tone designer compaction 2026-07-09. */
.subnote-workspace-mode .subnote-full-card {
  grid-column: auto;
  grid-row: auto;
  top: 54px;
  left: 4px;
  right: 4px;
  bottom: var(--ws-bottom);
  padding: 4px 8px 6px;
}

.subnote-workspace-mode .subnote-full-layout,
.subnote-workspace-mode .harmonic-stage.chorda {
  gap: 4px;
}

.subnote-workspace-mode .ch-head {
  min-height: 15px;
  margin: 0 4px;
  align-items: center;
}

.ch-title-block {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.ch-preset-title {
  margin: 0;
  color: var(--text3);
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: text;
}

.ch-title-edit {
  width: min(220px, 28vw);
  min-height: 19px;
  padding: 1px 6px;
  color: rgba(244,247,250,0.98);
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: rgba(8, 12, 18, 0.92);
  border: 1px solid rgba(245,166,35,0.72);
  border-radius: 5px;
  outline: none;
}

.subnote-workspace-mode .layer-edit-tag {
  font-size: 0.62rem;
}

.subnote-workspace-mode .ch-readout {
  font-size: 0.62rem;
}

.subnote-workspace-mode .ch-rail {
  gap: 7px;
  align-items: stretch;
  margin-bottom: 3px;
}

.subnote-workspace-mode .ch-sep {
  align-self: center;
  padding: 0 1px;
  font-size: 0.84rem;
  opacity: 0.75;
}

.subnote-workspace-mode .ch-card {
  position: relative;
  height: clamp(70px, 10.5vh, 88px);
  min-height: 58px;
  padding: 0;
  gap: 0;
  overflow: hidden;
  border-radius: 9px;
}

.subnote-workspace-mode .ch-card::before,
.subnote-workspace-mode .ch-card::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  z-index: 1;
  pointer-events: none;
}

.subnote-workspace-mode .ch-card::before {
  top: 0;
  height: 45px;
  background: linear-gradient(180deg, rgba(9, 13, 19, 0.92), rgba(9, 13, 19, 0.52) 62%, rgba(9, 13, 19, 0));
}

.subnote-workspace-mode .ch-card::after {
  bottom: 0;
  height: 34px;
  opacity: 0;
  background: rgba(7, 10, 15, 0.88);
  border-top: 1px solid rgba(255,255,255,0.035);
  transition: opacity 0.14s ease;
}

.subnote-workspace-mode .ch-card:hover::after,
.subnote-workspace-mode .ch-card.active::after {
  opacity: 1;
}

.subnote-workspace-mode .ch-card-head {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  padding: 8px 10px 18px;
}

.subnote-workspace-mode .ch-card-n {
  color: rgba(244,247,250,0.92);
  font-size: 0.72rem;
  line-height: 1;
  text-shadow: 0 1px 2px rgba(0,0,0,0.72);
}

.subnote-workspace-mode .ch-power {
  position: relative;
  z-index: 4;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.75));
}

.subnote-workspace-mode .ch-thumb {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 0;
}

.subnote-workspace-mode .ch-card .ch-headline,
.subnote-workspace-mode .ch-card .ch-card-sum {
  position: absolute;
  left: 10px;
  right: 10px;
  z-index: 3;
  opacity: 0;
  text-shadow: 0 1px 2px rgba(0,0,0,0.82);
  transition: opacity 0.14s ease, transform 0.14s ease;
}

.subnote-workspace-mode .ch-card .ch-headline {
  bottom: 18px;
  color: rgba(244,247,250,0.9);
  font-size: 0.62rem;
  transform: translateY(4px);
}

.subnote-workspace-mode .ch-card .ch-card-sum {
  bottom: 5px;
  color: rgba(179,191,205,0.84);
  font-size: 0.55rem;
  transform: translateY(6px);
}

.subnote-workspace-mode .ch-card:hover .ch-headline,
.subnote-workspace-mode .ch-card:hover .ch-card-sum,
.subnote-workspace-mode .ch-card.active .ch-headline,
.subnote-workspace-mode .ch-card.active .ch-card-sum {
  opacity: 1;
  transform: translateY(0);
}

.subnote-workspace-mode .ch-card.stage-off .ch-thumb,
.subnote-workspace-mode .ch-card.stage-off .ch-headline,
.subnote-workspace-mode .ch-card.stage-off .ch-card-sum {
  opacity: 0.35;
}

.subnote-workspace-mode .harmonic-stage.chorda .ch-main {
  min-height: clamp(170px, 30vh, 250px);
}

/* Producer patch composer: a deliberately small three-pane inspector. */
.palette-item.selected { border-color: color-mix(in srgb, var(--accent) 72%, var(--border)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 32%, transparent); }
.pal-top { display:flex; align-items:center; gap:6px; width:100%; }
.palette-zones { display:grid; grid-template-columns:1fr 1fr; gap:5px; width:100%; }
.palette-zone { min-width:0; border:1px dashed var(--border); background:var(--surface2); border-radius:6px; padding:5px 6px; text-align:left; color:var(--text3); cursor:pointer; }
.palette-zone b,.palette-zone span { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.palette-zone b { color:var(--text2); font-size:.59rem; text-transform:uppercase; letter-spacing:.06em; }
.palette-zone span { font-size:.68rem; margin-top:2px; }
.palette-zone.filled { border-style:solid; border-color:color-mix(in srgb,var(--accent) 38%,var(--border)); color:var(--text); background:color-mix(in srgb,var(--accent) 7%,var(--surface2)); }
.pal-draft-note { width:100%; font-size:.62rem; color:var(--text3); }
.patch-inspector { display:grid; grid-template-columns:minmax(250px,1fr) minmax(270px,1.05fr) minmax(250px,1fr); min-height:220px; background:var(--surface); }
.patch-pane { min-width:0; padding:10px; border-right:1px solid var(--border); display:flex; flex-direction:column; gap:8px; }
.patch-pane:last-child { border-right:0; }
.patch-pane header { display:flex; gap:6px; align-items:center; min-height:20px; color:var(--text2); font-size:.72rem; text-transform:uppercase; letter-spacing:.08em; }
.patch-pane header span { margin-left:auto; color:var(--text3); text-transform:none; letter-spacing:0; font-size:.62rem; }
.patch-pane header button { margin-left:auto; border:0; color:var(--text3); background:transparent; cursor:pointer; }
.patch-pane header button + button { margin-left:0; }
.patch-layer-list,.patch-space-map { display:flex; flex-direction:column; gap:5px; overflow:auto; max-height:230px; }
.patch-layer-list h4 { margin:2px 0; color:var(--text3); font-size:.64rem; text-transform:uppercase; letter-spacing:.08em; }
.patch-source-row { display:flex; align-items:center; gap:5px; padding:5px; background:var(--surface2); border-left:2px solid var(--accent); border-radius:4px; font-size:.62rem; }
.patch-source-row.muted { opacity:.45; }
.patch-source-row b { min-width:54px; color:var(--text2); }
.patch-source-row label { display:flex; align-items:center; gap:3px; color:var(--text3); min-width:0; flex:1; }
.patch-source-row input { width:58px; min-width:0; }
.patch-source-row button { border:1px solid var(--border); border-radius:3px; background:var(--display); color:var(--text3); font-size:.58rem; }
.patch-source-note,.patch-pane p,.patch-engine-summary,.patch-global-note { color:var(--text3); font-size:.64rem; line-height:1.35; }
.patch-pane > label { font-size:.66rem; color:var(--text2); display:flex; justify-content:space-between; align-items:center; gap:8px; }
.patch-pane select { max-width:130px; background:var(--display); color:var(--text); border:1px solid var(--border); border-radius:4px; }
.patch-perc-toggle { justify-content:flex-start !important; }
.patch-scale { border-top:1px solid var(--border); padding-top:7px; }
.patch-scale-head { color:var(--text2); font-size:.66rem; margin-bottom:5px; }
.patch-degrees { display:flex; gap:3px; flex-wrap:wrap; }
.patch-degrees button { width:23px; height:20px; border:1px solid var(--border); border-radius:3px; background:var(--display); color:var(--text3); font-size:.61rem; }
.patch-degrees button.sub { border-color:#d9a441; color:#d9a441; }.patch-degrees button.root { border-color:#7fce82; color:#7fce82; }
/* (The v1 pass's own ≤900px stack rule was removed with the v2 breakpoints
   above. It was already dead for the grid — v2 sets `.patch-inspector` to
   `display:block`, so its grid-template-columns had nothing to act on — but its
   `border-bottom` still leaked onto the v2 panes below 900px of WINDOW width,
   drawing a rule under panes that were not stacked.) */

/* Patch inspector v2 — one named, spatially legible object instead of three
   disconnected forms.  These rules intentionally supersede the first pass
   above while keeping its compact controls usable at narrow widths. */
.patch-editor-wrap { gap:0; }
.patch-editor-wrap .editor-body { overflow:auto; }
.patch-inspector { display:block; min-height:0; background:var(--surface); }
.patch-inspector-titlebar { display:flex; align-items:center; gap:12px; min-height:42px; padding:6px 12px; border-bottom:1px solid var(--border); background:linear-gradient(90deg, color-mix(in srgb, var(--accent) 10%, var(--surface)), var(--surface) 52%); }
.patch-inspector-titlebar > div:first-child { min-width:170px; }
.patch-inspector-titlebar span { display:block; color:var(--text3); font-size:.58rem; letter-spacing:.11em; text-transform:uppercase; }
.patch-inspector-titlebar h3 { margin:2px 0 0; color:var(--text); font-size:.92rem; line-height:1.05; font-weight:650; }
.patch-inspector-badges { display:flex; gap:5px; flex:1; align-items:center; min-width:0; overflow:auto; }
.patch-inspector-badges i { flex:0 0 auto; border:1px solid var(--border); border-radius:999px; background:var(--display); padding:3px 6px; color:var(--text3); font-size:.58rem; font-style:normal; white-space:nowrap; }
.patch-inspector-badges .patch-local-badge { color:color-mix(in srgb, var(--accent) 75%, var(--text)); border-color:color-mix(in srgb, var(--accent) 38%, var(--border)); }
.patch-title-actions { display:flex; align-items:center; gap:7px; flex:0 0 auto; }.patch-title-actions .editor-switch { margin:0; }.patch-title-actions .editor-tab { padding:3px 8px; }
.patch-close { width:25px; height:25px; border:1px solid var(--border); border-radius:5px; background:transparent; color:var(--text3); font-size:1rem; cursor:pointer; }
.patch-close:hover { background:var(--surface2); color:var(--text); }
.patch-inspector-grid { display:grid; grid-template-columns:minmax(235px,.88fr) minmax(310px,1.18fr) minmax(270px,.98fr); min-height:280px; }
.patch-inspector-grid .patch-pane { gap:9px; padding:11px 12px; border-right:1px solid var(--border); }
.patch-inspector-grid .patch-pane:last-child { border-right:0; }
.patch-inspector-grid .patch-pane > header { justify-content:space-between; min-height:18px; color:var(--text2); }
.patch-inspector-grid .patch-pane > header > span { color:var(--text2); font-size:.64rem; text-transform:uppercase; letter-spacing:.1em; font-weight:700; }
.patch-inspector-grid .patch-pane > header small { color:var(--text3); font-size:.59rem; text-transform:none; letter-spacing:0; font-weight:400; }
.patch-inspector-grid .patch-pane > header div { display:flex; gap:4px; }
.patch-inspector-grid .patch-pane > header button { width:20px; height:20px; margin:0; padding:0; border:1px solid transparent; border-radius:4px; }
.patch-inspector-grid .patch-pane > header button:hover { color:var(--text); border-color:var(--border); background:var(--surface2); }
.patch-sound-meta { display:flex; align-items:baseline; justify-content:space-between; margin-top:3px; color:var(--text2); font-size:.72rem; font-weight:600; }
.patch-sound-meta span { max-width:52%; overflow:hidden; color:var(--text3); font-size:.59rem; font-weight:400; text-overflow:ellipsis; white-space:nowrap; }
.patch-layer-list { max-height:none; gap:6px; overflow:visible; }
.patch-main-source { display:flex; align-items:center; gap:8px; min-height:42px; padding:7px 8px; border:1px solid color-mix(in srgb, var(--accent) 42%, var(--border)); border-radius:7px; background:linear-gradient(110deg, color-mix(in srgb, var(--accent) 15%, var(--surface2)), var(--surface2)); }
.patch-main-source > div { min-width:0; display:flex; flex:1; flex-direction:column; gap:1px; }
.patch-main-source b { color:var(--text); font-size:.7rem; }.patch-main-source span { color:var(--text3); font-size:.58rem; }
.patch-main-source .patch-main-source-pos { flex:0 0 auto; color:var(--text3); }
.patch-layer-card { display:flex; align-items:center; gap:7px; min-height:31px; padding:4px 7px; border:1px solid var(--border); border-radius:6px; background:var(--surface2); }
.patch-layer-card.muted { opacity:.5; }
.patch-layer-card b { min-width:0; color:var(--text2); font-size:.65rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }.patch-layer-card > span:not(.patch-layer-dot) { flex:1; color:var(--text3); font-size:.57rem; }
.patch-layer-card > div { display:flex; gap:3px; }
.patch-layer-dot { width:7px; height:7px; flex:0 0 auto; border-radius:50%; background:#d7a640; box-shadow:0 0 0 2px rgba(215,166,64,.14); }.patch-layer-dot.blue { background:#6da8df; box-shadow:0 0 0 2px rgba(109,168,223,.14); }.patch-layer-dot.pink { background:#cf7bc3; box-shadow:0 0 0 2px rgba(207,123,195,.14); }
.patch-layer-toggle { min-width:19px; height:18px; padding:0 3px; border:1px solid var(--border); border-radius:3px; background:var(--display); color:var(--text3); font-size:.55rem; cursor:pointer; }.patch-layer-toggle.active { color:var(--text); border-color:var(--accent); background:color-mix(in srgb, var(--accent) 18%, var(--display)); }
.patch-layer-empty { padding:9px; border:1px dashed var(--border); border-radius:6px; color:var(--text3); font-size:.62rem; line-height:1.35; }
.patch-space-stage { position:relative; align-self:center; width:min(160px,50vw); aspect-ratio:1; margin:1px auto -2px; overflow:hidden; border:1px solid color-mix(in srgb, var(--accent) 26%, var(--border)); border-radius:50%; background:radial-gradient(circle, color-mix(in srgb, var(--accent) 12%, var(--surface2)) 0 3%, transparent 3.5% 100%), var(--surface2); }
.patch-space-stage > i { position:absolute; inset:18%; border:1px solid color-mix(in srgb, var(--text3) 28%, transparent); border-radius:50%; pointer-events:none; }.patch-space-stage > i:nth-child(2) { inset:34%; }.patch-space-stage > i:nth-child(3) { inset:0; border-color:color-mix(in srgb, var(--accent) 15%, var(--border)); }
.patch-space-centre { position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); color:var(--text3); font-size:.55rem; pointer-events:none; }
.patch-space-dot { position:absolute; left:var(--dot-x); top:var(--dot-y); width:10px; height:10px; transform:translate(-50%,-50%); border:2px solid var(--surface); border-radius:50%; background:#d7a640; box-shadow:0 0 0 2px rgba(215,166,64,.25),0 2px 5px rgba(0,0,0,.5); }.patch-space-dot.blue { background:#6da8df; box-shadow:0 0 0 2px rgba(109,168,223,.25),0 2px 5px rgba(0,0,0,.5); }.patch-space-dot.pink { background:#cf7bc3; box-shadow:0 0 0 2px rgba(207,123,195,.25),0 2px 5px rgba(0,0,0,.5); }.patch-space-dot.muted { opacity:.3; }
.patch-movement-control { display:flex; align-items:center; justify-content:space-between; margin-top:1px; padding:5px 7px; border:1px solid var(--border); border-radius:5px; background:var(--surface2); color:var(--text2); font-size:.62rem; }.patch-movement-control select { max-width:112px; padding:2px 4px; font-size:.62rem; }
.patch-pane-space > p { margin:0; color:var(--text3); font-size:.59rem; line-height:1.3; }
.patch-placement-list { display:flex; flex-direction:column; gap:4px; max-height:104px; overflow:auto; }
.patch-placement-row { display:grid; grid-template-columns:9px minmax(47px,.75fr) minmax(80px,1fr) minmax(80px,1fr); align-items:center; gap:5px; padding:4px 5px; border-radius:5px; background:var(--surface2); }.patch-placement-row.muted { opacity:.46; }.patch-placement-row b { overflow:hidden; color:var(--text2); font-size:.59rem; text-overflow:ellipsis; white-space:nowrap; }.patch-placement-row label { display:flex; align-items:center; gap:3px; color:var(--text3); font-size:.54rem; }.patch-placement-row input { min-width:0; width:100%; }
.patch-pane-macro { background:linear-gradient(180deg, color-mix(in srgb, var(--accent) 3%, var(--surface)), var(--surface)); }
.patch-module-card { display:flex; flex-direction:column; gap:5px; padding:7px; border:1px solid var(--border); border-radius:7px; background:var(--surface2); }.patch-module-card-head { display:flex; align-items:center; gap:6px; min-height:15px; }.patch-module-card-head b { color:var(--text2); font-size:.65rem; }.patch-module-card-head > span { flex:1; overflow:hidden; color:var(--text3); font-size:.57rem; text-align:right; text-overflow:ellipsis; white-space:nowrap; }.patch-module-card-head > button { margin-left:0; border:0; background:transparent; color:var(--text3); cursor:pointer; }
.patch-perc-toggle { margin-left:auto; color:var(--text3); font-size:.58rem; text-transform:none; letter-spacing:0; }.patch-perc-toggle input { margin:0 3px 0 0; vertical-align:middle; }
.patch-module-card .smart-combo-btn { min-height:25px; font-size:.65rem; }.patch-module-card .smart-combo-pop { z-index:20; }
.patch-scale-card { gap:4px; }.patch-scale { border-top:0; padding-top:0; }.patch-scale-head { margin-bottom:5px; color:var(--text2); font-size:.64rem; }.patch-degrees { flex-wrap:nowrap; overflow:auto; padding-bottom:1px; }.patch-degrees button { flex:0 0 auto; }.patch-global-note { margin-top:4px; color:var(--text3); font-size:.56rem; }.patch-text-action { align-self:flex-start; padding:0; border:0; background:none; color:var(--text3); font-size:.59rem; cursor:pointer; }.patch-text-action:hover { color:var(--text); }
/* ── The editor panes shrink, then scroll — they never stack (owner 2026-08-27)
   ──────────────────────────────────────────────────────────────────────────
   Two viewport media queries used to live here: at ≤1000px the grid dropped to
   two columns and spanned the macro pane across the bottom, and at ≤720px it
   collapsed to one. Both were wrong twice over.

   1. They watched the WINDOW. This pane's width comes from the DAW grid and
      the library splitter, so a wide window with the library open stacked the
      panes anyway, and a narrow window with the library collapsed didn't stack
      when it should have. The reference was never the box being laid out.
   2. Stacking was the wrong answer regardless. The owner's rule: shrink
      horizontally until the panes hit their floors, then scroll.

   So the wrap is now a container-query context and the grid scrolls at its
   floor. The columns keep their minmax() minimums, which grid honours over the
   fr shares, so at the floor the tracks overflow the grid box and the grid —
   not the page, and not the titlebar above it — takes the scrollbar. */
.patch-editor-wrap { container-type: inline-size; container-name: patchpane; }
.patch-inspector-grid {
  /* Panes carry their own overflow-y (below), so only the x axis scrolls here.
     `hidden` rather than `clip` — clip would kill the panes' sticky headers. */
  overflow-x: auto;
  overflow-y: hidden;
}
/* A horizontally scrolled grid has no edge to read against — the panes are
   flush to the box. A hairline scrim on the overflowing side says there is
   more, and rides the scroll via `position: sticky` on the last pane's edge. */
.patch-inspector-grid::-webkit-scrollbar { height: 8px; }
.patch-inspector-grid::-webkit-scrollbar-thumb { background: rgba(120,130,150,0.3); border-radius: 4px; }

/* Only the titlebar still reflows, and now against the pane, not the window.
   The pane row deliberately has no rule here: it shrinks and then scrolls. */
@container patchpane (max-width: 720px) {
  .patch-inspector-titlebar { align-items:flex-start; flex-wrap:wrap; gap:7px; }
  .patch-inspector-badges { order:3; flex-basis:calc(100% - 32px); }
  .patch-space-stage { width:130px; }
  .patch-placement-list { max-height:none; }
}

/* Producer patch inspector v3 (owner 2026-07-10): a draggable space stage + a
   sub-note-style layer strip replace the static dots, placement sliders and
   layer cards. Reuses .sp-ctl / .pal-btn from the sub-note layer strip. */
.patch-pane-space { min-height:0; }
.patch-stage-wrap { flex:1; min-height:148px; display:flex; }
#patchStage { flex:1; width:100%; height:100%; min-height:148px; display:block; border:1px solid var(--border); border-radius:8px; background:var(--display); cursor:crosshair; }
.patch-stage-readout { min-height:14px; color:var(--text3); font-size:.6rem; font-variant-numeric:tabular-nums; }
.patch-lyr { display:flex; align-items:center; gap:8px; padding:6px 8px; border:1px solid var(--border); border-left:3px solid hsl(var(--layer-hue,36) var(--layer-sat, 70%) 55%); border-radius:7px; background:var(--surface2); }
.patch-lyr.base { background:linear-gradient(110deg, color-mix(in srgb, var(--accent) 12%, var(--surface2)), var(--surface2)); }
.patch-lyr.sel { box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent); }
.patch-lyr.muted { opacity:.5; }
.patch-lyr-tag { flex:0 0 auto; width:18px; height:18px; display:flex; align-items:center; justify-content:center; border-radius:4px; background:color-mix(in srgb, hsl(var(--layer-hue,36) var(--layer-sat, 70%) 55%) 55%, transparent); color:#0d1015; font-size:.6rem; font-weight:700; font-family:var(--mono); }
.patch-lyr-body { flex:1; min-width:0; display:flex; flex-direction:column; gap:4px; }
.patch-lyr-name { display:flex; align-items:center; gap:6px; color:var(--text2); font-size:.66rem; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.patch-lyr-badge { flex:0 0 auto; padding:1px 5px; border-radius:999px; background:color-mix(in srgb, var(--accent) 22%, var(--display)); color:var(--accent); font-size:.5rem; letter-spacing:.06em; }
.patch-lyr-ctls { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.patch-lyr-ctls .sp-ctl { font-size:.56rem; flex:1 1 auto; min-width:0; }
/* FE-13: 54px of travel is not a level control. The card wraps instead. */
.patch-lyr-ctls .sp-ctl input[type=range] { width:100%; min-width: var(--fader-min-travel); }
.patch-lyr-mute.on { color:var(--text); border-color:#c96; background:color-mix(in srgb, #c96 22%, var(--display)); }
.patch-lyr-solo.on { color:#0d1015; border-color:#e7b34a; background:#e7b34a; }
.patch-lyr-empty { padding:8px; border:1px dashed var(--border); border-radius:6px; color:var(--text3); font-size:.6rem; line-height:1.3; }
/* Percussion hits are grouped + tinted apart from the melodic layers (owner 2026-07-10) */
.patch-lyr-group { display:flex; align-items:baseline; justify-content:space-between; gap:8px; margin:6px 2px 2px; padding-top:6px; border-top:1px dashed var(--border2); color:var(--eff); font-size:.56rem; letter-spacing:.09em; text-transform:uppercase; font-weight:700; }
.patch-lyr-group small { color:var(--text3); text-transform:none; letter-spacing:0; font-weight:400; font-size:.55rem; }
.patch-lyr-perc { background:linear-gradient(110deg, color-mix(in srgb, var(--eff) 9%, var(--surface2)), var(--surface2)); }
.patch-lyr-badge.perc { background:color-mix(in srgb, var(--eff) 22%, var(--display)); color:var(--eff); }

/* The module smart-combo sits in a COLUMN flex here; keep it button-height so
   it can't stretch open a big gap (which also dropped its popover to the pane
   bottom) — the root of the "weird layers panel" (owner 2026-07-10). */
.patch-inspector .smart-combo { flex:0 0 auto; }
/* Fit the three-column view into the dock: the inspector fills the dock and each
   pane scrolls INTERNALLY, so the whole editor never scroll-jumps and the space
   stage stays put (owner 2026-07-10). Combined with a taller patch dock. */
.patch-editor-wrap .editor-body { overflow:hidden; }
.patch-inspector { display:flex; flex-direction:column; height:100%; min-height:0; }
.patch-inspector-grid { flex:1; min-height:120px; }
.patch-inspector-grid .patch-pane { gap:7px; padding:9px 11px; overflow-y:auto; min-height:0; }
.patch-inspector-grid .patch-pane::-webkit-scrollbar { width:6px; }
.patch-inspector-grid .patch-pane::-webkit-scrollbar-thumb { background:rgba(120,130,150,0.3); border-radius:4px; }
.patch-sound-meta { margin-top:1px; }
.patch-module-card { padding:6px 7px; gap:4px; }
.patch-pane p, .patch-pane-space > p, .patch-global-note { line-height:1.28; }

/* ── patch inspector: drag-drop module swap + 2-col macro (owner 2026-07-10) ── */
/* Percussion + Note engine sit side by side to shorten the macro pane; Scale
   spans full width below. */
.patch-macro-2col { display:grid; grid-template-columns:1fr 1fr; gap:6px; align-items:start; }
.patch-pane-name { max-width:58%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* the sub-note & macro dropdowns are gone — swap a module by dragging a browser
   preset onto the pane; it outlines GREEN before dropping */
.patch-drop-hint { margin-top:auto; padding:5px 7px; border:1px dashed var(--border2); border-radius:6px; color:var(--text3); font-size:.57rem; line-height:1.3; text-align:center; opacity:.65; }
.patch-inspector-grid [data-patch-drop] { transition:background-color .08s; }
.patch-inspector-grid [data-patch-drop].drop-target { outline:2px solid var(--green); outline-offset:-2px; background:color-mix(in srgb, var(--green) 9%, transparent); }
.patch-inspector-grid [data-patch-drop].drop-target .patch-drop-hint { border-color:var(--green); border-style:solid; color:var(--green); opacity:1; }
/* keep the left (sub-note) pane stacked above the middle/macro panes (d) */
.patch-inspector-grid .patch-pane-subnote { position:relative; z-index:2; }

/* Harmonic guide: palette-first scale source search above the marker roll. */
/* HG-B3: this row is the expanded guide's LABEL BAND, and it now carries the
   change-point stars as well as the scale's name — "the star area in the same
   space as the scale name row, with the regular backing colour" (owner
   2026-08-29). `--surface` IS that regular colour: it is the ground this row
   has always had, and the black the stars used to sit on was the lane's own
   `.gs-strip` ground showing through a gap that no longer exists.
   The 16px left inset is the `.gs-name` clearance, for the same reason: the
   first change point is pinned at beat 0, so its star straddles x=0 and a label
   starting at the row's 7px padding had its first letter drawn through. */
.hg-head {
  position: relative;
  /* The row's height is the STAR's, not the label's. Without this floor it
     collapsed to 11px the moment the label yielded to a nearby change point
     (below), and the stars dropped straight through onto the division grid —
     the collision the old band existed to prevent, arriving by another door.
     35px is the height this row has WITH its label (`.hg-current`'s 24px plus
     the padding, border-box), so the lane does not change height depending on
     whether the name is showing. Measured, not chosen. */
  min-height: 35px;
  padding: 5px 7px 5px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
/* In this band the star centres on the row rather than on the 18px the old
   band was; `.gs-handle`'s `top: 9px` is the COLLAPSED lane's number. */
.hg-head > .gs-handle { top: 50%; }
.hg-picker { display:flex; align-items:center; gap:6px; min-width:0; }
.hg-picker input { width:min(260px,38%); min-width:150px; border:1px solid var(--border); border-radius:4px; background:var(--display); color:var(--text); padding:4px 6px; font-size:.65rem; }
.hg-choice-list { display:flex; align-items:center; gap:4px; overflow:auto; min-width:0; }
.hg-choice-list button { flex:0 0 auto; max-width:180px; border:1px solid var(--border); border-radius:4px; background:var(--surface2); color:var(--text); padding:3px 6px; text-align:left; cursor:pointer; }
.hg-choice-list button b,.hg-choice-list button i { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hg-choice-list button b { font-size:.62rem; }.hg-choice-list button i { color:var(--text3); font-size:.56rem; font-style:normal; }
.tl2-gsbtn { min-width:25px; font-size:.57rem; letter-spacing:-.04em; }

/* ── Six-part producer notation system (five until harmony joined, 2026-09-21) ────────────────────────────────
   Each supplied PNG is used as an alpha mask. The differently cropped source
   canvases are positioned into one shared badge here, so active parts can be
   recoloured without maintaining duplicate artwork. */
.saem-icon {
  position:relative; display:inline-block; flex:0 0 auto; width:62px; height:38px;
  color:#737d8d; border:0; background:transparent; box-sizing:border-box; vertical-align:middle;
}
.saem-icon.compact { width:40px; height:25px; }
.saem-icon.has-active { border:0; box-shadow:none; }
.saem-part {
  position:absolute; display:block; background:#56606d; opacity:.68;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-size:contain; mask-size:contain;
  filter:drop-shadow(0 1px rgba(0,0,0,.9)) drop-shadow(0 -1px rgba(255,255,255,.055));
}
.saem-part.active {
  background:#367db9; opacity:1;
  filter:drop-shadow(-.65px 0 #7eb5df) drop-shadow(.65px 0 #7eb5df)
    drop-shadow(0 -.65px #7eb5df) drop-shadow(0 1px rgba(0,6,14,.96));
}
.saem-stave { left:3%; top:5%; width:94%; height:58%; -webkit-mask-image:url('/saem-icons/stave.png'); mask-image:url('/saem-icons/stave.png'); }
.saem-clef { left:8%; top:0; width:31%; height:78%; -webkit-mask-image:url('/saem-icons/clef.png'); mask-image:url('/saem-icons/clef.png'); }
/* Notes 1% → -6% and slur 59% → 46.5% (owner 2026-09-21): both lifted to open
   the band under the stave for the harmony numerals. The beam overhangs the box
   top by ~2px at full size; nothing clips it (checked in the rows). */
.saem-notes { left:42%; top:-6%; width:45%; height:62%; -webkit-mask-image:url('/saem-icons/notes.png'); mask-image:url('/saem-icons/notes.png'); }
.saem-space { left:43%; top:46.5%; width:42%; height:19%; -webkit-mask-image:url('/saem-icons/slur.png'); mask-image:url('/saem-icons/slur.png'); }
/* harmony — the three primary chords, I IV V, written under the stave where
   chord symbols go: between the stave and the percussion line. Owner
   2026-09-21 — first drawn as a figured bass (6 over 4); roman numerals read
   wide rather than tall, which is the shape this band actually has.
   An inline SVG mask rather than a sixth PNG so it needs no asset route; if
   the owner draws one, swap the two urls for /saem-icons/harmony.png. */
/* left:42% is the first notehead's left edge (column 1 of notes.png, measured),
   so the numerals begin where the music does (owner 2026-09-21). */
.saem-harmony { left:42%; top:64.5%; width:44%; height:19%; -webkit-mask-position:left center; mask-position:left center; -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 150 40'%3E%3Cg font-family='Georgia,Times New Roman,serif' font-weight='700' font-size='44' text-anchor='middle' stroke='%23000' stroke-width='1.6' stroke-linejoin='round'%3E%3Ctext x='10' y='36'%3EI%3C/text%3E%3Ctext x='69' y='36'%3EIV%3C/text%3E%3Ctext x='133' y='36'%3EV%3C/text%3E%3C/g%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 150 40'%3E%3Cg font-family='Georgia,Times New Roman,serif' font-weight='700' font-size='44' text-anchor='middle' stroke='%23000' stroke-width='1.6' stroke-linejoin='round'%3E%3Ctext x='10' y='36'%3EI%3C/text%3E%3Ctext x='69' y='36'%3EIV%3C/text%3E%3Ctext x='133' y='36'%3EV%3C/text%3E%3C/g%3E%3C/svg%3E"); }
/* 78% → 84%: the line moved down to open the band the figures stand in. */
.saem-percussion { left:4%; top:84%; width:88%; height:15%; -webkit-mask-image:url('/saem-icons/percussion.png'); mask-image:url('/saem-icons/percussion.png'); }

/* Six ticking facets (harmony joined 2026-09-21), no All: an empty row already means everything
   (owner 2026-08-14), so the button that used to say so has gone and the
   marks share the width evenly. */
.saem-browser-facets { display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:3px; margin:3px 0 5px; align-items:center; }
.saem-browser-facets > button {
  min-width:0; min-height:28px; padding:1px; border:1px solid var(--border);
  border-radius:6px; background:var(--display); color:var(--text3); cursor:pointer;
}
.saem-browser-facets .saem-icon { width:100%; max-width:40px; }
.saem-browser-facets > button.active { border-color:#4b91cf; background:rgba(41,88,133,.2); color:var(--text); }
.saem-browser-facets .saem-icon { background:transparent; }
.browser-row > .saem-icon { margin-right:2px; }
.pal-top { display:flex; align-items:center; gap:6px; width:100%; min-width:0; flex-wrap:nowrap; }
.pal-top > .saem-icon { margin-right:1px; }
.pal-top > .pal-name { flex:1 1 60px; }
.pal-top > .pal-kind { flex:0 0 auto; }
.pal-top > .pal-actions { flex:0 0 auto; margin-left:4px; justify-content:flex-end; }
.pal-module-names { display:flex; flex-wrap:wrap; gap:3px 7px; width:100%; padding-left:47px; }
.pal-module-name { min-width:0; color:var(--text2); font-size:.56rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pal-module-name b { margin-right:4px; color:var(--text3); font-size:.48rem; font-weight:600; letter-spacing:.05em; text-transform:uppercase; }
.editable-name { cursor:text; }
.editable-name:hover { color:var(--text); text-decoration:underline dotted rgba(126,181,223,.7); text-underline-offset:2px; }
.inline-name-input { min-width:70px; max-width:100%; height:22px; padding:2px 5px; border:1px solid #4b91cf; border-radius:4px; background:var(--display); color:var(--text); font:inherit; font-size:.64rem; }

.saem-route {
  flex:0 0 auto !important; width:auto !important; height:auto !important; margin:0 !important;
  padding:1px !important; border:1px solid transparent !important; border-radius:6px !important;
  background:transparent !important; cursor:pointer;
}
.saem-route:hover,.saem-route.active { border-color:#4b91cf !important; background:rgba(41,88,133,.18) !important; }
.patch-inspector-grid .patch-pane > header > .saem-route + span { margin-left:0; }
/* The scale card's × and ✎ sit in a wrapper div, as the Sub-note and Note
   engine headers do — so the `> button` rule above does not reach them and they
   fell back to the browser's own button chrome: light slabs on a dark panel.
   Same treatment as those headers, which is what "the same as the other parts"
   asked for. */
.patch-module-card-head > div { display:flex; gap:2px; margin-left:2px; }
.patch-module-card-head > div > button {
  width:18px; height:18px; padding:0; margin:0; font-size:.7rem; line-height:1;
  border:1px solid transparent; border-radius:4px;
  background:transparent; color:var(--text3); cursor:pointer;
}
.patch-module-card-head > div > button:hover {
  color:var(--text); border-color:var(--border); background:var(--surface2);
}
.patch-module-card-head > div > button:focus-visible {
  outline:2px solid var(--accent); outline-offset:1px;
}
.patch-module-card-head > .saem-route { margin-right:2px !important; }
.patch-module-card-head > .editable-name { margin-left:auto; max-width:48%; color:var(--text3); font-size:.56rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.patch-module-card > small { color:var(--text3); font-size:.58rem; }

.gs-chevron { display:flex; align-items:center; gap:5px; }
.gs-chevron .saem-icon { background:transparent; }
.hg-current { color:var(--text); font-size:.78rem; font-weight:600; min-height:24px; display:flex; align-items:center; }
.hg-current.hg-empty { color:var(--text3); font-weight:400; font-style:italic; }
.hg-divs { color:var(--text3); font-size:.62rem; }
.hg-divs::before { content:"·"; margin-right:6px; color:var(--text3); }

.patch-save-wrap { position:relative; }
.patch-save-toggle.dirty { box-shadow:0 0 0 1px rgba(75,145,207,.4); }
.patch-save-pop {
  position:absolute; z-index:60; top:calc(100% + 6px); right:0; width:360px; padding:10px;
  border:1px solid var(--border2); border-radius:8px; background:var(--surface);
  box-shadow:0 14px 38px rgba(0,0,0,.52); text-align:left;
}
.patch-save-pop > label { display:flex; align-items:center; gap:8px; color:var(--text2); font-size:.65rem; }
.patch-save-pop > label input { flex:1; min-width:0; padding:5px 7px; border:1px solid var(--border); border-radius:5px; background:var(--display); color:var(--text); }
.patch-save-label { margin:9px 0 5px; color:var(--text3); font-size:.58rem; letter-spacing:.08em; text-transform:uppercase; }
.saem-selector { display:grid; grid-template-columns:1fr 1fr; gap:5px; }
.saem-selector-part {
  display:flex; align-items:center; gap:6px; min-width:0; padding:4px; border:1px solid var(--border);
  border-radius:6px; background:var(--display); color:var(--text3); cursor:pointer; text-align:left;
}
.saem-selector-part.selected { border-color:rgba(75,145,207,.8); color:var(--text); background:rgba(41,88,133,.14); }
.saem-selector-part:disabled { opacity:.3; cursor:not-allowed; filter:grayscale(1); }
.saem-selector-part > span:last-child { overflow:hidden; font-size:.58rem; text-overflow:ellipsis; white-space:nowrap; }
.patch-save-actions { display:flex; justify-content:flex-end; gap:6px; margin-top:9px; }

@media (max-width:720px) {
  .patch-save-pop { position:fixed; left:10px; right:10px; top:auto; bottom:10px; width:auto; }
}

/* ─── Save overlay: pick which modules go down ───
   The same five marks as the library rows and the Producer's Include selector,
   but given room to breathe — one part per row, so the lit region of the mark
   reads as "this is the piece of the patch you're keeping". */
.save-modal .save-parts { display:flex; flex-direction:column; gap:6px; }
.save-modal .save-parts-head { display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
.save-modal .save-parts-title { color:var(--text2); font-size:.78rem; font-weight:600; }
.save-modal .save-parts-toggle {
  padding:0; border:none; background:none; color:var(--accent);
  font-family:inherit; font-size:.72rem; font-weight:600; cursor:pointer;
}
.save-modal .save-parts-toggle:hover { text-decoration:underline; }
.save-modal .save-parts-toggle[hidden] { display:none; }
.save-modal .save-parts-sum { margin:1px 0 0; }
.save-modal .saem-selector { display:flex; flex-direction:column; gap:4px; }
.save-modal .saem-selector-part {
  gap:10px; padding:7px 10px; border-color:var(--border2); border-radius:7px;
  color:var(--text2); font-family:inherit; font-weight:600;
  transition:border-color .12s, background .12s, color .12s;
}
.save-modal .saem-selector-part:hover:not(:disabled) { border-color:var(--text3); color:var(--text); }
.save-modal .saem-selector-part:disabled { opacity:.42; }
.save-modal .saem-selector-part > span:last-child { font-size:.8rem; }
/* Every row shows its own mark, so you can see WHERE in the whole notation
   that part sits; ticking it brings the mark up to full ink. */
.save-modal .saem-selector-part > .saem-icon { flex:none; width:46px; height:29px; opacity:.34; transition:opacity .12s; }
.save-modal .saem-selector-part:hover:not(:disabled) > .saem-icon { opacity:.6; }
.save-modal .saem-selector-part.selected > .saem-icon { opacity:1; }
/* The tick is the confirmation; the lit mark is the identification. */
.save-modal .saem-selector-part::after {
  content:"✓"; margin-left:auto; padding-left:6px; color:var(--accent);
  font-size:.9rem; opacity:0; transition:opacity .12s;
}
.save-modal .saem-selector-part.selected::after { opacity:1; }
.save-modal .saem-selector-part:disabled::after { content:"—"; opacity:.5; color:var(--text3); }

/* ─── Account control: embedded in each view's top panel ─── */
.account-bar { position:relative; display:inline-flex; align-items:center; flex:none;
  margin-left:auto; font-family: var(--font); }
.account-bar .acct-pill { display:inline-flex; align-items:center; gap:7px; padding:5px 11px;
  background: var(--surface); border:1px solid var(--border2); border-radius: 999px;
  color: var(--text); font-size:.82rem; font-weight:600; cursor:pointer; line-height:1; }
.account-bar .acct-pill:hover { border-color: var(--accent); }
.account-bar .acct-pill:focus { outline: none; }
.account-bar .acct-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.account-bar .acct-dot { width:7px; height:7px; border-radius:50%; background: var(--green); flex:none; }
.account-bar .acct-avatar { width:22px; height:22px; border-radius:50%; object-fit:cover;
  margin:-2px 0 -2px -5px; flex:none; }
.account-bar .acct-avatar.none { display:none; }
.account-bar .acct-avatar:not(.none) + .acct-dot { display:none; }
.account-bar .acct-name { max-width:14ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.account-bar .acct-pill.signin { color: var(--text2); font-weight:500; }
.account-bar .acct-pill.signin.primary { background: var(--accent); color:#000; border-color: var(--accent); font-weight:700; }
.account-bar .acct-pill.signin.primary:hover { filter:brightness(1.08); }
/* Signed-out "report a problem": glyph only, so it sits beside the primary
   sign-in call to action without competing with it. Square padding keeps the
   999px radius circular rather than lozenge-shaped. --text2, not --text3:
   the glyph is the whole affordance, and --text3 on --surface measures
   2.78:1, under the 3:1 a glyph carrying a control's meaning needs. */
.account-bar .acct-flag { padding:5px 9px; margin-right:6px; color: var(--text2);
  font-size:.9rem; }
.account-bar .acct-flag:hover { color: var(--text); }
.account-bar .acct-menu { position:absolute; top:calc(100% + 6px); right:0; min-width:180px; z-index:4000;
  background: var(--surface); border:1px solid var(--border2); border-radius: var(--radius); padding:6px;
  box-shadow: 0 14px 40px rgba(0,0,0,.5); }
.account-bar .acct-menu[hidden] { display:none; }
.account-bar .acct-who { padding:7px 9px 9px; border-bottom:1px solid var(--border); margin-bottom:5px; }
.account-bar .acct-who b { display:block; font-size:.85rem; color:var(--text); }
.account-bar .acct-who span { font-size:.72rem; color:var(--text3); }
.account-bar .acct-menu button { display:block; width:100%; text-align:left; padding:8px 9px;
  background:none; border:none; color: var(--text2); font-family:inherit; font-size:.83rem;
  border-radius: var(--radius-sm); cursor:pointer; }
.account-bar .acct-menu button:hover { background: var(--surface2); color: var(--text); }
.explore-top { display:flex; align-items:flex-start; }
.landing-header { position:relative; }
.landing-acct { position:absolute; top:14px; right:16px; }
/* The way back when the welcome page is reopened from inside the app via the
   logo — without it the landing page was a dead end (owner 2026-07-15). */
.landing-back {
  position: absolute; top: 14px; left: 16px;
  background: transparent;
  border: 1px solid var(--border2);
  color: var(--text2);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 0.85rem;
  cursor: pointer;
}
.landing-back:hover { color: var(--text); border-color: var(--text2); }
.profile-back { display:flex; align-items:center; }
.daw-transport .account-bar { margin-left:auto; }

/* App-owned dialogs and Producer file menu. */
.app-dialog-overlay { position:fixed; inset:0; z-index:5000; display:flex; align-items:center; justify-content:center; padding:24px; background:rgba(4,7,11,.72); backdrop-filter:blur(5px); -webkit-backdrop-filter:blur(5px); }
.app-dialog { width:min(440px,100%); padding:20px; border:1px solid var(--border2); border-radius:12px; background:var(--surface); box-shadow:0 24px 80px rgba(0,0,0,.58); }
.app-dialog h2 { margin:0 0 8px; font-size:1.05rem; }.app-dialog p { margin:0 0 14px; color:var(--text2); font-size:.82rem; }
.app-dialog-input { width:100%; padding:9px 10px; border:1px solid var(--border2); border-radius:7px; background:var(--display); color:var(--text); font:inherit; }
.app-dialog-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:16px; }.btn-danger { background:var(--red); border-color:var(--red); color:#fff; }
/* SSF spatial player: the tracker dot is the one live element — grey (no
   helper), amber (helper up, no AirPods), green (tracking). */
.ssf-player .ssf-status { min-height:1.1em; }
.ssf-track-row { display:flex; align-items:center; gap:7px; color:var(--text2); font-size:.76rem; }
.ssf-dot { flex:none; width:9px; height:9px; border-radius:50%; background:#888; box-shadow:0 0 6px rgba(0,0,0,.4); }
.ssf-yaw { margin-left:auto; color:var(--text3); font-size:.72rem; font-variant-numeric:tabular-nums; }
/* Head listening: ONE split control — the 3D head is the switch, the slim
   segment past the divider is the menu. Amber skull = on, green ears = a
   source is actually tracking. The head sits in a perspective plane tipped
   back (~50°) so it reads as an object, and the live yaw rotates the inner
   group within that plane — a head swivelling, not a badge spinning. */
/* A knob a measured room pins: visible, labelled, not editable — the value
   is the building's, not the user's. */
.knob-fixed { display:contents; }
.knob-fixed > * { opacity:.42; pointer-events:none; filter:saturate(.4); }

.hl-wrap.hl-split { position:relative; display:inline-flex; align-items:stretch; height:32px; flex:none;
  background:rgba(11,16,23,0.5); border:1px solid var(--border2); border-radius:7px; overflow:visible; }
.hl-btn, .hl-arrow { display:inline-flex; align-items:center; justify-content:center; border:0;
  background:transparent; color:var(--text2); cursor:pointer; font:inherit; padding:0; }
.hl-btn { width:34px; border-radius:6px 0 0 6px; }
.hl-arrow { width:16px; border-left:1px solid var(--border2); border-radius:0 6px 6px 0; }
.hl-btn:hover, .hl-arrow:hover { background:rgba(255,255,255,0.05); color:var(--text); }
.hl-wrap.hl-on { border-color:rgba(232,194,104,.55); box-shadow:0 0 8px rgba(232,194,104,.12); }
.hl-head3d { display:block; transform:perspective(70px) rotateX(48deg); }
.hl-btn svg { display:block; overflow:visible; }
.hl-btn #hlHeadG { transform-box:fill-box; transform-origin:50% 58%; transition:transform .06s linear; }
.hl-shadow { fill:rgba(0,0,0,.45); }
.hl-shoulders { fill:#39434f; }
.hl-skull { fill:url(#hlSkullOff); }
.hl-wrap.hl-on .hl-skull { fill:url(#hlSkullOn); }
.hl-nose { fill:#7c8ba0; }
.hl-wrap.hl-on .hl-nose { fill:#d9a53a; }
.hl-ear { fill:#66758a; }
.hl-wrap.hl-tracking .hl-ear { fill:#3fbf6f; }
.hl-shine { fill:rgba(255,255,255,.35); }
.hl-wrap.hl-on .hl-shoulders { fill:#4a4232; }
.hl-pop { position:absolute; top:calc(100% + 7px); right:0; left:auto; width:230px; }
/* setup dialog source cards */
.hl-sources { display:flex; flex-direction:column; gap:6px; }
.hl-source { display:flex; flex-direction:column; gap:2px; width:100%; padding:9px 11px; border:1px solid var(--border2); border-radius:8px; background:var(--display); color:var(--text2); text-align:left; cursor:pointer; font:inherit; font-size:.8rem; }
.hl-source b { color:var(--text); }
.hl-source span { font-size:.72rem; color:var(--text3); }
.hl-source:hover { border-color:var(--gold, #e8c268); }
.hl-source.sel { border-color:var(--gold, #e8c268); background:rgba(232,194,104,.07); }
/* The degraded-mode badge: quiet amber, but PERSISTENT — it stays for the
   rest of the session so the fallback is never mistaken for how the scene
   is meant to sound. Hover carries the full explanation. */
.ssf-degraded { display:flex; align-items:center; gap:7px; margin-top:8px; padding:5px 8px; border:1px solid rgba(217,165,58,.45); border-radius:6px; color:var(--text2); font-size:.72rem; background:rgba(217,165,58,.08); cursor:help; }
.ssf-degraded[hidden] { display:none; }
.ssf-degraded-dot { flex:none; width:7px; height:7px; border-radius:50%; background:#d9a53a; }
.daw-file-wrap { position:relative; flex:none; }.daw-file-button span { color:var(--text3); font-size:.58rem; }
.daw-file-pop { position:absolute; z-index:3000; top:calc(100% + 7px); left:0; width:240px; overflow:visible; padding:6px; border:1px solid var(--border2); border-radius:9px; background:var(--surface); box-shadow:0 18px 55px rgba(0,0,0,.58); }
.daw-file-pop[hidden] { display:none; }.daw-file-pop button { display:flex; flex-direction:column; gap:2px; width:100%; padding:7px 9px; border:0; border-radius:5px; background:transparent; color:var(--text2); text-align:left; cursor:pointer; font:inherit; font-size:.71rem; }
.daw-file-pop button:hover { background:var(--surface2); color:var(--text); }.daw-file-pop button.danger:hover { color:var(--red); }.daw-file-pop button b { color:inherit; font-size:.73rem; }.daw-file-pop button span,.daw-file-pop small { color:var(--text3); font-size:.61rem; }
.daw-file-section { margin-top:5px; padding-top:6px; border-top:1px solid var(--border); }.daw-file-section > strong { display:block; padding:3px 9px 4px; color:var(--text3); font-size:.56rem; letter-spacing:.09em; text-transform:uppercase; }.daw-file-ops { display:grid; grid-template-columns:1fr 1fr; }.daw-file-ops > strong { grid-column:1/-1; }
/* File menu fly-out submenus (Recent / Templates / Import-Export) */
.daw-file-divider { height:1px; background:var(--border); margin:5px 4px; }
.daw-file-sub { position:relative; }
.daw-file-pop .daw-file-subtrigger { flex-direction:row; align-items:center; justify-content:space-between; }
.daw-file-arrow { color:var(--text3); font-size:.7rem; }
.daw-file-flyout { position:absolute; left:100%; top:-7px; min-width:210px; max-height:min(460px,68vh); overflow:auto; padding:6px; border:1px solid var(--border2); border-radius:9px; background:var(--surface); box-shadow:0 18px 55px rgba(0,0,0,.58); display:none; }
.daw-file-sub:hover > .daw-file-flyout, .daw-file-sub:focus-within > .daw-file-flyout { display:block; }
.daw-file-sub:hover > .daw-file-subtrigger { background:var(--surface2); color:var(--text); }
.daw-file-empty { padding:7px 9px; color:var(--text3); font-size:.61rem; }

/* One coherent transport readout: position and editable BPM, no sliders. */
.daw-cluster-playback { border-color:color-mix(in srgb,var(--accent) 35%,var(--border)); background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 7%,var(--surface2)),var(--display)); }
.daw-transport-display { display:flex; align-items:stretch; overflow:hidden; border:1px solid var(--border2); border-radius:7px; background:#070b10; box-shadow:inset 0 1px 8px rgba(0,0,0,.55); }
.daw-transport-display > label,.daw-tempo-readout { display:grid; grid-template-columns:auto auto; align-items:center; gap:0 5px; min-width:64px; padding:3px 8px; border-right:1px solid var(--border); }
.daw-tempo-readout { grid-template-columns:auto auto auto; border-right:0; }.daw-transport-display span,.daw-tempo-readout span { grid-column:1/-1; color:var(--text3); font-size:.47rem; letter-spacing:.08em; text-transform:uppercase; }
.daw-pos { padding:0; border:0; background:transparent; color:var(--accent2); font:700 .78rem var(--mono); cursor:pointer; }.daw-tempo-readout input { width:38px; padding:0; border:0; outline:0; background:transparent; color:var(--accent2); font:700 .75rem var(--mono); }.daw-tempo-readout b { color:var(--text3); font-size:.47rem; }

.tl2-region.patch-selected { outline:2px solid color-mix(in srgb,var(--accent) 85%,white); outline-offset:1px; }

/* Effects read as a horizontal chain of filled mixer-style blocks. */
.prod-layer-fx,.layer-fx { flex-wrap:nowrap; overflow-x:auto; max-width:100%; padding-bottom:2px; }
.prod-fx-tag,.layer-fx-tag { flex:0 0 auto; min-width:132px; background:linear-gradient(90deg,color-mix(in srgb,var(--eff) 25%,var(--surface2)) 0 var(--wet),var(--surface2) var(--wet) 100%); }
.prod-fx-mix,.layer-fx-mix { display:flex; align-items:center; gap:3px; color:var(--text3); font-size:.46rem; text-transform:uppercase; }.prod-fx-wet,.layer-fx-wet { width:44px; }
.prod-fx-name,.layer-fx-name { max-width:86px; overflow:hidden; text-overflow:ellipsis; }.prod-fx-tag.off,.layer-fx-tag.off { filter:saturate(.2); }

.cloud-overlay { position: fixed; inset:0; z-index: 4100; background: rgba(8,9,12,.62);
  display:flex; align-items:center; justify-content:center; padding:24px; }
.cloud-overlay[hidden] { display:none; }
.cloud-modal { width:100%; max-width:520px; max-height:82vh; overflow:auto; background: var(--surface);
  border:1px solid var(--border2); border-radius: var(--radius); box-shadow: 0 24px 70px rgba(0,0,0,.55); }
.cloud-modal header { display:flex; align-items:center; justify-content:space-between;
  padding:16px 18px; border-bottom:1px solid var(--border); position:sticky; top:0; background:var(--surface); }
.cloud-modal header h3 { margin:0; font-size:1.02rem; }
.cloud-modal header button.x { background:none; border:none; color:var(--text2); font-size:1.3rem; cursor:pointer; }
.cloud-actions { display:flex; gap:8px; padding:14px 18px; border-bottom:1px solid var(--border); flex-wrap:wrap; }
.cloud-actions button { padding:8px 12px; border-radius: var(--radius-sm); border:1px solid var(--border2);
  background: var(--surface2); color: var(--text); font-family:inherit; font-size:.82rem; font-weight:600; cursor:pointer; }
.cloud-actions button.primary { background: var(--accent); color:#000; border-color: var(--accent); }
.cloud-actions button:hover { border-color: var(--accent); }
.cloud-list { list-style:none; margin:0; padding:8px 12px 16px; }
.cloud-list li { display:flex; align-items:center; gap:10px; padding:9px 8px; border-bottom:1px solid var(--border); }
.cloud-list li:last-child { border-bottom:none; }
.cloud-list .c-name { flex:1; min-width:0; }
.cloud-list .c-name b { display:block; font-size:.88rem; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cloud-list .c-name span { font-size:.7rem; color:var(--text3); }
.cloud-list .c-act { background:none; border:1px solid var(--border2); border-radius:5px; color:var(--text2);
  padding:4px 9px; font-size:.76rem; cursor:pointer; }
.cloud-list .c-act:hover { color:var(--text); border-color:var(--accent); }
.cloud-list .c-act.danger:hover { color:var(--red); border-color:var(--red); }
.cloud-empty { padding:22px 18px; color: var(--text3); font-size:.86rem; text-align:center; }

/* ─── Auth overlay (in-app create profile / log in) ─── */
.auth-modal { max-width:400px; }
.auth-modal header h3 { display:flex; align-items:center; gap:8px; }
.auth-tabs { display:flex; gap:4px; margin:14px 18px 0; padding:4px; background: var(--display);
  border:1px solid var(--border); border-radius: var(--radius-sm); }
.auth-tabs button { flex:1; padding:8px 0; background:none; border:none; border-radius:5px;
  color: var(--text3); font-family:inherit; font-size:.84rem; font-weight:600; cursor:pointer; }
.auth-tabs button.active { background: var(--surface2); color: var(--text); }
.auth-tabs button:hover { color: var(--text); }
.auth-reason { margin:12px 18px 0; padding:9px 11px; background: var(--surface2); border:1px solid var(--border);
  border-radius: var(--radius-sm); color: var(--text2); font-size:.8rem; }
.auth-form { display:flex; flex-direction:column; gap:11px; padding:16px 18px 6px; }
.auth-form label { display:flex; flex-direction:column; gap:5px; color: var(--text2); font-size:.78rem; font-weight:600; }
/* This `display:flex` outranks the UA's [hidden] rule, so every label the JS
   hides stayed on screen — the save overlay's Description box showed whether
   or not you were sharing. */
.auth-form label[hidden] { display:none; }
.auth-form input { padding:9px 10px; border:1px solid var(--border2); border-radius:7px;
  background: var(--display); color: var(--text); font:inherit; }
.auth-form input:focus { border-color: var(--accent); outline:none; }
.auth-hint { color: var(--text3); font-size:.72rem; font-weight:400; margin:0; }
.auth-form .auth-hint b { color: var(--text2); }
.auth-error { padding:8px 10px; background: color-mix(in srgb, var(--red) 14%, var(--surface));
  border:1px solid var(--red); border-radius: var(--radius-sm); color: var(--text); font-size:.78rem; }
.auth-error[hidden] { display:none; }
.auth-form button.primary { margin-top:4px; padding:10px 12px; border-radius: var(--radius-sm);
  border:1px solid var(--accent); background: var(--accent); color:#000; font-family:inherit;
  font-size:.86rem; font-weight:700; cursor:pointer; }
.auth-form button.primary:hover { filter:brightness(1.08); }
.auth-switch { display:block; width:100%; padding:12px 18px 16px; background:none; border:none;
  color: var(--text3); font-family:inherit; font-size:.78rem; cursor:pointer; text-align:center; }
.auth-switch:hover { color: var(--accent); }
.auth-form textarea { padding:9px 10px; border:1px solid var(--border2); border-radius:7px;
  background: var(--display); color: var(--text); font:inherit; resize:vertical; }
.save-share-row { flex-direction:row !important; align-items:center; gap:8px !important;
  color: var(--text2); font-size:.82rem; cursor:pointer; }
/* Sticky action rail for the save overlay. Ticking "Share to the community
   too" adds the Description field, which pushes the form past the modal's
   max-height — 80% of "Save & share" sat below the fold behind a very quiet
   scrollbar, so the only visible cue was an orange hairline. Negative margins
   bleed it through .auth-form's 18px padding to the modal edges. */
.save-modal .save-modal-actions {
  position:sticky; bottom:0; z-index:1;
  display:flex; flex-direction:column; gap:11px;
  margin:0 -18px -6px; padding:11px 18px 14px;
  background: var(--surface); border-top:1px solid var(--border);
}
.save-modal .save-modal-actions button.primary { margin-top:0; }
.top-save-btn { white-space:nowrap; }
/* Unsaved changes (basics audit #11): a mark on the corner, so it reads at
   every width, including when the label has gone. Neutral, not a hue: it is
   a state of the chrome, not data. Its ring is the bar's own ground, so it
   sits on the pill's edge rather than blending into the amber. */
.top-save-btn { position: relative; }
.top-save-btn.dirty::after {
  content: ""; position: absolute; top: -3px; right: -3px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--text); box-shadow: 0 0 0 2px var(--display);
  pointer-events: none;
}
.auth-form textarea:focus { border-color: var(--accent); outline:none; }

/* ─── Auth ENTRY card (create profile / log in) — shared design with the
   standalone /login page. Scoped to .auth-entry so the save / profile /
   share modals keep their plain header + title-case labels. ─── */
.auth-entry { max-width: 400px; position: relative; padding-bottom: 4px; }
.auth-entry .auth-x {
  position: absolute; top: 12px; right: 14px; z-index: 2;
  background: none; border: none; color: var(--text3);
  font-size: 1.4rem; line-height: 1; cursor: pointer; padding: 2px 7px; border-radius: 6px;
}
.auth-entry .auth-x:hover { color: var(--text); background: var(--surface2); }
.auth-brand { display: flex; align-items: center; gap: 12px; padding: 24px 24px 2px; }
.auth-brand-icon { width: 44px; height: 44px; border-radius: 11px; flex: none; box-shadow: 0 2px 10px rgba(0,0,0,0.35); }
.auth-brand-text h3 {
  margin: 0; font-family: var(--brand-font); font-size: 1.45rem; font-weight: 800;
  letter-spacing: 0.01em; color: var(--text); line-height: 1.1;
}
.auth-sub { margin: 2px 0 0; color: var(--text3); font-size: 0.82rem; }
.auth-entry .auth-tabs { margin: 20px 24px 0; padding: 4px; }
.auth-entry .auth-tabs button { padding: 9px 0; font-size: 0.85rem; }
.auth-entry .auth-tabs button.active { box-shadow: inset 0 0 0 1px rgba(255,255,255,0.03); }
.auth-entry .auth-reason { margin: 14px 24px 0; }
.auth-entry .auth-form { padding: 20px 24px 24px; gap: 14px; }
.auth-entry .auth-form > label {
  text-transform: uppercase; letter-spacing: 0.07em; font-size: 0.66rem;
  font-weight: 700; color: var(--text3); gap: 7px;
}
.auth-entry .auth-form > label .auth-hint { text-transform: none; letter-spacing: normal; font-weight: 400; }
.auth-entry .auth-form input { padding: 11px 12px; font-size: 0.92rem; background: var(--bg); }
.auth-entry .auth-form > .auth-hint { margin-top: -4px; }
.auth-entry .auth-form button.primary { margin-top: 8px; padding: 12px; font-size: 0.95rem; }

/* ─── Community: context menu, stars, browser tier ─── */
.ctx-menu { position:fixed; z-index:5200; min-width:190px; margin:0; padding:5px; list-style:none;
  background: var(--surface); border:1px solid var(--border2); border-radius:9px;
  box-shadow: 0 18px 55px rgba(0,0,0,.58); }
.ctx-menu li { margin:0; padding:0; }
.ctx-menu button { display:block; width:100%; padding:8px 10px; background:none; border:none;
  border-radius:5px; color: var(--text2); font-family:inherit; font-size:.8rem; text-align:left; cursor:pointer; }
.ctx-menu button:hover { background: var(--surface2); color: var(--text); }
.ctx-menu button.danger:hover { color: var(--red); }

.br-author { display:block; color: var(--text3); font-size:.64rem; font-weight:400; }
.browser-row .br-author { margin-top:1px; }

.stars { display:inline-flex; align-items:center; gap:1px; color: var(--text3); font-size:.85rem; line-height:1; }
.stars .star { color: var(--border2); cursor:default; }
.stars .star.on { color: var(--accent); }
.stars.editable .star { cursor:pointer; transition: transform .1s ease, color .12s ease; }
/* Fill left→right up to the hovered star (`:has(~ :hover)` = earlier siblings). */
.stars.editable .star:hover, .stars.editable .star:has(~ .star:hover) { color: var(--accent2); }
.stars.editable .star:hover { transform: scale(1.25); }
.stars.editable .star:active { transform: scale(1.45); }
.stars .stars-label { margin-left:6px; color: var(--text3); font-size:.68rem; }
.rate-modal .rate-body { padding:14px 18px 20px; display:flex; flex-direction:column; gap:12px; }
.rate-modal .stars { font-size:1.5rem; gap:5px; }

/* ─── Community browser overlay ─── */
.pal-btn.community-open { width:auto; padding:2px 9px; font-size:.66rem; letter-spacing:.04em;
  border:1px solid color-mix(in srgb, var(--accent) 45%, var(--border2)); border-radius:999px;
  color: var(--accent2); transition: background .15s ease, color .15s ease; }
.pal-btn.community-open:hover { background: var(--accent); color:#000; }
.cmty-modal { max-width:1080px; width:94vw; height:86vh; max-height:86vh; display:flex; flex-direction:column; overflow:hidden; }

/* ── FE-12: full-page community (owner 2026-08-28) ─────────────────────────
   "There should also be an expand to full page option for the community and
   everything should scale up sensibly."
   The second half is the work. Simply removing the max-width would have given
   a 2560px screen the same 250px cards with a great deal more gutter between
   them — wider, not bigger. So the things you are actually reading grow too:
   the cards take a larger minimum, the type steps up, the padding opens out,
   and the auditioner's machine (which is sized from its own box) gets more
   height to be drawn into. */
.cmty-modal.full {
  max-width: none;
  width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  border-radius: 0;
  border-left: 0;
  border-right: 0;
}
.cmty-modal.full .cmty-results { padding: 22px clamp(20px, 4vw, 64px); }
.cmty-modal.full .cmty-grid {
  grid-template-columns: repeat(auto-fill, minmax(clamp(300px, 22vw, 420px), 1fr));
  gap: 16px;
}
.cmty-modal.full .cmty-card { padding: 15px 16px; gap: 8px; border-radius: 11px; }
.cmty-modal.full .cmty-card-title b { font-size: 0.98rem; }
.cmty-modal.full .cmty-controls { padding: 14px clamp(20px, 4vw, 64px); }
.cmty-modal.full .cmty-controls input[type="search"] { font-size: 0.92rem; padding: 10px 14px; }
.cmty-modal.full header { padding-left: clamp(20px, 4vw, 64px); padding-right: 16px; }
.cmty-modal.full header h3 { font-size: 1.15rem; }

.cmty-expand {
  flex: none;
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  margin-right: 2px;
  border: 1px solid var(--border2); border-radius: 7px;
  background: transparent; color: var(--text3);
  font-size: 0.92rem; line-height: 1; cursor: pointer;
}
.cmty-expand:hover { background: var(--surface2); color: var(--text); }
.cmty-expand[aria-pressed="true"] { color: var(--accent2); border-color: rgba(245,166,35,0.5); }
.cmty-expand:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.cmty-modal header { flex:none; gap:14px; }
.cmty-tabs { display:flex; gap:4px; margin-right:auto; margin-left:10px; }
.cmty-tabs button { padding:6px 12px; background:none; border:1px solid transparent; border-radius:999px;
  color: var(--text3); font-family:inherit; font-size:.8rem; font-weight:600; cursor:pointer; }
.cmty-tabs button:hover { color: var(--text); }
.cmty-tabs button.active { background: var(--surface2); border-color: var(--border2); color: var(--text); }
.cmty-controls { flex:none; display:flex; align-items:center; gap:8px; padding:10px 18px;
  border-bottom:1px solid var(--border); flex-wrap:wrap; }
.cmty-controls input[type="search"] { flex:1; min-width:180px; padding:8px 11px; border:1px solid var(--border2);
  border-radius:999px; background: var(--display); color: var(--text); font:inherit; font-size:.84rem; }
.cmty-controls input[type="search"]:focus { border-color: var(--accent); outline:none; }
.cmty-byuser { display:flex; align-items:center; gap:5px; color: var(--text3); font-size:.75rem; white-space:nowrap; }
.cmty-controls select { padding:7px 9px; border:1px solid var(--border2); border-radius:7px;
  background: var(--surface2); color: var(--text2); font:inherit; font-size:.76rem; }
.cmty-results { flex:1; overflow:auto; padding:14px 18px; }
.cmty-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(250px, 1fr)); gap:10px; }
.cmty-card { display:flex; flex-direction:column; gap:6px; padding:11px 12px; background: var(--surface2);
  border:1px solid var(--border); border-radius:9px; cursor:grab;
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease; }
.cmty-card:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--border2));
  transform: translateY(-2px); box-shadow: 0 8px 22px rgba(0,0,0,.32); }
.cmty-card:active { cursor:grabbing; transform: translateY(0); }
.cmty-card-head { display:flex; align-items:flex-start; gap:8px; }
.cmty-card-title { flex:1; min-width:0; }
.cmty-card-title b { display:block; font-size:.85rem; color: var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cmty-author { background:none; border:none; padding:0; color: var(--text3); font-family:inherit; font-size:.7rem; cursor:pointer; }
.cmty-author:hover { color: var(--accent); text-decoration:underline; }
.cmty-author.big { font-size:.88rem; color: var(--text); font-weight:600; text-align:left; }
.cmty-author.big span { color: var(--text3); font-weight:400; font-size:.74rem; }
.cmty-kind { color: var(--text3); font-size:.62rem; text-transform:uppercase; letter-spacing:.05em; white-space:nowrap; }
.cmty-desc { margin:0; color: var(--text2); font-size:.74rem; line-height:1.4; }
.cmty-tags { display:flex; flex-wrap:wrap; gap:4px; }
.cmty-tag { padding:2px 8px; background: var(--display); border:1px solid var(--border); border-radius:999px;
  color: var(--text3); font-family:inherit; font-size:.66rem; cursor:pointer; }
.cmty-tag:hover { color: var(--accent); border-color: var(--accent); }
.cmty-card-foot { display:flex; align-items:center; gap:7px; margin-top:auto; }
.cmty-spacer { flex:1; }
.cmty-add { padding:4px 10px; border:1px solid var(--border2); border-radius:999px; background: var(--surface);
  color: var(--text2); font-family:inherit; font-size:.72rem; font-weight:600; cursor:pointer; white-space:nowrap; }
.cmty-add:hover:not(:disabled) { border-color: var(--accent); color: var(--text); }
.cmty-add.added { color: var(--green); border-color: color-mix(in srgb, var(--green) 40%, var(--border2)); cursor:default; }
.cmty-yours { color: var(--text3); font-size:.68rem; font-style:italic; }
.cmty-empty { display:flex; flex-direction:column; align-items:center; gap:12px;
  padding:40px 20px; color: var(--text3); font-size:.86rem; text-align:center; }
.cmty-empty .aud-mini-svg { width:64px; height:64px; opacity:.6; }
.cmty-empty .aud-mini-svg .icon-art { fill:none; stroke: var(--text3); }
.cmty-empty .aud-mini-svg .icon-fill { fill: var(--text3); }

/* Loading: shimmer skeleton cards instead of a bare "Loading…". */
@keyframes cmty-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.cmty-skel { height:118px; border-radius:9px; border:1px solid var(--border);
  background: linear-gradient(100deg, var(--surface2) 40%, color-mix(in srgb, var(--border2) 45%, var(--surface2)) 50%, var(--surface2) 60%);
  background-size: 200% 100%; animation: cmty-shimmer 1.4s linear infinite; }
@media (prefers-reduced-motion: reduce) { .cmty-skel { animation:none; } }

.cmty-toplist { margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:2px;
  counter-reset: cmty-rank; }
.cmty-toplist li { display:flex; align-items:baseline; gap:12px; padding:10px 8px;
  border-bottom:1px solid var(--border); counter-increment: cmty-rank; }
.cmty-toplist li::before { content: counter(cmty-rank); flex:none; width:26px; height:26px;
  display:inline-flex; align-items:center; justify-content:center; align-self:center;
  border-radius:50%; border:1px solid var(--border2); color: var(--text3);
  font-size:.74rem; font-weight:700; font-family: var(--mono); }
.cmty-toplist li:nth-child(1)::before { border-color: var(--accent); color: var(--accent); }
.cmty-toplist li:nth-child(2)::before, .cmty-toplist li:nth-child(3)::before {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border2)); color: var(--text2); }
.cmty-topscore { color: var(--accent); font-size:.8rem; font-weight:700; white-space:nowrap; }
.cmty-topitems { color: var(--text3); font-size:.72rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* ─── Auditioner: the home page's machine, standing on the strip ─── */
.cmty-auditioner { flex:none; position:relative; display:flex; flex-direction:column;
  --aud-h: 168px;
  padding:10px 18px; border-top:1px solid var(--border2); background: var(--surface); }
.cmty-modal.full .cmty-auditioner { --aud-h: clamp(168px, 20vh, 236px); padding-left: clamp(20px, 4vw, 64px); padding-right: clamp(20px, 4vw, 64px); }
/* The shadow the machine stands in: a full-width fade from the strip up,
   edge to edge of the overlay (owner 2026-10-19: "the gradient overlay doesn't
   go to the edge"), so the cards behind the machine drop back evenly. */
.cmty-auditioner::before {
  content:""; position:absolute; left:0; right:0; bottom:100%; z-index:5; pointer-events:none;
  height: calc(var(--aud-h) + 64px);
  background: linear-gradient(to top,
    var(--surface) 0%,
    color-mix(in srgb, var(--surface) 94%, transparent) 55%,
    color-mix(in srgb, var(--surface) 70%, transparent) 80%,
    transparent 100%);
}
.cmty-auditioner.min::before { display:none; }
/* Let the last cards scroll clear of the machine standing over the results. */
.cmty-results { padding-bottom: 200px; }

/* The machine: aspect-locked to the drawing's viewBox. It ignores pointer
   events except on its own parts, so cards behind its empty air stay
   clickable. */
.aud-machine { position:absolute; bottom:calc(100% - 4px); left:18px; z-index:6;
  height: var(--aud-h); aspect-ratio: 1480 / 450; max-width:calc(100% - 36px);
  pointer-events:none; }
.cmty-modal.full .aud-machine { left: clamp(20px, 4vw, 64px); }
.aud-svg { display:block; width:100%; height:100%; overflow:visible; }
.aud-svg .aud-part { pointer-events:auto; }
.aud-svg .aud-hit { cursor:pointer; }
.aud-svg .aud-hit-ns { cursor:ns-resize; }
.aud-svg .aud-hit-ew { cursor:ew-resize; }
.aud-svg #audCrankHit { cursor:grab; }

/* A part sleeps in the app's greys until its slot is filled; a loaded part
   wears the drawing's own materials. Fully opaque either way. */
.aud-svg .aud-part:not(.on) > [data-o],
.aud-svg .aud-part.no-perc > [data-o] {
  --o-panel: var(--surface2); --o-plane-top: var(--border2); --o-plane-side: var(--display);
  --o-paper: var(--border2); --o-bell: var(--display);
  --o-ink: var(--text3); --o-ink-soft: color-mix(in srgb, var(--text3) 75%, transparent);
}
/* Dragging a card over the machine inks the parts it would fill in amber,
   the landing page's lit look. */
.aud-svg .aud-part.drop-target > [data-o] { --o-ink: var(--accent); --o-ink-soft: var(--accent); }

/* The counter plate on the plinth, under the roll. */
.aud-svg .aud-plate { fill: var(--display); stroke: var(--o-ink-soft, var(--text3)); stroke-width:1.2; }
.aud-svg .aud-tick { fill: var(--text2); font: 700 17px var(--mono); font-variant-numeric: tabular-nums; }
.aud-svg .aud-tick.sep { fill: var(--text3); }
.aud-svg .aud-part.on .aud-tick { fill: var(--accent2); }
.aud-svg .aud-part.on .aud-plate { stroke: color-mix(in srgb, var(--accent) 45%, var(--border2)); }

/* Motion. Each moving piece keeps machine-v2.css's animation, paused; it runs
   only when its own slot is loaded and the machine is playing. The roll and
   the drum follow the tempo (--sheet-dur / --tap-dur, set inline); the crank
   turns at its own pace. Live tempo and fast-forward ride on playbackRate. */
.aud-svg #audCrank .m-spin, .aud-svg #audCrank .m-roll { animation-duration: 3.2s; }
.aud-svg #audRoll .m-roll { animation-duration: var(--sheet-dur, 4s); }
.aud-svg #audPerc .m-swing, .aud-svg #audPerc .m-tilt { animation-duration: var(--tap-dur, 1s); }
.aud-machine.playing .aud-part.on .m-spin, .aud-machine.playing .aud-part.on .m-roll,
.aud-machine.playing .aud-part.on .m-pulse, .aud-machine.playing .aud-part.on .m-slide,
.aud-machine.playing .aud-part.on .m-swing, .aud-machine.playing .aud-part.on .m-tilt,
.aud-machine.playing .aud-part.on .steam-bubble { animation-play-state: running; }
.aud-machine.playing .aud-part.on .m-wave { animation: o-wave 1.8s ease-out infinite; }
.aud-svg .aud-part.no-perc .m-swing, .aud-svg .aud-part.no-perc .m-tilt, .aud-svg .aud-part.no-perc .m-spin,
.aud-svg .aud-part.muted .m-swing, .aud-svg .aud-part.muted .m-tilt, .aud-svg .aud-part.muted .m-spin {
  animation-play-state: paused !important; }

@keyframes audg-steam1 { 0% { transform: translateY(0) scale(.5); opacity: 0; } 20% { transform: translateY(-10px) scale(1); opacity: .7; } 100% { transform: translateY(-40px) scale(1.5); opacity: 0; } }
@keyframes audg-steam2 { 0% { transform: translateY(0) scale(.5); opacity: 0; } 30% { transform: translateY(-15px) scale(1); opacity: .7; } 100% { transform: translateY(-45px) scale(1.5); opacity: 0; } }
@keyframes audg-steam3 { 0% { transform: translateY(0) scale(.5); opacity: 0; } 10% { transform: translateY(-8px) scale(1); opacity: .7; } 100% { transform: translateY(-38px) scale(1.5); opacity: 0; } }
@keyframes audg-steam4 { 0% { transform: translateY(0) scale(.5); opacity: 0; } 25% { transform: translateY(-12px) scale(1); opacity: .7; } 100% { transform: translateY(-42px) scale(1.5); opacity: 0; } }
/* Steam: invisible while the machine is stalled (opacity lives entirely in
   the keyframes), puffing from the pipes only while the synth plays. */
.aud-svg .steam-bubble { fill: var(--text3); opacity:0; animation: audg-steam1 2s linear infinite paused; }
@media (prefers-reduced-motion: reduce) {
  .aud-svg .steam-bubble, .aud-machine.playing .aud-part.on .m-wave { animation: none !important; }
}

/* The strip: play, the two slots, then the tools. Reads like the home page's
   deck: a round amber play button leading a quiet row. */
.aud-bar { flex:none; display:flex; align-items:center; gap:8px; min-height:40px; }
.aud-play { flex:none; width:40px; height:40px; display:grid; place-items:center; padding:0;
  background: var(--accent); border:0; border-radius:50%; color: var(--display); cursor:pointer;
  transition: transform 120ms ease; }
.aud-play:hover { transform: scale(1.05); }
.aud-play:active { transform: scale(0.97); }
.aud-play svg { width:18px; height:18px; fill: currentColor; }
.aud-tools { flex:none; display:flex; align-items:center; gap:6px; margin-left:4px; }
.aud-btn { height:32px; display:inline-flex; align-items:center; padding:0 12px;
  border:1px solid var(--border2); border-radius:999px; background: transparent;
  color: var(--text2); font-family:inherit; font-size:.74rem; font-weight:600; cursor:pointer; white-space:nowrap; }
.aud-btn:hover { border-color: var(--accent); color: var(--text); }
.aud-play:focus-visible, .aud-btn:focus-visible, .aud-occ-x:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; }
.aud-info { width:16px; height:16px; fill:none; stroke: var(--text2); stroke-width:1.8; stroke-linecap:round; }
.aud-btn:hover .aud-info { stroke: var(--accent); }

/* The two slot wells: SYNTH and NOTE ENGINE. Dashed while empty (a place to
   drop), solid once loaded. */
.aud-well { flex:1; min-width:0; height:32px; display:flex; align-items:center; gap:8px; padding:0 12px;
  border:1px dashed var(--border2); border-radius:999px; background: var(--display); }
.aud-well-label { flex:none; color: var(--text3); font-size:.6rem; font-weight:700; letter-spacing:.12em; }
.aud-well-hint { color: var(--text3); font-size:.72rem; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.aud-well b { font-size:.76rem; color: var(--text); max-width:22ch; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.aud-well .cmty-author { font-size:.68rem; }
.aud-well.on { border-style:solid; border-color: color-mix(in srgb, var(--accent) 45%, var(--border2));
  background: color-mix(in srgb, var(--accent) 7%, var(--display)); }
.aud-well.drop-target { border-color: var(--accent); border-style:solid; }
@media (prefers-reduced-motion: reduce) { .aud-play { transition:none; } }

.aud-occ-stars { color: var(--accent); font-size:.62rem; }
.aud-occ-x { background:none; border:none; color: var(--text3); font-size:.8rem; cursor:pointer; padding:0 1px; line-height:1; }
.aud-occ-x:hover { color: var(--red); }

/* Minimised: the strip folds away into a floating machine button. */
.cmty-modal { position:relative; }
.cmty-auditioner.min { height:auto; padding:0; border-top:none; background:none; }
.aud-fab { position:absolute; right:16px; bottom:14px; z-index:6; width:42px; height:42px;
  border-radius:50%; border:1px solid var(--border2); background: var(--surface2);
  box-shadow: 0 6px 20px rgba(0,0,0,.45); cursor:pointer; padding:6px;
  display:flex; align-items:center; justify-content:center; }
.aud-fab:hover { border-color: var(--accent); }
/* The minimise button wears the same little machine, smaller still. */
.aud-btn.aud-btn-icon { justify-content:center; width:32px; padding:0; }
.aud-btn.aud-btn-icon .aud-mini-svg { width:20px; height:16px; }
.aud-btn.aud-btn-icon .icon-art { fill:none; stroke: var(--text2); }
.aud-btn.aud-btn-icon:hover .icon-art { stroke: var(--accent); }
.aud-btn.aud-btn-icon:hover .icon-fill { fill: var(--accent); }
.aud-mini-svg { width:100%; height:100%; overflow:visible; }
.aud-mini-svg .icon-art { fill: var(--surface); stroke: var(--text2); stroke-width:6;
  stroke-linecap:round; stroke-linejoin:round; }
.aud-mini-svg .icon-fill { fill: var(--text2); }
.aud-fab:hover .aud-mini-svg .icon-art { stroke: var(--accent); }
.aud-fab:hover .aud-mini-svg .icon-fill { fill: var(--accent); }
.aud-fab.playing .aud-mini-svg .icon-art { stroke: var(--accent); }
.aud-fab-count { position:absolute; top:-4px; right:-4px; min-width:16px; height:16px; padding:0 3px;
  border-radius:999px; background: var(--accent); color:#000; font-size:.58rem; font-weight:700;
  display:flex; align-items:center; justify-content:center; }
@keyframes aud-fab-pulse { 0%,100% { box-shadow: 0 8px 26px rgba(0,0,0,.45), 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  50% { box-shadow: 0 8px 26px rgba(0,0,0,.45), 0 0 0 9px transparent; } }
.aud-fab.playing { border-color: var(--accent); animation: aud-fab-pulse 1.6s ease-out infinite; }

/* Minimise/restore: the machine tucks itself into the corner button and
   unfolds back out of it. */
@keyframes aud-tuck { to { transform: translate(38%, 65%) scale(.05); opacity: 0; } }
.aud-machine.closing { animation: aud-tuck .24s ease-in forwards; transform-origin: 92% 100%; pointer-events:none; }
@keyframes aud-bar-fade { to { opacity: 0; } }
.aud-bar.closing { animation: aud-bar-fade .2s ease-in forwards; pointer-events:none; }
/* Expanding: the machine rolls in from the right (no scaling), while the
   shadow pool fades up from the bottom on its own — it never rides the
   machine's movement. */
@keyframes aud-roll-in { from { transform: translateX(16%); opacity: 0; }
  60% { opacity: 1; } to { transform: none; opacity: 1; } }
.aud-machine.unfold .aud-svg { animation: aud-roll-in .34s cubic-bezier(.2, .75, .3, 1.04); }
@keyframes aud-grad-rise { from { opacity: 0; transform: translateY(26px); }
  to { opacity: 1; transform: none; } }
.aud-machine.unfold::before { animation: aud-grad-rise .45s ease-out; }
@keyframes aud-fab-pop { from { transform: scale(.25); opacity: 0; }
  70% { transform: scale(1.14); opacity: 1; } to { transform: scale(1); opacity: 1; } }
.aud-fab.pop { animation: aud-fab-pop .26s ease-out; }
.aud-fab.pop.playing { animation: aud-fab-pop .26s ease-out, aud-fab-pulse 1.6s ease-out .3s infinite; }
@keyframes aud-fab-close { to { transform: scale(.25); opacity: 0; } }
.aud-fab.closing { animation: aud-fab-close .15s ease-in forwards !important; pointer-events:none; }
@media (prefers-reduced-motion: reduce) {
  .aud-fab.playing, .aud-fab.pop, .aud-fab.closing,
  .aud-machine.closing, .aud-machine.unfold .aud-svg,
  .aud-machine.unfold::before, .aud-bar.closing { animation:none !important; }
}
@media (max-width:900px) { .cmty-auditioner { --aud-h: 120px; } .aud-well-hint { display:none; } }

/* View-level share buttons (synth / engine / composition). */
.share-view-btn { padding:5px 12px; border:1px solid color-mix(in srgb, var(--accent) 45%, var(--border2));
  border-radius:999px; background:none; color: var(--accent2); font-family:inherit; font-size:.72rem;
  font-weight:600; cursor:pointer; white-space:nowrap; transition: background .15s ease, color .15s ease; }
.share-view-btn:hover { background: var(--accent); color:#000; }

/* ─── Profile pages ─── */
.profile-page { max-width:920px; margin:0 auto; padding:26px 22px 60px; }
.profile-back { margin-bottom:14px; }
.profile-header { display:flex; align-items:flex-start; gap:20px; padding:20px;
  background: var(--surface); border:1px solid var(--border2); border-radius:12px; margin-bottom:26px; }
.profile-avatar { flex:none; width:96px; height:96px; border-radius:50%; overflow:hidden;
  background: var(--surface2); border:1px solid var(--border2);
  display:flex; align-items:center; justify-content:center; }
.profile-avatar img { width:100%; height:100%; object-fit:cover; }
.profile-avatar span { font-size:2.2rem; font-weight:700; color: var(--text3); }
.profile-id { flex:1; min-width:0; }
.profile-id h1 { margin:0; font-size:1.5rem; }
.profile-handle { color: var(--text3); font-size:.86rem; }
.profile-bio { margin:9px 0 0; color: var(--text2); font-size:.9rem; line-height:1.5; max-width:52ch; }
.profile-stats { display:flex; gap:16px; margin-top:12px; color: var(--text3); font-size:.76rem; }
.profile-stats b { color: var(--text); }
.profile-actions { display:flex; flex-direction:column; gap:8px; align-items:stretch; }
/* Avatar picker inside the Edit profile form. */
.prof-edit-avatar { display:flex; align-items:center; gap:12px; }
.profile-avatar.sm { width:52px; height:52px; }
.profile-avatar.sm span { font-size:1.2rem; }
.prof-edit-avatar-btn { cursor:pointer; white-space:nowrap; }
.profile-page section { margin-bottom:30px; }
.profile-page section h2 { font-size:.82rem; text-transform:uppercase; letter-spacing:.1em;
  color: var(--text3); margin:0 0 12px; }

.comp-row { display:flex; align-items:center; gap:13px; padding:12px 14px; margin-bottom:8px;
  background: var(--surface); border:1px solid var(--border); border-radius:10px; }
.comp-play { flex:none; width:42px; height:42px; border-radius:50%; border:1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface)); color: var(--accent);
  font-size:1rem; cursor:pointer; }
.comp-play:hover { background: var(--accent); color:#000; }
.comp-main { flex:1; min-width:0; display:flex; flex-direction:column; gap:5px; }
.comp-head { display:flex; align-items:center; gap:12px; }
.comp-head b { font-size:.92rem; color: var(--text); }
.comp-progress { height:5px; border-radius:999px; background: var(--display); overflow:hidden; }
.comp-progress-fill { height:100%; width:0%; background:linear-gradient(90deg, var(--accent), var(--accent2)); }
.comp-time { flex:none; color: var(--text3); font-size:.72rem; font-family: var(--mono); }
.cmty-tag.edit { border-style:dashed; }

/* Space stage: percussion is view-only here — this toggles its emphasis. */
.sp-showperc { position:absolute; left:10px; bottom:8px; display:flex; align-items:center; gap:5px;
  color: var(--text3); font-size:.68rem; cursor:pointer; user-select:none; }
.sp-showperc:hover { color: var(--text2); }
.stage-pos { position:relative; }
/* Per-hit position pad in the percussion panel rows. */
.perc-lyr-ctls .layer-minipad { flex:none; cursor:grab; }
.perc-lyr-ctls .layer-minipad:active { cursor:grabbing; }
/* Composition rows span the whole grid inside the community overlay. */
.cmty-grid .comp-row { grid-column: 1 / -1; margin-bottom:0; }
.comp-head .cmty-author { margin-right:auto; }
/* Server-owned user badges ("Beta tester"): a quiet pb-chip after a handle.
   Chrome, not data — so monochrome, one step brighter than the handle. */
.user-badge { display:inline-block; margin-left:6px; font-size:.64rem; font-weight:500; line-height:1.45;
  color: var(--text2); border-color: var(--border2); background: var(--surface); vertical-align:1px; cursor:help; }
.cmty-author.big .user-badge { font-size:.62rem; font-weight:500; color: var(--text2); margin-left:0; }
/* Gap, not margin: on a narrow list the chip wraps under the handle flush-left. */
.cmty-toplist .cmty-author.big { display:inline-flex; flex-wrap:wrap; align-items:baseline; column-gap:6px; }
.profile-handle + .user-badge { font-size:.7rem; margin-left:8px; vertical-align:1px; }
.comp-head .comp-author { margin-right:auto; display:inline-flex; align-items:baseline; min-width:0; }
.comp-head .comp-author .cmty-author { margin-right:0; }
@media (max-width:640px) { .profile-header { flex-direction:column; } }

/* ═══ Unified top bar (audit 2026-07-14) ══════════════════════════════════
   One structural grammar for every view's top strip, left to right:
   brand · view nav · (space) · transport · (space) · utilities · primary
   action · account. The Explore bar (.tb-explore) and the Producer bar
   (.daw-transport.tb-producer) share the surface, the round transport
   language, a gold primary at the right edge, and the account pill LAST —
   the welcome copy sends people to the top-right for their profile.
   Appended at the end of the sheet so it wins the earlier era layers. */

/* One control height governs the whole bar so the row reads as a single
   even band (round audit found five different heights: 24/26/32/34/36). */
.app-topbar {
  --tb-h: 32px;
  min-width: 0;
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 8px;
  padding: 0 10px;
  background: linear-gradient(180deg, rgba(15,22,31,0.84), rgba(7,11,17,0.66));
  border: 1px solid rgba(58,75,92,0.72);
  border-radius: 7px;
  /* The account + File dropdowns hang below the strip — never clip them. */
  overflow: visible;
}
/* Nothing in the bar shrinks or wraps — the round audit's core bug was the
   Producer control wrapping to two lines and the seed value truncating to
   "10". Width pressure is handled by hiding labels (progressive disclosure
   below), never by squeezing a control. */
.app-topbar > * { flex: none; min-width: 0; }
.tb-explore { grid-column: 1 / -1; grid-row: 1; }
.tb-spacer { flex: 1 1 0 !important; min-width: 8px; }

/* Icons: one 24-grid SVG language, sized by context, inheriting text colour. */
.tb-ico { width: 16px; height: 16px; display: block; flex: none; pointer-events: none; }
.tb-ico.acct-caret { width: 13px; height: 13px; opacity: 0.66; margin-left: 1px; }

.tb-brand { display: inline-flex; align-items: center; gap: 7px; margin: 0; min-width: 0; flex: none; font-size: 0.72rem; white-space: nowrap; }
.tb-home { display: inline-flex; align-items: center; gap: 7px; color: inherit; text-decoration: none; border-radius: 6px; }
.tb-home:focus { outline: none; }
.tb-home:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tb-brand .app-name {
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  white-space: nowrap;
  background: linear-gradient(180deg, #f0f2f5, #b8c4d0);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.tb-home:hover { filter: brightness(1.25); }
/* FE-15: in the studio the wordmark is identity, not navigation — so it drops
   the pointer, the hover lift and the focus ring that promised a destination. */
.tb-home-static { cursor: default; }
.tb-home-static:hover { filter: none; }
.tb-brand .build-tag { color: rgba(154,160,171,0.62); font-weight: 500; white-space: nowrap; }

/* Text pills — Producer, Save, Share. A real pill: fixed height, icon + label,
   never underlined (it used to be an <a> inheriting link underline), never
   wrapped. */
.app-topbar .tb-pill {
  height: var(--tb-h);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px;
  border-radius: 7px;
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
}
.app-topbar .tb-pill .tb-label { white-space: nowrap; }

/* Workspace tabs, seed, transport, account all snap to the same height. */
.app-topbar .workspace-tabs { height: var(--tb-h); }
.app-topbar .transport-round { width: var(--tb-h); height: var(--tb-h); }
.app-topbar .transport-play { width: var(--tb-h); height: var(--tb-h); }
.app-topbar .transport-round .tb-ico { width: 15px; height: 15px; }
.app-topbar .transport-cluster { display: inline-flex; align-items: center; gap: 6px; flex: none; }
.app-topbar .seed-box {
  height: var(--tb-h);
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 0 5px 0 11px;
  border-radius: 7px;
}
.app-topbar .seed-box #seedBtn { flex: none; white-space: nowrap; padding: 3px 8px; }
.app-topbar .seed-box .tb-label { color: var(--text3); font-size: 0.6rem; letter-spacing: 0.09em; text-transform: uppercase; }
.app-topbar .account-bar .acct-pill { height: var(--tb-h); }

/* Theme accents that used to be scoped to the old .transport-card. */
.app-topbar .transport-round,
.app-topbar .btn,
.app-topbar .seed-box,
.app-topbar .top-rating-row { border-color: rgba(62, 79, 96, 0.84); }
.app-topbar .seed-box,
.app-topbar .top-rating-row { background: rgba(11, 16, 23, 0.68); }
.app-topbar .producer-pill {
  background: rgba(245,166,35,0.09);
  border: 1px solid rgba(245,166,35,0.62);
  color: #ffd79a;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}
.app-topbar .producer-pill:hover { background: rgba(245,166,35,0.16); color: #ffe6bf; }
.app-topbar .btn-primary { border-color: var(--accent); }

/* ── FE-5: four destinations, one group, one accent (owner 2026-08-27) ─────
   "This row of buttons looks ugly." The mechanics were already fixed by an
   earlier round — one 32px control height, nothing wraps — so what was left
   was compositional:
     · FOUR shape languages in one band: segmented rectangles (the tabs), a
       rounded pill (Producer), circles (transport), a bordered box (Seed).
     · Producer drawn as a call-to-action although it is simply the fourth
       place you can be. Handled in the markup — it is a .workspace-tab now.
     · FOUR accents on chrome: gold on the active tab, gold again on Producer,
       a green ring on Play, a blue dice. The system reserves colour for data
       and one accent for state, so the accent was doing three jobs at once and
       reading as none of them.
   Now: the accent means "the page you are on", and nothing else in the bar
   competes for it. */
.app-topbar .ws-sep {
  width: 1px;
  align-self: stretch;
  margin: 3px 4px;
  background: var(--hairline-soft);
  flex: none;
}
/* The Producer tab carries an icon the other three don't, so it gets the gap
   and the padding for it — same height, same radius, same weight. */
.app-topbar .ws-producer { gap: 5px; padding: 0 8px; }
.app-topbar .ws-producer .tb-ico { width: 13px; height: 13px; }
.app-topbar .ws-producer .tb-label {
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  text-transform: uppercase;
}
/* Transport goes monochrome. Play keeps a tint because "is it sounding" is
   real state; Restart and Randomise are plain actions and were only tinted
   because the colour was there. */
.app-topbar .transport-icon.rand-icon { color: var(--text2); }
.app-topbar .transport-icon.rand-icon:hover { color: var(--text); }
/* The seed now sits INSIDE the transport cluster (markup), so it drops the
   box it used to need to look deliberate out on its own. */
.app-topbar .transport-cluster {
  gap: 6px;
  padding: 0 3px 0 0;
}
.app-topbar .transport-cluster .seed-box {
  margin-left: 3px;
  padding-left: 8px;
  border: 0;
  border-left: 1px solid var(--hairline-soft);
  border-radius: 0;
  background: transparent;
}
/* Two solid gold buttons sat side by side at the right edge — Save and
   "Create profile / Log in" — so neither read as the primary. Save is the
   action this bar is FOR; the account CTA steps back to an outline. It still
   carries the accent, so it is still obviously the way in. */
.app-topbar .acct-pill.signin.primary {
  background: rgba(245,166,35,0.10);
  border: 1px solid rgba(245,166,35,0.55);
  color: #ffd79a;
}
.app-topbar .acct-pill.signin.primary:hover {
  background: rgba(245,166,35,0.18);
  color: #ffe6bf;
}
/* A quiet divider sets off the identity zone at the far right. */
.app-topbar .account-bar { flex: none; margin-left: 2px; padding-left: 10px; border-left: 1px solid rgba(58,75,92,0.55); }

/* Producer parity: the daw bar is denser (File, name, transport, tempo, edit,
   MIDI, Share, account), so its rounds run one notch smaller but share the
   icon language and the gold primary. */
.daw-transport.app-topbar { border-radius: 7px; }
/* High enough specificity to unify play with its siblings (base .transport-play
   is 36px): in both bars the play button is the SAME size as restart/stop/loop,
   emphasised only by its green ring — size stays consistent. */
.daw-transport .transport-cluster .transport-round,
.daw-transport .transport-cluster .transport-play { width: 32px !important; height: 32px !important; font-size: 0; }
.daw-transport .transport-round .tb-ico { width: 15px; height: 15px; }
.daw-transport .transport-cluster { gap: 5px; }
/* Keep the studio's divider before the identity zone (both bars match). */
.daw-transport .account-bar { margin-left: 2px; }
/* Round loop keeps its lit state (the old rule targeted the ghost button). */
#arrLoop.loop-on { color: #5fd4c8; border-color: #2c5b56; background: rgba(95,212,200,0.08); box-shadow: 0 0 0 2px rgba(95,212,200,0.10); }

/* Progressive disclosure — drop decoration before function as the row tightens.
   Order: build tag → wordmark + seed label → Producer/Save text (icon stays)
   + the optional tour button. The transport, seed VALUE and account never go. */
@media (max-width: 1280px) { .tb-brand .build-tag { display: none; } }
@media (max-width: 1120px) {
  .tb-explore .app-name { display: none; }
  .tb-explore .seed-box .tb-label { display: none; }
}
@media (max-width: 1000px) {
  .tb-explore .ws-producer .tb-label,
  .tb-explore .top-save-btn .tb-label { display: none; }
  .tb-explore .ws-producer,
  .tb-explore .top-save-btn { padding: 0 9px; }
  .tb-explore .studio-tour-btn .tb-label { display: none; }
  .tb-explore .studio-tour-btn { padding: 0 9px; }
}
/* The tour still leaves before the transport does — it just now sheds its
   label first, like Producer and Save, instead of vanishing whole at 1000px. */
@media (max-width: 900px) { .tb-explore .studio-tour-btn { display: none; } }

/* ── Report a problem dialog + early-access lock notice ─────────────────── */
.feedback-dialog .app-dialog-input { margin-bottom: 10px; }
.feedback-dialog .fb-text { resize: vertical; min-height: 96px; }
.feedback-dialog .fb-sub { margin: 0 0 12px; }
.feedback-dialog .fb-shot { display: block; font-size: .78rem; color: var(--text2); }
.feedback-dialog .fb-shot input { display: block; margin-top: 4px; font-size: .78rem; color: var(--text2); }
.feedback-dialog .fb-msg { margin: 10px 0 0; min-height: 1.1em; font-size: .8rem; color: var(--text2); }
.landing-lock { margin-top: 6px; font-size: .82rem; color: var(--accent, #f5a623); }
/* Landing hero uses the square mark at heading scale. */
.app-icon.lg { width: 44px; height: 44px; }
.landing-header h1 .app-icon { vertical-align: -6px; margin-right: 4px; }

/* ═══ Producer bar rebuild (audit round 2, 2026-07-14) ════════════════════
   The Producer top bar now follows the SAME grammar as the studio bar:
   brand-first identity, bare transport (no backing box → no nested outlines),
   one compact readout, ungrouped single-purpose tools, gold primary + account
   last. Functional zones are set off by whitespace + the two flex spacers,
   never by filled group boxes. Every control is one height (32px) and the bar
   matches the studio's 46px. */

.tb-producer { flex-wrap: nowrap; gap: 7px; min-height: 46px;
  /* The bar holds ~1590px of controls; below that width it SCROLLS rather
     than clipping MIDI and the account off the right edge (owner 2026-09-01).
     Its two hanging popovers are lifted to position:fixed at open time
     (liftTopbarPop), so the app-topbar "never clip the dropdowns" rule
     survives the scroller. overflow-y hidden, not auto: nothing in the bar
     is ever taller than it, and a surprise vertical scrollbar would be. */
  overflow-x: auto; overflow-y: hidden;
  /* No visible scrollbar (owner 2026-09-01) — a chrome scrollbar under the
     transport reads as a broken layout, not an affordance. Scrolling is by
     gesture: trackpad swipe natively, and a plain mouse wheel is translated
     to horizontal in wireProduce. */
  scrollbar-width: none; overscroll-behavior-x: contain;
}
.tb-producer::-webkit-scrollbar { display: none; width: 0; height: 0; }

/* Identity: dim breadcrumb root (Producer, links back to studio) → bright
   editable title (the arrangement) → borderless File menu trigger. */
.tb-producer .daw-brand { flex: none; gap: 6px; }
.tb-producer .daw-brand .app-name {
  font-size: 0.62rem; letter-spacing: 0.14em; text-transform: uppercase;
  font-weight: 700; color: var(--text3);
  -webkit-text-fill-color: currentColor; background: none;
}
.tb-producer .daw-brand:hover .app-name { color: var(--text2); }
.tb-producer .daw-crumb-sep { flex: none; color: var(--text3); opacity: 0.45; font-size: 0.95rem; }
.tb-producer .daw-arr-name {
  flex: none; max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 0.9rem; font-weight: 600; color: #f0f2f5;
  padding: 3px 5px; border-radius: 5px; cursor: text;
}
.tb-producer .daw-arr-name:hover { background: rgba(255,255,255,0.05); }

/* File reads as a menu, not a button: no border, visible caret, hover fill. */
.tb-producer .daw-file-wrap { flex: none; position: relative; }
.tb-producer .daw-file-button {
  display: inline-flex; align-items: center; gap: 4px; height: 30px; padding: 0 9px;
  background: none; border: 0; border-radius: 6px;
  color: var(--text2); font: inherit; font-size: 0.8rem; cursor: pointer;
}
.tb-producer .daw-file-button:hover,
.tb-producer .daw-file-button[aria-expanded="true"] { background: rgba(255,255,255,0.07); color: var(--text); }
.tb-producer .daw-file-caret { width: 14px; height: 14px; opacity: 0.85; margin: 0; }

/* Position + tempo: one compact readout; the two cells share label-row and
   value-row baselines (they were ~3px out and 45px tall). */
.tb-producer .daw-readout {
  flex: none; display: flex; align-items: stretch; height: 32px;
  border: 1px solid var(--border2); border-radius: 7px;
  background: rgba(7,11,16,0.55); overflow: hidden;
}
.tb-producer .daw-cell {
  display: flex; flex-direction: column; justify-content: center; gap: 2px;
  padding: 0 11px; min-width: 0; margin: 0; height: auto;
}
.tb-producer .daw-cell + .daw-cell { border-left: 1px solid var(--border); }
.tb-producer .daw-cell-label {
  font-size: 0.5rem; letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--text3); line-height: 1;
}
.tb-producer .daw-cell-val {
  display: inline-flex; align-items: baseline; gap: 3px;
  font-family: var(--mono); font-size: 0.82rem; color: var(--text);
  line-height: 1; font-variant-numeric: tabular-nums;
}
.tb-producer .daw-pos {
  min-height: 0; min-width: 0; height: auto; display: inline; align-items: initial; justify-content: initial;
  background: none; border: 0; border-radius: 0; padding: 0; margin: 0; cursor: pointer;
  color: var(--accent2); font: inherit; font-family: var(--mono); font-weight: 600; line-height: 1;
}
.tb-producer .daw-pos:hover { color: var(--accent); }
.tb-producer .daw-tempo-cell .daw-cell-val input {
  width: 3ch; background: none; border: 0; padding: 0; margin: 0;
  color: var(--text); font: inherit; font-family: var(--mono); text-align: right; line-height: 1;
  -moz-appearance: textfield;
}
.tb-producer .daw-tempo-cell .daw-cell-val input::-webkit-outer-spin-button,
.tb-producer .daw-tempo-cell .daw-cell-val input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.tb-producer .daw-tempo-cell .daw-cell-val i { font-style: normal; font-size: 0.55rem; color: var(--text3); text-transform: uppercase; letter-spacing: 0.06em; }

/* Single-purpose utility buttons (undo, zoom ±, MIDI): one height, one look.
   The Studio bar uses the same component for its undo/redo pair. */
.tb-producer .tb-util-btn, .tb-explore .tb-util-btn {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 11px; flex: none;
  background: rgba(11,16,23,0.5); border: 1px solid var(--border2); border-radius: 7px;
  color: var(--text2); font: inherit; font-size: 0.8rem; font-weight: 600; cursor: pointer;
}
.tb-producer .tb-util-btn:hover, .tb-explore .tb-util-btn:hover { border-color: var(--accent); color: var(--text); }
.tb-producer .tb-util-btn.tb-icon-only, .tb-explore .tb-util-btn.tb-icon-only { width: 32px; padding: 0; justify-content: center; }
.tb-producer .tb-util-btn .tb-ico, .tb-explore .tb-util-btn .tb-ico { width: 16px; height: 16px; }
.tb-producer .tb-util-btn:focus-visible, .tb-explore .tb-util-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Nothing to undo is a state, not an error: the button stays in place, dimmed,
   and its tooltip says so. */
.tb-producer .tb-util-btn:disabled, .tb-explore .tb-util-btn:disabled { color: var(--text3); border-color: var(--border); cursor: default; }
.tb-producer .tb-util-btn:disabled:hover, .tb-explore .tb-util-btn:disabled:hover { border-color: var(--border); color: var(--text3); }
.tb-producer .tb-undo-pair, .tb-explore .tb-undo-pair { display: inline-flex; gap: 4px; flex: none; }
/* The status line gives way first (basics review F6): it shrinks and ellipses
   before the bar pushes the account button past the edge. */
.tb-explore #exploreStatus { min-width: 0; flex: 0 1 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* a reserved width, so a message appearing does not shove the transport along */
@media (max-width: 900px) {
  .tb-explore .build-tag { display: none; }
  .account-bar .acct-long { display: none; }   /* "Log in" alone: the dialog offers both */
}
@media (max-width: 1400px) {
  .tb-explore .studio-tour-btn .tb-label { display: none; }
  .tb-explore .studio-tour-btn { padding: 0 9px; }
}
/* Musical typing: the lit state says "letter keys are notes right now",
   and the badge carries the two live values (base octave · velocity). */
.tb-producer .tb-util-btn.on { border-color: var(--accent); color: var(--text); background: rgba(139,124,246,0.16); }
.tb-producer .kbd-oct { font-size: 0.66rem; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
.tb-producer .kbd-hint { font-size: 0.7rem; color: var(--text3); white-space: nowrap; }
/* The play readout: which thread the keys reach, whether it is being kept, and
   what is sounding. A cell in the transport block rather than another chip on
   the right-hand rail, which is already over-full at 1280px. Bounded width with
   an ellipsis on the thread name, so a long name cannot push the transport
   about; the notes span reserves its width so a chord arriving does not
   either. */
.tb-producer .daw-cell-play { max-width: 190px; gap: 3px; }
.tb-producer .daw-cell-play .daw-cell-label { display: flex; align-items: center; gap: 5px; }
.tb-producer .daw-cell-play .daw-cell-val { font-size: 0.72rem; gap: 6px; min-width: 0; }
.tb-producer .midi-play-name {
  color: var(--text2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tb-producer .midi-voices {
  border: 0; background: none; padding: 0; cursor: pointer;
  font: inherit; font-size: 0.5rem; letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--text3); border-bottom: 1px dotted var(--border2); line-height: 1;
}
.tb-producer .midi-voices:hover { color: var(--accent); border-bottom-color: var(--accent); }
.tb-producer .midi-voices:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* MPE detected: a state badge, not a control — it says what the controller
   announced about itself, which is the one thing you cannot tell by playing. */
.tb-producer .midi-mpe {
  font-size: 0.5rem; letter-spacing: 0.11em; line-height: 1;
  padding: 1px 4px; border-radius: 3px;
  background: var(--rootc); color: var(--bg); font-weight: 700;
}
.tb-producer .midi-notes {
  flex: none; min-width: 4.5ch; font-variant-numeric: tabular-nums;
  font-size: 0.66rem; color: var(--text3); white-space: nowrap;
}
.tb-producer .midi-notes.sounding { color: var(--accent); }
/* A thread whose fader is down plays the keyboard down with it. Saying the
   number beats leaving someone to wonder whether the instrument is broken. */
.tb-producer .midi-play-name.quiet { color: var(--text3); }
.tb-producer .midi-quiet {
  flex: none; font-size: .58rem; font-weight: 700; letter-spacing: .04em;
  padding: 0 3px; border-radius: 3px;
  background: var(--recc-dim); color: var(--accent2);
}
/* Zoom's two buttons read as one control (shared context) without a group box. */
.tb-producer .daw-zoom { display: inline-flex; align-items: center; gap: 3px; flex: none; }

/* Empty status/saved spans must not reserve width (the dead gap). */
.tb-producer .daw-saved:empty, .tb-producer .toolbar-hint:empty { display: none; }
.tb-producer .daw-saved, .tb-producer .toolbar-hint { flex: none; }

/* Producer progressive disclosure — like the studio bar, drop decoration
   before function as the (denser) bar tightens. Order: breadcrumb wordmark →
   separator + MIDI label → Share label. Transport, readout, account never go. */
/* The redo button (basics audit #10) costs ~40 px; the account pill's
   "Create profile /" gives more than that back, so 1440 still fits whole.
   "Log in" alone opens the same dialog, which offers both. */
@media (max-width: 1599px) {
  .tb-producer .account-bar .acct-long { display: none; }
}
@media (max-width: 1180px) {
  .tb-producer .daw-brand .app-name { display: none; }
  .tb-producer .daw-arr-name { max-width: 190px; }
}
@media (max-width: 1040px) {
  .tb-producer .daw-crumb-sep { display: none; }
  .tb-producer #midiBtn .tb-label { display: none; }
  .tb-producer #midiBtn { width: 32px; padding: 0; justify-content: center; }
  .tb-producer .daw-arr-name { max-width: 150px; }
}
@media (max-width: 940px) {
  .tb-producer .top-save-btn .tb-label,
  .tb-producer #shareCompBtn .tb-label { display: none; }
  .tb-producer #shareCompBtn { padding: 0 10px; }
}

/* ═══ Early-access invite gate ("preview stopper") ═══════════════════════════
   A purpose-built overlay shown when a signed-out visitor tries to enter the
   studio in an invite-locked build. Warm, centred, and unmistakably on-brand. */
.gate-overlay {
  position: fixed; inset: 0; z-index: 5200;
  display: flex; align-items: center; justify-content: center; padding: 24px;
  background: radial-gradient(900px 500px at 50% -5%, rgba(245,166,35,0.10), rgba(6,8,12,0.72));
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  opacity: 0; transition: opacity 0.28s ease;
}
.gate-overlay.in { opacity: 1; }
.gate-card {
  position: relative; overflow: hidden;
  width: 100%; max-width: 430px; padding: 34px 32px 26px;
  text-align: center;
  background: linear-gradient(180deg, var(--surface2), var(--surface));
  border: 1px solid var(--border2); border-radius: 18px;
  box-shadow: 0 30px 80px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.04);
  transform: translateY(10px) scale(0.985); transition: transform 0.28s cubic-bezier(0.2,0.7,0.2,1);
}
.gate-overlay.in .gate-card { transform: none; }
/* A soft amber wash behind the icon. */
.gate-glow {
  position: absolute; top: -70px; left: 50%; width: 260px; height: 200px;
  transform: translateX(-50%); pointer-events: none;
  background: radial-gradient(closest-side, rgba(245,166,35,0.28), transparent 70%);
  filter: blur(6px);
}
.gate-badge {
  position: relative; display: inline-block; margin-bottom: 18px;
  padding: 4px 12px; border-radius: 999px;
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent2);
  background: rgba(245,166,35,0.10); border: 1px solid rgba(245,166,35,0.34);
}
.gate-icon {
  position: relative; display: block; width: 60px; height: 60px; margin: 0 auto 18px;
  border-radius: 15px; box-shadow: 0 8px 26px rgba(245,166,35,0.28);
}
.gate-card h2 {
  position: relative; margin: 0 0 10px;
  font-family: var(--brand-font); font-size: 1.5rem; font-weight: 800; letter-spacing: 0.01em;
  color: var(--text);
}
.gate-card > p {
  position: relative; margin: 0 auto; max-width: 34ch;
  color: var(--text2); font-size: 0.92rem; line-height: 1.6;
}
.gate-actions { position: relative; display: flex; flex-direction: column; gap: 9px; margin: 24px 0 4px; }
.gate-primary {
  padding: 12px 16px; border: 1px solid var(--accent); border-radius: 9px;
  background: linear-gradient(180deg, var(--accent2), var(--accent));
  color: #1a1204; font-family: inherit; font-size: 0.95rem; font-weight: 700; cursor: pointer;
  box-shadow: 0 6px 18px rgba(245,166,35,0.26); transition: filter 0.15s ease, transform 0.05s ease;
}
.gate-primary:hover { filter: brightness(1.06); }
.gate-primary:active { transform: translateY(1px); }
.gate-secondary {
  padding: 9px; border: none; background: none; border-radius: 8px;
  color: var(--text3); font-family: inherit; font-size: 0.86rem; font-weight: 500; cursor: pointer;
}
.gate-secondary:hover { color: var(--text2); }
.gate-foot { position: relative; margin: 16px 0 0; font-size: 0.74rem; color: var(--text3); line-height: 1.5; }
.gate-foot b { color: var(--text2); font-weight: 600; }

/* ── Palette: patches and their variants (producer hierarchy, 2026-07-28) ──
   A variant is the same patch with one module changed, so it renders as an
   indented child labelled by the diff — never "v2". Two levels, always. */
.palette-item.variant {
  margin-left: 14px; border-left: 2px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-top-left-radius: 0; border-bottom-left-radius: 0;
}
.palette-item.variant::before {
  content: "└"; position: absolute; left: -11px; top: 6px;
  color: var(--text3); font-size: 0.7rem; line-height: 1;
}
.palette-item.variant { position: relative; }
.palette-item.variant .pal-name { font-weight: 500; }
.pal-variant-diff { display: inline-flex; align-items: center; opacity: 0.9; }

/* How many takes play this row, and whether any of them have their own edits. */
.pal-take-count {
  flex: 0 0 auto; min-width: 15px; padding: 1px 4px; border-radius: 4px;
  background: var(--surface2); color: var(--text3); text-align: center;
  font-size: 0.55rem; font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* The name is the identity — it gets the room. The badge is a count. */
.pal-top > .pal-name { flex: 1 1 auto; min-width: 0; }
.daw-palette.min .pal-kind { display: none; }
.pal-diverged { color: var(--accent); font-style: normal; font-size: 0.8em; vertical-align: 1px; }

/* Staging strip: this take has edits that belong to no patch yet. Shown only
   while the take is selected — the persistent form is the ● above. */
.pal-stage-strip {
  margin: 2px 0 4px 14px; padding: 6px 7px; border-radius: 5px;
  border: 1px solid color-mix(in srgb, var(--accent) 34%, var(--border));
  background: color-mix(in srgb, var(--accent) 7%, var(--surface2));
  display: flex; flex-direction: column; gap: 5px;
}
.pal-stage-what { color: var(--text2); font-size: 0.6rem; line-height: 1.3; }
.pal-stage-what b { color: var(--text); font-weight: 600; }
.pal-stage-actions { display: flex; flex-wrap: wrap; gap: 4px; }
.pal-stage-actions .btn { padding: 2px 7px; font-size: 0.58rem; }
.daw-palette.min .pal-stage-what { display: none; }

/* ── Superseded modules (producer hierarchy, 2026-07-28) ──────────────────
   A superseded control stays VISIBLE and readable — it shows the value that
   is actually winning and names who won. Hiding it is what made the
   hierarchy unguessable in the first place. */
.module-owner-chip {
  flex: 0 0 auto; margin-left: 5px; padding: 0 4px; border-radius: 3px;
  border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border));
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: color-mix(in srgb, var(--accent) 80%, var(--text));
  font-size: 0.5rem; font-weight: 600; letter-spacing: 0.04em; white-space: nowrap;
  text-transform: uppercase; cursor: help;
}
.patch-pane.superseded .patch-degrees,
.patch-pane.superseded .patch-engine-knobs,
.patch-scale.superseded .patch-degrees { opacity: 0.5; }
.patch-pane.superseded .patch-pane-name { color: var(--text3); }
.superseded-note { color: color-mix(in srgb, var(--accent) 62%, var(--text3)); }

/* The inspector says what it is editing, truthfully. */
.patch-inspector-badges .patch-local-badge.diverged {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
}

/* Note-engine quick dials */
.patch-engine-knobs {
  display: flex; flex-wrap: wrap; gap: 2px; align-items: flex-start;
  padding: 2px 0 4px;
}
.patch-engine-knobs .knob-cell { width: 46px; }
.patch-surprise-dims { display: flex; gap: 3px; padding-bottom: 4px; }
.patch-surprise-dims i {
  padding: 0 3px; border-radius: 3px; background: var(--surface2);
  color: var(--text3); font-style: normal; font-size: 0.5rem; font-weight: 600;
}
.patch-own-head {
  display: flex; align-items: center; gap: 4px;
  color: var(--text3); font-size: 0.56rem; cursor: pointer;
}
.patch-own-head input { accent-color: var(--accent); }

/* Percussion group header doubles as its Library route and drop target. */
.patch-lyr-group { display: flex; align-items: center; gap: 5px; }
.patch-lyr-group .saem-route { flex: 0 0 auto; }
.patch-lyr-group .patch-lyr-edit {
  margin-left: auto; padding: 0 4px; border: 0; background: none;
  color: var(--text3); font-size: 0.62rem; cursor: pointer;
}
.patch-lyr-group .patch-lyr-edit:hover { color: var(--text); }

/* A drop that cannot work must not look like one that can. */
.drop-reject {
  outline: 1px dashed color-mix(in srgb, #e0524d 70%, var(--border));
  outline-offset: 2px; border-radius: 6px; cursor: not-allowed;
}

/* ── Thread head: only what the ARRANGEMENT owns (2026-07-28) ─────────────
   Two flags, because only two facts are true of a whole thread — a thread can
   carry takes from several patches, so anything take-level would change
   meaning as the playhead crossed regions. Those markers live on the region. */
/* Compact glyphs on the controls row. As their own row they made every head
   taller than its lane, which showed up as a gap under each track. */
.tl2-flag {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 15px; padding: 0; border: 1px solid var(--border);
  border-radius: 3px; background: none; color: var(--text3);
  font-size: 0.66rem; line-height: 1; cursor: pointer;
}
.tl2-flag:hover { border-color: var(--text3); color: var(--text2); }
.tl2-flag.on {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: color-mix(in srgb, var(--accent) 85%, var(--text));
}
/* Drawn flag icons: a room with a source in it, and the circle of fifths.
   Two unicode circles read as the same button at this size. */
.tl2-flag-svg { width: 13px; height: 13px; display: block; }
.tl2-flag-svg .ring { fill: none; stroke: currentColor; stroke-width: 1; opacity: 0.5; }
.tl2-flag-svg .head { fill: currentColor; opacity: 0.55; }
.tl2-flag-svg .src  { fill: currentColor; opacity: 0.9; }
.tl2-flag-svg .deg  { fill: currentColor; opacity: 0.4; }
.tl2-flag-svg .deg.on { fill: currentColor; opacity: 1; }
.tl2-flag.on .tl2-flag-svg .ring { opacity: 0.75; }
.tl2-takes {
  flex: 0 0 auto; padding: 0 3px; border-radius: 3px; background: var(--surface2);
  color: var(--text3); font-size: 0.52rem; font-variant-numeric: tabular-nums;
}

/* Per-take markers on the region — one patch per region, so unambiguous. */
.tl2-mark {
  position: absolute; top: 2px; font-size: 0.6rem; line-height: 1;
  color: var(--accent); text-shadow: 0 1px 2px rgba(0,0,0,.8); pointer-events: auto; cursor: help;
}
.tl2-mark-own { right: 14px; }
.tl2-mark-baked { right: 3px; color: color-mix(in srgb, var(--text) 70%, var(--accent)); }

.tl2-head-ctl .tl2-db { color: var(--text3); font-size: 0.52rem; font-variant-numeric: tabular-nums; }

/* A module the patch does not have must not look like one it does — the
   defaults would otherwise read as the patch's own settings. */
.patch-pane-absent {
  padding: 8px 7px; border: 1px dashed var(--border); border-radius: 5px;
  background: color-mix(in srgb, var(--surface2) 60%, transparent);
  color: var(--text3); font-size: 0.6rem; line-height: 1.35;
}

/* The Harmonic-guide editor opens beneath the change point it edits. It stays
   in normal flow so its row GROWS with the divisions — absolutely positioned,
   a 12-division guide wrapped to two rows and the second was clipped. */
.gs-editor { flex: 0 0 auto; align-self: flex-start; }
.gs-editor .gs-roll { flex-wrap: wrap; }
/* Delete the anchor under the playhead, in the space area's top-right. */
/* Sits in the cross-section's corner — the slice whose anchor it removes.
   It needs a positioned ancestor, which .tl2-head's `sticky` already is; the
   `relative` that used to be restated here just broke the pinning. */
.sp-anchor-del {
  position: absolute; top: 2px; right: 3px; z-index: 5;
  padding: 1px 5px; border: 1px solid var(--border); border-radius: 4px;
  background: color-mix(in srgb, var(--surface2) 88%, transparent);
  color: var(--text2); font-size: 0.72rem; line-height: 1.2; cursor: pointer;
}
.sp-anchor-del:hover { border-color: #e0524d; color: #e0524d; }
.sp-addall {
  padding: 0 5px; border: 1px solid var(--border); border-radius: 3px;
  background: none; color: var(--text3); font-size: 0.55rem; cursor: pointer;
}
.sp-addall:hover { border-color: var(--accent); color: var(--accent); }

/* ── Provisional vs committed takes (owner 2026-07-28) ────────────────────
   Both region bodies now show their real notes, so the shape alone no longer
   says which kind of take you are looking at. The distinction that matters is
   whether the notes can still change:

     generative — one roll of the dice. Reroll or edit the patch and these
                  notes change. Drawn soft: rounded caps, feathered ends, a
                  little glow. It reads as "about here".
     baked      — frozen, editable note data. Drawn crisp: square caps, full
                  strength, no bloom. It reads as "exactly here".

   Corner/edge softness carries the meaning; the region outline (dashed vs
   solid) and the ▦ marker say the same thing again for anyone who does not
   read the texture. */
.tl2-roll-generative .tl2-mini-note {
  height: 3px;
  border-radius: 2px;                       /* rounded — provisional */
  opacity: 0.82;
  filter: blur(0.35px);                     /* soft edges */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 22%, #000 78%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 22%, #000 78%, transparent 100%);
  box-shadow: 0 0 6px hsla(var(--track-h, 36), 85%, 60%, calc(var(--a) * 0.45));
}
.tl2-roll-baked .tl2-mini-note {
  height: 4px;
  border-radius: 0;                         /* square — committed */
  opacity: 1;
  filter: none;
  -webkit-mask-image: none;
  mask-image: none;
  box-shadow: none;
  outline: 0.5px solid hsla(var(--track-h, 36), 70%, 22%, 0.7);
}

/* Variation scope: an explicit either/or, not a heading (owner 2026-08-11).
   A labelled radio pair — dot + filled state — so it reads as "choose one",
   which is what the override relationship actually is. */
.env-scope-row { display: flex; align-items: center; gap: 7px; margin: 5px 0 7px; }
.env-scope-label {
  font-size: 0.55rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text3); font-weight: 600; flex: none;
}
.env-scope {
  display: flex; flex: 1 1 auto; min-width: 0;
  border: 1px solid var(--border); border-radius: 7px; overflow: hidden;
  background: rgba(10, 13, 17, 0.55);
}
.env-scope-btn {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: center; justify-content: center; gap: 5px;
  background: none; border: none; border-right: 1px solid var(--border);
  color: var(--text3); font: inherit; font-size: 0.62rem; font-weight: 600;
  padding: 5px 6px; cursor: pointer; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  transition: background 120ms ease, color 120ms ease;
}
.env-scope-btn:last-child { border-right: none; }
.env-scope-btn:hover { color: var(--text2); background: rgba(255, 255, 255, 0.03); }
/* the radio dot: hollow when unchosen, filled ring when chosen */
.env-scope-dot {
  width: 9px; height: 9px; flex: none; border-radius: 50%;
  border: 1.5px solid currentColor; background: none;
  box-shadow: inset 0 0 0 6px transparent;
  transition: box-shadow 120ms ease;
}
.env-scope-btn.active {
  background: rgba(245, 166, 35, 0.16);
  color: #ffd28a;
  box-shadow: inset 0 -2px 0 rgba(245, 166, 35, 0.85);
}
.env-scope-btn.active .env-scope-dot { box-shadow: inset 0 0 0 2px rgba(245, 166, 35, 0.95); }

/* ════════════════════════════════════════════════════════════════
   CIRCUIT MODULE — 2026-08-13
   The rail's module bracket (both modules), and the circuit pages'
   joined control+display surface.  docs/CIRCUIT_MODULE_DESIGN.md
   ════════════════════════════════════════════════════════════════ */

/* ── The module bracket ──────────────────────────────────────────
   Excitor/Resonator/Body are ONE swappable unit and Effects/Space are
   not, and until this existed the rail said nothing about that. The
   bracket is a frame with its label notched into the top edge; the
   cards inside keep their own borders, so the grouping reads without
   the three of them merging into one slab. */
.ch-module {
  position: relative;
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  padding: 13px 9px 9px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.012);
}
.ch-module-cards { display: flex; gap: 10px; align-items: stretch; flex: 1; min-width: 0; }
.ch-module-tag {
  position: absolute;
  top: -8px;
  left: 14px;
  display: flex;
  align-items: baseline;
  gap: 7px;
  padding: 0 8px;
  background: var(--bg, #0d1014);
  font-size: 0.58rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
}
.ch-module-name { color: var(--text2); font-weight: 600; }
.ch-module-hint { color: var(--text3); letter-spacing: 0.06em; text-transform: none; font-size: 0.58rem; }
@media (max-width: 1100px) { .ch-module-hint { display: none; } }

/* The instrument half is tinted by which module is loaded; the shared
   half stays neutral, because it does not change when they swap. */
.ch-module-acoustic { border-color: #3a2f1c; background: rgba(245, 166, 35, 0.022); }
.ch-module-circuit  { border-color: #1f3a4a; background: rgba(88, 200, 255, 0.026); }
.ch-module-acoustic .ch-module-name { color: #e0b478; }
.ch-module-circuit  .ch-module-name { color: #7fd0f0; }
.ch-module-shared { flex: 0 1 42%; border-style: dashed; border-color: #2a3140; }
.ch-sep-major { color: #5a6b85; font-size: 1.2rem; padding: 0 2px; }

/* The cards are the module's PAGES, so they get a tab's affordances: a
   lit top edge on the open one and a hover lift on the others. */
.ch-module .ch-card { transition: border-color 0.15s, box-shadow 0.15s, transform 0.12s; }
.ch-module .ch-card:hover:not(.active) { transform: translateY(-1px); }
.ch-module .ch-card.active::after {
  content: "";
  position: absolute;
  left: 11px; right: 11px; top: -1px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  opacity: 0.85;
}
.ch-module .ch-excitor.active::after   { color: #f5a623; }
.ch-module .ch-resonator.active::after { color: #58a6ff; }
.ch-module .ch-body.active::after      { color: #b48ede; }
.ch-module .ch-effects.active::after   { color: #e0669a; }
.ch-module .ch-space.active::after     { color: #58d6a9; }

/* ── The joined surface ──────────────────────────────────────────
   For circuit pages the inspector and the field become one panel: the
   display is a scope of the controls beside it, not a separate editor,
   so a splitter between them would be a seam with nothing on either
   side of it. */
.ch-circuit-wide { width: auto; flex: 1 1 auto; min-width: 0; padding: 0; overflow: hidden; }
/* FE-14 step 1 — which column flexes is inverted (owner 2026-08-28: "not
   practical use of space … it is not showing any more info than the little
   window in the top sequence"). The controls were CAPPED at 350px and given
   the scrollbar while the display took every remaining pixel to redraw the
   rail thumbnail at four times the size. Now the CONTROLS flex and the
   DISPLAY has a ceiling, and the reclaimed width buys back the macros the
   old cap had shrunk to a 46px knob. */
.circuit-surface {
  display: grid;
  /* The display's ceiling is a share OR 520px, whichever is smaller, and the
     controls take everything left. A plain `minmax(360px, 520px)` would still
     have let the display claim its 520 first and handed the remainder to the
     controls — the same inversion, one column narrower. */
  grid-template-columns: minmax(320px, 1fr) minmax(300px, min(520px, 46%));
  gap: 0;
  height: 100%;
  min-height: 0;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(20, 24, 31, 0.72), rgba(13, 16, 21, 0.9));
  overflow: hidden;
}
.circuit-controls {
  min-width: 0;
  overflow-y: auto;
  padding: 11px 13px 16px;
  border-right: 1px solid var(--border);
  /* Layout inside this column answers to the COLUMN's width, not the
     window's: the same window can give it 320px or 640px depending on what
     else is on screen, and a `@media` rule would guess. */
  container-type: inline-size;
  container-name: circuitcol;
}
.circuit-display {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 13px 10px;
  overflow-x: hidden;
  overflow-y: auto;
}
/* Stacked, the two halves stop competing for one short box and the SURFACE
   scrolls instead. The old rule capped the controls at a percentage and gave
   the display `1fr` of whatever was left, which at 860px wide left the
   display 20 pixels tall — a share of nothing is still nothing. */
@media (max-width: 980px) {
  .circuit-surface {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    overflow-y: auto;
  }
  .circuit-controls {
    border-right: none;
    border-bottom: 1px solid var(--border);
    max-height: none;
    overflow: visible;
  }
  .circuit-display { overflow: visible; min-height: 250px; }
}

.circuit-disp-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 0.72rem;
  color: var(--text2);
}
.circuit-disp-head.sub { font-size: 0.62rem; margin-top: 2px; }
.circuit-disp-head b {
  margin-left: auto;
  font-weight: 500;
  font-size: 0.62rem;
  color: var(--text3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* A lane title is a micro-label (§1.4): it names the strip under it, it is
   not a heading competing with the display's own. */
.circuit-lane-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-top: 1px;
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text3);
}
.circuit-lane-head b {
  margin-left: auto;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.58rem;
  letter-spacing: 0;
  text-transform: none;
  font-variant-numeric: tabular-nums;
  color: var(--text2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.circuit-canvas-wrap {
  flex: 1 1 auto;
  min-height: 90px;
  border-radius: 8px;
  background: var(--display);
  border: 1px solid var(--border);
  overflow: hidden;
}
/* The hero keeps a floor AND a ceiling. It absorbs spare height when the
   page has some and gives it up first when it does not — the lanes below
   carry information the hero does not repeat, so they are never the ones
   that get squeezed. */
.circuit-canvas-wrap.hero { flex: 1 1 auto; min-height: 66px; max-height: 240px; }
.circuit-canvas-wrap.short { flex: 0 0 30%; min-height: 62px; }
/* Lanes prefer their own height and give it up only after the hero has
   reached its floor — the stack fits a short panel without a scrollbar
   instead of turning the display into a scrolling document. */
.circuit-canvas-wrap.lane { flex: 0 1 36px; height: 36px; min-height: 26px; border-radius: var(--radius-sm); }
.circuit-canvas-wrap.lane.tall { flex: 0 1 54px; height: 54px; min-height: 34px; }
.circuit-canvas-wrap.spec { flex: 0 1 58px; height: 58px; min-height: 34px; }
.circuit-canvas-wrap canvas { width: 100%; height: 100%; display: block; }
.circuit-disp-foot { font-size: 0.58rem; color: var(--text3); line-height: 1.4; }

/* The Amp page's display is an EDITOR, not a picture: the curve is capped and
   the height it gives up goes to the band strip that shapes it.
   Both trailing blocks sit ON the bottom edge, so once the hero has taken its
   ceiling the leftover collects in ONE deliberate gap rather than trailing off
   under the last line of text. */
.circuit-band-editor {
  flex: 0 0 auto; margin-top: auto;
  border-top: 1px solid var(--border); padding-top: 5px;
}
.circuit-band-editor .body-band-strip { margin: 4px 0 2px; }
.circuit-tail {
  flex: 0 0 auto; margin-top: auto;
  display: flex; flex-direction: column; gap: 4px; min-height: 0;
}

/* ── The six macros ──────────────────────────────────────────────
   The hero of the oscillator page: bigger than an ordinary knob,
   three across, each one bipolar around a detented zero. */
.circuit-macros { border-top: 1px solid var(--border); padding-top: 7px; margin-top: 2px; }
.macro-knobs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px 2px;
  margin: 4px 0 2px;
}
.macro-knobs .knob-cell { gap: 0; width: auto; }
/* Sized so all six fit the column without scrolling at the panel's own
   height — they are the page's hero and a hero you have to scroll to is not
   one. They stay the largest controls on the page.
   FE-14: 46px was the price of the 350px cap. The column flexes now, so the
   hero is allowed to look like one again. */
.macro-knobs .knob-svg { width: 46px; height: 46px; }
/* Two rows of three cost ~95px of a column that is only ~490px tall, which
   put both disclosures below the fold. One rail of six, once the column is
   wide enough to hold it, is also the truer picture: they are six peers. */
@container circuitcol (min-width: 430px) {
  .macro-knobs { grid-template-columns: repeat(6, 1fr); }
  .macro-knobs .knob-svg { width: 54px; height: 54px; }
}
.macro-knobs .knob-label {
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text2);
}
.macro-knobs .knob-out {
  /* inline-block, not the inherited block: the cell is `width: auto` now that
     the column flexes, and a block readout stretched the value pill into a
     full-width bar. */
  display: inline-block;
  font-size: 0.62rem;
  color: var(--accent2);
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
  border-radius: 4px;
  padding: 0 5px;
  font-variant-numeric: tabular-nums;
}
.knob-cell.big .knob-svg { width: 46px; height: 46px; }

/* The circuit pages own their whole column, so their groups can breathe. */
.circuit-controls .seg-control { margin-bottom: 7px; }
.circuit-controls .ins-group { margin-bottom: 7px; }
.circuit-controls .ins-group-label { margin-bottom: 3px; }
.circuit-controls .knob-row { gap: 4px; }
.circuit-controls .ch-caption { margin-top: 3px; }
.circuit-controls details.ch-perf { margin-top: 5px; }
.circuit-controls .smart-combo { width: 100%; }
.circuit-controls .smart-combo-btn { width: 100%; justify-content: space-between; }

/* FE-14 step 2 — the reclaimed width, spent. Slider rows lay two across
   wherever the column can hold two, and fall back to one when it cannot;
   `auto-fit` means the breakpoint is the COLUMN's width, not the window's,
   so the narrow stacked layout below 980px still gets single rows. */
.circuit-controls .controls-grid {
  grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
  gap: 0.5rem 14px;
}
.circuit-controls .control-row {
  grid-template-columns: minmax(0, 100px) minmax(36px, 1fr) 50px;
  gap: 6px;
}
.circuit-controls .control-row .label {
  font-size: 0.68rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.circuit-controls .control-row output {
  font-size: 0.66rem;
  font-variant-numeric: tabular-nums;
  /* "2 voices" wrapping to a second line made its row taller than its
     neighbour in the same grid band. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Workspace bottom lane (owner 2026-08-14) ─────────────
   Macro, Sub-note and Scale Lab each reserved a 42–46px band at the foot of
   the plugin for two strips that are almost never there: the research opt-in
   line (experiments mode only) and the palette-edit banner (only while a
   Producer patch is out for edit). Empty, that band read as dead space above
   the credit watermark. The pages now run down to just above the credit, and
   the band comes back only when one of those strips is genuinely on screen. */
.explore-dashboard { --ws-bottom: 12px; }
.explore-dashboard:has(.research-note:not(:empty)),
.explore-dashboard:has(.palette-edit-banner) { --ws-bottom: 42px; }

/* ── Browser lists read as recessed trays (owner 2026-08-14) ──────────────
   The scrollable preset list is a shade LIGHTER than the panel around it and
   lit by an inset shadow, so it sits back in the surface rather than floating
   on it. The rows stop being separate chips on that surface: the dark colour
   becomes the hairline BETWEEN presets instead. Covers the Producer's Library
   (.browser-cards) and the same list on Sub-note and Macro (.m2-lib-list). */
.m2-lib-list,
.browser-cards {
  gap: 0;
  border-radius: 7px;
  background: rgba(28, 36, 47, 0.55);
  box-shadow:
    inset 0 2px 6px rgba(0, 0, 0, 0.5),
    inset 0 0 0 1px rgba(6, 9, 14, 0.7);
}
/* The list's own frame replaces the rule that used to divide it from the
   filter row above. */
.m2-lib-list { border-top: none; padding: 2px 2px 0; }
.browser-cards { padding: 2px 2px 0; }

/* Square rows, edge to edge: the tray's own overflow clips them to its
   rounded corners, so a per-row radius would only break the hairlines. */
.m2-lib-row,
.browser-row {
  background: transparent;
  border: none;
  border-bottom: 1px solid rgba(6, 9, 14, 0.72);
  border-radius: 0;
}
.m2-lib-row:last-child,
.browser-row:last-child { border-bottom: none; }

.m2-lib-row:hover,
.browser-row:hover {
  background: rgba(62, 76, 96, 0.62);
  border-color: transparent;
  border-bottom-color: rgba(6, 9, 14, 0.72);
}

/* ── Studio frame: one treatment on all three pages (owner 2026-08-14) ────
   1. The module bracket's label is NOTCHED 8px above its frame, over an
      opaque background. The rail sat only 4px below the header row, so that
      box painted over the bottom 3px of "editing Layer 1" and ate its
      descenders. The rail now clears the header by the label's own overhang.
   2. Sub-note's card started at 54px and the other two at 50px, so the line
      under the top bar read as one thickness on Macro and Scale Lab and
      another on Sub-note. All three now leave the same 4px gap.
   3. The horizontal inset (the dashboard's side border plus 4px of padding)
      is gone: the pages run edge to edge and get that width back. */
.ch-rail { margin-top: 9px; }

.macro2-workspace-mode .macro2-card,
.subnote-workspace-mode .subnote-full-card {
  top: 55px;
  left: 0;
  right: 0;
}

body.explore-mode .explore-dashboard {
  padding: 4px 0 0;
  border-left: 0;
  border-right: 0;
  border-radius: 0;
}
/* The top bar becomes a true full-width bar rather than a rounded box with a
   sliver of page showing past its corners. */
body.explore-mode .app-topbar.tb-explore {
  border-left: 0;
  border-right: 0;
  border-top: 0;
  border-radius: 0;
}

/* The stage card's caption lines share one scrim over the sparkline. The
   text used to sit straight on the spectrum with only a shadow behind it,
   which on the excitor's dense amber bars was unreadable. */
.subnote-workspace-mode .ch-card .ch-card-foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  padding: 12px 10px 5px;
  opacity: 0;
  background: linear-gradient(180deg, rgba(8, 11, 16, 0) 0%, rgba(8, 11, 16, 0.82) 42%, rgba(8, 11, 16, 0.93) 100%);
  transition: opacity 0.14s ease, transform 0.14s ease;
  transform: translateY(5px);
  pointer-events: none;
}
.subnote-workspace-mode .ch-card:hover .ch-card-foot,
.subnote-workspace-mode .ch-card.active .ch-card-foot {
  opacity: 1;
  transform: translateY(0);
}
/* The lines are now laid out by the scrim, so they drop the absolute
   positioning and the fade they each used to own. */
.subnote-workspace-mode .ch-card .ch-headline,
.subnote-workspace-mode .ch-card .ch-card-sum {
  position: static;
  left: auto;
  right: auto;
  bottom: auto;
  opacity: 1;
  transform: none;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.subnote-workspace-mode .ch-card.stage-off .ch-card-foot { opacity: 0.35; }

/* The automatic module tag takes the same two tints the rail bracket uses, so
   "which instrument is this built on" reads the same in the browser as it
   does on the page (owner 2026-08-14). */
.m2-tag-acoustic { color: #e0b478; border-color: rgba(245, 166, 35, 0.32); }
.m2-tag-circuit  { color: #7fd0f0; border-color: rgba(88, 200, 255, 0.32); }
/* The third module joins on the same terms, but through its token rather than
   a fourth raw hex: --smp is the tape magenta the sampletron rail, panel and
   keyroll already wear, so a row in the browser and the page it opens are
   provably the same colour (standard §1.2 — no raw hex in a new rule). The
   lift toward white matches what the two above do by hand, which is why they
   read as tags and not as headings. */
.m2-tag-sampletron {
  color: color-mix(in srgb, var(--smp) 62%, white);
  border-color: color-mix(in srgb, var(--smp) 34%, transparent);
}

/* ── The head column is ONE layer over the timeline (owner 2026-08-21) ─────
   "Just have a left hand area that is a layer above the embedded timeline."

   Its geometry — position in the layer, width, and the band it paints over
   the gutter — is declared HERE and nowhere else. The selector carries two
   classes on purpose: it outranks every variant (.tl2-track-head, .gs-head,
   .sp-left, .tl2-corner), so a variant can restyle how its head LOOKS but
   cannot fall out of the column.

   That is exactly how this broke twice. `.sp-left` kept private copies of the
   width and the position, and both had rotted: 190px against the column's
   200px put the global-space cylinder 10px off the lanes it is beat-aligned
   with, and `position: relative` instead of `sticky` dropped it out of the
   layer altogether — so expanding Global space and scrolling carried the
   cross-section off the left edge while every other head stayed pinned.
   Restating any of these four properties on a head is now a bug by
   construction. */
.tl2-row > .tl2-head {
  position: sticky;
  left: 0;
  z-index: 6;
  flex: none;
  width: var(--tl-head-w, 200px);
}
/* The gutter between a head and its lane is the panel's job now, not a
   per-head box-shadow, so the track head keeps only its own top highlight. */
.tl2-row > .tl2-track-head {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035);
}

/* ...and the heads sit on a PANEL ONE LEVEL UP from the scrolling track area
   (owner 2026-08-21). My first attempt at this painted the pane as the
   scroller's own background, which was wrong in a way worth recording: a
   background is BELOW content, so scrolled content still drew straight over
   it. The playhead is `position: absolute; z-index: 2` on the lane, and it
   went on running down through the gaps between the head cards exactly as
   before — a backdrop can never occlude, only an overlay can.

   So the panel is a real layer, ABOVE the lanes and BELOW the heads. It lives
   on the un-scrolled wrapper rather than inside the scroller, so it is pinned
   to the viewport for free: no sticky, no spacer, nothing to keep in register
   with a scroll offset. The stack, low to high:

     lanes, regions, playhead   z 2   (scrolls)
     head panel                 z 5   (pinned — hides all of the above)
     heads                      z 6   (pinned — sit on the panel)

   The playhead's drag handle stays at z 4 on purpose: it belongs to the
   ruler, so it should disappear under the panel when it scrolls off, not
   float over the track names. */
#timelineGrid,
.strips-panel { position: relative; }
#timelineGrid::before,
.strips-panel::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: calc(var(--tl-head-w, 200px) + 6px);
  background: var(--tl-head-pane, #1b2029);
  border-right: 1px solid var(--tl-head-pane-edge, rgba(66, 75, 91, 0.72));
  z-index: 5;
  pointer-events: none;
}
/* A row whose lane side is empty (the collapsed Harmonic guide, the Global
   space toggle row once its cylinder has moved to the expanded panel) still
   has to span the arrangement: a row only as wide as its head gives sticky
   nothing to hold, and that head alone came unstuck while the rest of the
   column stayed put. Invisible, non-interactive, pure width. */
.tl2-rowfill { flex: none; pointer-events: none; }

/* FE-16: the favourites chip's own LOAD. Preview is the click; committing is
   this, deliberately small and deliberately labelled — the chip used to load
   on click while calling itself a preview. */
.m2-chip-load {
  position: absolute;
  right: 6px;
  bottom: 6px;
  padding: 1px 6px;
  border: 1px solid var(--control-border);
  border-radius: 999px;
  background: var(--control-bg);
  color: var(--text3);
  font-size: 0.52rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  line-height: 1.5;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s, color 0.12s, border-color 0.12s;
}
.m2-preset { position: relative; }
.m2-preset:hover .m2-chip-load,
.m2-chip-load:focus-visible { opacity: 1; }
.m2-chip-load:hover { color: var(--accent2); border-color: rgba(245,166,35,0.55); }
.m2-chip-load:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ── FE-28 / FE-32: the favourites rack ────────────────────────────────────
   The quick-start rail IS the hearted set now, so it gained the three things a
   list you own needs: an order you can change, a way out, and a commit action
   that is findable without hovering. No new hues — reorder speaks in the
   timeline's amber drag language, removal in the one place --red is honest. */

/* Load is a primary action on the chip, not a hover secret (FE-28 step 5). It
   rests quiet and lifts on hover/focus, which keeps the chip's name and art
   readable without hiding the button that commits. */
.m2-chip-load { opacity: 0.62; }
.m2-preset:hover .m2-chip-load,
.m2-chip-load:hover,
.m2-chip-load:focus-visible { opacity: 1; }

.m2-fav-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.m2-fav-chip { cursor: grab; }
.m2-fav-chip.dragging { opacity: 0.4; cursor: grabbing; }

/* The insertion caret: where the chip you are dragging will land. A hairline,
   not a gap — the chips must not reflow under the pointer. */
.m2-fav-caret {
  position: absolute; top: 6px; bottom: 6px; width: 2px;
  background: var(--accent);
  box-shadow: 0 0 6px 0 rgba(245, 166, 35, 0.65);
  border-radius: 1px; pointer-events: none; z-index: 4;
}

/* Dragging a chip OUT of the rack and into the library un-favourites it. The
   list says so while a chip is in flight, and commits to red only under the
   pointer — an always-red list would read as an error state. */
.m2-lib-list.fav-remove-armed {
  outline: 1px dashed rgba(239, 68, 68, 0.35);
  outline-offset: -2px;
}
.m2-lib-list.fav-remove-over {
  outline: 1px solid var(--red);
  background: rgba(239, 68, 68, 0.07);
}
.m2-lib-list.fav-remove-armed::before {
  content: "Drop here to un-favourite";
  position: sticky; top: 0; z-index: 3;
  display: block; padding: 3px 8px;
  font-size: 0.55rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--red); background: rgba(239, 68, 68, 0.10);
}

/* FE-32 step 6: double-clicking a chip finds its row. The highlight has to be
   findable in a long list and then get out of the way, so it is a short-lived
   accent wash rather than a permanent selection mark. */
.m2-lib-row.revealed,
.m2-lib-row.sel {
  background: rgba(245, 166, 35, 0.13);
  box-shadow: inset 2px 0 0 0 var(--accent);
}

/* The library in its scale mode (Scale & Root, owner 2026-10-16): the same component in a column beside the wheel.
   The head wraps (the search takes a line of its own when the column is narrow), a row is two lines (name and its
   actions, then its tags), the Factory list is grouped by region, and each row adds Hear beside Load. */
.m2-lib.scale-mode { gap: 8px; }
.m2-lib.scale-mode .m2-lib-head { flex-wrap: wrap; row-gap: 8px; }
.m2-lib.scale-mode .m2-lib-search { flex: 1 1 150px; max-width: none; }
.m2-lib.scale-mode .m2-lib-row { flex-wrap: wrap; row-gap: 3px; padding: 6px 8px; content-visibility: auto; contain-intrinsic-size: auto 54px; }
.m2-lib.scale-mode .m2-lib-name { flex: 1 1 0; min-width: 0; }
.m2-lib.scale-mode .m2-lib-tags { order: 9; flex: 1 1 100%; min-width: 0; }
.m2-lib.scale-mode .m2-tag { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.m2-lib.scale-mode .m2-tag:first-child { flex: 0 1 auto; }
.m2-lib.scale-mode .m2-tag + .m2-tag { flex: none; }
.m2-lib.scale-mode .m2-lib-stars { width: auto; }
.m2-lib.scale-mode button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.m2-lib-group {
  display: flex; align-items: baseline; gap: 8px; padding: 12px 8px 4px;
  font-size: 0.56rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text3);
}
.m2-lib-group span { letter-spacing: 0; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.m2-lib .m2-hear[aria-pressed="true"] { border-color: var(--accent); color: var(--text); }
.m2-lib.scale-mode .m2-load-main { min-width: 4.8em; }
.m2-lib-row.in-use .m2-load-main { background: none; border-color: transparent; color: var(--text2); cursor: default; }
.m2-lib-row.in-use .m2-lib-name { color: var(--text); }
.sf-signin { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 10px; }
/* The reveal's scroll stop, from ONE measured value per edge (app.js
   `syncBrowserRevealInsets`) rather than a literal repeated per row: how far
   the favourites rack — or anything painted over the list's bottom edge —
   actually covers the scroller. Zero when nothing does, including when the
   strip is hidden, so no gap opens above a row for no reason. */
.m2-lib-list { --m2-reveal-top: 0px; --m2-reveal-bottom: 0px; }
.m2-lib-row {
  scroll-margin-top: calc(var(--m2-reveal-top) + 6px);
  scroll-margin-bottom: calc(var(--m2-reveal-bottom) + 6px);
}

/* FE-32: the split Load. One control, a default and a variant — the shape says
   the two actions are not peers, which is the truth: browsing reaches for the
   macro, replacing the whole patch is the rarer move. Neither half is accented
   (FE-5: the accent marks state; a load is a destination), and the caret has
   its own hit area rather than appearing on hover, so nothing primary is
   hidden behind a pointer the way FE-16's chip LOAD was. */
.m2-load-split { display: inline-flex; align-items: stretch; flex: none; }
.m2-load-split.has-more .m2-load-main {
  border-top-right-radius: 0; border-bottom-right-radius: 0; border-right-color: transparent;
}
.m2-load-caret {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; padding: 0 5px;
  background: var(--surface2); color: var(--text2);
  border: 1px solid var(--border2); border-left: 1px solid var(--border);
  border-top-right-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm);
  font: inherit; font-size: 0.62rem; line-height: 1; cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.m2-load-caret:hover { background: var(--border); color: var(--text); }
.m2-load-caret:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; z-index: 1; }
.m2-load-caret[aria-expanded="true"] { background: var(--border); color: var(--text); }
/* Coarse pointers get the 44px target the Touch ergonomics block promises. */
@media (pointer: coarse) {
  .m2-load-caret { min-width: 44px; }
}

/* FE-32 step 5: the display pane accepts a favourite and loads its macro. The
   target has to be discoverable, so it names what the drop will do. */
.m2-display { position: relative; }
.m2-display.drop-load { outline: 1px solid var(--accent); outline-offset: -2px; }
.m2-display.drop-load::after {
  content: attr(data-drop-hint);
  position: absolute; left: 50%; top: 10px; transform: translateX(-50%);
  z-index: 6; pointer-events: none;
  padding: 4px 10px; border-radius: 999px;
  background: var(--accent); color: var(--bg);
  font-size: 0.58rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
}

@media (prefers-reduced-motion: reduce) {
  .m2-chip-load, .m2-lib-loadfull { transition: none; }
}

/* ── FE-29 → FE-37: a preview must not wear a layer's identity ─────────────
   While a browser sound auditions, the patch's own layers are muted. They
   LOOK muted, because that is the truth — dimmed rows and (in app.js) meters
   held at silence, so nothing implies layer 1 is sounding.

   FE-37 (owner 2026-08-29): the rows must stay VISIBLE while they say that.
   FE-29's amber explanation box was a flex ITEM in `.layer-area`, which is a
   flex ROW, so it stood up as a tall column and pushed the layer rows out of
   the pane — content replaced by an explanation of itself. It is gone. The
   dimming is the whole in-pane signal, the reason rides in the strip header
   as one quiet line, and the loud indicator stays on the chip. */
.layer-area.previewing .layer-rows { opacity: 0.42; filter: saturate(0.5); }
.layer-area.previewing .layer-rows,
.layer-area.previewing .layer-rows * { pointer-events: auto; }
/* Peripheral by construction: it sits on the header line the LAYERS label
   already owns, so it cannot take a pixel of row space however long it gets. */
.layer-strip-note.auditioning { color: var(--accent2); letter-spacing: 0.02em; }
@media (prefers-reduced-motion: reduce) {
  .layer-area.previewing .layer-rows { transition: none; }
}

/* ══ SAMPLETRON MODULE (FE-40) ══════════════════════════════════════════════
   Design plan: docs/FRONTEND_FIXES_PLAN.md § FE-40.

   The module's PAGE SHELL is not here. `.circuit-surface` / `.circuit-controls`
   / `.circuit-display` / `.circuit-canvas-wrap` are the module-page surface
   language rather than a circuit-only style, and the sampletron pages wear
   them unchanged — a third module that grew its own two-column grid would be
   the divergence FE-1 exists to remove. What IS here is the four things that
   genuinely did not exist before: the module's identity hue on the rail, the
   waveform's readout column, the value strip under a display, and the keyroll.

   Colour does exactly one job on these pages: --smp says "this is the
   sampletron", and on the keyroll it says "this key is real". Everything else
   is chrome. */

/* The display is the bigger half here. The circuit split (controls flex,
   display capped at 520px) was tuned for a page with six macros and two
   disclosures; the sampler's filter page has one seg row and three knobs, so
   that split left a third of the surface empty on the left while the response
   curve was capped on the right. The controls still have a real floor. */
.ch-sampletron .circuit-surface {
  grid-template-columns: minmax(300px, 0.8fr) minmax(340px, min(640px, 55%));
}
.ch-sampletron .circuit-canvas-wrap.hero { max-height: none; }

.ch-module-sampletron { border-color: #3f2447; background: rgba(204, 99, 198, 0.024); }
.ch-module-sampletron .ch-module-name { color: color-mix(in srgb, var(--smp) 72%, white); }
/* Same specificity as the per-stage rules above and later in the file, so the
   module hue wins on all three of its cards. The sampletron's pages are one
   instrument seen three ways, not three stages of a chain. */
.ch-module-sampletron .ch-card.active::after { color: var(--smp); }
.ch-sampletron-word { color: var(--smp) !important; }

/* The seg buttons, the boxed knob readouts and the ins-group rules inside the
   sampletron surface take the module hue instead of the global amber. Scoped
   to the surface, so nothing else in the app changes colour. */
.ch-sampletron .seg-btn.active {
  color: color-mix(in srgb, var(--smp) 80%, white);
  background: color-mix(in srgb, var(--smp) 12%, transparent);
}
.ch-sampletron .seg-btn:focus-visible,
.ch-sampletron .st-toggle:focus-visible,
.ch-sampletron .st-browse:focus-visible,
.ch-sampletron .st-zone-row:focus-visible {
  outline: 2px solid var(--smp);
  outline-offset: 1px;
  border-radius: var(--radius-sm);
}
.ch-sampletron .ins-group.st-knobs .knob-row { gap: 4px 8px; }
/* Boxed value pills, the same device the circuit macros use, in this module's
   hue. The readout is the star (§1.2 cue 4), so it gets the frame. */
.st-knobs .knob-out {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.6rem;
  color: color-mix(in srgb, var(--smp) 62%, white);
  background: color-mix(in srgb, var(--smp) 9%, transparent);
  border: 1px solid color-mix(in srgb, var(--smp) 28%, transparent);
  border-radius: 4px;
  padding: 0 5px;
  margin-top: 1px;
  font-variant-numeric: tabular-nums;
}
.st-knobs .knob-svg { width: 50px; height: 50px; }
.st-knobs .knob-cell { width: auto; flex: 1 1 0; min-width: 74px; }

/* Instrument row: the picker takes the width, BROWSE keeps its own. */
.st-instr-row { display: flex; gap: 6px; align-items: stretch; }
.st-instr-row > :first-child { flex: 1 1 auto; min-width: 0; }
.st-browse {
  flex: 0 0 auto;
  height: var(--control-h);
  padding: 0 10px;
  background: var(--control-bg);
  border: 1px solid var(--control-border);
  border-radius: var(--radius-sm);
  color: var(--text2);
  font: inherit;
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  cursor: pointer;
}
.st-browse:hover { color: var(--text); border-color: color-mix(in srgb, var(--smp) 55%, transparent); }

/* Two-state switches. `aria-pressed` carries the state; the fill repeats it,
   because a control whose only state cue is a screen-reader attribute is not
   a control anyone can use. */
.st-toggles { display: flex; gap: 6px; margin: 5px 0 2px; }
.st-toggle {
  height: var(--control-h);
  padding: 0 11px;
  background: var(--control-bg);
  border: 1px solid var(--control-border);
  border-radius: var(--radius-sm);
  color: var(--text3);
  font: inherit;
  font-size: 0.64rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.st-toggle:hover { color: var(--text2); }
.st-toggle.on {
  color: color-mix(in srgb, var(--smp) 78%, white);
  border-color: color-mix(in srgb, var(--smp) 52%, transparent);
  background: color-mix(in srgb, var(--smp) 12%, transparent);
}

/* The zone table. Read-only in v1 and it has to look it: rows, not fields. */
.st-zones { max-height: 190px; overflow-y: auto; content-visibility: auto; }
.st-zone-row {
  display: grid;
  grid-template-columns: 5.4rem 3.2rem 2rem 1fr;
  gap: 4px;
  padding: 2px 4px;
  font-family: var(--mono);
  font-size: 0.6rem;
  font-variant-numeric: tabular-nums;
  color: var(--text2);
  border-radius: 3px;
  cursor: pointer;
}
.st-zone-row:hover { background: color-mix(in srgb, var(--smp) 10%, transparent); color: var(--text); }
.st-zone-head {
  color: var(--text3);
  font-family: var(--font);
  font-size: 0.55rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: default;
  position: sticky;
  top: 0;
  background: var(--panel);
}
.st-zone-head:hover { background: var(--panel); color: var(--text3); }
.st-zone-file { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text3); }

/* ── The waveform and its readouts ──────────────────────────────────────── */

/* The waveform is the page's hero and takes the display column's full width.
   Its handle captions are drawn ON the canvas at the handles' own positions —
   a DOM caption row can only space itself evenly and would point at nothing. */
.st-wave { flex: 1 1 auto; max-height: none; min-height: 120px; }
.st-wave canvas { cursor: default; }

/* The value strip under a display. Two to four cells, equal width, the number
   large and the name small — the value is the star. */
.st-cells {
  display: flex;
  /* WRAPS, since this pass took the strip from five cells to seven. At a
     315 px display column seven equal cells are 45 px and "3.400 s" is 48,
     so START and END printed into each other — the strip has to break to a
     second row rather than overlap. The 4.4rem basis is the widest reading
     any cell carries. */
  flex-wrap: wrap;
  gap: 1px;
  background: var(--hairline-soft);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--radius-sm);
  overflow: hidden;
  margin-top: 2px;
}
.st-cells > div {
  flex: 1 1 4.4rem;
  min-width: 4.4rem;
  background: var(--well);
  padding: 3px 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}
.st-cells span {
  font-size: 0.5rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text3);
}
.st-cells output {
  font-family: var(--mono);
  font-size: 0.76rem;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  white-space: nowrap;
}

.st-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  font-size: 0.55rem;
  letter-spacing: 0.04em;
  color: var(--text3);
  padding-top: 1px;
}
.st-legend span { display: inline-flex; align-items: center; gap: 4px; }
.st-legend-hint { margin-left: auto; font-style: italic; }
.st-swatch { display: inline-block; width: 14px; height: 2px; background: var(--smp); border-radius: 1px; }
.st-swatch.dash {
  width: 18px;
  background: repeating-linear-gradient(90deg,
    var(--smp) 0 4px, transparent 4px 7px);
  opacity: 0.75;
}
.st-swatch.key { width: 9px; height: 11px; border-radius: 1px; }
.st-swatch.key.auth { background: var(--smp); }
.st-swatch.key.rep { background: color-mix(in srgb, var(--smp) 34%, transparent); }
.st-swatch.key.root { background: var(--accent2); }
.st-keyroll-empty {
  font-size: 0.6rem;
  color: var(--text3);
  padding: 12px 0;
  text-align: center;
  border: 1px dashed var(--hairline-soft);
  border-radius: var(--radius-sm);
}

/* ── The 2026-08-30 control pass ────────────────────────────────────────────
   Thirteen parameters that shipped real and unreachable. Nothing here is a new
   surface language: the disclosure is `.ch-perf`, the rows are `.control-row`,
   the switch borrows `.st-toggle`'s shape. What genuinely did not exist is a
   DISCLOSURE THAT READS ITS OWN VALUE while closed, an INHERITED row, and the
   link switch itself. */

/* A summary that carries live state. The value sits on the right in the same
   mono tabular treatment `.circuit-lane-head b` uses, so a closed drawer says
   what is inside it and the page can afford to keep it closed.
   FLOATED, not flexed: `display: flex` on a <summary> drops its `list-item`
   box and takes the disclosure triangle with it, and every other drawer in
   this app has one. A float leaves the marker exactly where it was. */
/* …and the float is CLEARED inside the summary. A <summary> is a plain block
   container, so a float in it goes on intruding into whatever follows — and
   what follows here is a `display: grid` row, which establishes its own
   formatting context and therefore SHRINKS TO AVOID THE FLOAT. At 900 px that
   pulled the LFO's Shape row from 256 px to 105 px and collapsed its label
   track to six pixels: the row read as a bare dropdown arrow with no name.
   One empty cleared block ends it, and costs nothing where there is no
   float. */
.ch-perf summary::after { content: ""; display: block; clear: both; }
.ch-perf summary .st-drawer-val {
  float: right;
  max-width: 60%;
  margin-left: 10px;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.58rem;
  letter-spacing: 0;
  text-transform: none;
  font-variant-numeric: tabular-nums;
  color: var(--text2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ch-sampletron .ch-perf > summary:focus-visible {
  outline: 2px solid var(--smp);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* The link switch. Full width, because it is the master control of the four
   rows beneath it and a chip floated beside them would read as a fifth. */
.st-link {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  min-height: 30px;
  margin: 4px 0 6px;
  padding: 4px 10px;
  background: var(--control-bg);
  border: 1px solid var(--control-border);
  border-radius: var(--radius-sm);
  color: var(--text3);
  font: inherit;
  font-size: 0.64rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: left;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.st-link:hover { color: var(--text2); border-color: var(--border2); }
.st-link:focus-visible { outline: 2px solid var(--smp); outline-offset: 1px; }
.st-link.on {
  color: color-mix(in srgb, var(--smp) 78%, white);
  border-color: color-mix(in srgb, var(--smp) 52%, transparent);
  background: color-mix(in srgb, var(--smp) 12%, transparent);
}
.st-link-icon { font-size: 0.8rem; line-height: 1; opacity: 0.9; }

/* The four rows live in a <fieldset> so the linked state can be a NATIVE
   disabled state (app.js says why an attribute on the inputs could not be).
   A fieldset carries a browser margin, padding and border by default and none
   of them belong in a control grid. */
.st-env-grid { border: 0; margin: 0; padding: 0; min-width: 0; }

/* An inherited row: the value is real and live, it just is not this stage's.
   The greying is the read-only zone table's, and the tag says whose it is —
   a row that was only greyed would read as broken rather than as borrowed. */
.st-env-row.inherited .label { color: var(--text3); }
.st-env-row.inherited output { color: var(--text3); }
.st-env-row.inherited input[type="range"] { opacity: 0.5; cursor: not-allowed; }
.st-inherit {
  font-family: var(--mono);
  font-style: normal;
  font-size: 0.5rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-left: 5px;
  padding: 0 4px;
  border-radius: 3px;
  color: color-mix(in srgb, var(--smp) 62%, white);
  border: 1px solid color-mix(in srgb, var(--smp) 28%, transparent);
}

/* A select already shows its own value in full, so the readout beside it is
   the same word twice — and in a 50 px column the second copy is the one that
   gets truncated ("Sample & h ▾" beside "Sampl…"). The row keeps the shared
   `selectControlRow` markup, and therefore the shared wiring, and gives the
   width back to the control. */
.ch-sampletron .control-row.select-row { grid-template-columns: minmax(0, 100px) minmax(36px, 1fr); }
.ch-sampletron .control-row.select-row output { display: none; }

/* The two value-strip cells this pass added state to. A clamped fade and a
   snapped edge are both "the module did something you did not ask for", and
   both say so in FORM as well as in number (standard §1.5). */
.st-cells > div.clamped output { color: var(--accent2); }
.st-cells > div.snapped output { color: color-mix(in srgb, var(--smp) 70%, white); }
.st-cells > div.snapped span,
.st-cells > div.clamped span { color: color-mix(in srgb, var(--smp) 50%, var(--text3)); }

/* The LFO's swing on the filter response, for the legend. */
.st-swatch.band {
  height: 8px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--smp) 30%, transparent);
}

/* Four knobs in signal order need 326 px and the controls column is 274 at
   1180, so the row wrapped 3 + 1 and left ENV AMOUNT alone under three
   siblings — the worst of the three possible wraps. Below the existing 1180
   breakpoint each cell takes 40 % of the row instead, which makes it 2 + 2:
   Drive · Cutoff over Resonance · Env amount, still in signal order and still
   reading left to right, top to bottom. */
@media (max-width: 1180px) {
  .ch-sampletron .st-knobs .knob-row-4 .knob-cell { flex: 1 1 40%; }
}

/* Coarse pointers: the switch and the four rows are the newest touch targets
   in the app and they meet the floor rather than inheriting a desktop height.
   The waveform's own caps ask for the same widening in `panel.js`, which is
   the only place a canvas can. */
@media (pointer: coarse) {
  .st-link { min-height: 44px; }
  .st-env-row input[type="range"] { height: 44px; }
}

/* ── The keyroll ────────────────────────────────────────────────────────────
   DOM keys, not canvas: 61 buttons is nothing to render and it is the only
   shape that can carry a role, a name and arrow keys per key (standard §1.7).
   White keys are a flex row; black keys sit on the white-key boundaries at
   `--i` units of `--kw`, which is what keeps the two rows in step at any
   width without a single measured pixel. */
.kr { display: flex; flex-direction: column; gap: 2px; --kw: calc(100% / var(--kr-n)); }
.kr-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text3);
}
.kr-read {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0;
  text-transform: none;
  font-variant-numeric: tabular-nums;
  color: var(--text2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kr-board {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--display);
  padding: 3px;
  overflow: hidden;
}
/* The zone ribbon is the only thing that can show where one recording stops
   and the next begins — every key of a 19-zone instrument is the same lit
   colour, so the keys alone cannot say it. */
.kr-ribbon { position: relative; height: 5px; margin-bottom: 2px; }
.kr-zone {
  position: absolute;
  top: 0;
  height: 5px;
  left: calc(var(--a) * var(--kw));
  width: calc((var(--b) - var(--a)) * var(--kw));
  background: color-mix(in srgb, var(--smp) 34%, transparent);
  border-left: 1px solid color-mix(in srgb, var(--smp) 70%, transparent);
  border-radius: 1px;
}
.kr-keys { position: relative; display: flex; height: 54px; touch-action: none; }
.kr-k {
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
  position: relative;
}
.kr-w {
  flex: 1 1 0;
  min-width: 0;
  background: #2a2f38;
  border-right: 1px solid #14171c;
  border-radius: 0 0 2px 2px;
}
.kr-w:last-of-type { border-right: none; }
.kr-b {
  position: absolute;
  top: 0;
  z-index: 2;
  height: 62%;
  width: calc(var(--kw) * 0.62);
  left: calc(var(--i) * var(--kw) - var(--kw) * 0.31);
  background: #0d1014;
  border: 1px solid #05070a;
  border-radius: 0 0 2px 2px;
}
/* THE COLOUR RULE. Mapped but repitched is the hue held back; recorded here is
   the hue at full strength. Nothing else on this strip is coloured. */
.kr-w.is-mapped { background: color-mix(in srgb, var(--smp) 30%, #2a2f38); }
.kr-w.is-mapped.is-auth { background: color-mix(in srgb, var(--smp) 74%, #2a2f38); }
.kr-b.is-mapped { background: color-mix(in srgb, var(--smp) 26%, #0d1014); }
.kr-b.is-mapped.is-auth { background: color-mix(in srgb, var(--smp) 70%, #0d1014); }
.kr-k.is-root::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 3px;
  transform: translateX(-50%);
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--accent2);
}
.kr-k:hover { filter: brightness(1.35); }
.kr-k.is-on { background: var(--smp); box-shadow: 0 0 8px color-mix(in srgb, var(--smp) 60%, transparent); }
.kr-k:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 3; }
/* The octave scale, its own row under the board. Positioned in the same
   `--i × --kw` units as the keys, so it stays under its C at any width. */
.kr-scale { position: relative; height: 11px; margin-top: 2px; }
.kr-oct {
  position: absolute;
  top: 0;
  left: calc(var(--i) * var(--kw));
  width: calc(var(--kw) * 2);
  margin-left: calc(var(--kw) * -0.5);
  text-align: center;
  font-family: var(--mono);
  font-size: 0.48rem;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text3);
  pointer-events: none;
}

/* Coarse pointers: the keys are the one target here that has to be hit
   accurately, so the board grows rather than the keys getting wider. */
@media (pointer: coarse) {
  .kr-keys { height: 72px; }
  .st-toggle, .st-browse { min-height: 44px; }
  .ch-sampletron .seg-btn { padding: 10px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .st-toggle { transition: none; }
  .kr-k.is-on { box-shadow: none; }
}

/* The narrow case. The surface already stacks at 980px (`.circuit-surface`),
   which gives the display its own full width — so the waveform's readout
   column moves under the waveform rather than squeezing it, and the keyroll
   keeps its height. */
@media (max-width: 760px) {
  .st-cells { flex-wrap: wrap; }
  .st-cells > div { flex: 1 1 28%; }
  .st-cells output { font-size: 0.66rem; }
  .kr-keys { height: 46px; }
}

/* ── Imported audio ────────────────────────────────────────────
   docs/AUDIO_IMPORT_AND_EDITING_DESIGN.md §4.2. Two surfaces: the audio take
   on the timeline, and the clip editor in the bottom panel. Tokens only — the
   waveform canvas reads --aud-wave-* off the computed style so a token change
   reaches the pixels it draws. */

.tl2-region.audio {
  background: linear-gradient(180deg, var(--aud-dim), transparent 70%), var(--surface);
  border-color: color-mix(in srgb, var(--aud) 55%, var(--border2));
}
.tl2-region.audio.selected { border-color: var(--aud); box-shadow: 0 0 0 1px var(--aud) inset; }
.tl2-audio-clips { position: absolute; inset: 14px 2px 4px; pointer-events: none; }
.tl2-audio-clip {
  position: absolute; top: 0; bottom: 0;
  background: color-mix(in srgb, var(--aud) 38%, transparent);
  border-left: 1px solid color-mix(in srgb, var(--aud) 75%, transparent);
  border-radius: 2px;
}
.tl2-audio-clip.muted { opacity: 0.35; }
.tl2-mark-audio { color: var(--aud-tip); }

.aud-editor { display: flex; flex-direction: column; height: 100%; min-height: 0; gap: 6px; }
.aud-toolbar {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 4px 8px; border-bottom: 1px solid var(--hairline-soft);
}
.aud-toolbar-sep { width: 1px; height: 16px; background: var(--hairline-soft); }
.aud-import { position: relative; cursor: pointer; }
.aud-check {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 0.72rem; color: var(--text2); cursor: pointer;
}
.aud-warn { font-size: 0.72rem; color: var(--meter-warm); margin-left: auto; }

.aud-main { display: flex; gap: 8px; flex: 1 1 auto; min-height: 0; padding: 0 8px 8px; }
.aud-lane-wrap { flex: 1 1 auto; min-width: 0; display: flex; }
.aud-lane {
  position: relative; flex: 1 1 auto; min-height: 96px;
  background: var(--well); border: 1px solid var(--hairline-soft); border-radius: 5px;
  overflow: hidden;
}
.aud-lane-ruler { position: absolute; inset: 0 0 auto 0; height: 13px; pointer-events: none; }
.aud-tick {
  position: absolute; top: 0; font-size: 0.6rem; color: var(--text3);
  font-variant-numeric: tabular-nums; border-left: 1px solid var(--hairline-soft);
  padding-left: 2px; height: 100%;
}
.aud-tick.bar { border-left-color: var(--border2); color: var(--text2); }

.aud-clip {
  position: absolute; top: 15px; bottom: 4px;
  background: color-mix(in srgb, var(--aud) 22%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--aud) 60%, var(--border2));
  border-radius: 4px; overflow: hidden; cursor: grab;
}
.aud-clip.selected { border-color: var(--aud-tip); box-shadow: 0 0 0 1px var(--aud-tip) inset; }
.aud-clip.muted { opacity: 0.4; }
.aud-clip.offline { border-style: dashed; border-color: var(--meter-warm); }
.aud-clip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.aud-wave {
  position: absolute; inset: 0; width: 100%; height: 100%;
  --aud-wave-fill: color-mix(in srgb, var(--aud-tip) 45%, transparent);
  --aud-wave-rms:  color-mix(in srgb, var(--aud-tip) 90%, transparent);
  --aud-wave-dim:  var(--text3);
}
.aud-clip-label {
  position: absolute; left: 4px; top: 2px; right: 4px;
  font-size: 0.66rem; color: var(--text); text-shadow: 0 1px 2px rgba(0,0,0,0.75);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none;
}
.aud-fade { position: absolute; top: 0; bottom: 0; pointer-events: none; }
.aud-fade-in  { left: 0;  background: linear-gradient(90deg, var(--display), transparent); }
.aud-fade-out { right: 0; background: linear-gradient(270deg, var(--display), transparent); }
.aud-handle { position: absolute; top: 0; bottom: 0; width: 5px; cursor: ew-resize; }
.aud-handle-l { left: 0; }
.aud-handle-r { right: 0; }
.aud-handle:hover { background: color-mix(in srgb, var(--aud-tip) 45%, transparent); }
.aud-fade-grip {
  position: absolute; top: 0; width: 9px; height: 9px; cursor: crosshair;
  background: color-mix(in srgb, var(--aud-tip) 70%, transparent); border-radius: 2px;
}
.aud-fade-grip-in { left: 0; }
.aud-fade-grip-out { right: 0; }

.aud-empty {
  flex: 1 1 auto; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 6px; text-align: center;
  border: 1px dashed var(--hairline); border-radius: 6px; color: var(--text2);
  background: var(--well); padding: 18px;
}
.aud-empty-art { color: color-mix(in srgb, var(--aud) 70%, transparent); }
.aud-empty-title { margin: 0; font-size: 0.82rem; color: var(--text); }
.aud-empty-sub { margin: 0; font-size: 0.72rem; color: var(--text3); max-width: 44ch; }
.aud-drop-over { border-color: var(--aud); background: var(--aud-dim); }

.aud-inspector {
  flex: 0 0 244px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px;
  padding: 6px 8px; background: var(--panel);
  border: 1px solid var(--hairline-soft); border-radius: 5px;
}
.aud-inspector-empty { color: var(--text3); font-size: 0.74rem; margin: 0; }
.aud-insp-head { display: flex; flex-direction: column; gap: 2px; }
.aud-insp-name {
  font-size: 0.78rem; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.aud-insp-meta { font-size: 0.66rem; color: var(--text3); font-variant-numeric: tabular-nums; }
.aud-insp-group {
  display: flex; flex-direction: column; gap: 4px;
  padding-top: 6px; border-top: 1px solid var(--hairline-soft);
}
.aud-group-title {
  margin: 0 0 2px; font-size: 0.64rem; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--text3);
}
.aud-note-inline { text-transform: none; letter-spacing: 0; color: var(--text3); }
.aud-note { margin: 2px 0 0; font-size: 0.66rem; color: var(--text3); line-height: 1.35; }
.aud-row { display: grid; grid-template-columns: 64px 1fr; align-items: center; gap: 6px; }
.aud-row-label { font-size: 0.7rem; color: var(--text2); }
.aud-num { display: grid; grid-template-columns: 1fr 58px; align-items: center; gap: 5px; }
.aud-out {
  font-size: 0.68rem; color: var(--text); text-align: right;
  font-variant-numeric: tabular-nums;
}
.aud-select {
  height: var(--control-h); background: var(--control-bg); color: var(--text);
  border: 1px solid var(--control-border); border-radius: 4px; font-size: 0.7rem;
}
.aud-seg { display: flex; gap: 2px; }
.aud-seg-btn {
  flex: 1 1 0; height: var(--control-h); font-size: 0.68rem; cursor: pointer;
  background: var(--control-bg); color: var(--text2);
  border: 1px solid var(--control-border); border-radius: 4px;
}
.aud-seg-btn.on {
  background: color-mix(in srgb, var(--aud) 28%, var(--control-bg));
  border-color: var(--aud); color: var(--text);
}
.aud-seg-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.aud-toggles { display: flex; gap: 10px; flex-wrap: wrap; }
.aud-proc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.aud-proc {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  font-size: 0.7rem; color: var(--text2);
  background: var(--control-bg); border-radius: 3px; padding: 2px 4px;
}
.aud-proc .num { font-variant-numeric: tabular-nums; color: var(--text3); }
.aud-proc-x {
  background: none; border: 0; color: var(--text3); cursor: pointer;
  font-size: 0.72rem; line-height: 1; padding: 2px;
}
.aud-proc-x:hover { color: var(--red); }
.aud-proc-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

@media (prefers-reduced-motion: reduce) {
  .aud-clip, .aud-seg-btn, .aud-handle { transition: none; }
}

/* ═══ WP H6 — the Harmony macro panel ═══════════════════════════════════
   docs/PROBABILISTIC_HARMONY_DESIGN.md §13.2; design plan HG-C2 in
   docs/FRONTEND_FIXES_PLAN.md. The panel is built from the macro anatomy's
   own parts, so most of it needs no CSS at all: `.macro-controls`,
   `.macro-subsection`, `.control-row` and `.surprise-disabled` already carry
   the inspector's grid, rhythm and recession. What follows is only the four
   rows that hold something other than a slider, plus the preview well.
   One hue throughout: --chordc, the Chord guide's token (§13.1). */

/* The rail buttons animate four properties and had no reduced-motion cover;
   new work touching them owes it (standard §1.7). Scoped to the rail so it
   states exactly what it is switching off. */
@media (prefers-reduced-motion: reduce) {
  .m2-rail-btn, .m2-rail-icon { transition: none; }
}

.harmony-posture { margin: 0 0 2px; }

/* The picker takes the slider column AND the readout column: a progression's
   name is the value, so there is nothing to put in a third column. */
.m2-inspector .macro-controls .harmony-pick-row {
  grid-template-columns: minmax(112px, 1fr) minmax(0, 1.5fr);
}
.harmony-pick-row .smart-combo { min-width: 0; }
.harmony-pick-row .smart-combo-btn { width: 100%; }

/* label · seed · dice. The dice sits in the readout column at readout width. */
.m2-inspector .macro-controls .harmony-seed-row {
  grid-template-columns: minmax(112px, 1fr) minmax(0, 0.84fr) 52px;
}
.harmony-seed-chip {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.66rem; color: var(--accent);
  background: rgba(6,10,15,0.72);
  border: 1px solid rgba(49,69,86,0.72); border-radius: 3px;
  padding: 2px 6px; text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.m2-inspector .harmony-reroll { margin: 0; justify-self: end; }

/* ── The panel's frame: HF-7 at the top, HF-8 at the foot ───────────────
   docs/HARMONY_UI_FEEDBACK_PLAN.md §3, §4.7. The two elements that are about
   the panel as a whole rather than about one subsection's dials — what is
   sounding, and what the last take came out as. Tokens only; the one piece of
   data in either is the band stack, which is --chordc like every other
   sonority in the panel, and everything else is monochrome chrome. */

/* THE HEIGHT IS FIXED, and that is the whole layout requirement. This caption
   changes at every phrase boundary while a take runs, so a line that grew and
   shrank with its sentence would jog the entire panel under the reader's
   pointer 20 times a minute. Two lines of room, always, whether the reading is
   "a core dyad, bare" or a core of four tones with three clauses of roles. */
.harmony-inforce-line {
  display: grid;
  grid-template-columns: 15px minmax(0, 1fr) auto;
  align-items: center;
  gap: 6px;
  min-height: 26px;
  margin: 4px 0 2px;
}
.harmony-inforce-glyph { --hb-h: 15px; display: block; width: 15px; height: 15px; }
.harmony-inforce-text {
  font-size: 0.66rem; line-height: 1.2; color: var(--text2);
  height: 2.4em;                      /* exactly the two lines below */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* §33.4's two words, and the only place either appears as a label. Micro-label
   treatment so the sentence beside it stays the thing being read. */
.harmony-inforce-lead {
  font-style: normal; font-size: 0.56rem;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text3);
}
.harmony-inforce-tally {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.58rem; color: var(--text3);
  white-space: nowrap;
}
.harmony-inforce-line.is-empty .harmony-inforce-text {
  font-style: italic; color: var(--text3);
}

/* HF-8. A rule above it because it is a different kind of statement from the
   controls it follows — everything else in this panel is a setting, and this is
   a measurement of something that already happened. */
.harmony-metrics-line {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.58rem; color: var(--text3);
  min-height: 1.3em;
  margin-top: 6px; padding-top: 6px;
  border-top: 1px solid var(--border);
}

/* ── The coupling section's feedback displays (HF-1, HF-2) ──────────────
   docs/HARMONY_UI_FEEDBACK_PLAN.md §3, §4.7. Both ride `.mini-canvas` for the
   box and the hairline; all these rules add is the well ground (`--display`,
   the same visualiser ground every other display in the app draws on) and, for
   the pull profile, the taller `.register-mini-canvas` height the plan sizes it
   at. No new tokens, no second hue — the data is `--chordc` throughout and the
   root marker is `--rootc`, both painted by the canvas. */
.harmony-display { margin: 2px 0 6px; }
.harmony-display-label {
  font-size: 0.58rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text3);
}
.harmony-panel .mini-canvas.harmony-pull-canvas,
.harmony-panel .mini-canvas.harmony-prox-canvas {
  background: var(--display);
  margin-top: 3px;
}
.harmony-panel .mini-canvas.harmony-pull-canvas { height: 40px; }

/* The preview well. `--display` is the visualiser ground the whole app draws
   data on; the canvas paints its own background, so the rule only has to give
   it a box and the house hairline. */
.harmony-preview { margin-top: 6px; }
.harmony-preview-canvas {
  width: 100%; height: 76px;
  background: var(--display);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}

/* ── The tonic section's displays (HF-4, HF-9, HF-5) ────────────────────
   docs/HARMONY_UI_FEEDBACK_PLAN.md §3, §4.7. Tokens only; the data is
   --chordc throughout and the one violet line is --rootc, both painted by the
   canvas, so none of these rules names a colour the canvas also names. */

/* Two timescales, ONE box. The plan well reads across phrases and the pull
   timeline reads within one, and they share a right-hand end — the arrival —
   so they share an edge too: the well loses its bottom corners, the strip
   loses its top border, and the pair reads as one instrument rather than as
   two displays that happen to be adjacent. */
.harmony-plan-stack { margin: 2px 0 6px; }
.harmony-plan-stack .harmony-preview { margin-top: 3px; }
.harmony-plan-stack .harmony-preview-canvas {
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
  border-bottom-color: color-mix(in srgb, var(--border) 55%, transparent);
}
.harmony-phrase-canvas {
  display: block; width: 100%; height: 40px;
  background: var(--display);
  border: 1px solid var(--border); border-top: 0;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}

/* HF-5: the spread and the meter are one answer to one pair of dials, so they
   are one row. The strip takes the label column's width and the meter the
   slider + readout columns, which lines it up with the two sliders above it.

   BOTH TRACKS HAVE A ZERO MINIMUM AND BOTH CHILDREN OVERRIDE `min-width: auto`,
   and neither is cosmetic. The strip's track floor used to be 90 px, which is a
   floor the row cannot honour: this inspector drags down to a 221 px panel and
   the two tracks plus the meter's own min-content width run past it, at which
   point the strip stops fitting its cell and its empty-state caption lands on
   the arrival meter's label. A grid whose minimums cannot be met does not
   shrink, it overflows — so the minimums go, and the strip narrows gracefully
   instead (its bars already degrade below 3 px, and `harmonyEmptyWell` fits its
   own copy to whatever width is left). */
.harmony-coupling-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
  align-items: center;
  gap: 6px;
  margin: 2px 0 6px;
  min-width: 0;
}
.harmony-coupling-row > * { min-width: 0; }
.harmony-panel .mini-canvas.harmony-coupling-canvas {
  background: var(--display);
  margin-top: 0;
  /* A canvas is a replaced element, so its `width` ATTRIBUTE is an intrinsic
     size and `min-width: auto` would let it refuse to go under it. */
  min-width: 0; max-width: 100%;
}

/* The arrival meter. The `.meter-pair` idiom — a track, a fill and a mono
   readout beside a micro-label — laid horizontally and in tokens: the output
   card's own rule paints a raw three-stop gradient, which the standard's
   no-raw-hex rule does not let new work copy, and a green/amber VU ramp would
   say "level" about a quantity that is not one. */
.harmony-meter {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 6px;
}
.harmony-meter-label {
  font-size: 0.58rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text3);
}
.harmony-meter-track {
  height: 6px; border-radius: 3px;
  background: var(--display);
  border: 1px solid var(--border);
  overflow: hidden;
}
.harmony-meter-fill {
  display: block; height: 100%; width: 0;
  background: var(--chordc);
  opacity: 0.85;
  transition: width 140ms ease;
}
.harmony-meter-out {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.62rem; color: var(--text2);
  min-width: 2.4em; text-align: right;
}

@media (prefers-reduced-motion: reduce) {
  .harmony-meter-fill { transition: none; }
}

/* ── The vocabulary section's two ladders (HF-3, HF-6) ──────────────────
   docs/HARMONY_UI_FEEDBACK_PLAN.md §3, §4.7. Tokens only, one hue: the bands
   and the bars are --chordc and everything else is the monochrome chrome the
   rest of the inspector is built from. Both ladders share every rule below —
   they are the same row, at two sizes, saying two things about the same
   vocabulary — and differ only in the band height and the "stays" form. */

.harmony-vocab, .harmony-wn { margin: 2px 0 8px; }
.harmony-vocab-list { margin-top: 4px; display: grid; gap: 3px; }

/* stack · bar · reading. The label column is FIXED rather than auto so every
   bar in the ladder starts and ends at the same two x positions: the whole
   point of the display is comparing lengths, and an auto column would have
   given each row a different scale depending on how long its own label is. */
.harmony-vocab-row {
  --hb-h: 22px;
  display: grid;
  grid-template-columns: 15px minmax(0, 1fr) 52px;
  align-items: center;
  gap: 6px;
}
.harmony-wn-row { --hb-h: 14px; }

/* The Chord guide's band geometry (styles.css:6714), in a class of its own:
   `.chord-stack` is absolutely positioned inside a timeline span and carries
   that lane's own insets, so reusing it here would have dragged the producer's
   layout into the inspector. A dark WELL with bands in it, never a rose block
   — colour belongs to the data, and the data is the tones. */
.harmony-band-stack {
  position: relative;
  display: block;
  width: 15px; height: var(--hb-h);
  border-radius: 2px;
  overflow: hidden;
  background: var(--well);
}
/* §36's base/extension split, carried by FORM and never by a second hue. TWO
   forms, not one, and the reason is a measurement: twelve divisions in a 22px
   stack is 1.8px a band, and at 1.8px the alpha step the plan specifies (0.95
   against 0.55) is most of the way to invisible once the edges are antialiased
   — checked at 3× in the browser, not in the DOM. The horizontal extent of a
   pitch-class stack carries nothing at all, so it is free to carry this: a
   colour tone is a SHORT faint tick, a core tone a FULL bright band. The alpha
   still does its work at the sizes where alpha can be seen. 0.55 and not the
   0.42 the pinned/drawn spans use, for the reason Phase B recorded: below
   about 0.5 a band this thin stops reading as present at all. */
.harmony-band {
  position: absolute; left: 6px; right: 0;
  min-height: 1.5px;
  background: var(--chordc);
  opacity: 0.55;
}
.harmony-band.is-core { left: 0; opacity: 0.95; min-height: 2px; }

/* The score, as a fraction of a full row. The track is the whole scale, so a
   short bar reads as "not much of it" rather than as a small number. */
.harmony-vocab-bar {
  display: block; height: 7px;
  border-radius: 3px;
  background: var(--display);
  border: 1px solid var(--border);
  overflow: hidden;
}
.harmony-vocab-bar > i {
  display: block; height: 100%;
  background: var(--chordc);
  opacity: 0.85;
}

/* Relative degrees and a shape, never a note name (owner law, §0). */
.harmony-vocab-label {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 0.6rem; color: var(--text2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* STANDING STILL IS NOT A MOVE, said in form. An outline where every other row
   is filled — the same grammar the pinned/drawn spans and HF-5's spread already
   teach. The bar is the mark that carries it, because at 7px an outline is
   legible and at the 1.2px of one band it would not be; the stack goes faint
   instead, which is the same statement at a size where it can be read.

   Below about 3px an outline IS a filled bar — Phase B measured that in the
   pairing spread — and a "stays" mass of 1% is 3px of a 330px track. So the
   outline degrades the way Phase B's does: a faint body under a bright cap at
   the leading edge, which stays unmistakably not-filled at any width, and
   reads as a true outline once the bar is wide enough to have an inside. */
.harmony-wn-row.is-stay .harmony-vocab-bar > i {
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--chordc) 20%, transparent) 0 calc(100% - 2px),
      var(--chordc) calc(100% - 2px) 100%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--chordc) 60%, transparent);
  opacity: 0.9;
}
.harmony-band-stack.is-stay .harmony-band { opacity: 0.3; }
.harmony-band-stack.is-stay .harmony-band.is-core { opacity: 0.5; }
.harmony-wn-row.is-stay .harmony-vocab-label { color: var(--text3); }

.harmony-vocab-note { margin-top: 4px; }

/* The `.hg-empty` idiom — --text3, italic, and the reason rather than a blank
   box. Same two absences the canvases in this panel tell apart (§4.5). */
.harmony-empty {
  font-size: 0.58rem; font-style: italic; color: var(--text3);
  padding: 8px 0;
}

/* THE COST NOTE, DRAWN. Harmonic density, Progression focus and Root motion are
   all in the engine's tables cache key, and rebuilding that vocabulary costs
   20-200 ms — far too much to do per input event. So the ladder does not lie
   about being current while the dial moves: it recedes to the house `.off`
   opacity and its caption says what it is waiting for. */
.harmony-stale { opacity: 0.45; transition: opacity 140ms ease; }
@media (prefers-reduced-motion: reduce) {
  .harmony-stale { transition: none; }
}

/* Propriety (§2.3). A micro-label, not a badge: the chrome stays monochrome
   and only the verdict word takes the harmony hue, so the chip reads as a
   sentence about the scale rather than a status light. */
.harmony-prop-row { margin-top: 6px; }
.prop-chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 0.58rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text3);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 2px 7px; cursor: help;
}
.prop-chip b {
  font-weight: 700; letter-spacing: 0.04em;
  color: color-mix(in srgb, var(--chordc) 82%, var(--text));
}
/* The one case that changes how chords come out gets a hairline in the hue —
   still no second colour, just the same one turned up. */
.prop-chip.prop-improper { border-color: color-mix(in srgb, var(--chordc) 45%, var(--border)); }

/* An inert control in this panel is greyed by its own disabled state, not by a
   wrapper — so the reason beside it keeps full contrast. */
.harmony-panel select:disabled,
.harmony-panel input:disabled,
.harmony-panel button:disabled { opacity: 0.45; cursor: default; }
.harmony-panel .harmony-seed-row:has(#harmonyReroll:disabled) .harmony-seed-chip { opacity: 0.45; }

/* HG-C3 — the "Retired in v2" block.

   A native `<fieldset disabled>` rather than a class and `pointer-events:
   none`: it disables every control inside it in one attribute, takes them out
   of the Tab order, and is the state a screen reader already knows how to
   announce. It carries no box of its own — the fieldset's default border,
   margin and padding are removed so the rows keep the macro grid's rhythm —
   and it is NOT dimmed as a whole, because the micro-note above each group is
   the part a reader most needs, and a parent opacity would take it down with
   the controls. The label and readout columns are dimmed to meet the 0.45 the
   disabled controls already sit at. */
.harmony-retired-set {
  border: 0; margin: 0; padding: 0; min-width: 0;
}
.harmony-retired-set .label,
.harmony-retired-set output { opacity: 0.45; }
.harmony-retired-set .smart-combo-btn { cursor: default; }

/* Standard §1.7: every new control carries a visible focus-visible state. The
   macro panels' sliders had none of their own — this is the whole family, not
   just HG-C3's nine, and it adds rather than replaces. */
.macro-controls .control-row input[type="range"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ── The audio module's rail block ─────────────────────────────
   docs/AUDIO_IMPORT_AND_EDITING_DESIGN.md §4.5. It occupies the width the
   three instrument cards would, but it is one presentational block, not three
   pages: a recording has no excitor, resonator or body. Deliberately NOT a
   button — the clips are edited on the timeline, and EFFECTS and SPACE after
   it stay live. */

.ch-module-audio .ch-module-tag { border-color: color-mix(in srgb, var(--aud) 55%, var(--hairline-soft)); }
.ch-module-audio .ch-module-name { color: var(--aud-tip); }

.ch-audio-block {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  padding: 10px 14px;
  border: 1px solid color-mix(in srgb, var(--aud) 42%, var(--border2));
  border-radius: 6px;
  background:
    linear-gradient(180deg, var(--aud-dim), transparent 62%),
    var(--well);
  cursor: default;
}
.ch-audio-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
}
.ch-audio-name {
  font-size: 0.84rem;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 0 1 auto;
}
.ch-audio-sub {
  font-size: 0.7rem;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ch-audio-note {
  font-size: 0.66rem;
  color: var(--text3);
  margin-left: auto;
  white-space: nowrap;
}

/* The region to scale: every clip where it actually sits across the reserved
   span. The SVG is stretched non-uniformly to the block width, which is why
   the envelope is a FILLED path — a stroke would scale with it and go lumpy. */
.ch-audio-map {
  position: relative;
  height: 46px;
  border-radius: 4px;
  background: var(--display);
  border: 1px solid var(--hairline-soft);
  overflow: hidden;
}
.ch-audio-map > svg {
  display: block;
  width: 100%;
  height: 100%;
}
.ch-audio-bar {
  stroke: var(--hairline-soft);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.ch-audio-slot {
  fill: color-mix(in srgb, var(--aud) 20%, transparent);
  stroke: color-mix(in srgb, var(--aud) 55%, transparent);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.ch-audio-slot.muted { opacity: 0.35; }
.ch-audio-env {
  fill: color-mix(in srgb, var(--aud-tip) 78%, transparent);
}
.ch-audio-env.muted { opacity: 0.4; }
.ch-audio-rest {
  stroke: var(--text3);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.ch-audio-cliplabel {
  position: absolute;
  top: 2px;
  padding: 0 4px;
  font-size: 0.62rem;
  line-height: 1.2;
  color: var(--text);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
.ch-audio-map-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.68rem;
  color: var(--text3);
}

@media (max-width: 900px) {
  .ch-audio-block { padding: 8px 10px; gap: 10px; }
  .ch-audio-note { display: none; }
}

.ch-audio-layers-note {
  padding: 14px 16px;
  font-size: 0.74rem;
  line-height: 1.45;
  color: var(--text3);
  border: 1px dashed var(--hairline-soft);
  border-radius: 5px;
  background: var(--well);
}

/* ── The freeze chooser ────────────────────────────────────────
   docs/AUDIO_IMPORT_AND_EDITING_DESIGN.md §4.4. It lives in the app dialog
   rather than a toolbar popover for two reasons: a freeze cannot be undone, so
   it deserves a modal; and the region toolbar clips its own overflow, so a
   popover anchored there is invisible. */
.freeze-body {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 4px 0 2px;
  text-align: left;
}
.freeze-head {
  font-size: 0.64rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text3);
}
.freeze-note {
  margin: 0;
  font-size: 0.7rem;
  line-height: 1.45;
  color: var(--text3);
}
.freeze-row {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: 4px 8px;
  padding: 7px 9px;
  border: 1px solid var(--hairline-soft);
  border-radius: 5px;
  background: var(--control-bg);
  cursor: pointer;
}
.freeze-row.unavailable { opacity: 0.55; cursor: not-allowed; }
.freeze-row-label { font-size: 0.8rem; color: var(--text); }
.freeze-row small {
  grid-column: 2;
  font-size: 0.68rem;
  line-height: 1.4;
  color: var(--text3);
}
.freeze-row:focus-within { outline: 2px solid var(--accent); outline-offset: 1px; }
.freeze-summary {
  margin: 0;
  padding: 7px 9px;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--aud-tip);
  background: var(--aud-dim);
  border-radius: 5px;
}

/* An effect whose face could not mount. It used to leave an empty panel and a
   console warning, which reads as "this effect has no controls" rather than as
   a fault — the reason a state mismatch here went unnoticed. */
.fx-face-fault {
  margin: 12px;
  padding: 12px 14px;
  font-size: 0.76rem;
  line-height: 1.5;
  color: var(--text2);
  background: var(--well);
  border: 1px dashed var(--meter-warm);
  border-radius: 6px;
}


/* ═══ Compose · Melody: the landscape (UI overhaul 2, Stage C3) ═══════════
   docs/ui-overhaul-2/compose/C-melody/; the component is melody-landscape.js. */
.mls { display: flex; flex-direction: column; background: var(--display); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.mls { position: relative; }
.mls-mono { font-family: var(--mono); color: var(--text); font-variant-numeric: tabular-nums; }
.mls-stage { position: relative; padding: 12px 16px 0; }
/* Given a height by its host (a flex column), the stage fills it and the
   canvas, measured from it, cannot push it taller. */
.mls-host-fill .mls { height: 100%; }
.mls-host-fill .mls-stage { flex: 1; min-height: 0; overflow: hidden; }
.mls-stage.mls-sized .mls-cv { position: absolute; left: 16px; top: 12px; }
.mls-cv { display: block; touch-action: pan-y; }   /* a vertical swipe scrolls the page; grips take sideways drags (BAR lesson 1) */
.mls-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.mls [hidden] { display: none !important; }
/* The walker's knobs, for the keyboard: invisible over the drawn knob until focused. */
.mls-knobs { position: absolute; inset: 12px 16px 0; pointer-events: none; }
.mls-knob { position: absolute; width: 22px; height: 22px; margin: -11px 0 0 -11px; padding: 0; border: 0; border-radius: 50%; background: transparent; pointer-events: none; }
.mls-knob:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
/* Cues: buttons over the picture, above the shelves in hit order (review L-8 N1). */
.mls-cues { position: absolute; inset: 12px 16px 0; pointer-events: none; z-index: 3; }
.mls-cue { position: absolute; pointer-events: auto; height: 18px; padding: 0 6px; border-radius: 9px; border: 1px solid rgba(var(--walk-light), 0.7); background: var(--display); color: rgb(var(--walk-light)); font: 600 10px/16px var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.mls-cue:hover { border-color: rgb(var(--walk-light)); }
.mls-cue:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
.mls-coarse .mls-cue { height: 28px; line-height: 26px; border-radius: 14px; margin-top: -5px; }
.mls-tip { position: absolute; z-index: 5; pointer-events: none; display: flex; flex-direction: column; gap: 1px; max-width: 240px; padding: 6px 9px; background: var(--display); border: 1px solid var(--border2); border-radius: var(--radius-sm); box-shadow: var(--elev-float); font-size: 11px; line-height: 1.35; color: var(--text2); }
.mls-tip b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
/* By touch: a tapped grip is set here. Fixed height and widths, so a tap moves nothing (lesson 9). */
.mls-adjust { flex: none; height: 48px; display: flex; align-items: center; gap: 8px; padding: 0 12px; border-top: 1px solid var(--border); font-size: 12px; color: var(--text2); overflow-anchor: none; }
.mls-adj-hint { color: var(--text3); }
.mls-adj-name { width: 104px; flex: none; color: var(--text); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mls-adj-step, .mls-adj-done { flex: none; height: 44px; min-width: 44px; border: 1px solid var(--border2); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; font-size: 16px; }
.mls-adj-done { font-size: 12px; margin-left: auto; padding: 0 10px; }
.mls-adj-val { width: 64px; flex: none; height: 36px; text-align: right; padding: 0 8px; font: 600 13px var(--mono); font-variant-numeric: tabular-nums; color: var(--text); background: var(--bg); border: 1px solid var(--border2); border-radius: var(--radius-sm); }
.mls-adj-step:focus-visible, .mls-adj-done:focus-visible, .mls-adj-val:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
.mls-rows { position: absolute; inset: 12px 16px 0; pointer-events: none; }
.mls-ledge { position: absolute; pointer-events: auto; background: transparent; border: 0; padding: 0; cursor: pointer; border-radius: 3px; }
.mls-ledge:focus-visible { outline: 2px solid var(--text); outline-offset: -1px; }
.mls-home { position: absolute; pointer-events: auto; border: 0; border-radius: 3px; background: transparent; color: var(--text2); font-size: 11px; line-height: 1; padding: 0; cursor: pointer; opacity: 0; }
.mls-home[aria-pressed="true"] { opacity: 1; color: var(--rootc); }
.mls-wrap:hover .mls-home, .mls-ledge:focus-visible + .mls-home, .mls-home:focus-visible { opacity: 1; }
.mls-home:focus-visible { outline: 2px solid var(--text); }
/* Under a finger there is no hover: every ⌂ shows, and is a full target (review L-1 M10). */
.mls-coarse .mls-home { opacity: 0.55; font-size: 16px; }
.mls-coarse .mls-home[aria-pressed="true"] { opacity: 1; }
.mls-note { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; padding: 8px 16px 10px; min-height: 34px; font-size: 12px; line-height: 1.4; color: var(--text2); }
/* The words never eat the picture: past three lines they scroll (review L-1 M5). */
/* The words: a fixed height of whole lines (they never resize the picture, the
   zoom on Play), never a scroller (a nested scroller traps a phone's swipe,
   review L-6 N2). More opens the rest over the picture, from the bottom up. */
.mls-words { position: relative; flex: none; height: calc(4 * 12px * 1.4 + 18px); overflow-anchor: none; }   /* four lines, not five: the rest chance is always the first (review L-7 S4) */
.mls-coarse .mls-words { height: calc(5 * 12px * 1.4 + 18px); }
.mls-words .mls-note { position: absolute; left: 0; right: 0; bottom: 0; height: 100%; overflow: hidden; align-content: flex-start; background: var(--display); }
.mls-words.mls-open .mls-note { height: auto; min-height: 100%; z-index: 5; border-top: 1px solid var(--border2); box-shadow: var(--elev-float); padding-bottom: 34px; }
.mls-more { position: absolute; right: 12px; bottom: 6px; z-index: 6; font: 600 10px/1 var(--font); letter-spacing: 0.12em; text-transform: uppercase; color: var(--text); background: var(--display); border: 1px solid var(--border2); border-radius: var(--radius-sm); padding: 5px 9px; cursor: pointer; }
.mls-coarse .mls-more { min-height: 32px; min-width: 56px; }
.mls-more:hover { border-color: var(--text3); }
.mls-more:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
.mls-note-more { padding-right: 84px !important; -webkit-mask-image: linear-gradient(to bottom, black calc(100% - 22px), transparent calc(100% - 4px)); mask-image: linear-gradient(to bottom, black calc(100% - 22px), transparent calc(100% - 4px)); }   /* clipped: only its last line fades, and nothing runs under More */
.mls-note b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.mls-widen { font: inherit; color: var(--text); background: transparent; border: 1px solid var(--border2); border-radius: var(--radius-sm); padding: 2px 8px; cursor: pointer; }
.mls-widen:hover { border-color: var(--accent); }
.mls-widen:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.m2-landscape { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.m2-landscape .mls { border: 0; border-radius: 0; }
/* On a phone the page scrolls, so the landscape can be tall enough for its
   rows (44 px each) and the next note's odds: 540 px held four (review L-5, M2). */
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  .macro2-workspace-mode .m2-display:has(.m2-landscape) { height: 900px; }
}
.m2-display .m2-visual[hidden], .vis-mode-switch[hidden], .vis-spec-toggle[hidden] { display: none; }
.m2-chips .vis-seg .vis-mode-btn { flex: none; padding: 1px 6px; }   /* three words, none clipped (review L-2) */
.melody-panel .unit-help, #m2Inspector .unit-help { margin: 4px 0 2px; font-size: 0.72rem; line-height: 1.45; color: var(--text2); }
.melody-panel .unit-help b, #m2Inspector .unit-help b { color: var(--text); font-weight: 600; }
.melody-panel .unit-next { margin: 10px 0 2px; padding-top: 10px; border-top: 1px solid var(--border); font-size: 0.72rem; line-height: 1.45; color: var(--text2); }
/* The unit's own groups read first (review L-1 S5): full-contrast titles, and
   the legacy "section being edited" amber does not light the unchanged ones. */
/* the Compose units' group title: one rule for Melody and Harmony (review HARMONY-BUILD-1 M2, gates D and G) */
.m2-inspector .melody-panel .subsection-label.unit-title, .m2-inspector .harmony-panel .subsection-label.unit-title { font: 600 0.68rem/1.3 var(--font); letter-spacing: 0.1em; color: var(--text); margin-bottom: 8px; }
.melody-panel .macro-subsection.active .subsection-label:not(.unit-title) { color: var(--text3); }
.harmony-panel .macro-subsection.active .subsection-label.unit-title { color: var(--text); }   /* no legacy "being edited" amber */
.melody-panel .arp-inert { opacity: 0.45; }
.melody-panel .arp-inert input[type=range] { cursor: not-allowed; }

/* Hear a tuning before choosing it (basics audit #12): the row sounding now. */
.smart-combo-opt.previewing { box-shadow: inset 2px 0 0 var(--accent); }
/* "hearing" never shrinks: a long name gives way to it, not the other way
   round (review 12-3b, minor). */
.smart-combo-opt.previewing > .smart-combo-opt-label { margin-right: auto; }
.smart-combo-opt.previewing::after { content: "hearing"; order: 2; flex: none; color: var(--accent2); font-weight: 600; font-size: 0.58rem; letter-spacing: 0.06em; text-transform: uppercase; }

/* Changed from what was loaded (basics audit #13): a small neutral mark
   after the control's name. State of the chrome, so not a hue. */
.control-row.changed > .label::after,
.knob-cell.changed .knob-label::after,
.feature-check.changed > span::after,
[data-changed-key].changed .seg-btn.active::after {
  content: ""; display: inline-block; width: 5px; height: 5px; margin-left: 6px;
  border-radius: 50%; background: var(--text); vertical-align: 0.12em;
}

/* Revert a group (basics audit #14): a quiet text button in the group's
   label, present only while something in the group has changed. */
.group-reset {
  position: relative; margin: -7px 0 -7px 8px; padding: 1px 5px; vertical-align: 0.05em;   /* negative margins: its box never makes the label taller, down to 8 px labels (S3, review 5 T3) */
  font: inherit; font-size: max(10px, 1em); letter-spacing: inherit; line-height: 1.2; text-transform: uppercase;   /* the label's own face, never under 10 px (review 4, S9); a tight line keeps even an 8 px label its height (review 5, T3) */
  color: var(--text2); background: transparent; border: 1px solid var(--border2); border-radius: var(--radius-sm); cursor: pointer;
}
/* Under a finger the land's octave buttons are full targets too (review L-4). */
@media (pointer: coarse) { .oct-btns .pal-btn { min-height: 44px; min-width: 44px; } }
/* Under a finger: every label that can hold a Reset keeps a 44 px row, so
   the Reset is a full target and nothing below it moves or is covered
   (review 4, S7). Compare reaches 44 px tall without touching Redo. */
@media (pointer: coarse) {
  .macro-subsection > .subsection-label, .ins-group > .ins-group-label, details.ch-perf > summary,
  .reset-group > .section-label, .reset-group > .section-subhead, .reset-group > .subsection-label,
  .ch-inspector > .ch-ins-head, .circuit-controls > .ch-ins-head, .td-side > .td-tabs { min-height: 44px; }
  /* …and the label's line sits in the middle of that row from the start,
     so the Reset's arrival moves nothing (review 5, T1). The Reset shares
     the label's baseline; its negative margins keep its 44 px box out of the
     line's height, whatever the label's type size. */
  .macro-subsection > .subsection-label, .ins-group > .ins-group-label, details.ch-perf > summary,
  .reset-group > .section-label, .reset-group > .section-subhead, .reset-group > .subsection-label { box-sizing: border-box; padding-block: calc((44px - 1lh) / 2); align-items: baseline; }
  .ch-inspector > .ch-ins-head, .circuit-controls > .ch-ins-head { justify-content: center; }
  .group-reset { min-height: 44px; margin-block: -23px -17px; }
  .td-side > .td-tabs > .group-reset { min-height: 0; align-self: stretch; }   /* the tab row is already 44 px: fill it, never grow it */
  /* A slider is taken by its thumb or a tap, never by a swipe that crosses it
     (review 12-3b, S5; installTouchSliders in app.js). */
  input[type=range]:not([orient=vertical]):not(.fader--v) { pointer-events: none; }
  /* the row lets the page pan either way, so a leaning swipe scrolls; a sideways drag on the thumb is kept still by
     installTouchSliders, which cancels its touchmoves once it decides the drag is sideways (review DICE-BUILD-1 S1) */
  :has(> input[type=range]:not([orient=vertical]):not(.fader--v)) { touch-action: manipulation; }
  .tb-explore #studioCompareBtn { position: relative; }
  .tb-explore #studioCompareBtn::before { content: ""; position: absolute; inset: -7px -2px; }
}
.register-mini-section > .subsection-label > .group-reset { margin-right: auto; }   /* after the name, as everywhere (review 4) */
.register-mini-section > .subsection-label:has(> .group-reset) { align-items: baseline; }   /* the Reset on the name's baseline, not centred on a smaller name */
/* Where the group's label is not a small caps label (the envelope's tab row,
   a stage inspector's heading), the Reset keeps the small face of every other. */
.td-tabs > .group-reset, .ch-ins-head > .group-reset {
  flex: none; align-self: center; margin: 0 6px; font: 700 10px/1.2 var(--mono); letter-spacing: 0.1em;   /* 10 px here too (review 5, T2) */
}
.ch-ins-head { position: relative; }
.ch-ins-head > .group-reset { position: absolute; top: 0; right: 0; margin: 0; }
.group-reset:hover { color: var(--text); border-color: var(--accent); }
.group-reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Compare (basics audit #15): lit while held. The bar sheds it below 900 px
   before the account pill would be pushed off. */
.tb-explore #studioCompareBtn[aria-pressed="true"] { color: var(--text); border-color: var(--accent); background: var(--surface2); }
@media (max-width: 900px) { .tb-explore #studioCompareBtn { display: none; } }

/* ═══ Compose on a phone (basics audit #3) ═══════════════════════════════
   One column that scrolls with the page: the rail as a strip you can swipe,
   the display (the landscape, or the lanes), the settings, then the
   library. The bar wraps to a second row rather than running off-screen. */
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  /* The page itself scrolls: the studio's full-height shell is released for
     Compose on a phone (basics review #3, M2). */
  body.explore-mode:has(.macro2-workspace-mode) { overflow-y: auto; height: auto; }
  body.explore-mode:has(.macro2-workspace-mode) #app,
  body.explore-mode:has(.macro2-workspace-mode) .view { height: auto; min-height: 100dvh; }
  .tb-explore { position: sticky; top: 0; z-index: 20; background: var(--surface); }   /* the transport stays in reach, opaque over what scrolls under it (review 12-3b, N2) */
  .explore-dashboard.macro2-workspace-mode { display: block; min-height: 0; height: auto; overflow: visible; }
  .macro2-workspace-mode .macro2-card { position: static; height: auto; overflow: visible; margin-top: 8px; }
  .macro2-workspace-mode .m2-main { flex-direction: column; }
  .macro2-workspace-mode .m2-rail { width: auto; flex-direction: row; overflow-x: auto; overflow-y: hidden; }
  .macro2-workspace-mode .m2-rail-grid { flex-direction: row; }
  .macro2-workspace-mode .m2-rail-btn { min-width: 72px; min-height: 52px; }
  /* the centre column is flattened so the settings can sit between the display and the library */
  .macro2-workspace-mode .m2-center { display: contents; }
  .macro2-workspace-mode .m2-chips { order: 1; }
  .macro2-workspace-mode .m2-display { order: 2; flex: none; height: 540px; }   /* a real height, so Lanes' and Roll's canvases resolve (M4) */
  .macro2-workspace-mode .m2-inspector { order: 3; width: auto !important; max-width: none; height: auto; overflow: visible; }
  .macro2-workspace-mode .m2-lib-dock { order: 4; }
  .macro2-workspace-mode .m2-bottom { flex-wrap: wrap; row-gap: 6px; }
  .macro2-workspace-mode .m2-vsplit, .macro2-workspace-mode .m2-hsplit { display: none; }
  /* The library grows with its content; its list scrolls in place (M3). */
  .macro2-workspace-mode .m2-lib-dock { height: auto; max-height: none; overflow: visible; }
  .macro2-workspace-mode .m2-lib-dock .m2-lib, .macro2-workspace-mode .m2-lib.docked { flex: none; }
  .macro2-workspace-mode .m2-lib-list { flex: none; max-height: 60dvh; }
  .macro2-workspace-mode .m2-lib-head { flex-wrap: wrap; row-gap: 6px; }
  .macro2-workspace-mode .m2-lib-search { flex: 1 1 140px; min-width: 0; }
  /* Nothing in the library widens the page: the favourites scroll in their
     own strip, and a row's tags wrap under its name. */
  .macro2-workspace-mode .m2-lib-dock, .macro2-workspace-mode .m2-lib, .macro2-workspace-mode .m2-presets { min-width: 0; max-width: 100%; }
  .macro2-workspace-mode .m2-lib-row { flex-wrap: wrap; row-gap: 4px; }
  .macro2-workspace-mode .m2-lib-tags { flex: 1 1 100%; flex-wrap: wrap; }
  .macro2-workspace-mode .m2-tiles { flex: 1 1 100%; min-width: 0; flex-wrap: wrap; row-gap: 6px; }   /* every readout shows */
  .tb-explore { flex-wrap: wrap; row-gap: 6px; padding-block: 6px; height: auto; }
  .tb-explore .tb-spacer { display: none; }
  /* "Undid …" and the preview's words are read on a phone too, as a toast under the sticky header: it takes no
     layout space, so its arrival never moves the page (REVIEW-PERC-BUILD-1 M3, lesson 9) */
  .tb-explore #exploreStatus { position: absolute; top: calc(100% + 4px); left: 8px; right: 8px; z-index: 21; flex: none; order: 99;
    padding: 6px 10px; border: 1px solid var(--border2); border-radius: var(--radius-sm); background: var(--surface2); color: var(--text);
    box-shadow: var(--elev-float); white-space: normal; pointer-events: none; }
  .tb-explore #exploreStatus:empty { display: none; }
  body.explore-mode:has(.macro2-workspace-mode) { flex-direction: column; }   /* the credit goes under the app, not beside it */
  body.explore-mode:has(.macro2-workspace-mode) .app-credit { position: static; padding-block: 8px; width: 100%; }   /* not over the readouts */
}

/* Compose · Melody: rows linked to the landscape's parts (DESIGN-1 B). The
   mark in front of a row is the knob it moves on the picture; hover or focus
   on either lights the other. */
.mls-gslot { display: inline-block; width: 16px; height: 14px; margin-right: 6px; vertical-align: -2px; }
.mls-g { width: 16px; height: 16px; display: block; overflow: visible; }
.mls-group-head { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; white-space: nowrap; min-width: 0; position: relative; padding-right: 64px; }   /* a Reset appearing never re-wraps the head (lesson 9) */
.mls-group-head > .group-reset { position: absolute; right: 0; top: 50%; transform: translateY(-50%); margin: 0; }   /* in the space the head always keeps for it: nothing beside it moves (review L-6 N3) */
.mls-group-head .oct-btns { flex: none; margin-left: auto; }
/* The land's help and "every note is stable" share one slot, as tall as the
   taller of the two: one replaces the other without moving anything below (review L-6). */
.mls-help-slot { display: grid; }
.mls-help-slot > .unit-help { grid-area: 1 / 1; }
.mls-help-slot > #m2FavourNote[hidden] { display: block !important; visibility: hidden; }
.mls-help-slot:has(> #m2FavourNote:not([hidden])) > .unit-help:not(#m2FavourNote) { visibility: hidden; }
.mls-group-head > .mls-g { width: 16px; height: 16px; flex: none; }
.mls-kind { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.68rem; font-weight: 400; letter-spacing: 0.02em; text-transform: none; color: var(--text3); }
.mls-gf-walk { fill: rgb(var(--walk-light)); }
.mls-gs-walk { stroke: rgba(var(--walk-light), 0.45); stroke-width: 1.5; }
.mls-gf-root { fill: var(--rootc); }
.mls-gf-land { fill: rgba(var(--land-light), 0.85); }
.mls-gf-land-dim { fill: rgba(var(--land-light), 0.3); }
.mls-gk { stroke: var(--knob-ring); stroke-width: 1.5; }
.mls-gc { fill: none; stroke: var(--knob-ring); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.mls-gb { fill: rgba(var(--walk-light), 0.2); stroke: rgba(var(--walk-light), 0.8); stroke-width: 1.2; }
.mls-gpill { fill: none; stroke: var(--text2); stroke-width: 1.3; }
.control-row.mls-linked { border-radius: var(--radius-sm); transition: background-color 120ms; }
#m2Inspector .control-row.mls-linked output { white-space: nowrap; }   /* "13 steps" on one line: a readout never grows its row (lesson 9, review L-7 S3) */
#m2Inspector .control-row.mls-linked { grid-template-columns: minmax(0, 140px) 1fr 72px; }
.control-row.mls-lit, .control-row.mls-linked[data-mls-part]:hover, .control-row.mls-linked[data-mls-part]:focus-within { background: var(--surface2); }
.control-row.mls-lit .label { color: var(--text); }
@media (prefers-reduced-motion: reduce) { .control-row.mls-linked { transition: none; } }


/* ── Compose · Harmony: the route (harmony-route.js; UI overhaul 2 Stage C, D-16) ─────────────────── */
.m2-route { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: auto; overflow-anchor: none; }
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  /* on a phone the page scrolls, not the display: the display grows to the picture (no nested scroller, HARM-6 N2) */
  .macro2-workspace-mode .m2-display:has(.m2-route) { height: auto; }
  .m2-route { overflow: visible; }
}
.hr { position: relative; display: flex; flex-direction: column; background: var(--display); }
.hr-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.hr-head { display: flex; align-items: center; gap: 12px; padding: 8px 12px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.hr-switch { display: inline-flex; align-items: center; gap: 8px; border: 0; background: none; color: var(--text); font: 12px var(--font); cursor: pointer; padding: 4px 2px; }
.hr-switch i { position: relative; width: 30px; height: 16px; border-radius: 8px; background: var(--hm-chord-fill); border: 1px solid var(--chordc); }
.hr-switch i::after { content: ""; position: absolute; top: 2px; left: 15px; width: 10px; height: 10px; border-radius: 50%; background: var(--chordc); }
.hr-switch.off i { background: var(--surface2); border-color: var(--border2); }
.hr-switch.off i::after { left: 2px; background: var(--text3); }
.hr-pull { display: block; overflow: visible; }
.hr-tabs { display: flex; gap: 2px; margin-left: auto; }
.hr-tabs button { font: 12px var(--font); color: var(--text2); padding: 5px 10px; border-radius: var(--radius-sm); border: 0; background: none; cursor: pointer; white-space: nowrap; min-width: 150px; text-align: left; }
.hr-tabs button.on { color: var(--text); background: var(--surface2); }
.hr-tabs button small { color: var(--text3); margin-left: 6px; font-size: 11px; font-variant-numeric: tabular-nums; }
.hr-switch:focus-visible, .hr-tabs button:focus-visible, .hr-bar button:focus-visible, .hr-bar input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hr-pic { display: block; width: 100%; flex: none; touch-action: pan-y; }
.hr-head, .hr-bar { flex: none; }
.hr-pic .mono, .hr-pull .mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.hr-bar { position: relative; height: 42px; display: flex; align-items: center; gap: 10px; padding: 0 12px; border-top: 1px solid var(--border); font-size: 12px; color: var(--text2); white-space: nowrap; overflow: hidden; }
.hr-status { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.hr-upd { font-size: 11px; color: var(--text3); opacity: 0; transition: opacity 200ms linear; width: 64px; text-align: right; flex: none; }
.hr.is-stale .hr-upd { opacity: 1; }
.hr-bar .hr-lbl { width: 110px; flex: none; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
.hr-bar .hr-step { width: 44px; height: 36px; flex: none; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: var(--surface2); color: var(--text); font: 16px var(--font); }
.hr-bar .hr-val { width: 72px; height: 36px; flex: none; background: var(--surface2); border: 1px solid var(--border2); border-radius: var(--radius-sm); color: var(--text); font: 13px var(--mono); font-variant-numeric: tabular-nums; text-align: right; padding: 0 6px; }
/* the picture's controls */
.hr-pic .kn, .hr-pull .kn { cursor: ew-resize; outline: none; }
.hr-pic .kn .ring, .hr-pull .kn .ring { stroke: none; }
.hr-pic .kn:focus-visible .ring, .hr-pull .kn:focus-visible .ring { stroke: var(--accent); stroke-width: 2; }
.hr-pic .clock, .hr-pic .bt { cursor: pointer; outline: none; }
.hr-pic .clock:focus-visible .cell { stroke: var(--accent); stroke-width: 2; }
.hr-pic .bt:focus-visible rect:first-child { stroke: var(--accent); stroke-width: 2; }
.hr-pull .kn.off circle[stroke] { fill: var(--display); stroke: var(--text3); }
/* hover and focus: classes on what is drawn (the picture is never rebuilt for a hover) */
.hr-pic .halo { fill: var(--hm-hot); stroke: var(--accent); opacity: 0; }
.hr-pic .hot .halo { opacity: 1; }
.hr-pic .clock.hot .cell { fill: var(--hm-hot); stroke: var(--accent); }
.hr-pic .hot text[data-role] { fill: var(--accent); }
.hr-pic rect.band.lit { stroke: var(--accent); }
.hr-pic .kn .glow, .hr-pull .kn .glow { opacity: 0; }
.hr-pic[data-hp="route"] .kn[data-part="route"] .glow, .hr-pic[data-hp="arrival"] .kn[data-part="arrival"] .glow,
.hr-pic[data-hp="offer"] .kn[data-part="offer"] .glow, .hr-pic[data-hp="next"] .kn[data-part="next"] .glow,
.hr-pic[data-hp="played"] .kn[data-part="played"] .glow, .hr-pull[data-hp="head"] .kn .glow { opacity: 0.3; }
/* the held picture: only for a single discrete edit, and only past 150 ms (the script waits; then this eases in) */
.hr-pic .pic > * { transition: opacity 150ms ease-out; }
.hr.is-held .hr-pic .pic > :not(.kn) { opacity: var(--hm-held); }
.hr::before { content: ""; position: absolute; left: 0; top: 0; height: 2px; width: 0; background: var(--accent); opacity: 0; transition: opacity 200ms linear; z-index: 2; }
.hr.is-stale::before { opacity: 1; animation: hr-busy 1.2s ease-in-out infinite; }
@keyframes hr-busy { 0% { width: 8%; margin-left: 0; } 50% { width: 40%; margin-left: 30%; } 100% { width: 8%; margin-left: 92%; } }
@media (pointer: coarse) { .hr-tabs button, .hr-switch { min-height: 44px; } .hr-bar { height: 52px; } }
@media (max-width: 760px) { .hr-tabs { margin-left: 0; width: 100%; display: grid; grid-template-columns: 1fr 1fr; } .hr-tabs button { min-width: 0; } }
@media (prefers-reduced-motion: reduce) { .hr-pic .pic > *, .hr-upd, .hr::before { transition: none; } .hr.is-stale::before { animation: none; width: 45%; } }
/* the inspector's groups: the picture's parts, in its order; a row's glyph is its knob there, in its hue */
.hr-group { border-radius: var(--radius-sm); transition: background-color 120ms; }
.hr-group.hr-lit { background: var(--surface2); }
.hr-group.hr-lit .subsection-label.unit-title { color: var(--accent); }
.hr-gslot { display: inline-block; width: 16px; height: 14px; margin-right: 6px; vertical-align: -2px; }
.hr-g { width: 14px; height: 14px; display: block; overflow: visible; }
.hr-g-chord { fill: var(--chordc); stroke: var(--knob-ring); stroke-width: 2; }
.hr-g-root { fill: var(--rootc); stroke: var(--knob-ring); stroke-width: 2; }
.hr-g-sw { fill: var(--hm-root-soft); stroke: var(--rootc); stroke-width: 1; }
#m2Inspector .control-row.hr-linked { grid-template-columns: minmax(0, 150px) 1fr 64px; }
@media (prefers-reduced-motion: reduce) { .hr-group { transition: none; } }

/* review BUILD-1 M1: the "more below" cue (a zero-height sticky row: showing it moves nothing) */
.hr-more-wrap { position: sticky; bottom: 0; height: 0; z-index: 3; pointer-events: none; }
.hr-more { position: absolute; bottom: 8px; right: 12px; pointer-events: auto; font: 600 11px var(--font); letter-spacing: 0.04em; color: var(--text); background: var(--surface2); border: 1px solid var(--border2); border-radius: 999px; padding: 5px 12px; cursor: pointer; box-shadow: 0 1px 0 rgba(0,0,0,0.35); }
.hr-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (pointer: coarse) { .hr-more { min-height: 44px; } }
/* the arrival part lights its ringed clock, not the whole band (review BUILD-1 S4) */
.hr-pic[data-hp="arrival"] .clock[data-arrival] .cell { stroke: var(--accent); stroke-width: 1.5; }
/* …and the preset library closes to a one-line strip in the Harmony route view */
.m2-lib-strip { flex: none; display: block; width: 100%; text-align: left; padding: 6px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text2); font: 600 0.68rem/1.3 var(--font); letter-spacing: 0.1em; text-transform: uppercase; cursor: pointer; }
.m2-lib-strip:hover { color: var(--text); }
.m2-lib-strip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.m2-hsplit[hidden] { display: none; }
.m2-lib-dock.is-closed { display: none; }
@media (pointer: coarse) { .m2-lib-strip { min-height: 44px; } }
.macro2-workspace-mode .m2-lib-strip { order: 4; }
/* the route's words line stays in sight at the display's foot while the picture scrolls under it; the cue sits above it */
.m2-route .hr-bar { position: sticky; bottom: 0; z-index: 2; background: var(--display); }
.hr-more { bottom: 8px; }   /* in the words line's right end, which it keeps clear: over no chord or odds */
.m2-route:has(.hr-more:not([hidden])) .hr-bar { padding-right: 136px; }
@media (pointer: coarse) { .hr-more { bottom: 60px; } }
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) { .m2-route .hr-bar { position: relative; } }


/* ── Compose · Rhythm · the feel: the rubber ruler (feel-ruler.js; UI overhaul 2 Stage C, D-16, D-17) ───── */
.m2-feel { flex: 1; min-height: 0; min-width: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: auto; overflow-anchor: none; }
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  /* on a phone the page scrolls, not the display (no nested scroller: HARM-6 N2) */
  .macro2-workspace-mode .m2-display:has(.m2-feel) { height: auto; }
  .m2-feel { overflow: visible; }
}
@media (pointer: coarse) { :root { --fr-hit: 44px; } }
.fr { position: relative; display: flex; flex-direction: column; background: var(--display); min-width: 0; }
.fr > * { flex: none; }   /* the display scrolls; its lines never shrink into each other */
.fr-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.fr-head { display: flex; align-items: center; gap: 8px 14px; padding: 8px 12px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.fr-named { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.fr-named-l { font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text3); font-weight: 650; margin-right: 2px; }
.fr-chip { height: 24px; padding: 0 8px; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--font); cursor: pointer; white-space: nowrap; }
.fr-chip[aria-pressed="true"] { color: var(--text); border-color: var(--text2); background: var(--surface2); }
.fr-chip:disabled { opacity: 0.4; cursor: default; }
.fr-switch { display: inline-flex; align-items: center; gap: 7px; height: 26px; padding: 0 2px; background: none; border: 0; color: var(--text2); font: 12px var(--font); cursor: pointer; white-space: nowrap; }
.fr-switch i { position: relative; width: 26px; height: 14px; border-radius: 7px; background: var(--surface2); border: 1px solid var(--border2); flex: none; }
.fr-switch i::after { content: ""; position: absolute; top: 2px; left: 2px; width: 8px; height: 8px; border-radius: 50%; background: var(--text3); transition: left 150ms ease; }
.fr-switch[aria-pressed="true"] { color: var(--text); }
.fr-switch[aria-pressed="true"] i { border-color: var(--text2); }
.fr-switch[aria-pressed="true"] i::after { left: 14px; background: var(--text); }
.fr-keybtn { margin-left: auto; height: 24px; padding: 0 8px; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--font); cursor: pointer; white-space: nowrap; }
.fr-keybtn[aria-expanded="true"] { color: var(--text); background: var(--surface2); }
.fr-chip:focus-visible, .fr-switch:focus-visible, .fr-keybtn:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }   /* focus is white on this unit: amber means swing (review m1) */
.fr-pic { position: relative; padding: 10px 12px 0; min-width: 0; }
.fr-pic canvas { max-width: 100%; }
.fr-pic canvas { display: block; touch-action: pan-y; -webkit-tap-highlight-color: transparent; }
.fr-pic canvas:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
/* the playhead: the studio's audio clock sweeping the beat, and the take's row it is on */
.fr-playhead { position: absolute; width: 0; border-left: 1.5px solid var(--text); opacity: 0.7; pointer-events: none; }
.fr-playrow { position: absolute; width: 14px; margin-left: -7px; border-radius: 1px; background: var(--text); opacity: 0.55; pointer-events: none; }
/* the always-visible caption under the ruler: how to use it (review M1) */
.fr-cap { margin: 0; padding: 6px 12px 0; display: flex; flex-wrap: wrap; gap: 2px 14px; font-size: 11.5px; line-height: 1.45; color: var(--text2); }
.fr-cap b { color: var(--text); font-weight: 600; }
.fr-cap span { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.fr-cap .k, .fr-key .k { display: inline-block; width: 9px; height: 9px; border-radius: 1px; background: rgb(var(--land-light)); box-shadow: 0 0 0 2px var(--knob-ring); margin-left: 3px; }
.fr-cap .k.sw, .fr-key .k.sw { background: var(--accent); transform: rotate(45deg) scale(0.9); }
.fr-cap .k.ring, .fr-key .k.ring { border-radius: 50%; background: var(--display); box-shadow: inset 0 0 0 2.5px rgb(var(--land-light)), 0 0 0 2px var(--knob-ring); }
.fr-cap .t.h, .fr-key .t.h { display: inline-block; width: 5px; height: 11px; background: transparent; border-radius: 0; box-shadow: inset 0 0 0 1px rgb(var(--land-light)); }
.fr-key kbd { font: 11px var(--mono); color: var(--text); border: 1px solid var(--border2); border-radius: 3px; padding: 0 4px; }
.fr-more { position: sticky; bottom: 0; align-self: stretch; height: 26px; border: 0; border-top: 1px solid var(--border); background: linear-gradient(to bottom, transparent, var(--display) 40%); color: var(--text2); font: 11.5px var(--font); cursor: pointer; }
.fr-more[hidden] { display: none; }
/* the column: named swings and one engine-true line under each group (review S1), fixed height (lesson 9) */
.fr-named-row { display: flex; align-items: center; gap: 8px; margin: 2px 0 4px; }
.fr-says { margin: 2px 0 6px; font-size: 11.5px; line-height: 1.45; color: var(--text2); height: calc(2 * 1.45em); overflow: hidden; }
.fr-says b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
/* the knobs: real buttons over the canvas; the three differ by shape (◆ swing, ■ lay-back, ○ looseness), not hue alone */
.fr-knob { position: absolute; width: var(--fr-hit); height: var(--fr-hit); margin: 0; padding: 0; transform: translate(-50%, -50%); border: 0; background: transparent; cursor: ew-resize; touch-action: pan-y; display: grid; place-items: center; border-radius: 50%; -webkit-tap-highlight-color: transparent; }
.fr-knob::after { content: ""; width: 13px; height: 13px; border-radius: 50%; background: rgb(var(--land-light)); box-shadow: 0 0 0 2px var(--knob-ring); transition: transform 120ms ease, box-shadow 120ms ease; }
.fr-knob.sw::after { width: 12px; height: 12px; border-radius: 2px; background: var(--accent); transform: rotate(45deg); }
.fr-knob.sq::after { width: 12px; height: 12px; border-radius: 2px; }
.fr-knob.ring::after { background: var(--display); box-shadow: inset 0 0 0 3px rgb(var(--land-light)), 0 0 0 2px var(--knob-ring); }
.fr-knob:hover::after, .fr-knob.lit::after, .fr-knob[data-drag="true"]::after { transform: scale(1.2); box-shadow: 0 0 0 2px var(--knob-ring), 0 0 0 4px var(--text); }
.fr-knob.sw:hover::after, .fr-knob.sw.lit::after, .fr-knob.sw[data-drag="true"]::after { transform: rotate(45deg) scale(1.2); }
.fr-knob.ring:hover::after, .fr-knob.ring.lit::after, .fr-knob.ring[data-drag="true"]::after { box-shadow: inset 0 0 0 3px rgb(var(--land-light)), 0 0 0 2px var(--knob-ring), 0 0 0 4px var(--text); }
.fr-knob:focus-visible { outline: 2px solid var(--text); outline-offset: 0; }
.fr-knob[hidden] { display: none; }
/* fixed-height lines: a tap never moves the layout (lesson 9) */
.fr-status { margin: 0; padding: 8px 12px 0; height: calc(2 * 1.45em + 8px); overflow: hidden; font-size: 12px; line-height: 1.45; color: var(--text2); }
.fr-heard { margin: 0; padding: 4px 12px 8px; height: calc(2 * 1.45em + 12px); overflow: hidden; font-size: 12px; line-height: 1.45; color: var(--text2); font-variant-numeric: tabular-nums; }
.fr-status b, .fr-heard b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.fr-dim { color: var(--text3); }
/* the key folds into "Key ▸" and opens OVER the picture, so opening it moves nothing (lesson 9) */
.fr-key { position: absolute; top: 46px; right: 8px; z-index: 6; max-width: min(460px, calc(100% - 16px)); display: flex; flex-direction: column; align-items: flex-start; gap: 5px; padding: 10px 12px; background: var(--surface); border: 1px solid var(--border2); border-radius: var(--radius-sm); box-shadow: var(--elev-float); font-size: 11.5px; line-height: 1.45; color: var(--text2); }
.fr-key[hidden] { display: none; }
.fr-key span { display: block; }   /* running text: a glyph stays with its words */
.fr-key .k, .fr-key .t { vertical-align: -1px; margin: 0 4px 0 2px; }
.fr-key .t { display: inline-block; width: 3px; height: 11px; border-radius: 1px; background: rgb(var(--land-light)); }
.fr.fr-narrow .fr-status { height: calc(3 * 1.45em + 8px); }   /* by the display's width, not the window's */
.fr.fr-narrow .fr-heard { height: calc(3 * 1.45em + 12px); }
/* the inspector's Groove group, by the ruler's parts */
.fr-group { border-radius: var(--radius-sm); transition: background 150ms ease; }
.fr-group.fr-lit { background: var(--surface2); }
.fr-group-head { margin: 8px 0 2px; font-size: 0.68rem; font-weight: 650; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text2); }
.fr-group.fr-lit .fr-group-head { color: var(--text); }
.fr-gslot { display: inline-block; width: 16px; height: 14px; margin-right: 6px; vertical-align: -2px; }
.fr-g { width: 14px; height: 14px; display: block; overflow: visible; }
.fr-g-sw { fill: var(--accent); stroke: var(--knob-ring); stroke-width: 2; }
.fr-g-sq { fill: rgb(var(--land-light)); stroke: var(--knob-ring); stroke-width: 2; }
.fr-g-ring { fill: none; stroke: rgb(var(--land-light)); stroke-width: 2.4; }
#m2Inspector .control-row.fr-linked { grid-template-columns: minmax(0, 150px) 1fr 64px; }
#m2Inspector .control-row.fr-linked output { white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { .fr-knob::after, .fr-switch i::after, .fr-group { transition: none; } }


/* ── Compose · Rhythm · How loud: the loudness ladder (dynamics-ladder.js; UI overhaul 2 Stage C) ───────────── */
.m2-dyn { flex: 1; min-height: 0; min-width: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: auto; overflow-anchor: none; }
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  /* on a phone the page scrolls, not the display (no nested scroller) */
  .macro2-workspace-mode .m2-display:has(.m2-dyn) { height: auto; }
  .m2-dyn { overflow: visible; }
  /* opening a fold in the picture must not scroll the page: the browser's scroll anchoring pinned the inspector
     below it and moved the page by the fold's height (lesson 9) */
  html:has(.m2-dyn) { overflow-anchor: none; }
}
.dl { position: relative; display: flex; flex-direction: column; background: var(--display); min-width: 0; padding: 0 12px 10px; }
.dl > * { flex: none; }
.dl-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.dl-head { display: flex; align-items: center; gap: 8px 16px; padding: 8px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap; margin-bottom: 8px; }
.dl-play { display: inline-flex; align-items: center; justify-content: center; gap: 6px; width: 13.5em; height: 28px; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: var(--surface2); color: var(--text); font: 600 12px var(--font); cursor: pointer; }
.dl-play svg { width: 10px; height: 10px; }
.dl-play:hover { border-color: var(--accent); }
.dl-play:focus-visible, .dl-step:focus-visible, .dl-heard:focus-visible, .dl-words-more summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dl-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; font-size: 11.5px; color: var(--text2); }
.dl-keybtn { margin-left: auto; height: 24px; padding: 0 8px; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--font); cursor: pointer; white-space: nowrap; }
.dl-keybtn[aria-expanded="true"] { color: var(--text); background: var(--surface2); }
.dl-keybtn:focus-visible, .dl-moreb:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The how-to line, always on the picture (the feel's caption pattern): what drags, which way, what plays. */
.dl-cap { margin: 0 0 4px; display: flex; flex-wrap: wrap; gap: 2px 14px; font-size: 11.5px; line-height: 1.4; color: var(--text2); }
.dl-cap b { color: var(--text); font-weight: 600; }
.dl-cap span { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.dl-cap .dl-short, .dl.dl-compact .dl-cap .dl-long { display: none; }
.dl.dl-compact .dl-cap .dl-short { display: inline; }
.dl.dl-compact .dl-cap { gap: 0 10px; }
.dl-cap .g { display: inline-block; margin-left: 4px; background: var(--fader-cap); border: 1px solid var(--fader-cap-3); border-radius: 2px; }
.dl-cap .g.bar { width: 5px; height: 11px; }
.dl-cap .g.wide { width: 11px; height: 5px; }
.dl-cap .g.puck { width: 10px; height: 10px; border-radius: 50%; background: var(--display); border: 2px solid var(--fader-cap); }
.dl-cap .g.ring { width: 8px; height: 8px; border-radius: 50%; background: var(--display); border: 2px solid var(--fader-cap); }
/* The key and the measurement's conditions: over the picture, so opening it moves nothing. */
.dl-key { position: absolute; left: 12px; right: 12px; z-index: 4; padding: 10px 12px; background: var(--surface); border: 1px solid var(--border2); border-radius: var(--radius-sm); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); font-size: 12px; color: var(--text2); max-height: 70%; overflow-y: auto; }
.dl-key[hidden] { display: none; }
.dl-key-legend { display: none; margin-bottom: 4px; }
.dl.dl-compact .dl-key-legend { display: flex; }
.dl.dl-compact .dl-head > .dl-legend { display: none; }
.dl.dl-compact .dl-win { display: none; }
.dl.dl-compact .dl-heard { height: calc(2 * 1.45em); -webkit-line-clamp: 2; }
.dl-moreb { position: sticky; bottom: 6px; align-self: flex-end; margin: -30px 6px 0 0; z-index: 3; height: 24px; padding: 0 10px; border-radius: 12px; border: 1px solid var(--border2); background: var(--surface2); color: var(--text); font: 600 11.5px var(--font); cursor: pointer; }
.dl-moreb[hidden] { display: none; }
.dl-k { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.dl-k i { display: inline-block; width: 12px; height: 3px; border-radius: 1px; }
.dl-k i.lv { background: var(--dl-level); height: 2px; }
.dl-k i.tn { background: var(--dl-tone); height: 2px; }
.dl-k i.held { background: rgba(var(--dl-lamp-rgb), 0.95); }
.dl-k i.away { background: rgba(var(--dl-lamp-rgb), 0.6); }
.dl-k i.cut { background: var(--dl-cut); }
.dl-k i.surp { background: var(--dl-surp); height: 5px; }
.dl-k i.rest { background: transparent; border: 1px solid rgba(var(--dl-lamp-rgb), 0.32); height: 5px; }
.dl-pic { position: relative; min-width: 0; }
.dl-pic canvas { display: block; touch-action: pan-y pinch-zoom; }
.dl-pic canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dl-lines { min-width: 0; }
.dl:not(.dl-narrow) .dl-lines { position: absolute; }
.dl-win { margin: 6px 0 0; height: 18px; overflow: hidden; font-size: 11.5px; line-height: 18px; color: var(--text2); white-space: nowrap; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.dl-heard { margin: 4px 0 0; height: calc(2 * 1.45em); overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; font-size: 12px; line-height: 1.45; color: var(--text2); font-variant-numeric: tabular-nums; }
.dl-heard b { color: var(--text); font-weight: 600; }
.dl-idle { opacity: 0.75; }
.dl.dl-narrow:not(.dl-compact) .dl-win { height: 36px; white-space: normal; }
.dl.dl-narrow:not(.dl-compact) .dl-heard { height: calc(3 * 1.45em); -webkit-line-clamp: 3; }
.dl-words-more summary { cursor: pointer; font-weight: 600; width: max-content; max-width: 100%; }
.dl-words-more summary:hover { color: var(--text); }
.dl-cond { margin: 6px 0 0; font-size: 11.5px; line-height: 1.45; }
.dl-cond b { color: var(--text); font-weight: 600; }
.dl-cond kbd { font-family: var(--mono); font-size: 11px; color: var(--text); border: 1px solid var(--border2); border-radius: 3px; padding: 0 4px; }
/* A grip on the picture: a real slider placed over the canvas. Its ridges lie across its drag: horizontal with a
   mouse (it drags up and down), vertical on a touch screen (every grip drags sideways there, lesson 1). */
.dl-grip { position: absolute; left: 0; top: 0; width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%; background: var(--display); border: 2px solid var(--fader-cap); box-shadow: var(--dl-shadow); cursor: grab; touch-action: none; }
.dl-grip::before { content: ""; position: absolute; inset: -6px; }
.dl-grip:hover { border-color: var(--accent2); }
.dl-grip.is-drag { border-color: var(--accent); cursor: grabbing; }
.dl-grip:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.dl-grip.is-linked { box-shadow: 0 0 0 3px var(--accent), var(--dl-shadow); }
.dl-grip.dl-bar { width: 12px; height: 26px; margin: -13px 0 0 -6px; border-radius: 3px; background: var(--fader-cap); border: 1px solid var(--fader-cap-3); }
.dl-grip.dl-bar::after { content: ""; position: absolute; left: 3px; right: 3px; top: 50%; height: 1px; background: var(--fader-ridge); box-shadow: 0 -4px 0 var(--fader-ridge), 0 4px 0 var(--fader-ridge); }
.dl-grip.dl-wide { width: 26px; height: 12px; margin: -6px 0 0 -13px; border-radius: 3px; background: var(--fader-cap); border: 1px solid var(--fader-cap-3); }
.dl-grip.dl-wide::after { content: ""; position: absolute; left: 7px; right: 7px; top: 50%; height: 1px; margin-top: -0.5px; background: var(--fader-ridge); box-shadow: 0 -3px 0 var(--fader-ridge), 0 3px 0 var(--fader-ridge); }
.dl-grip.dl-bar:hover, .dl-grip.dl-bar.is-drag, .dl-grip.dl-wide:hover, .dl-grip.dl-wide.is-drag { border-color: var(--accent); }
.dl-grip.dl-puck { width: 22px; height: 22px; margin: -11px 0 0 -11px; border-width: 2.5px; }
.dl-chev { display: none; }
@media (pointer: coarse) {
  .dl-grip { width: 28px; height: 28px; margin: -14px 0 0 -14px; }
  .dl-grip.dl-puck { width: 32px; height: 32px; margin: -16px 0 0 -16px; }
  /* every hit area at least 44 × 44 (FRONTEND_DESIGN_STANDARD §1.7): 28 + 2·8, 32 + 2·6, 12 × 26 + 2·(16, 9), 26 × 12 + 2·(9, 16) */
  .dl-grip::before { inset: -8px; }
  .dl-grip.dl-puck::before { inset: -6px; }
  .dl-grip.dl-bar::before { inset: -9px -16px; }
  .dl-grip.dl-wide::before { inset: -16px -9px; }
  .dl-grip.dl-bar::after { left: 50%; right: auto; width: 1px; top: 7px; bottom: 7px; height: auto; margin: 0 0 0 -0.5px; box-shadow: -3px 0 0 var(--fader-ridge), 3px 0 0 var(--fader-ridge); }
  .dl-grip.dl-wide::after { left: 50%; right: auto; width: 1px; top: 3px; bottom: 3px; height: auto; margin: 0; box-shadow: -4px 0 0 var(--fader-ridge), 4px 0 0 var(--fader-ridge); }
  .dl-chev { display: block; position: absolute; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none; }
  .dl-chev i { position: absolute; top: -9px; font-style: normal; }
  .dl-chev i::after { font: 700 13px/18px var(--font); color: var(--accent2); }
  .dl-chev i:first-child { right: 14px; }
  .dl-chev i:last-child { left: 14px; }
  .dl-grip.dl-bar .dl-chev i:first-child { right: 9px; }
  .dl-grip.dl-bar .dl-chev i:last-child { left: 9px; }
  .dl-chev i:first-child::after { content: "↙"; }
  .dl-chev i:last-child::after { content: "↗"; }
}
.dl-step { position: absolute; left: 0; top: 0; display: grid; place-items: center; padding: 0; font: 600 18px/1 var(--font); color: var(--text); background: var(--surface2); border: 1px solid var(--border2); border-radius: 6px; cursor: pointer; }
.dl-step:hover { border-color: var(--accent); }
.dl-step[aria-disabled="true"] { color: var(--text3); border-color: transparent; cursor: default; }
.dl-step[hidden] { display: none; }
/* The inspector's groups, in the ladder's words; a group lights with its grips, and the other way round. */
.dl-group, .dl-does-box { border-radius: var(--radius-sm); transition: background 150ms ease; }
.dl-group.dl-lit { background: var(--surface2); }
.dl-group-head { margin: 8px 0 2px; font-size: 0.68rem; font-weight: 650; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text2); }
.dl-group.dl-lit .dl-group-head { color: var(--text); }
.dl-does { border-collapse: collapse; width: 100%; max-width: 100%; font-size: 12.5px; color: var(--text); font-variant-numeric: tabular-nums; margin-top: 2px; }
.dl-does th, .dl-does td { padding: 3px 12px 3px 0; text-align: left; font-weight: 400; white-space: nowrap; vertical-align: baseline; line-height: 1.35; }
.dl-does td:last-child, .dl-does th:last-child { padding-right: 0; }
.dl-does td:nth-child(2), .dl-does thead th:nth-child(2) { text-align: right; }
.dl-does td:nth-child(3), .dl-does thead th:nth-child(3) { padding-left: 12px; }
.dl-does thead th { font-size: 10.5px; color: var(--text2); letter-spacing: 0.04em; padding-bottom: 4px; border-bottom: 1px solid var(--border); }
.dl-does tbody th { color: var(--text2); }
.dl-does tr.is-quiet td { color: var(--text2); }
.dl-does.dl-two tbody tr:nth-child(2) td:last-child, .dl-does.dl-two tbody tr:nth-child(3) td:last-child { white-space: normal; height: calc(2 * 1.35em + 6px); }
.dl-does.dl-two tbody tr:nth-child(2) > *, .dl-does.dl-two tbody tr:nth-child(3) > * { vertical-align: top; }
.dl-words-more { margin-top: 4px; font-size: 12px; color: var(--text2); }
.dl-words { margin: 4px 0 0; font-size: 12px; line-height: 1.5; }
.dl-words b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) { .dl-group, .dl-does-box { transition: none; } }


/* ── Compose · Percussion · the phrase wheel (percussion-wheel.js; UI overhaul 2 Stage C, D-16) ─────────────────── */
.m2-perc { flex: 1; min-height: 0; min-width: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: auto; overflow-anchor: none; }
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  /* on a phone the page scrolls, not the display (no nested scroller: HARM-6 N2) */
  .macro2-workspace-mode .m2-display:has(.m2-perc) { height: auto; }
  .m2-perc { overflow: visible; }
  html:has(.m2-perc) { overflow-anchor: none; }
}
/* Lesson 9 (REVIEW-PERC-BUILD-1 M1): on a phone the studio's page scrolls, and a tap that re-renders it (a group's
   Reset) must leave it where it was. The browser's scroll anchoring moved it 18–19 px after the re-render on the
   Melody, Harmony and Duration rails (the ladder and the wheel already opted out), so the studio opts out whole. */
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  html:has(#m2Display) { overflow-anchor: none; }
}
@media (pointer: coarse) { :root { --pw-hit: 44px; } }
.pw { position: relative; display: flex; flex-direction: column; background: var(--display); min-width: 0; }
.pw > * { flex: none; }   /* the display scrolls; its lines never shrink into each other */
.pw-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.pw-head { display: flex; align-items: center; gap: 8px 14px; padding: 8px 12px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.pw-switch { display: inline-flex; align-items: center; gap: 7px; height: 26px; padding: 0 2px; background: none; border: 0; color: var(--text2); font: 12px var(--font); cursor: pointer; white-space: nowrap; }
.pw-switch i { position: relative; width: 26px; height: 14px; border-radius: 7px; background: var(--surface2); border: 1px solid var(--border2); flex: none; }
.pw-switch i::after { content: ""; position: absolute; top: 2px; left: 2px; width: 8px; height: 8px; border-radius: 50%; background: var(--text3); transition: left 150ms ease; }
.pw-switch[aria-checked="true"], .pw-switch[aria-pressed="true"] { color: var(--text); }
.pw-switch[aria-checked="true"] i, .pw-switch[aria-pressed="true"] i { border-color: var(--text2); }
.pw-switch[aria-checked="true"] i::after, .pw-switch[aria-pressed="true"] i::after { left: 14px; background: var(--text); }
/* lesson 9: the count has a fixed box, so re-wording it never re-wraps the head */
.pw-count { flex: 1 1 0; min-width: 10em; height: 2.7em; display: flex; align-items: center; font-size: 12px; line-height: 1.35; color: var(--text2); font-variant-numeric: tabular-nums; }
.pw-keybtn { height: 24px; padding: 0 8px; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--font); cursor: pointer; white-space: nowrap; }
.pw-keybtn[aria-expanded="true"] { color: var(--text); background: var(--surface2); }
.pw-switch:focus-visible, .pw-keybtn:focus-visible, .pw-more:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
/* the picture: how to read it, then the wheel */
.pw-pic { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 8px; padding: 10px 12px 0; align-items: center; min-width: 0; }
.pw.pw-narrow .pw-pic { grid-template-columns: minmax(0, 1fr); }
.pw-read { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.pw-read li, .pw-key-read li { display: grid; align-content: start; grid-template-columns: 22px 1fr; column-gap: 8px; row-gap: 1px; }
.pw-read b, .pw-key-read b { grid-column: 2; grid-row: 1; font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text); font-weight: 650; line-height: 16px; }
.pw-read span:not(.pw-rg), .pw-key-read span:not(.pw-rg) { grid-column: 2; grid-row: 2; font-size: 11.5px; color: var(--text2); line-height: 1.45; }
.pw-rg { grid-column: 1; grid-row: 1 / span 2; width: 18px; height: 18px; position: relative; display: block; }
.pw-rg.turn { border-radius: 50%; border: 1.5px solid var(--pw-track); border-top-color: var(--pw-seam); }
.pw-rg.turn::after { content: ""; position: absolute; right: -1px; top: 1px; border: 3.5px solid transparent; border-left-color: var(--pw-seam); transform: rotate(40deg); }
.pw-rg.ring { border-radius: 50%; box-shadow: inset 0 0 0 1.5px hsl(32 70% 58% / 0.75); }
.pw-rg.dot i { position: absolute; border-radius: 50%; background: hsl(32 70% 58%); }
.pw-rg.dot i:first-child { width: 6px; height: 6px; left: 1px; top: 8px; }
.pw-rg.dot i:last-child { width: 11px; height: 11px; left: 7px; top: 3px; }
.pw-rg.knob::after { content: ""; position: absolute; left: 3px; top: 3px; width: 12px; height: 12px; border-radius: 50%; background: hsl(32 70% 58%); box-shadow: 0 0 0 2px var(--knob-ring), 0 0 0 3px var(--text2); }
/* narrow boxed (compact desktop, 1024): the reading moves into the Key panel; on a phone it sits under the wheel */
.pw.pw-compact .pw-read { display: none; }
.pw.pw-phone .pw-read { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px; order: 2; padding: 6px 0 2px; }
.pw.pw-phone .pw-read span:not(.pw-rg) { font-size: 11px; }
.pw-wheel { min-width: 0; display: flex; justify-content: center; }
.pw-wheel canvas { display: block; max-width: 100%; touch-action: pan-y; -webkit-tap-highlight-color: transparent; border-radius: 4px; }
.pw-wheel canvas:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
/* the one-line how-to on the picture */
.pw-cap { margin: 0; padding: 6px 12px 0; display: flex; flex-wrap: wrap; gap: 2px 16px; font-size: 11.5px; line-height: 1.45; color: var(--text2); }
.pw-cap b { color: var(--text); font-weight: 600; }
.pw:not(.pw-narrow) .pw-cap { flex-wrap: nowrap; height: calc(1.45em + 6px); overflow: hidden; }   /* one line: the marks that come and go never re-wrap it */
.pw-cap .gap { display: inline-block; width: 16px; height: 0; border-top: 2px dotted var(--hue-c, var(--text2)); margin: 0 3px; vertical-align: 3px; }
.pw-cap .hand { display: inline-block; width: 2px; height: 12px; background: rgb(var(--land-light)); border-radius: 1px; margin: 0 3px; vertical-align: -1px; }
.pw-cap-x { color: var(--text2); }
.pw-cap span { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.pw-cap .k, .pw-key .k { display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: var(--hue-c, var(--text2)); box-shadow: 0 0 0 2px var(--knob-ring), 0 0 0 3px var(--text2); margin: 0 7px 0 5px; vertical-align: -1px; }
.pw-cap .k.parked { background: transparent; box-shadow: none; border: 1.5px dashed var(--hue-c); width: 12px; height: 12px; }
.pw-key .d { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--hue-c, var(--text2)); margin: 0 3px; }
.pw-key .gap { display: inline-block; width: 16px; height: 0; border-top: 2px dotted var(--hue-c, var(--text2)); margin: 0 3px; vertical-align: 3px; }
.pw-key .hand { display: inline-block; width: 2px; height: 12px; background: rgb(var(--land-light)); border-radius: 1px; margin: 0 3px; vertical-align: -1px; }
.pw-key kbd { font: 11px var(--mono); color: var(--text); border: 1px solid var(--border2); border-radius: 3px; padding: 0 4px; }
/* fixed-height lines: a tap never moves the layout (lesson 9) */
.pw-status { margin: 0; padding: 8px 12px 0; height: calc(2 * 1.45em + 8px); overflow: hidden; font-size: 12px; line-height: 1.45; color: var(--text2); font-variant-numeric: tabular-nums; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.pw-heard { margin: 0; padding: 4px 12px 10px; height: calc(2 * 1.45em + 14px); overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; font-size: 12px; line-height: 1.45; color: var(--text2); font-variant-numeric: tabular-nums; }
.pw-status b, .pw-heard b { color: var(--text); font-weight: 600; }
.pw-heard .dim { color: var(--text3); }
.pw.pw-phone .pw-status { height: calc(3 * 1.45em + 8px); -webkit-line-clamp: 3; }
.pw.pw-phone .pw-heard { height: calc(3 * 1.45em + 14px); -webkit-line-clamp: 3; }
/* compact desktop (1024): the how-to on one line and the head in one row, so the wheel keeps its room */
.pw.pw-compact .pw-cap { flex-wrap: nowrap; gap: 0 12px; font-size: 11px; overflow: hidden; }
.pw.pw-compact .pw-count { min-width: 0; }
.pw.pw-compact .pw-head { flex-wrap: nowrap; }
/* a phone: On, Kit alone and Key in one row, the count under them in its own fixed box */
.pw.pw-phone .pw-count { order: 5; flex: 1 1 100%; height: 1.4em; }
.pw.pw-phone .pw-keybtn { margin-left: auto; }
/* the key folds into "Key ▸" and opens OVER the picture, so opening it moves nothing (lesson 9) */
.pw-key { position: absolute; top: 46px; right: 8px; z-index: 6; max-width: min(480px, calc(100% - 16px)); display: flex; flex-direction: column; align-items: flex-start; gap: 7px; padding: 10px 12px; background: var(--surface); border: 1px solid var(--border2); border-radius: var(--radius-sm); box-shadow: var(--elev-float); font-size: 11.5px; line-height: 1.45; color: var(--text2); }
.pw-key[hidden] { display: none; }
.pw-key span { display: block; }
.pw-key b { color: var(--text); font-weight: 600; }
.pw-key-read { list-style: none; margin: 0 0 2px; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 8px 14px; }
.pw:not(.pw-compact) .pw-key-read { display: none; }
.pw-more { position: sticky; bottom: 0; align-self: stretch; height: 26px; border: 0; border-top: 1px solid var(--border); background: linear-gradient(to bottom, transparent, var(--display) 40%); color: var(--text2); font: 11.5px var(--font); cursor: pointer; }
.pw-more[hidden] { display: none; }

/* the inspector's column while the wheel shows: grouped by the wheel's parts (the feel's and harmony's language) */
.pw-panel { display: flex; flex-direction: column; overflow-anchor: none; }
.pw-ph { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin: 10px 0 8px; }
.pw-ph b { font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text2); font-weight: 650; }
.pw-ph span { font-size: 11px; color: var(--text3); }
.pw-panel .pw-grp { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--mls-section); padding: 8px 10px 9px; margin: 0 0 8px; transition: border-color 150ms ease; }
.pw-panel .pw-grp.lit { border-color: var(--text); }
.pw-panel .ins-group.pw-grp:first-of-type { border-top: 1px solid var(--border); }
.pw-h4 { display: flex; justify-content: space-between; align-items: center; gap: 8px; min-height: 24px; margin: 0 0 6px; font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text); font-weight: 650; }
.pw-h4 > span { display: inline-flex; align-items: center; }
.pw-h4 small { letter-spacing: 0; text-transform: none; font-weight: 400; color: var(--text3); font-size: 11px; }
.pw-g { display: inline-block; position: relative; width: 11px; height: 11px; margin: 0 8px 0 1px; flex: none; }
.pw-g.ring { border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--text2); }
.pw-g.ring.hue { width: 14px; height: 14px; box-shadow: inset 0 0 0 2px hsl(var(--hue) 70% 58%); }
.pw-g.knob { width: 9px; height: 9px; border-radius: 50%; background: hsl(var(--hue, 32) 70% 58%); box-shadow: 0 0 0 2px var(--knob-ring), 0 0 0 3px var(--text2); margin-left: 2px; margin-right: 9px; }
.pw-g.dots i { position: absolute; border-radius: 50%; background: hsl(var(--hue, 32) 70% 58%); }
.pw-g.dots i:first-child { width: 4px; height: 4px; left: 0; top: 5px; }
.pw-g.dots i:last-child { width: 8px; height: 8px; left: 5px; top: 1px; }
.pw-sub { margin: -2px 0 6px; font-size: 11px; color: var(--text3); line-height: 1.45; }
.pw-hits { display: flex; flex-direction: column; gap: 4px; }
.pw-hit { display: grid; grid-template-columns: 14px minmax(0, 1fr) auto; align-items: center; gap: 8px; height: 30px; padding: 0 8px; border-radius: var(--radius-sm); border: 1px solid transparent; background: transparent; color: var(--text2); font: 12px var(--font); cursor: pointer; text-align: left; width: 100%; }
.pw-hit i { width: 12px; height: 12px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px hsl(var(--hue) 70% 58%); position: relative; }
.pw-hit i::after { content: ""; position: absolute; left: 3.5px; top: 3.5px; width: 5px; height: 5px; border-radius: 50%; background: hsl(var(--hue) 70% 58%); }
.pw-hit.silent i::after { background: transparent; box-shadow: inset 0 0 0 1px hsl(var(--hue) 70% 58%); }
.pw-hit-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.pw-hit small { font: 11px var(--mono); color: var(--text3); white-space: nowrap; }
.pw-hit:hover, .pw-hit.lit { background: var(--surface2); }
.pw-hit[aria-pressed="true"] { border-color: hsl(var(--hue) 70% 58% / 0.7); background: var(--surface2); }
.pw-hit[aria-pressed="true"] small { color: var(--text2); }
.pw-hit-undo { grid-template-columns: 1fr; border: 1px dashed var(--border2); justify-items: center; }
.pw-hit-undo:hover { border-color: var(--accent); }
.pw-hit-gone { grid-template-columns: 1fr; border: 1px dashed var(--border); cursor: default; justify-items: center; }
.pw-hit-gone .pw-hit-t { color: var(--text3); }
.pw-hit-gone:hover { background: transparent; }
/* lesson 9: the kit's Reset arrives beside the title, never at the end of the row, so "+ Add hit" stays under the finger */
.pw-rings > .pw-h4 > span { order: 0; }
.pw-rings > .pw-h4 > .group-reset { order: 1; margin-right: auto; }
.pw-add { order: 2; height: 24px; padding: 0 8px; border-radius: var(--radius-sm); border: 1px dashed var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--font); letter-spacing: 0; text-transform: none; cursor: pointer; flex: none; margin-left: auto; }
.pw-add:hover { color: var(--text); border-color: var(--accent); }
.pw-who { display: flex; align-items: center; gap: 8px; margin: 4px 0 8px; padding: 0 2px; }
.pw-who-t { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.pw-who-t small { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text3); font-weight: 650; }
.pw-who-t b { font-size: 13px; font-weight: 650; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pw-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: var(--control-h); padding: 0 10px; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: var(--surface2); color: var(--text); font: 12px var(--font); cursor: pointer; white-space: nowrap; flex: none; letter-spacing: 0; text-transform: none; }
.pw-btn svg { width: 11px; height: 11px; flex: none; }
.pw-btn:hover:not(:disabled) { border-color: var(--text3); }
.pw-btn:disabled { color: var(--text3); background: transparent; border-color: var(--border); cursor: default; }
.pw-btn.pw-sm { height: 24px; padding: 0 8px; font-size: 11.5px; }
.pw-rm { width: 6.5em; }   /* Remove and Restore share one width: the swap never moves Hear beside them */
.pw-restore { border-color: var(--accent); }
.pw-side.ghost .pw-grp { opacity: 0.5; }
.pw-seg { display: flex; border: 1px solid var(--border2); border-radius: var(--radius-sm); overflow: hidden; margin-bottom: 6px; }
.pw-seg button { flex: 1 1 0; min-width: 0; height: 26px; border: 0; border-left: 1px solid var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--font); cursor: pointer; white-space: nowrap; }
.pw-seg button:first-child { border-left: 0; }
.pw-seg button[aria-checked="true"] { background: var(--surface2); color: var(--text); box-shadow: inset 0 -2px 0 hsl(var(--hue, 32) 70% 58%); }
.pw-seg button:disabled { color: var(--text3); cursor: default; }
.pw-row { display: grid; grid-template-columns: minmax(0, 1fr) 62px; align-items: center; gap: 8px; min-height: 30px; font-size: 12px; color: var(--text2); }
.pw-row.pw-lab { min-height: 18px; grid-template-columns: 1fr; font-size: 11.5px; }
.pw-in { width: 62px; height: var(--control-h); background: var(--control-bg); border: 1px solid var(--control-border); border-radius: var(--radius-sm); color: var(--text); font: 12px var(--mono); font-variant-numeric: tabular-nums; text-align: right; padding: 0 6px; }
.pw-in:disabled { color: var(--text3); background: transparent; }
.pw-snd { margin-bottom: 4px; }
.pw-says { margin: 4px 0 0; font-size: 11.5px; line-height: 1.45; color: var(--text2); min-height: calc(2 * 1.45em); }
.pw-says.pw-1 { min-height: 1.45em; }
.pw-says.pw-3 { min-height: calc(3 * 1.45em); }
.pw-says b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.pw-foot { margin: 6px 2px 0; font-size: 11px; color: var(--text3); line-height: 1.45; }
.pw-hit:focus-visible, .pw-add:focus-visible, .pw-btn:focus-visible, .pw-seg button:focus-visible, .pw-in:focus-visible, .pw-rail:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
/* the house rail with the house knob (feel, harmony, how loud) */
.pw-rail { position: relative; height: var(--pw-hit); cursor: pointer; touch-action: pan-y; -webkit-tap-highlight-color: transparent; --t: 0; --f0: 0; --f1: 0; }
.pw-rail s { position: absolute; left: 7px; right: 7px; top: calc(50% - 1px); height: 2px; background: var(--border2); border-radius: 1px; }
.pw-rail em { position: absolute; top: calc(50% - 1px); height: 2px; left: calc(7px + (100% - 14px) * var(--f0)); width: calc((100% - 14px) * (var(--f1) - var(--f0))); background: hsl(var(--hue, 32) 70% 58%); border-radius: 1px; }
.pw-rail u { position: absolute; top: calc(50% - 6px); left: calc(7px + (100% - 14px) * var(--t) - 6px); width: 12px; height: 12px; border-radius: 50%; background: hsl(var(--hue, 32) 70% 58%); box-shadow: 0 0 0 2px var(--knob-ring); transition: box-shadow 120ms ease; }
.pw-rail:hover u, .pw-rail[data-drag="true"] u { box-shadow: 0 0 0 2px var(--knob-ring), 0 0 0 4px var(--text); }
.pw-grp:not([style*="--hue"]) .pw-rail u, .pw-grp:not([style*="--hue"]) .pw-rail em { background: rgb(var(--land-light)); }
.pw-grp .pw-rail[aria-disabled="true"] { cursor: default; }
.pw-grp .pw-rail[aria-disabled="true"] u { background: var(--surface2); box-shadow: 0 0 0 2px var(--knob-ring), inset 0 0 0 1px var(--border2); }
.pw-grp .pw-rail[aria-disabled="true"] em { background: transparent; }
.pw-grp .pw-rail[aria-disabled="true"]:hover u { box-shadow: 0 0 0 2px var(--knob-ring), inset 0 0 0 1px var(--border2); }
@media (pointer: coarse) {
  .pw-switch, .pw-keybtn, .pw-hit, .pw-add, .pw-btn, .pw-btn.pw-sm, .pw-seg button, .pw-more { min-height: 44px; }
  .pw-hit { height: 44px; }
  .pw-in { height: 44px; }
  .pw-snd .smart-combo-btn { min-height: 44px; }   /* the studio's sound picker, full size under a finger (review S2) */
}
@media (prefers-reduced-motion: reduce) { .pw-switch i::after, .pw-panel .pw-grp, .pw-rail u { transition: none; } }


/* ── Compose · Rhythm · where notes fall: the dice (fall-dice.js; UI overhaul 2 Stage C, D-16, D-17) ──────────── */
.m2-dice { flex: 1; min-height: 0; min-width: 0; position: relative; overflow-y: auto; overflow-x: hidden; overscroll-behavior: auto; overflow-anchor: none; }
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  /* on a phone the page scrolls, not the display (no nested scroller: HARM-6 N2) */
  .macro2-workspace-mode .m2-display:has(.m2-dice) { height: auto; }
  .m2-dice { overflow: visible; }
  html:has(.m2-dice) { overflow-anchor: none; }
}
@media (pointer: coarse) { :root { --fd-hit: 44px; } }
.fd { display: flex; flex-direction: column; background: var(--display); min-width: 0; }
.fd > * { flex: none; }
.fd-body { display: flex; flex-direction: column; gap: 6px; padding: 0 12px 2px; min-width: 0; }
.fd-body > * { flex: none; min-width: 0; }
.fd-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.fd-head { display: flex; align-items: center; gap: 6px 12px; padding: 8px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.fd-phl { font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text3); font-weight: 650; }
.fd-tabs { display: inline-flex; border: 1px solid var(--border2); border-radius: var(--radius-sm); overflow: hidden; }
.fd-tabs button { min-width: 28px; height: 24px; border: 0; border-left: 1px solid var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--mono); cursor: pointer; }
.fd-tabs button:first-child { border-left: 0; }
.fd-tabs button[aria-selected="true"] { background: var(--surface2); color: var(--text); }
/* the how-to line: wraps, never clips (review PERC-BUILD-1 M4) */
.fd-cap { flex: 1 1 260px; margin: 0; display: flex; flex-wrap: wrap; gap: 0 14px; font-size: 11.5px; line-height: 1.45; color: var(--text2); }
.fd-cap span { white-space: nowrap; }
.fd-cap b { color: var(--text); font-weight: 600; }
.fd-cap-k { color: var(--text3); }
.fd-keybtn { margin-left: auto; height: 24px; padding: 0 8px; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--font); cursor: pointer; white-space: nowrap; }
.fd-keybtn[aria-expanded="true"] { color: var(--text); background: var(--surface2); }
.fd-tabs button:focus-visible, .fd-keybtn:focus-visible, .fd-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (pointer: coarse) { .fd-tabs button { min-width: 44px; height: 44px; } .fd-keybtn { height: 44px; padding: 0 12px; } }
/* the key opens OVER the picture, so opening it moves nothing (lesson 9) */
.fd-key { position: absolute; top: 44px; right: 8px; z-index: 6; max-width: min(520px, calc(100% - 16px)); display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; background: var(--surface); border: 1px solid var(--border2); border-radius: var(--radius-sm); box-shadow: var(--elev-float); font-size: 11.5px; line-height: 1.5; color: var(--text2); }
.fd-key[hidden] { display: none; }
.fd-key b { color: var(--text); font-weight: 600; }
.fd-key kbd { font: 11px var(--mono); color: var(--text); border: 1px solid var(--border2); border-radius: 3px; padding: 0 4px; }
.fd-dim { color: var(--text3); }
.fd-k { display: inline-block; vertical-align: -1px; margin: 0 5px 0 2px; }
.fd-k.die { width: 8px; height: 8px; border-radius: 50%; background: rgb(var(--land-light)); }
.fd-k.die.o { background: transparent; box-shadow: inset 0 0 0 1.25px var(--text2); }
.fd-k.ln { width: 14px; height: 2px; vertical-align: 3px; background: var(--fd-line); }
.fd-k.raise { width: 10px; height: 10px; background: rgba(var(--fd-repeat-rgb), 0.34); box-shadow: inset 0 2px 0 rgb(var(--fd-repeat-rgb)); }
.fd-k.note { width: 16px; height: 8px; border-radius: 1px; background: rgba(var(--land-light), 0.82); }
.fd-k.note.s { background: transparent; box-shadow: inset 0 0 0 1px rgba(var(--land-light), 0.32); }   /* How loud's rest mark */
/* the three parts: bounded, numbered, captioned */
.fd-part { position: relative; background: var(--mls-section); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 7px 10px 8px; transition: border-color 150ms ease; }
.fd-part.lit { border-color: var(--border2); }
.fd-ph { display: flex; align-items: center; gap: 4px 10px; flex-wrap: nowrap; min-height: 22px; min-width: 0; }
.fd-n { flex: none; font: 600 10px/1 var(--mono); color: var(--text3); border: 1px solid var(--border2); border-radius: 3px; padding: 3px 5px; }
.fd-kind { flex: none; font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text2); font-weight: 650; }
.fd-ph > b { flex: none; font-size: 12.5px; font-weight: 600; color: var(--text); white-space: nowrap; }
.fd-end { margin-left: auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--text3); font-variant-numeric: tabular-nums; }
.fd-end b { color: var(--text2); font-weight: 600; }
.fd-say { margin: 2px 0 4px; font-size: 11.5px; line-height: 1.45; color: var(--text2); }
.fd.fd-short .fd-say { display: none; }   /* a short display drops the captions first (they are in Key ▸ and the description) */
/* compact (1024 × 768): each part's head is drawn in its canvas, the frames tighten, the marker's words shorten */
.fd.fd-compact .fd-ph { display: none; }
.fd.fd-compact .fd-part { padding: 4px 8px 5px; }
.fd.fd-compact .fd-cv { margin-top: 0; }
/* compact: the marker keeps its name ("Repeats" where a display is narrow) and its reach; only "of notes after a
   phrase's first" goes, and the readout sits a clear 12 px from the track's cell (review DICE-BUILD-1 M1) */
.fd.fd-compact .fd-rep { grid-template-columns: auto minmax(80px, 260px) auto; justify-content: start; margin-top: 2px; padding-top: 2px; }
.fd.fd-compact .fd-rep-rd { grid-column: auto; white-space: nowrap; }
.fd.fd-compact .fd-rep-of { display: none; }
.fd.fd-compact .fd-status { height: calc(2 * 1.45em + 4px); padding-bottom: 4px; }   /* compact: two lines; the status picks a form that fits (review DICE-BUILD-1 S2: the height goes to the plots) */
.fd.fd-compact .fd-body { gap: 4px; }
.fd.fd-compact .fd-head { padding: 6px 0; }
.fd-cv { position: relative; margin-top: 4px; }
.fd-cv canvas { display: block; max-width: 100%; touch-action: pan-y; -webkit-tap-highlight-color: transparent; }
.fd-cv canvas:focus-visible, .fd-rep-cv:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* the knobs: real buttons over the canvas; the house knob in the hue of what it moves */
.fd-knob { position: absolute; width: var(--fd-hit); height: var(--fd-hit); margin: 0; padding: 0; transform: translate(-50%, -50%); border: 0; background: transparent; cursor: ns-resize; touch-action: pan-y; display: grid; place-items: center; border-radius: 50%; -webkit-tap-highlight-color: transparent; z-index: 1; }
.fd-knob::after { content: ""; width: 13px; height: 13px; border-radius: 50%; background: rgb(var(--land-light)); box-shadow: 0 0 0 2px var(--knob-ring); transition: transform 120ms ease, box-shadow 120ms ease; }
.fd-knob.rest::after { background: rgb(var(--fd-rest-rgb)); }
.fd-knob:hover::after, .fd-knob.lit::after, .fd-knob[data-drag="true"]::after { transform: scale(1.2); box-shadow: 0 0 0 2px var(--knob-ring), 0 0 0 4px var(--text); }
.fd-knob:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.fd-knob:focus-visible::after, .fd-knob.lit:focus-visible::after { transform: scale(1.18); box-shadow: 0 0 0 2px var(--knob-ring); }   /* one ring on keyboard focus */
.fd-knob[hidden] { display: none; }
@media (pointer: coarse) { .fd-knob { cursor: ew-resize; } }
/* the repeat marker (option C's), under what phrase 1 wrote */
.fd-rep { display: grid; grid-template-columns: auto minmax(120px, 260px) minmax(0, 1fr); align-items: center; gap: 2px 12px; margin-top: 4px; padding-top: 4px; border-top: 1px dashed var(--border); font-size: 11.5px; color: var(--text2); }
.fd-rep-l { display: inline-flex; align-items: center; gap: 7px; color: var(--text); font-size: 12px; white-space: nowrap; }
.fd-rep-l i { width: 10px; height: 10px; background: rgba(var(--fd-repeat-rgb), 0.34); box-shadow: inset 0 2px 0 rgb(var(--fd-repeat-rgb)); }
.fd-rep-track { min-width: 0; overflow: hidden; }
.fd-rep-short { display: none; }
.fd-rep-cv { display: block; height: 28px; cursor: ew-resize; touch-action: pan-y; border-radius: var(--radius-sm); -webkit-tap-highlight-color: transparent; }
.fd-rep-rd { font-variant-numeric: tabular-nums; min-width: 0; }
.fd-rep-rd b { color: var(--text); font: 600 12px var(--mono); }
@media (pointer: coarse) { .fd-rep-cv { height: 44px; } }
@container (max-width: 560px) {
  .fd-rep { grid-template-columns: auto minmax(0, 1fr); } .fd-rep-rd { grid-column: 1 / -1; }
  .fd.fd-compact .fd-rep { grid-template-columns: auto minmax(0, 1fr) auto; }
  .fd.fd-compact .fd-rep-full { display: none; } .fd.fd-compact .fd-rep-short { display: inline; }
}
.m2-dice { container-type: inline-size; }
/* fixed-height lines: a tap never moves the layout (lesson 9) */
.fd-status { margin: 0; padding: 0 0 6px; height: calc(2 * 1.45em + 6px); overflow: hidden; font-size: 12px; line-height: 1.45; color: var(--text2); font-variant-numeric: tabular-nums; }
.fd-status b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
@container (max-width: 560px) { .fd-status { height: calc(3 * 1.45em + 6px); } }
@container (max-width: 560px) { .fd-cap { order: 3; flex-basis: 100%; } }
@container (max-width: 560px) { .fd-ph { flex-wrap: wrap; } .fd-end { flex-basis: 100%; margin-left: 0; white-space: normal; } }   /* a narrow head puts its count on its own line: never cut */
/* the cue overlays the display's foot: showing it adds no height, so it can never cause itself */
.fd-more { position: sticky; bottom: 0; margin-top: -26px; align-self: stretch; height: 26px; border: 0; border-top: 1px solid var(--border); background: linear-gradient(to bottom, transparent, var(--display) 40%); color: var(--text2); font: 11.5px var(--font); cursor: pointer; }
.fd-more[hidden] { display: none; }
/* the inspector's Generation group, by the dice's parts */
.fdc-group { border-radius: var(--radius-sm); transition: background 150ms ease; }
.fdc-group.fdc-lit { background: var(--surface2); }
.fdc-group-head { margin: 8px 0 2px; font-size: 0.68rem; font-weight: 650; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text2); }
.fdc-group.fdc-lit .fdc-group-head { color: var(--text); }
.fdc-n { font: 600 10px/1 var(--mono); color: var(--text3); border: 1px solid var(--border2); border-radius: 3px; padding: 2px 4px; letter-spacing: 0; }
.fdc-gslot { display: inline-block; width: 16px; height: 14px; margin-right: 6px; vertical-align: -2px; }
.fdc-dot { display: block; width: 9px; height: 9px; margin: 2px 0 0 2px; border-radius: 50%; background: rgb(var(--land-light)); box-shadow: 0 0 0 2px var(--knob-ring); }
.fdc-dot.rest { background: rgb(var(--fd-rest-rgb)); }
.fdc-dot.rep { background: rgb(var(--fd-repeat-rgb)); }
.fdc-says { margin: 2px 0 6px; font-size: 11.5px; line-height: 1.45; color: var(--text2); height: calc(2 * 1.45em); overflow: hidden; }
.fdc-says b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.fdc-sum { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; font-size: 11.5px; color: var(--text2); padding: 2px 0 6px; }
.fdc-v { color: var(--text); text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
#m2Inspector .control-row.fdc-linked { grid-template-columns: minmax(0, 150px) 1fr 64px; }
@media (prefers-reduced-motion: reduce) { .fd-knob::after, .fd-part, .fdc-group { transition: none; } }


/* ── Compose · Rhythm · how notes join: the join rule over its take (join-rule.js; UI overhaul 2 Stage C, D-16) ───────── */
.m2-join { flex: 1; min-height: 0; min-width: 0; position: relative; overflow-y: auto; overflow-x: hidden; overscroll-behavior: auto; overflow-anchor: none; container-type: inline-size; }
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  /* on a phone the page scrolls, not the display (no nested scroller: HARM-6 N2) */
  .macro2-workspace-mode .m2-display:has(.m2-join) { height: auto; }
  .m2-join { overflow: visible; }
  html:has(.m2-join) { overflow-anchor: none; }
}
.jr { display: flex; flex-direction: column; background: var(--display); min-width: 0; }
.jr > * { flex: none; }
.jr-body { display: flex; flex-direction: column; gap: 6px; padding: 0 12px 2px; min-width: 0; }
.jr-body > * { flex: none; min-width: 0; }
.jr-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.jr-head { display: flex; align-items: center; gap: 6px 12px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.jr-how { flex: 1 1 auto; min-width: 0; margin: 0; font-size: 11.5px; line-height: 1.45; color: var(--text2); }
.jr-how b { color: var(--text); font-weight: 600; }
.jr-keybtn { flex: none; margin-left: auto; height: 24px; padding: 0 8px; border-radius: var(--radius-sm); border: 1px solid var(--border2); background: transparent; color: var(--text2); font: 11.5px var(--font); cursor: pointer; white-space: nowrap; }
.jr-keybtn[aria-expanded="true"] { color: var(--text); background: var(--surface2); }
.jr-keybtn:focus-visible, .jr-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (pointer: coarse) { .jr-keybtn { height: 44px; padding: 0 12px; } }
/* Key ▸ opens over the picture: showing it moves nothing */
.jr-keypanel { position: absolute; top: 44px; right: 8px; z-index: 6; max-width: min(560px, calc(100% - 16px)); max-height: calc(100% - 56px); overflow-y: auto; display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; background: var(--surface); border: 1px solid var(--border2); border-radius: var(--radius-sm); box-shadow: var(--elev-float); font-size: 11.5px; line-height: 1.5; color: var(--text2); }
.jr-keypanel[hidden] { display: none; }
.jr-keypanel b { color: var(--text); font-weight: 600; }
.jr-keypanel p { margin: 0 0 4px; }
.jr-keypanel kbd { font: 11px var(--mono); color: var(--text); border: 1px solid var(--border2); border-radius: 3px; padding: 0 4px; }
.jr-dim { color: var(--text3); }
.jr-q::before { content: "Owner question · "; color: var(--accent2); font-weight: 600; }
.jr-cv { position: relative; }
.jr-cv canvas { display: block; max-width: 100%; touch-action: pan-y; -webkit-tap-highlight-color: transparent; border-radius: 4px; }
.jr-cv canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* the key: one row, only the marks drawn; its height reserved (join-rule.js reserveKey) */
.jr-key { display: flex; align-items: center; align-content: flex-start; gap: 4px 14px; flex-wrap: wrap; padding: 4px 0; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--text2); }
.jr-key > span { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; line-height: 18px; }
.jr-key > span[hidden] { display: none; }
.jr-key i { display: inline-block; flex: 0 0 auto; }
.jr-key .dot { width: 7px; height: 7px; border-radius: 50%; }
.jr-key .dot.det { background: var(--text2); }
.jr-key .dot.nat { background: rgb(var(--land-light)); }
.jr-key .dot.sl { background: var(--surp); }
.jr-key .end { width: 8px; height: 8px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--text2); }
.jr-key .br { font: 700 14px/10px var(--font); color: var(--text); font-style: normal; width: 6px; }
.jr-key .half { width: 8px; height: 8px; border-radius: 50%; box-shadow: inset 0 0 0 1.2px rgb(var(--land-light)); background: linear-gradient(90deg, rgb(var(--land-light)) 50%, transparent 50%); }
.jr-key .stk { width: 13px; height: 13px; border-radius: 3px; background: linear-gradient(90deg, rgb(var(--land-light)) 50%, var(--surp) 50%); color: var(--knob-ring); font: 700 8.5px/13px var(--mono); text-align: center; font-style: normal; }
.jr-key .deep { width: 0; height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 7px solid rgb(var(--land-light)); }
.jr-key .tail { width: 13px; height: 8px; background: var(--jr-tail); box-shadow: inset 0 0 0 1px var(--jr-tail-edge); }
.jr-key .crv { width: 14px; height: 2px; border-radius: 1px; background: rgb(var(--land-light)); }
.jr-key .crv.sl { background: var(--surp); }
/* two fixed-height lines: a tap never moves the layout (lesson 9) */
.jr-status { margin: 0; height: calc(3 * 1.45em); overflow: hidden; font-size: 12px; line-height: 1.45; color: var(--text); font-variant-numeric: tabular-nums; }
.jr-status b { font-weight: 600; }
.jr-heard { margin: 0 0 6px; height: calc(2 * 1.45em); overflow: hidden; font-size: 12px; line-height: 1.45; color: var(--text2); font-variant-numeric: tabular-nums; }
.jr-heard b { color: var(--text); font-weight: 600; }
.jr.jr-compact .jr-head { padding: 6px 0; }
.jr.jr-compact .jr-body { gap: 4px; }
.jr.jr-compact .jr-key { display: none; }   /* compact (1024 × 768): the marks are named in Key ▸; the height goes to the plots */
@container (max-width: 560px) {
  .jr-status { height: calc(4 * 1.45em); }
  .jr-heard { height: calc(4 * 1.45em); }
}
.jr-more { position: sticky; bottom: 0; margin-top: -26px; align-self: stretch; height: 26px; border: 0; border-top: 1px solid var(--border); background: linear-gradient(to bottom, transparent, var(--display) 40%); color: var(--text2); font: 11.5px var(--font); cursor: pointer; }
.jr-more[hidden] { display: none; }
/* the inspector's Breaks & Slides, by the picture's parts, each group linked to its lettered grips */
.jrc-group { border-radius: var(--radius-sm); transition: background 150ms ease; }
.jrc-group.jrc-lit { background: var(--surface2); }
.jrc-group-head { margin: 8px 0 2px; font-size: 0.68rem; font-weight: 650; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text2); display: flex; align-items: center; gap: 6px; }
.jrc-group.jrc-lit .jrc-group-head { color: var(--text); }
.jrc-group .seg-btn:disabled, .connection-row .seg-btn:disabled { opacity: 0.45; cursor: default; }
.jrc-l { display: inline-grid; place-items: center; width: 16px; height: 16px; flex: none; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--text); color: var(--text); font: 600 8.5px/1 var(--mono); letter-spacing: 0; }
.jrc-l.sl { box-shadow: inset 0 0 0 1.5px var(--surp); color: var(--surp); }
.jrc-group.jrc-lit .jrc-l { box-shadow: inset 0 0 0 2px var(--accent); color: var(--accent2); }
.jrc-says { margin: 2px 0 6px; font-size: 11.5px; line-height: 1.45; color: var(--text2); height: calc(2 * 1.45em); overflow: hidden; }
.jrc-says.h3 { height: calc(3 * 1.45em); }
.jrc-says b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.jrc-borrow { margin: 10px 0 4px; padding: 8px 10px; border: 1px dashed rgba(var(--land-light), 0.16); border-radius: var(--radius-sm); background: rgba(var(--land-light), 0.025); }
.jrc-borrow .jrc-group-head { margin-top: 0; color: var(--text3); flex-wrap: wrap; }
.jrc-tag { font-size: 10px; letter-spacing: 0.04em; text-transform: none; font-weight: 500; color: var(--text3); border: 1px solid rgba(var(--land-light), 0.16); border-radius: 999px; padding: 1px 7px; white-space: nowrap; }
.jrc-borrow .jrc-says { color: var(--text3); height: auto; }
.jrc-borrow .jrc-says b { color: var(--text2); }
@media (prefers-reduced-motion: reduce) { .jrc-group { transition: none; } }

/* ══ Sound · how long it rings: the Envelope page (ring-view.js, UI overhaul 2 Stage C) ══════════════════════════
   The Sub-note Envelope page, "Who holds the note". The rules after the page layout are the Stage B mock design 1's
   (docs/ui-overhaul-2/sound/B-ring/design-1/ring-d1.css), scoped under .ring-view; colours are :root tokens. */
.ch-main.ring-page { display: block; min-height: 0; overflow: hidden; }
/* The page is the desk: the layers-and-browser band steps aside while it is open (the page's own header picks the
   layer it shows), and comes back with any stage card. */
.harmonic-stage.chorda:has(.ring-page) .chorda-bottom, .harmonic-stage.chorda:has(.ring-page) .ch-hsplit { display: none; }
.harmonic-stage.chorda:has(.ring-page) .ch-main.ring-page { flex: 1; }
.ring-view {
  --rk-fill: 1;                            /* the picture fills the page's height (0 on a phone: the width decides) */
  --row-l1: 32px; --row-l2: 30px; --chip-w: 88px; --field-w: 68px; --unit-w: 28px; --mark-w: 20px; --why-lines: 2;
  --indent: calc(var(--mark-w) + 8px);
  height: 100%; min-height: 0; display: flex; flex-direction: column; gap: 6px; color: var(--text); font-size: 13px; line-height: 1.45;
}
.ring-view .num, .ring-view output, .ring-view .rk-field input { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.ring-view .rk-case { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; padding: 2px 2px 0; }
.ring-view .rk-case .rk-title { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text); }
.ring-view .rk-case .rk-layer { font-size: 12px; color: var(--text2); }
.ring-view .rk-case label { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text2); }
.ring-view .rk-case select, .ring-view .rk-case input, .ring-view .rk-btn {
  background: var(--display); color: var(--text); border: 1px solid var(--border2); border-radius: var(--radius-sm);
  font: inherit; font-size: 12px; min-height: 30px; padding: 0 8px; }
.ring-view .rk-case input { width: 58px; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.ring-view .rk-case .u { font-size: 11px; color: var(--rk-text3); }
.ring-view .rk-spacer { flex: 1; }
.ring-view .rk-btn { cursor: pointer; display: inline-flex; align-items: center; gap: 6px; padding: 0 12px; }
.ring-view .rk-btn:hover { border-color: var(--text2); }
.ring-view .rk-btn.primary { border-color: var(--accent); color: var(--accent); }
.ring-view .rk-btn:focus-visible, .ring-view .rk-case select:focus-visible, .ring-view .rk-case input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ring-view .rk-main { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) clamp(300px, 28vw, 400px); gap: 10px; align-items: stretch; }
.ring-view .rk-stage { min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.ring-view .rk-insp { min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.ring-view .rk-pic-title { margin: 0; font-size: 12px; font-weight: 600; color: var(--text); }
@media (pointer: coarse) {
  .ring-view { --row-l1: 44px; --row-l2: 44px; }
  .ring-view .rk-case select, .ring-view .rk-case input, .ring-view .rk-btn { min-height: 44px; }
}

.ring-view:focus { outline: none; }
@media (max-width: 760px) {
  .ring-view { --rk-fill: 0; height: auto; }
  .ch-main.ring-page { overflow: visible; height: auto; }
  .ring-view .rk-main { grid-template-columns: minmax(0, 1fr); }
  .ring-view .rk-stage, .ring-view .rk-insp { overflow: visible; }
}
.ring-view .num, .ring-view output, .ring-view .rk-field input {font-family: var(--mono); font-variant-numeric: tabular-nums;}
.ring-view .rk-field input, .ring-view .rk-btn {background: var(--display); color: var(--text); border: 1px solid var(--border2);
  border-radius: var(--radius-sm); font: inherit; min-height: 32px; padding: 0 8px;}
.ring-view .rk-btn {cursor: pointer; padding: 0 12px; display: inline-flex; align-items: center; gap: 8px;}
.ring-view .rk-btn:hover {border-color: var(--rk-text3);}
.ring-view .rk-btn.primary {border-color: var(--accent); color: var(--accent);}
.ring-view .rk-btn[aria-pressed="true"] {background: var(--surface2); border-color: var(--accent);}
.ring-view .rk-fam {font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--text); padding: 2px 8px;
  border: 1px solid var(--border2); border-radius: 999px;}
.ring-view .rk-stage {background: var(--display); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; min-width: 0;}
.ring-view .rk-stage-head {display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 8px; flex-wrap: wrap;}
.ring-view .rk-stage-head h2 {margin: 0; font-size: 13px; font-weight: 600;}
.ring-view .rk-pic {position: relative; width: 100%; touch-action: pan-y;}
.ring-view .rk-pic canvas {display: block; width: 100%; touch-action: pan-y;}
.ring-view .rk-caption {margin: 8px 0 0; color: var(--text2); font-size: 12px;}
.ring-view .rk-grip {position: absolute; width: 14px; height: 28px; margin: -14px 0 0 -7px; padding: 0;
  border: 2px solid var(--gc, var(--text)); background: var(--display); border-radius: 4px; cursor: ew-resize;
  touch-action: pan-y; z-index: 2;}
.ring-view .rk-grip.round {width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%;}
.ring-view .rk-grip.vert {cursor: ns-resize;}
.ring-view .rk-grip::before {content: ""; position: absolute; inset: -8px -10px;}
@media (pointer: coarse) {
  .ring-view .rk-grip::before {inset: -10px -17px;}
}
.ring-view .rk-grip:hover {background: var(--surface2);}
.ring-view .rk-grip[aria-disabled="true"] {cursor: default; border-style: dashed;}
.ring-view .rk-grip:focus-visible, .ring-view .rk-btn:focus-visible, .ring-view .rk-field input:focus-visible, .ring-view .rk-row input[type=range]:focus-visible, .ring-view .rk-pic canvas:focus-visible {outline: 2px solid var(--accent); outline-offset: 2px;}
.ring-view .rk-grip.is-drag {background: var(--gc, var(--text));}
.ring-view .rk-gtag {position: absolute; transform: translate(-50%, 0); font-size: 11px; white-space: nowrap; pointer-events: none;
  color: var(--text); background: var(--display); padding: 0 4px; border-radius: 3px; font-family: var(--mono); font-variant-numeric: tabular-nums; z-index: 1;}
.ring-view .rk-insp {background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; display: grid; gap: 12px;}
.ring-view .rk-group h3 {margin: 0 0 8px; font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--rk-text3); font-weight: 600;
  display: flex; align-items: center; gap: 8px;}
.ring-view .rk-group h3 i {width: 8px; height: 8px; border-radius: 2px; background: var(--gc); display: inline-block;}
.ring-view .rk-row {display: grid; grid-template-columns: 1fr 88px; gap: 2px 8px; padding: 6px 0; border-top: 1px solid var(--border);}
.ring-view .rk-row:first-of-type {border-top: 0;}
.ring-view .rk-row .lab {font-size: 12.5px; color: var(--text);}
.ring-view .rk-row .why {grid-column: 1 / -1; font-size: 11.5px; color: var(--text2);}
.ring-view .rk-row .state {font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; margin-left: 6px; padding: 1px 6px; border-radius: 999px;
  border: 1px solid var(--sc, var(--border2)); color: var(--sc, var(--text2)); white-space: nowrap;}
.ring-view .rk-row input[type=range] {grid-column: 1 / -1; width: 100%; accent-color: var(--accent); margin: 2px 0; touch-action: pan-y;}
.ring-view .rk-row.off .lab, .ring-view .rk-row.off .rk-field input {color: var(--rk-text3);}
.ring-view .rk-row.off input[type=range] {opacity: .35;}
.ring-view .rk-field {display: flex; align-items: center; gap: 4px; justify-content: flex-end;}
.ring-view .rk-field input {width: 64px; min-height: 28px; text-align: right;}
.ring-view .rk-field .u {color: var(--rk-text3); font-size: 11px; width: 14px;}
.ring-view .rk-row .reset {grid-column: 1 / -1; justify-self: start; background: none; border: 0; color: var(--rk-text3); font-size: 11px; padding: 0; cursor: pointer; min-height: 24px;}
.ring-view .rk-row .reset:hover {color: var(--text);}
.ring-view .rk-row .reset:focus-visible {outline: 2px solid var(--accent);}
.ring-view .rk-last {background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 12px; font-size: 12.5px; color: var(--text2); min-height: 40px;}
.ring-view .rk-last b {color: var(--text); font-weight: 600;}
.ring-view .rk-last .num {color: var(--text);}
.ring-view .rk-key {display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: 11.5px; color: var(--text2); margin-top: 8px;}
.ring-view .rk-key span {display: inline-flex; align-items: center; gap: 6px;}
.ring-view .rk-key i {width: 14px; height: 4px; border-radius: 2px; background: var(--gc); display: inline-block;}
.ring-view .rk-key i.dots {height: 4px; background: repeating-linear-gradient(90deg, var(--gc) 0 2px, transparent 2px 5px);}
.ring-view .rk-busy {color: var(--rk-text3); font-size: 11.5px;}
.ring-view .rk-notes {color: var(--text2); font-size: 12px; max-width: 90ch;}
.ring-view .rk-notes li {margin: 2px 0;}
@media (max-width: 760px) {
  .ring-view .rk-insp {padding: 8px 12px;}
}
.ring-view details.rk-group > summary {list-style: none; cursor: pointer;}
.ring-view details.rk-group > summary::-webkit-details-marker {display: none;}
.ring-view details.rk-group > summary h3 {margin: 0;}
.ring-view details.rk-group > summary h3::after {content: "▸"; margin-left: auto; color: var(--rk-text3);}
.ring-view details.rk-group[open] > summary h3::after {content: "▾";}
.ring-view details.rk-group[open] > summary {margin-bottom: 8px;}
.ring-view details.rk-group > summary:focus-visible {outline: 2px solid var(--accent); outline-offset: 2px;}
.ring-view .rk-grip.round {background: color-mix(in srgb, var(--gc) 30%, var(--display));}
.ring-view .rk-row .why {display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; height: calc(3 * 1.45em);}
.ring-view .rk-caption {min-height: calc(4 * 1.45em);}
.ring-view .rk-last {min-height: calc(3 * 1.45em + 16px);}
@media (max-width: 760px) {
  .ring-view .rk-caption {min-height: calc(8 * 1.45em);}
  .ring-view .rk-last {min-height: calc(7 * 1.45em + 16px);}
}
.ring-view .rk-stage-head {position: relative;}
.ring-view .rk-busy {position: absolute; right: 0; top: 0;}
.ring-view .rk-scope {display: grid; grid-template-columns: 1fr auto; gap: 4px 8px; align-items: center; padding: 6px 0;}
.ring-view .rk-scope .why {grid-column: 1 / -1; font-size: 11.5px; color: var(--text2);}
.ring-view .rk-segs {display: inline-flex; border: 1px solid var(--border2); border-radius: var(--radius-sm); overflow: hidden;}
.ring-view .rk-seg {background: var(--display); color: var(--text2); border: 0; font: inherit; font-size: 12px; min-height: 32px; min-width: 88px; padding: 0 8px; cursor: pointer;}
.ring-view .rk-seg[aria-checked="true"] {background: var(--surface2); color: var(--text); box-shadow: inset 0 -2px 0 var(--accent);}
.ring-view .rk-seg:disabled {cursor: default; opacity: .55;}
.ring-view .rk-seg:focus-visible {outline: 2px solid var(--accent); outline-offset: -2px;}
.ring-view .rk-row .reset {min-height: 24px;}
.ring-view .rk-row input[type=range]:disabled {opacity: .3;}
@media (pointer: coarse) {
  .ring-view .rk-grip.round::before {inset: -16px;}
}
.ring-view .rk-grip.dial {background: var(--display); border-style: dashed;}
.ring-view .rk-marker {position: absolute; pointer-events: none; transform: translate(-50%, -50%); width: 2px; height: 22px; background: var(--own-fit); z-index: 1;}
.ring-view .rk-scope .why {height: calc(2 * 1.45em); overflow: hidden;}
.ring-view .rk-stage-head h2 {white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: calc(100% - 130px);}
.ring-view .rk-row {grid-template-columns: 1fr 120px;}
.ring-view .rk-row .reset {grid-column: auto; justify-self: auto; width: 28px; min-height: 28px; font-size: 14px; color: var(--text2); border: 1px solid var(--border2); border-radius: var(--radius-sm); background: var(--display);}
@media (pointer: coarse) {
  .ring-view .rk-row .reset {width: 36px; min-height: 36px;}
  .ring-view .rk-row {grid-template-columns: 1fr 140px;}
}
.ring-view .rk-field {position: relative;}
.ring-view .rk-replace {position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 84px; min-height: 28px;
  background: var(--display); color: var(--own-fit); border: 1px solid var(--own-fit); border-radius: var(--radius-sm); font: inherit; font-size: 12px; cursor: pointer;}
.ring-view .rk-replace:focus-visible, .ring-view .rk-card button:focus-visible, .ring-view .rk-pop input:focus-visible {outline: 2px solid var(--accent); outline-offset: 2px;}
.ring-view .rk-stage .rk-last {margin: 8px 0; display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: start; background: var(--surface);}
@media (pointer: coarse) {
  .ring-view .rk-row .reset {width: 44px; min-height: 44px;}
  .ring-view .rk-row {grid-template-columns: 1fr 156px;}
  .ring-view .rk-seg {min-height: 44px;}
  .ring-view .rk-replace {min-height: 44px;}
}
.ring-view .rk-card {position: absolute; z-index: 5; width: min(320px, calc(100% - 16px)); background: var(--surface2); border: 1px solid var(--own-fit);
  border-radius: var(--radius-sm); padding: 8px 12px; font-size: 12.5px; color: var(--text); box-shadow: var(--rk-shadow-pop);}
.ring-view .rk-card p {margin: 0 0 8px;}
.ring-view .rk-card .num {font-family: var(--mono); font-variant-numeric: tabular-nums;}
.ring-view .rk-card .row {display: flex; gap: 8px; justify-content: flex-end;}
.ring-view .rk-card button {min-height: 32px; padding: 0 12px; background: var(--display); color: var(--text); border: 1px solid var(--border2); border-radius: var(--radius-sm); font: inherit; cursor: pointer;}
.ring-view .rk-card button.go {border-color: var(--own-fit); color: var(--own-fit);}
@media (pointer: coarse) {
  .ring-view .rk-card button {min-height: 44px;}
}
.ring-view .rk-pop {position: absolute; z-index: 5; display: flex; gap: 6px; align-items: center; background: var(--surface2); border: 1px solid var(--own-env); border-radius: var(--radius-sm); padding: 6px 8px; font-size: 12px;}
.ring-view .rk-pop input {width: 64px; min-height: 32px; background: var(--display); color: var(--text); border: 1px solid var(--border2); border-radius: var(--radius-sm); font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right;}
@media (pointer: coarse) {
  .ring-view .rk-pop input {min-height: 44px;}
}
.ring-view .rk-last-text {display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; height: calc(3 * 1.45em);}
.ring-view .rk-caption {display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; overflow: hidden; height: calc(4 * 1.45em); min-height: 0;}
.ring-view .rk-stage .rk-last {min-height: 0;}
@media (max-width: 760px) {
  .ring-view .rk-last-text {-webkit-line-clamp: 7; height: calc(7 * 1.45em);}
  .ring-view .rk-caption {-webkit-line-clamp: 9; height: calc(9 * 1.45em);}
}
.ring-view .rk-grip.dial {border-style: solid; border-color: var(--own-fit); background: var(--own-fit-dim);}
.ring-view .rk-grip.dial::after {content: ""; position: absolute; left: 50%; top: -6px; width: 6px; height: 6px; margin-left: -3px; border: 2px solid var(--own-fit); border-bottom: 0; border-radius: 4px 4px 0 0;}
.ring-view .rk-grip.dial.is-proposing {background: var(--own-fit);}
.ring-view .rk-mark {display: inline-grid; place-items: center; width: 18px; height: 18px; margin-right: 6px; border-radius: 4px; background: var(--surface2); border: 1px solid var(--border2); color: var(--text); font: 600 11px var(--mono); vertical-align: 1px;}
.ring-view .rk-row.is-linked {background: var(--rk-link); box-shadow: inset 2px 0 0 var(--accent);}
.ring-view .rk-row {transition: background-color .12s;}
.ring-view .rk-grip.is-linked {box-shadow: 0 0 0 3px var(--rk-link), 0 0 0 4px var(--accent);}
@media (max-width: 760px) {
  .ring-view .rk-last-text {-webkit-line-clamp: unset; display: block; height: calc(5 * 1.45em); overflow-y: auto;}
}
.ring-view .rk-key i.thin {height: 1px; opacity: .6;}
@media (pointer: coarse) {
  .ring-view .rk-row input[type=range] {pointer-events: none;}
}
.ring-view .rk-row.is-linked {box-shadow: -6px 0 0 0 var(--accent);}
.ring-view .rk-card button:disabled {opacity: .55; cursor: default;}
.ring-view .rk-row .rk-slide {grid-column: 1 / -1; display: block; touch-action: pan-y; cursor: pointer; padding: 3px 0;}
.ring-view .rk-row .rk-slide input[type=range] {pointer-events: none; display: block;}
.ring-view .rk-row .rk-slide:has(input:disabled) {cursor: default;}
@media (pointer: coarse) {
  .ring-view .rk-row .rk-slide {padding: 10px 0;}
}
.ring-view .rk-row .rk-slide:hover input[type=range]:not(:disabled) {filter: brightness(1.15);}
.ring-view .rk-last .num, .ring-view .rk-card .num {white-space: nowrap;}
.ring-view .rk-row .lab {display: flex; align-items: flex-start; flex-wrap: nowrap;}
.ring-view .rk-row .lab .rk-mark {flex: none; margin-top: 1px;}
.ring-view .rk-row .lab .rk-lab-body {min-width: 0;}
.ring-view .rk-row input[type=range][data-pointer-focus]:focus-visible {outline: none;}
.ring-view .rk-insp {gap: 16px; align-content: start;}
.ring-view .rk-group h3 {display: flex; align-items: baseline; gap: 8px; margin: 0 0 4px;}
.ring-view .rk-group h3 i {width: 14px; height: 3px; border-radius: 2px; align-self: center;}
.ring-view .rk-group h3 i.thin {height: 1px; opacity: .7;}
.ring-view .rk-ghint {margin-left: auto; font-size: 11px; letter-spacing: 0; text-transform: none; font-weight: 400; color: var(--rk-text3);}
.ring-view .rk-row {display: block; padding: 10px 0 8px; border-top: 1px solid var(--border);}
.ring-view .rk-group > .rk-row:first-of-type, .ring-view .rk-group > h3 + .rk-row {border-top: 0;}
.ring-view .rk-l1 {display: grid; grid-template-columns: var(--mark-w) minmax(0, 1fr) var(--chip-w) var(--field-w) var(--unit-w);
  column-gap: 8px; align-items: baseline; min-height: var(--row-l1);}
.ring-view .rk-l1 .rk-mark {margin: 0; width: var(--mark-w); height: var(--mark-w); align-self: baseline;}
.ring-view .rk-l1 .rk-mark.none {visibility: hidden;}
.ring-view .rk-row .lab, .ring-view .rk-row .rk-l1 .lab {display: block; min-width: 0;}
.ring-view .rk-lab-text {display: block; font-size: 12.5px; line-height: 1.3;}
.ring-view .rk-sub {display: block; font-size: 11px; line-height: 1.3; color: var(--rk-text3);}
.ring-view .rk-sub:empty {display: none;}
.ring-view .rk-l1 .state {margin: 0; justify-self: start; max-width: var(--chip-w); overflow: hidden; text-overflow: ellipsis; font-size: 10px; line-height: 1.5;}
.ring-view .rk-l1 .rk-field {display: block;}
.ring-view .rk-l1 .rk-field input {width: 100%; min-height: 30px; line-height: 1.3;}
@media (pointer: coarse) {
  .ring-view .rk-l1 .rk-field input {min-height: 44px;}
}
.ring-view .rk-l1 .u {width: auto; font-size: 11px; color: var(--rk-text3);}
.ring-view .rk-row-ro .rk-l1 .rk-field {text-align: right; font-size: 12.5px;}
.ring-view .rk-l2 {display: grid; grid-template-columns: minmax(0, 1fr) var(--unit-w); column-gap: 8px; align-items: center; height: var(--row-l2); margin: 4px 0 0 var(--indent);}
@media (pointer: coarse) {
  .ring-view .rk-l2 {grid-template-columns: minmax(0, 1fr) 44px;}
}
.ring-view .rk-row .why {margin-left: var(--indent);}
.ring-view .rk-slot {display: grid; min-width: 0;}
.ring-view .rk-slot > * {grid-area: 1 / 1;}
.ring-view .rk-row .rk-slide {padding: 5px 0;}
@media (pointer: coarse) {
  .ring-view .rk-row .rk-slide {padding: 10px 0;}
}
.ring-view .rk-row .reset {width: 28px; min-height: 28px; height: 28px;}
@media (pointer: coarse) {
  .ring-view .rk-row .reset {width: 44px; min-height: 44px; height: 44px;}
}
.ring-view .rk-row .why {margin-top: 4px; -webkit-line-clamp: var(--why-lines); height: calc(var(--why-lines) * 1.45em);}
.ring-view .rk-row.off .rk-lab-text {color: var(--rk-text3);}
.ring-view .rk-row .rk-replace {position: static; transform: none; width: 100%; height: 30px; min-height: 30px; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 0 10px; background: var(--own-fit-dim); color: var(--text); border: 1px solid var(--own-fit); border-radius: var(--radius-sm); font: 12px var(--font); cursor: pointer; text-align: left;}
@media (pointer: coarse) {
  .ring-view .rk-row .rk-replace {height: 44px;}
}
.ring-view .rk-row .rk-replace:hover {background: var(--own-fit); color: var(--display);}
.ring-view .rk-row .rk-replace:hover .rk-rep-sub {color: var(--display);}
.ring-view .rk-rep-main {font-weight: 600; white-space: nowrap;}
.ring-view .rk-rep-main::before {content: "↻ ";}
.ring-view .rk-rep-sub {font-size: 11px; color: var(--text2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;}
.ring-view .rk-unused {border-top: 1px solid var(--border2); padding-top: 8px;}
.ring-view .rk-unused > summary {display: flex; align-items: center; gap: 8px; min-height: 36px; color: var(--text2); font-size: 12.5px; cursor: pointer; list-style: none;}
@media (pointer: coarse) {
  .ring-view .rk-unused > summary {min-height: 44px;}
}
.ring-view .rk-unused > summary::-webkit-details-marker {display: none;}
.ring-view .rk-unused > summary::before {content: "▸"; color: var(--rk-text3); width: 12px;}
.ring-view .rk-unused[open] > summary::before {content: "▾";}
.ring-view .rk-unused > summary:hover {color: var(--text);}
.ring-view .rk-unused > summary:focus-visible {outline: 2px solid var(--accent); outline-offset: 2px;}
.ring-view .rk-unused ul {list-style: none; margin: 0; padding: 0;}
.ring-view .rk-un {display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 8px; row-gap: 2px; padding: 8px 0; border-top: 1px solid var(--border);}
.ring-view .rk-un-name {font-size: 12.5px; color: var(--text2);}
.ring-view .rk-un-tag {font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--rk-text3); align-self: baseline;}
.ring-view .rk-un-why {grid-column: 1 / -1; font-size: 11.5px; color: var(--rk-text3);}
.ring-view .rk-un .rk-open {grid-column: 1 / -1; justify-self: start; margin-top: 4px; min-height: 30px; padding: 0 12px; background: var(--display); color: var(--text); border: 1px solid var(--border2); border-radius: var(--radius-sm); font: 12px var(--font); cursor: pointer;}
@media (pointer: coarse) {
  .ring-view .rk-un .rk-open {min-height: 44px;}
}
.ring-view .rk-un .rk-open:hover {border-color: var(--rk-text3);}
.ring-view .rk-un .rk-open:focus-visible {outline: 2px solid var(--accent); outline-offset: 2px;}
.ring-view .rk-open-body {grid-column: 1 / -1;}
.ring-view .rk-open-body:empty {display: none;}
.ring-view .rk-open-note {margin: 8px 0 0; font-size: 11.5px; color: var(--text2);}
.ring-view .rk-stage .rk-last {margin: 12px 0 0; padding: 8px 12px;}
.ring-view .rk-last-text {-webkit-line-clamp: 2; height: calc(2 * 1.45em);}
.ring-view .rk-caption {-webkit-line-clamp: 2; height: calc(2 * 1.45em); margin: 8px 0 0; color: var(--text2);}
.ring-view .rk-keyrow {display: flex; align-items: flex-start; justify-content: space-between; gap: 8px 16px; margin-top: 8px;}
.ring-view .rk-keyrow .rk-key {margin: 0; height: calc(2 * 20px); align-content: flex-start; row-gap: 4px; line-height: 16px;}
.ring-view .rk-key i.dash {height: 2px; background: repeating-linear-gradient(90deg, var(--gc) 0 4px, transparent 4px 7px);}
.ring-view .rk-key i.dots {height: 2px;}
.ring-view .rk-how-wrap {position: relative; flex: none;}
.ring-view .rk-how {background: none; border: 0; padding: 0 0 0 14px; min-height: 28px; color: var(--text2); font: 12px var(--font); cursor: pointer; white-space: nowrap; position: relative;}
.ring-view .rk-how::before {content: "▸"; position: absolute; left: 0; color: var(--rk-text3);}
.ring-view .rk-how[aria-expanded="true"]::before {content: "▾";}
.ring-view .rk-how:hover {color: var(--text);}
.ring-view .rk-how:focus-visible {outline: 2px solid var(--accent); outline-offset: 2px;}
@media (pointer: coarse) {
  .ring-view .rk-how {min-height: 44px;}
}
.ring-view .rk-how-body {position: absolute; right: 0; bottom: calc(100% + 6px); width: min(520px, calc(100vw - 48px)); z-index: 10;
  background: var(--surface2); border: 1px solid var(--border2); border-radius: var(--radius-sm); box-shadow: var(--rk-shadow-pop); padding: 8px 12px; font-size: 12px; color: var(--text2);}
.ring-view .rk-how-body p {margin: 0 0 8px;}
.ring-view .rk-how-body p:last-child {margin: 0;}
.ring-view .rk-how-body[hidden] {display: none;}
@media (max-width: 760px) {
  .ring-view .rk-last-text {height: calc(4 * 1.45em);}
  .ring-view .rk-caption {-webkit-line-clamp: 4; height: calc(4 * 1.45em);}
  .ring-view .rk-keyrow {flex-direction: column;}
  .ring-view .rk-keyrow .rk-key {height: calc(4 * 20px);}
  .ring-view .rk-how-wrap {align-self: stretch;}
  .ring-view .rk-how-body {left: 0; right: auto; width: 100%;}
}
.ring-view .rk-slot {grid-template-columns: minmax(0, 1fr);}
.ring-view .rk-row .rk-replace {min-width: 0; overflow: hidden;}
.ring-view .rk-row.is-fit .rk-l1 .rk-field input {color: var(--rk-text3);}
@media (max-width: 760px) {
  .ring-view .rk-caption {-webkit-line-clamp: 3; height: calc(3 * 1.45em);}
}
.ring-view .rk-un {position: relative;}
.ring-view .rk-gatecard {top: calc(100% - 4px); left: 0; width: 100%; z-index: 6; border-color: var(--border2);}
.ring-view .rk-gatecard > p {color: var(--text2); font-size: 11.5px;}
.ring-view .rk-gatecard .rk-row:first-of-type {border-top: 0;}
.ring-view .rk-row .rk-l1 .state {border-color: var(--border2); color: var(--text2);}
.ring-view .rk-row.is-fit .rk-l1 .state, .ring-view .rk-row-ro .rk-l1 .state {border-color: var(--own-fit); color: var(--own-fit);}
.ring-view .rk-row.off .rk-l1 .state {border-style: dashed;}
.ring-view .rk-gatecard.up {top: auto; bottom: calc(100% - 4px);}
.ring-view .rk-gatecard-title {margin: 0 0 4px; font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text); font-weight: 600;}
@media (max-width: 760px) {
  .ring-view .rk-rep-inst {display: none;}
}
.ring-view .rk-scope .why {display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; height: calc(3 * 1.45em); overflow: hidden;}
.ring-view .rk-how {border: 1px solid var(--border2); border-radius: var(--radius-sm); padding: 0 8px 0 22px;}
.ring-view .rk-how::before {left: 8px;}
.ring-view .rk-insp-label { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0 0 -4px; }
/* A short desk (1024 × 768 and the like): the picture keeps its room; the one-line caption moves into
   "How this was measured" (it is there in full), and the replace action drops its "instead". These come after
   the mock's rules they override. */
@media (max-height: 820px) and (min-width: 761px) {
  .ring-view .rk-stage .rk-caption { display: none; }
}
@media (max-width: 1280px) { .ring-view .rk-row .rk-rep-inst { display: none; } }
/* The panel's sliders show their value as a fill in the level arc's amber, as the mock's did (accent-color). */
.ring-view .rk-row input[type=range] { accent-color: var(--accent); }
/* Ring build 2 (REVIEW-RING-BUILD-1) */
/* M3 · the how-to line under the page title */
.ring-view .rk-howto { flex: none; margin: -2px 2px 0; font-size: 12px; color: var(--text2); }
/* S2 · a way out, and the page named as the open Envelope tab (the column's tab style, lit) */
.ring-view .rk-case .rk-back { color: var(--text2); }
.ring-view .rk-case .rk-back:hover { color: var(--text); }
.ring-view .rk-case .rk-title { display: inline-flex; align-items: baseline; gap: 8px; }
.ring-view .rk-tabpill { font-size: 0.7rem; font-weight: 600; letter-spacing: 0.03em; text-transform: none; color: var(--rk-tab-lit); background: var(--rk-tab-lit-bg); box-shadow: inset 0 0 0 1px var(--rk-tab-lit-edge); border-radius: var(--radius-sm); padding: 3px 10px; }
.ring-view .rk-title-sub { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text); }
/* M2 · a row this layer does not hold (the base's): a dashed chip, the reason says whose */
.ring-view .rk-row.is-inherited .rk-l1 .state { border-style: dashed; border-color: var(--border2); color: var(--text2); }
/* S3 · no cut text in a narrow panel: reasons get a third line at 1280 and below */
@media (max-width: 1280px) { .ring-view { --why-lines: 3; } }
/* S6 · 44 px on a touch screen: the header's buttons and the pitch select */
@media (pointer: coarse) {
  .ring-view .rk-case .rk-btn, .ring-view .rk-case select, .ring-view .rk-case input { min-height: 44px; }
  .ring-view .rk-case select { min-width: 64px; }
}
/* whose it is, then the reason: never cut. An inherited row's reason is as long as it needs (REVIEW-RING-BUILD-1
   build 2, S3); it does not change under a drag, so its height is steady */
.ring-view .rk-row.is-inherited { --why-lines: 3; }
.ring-view .rk-row.is-inherited .why { display: block; -webkit-line-clamp: unset; height: auto; min-height: calc(3 * 1.45em); overflow: visible; }
/* …and so is every reason: a replaced table's words run to four lines in a narrow panel. The row keeps its
   usual height as a floor, so a reason that fits never moves the rows under it */
.ring-view .rk-row .why { display: block; -webkit-line-clamp: unset; height: auto; min-height: calc(var(--why-lines) * 1.45em); overflow: visible; }
/* S3 · a narrow desk: the header stays one row (the "Envelope" tab names the page), and the replace action keeps
   what the dial will give ("→ 810 ms"), dropping what it had */
@media (max-width: 1100px) and (min-width: 761px) {
  .ring-view .rk-last-text { -webkit-line-clamp: 3; height: calc(3 * 1.45em); }   /* what a replace did, whole */
  .ring-view .rk-title-sub { display: none; }
  .ring-view .rk-row .rk-rep-from { display: none; }
}


/* ══ Sound · how a note starts: the Attack page (attack-view.js, UI overhaul 2 Stage C) ════════════════════════════
   The Sub-note Attack page, placed as the Envelope page is: it takes the desk, the layers band steps aside, its header
   picks the layer. The rules after the page layout are the Stage B working mock's (docs/ui-overhaul-2/sound/B-attack/
   design-3/: start.html and live.css), scoped under .attack-view; colours are :root tokens. */
.ch-main.attack-page { display: block; min-height: 0; overflow: hidden; }
.harmonic-stage.chorda:has(.attack-page) .chorda-bottom, .harmonic-stage.chorda:has(.attack-page) .ch-hsplit { display: none; }
.harmonic-stage.chorda:has(.attack-page) .ch-main.attack-page { flex: 1; }
.ins-group-label .ins-page-link { margin-left: 8px; background: none; border: 0; padding: 0 2px; font: inherit; font-style: normal; letter-spacing: 0.06em; color: var(--text2); cursor: pointer; }
.ins-group-label .ins-page-link:hover { color: var(--text); }
.ins-group-label .ins-page-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
@media (pointer: coarse) { .ins-group-label .ins-page-link { min-height: 44px; padding: 0 8px; } }
.attack-view {
  --atk-fill: 1;                           /* the picture fills the stage's height (0 on a phone: the width decides) */
  height: 100%; min-height: 0; display: flex; flex-direction: column; gap: 6px; color: var(--text); font-size: 13px; line-height: 1.45;
}
.attack-view:focus { outline: none; }
.attack-view .atk-case { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; padding: 2px 2px 0; }
.attack-view .atk-head { display: inline-flex; align-items: center; gap: 10px; }
.attack-view .atk-tabpill { font-size: 0.7rem; font-weight: 600; letter-spacing: 0.03em; color: var(--rk-tab-lit); background: var(--rk-tab-lit-bg); box-shadow: inset 0 0 0 1px var(--rk-tab-lit-edge); border-radius: var(--radius-sm); padding: 3px 10px; }
.attack-view .atk-head-sub { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text); }
.attack-view .atk-case label { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text2); }
.attack-view .atk-layer { font-size: 12px; color: var(--text2); }
.attack-view .atk-fam { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--text); padding: 2px 8px; border: 1px solid var(--border2); border-radius: 999px; }
.attack-view .atk-spacer { flex: 1; }
.attack-view .atk-sel, .attack-view .atk-btn, .attack-view .atk-num {
  background: var(--display); color: var(--text); border: 1px solid var(--border2); border-radius: var(--radius-sm); font: inherit; font-size: 12px; min-height: 30px; padding: 0 10px; }
.attack-view .atk-btn { cursor: pointer; display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; font-weight: 600; }
.attack-view .atk-btn:hover:not([disabled]) { border-color: var(--text2); }
.attack-view .atk-btn.primary { border-color: var(--accent); color: var(--accent); }
.attack-view .atk-btn[disabled] { opacity: 0.45; cursor: default; }
.attack-view .atk-btn.quiet { min-height: 28px; font-size: 11.5px; font-weight: 500; }
.attack-view .atk-btn:focus-visible, .attack-view .atk-sel:focus-visible, .attack-view .atk-num:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.attack-view .atk-howto { flex: none; margin: -2px 2px 0; font-size: 12px; color: var(--text2); display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: baseline; }
/* the status keeps its place whatever it says: one line, clipped by width, never by wrapping (lesson 9) */
/* the status keeps its place whatever it says: two lines' room, never cut (lesson 9) */
.attack-view .atk-status { flex: 1 1 260px; min-width: 0; font-size: 11.5px; line-height: 1.4; min-height: calc(2 * 1.4em); color: var(--text2); font-variant-numeric: tabular-nums; }
@media (min-width: 761px) { .attack-view .atk-status { min-height: 0; white-space: nowrap; } }   /* one line on a desk: the how-to row leaves it room for its longest words */
.attack-view .atk-status[data-busy="true"]::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 8px; border-radius: 50%; background: var(--text2); vertical-align: 1px; }
.attack-view .atk-main { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) clamp(300px, 30vw, 420px); gap: 10px; align-items: stretch; }
.attack-view .atk-stage { min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; background: var(--display); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; min-width: 0; }
.attack-view .atk-title { margin: 0 0 4px; font-size: 14px; font-weight: 650; }
.attack-view .atk-stacknote { margin: 0 0 6px; padding: 0 0 0 8px; font-size: 12px; line-height: 1.4; color: var(--text2); border-left: 2px dashed var(--own-fit); min-height: calc(2 * 1.4em); box-sizing: border-box; }
.attack-view .atk-sum { margin: 0 0 8px; font-size: 12.5px; color: var(--text2); line-height: 1.5; max-width: 90ch; }
.attack-view .atk-sum b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
/* the picture is as tall as it draws itself: when the stage is too short for it, the stage scrolls; nothing under it is overdrawn */
.attack-view .atk-pic { position: relative; flex: none; touch-action: pan-y; }
.attack-view .atk-cv { display: block; width: 100%; touch-action: pan-y; }
.attack-view .atk-key { flex: none; display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 11.5px; color: var(--text2); padding: 6px 0 2px; }
.attack-view .atk-key span { display: inline-flex; align-items: center; gap: 6px; }
.attack-view .atk-key i { display: inline-block; width: 16px; height: 8px; border-radius: 2px; }
.attack-view .atk-note { flex: none; margin: 4px 0 0; font-size: 11px; color: var(--rk-text3); }
.attack-view .atk-insp { min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 8px; overflow-anchor: none; }
.attack-view .atk-insp-label { flex: none; margin: 2px 2px 0; }
.attack-view .atk-card { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; min-width: 0; flex: none; }
.attack-view .atk-card h3 { margin: 0; display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 650; }
.attack-view .atk-card h3 i { width: 10px; height: 10px; border-radius: 2px; flex: none; }
.attack-view .atk-card h3 i.pitch { border-radius: 50%; }
.attack-view .atk-card h3 i.level { background: transparent !important; border: 1.5px solid var(--text2); }
.attack-view .atk-body, .attack-view .atk-bridge, .attack-view .atk-else { margin: 0; font-size: 12px; color: var(--text2); line-height: 1.45; }
.attack-view .atk-body b, .attack-view .atk-bridge b, .attack-view .atk-else b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.attack-view .atk-bridge { font-size: 11.5px; }
/* a verdict chip keeps one width whatever it says (lesson 9); it takes its part's kind hue when the part stands out */
.attack-view .atk-chip { align-self: flex-start; display: inline-flex; align-items: center; min-width: 15em; height: 20px; padding: 0 8px; border-radius: 10px; font-size: 11px; font-weight: 600; border: 1px solid var(--border2); color: var(--text2); font-variant-numeric: tabular-nums; }
.attack-view .atk-chip.stands.beside { border-color: rgba(var(--atk-beside-rgb), 0.7); color: rgb(var(--atk-beside-rgb)); }
.attack-view .atk-chip.stands.shape { border-color: rgba(var(--atk-shape-rgb), 0.7); color: rgb(var(--atk-shape-rgb)); }
.attack-view .atk-chip.stands.pitch { border-color: rgba(var(--atk-pitch-rgb), 0.7); color: rgb(var(--atk-pitch-rgb)); }
.attack-view .atk-chip.borderline { border-style: dashed; color: var(--text); }
.attack-view .atk-chip.off { border-style: dashed; }
.attack-view .atk-chip.stale { opacity: 0.55; }
.attack-view .atk-ears { display: flex; flex-wrap: wrap; gap: 6px; }
.attack-view .atk-ears .alone { min-width: 10.5em; }
/* a control row: name, whose (on a stacked layer), typed value, reset; the slider; one line of state */
.attack-view .atk-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; gap: 2px 6px; align-items: center; font-size: 12px; color: var(--text2); padding-top: 6px; border-top: 1px solid var(--border); }
.attack-view .atk-row label { min-width: 0; overflow-wrap: anywhere; line-height: 1.3; }
.attack-view .atk-row label[data-edited="true"] { color: var(--text); }
.attack-view .atk-row label[data-edited="true"]::after { content: " ·"; color: var(--accent); }
.attack-view .atk-own { font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--own-fit); }
.attack-view .atk-row.is-inherited .atk-own { padding: 1px 6px; border: 1px dashed var(--own-fit); border-radius: 999px; }
.attack-view .atk-num { width: 76px; min-height: 28px; text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.attack-view .atk-reset { width: 28px; height: 28px; border: 1px solid transparent; border-radius: var(--radius-sm); background: transparent; color: var(--rk-text3); cursor: pointer; font: inherit; font-size: 13px; }
.attack-view .atk-reset[aria-disabled="true"] { visibility: hidden; }
.attack-view .atk-reset:hover { color: var(--text); }
.attack-view .atk-reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* the slider takes only sideways drags; a vertical swipe is the page's (lesson 1). Specific enough to win over the
   studio's coarse-pointer row rule (touch-action: manipulation, for its own installTouchSliders, which this page's
   sliders opt out of: data-own-touch) */
.attack-view .atk-row > .atk-slide.atk-slide { grid-column: 1 / -1; display: block; touch-action: pan-y; }
.attack-view .atk-slide input[type=range] { pointer-events: none; }
.attack-view .atk-row input[type=range] { width: 100%; margin: 6px 0; }
.attack-view .atk-row input[type=range]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.attack-view .atk-row input[type=range][data-pointer-focus]:focus-visible { outline: none; }
.attack-view .atk-row[data-live="false"] input[type=range] { opacity: 0.4; }
/* two lines, always (a reason that re-words never moves the rows below; lesson 9), and never cut */
.attack-view .atk-state { grid-column: 1 / -1; font-size: 11px; color: var(--rk-text3); line-height: 1.4; min-height: calc(2 * 1.4em); }
.attack-view .atk-more { flex: none; overflow-anchor: none; }
.attack-view .atk-more > summary { list-style: none; display: flex; align-items: center; gap: 8px; min-height: 32px; cursor: pointer; font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text2); font-weight: 600; }
.attack-view .atk-more > summary::-webkit-details-marker { display: none; }
.attack-view .atk-more > summary::before { content: ""; width: 0; height: 0; border-left: 5px solid currentColor; border-top: 4px solid transparent; border-bottom: 4px solid transparent; }
.attack-view .atk-more[open] > summary::before { border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 5px solid currentColor; border-bottom: 0; }
.attack-view .atk-more > summary:hover { color: var(--text); }
.attack-view .atk-more > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.attack-view .atk-groups h4 { margin: 8px 0 0; font-size: 12px; font-weight: 650; display: flex; align-items: center; gap: 8px; }
.attack-view .atk-groups h4 i { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.attack-view .atk-groups h4 i.pitch { border-radius: 50%; }
.attack-view .atk-also { flex: none; margin: 0; font-size: 12px; color: var(--text2); line-height: 1.5; }
.attack-view .atk-also b { color: var(--text); font-weight: 600; }
.attack-view .atk-spacer-reserve { flex: none; height: 0; }
@media (pointer: coarse) {
  .attack-view .atk-sel, .attack-view .atk-btn, .attack-view .atk-btn.quiet, .attack-view .atk-num, .attack-view .atk-reset { min-height: 44px; }
  .attack-view .atk-reset { width: 44px; height: 44px; }
  .attack-view .atk-row input[type=range] { margin: 12px 0; }
  .attack-view .atk-slide { min-height: 44px; }
  .attack-view .atk-more > summary { min-height: 44px; }
}
@media (max-width: 1100px) and (min-width: 761px) {
  .attack-view .atk-head-sub { display: none; }
}
@media (max-width: 760px) {
  .attack-view { --atk-fill: 0; height: auto; }
  .ch-main.attack-page { overflow: visible; height: auto; }
  .attack-view .atk-main { grid-template-columns: minmax(0, 1fr); }
  .attack-view .atk-stage, .attack-view .atk-insp { overflow: visible; }
}
@media (prefers-reduced-motion: reduce) { .attack-view * { transition: none !important; animation: none !important; } }

/* Prepared playback: inset readiness hairlines and matching border badges. */
:root { --preview-play-color: #55cda2; --preview-head-color: #6fcbea; }
.strips-panel:has(.preview-row) { padding-bottom: 0; border-bottom: 0; }
.tl2.strips-tl2:has(.preview-row) { padding-bottom: 0; }
.strips-panel .preview-row { height: 2px; min-height: 2px; margin-bottom: 0; }
.tl2-row > .preview-label { padding: 0; min-height: 0; border: 0; background: transparent; }
.preview-lane { position: relative; height: 2px; margin-top: 0; background: #17212d; overflow: hidden; opacity: .55; transition: opacity .15s ease; }
.preview-row:hover .preview-lane { opacity: 1; }
.preview-range { position: absolute; top: 0; height: 100%; border-right: 1px solid #17212d; background: #344357; }
.preview-range.empty { background: transparent; }
.preview-range.ready { background: var(--preview-play-color); }
[data-preview-lane="head"] .preview-range.ready { background: var(--preview-head-color); }
.preview-range.rendering { background: repeating-linear-gradient(115deg, #799cae 0 4px, #344357 4px 8px); animation: preview-working 1.2s linear infinite; background-size: 18px 100%; }
.preview-range.error { background: #b98b49; }
#arrPlayBtn { overflow: visible; }
.preview-pips { position: absolute; inset: 0; pointer-events: none; }
.preview-pips svg { position: absolute; bottom: -4px; width: 14px; height: 14px; overflow: visible; }
.preview-play-pip { left: -3px; color: var(--preview-play-color); }
.preview-head-pip { right: -3px; color: var(--preview-head-color); }
.preview-badge-outline { fill: #17212d; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; }
.preview-badge-check { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; opacity: 0; }
[data-playback-ready="ready"] .preview-play-pip .preview-badge-check,
[data-head-ready="ready"] .preview-head-pip .preview-badge-check { opacity: 1; }
[data-playback-ready="preparing"] .preview-play-pip,
[data-head-ready="preparing"] .preview-head-pip { opacity: .5; }
[data-playback-ready="preparing"] .preview-play-pip .preview-badge-outline,
[data-head-ready="preparing"] .preview-head-pip .preview-badge-outline { stroke-dasharray: 2 2; }
@keyframes preview-working { to { background-position: 18px 0; } }
@media (prefers-reduced-motion: reduce) { .preview-range.rendering { animation: none; } }
.preview-range.rendering::after { content: ''; position: absolute; inset: 0 auto 0 0; width: var(--preview-progress, 0%); background: rgba(135, 211, 236, .45); }
[data-playback-ready="unavailable"] .preview-play-pip,
[data-head-ready="unavailable"] .preview-head-pip { color: #b98b49; }

/* Quiet transport feedback while ordinary audio substitutes for pending head playback. */
.preview-listening-status { font-size: 11px; opacity: .72; margin-inline: 7px; max-width: 220px; line-height: 1.25; }
.preview-listening-status[hidden] { display: none; }

.preview-mode-btn { font-size: 11px; padding: 3px 7px; opacity: .8; }

/* Keep the audible output explicit, separately from cache readiness. */
.preview-listening-status[data-output="binaural"] { color: var(--preview-head-color); opacity: 1; }
.preview-listening-status[data-output="stereo"] { color: var(--preview-play-color); opacity: 1; }
/* ═══ Compose · the instrument face page (UI overhaul 2, D-19; kit: face/face.css) ═══════════════════════
   The rail, then one column holding the face page and, under it, the preset library. The column scrolls on a
   desktop (the studio shell is fixed-height); on a phone the page itself scrolls (the phone block above), so no
   box inside the page ever traps a swipe. From 700 px the face is VW − 184 wide (FACE §8): a 136 px rail
   (10 + 126) with its 10 px gap, and 16 + 22 px of column padding. */
.macro2-card.face-mode .m2-facecol { flex: 1 1 0; min-width: 0; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain;
  padding: 4px 22px 28px 16px; display: flex; flex-direction: column; gap: 18px; overflow-anchor: none; scrollbar-gutter: stable; }
.macro2-card.face-mode .m2-facecol::-webkit-scrollbar { width: 7px; }
.macro2-card.face-mode .m2-facecol::-webkit-scrollbar-thumb { background: var(--face-tick); border-radius: 4px; }
.macro2-card.face-mode .face-lib { flex: none; height: var(--m2-lib-h, 300px); min-height: 220px; }
.macro2-card.face-mode .fh .panel-rand-btn { width: 30px; height: 30px; margin-left: 6px; }
.macro2-card.face-mode .fh .fh-end .fh-link + .fh-link { margin-left: 10px; }
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  .macro2-card.face-mode .m2-facecol { overflow: visible; padding: 4px 16px 24px; flex: none; scrollbar-gutter: auto; }
  .macro2-card.face-mode .face-lib { height: auto; min-height: 0; }
}
@media (pointer: coarse), (max-width: 699px) {
  .macro2-card.face-mode .fh .panel-rand-btn { width: 44px; height: 44px; }
}
.macro2-card.face-mode .fh .panel-rand-btn { background: none; border: 0; box-shadow: none; color: var(--face-quiet); border-radius: var(--radius-sm); }
.macro2-card.face-mode .fh .panel-rand-btn:hover { color: var(--text); background: var(--surface2); }

/* ── Polish pass (owner 2026-10-09): direct headings, one heading style across Compose, Sound and Tuning, flat
   marks. Heads follow the Compose deck's group head (11 px, 700, caps, 0.12em); a stage's head wears its stage hue,
   everything else --text2. No glow on an active card: a 1 px ring in its hue (faces-flat-no-glow). ── */
.m2-rail-head:empty { display: none; }
.ch-ins-head .ch-card-n, .ins-group-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; line-height: 1.3;
}
.ins-group-label { color: var(--text2); margin-bottom: 8px; }
.ch-excitor.active   { box-shadow: 0 0 0 1px var(--exc); }
.ch-resonator.active { box-shadow: 0 0 0 1px var(--res); }
.ch-body.active      { box-shadow: 0 0 0 1px var(--bodyc); }
.ch-effects.active   { box-shadow: 0 0 0 1px var(--eff); }
.ch-space.active     { box-shadow: 0 0 0 1px var(--spc); }
/* Sound's knobs: a readable sentence-case name that may wrap to two lines, never into its neighbour */
.ch-inspector .knob-row { gap: 10px 8px; }
.ch-inspector .knob-cell { width: 78px; }
.ch-inspector .knob-label { font-size: 11px; letter-spacing: 0; text-transform: none; white-space: normal; text-align: center; line-height: 1.25;
  min-height: 2.5em; margin-top: 3px; color: var(--text2); overflow-wrap: anywhere; }
.ch-inspector .knob-out { font-family: var(--mono); font-size: 11px; color: var(--face-quiet); margin-top: 1px; }
.td-field-title { font-size: 14px; }
.td-field-title .td-stage-word { font-weight: 600; }
/* Sound: the stage and its inspector are the page; the layers and library dock is the lesser half by default */
.chorda-bottom { height: clamp(190px, 27vh, 300px); }
