/* PATRICK: the page's styles (split from the live index.html, V2 stage 1). */
img{max-width:100%}[hidden]:not([hidden=until-found i]){display:none!important}
/* safe areas (4c-6): applied once, on #frame (Frame in ui.js), which holds the whole interface. Inside it the
   per-region --safe-* tokens of 4c-1 are 0, so the old max(gutter, --safe-*) paddings fall back to the gutters. */
/* 4c hotfix (Benjamin 2026-10-19): no zoom / no iOS text loupe anywhere outside real text inputs.
   manipulation kills double-tap zoom; pinch + loupe are blocked by nozoom.js (iOS ignores user-scalable). */
html,body,*{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}
html,body{touch-action:manipulation}
input,textarea,[contenteditable],[contenteditable=true]{-webkit-user-select:text;user-select:text;-webkit-touch-callout:default}
::selection{background:transparent;color:inherit}
input::selection,textarea::selection,[contenteditable]::selection,[contenteditable=true]::selection{background:Highlight;color:HighlightText}
a,button,input,select,textarea,label,summary,[role=button]{touch-action:manipulation}
/* PATRICK for the PC. Line work only: black ground, solid outlines, square corners, one flat colour per element
 * (DESIGHNUS tokens.css §4 module colours, ROYGBIV, --value, --ink-2 labels, --rec red). No gradients except the
 * rainbow line, no glow. Round shapes are kept for knobs and LED dots, as on the hardware. Seventies meters: green,
 * yellow, orange, red segments. V2 stage 4b-1: these names now alias tokens.css (the source of truth) instead of
 * hardcoded hex, so every selector below repaints from the real tokens without being rewritten one by one. */
:root {
  /* mask-fade (Benjamin 10-24): every fade in the UI is an alpha mask on the content it fades (never a black layer laid over
     it), so it works over any page background. These are the sizes (a theme can change them) and the page background itself
     (the one layer the fades reveal; body::before paints it). Stop curves: FADE_A in ui.js / the stops below. */
  --fade-t: 40px;          /* the stage's top fade (#pages) */
  --fade-grid-b: 48px;     /* the pinned Library grid's bottom fade, at most (and 18 % of the grid) */
  --fade-grid-t: 40px;     /* ...its top fade, at most (and 16 % of the grid) */
  --fade-perf-r: 60px;     /* the HIDE KEYS strip's right fade */
  --fade-perf-l: 32px;     /* ...its left fade */
  --fade-side-b: 28px;     /* the Library rail / side column, bottom fade */
  --fade-side-t: 20px;     /* ...top fade */
  --page-bg: #000 url(../img/sky-fade.png) repeat-x 0 0 / 64px 100%;   /* the night sky: pure black to a dark blue at the very bottom */
  --scrim: rgba(0,0,0,.75); /* a modal's dim (Help): meant to darken what is under it, not a fade */
  --space: var(--black);
  --ring: var(--line-2);   /* neutral, inactive outlines */
  --dim: var(--ink-3);     /* the text floor */
  --lav: var(--ink-2);     /* labels */
  --bone: var(--ink);      /* primary text */
  --glow: var(--value);    /* values (the roll's own playhead points at --playhead directly instead) */
  --blood: var(--rec);     /* record / clip / arm, one red */
  --y: var(--meter-hot); --g: var(--meter-ok);   /* VU-ladder colours still used standalone */
  --pc: var(--lav);        /* the plate's page colour */
  --lw: var(--bw);         /* integer border (Benjamin: crisp text, integer borders) */
  color-scheme: dark;
}
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }   /* Benjamin 10-20: iOS must never auto-inflate text (esp. on rotate) */
* { box-sizing: border-box; border-radius: 0 !important; box-shadow: none !important; text-shadow: none !important; }
html, body { margin: 0; height: 100%; background: var(--space); overflow: hidden; }
/* ui-batch1 (Benjamin, iPhone): scrolling to the end of a tab gave Apple's bounce and then a second snap. The stage's
   scroller let the leftover momentum chain out to the page itself, which iOS rubber-bands on its own (toolbar and
   visual viewport included: our resize handlers then re-fit the frame mid-bounce). Nothing chains out any more: the page
   never overscrolls, and every inner scroller keeps its own bounce (contain) and ends there */
html, body { overscroll-behavior: none; }
body { font-family: var(--font-body), system-ui, sans-serif; color: var(--bone); -webkit-font-smoothing: antialiased; }
button { font: inherit; color: inherit; }
#sky { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }
/* space zoo (Benjamin 10-24): the animals' canvas, in front of the sky's stars (later in tree order at the same level) and
   behind #frame (z-index 1), so every piece of UI is above it; it only shows in the letterbox and the UI's see-through gaps.
   Nothing translucent and black sits over it any more: the stage's scroll fades are a mask on #pages (see #pages.pf below) */
#zoo { position: fixed; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; z-index: 0; }
/* sky-bg (Benjamin 10-21, his starfield photo): the page fades from pure black into a dark night-sky blue (#040813) at the
   very bottom. A fixed full-viewport layer under the star canvas (first in paint order, so it sits behind #sky and #frame),
   not background-attachment: fixed, which iOS Safari ignores. The fade is a pre-dithered PNG (tools/make_sky_fade.py)
   so the ~19 blue levels never show as bands on an 8-bit OLED; plates stay transparent and the black-filled cards stay black. */
body::before { content: ""; position: fixed; inset: 0; pointer-events: none; background: var(--page-bg); }
/* 4c-6: the interface frame. JS (Frame.fit) sets its rect: the largest 16:9 (landscape) / 9:16 (portrait) box inside
   the safe area (env() read from #safe, iOS's one-sided landscape inset mirrored, a 44px floor for env()=0 on a phone
   in landscape), centred; the sky shows in the letterbox. Before JS runs it fills the safe area. contain makes it the
   containing block of every position:fixed thing inside (stage, fade, scroll line, overlays, book, tip, toast);
   container-type makes it the size every band below keys off (@container frame); overflow clip: nothing escapes. */
#frame { position: fixed; z-index: 1; overflow: clip; contain: layout paint; container: frame / size;
  top: env(safe-area-inset-top, 0px); bottom: env(safe-area-inset-bottom, 0px);
  left: max(env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px)); right: max(env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px));
  --safe-t: 0px; --safe-r: 0px; --safe-b: 0px; --safe-l: 0px; }
#stage { position: fixed; inset: 0; }
body.off #stage { visibility: hidden; }
/* ---------- the layout: three fixed regions, header / stage / deck (V2 stage 4a, R§1) ---------- */
#board { position: absolute; inset: 0; display: flex; flex-direction: column; min-height: 0; font-feature-settings: "tnum" 1, "ss01" 1; }
.rainbow-line { background: var(--rainbow-fallback); background: var(--rainbow); }   /* smooth blend, never stepped (Benjamin) */
button:focus-visible, .ctl:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }

/* type: titles and controls in bold capitals; prose stays in sentence case */
.ttl { font-family: var(--font-head); font-weight: 800; text-transform: uppercase; letter-spacing: var(--track-head); white-space: nowrap; line-height: 1; }
.lab, .val, .cap, .seg button, .pill, .hbtn, .x, .tab, .rowlabel, .stat, .pm .n, .pm .s, .cats button span, .stepper .nm, .stepper .cap,
.tile .nu, .tile .bn, .tile .dv, .typegrid button, .rootkeys button, .play-big, .songstrip i, .rsay, .pk span, .wheel span, .klab, #ticker,
.book-group h4, .bk-item b, select.sel, kbd, #tip, .scope-note { text-transform: uppercase; letter-spacing: .04em; }

/* ---------- the header (HEADER region: logo, tabs, status; never scrolls, R§1) ---------- */
#bar { position: relative; flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  padding: 10px max(var(--page-gutter), var(--safe-r)) 10px max(var(--page-gutter), var(--safe-l));
  padding-top: max(10px, var(--safe-t)); min-height: var(--hit); }
#bar::after { content: ""; position: absolute; left: 0; right: var(--bar-end, 0px); bottom: 0;   /* --bar-end: ends at the scroll line's outer edge (updateFade) */ height: var(--bw-bold); z-index: 6;   /* over the stage's scroll line (5), which starts under it */
  background: var(--rainbow-fallback); background: var(--rainbow); }   /* the app's one rainbow horizon (D11) */
.brand { display: flex; align-items: center; gap: 10px; flex: none; }
.maker { font-size: 11px; font-weight: 800; color: var(--lav); letter-spacing: .3em; white-space: nowrap; }
#tabs { display: flex; gap: 4px; flex: none; align-items: center; flex-wrap: wrap; }
/* VOICES' sub-tabs (4c-2): the tabs' own look, one full-width row as the sub-page's first cell */
.subtabs { display: flex; gap: 4px; flex-wrap: wrap; grid-column: 1 / -1; min-width: 0; }
.subtab { flex: 1 1 0; justify-content: center; min-width: 0; padding: 0 6px; }
.subtab:not(.on) { color: var(--tc); font-weight: 800; }   /* colour pass: the sub-tab colours all read >= 8:1 now, no white mixed in */   /* audit-fix: the inactive labels lifted (Model was #267FB3 on black, readable but dim) */
.subtab.on { color: #000; }
.tab { height: var(--hit); min-width: var(--hit); border: var(--lw) solid var(--tc); background: transparent; padding: 0 6px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 6px; color: var(--tc); font-size: 12px; }
.tab svg { width: 15px; height: 15px; color: var(--tc); display: none; }
.tab.on svg { display: none; }
.tab .ttl { font-size: 12px; }
.tab .ttl .code { display: none; }
/* hdr-1 (Benjamin 10-21): the three-letter codes (PAT PLY VOX MOD FX MST) on every phone-sized frame, either way up:
   under 1000 wide, or a short (landscape phone) frame. Bigger frames keep the full names */
@container frame (max-width: 999px) or (max-height: 500px) {
  .tab .ttl .full { display: none; } .tab .ttl .code { display: inline; }
}
#stat-midi > span { display: inline-block; max-width: 74px; overflow: hidden; text-overflow: ellipsis; vertical-align: bottom; }
.tab:hover { outline: var(--lw) solid var(--tc); outline-offset: 1px; }
.tab.on { background: var(--tc); }
.tab.on svg, .tab.on .ttl { color: #000 !important; }
.tab .k { display: none; }
.ticker { flex: 1; min-width: 96px; height: 30px; display: flex; align-items: center; justify-content: center; border: var(--lw) solid var(--tk, var(--ring)); font-family: var(--font-seg14), var(--font-body); font-size: 13px; font-weight: 850; letter-spacing: var(--track-seg); text-transform: uppercase; white-space: nowrap; overflow: hidden; color: var(--tk, var(--bone)); padding: 0 12px; }   /* 4d-3: --tk = the patch's category colour (ui.js tickerColour) */
#ticker { display: inline-block; transition: opacity .4s; overflow: hidden; text-overflow: ellipsis; }
#ticker.off { opacity: 0; }
.status { display: flex; align-items: center; gap: 8px; flex: none; }
/* 4d-2b (Benjamin): a mini rainbow spectrum where the CPU meter was: the ticker's height, a square outline like the
   ticker's, solid bars red (lows) to violet (highs) on black (drawMiniSpec in ui.js, the Master spectrum's data) */
.minispec { display: block; flex: none; width: 64px; height: 30px; border: var(--lw) solid var(--ring); background: #000; }
.stat { font-size: 11px; font-weight: 800; display: inline-flex; align-items: center; gap: 6px; color: var(--lav); white-space: nowrap; }
.stat .dot { width: var(--led); height: var(--led); border: var(--lw) solid var(--dim); display: inline-block; }   /* D18: square LED */
.stat.on .dot { background: var(--g); border-color: var(--g); }
.stat.blink .dot { background: var(--y); border-color: var(--y); }
/* 4d-2a: the CPU monitor (engine load + output LEDs) moved from the header into MASTER > System */
.sys-load { display: flex; align-items: center; gap: 10px; height: var(--hit); padding: 0 10px; margin-bottom: 8px; border: var(--lw) solid var(--pc); background: #000; }
.sys-load .lab { font-size: 11px; font-weight: 800; color: var(--pc); margin: 0; }
.sys-cpu { min-width: 4ch; text-align: right; font-family: var(--font-seg7), var(--font-body); font-size: 13px; font-variant-numeric: tabular-nums; letter-spacing: var(--track-seg); color: var(--pc); }
.sys-load .minivu { display: block; flex: none; width: 74px; height: 16px; margin-left: auto; }   /* 148x32 buffer at 2x: never stretched */
.hbtn { background: transparent; border: var(--lw) solid var(--ring); min-height: var(--hit); padding: 0 11px; display: inline-flex; align-items: center; justify-content: center; text-align: center; font-size: 11px; font-weight: 800; cursor: pointer; color: var(--lav); }
.hbtn.icon { width: var(--hit); padding: 0; display: inline-grid; place-items: center; font-size: 14px; font-weight: 900; }
.hbtn:hover, .hbtn.on { border-color: var(--bone); color: var(--bone); }

/* ---------- pages and plates: plain outlined rectangles ---------- */
/* STAGE: the only scroller (R§1.1-2), one axis, safe-area padding left/right (R§1.6) */
/* 4d-3 (Benjamin): the bottom padding is the fade's height plus a gap, so scrolled fully down the last row of cells rests
   above .stage-fade-b with its whole outline solid (every band, keys shown or hidden; checks/s4d3/tools/bottom.py) */
/* 4d-3e (Benjamin 10-20): the cells' right outline sits as far from the scroll line as their top outline sits below the
   header's rainbow line (--pad-t): --gap-r widens the right padding by that minus the 3px the line always had, and
   updateFade puts the line at the padding's old place (content edge + --pad-t), so the line and the corner don't move */
#pages { --fade-b: 56px; --pad-t: var(--s-1); --gap-r: calc(var(--pad-t) - 3px); position: relative; flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; touch-action: pan-y; overscroll-behavior: contain;
  padding: var(--pad-t) calc(max(var(--page-gutter), calc(var(--safe-r) + 2 * var(--progress-w))) + var(--gap-r)) calc(var(--fade-b) + 6px) max(var(--page-gutter), var(--safe-l));
  scrollbar-width: none; }   /* 4c-4: the rainbow line is the stage's scroll indicator; the right padding always keeps room for it inside the safe area */
#pages::-webkit-scrollbar { display: none; }
.page { display: none; gap: var(--cell-gap); grid-template-columns: repeat(12, minmax(0, 1fr)); grid-auto-rows: minmax(120px, 1fr); }
.page.on { display: grid; }
/* the stage melts under the deck instead of being chopped (Benjamin, matches the main site's nav scrim feel):
   position:fixed, sized and placed from #pages' own rect by JS (updateFade in ui.js) so it stays flush with the
   stage's visible bottom edge regardless of #pages' layout mode (grid/flex) or its own padding; pointer-events:none
   so it never blocks a tap; hidden (opacity 0) unless the stage can scroll further down. Eased stops, not a hard step. */
.stage-fade { display: none; }   /* (space zoo: the fades are a mask on #pages now, below; the two elements stay as the geometry updateFade reads) */
/* 4c-4: the main site's rainbow scroll-progress line (benventions site.css .progress v2): one per scroller (the stage,
   Help), placed by JS (updateFade / Help), 3px, the logo spectrum, clip-path fill, no track, never a target */
.progress { position: fixed; z-index: 5; width: var(--progress-w); pointer-events: none; overflow: hidden; contain: strict; visibility: hidden; }
.progress.on { visibility: visible; }
.progress span { position: absolute; inset: 0; background: var(--spectrum-up); clip-path: inset(0 0 100% 0); }   /* violet at the top (Benjamin) */
/* 4d-2b: its mirror under the header's rainbow line, faded in by the showing view's own scroll (updateFade); no CSS
   transition: the scroll itself is the animation, and a tab switch to an unscrolled view drops it at once */
/* space zoo (Benjamin 10-24, "layered above all of our drop shadow black gradients"): the stage's two fades are no longer black
   boxes laid over #frame's content (they darkened whatever sat under them, the animals included). They are a mask on #pages
   itself, the same eased stops (FADE_A in ui.js) with the alpha inverted, so the controls melt away exactly as before while
   the sky, and the space zoo behind the UI, show through at full strength. updateFade sets --pf-b (the bottom fade, 0 or 1,
   eased in .2s as the old box's opacity was), --pf-t (the top fade, 0..1, smoothstep of the scroll) and --pf-x/y/w (the top
   fade's box in #pages' coordinates; it is narrower than #pages under the pinned Library head) and keeps .pf on #pages only
   while a fade is showing. Three mask layers, composited bottom-up with "exclude": solid, minus the top fade, minus the bottom fade. */
@property --pf-b { syntax: "<number>"; inherits: false; initial-value: 0; }
@property --pf-t { syntax: "<number>"; inherits: false; initial-value: 0; }
#pages { transition: --pf-b .2s; }
#pages.pin-lib { transition: none; }   /* (mask-fade: pinned Library, --pf-b follows the scroll itself) */
@supports (mask-composite: exclude) {   /* (no mask support: no fade, rather than a wrong one) */
#pages.pf { --pf-x: 0px; --pf-y: 0px; --pf-w: 100%;
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,calc(var(--pf-b) * 1)) 0%, rgba(0,0,0,calc(var(--pf-b) * .94)) 10%, rgba(0,0,0,calc(var(--pf-b) * .84)) 20%, rgba(0,0,0,calc(var(--pf-b) * .69)) 32%, rgba(0,0,0,calc(var(--pf-b) * .52)) 44%, rgba(0,0,0,calc(var(--pf-b) * .35)) 56%, rgba(0,0,0,calc(var(--pf-b) * .2)) 68%, rgba(0,0,0,calc(var(--pf-b) * .09)) 80%, rgba(0,0,0,calc(var(--pf-b) * .025)) 92%, rgba(0,0,0,calc(var(--pf-b) * 0)) 100%), linear-gradient(to bottom, rgba(0,0,0,calc(var(--pf-t) * 1)) 0%, rgba(0,0,0,calc(var(--pf-t) * .94)) 10%, rgba(0,0,0,calc(var(--pf-t) * .84)) 20%, rgba(0,0,0,calc(var(--pf-t) * .69)) 32%, rgba(0,0,0,calc(var(--pf-t) * .52)) 44%, rgba(0,0,0,calc(var(--pf-t) * .35)) 56%, rgba(0,0,0,calc(var(--pf-t) * .2)) 68%, rgba(0,0,0,calc(var(--pf-t) * .09)) 80%, rgba(0,0,0,calc(var(--pf-t) * .025)) 92%, rgba(0,0,0,calc(var(--pf-t) * 0)) 100%), linear-gradient(#000, #000);
  mask-image: linear-gradient(to top, rgba(0,0,0,calc(var(--pf-b) * 1)) 0%, rgba(0,0,0,calc(var(--pf-b) * .94)) 10%, rgba(0,0,0,calc(var(--pf-b) * .84)) 20%, rgba(0,0,0,calc(var(--pf-b) * .69)) 32%, rgba(0,0,0,calc(var(--pf-b) * .52)) 44%, rgba(0,0,0,calc(var(--pf-b) * .35)) 56%, rgba(0,0,0,calc(var(--pf-b) * .2)) 68%, rgba(0,0,0,calc(var(--pf-b) * .09)) 80%, rgba(0,0,0,calc(var(--pf-b) * .025)) 92%, rgba(0,0,0,calc(var(--pf-b) * 0)) 100%), linear-gradient(to bottom, rgba(0,0,0,calc(var(--pf-t) * 1)) 0%, rgba(0,0,0,calc(var(--pf-t) * .94)) 10%, rgba(0,0,0,calc(var(--pf-t) * .84)) 20%, rgba(0,0,0,calc(var(--pf-t) * .69)) 32%, rgba(0,0,0,calc(var(--pf-t) * .52)) 44%, rgba(0,0,0,calc(var(--pf-t) * .35)) 56%, rgba(0,0,0,calc(var(--pf-t) * .2)) 68%, rgba(0,0,0,calc(var(--pf-t) * .09)) 80%, rgba(0,0,0,calc(var(--pf-t) * .025)) 92%, rgba(0,0,0,calc(var(--pf-t) * 0)) 100%), linear-gradient(#000, #000);
  -webkit-mask-size: 100% var(--fade-b), var(--pf-w) var(--fade-t), 100% 100%; mask-size: 100% var(--fade-b), var(--pf-w) var(--fade-t), 100% 100%;
  -webkit-mask-position: 0 100%, var(--pf-x) var(--pf-y), 0 0; mask-position: 0 100%, var(--pf-x) var(--pf-y), 0 0;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-composite: xor, xor, source-over; mask-composite: exclude, exclude, add; }
}
.plate { min-width: 0; grid-column: span 4; }
/* desktop and up: the named layouts below, each area a span of the 12 columns (R§3.C/D, "each plate declares a span") */
@container frame (min-width: 1280px) and (min-height: 720px) {
  /* 4c-2: the tabs (tabs6: six) and VOICES' 4 sub-pages (PLAN "Final plate placement"); `subs` is the sub-tab row. Rows that
     hold different kinds of cell are `auto` (each its own height); 1fr rows share the tallest one's height. */
  .page.patrick { grid-template-rows: auto auto; grid-template-areas: "lib lib lib lib lib lib lib lib lib lib lib lib" "pmac pmac pmac pmac pmac pmac pmac pmac pmac pmac pmac pmac"; }   /* (S6b: the macros' mirror under the Library) */
  .page.play { grid-template-rows: auto auto;
    grid-template-areas: "arp arp arp arp arp arp blk blk blk blk blk blk" "seq seq seq seq seq seq seq seq seq seq seq seq"; }
  /* tabs6 (Benjamin 10-22): LIFE is ANALOG's first cell, half the width (was the whole LIFE tab), right over the
     oscillators it moves; the two together are about as tall as the Mixer and the Filter beside them (the oscillators
     alone left ~250px of their row empty), so the page grows by little */
  /* Syn Rise S2: Pulse width under the oscillators (half width); Mixer and Filter run down beside it. S4: the Shape env
     beside Contours (half width each), Glide and Cross-mod under them (ANALOG: its 9 cells) */
  .page.analog { grid-template-rows: auto auto 1fr auto auto auto;
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "life life life life life life mix mix mix flt flt flt" "osc osc osc osc osc osc mix mix mix flt flt flt" "pwm pwm pwm pwm pwm pwm mix mix mix flt flt flt" "env env env env env env jenv jenv jenv jenv jenv jenv" "gld gld gld gld xm xm xm xm xm xm xm xm"; }
  .page.super { grid-template-rows: auto 1fr;
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "star star star star star star sco sco sco sco sco sco"; }
  /* UPGRADE: the DELUXE sub-tab: Poly-Moddy and Uni-son side by side, Brass-a-lot beside Release me, the Ribbon's settings last */
  .page.deluxe { grid-template-rows: auto auto auto auto;
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "pmd pmd pmd pmd pmd pmd uni uni uni uni uni uni" "brs brs brs brs brs brs rel rel rel rel rel rel" "rib rib rib rib rib rib rib rib rib rib rib rib"; }
  /* PAN: Fingers and Voice pan side by side, Auto-pan beside Cutoff > Pan, the oscillators' pans last */
  .page.pan { grid-template-rows: auto auto auto auto;
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "pfg pfg pfg pfg pfg pfg pvp pvp pvp pvp pvp pvp" "pap pap pap pap pap pap pcp pcp pcp pcp pcp pcp" "pop pop pop pop pop pop pop pop pop pop pop pop"; }
  .page.model { grid-template-rows: auto auto 1fr;
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "mdl mdl mdl mdl mdl mdl menv menv menv menv menv menv" "mdl mdl mdl mdl mdl mdl mvis mvis mvis mvis mvis mvis"; }
  .page.singers { grid-template-rows: auto 1fr 1fr;
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "sng sng sng sng sng sng fac fac fac vow vow vow" "sng sng sng sng sng sng stg stg stg vow vow vow"; }
  /* Syn Rise S7b: the PULSAR sub-tab: DCO (half width) beside Filter over DCO 2, the three mirrors in a row under them */
  .page.pulsar { grid-template-rows: auto auto 1fr auto auto;   /* (S8: FX › Chorus's mirror, a full-width row last) */
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "pdco pdco pdco pdco pdco pdco pflt pflt pflt pflt pflt pflt" "pdco pdco pdco pdco pdco pdco pdc2 pdc2 pdc2 pdc2 pdc2 pdc2" "ppwm ppwm ppwm ppwm pshp pshp pshp pshp plf2 plf2 plf2 plf2" "pens pens pens pens pens pens pens pens pens pens pens pens"; }
  /* Syn Rise S3: LFO 2 beside LFO 1 (the first row's four cells three columns each). S5: the Matrix, a full-width row last */
  .page.mod { grid-template-rows: auto auto auto auto auto auto;   /* (S6b: the Macros, a full-width row first; GOLDCHAIN: the MOD | GOLDCHAIN sub-tab row above) */
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "mac mac mac mac mac mac mac mac mac mac mac mac" "mod mod mod lfo lfo lfo lfo2 lfo2 lfo2 wh wh wh" "cyc cyc cyc cyc cyc cyc joy joy joy joy joy joy" "mvel mvel mvel mvel mmpe mmpe mmpe mmpe bnd bnd bnd bnd" "mtx mtx mtx mtx mtx mtx mtx mtx mtx mtx mtx mtx"; }
  /* GOLDCHAIN: the controller and the envelope over the steps and the detector, CHAINED down the right */
  .page.mod.sub-gch { grid-template-rows: auto auto 1fr;
    grid-template-areas: "subs subs subs subs subs subs subs subs subs subs subs subs" "gch gch gch gch gce gce gce gce gct gct gct gct" "gcs gcs gcs gcs gcs gcs gcd gcd gct gct gct gct"; }
  .plate[data-area="gch"] { grid-area: gch; } .plate[data-area="gce"] { grid-area: gce; } .plate[data-area="gcd"] { grid-area: gcd; } .plate[data-area="gcs"] { grid-area: gcs; } .plate[data-area="gct"] { grid-area: gct; }
  .page.fx { grid-template-rows: auto auto auto;
    grid-template-areas: "sv sv sv sv sv sv sv sv sv str str str" "sw sw sw sw sw sw sw sw sw rig rig rig" "fx fx fx fx fx fx spr spr spr spr spr spr"; }
  /* tabs6: MIX's engine strips are MASTER's first cell, beside the Output (volume, RAW / MASTERED, MONO); the monitor
     and System under them */
  .page.master { grid-template-rows: auto auto;
    grid-template-areas: "eng eng eng eng eng eng out out out out out out" "mon mon mon mon mon mon sys sys sys sys sys sys"; }
  .subtabs { grid-area: subs; }
  /* grid-area comes from CSS (not the inline style JS no longer sets), so the band-specific rules above win outright */
  .plate[data-area="eng"] { grid-area: eng; } .plate[data-area="gld"] { grid-area: gld; } .plate[data-area="bnd"] { grid-area: bnd; }
  .plate[data-area="lib"] { grid-area: lib; } .plate[data-area="mon"] { grid-area: mon; } .plate[data-area="out"] { grid-area: out; }
  .plate[data-area="fx"] { grid-area: fx; } .plate[data-area="sys"] { grid-area: sys; }
  .plate[data-area="osc"] { grid-area: osc; } .plate[data-area="pwm"] { grid-area: pwm; } .plate[data-area="jenv"] { grid-area: jenv; } .plate[data-area="mix"] { grid-area: mix; } .plate[data-area="flt"] { grid-area: flt; }
  .plate[data-area="env"] { grid-area: env; } .plate[data-area="mod"] { grid-area: mod; } .plate[data-area="lfo"] { grid-area: lfo; } .plate[data-area="lfo2"] { grid-area: lfo2; }
  .plate[data-area="mtx"] { grid-area: mtx; } .plate[data-area="mac"] { grid-area: mac; } .plate[data-area="pmac"] { grid-area: pmac; }
  .plate[data-area="star"] { grid-area: star; } .plate[data-area="xm"] { grid-area: xm; } .plate[data-area="sco"] { grid-area: sco; } .plate[data-area="wh"] { grid-area: wh; }
  .plate[data-area="life"] { grid-area: life; } .plate[data-area="cyc"] { grid-area: cyc; } .plate[data-area="joy"] { grid-area: joy; } .plate[data-area="spr"] { grid-area: spr; }
  .plate[data-area="sv"] { grid-area: sv; } .plate[data-area="str"] { grid-area: str; } .plate[data-area="sw"] { grid-area: sw; } .plate[data-area="rig"] { grid-area: rig; }
  .plate[data-area="mdl"] { grid-area: mdl; } .plate[data-area="mvis"] { grid-area: mvis; } .plate[data-area="menv"] { grid-area: menv; } .plate[data-area="mvel"] { grid-area: mvel; } .plate[data-area="mmpe"] { grid-area: mmpe; }
  .plate[data-area="seq"] { grid-area: seq; }
  .plate[data-area="sng"] { grid-area: sng; } .plate[data-area="fac"] { grid-area: fac; } .plate[data-area="vow"] { grid-area: vow; } .plate[data-area="stg"] { grid-area: stg; }
  .plate[data-area="blk"] { grid-area: blk; } .plate[data-area="arp"] { grid-area: arp; }
  .plate[data-area="pdco"] { grid-area: pdco; } .plate[data-area="pdc2"] { grid-area: pdc2; } .plate[data-area="pflt"] { grid-area: pflt; }
  .plate[data-area="ppwm"] { grid-area: ppwm; } .plate[data-area="pshp"] { grid-area: pshp; } .plate[data-area="plf2"] { grid-area: plf2; }
  .plate[data-area="pens"] { grid-area: pens; }
  .plate[data-area="pmd"] { grid-area: pmd; } .plate[data-area="uni"] { grid-area: uni; } .plate[data-area="brs"] { grid-area: brs; } .plate[data-area="rel"] { grid-area: rel; } .plate[data-area="rib"] { grid-area: rib; }   /* (UPGRADE: DELUXE) */
  .plate[data-area="pfg"] { grid-area: pfg; } .plate[data-area="pvp"] { grid-area: pvp; } .plate[data-area="pap"] { grid-area: pap; } .plate[data-area="pcp"] { grid-area: pcp; } .plate[data-area="pop"] { grid-area: pop; }   /* (PAN) */
}
/* 1920x1080 and up: same shapes, the whole stage width (4d-3f, Benjamin 10-20: the 1760px cap went, so the cells' right
   edge sits --pad-t from the scroll line at any width, like everywhere else); the Library's patch grid gains columns */
@container frame (min-width: 1800px) and (min-height: 1000px) {
  #pages { display: flex; justify-content: center; }
  /* at least the stage's height (rows stretch to fill it), never squeezed to it: a three-row tab (MOD, FX) scrolls */
  .page.on { width: 100%; align-self: flex-start; min-height: 100%; }
}
/* desktop: the left margin matches the right one (the gutter + --gap-r), the header's coin lines up with the cells */
@container frame (min-width: 1280px) and (min-height: 720px) {
  #pages { padding-left: calc(max(var(--page-gutter), var(--safe-l)) + var(--gap-r)); }
  #bar { padding-left: calc(max(var(--page-gutter), var(--safe-l)) + var(--s-1) - 3px); }   /* (= #pages' --gap-r) */
}
/* tablet / small laptop 600-1279: 2 columns, named areas dropped, plates auto-flow in priority order (R§3.C "tablet band gap") */
@container frame (min-width: 600px) and (max-width: 1279px) and (min-height: 501px) {
  /* auto (not 1fr): rows size to their own content so a capped-tall plate (the library) doesn't drag its
     row-mates up to match it the way flexible tracks do in a content-sized grid */
  .page { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-areas: none !important; grid-auto-flow: row; grid-auto-rows: minmax(120px, auto); }
  .page .plate { grid-column: span 1; grid-area: auto; }
  .page .plate[data-wide] { grid-column: 1 / -1; }
}
/* phone landscape: 2-3 columns, whatever fits, never clipped (R§3.B, M8) */
@container frame (max-height: 500px) and (orientation: landscape) {
  .page { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); grid-template-areas: none !important; grid-auto-flow: row; grid-auto-rows: minmax(120px, auto); }
  .page .plate { grid-column: span 1; grid-area: auto; }
  .page .plate[data-wide] { grid-column: 1 / -1; }
}
/* phone portrait: one column, cells stack in priority order (R§3.A) */
@container frame (max-width: 599px) {
  .page { grid-template-columns: 1fr; grid-template-areas: none !important; grid-auto-flow: row; }
  .page .plate { grid-column: 1; grid-area: auto; }
}
/* priority order for the auto-flow bands above: the DOM order itself (ui.js VIEW_AREAS, arrangePlates), so no
   per-area `order` rules. Wide cells that need full stage width even when columns are narrow (R§3.B, "wide editors
   get the full stage width"); the engine strips too (tabs6: LIFE, a compact cell now, takes one column). Scoped to the auto-flow bands only: desktop
   (1280+) keeps its named-area spans, set above, untouched. */
@container frame (max-width: 1279px) or ((max-height: 500px) and (orientation: landscape)) {
  .plate[data-area="lib"], .plate[data-area="seq"], .plate[data-area="eng"],
  .plate[data-area="sv"], .plate[data-area="sw"], .plate[data-area="mdl"], .plate[data-area="sng"], .plate[data-area="mtx"],
  .plate[data-area="mac"], .plate[data-area="pmac"], .plate[data-area="pmd"], .plate[data-area="uni"], .plate[data-area="brs"], .plate[data-area="rel"], .plate[data-area="rib"],
  .plate[data-area="pfg"], .plate[data-area="pvp"], .plate[data-area="pap"], .plate[data-area="pcp"], .plate[data-area="pop"] { grid-column: 1 / -1; }   /* (UPGRADE: DELUXE cells full width on narrow bands) */
  /* PLAY: ARP and BLOCKS half width each, side by side (two columns in every band), the sequencer full width below */
  .page.play { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* VOICES: the sub-tab row is its own height, not the 120px cell minimum (grid-auto-rows) */
  .page.analog, .page.super, .page.model, .page.singers, .page.pulsar, .page.deluxe, .page.pan { grid-template-rows: auto; }
  /* the 6-segment Star-mode switch (Super/Sub/Wave/Vox/FM/Casio): one row fits on a wide desktop plate but not a narrow column */
  .starmodes .seg { display: grid; grid-template-columns: repeat(3, 1fr); height: auto; width: 100%; }
  .starmodes .seg button { height: var(--hit); padding: 0 2px; font-size: 11px; }
  .plate .starmodes .seg button { min-width: 0; }   /* 4c-6: three to a row in a 225px column (still >=48px wide) */
  /* the vowel plate's canvas+controls split assumes room for a 330px first column; give it the full stage width */
  .plate[data-area="vow"] { grid-column: 1 / -1; }
  /* Blocks' top toolbar (stepper + Play blocks button) wraps instead of overflowing a narrower plate */
  .blk-top { flex-wrap: wrap; height: auto; gap: 8px 14px; white-space: normal; }
}
/* PLAY under ~760 px wide: ARP and BLOCKS stack (4c-6: was 700; Blocks' root keys need 7 x 48px + the cell's padding,
   which two half-width cells only have from 760: the 727px phone-landscape frame stacks) */
@container frame (max-width: 759px) { .page.play { grid-template-columns: minmax(0, 1fr); } }
.plate[data-area="sng"] .row { justify-content: space-between; }
.hmodes .seg button, .hcast .seg button, .facviews button { padding: 0 9px; }
.hstyles .seg { display: grid; grid-template-columns: repeat(4, 1fr); height: auto; }
.hstyles .seg button { height: var(--hit); }
.hrooms .seg, .hmoves .seg { display: grid; grid-template-columns: repeat(3, 1fr); height: auto; width: 100%; }
.hrooms .seg button, .hmoves .seg button { height: var(--hit); padding: 0 2px; font-size: 11px; }
.sngcap { margin-top: 6px; }
.sngwho { font-size: 11px; font-weight: 800; color: var(--pc); text-transform: uppercase; letter-spacing: .04em; margin-top: 4px; }
.sngnote, .vownote { min-height: 2.6em; }
.stagecv, .vowcv { touch-action: none; cursor: grab; display: block; }
.dice { height: var(--hit); min-width: var(--hit); align-self: center; }
.facviews button { height: var(--hit); font-size: 11px; padding: 0 5px !important; }
.mdtypes .seg { display: grid; grid-template-columns: repeat(3, 1fr); height: auto; width: 100%; }
.mdtypes { width: 100%; margin-bottom: 8px; }
.mdtypes .seg button { height: var(--hit); padding: 0 4px; }
/* grids of choices (Model types, Star modes, Synth Wah types, Sing styles/rooms/moves): every cell has its own full
   outline and overlaps its neighbours by one border, instead of the group's outline plus inner left/top rules, so a
   short last row still closes every cell above it (4c-3: Bell and Bowed had no bottom edge over the empty cells) */
.mdtypes .seg, .starmodes .seg, .swtypes .seg, .hstyles .seg, .hrooms .seg, .hmoves .seg { border-width: 0; padding: var(--lw) 0 0 var(--lw); align-content: start; }
.mdtypes .seg button, .starmodes .seg button, .swtypes .seg button, .hstyles .seg button, .hrooms .seg button, .hmoves .seg button {
  border: var(--lw) solid var(--pc); margin: calc(-1 * var(--lw)) 0 0 calc(-1 * var(--lw)); }
.sqbar { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; }
.sqbar .seg button { padding: 0 8px; }
.seqplay { min-width: 76px; height: var(--hit); font-size: 12px; }
.seqplay.on { background: var(--pc); color: #000; }
.sqstep { display: flex; align-items: center; gap: 4px; }
.sqstep b { min-width: 26px; text-align: center; font-size: 13px; color: var(--pc); }
.sqstep .pill { width: var(--hit); padding: 0; height: var(--hit); }
.sqpresets { display: flex; gap: 6px; margin: 8px 0 6px; flex-wrap: wrap; }
.sqpresets .pill { height: var(--hit); padding: 0 9px; }
.sqgrid { display: grid; grid-template-columns: repeat(16, 1fr); gap: 8px 4px; }
.sqcol { display: flex; flex-direction: column; align-items: center; gap: 4px; border: var(--lw) solid transparent; padding: 3px 0; }
.sqcol.now { border-color: var(--pc); }
.sqcol.off { opacity: .3; }
.sqnum { font-size: 11px; font-weight: 800; color: var(--lav); }
.sqon { width: 48px; height: 48px; }
.sqon.on::after { background: var(--pc); }
.sqnote { width: 100%; text-align: center; font-size: 11px; font-weight: 850; color: var(--bone); padding: 4px 0; border: var(--lw) solid var(--pc); cursor: ns-resize; touch-action: none; white-space: nowrap; user-select: none; }
.sqlanes button { padding: 0 8px; }
.sqlane { cursor: crosshair; touch-action: none; }
.seqmode[hidden] { display: none !important; }
.seqmodes button, .mdeng .seg button { padding: 0 10px; height: var(--hit); }
.rollbar { gap: 8px; flex-wrap: wrap; }
.rollbar .cap { margin-left: 4px; }
.rollrec.on { background: var(--rec); border-color: var(--rec); color: #000; }   /* D2: one record red */
.rollcv { touch-action: none; cursor: crosshair; display: block; }
.rolllane { touch-action: none; cursor: crosshair; display: block; }
.rollhint { color: var(--lav); text-transform: none; letter-spacing: 0; font-weight: 600; }
.rlanes button { padding: 0 8px; }
.seqmode.roll { position: relative; }
.rollpats { position: absolute; left: 0; right: 0; top: 70px; z-index: 5; background: #050208; border: var(--lw) solid var(--pc); padding: 10px 12px; max-height: 360px; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
.rollpats[hidden] { display: none; }
.pathead { display: flex; gap: 14px; align-items: center; margin-bottom: 8px; }
.patnote { flex: 1; font-size: 11px; color: var(--bone); min-height: 2.4em; line-height: 1.3; }
.patsnd { display: flex; align-items: center; gap: 4px; white-space: nowrap; }
.patcols { display: grid; grid-template-columns: repeat(7, 1fr); gap: 10px 10px; }
.patcol { display: flex; flex-direction: column; gap: 4px; }
.patcol b { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--pc); margin-bottom: 2px; }
.patcol .pill { height: var(--hit); text-align: left; padding: 0 8px; font-size: 11px; }
.swtypes .seg { display: grid; grid-template-columns: repeat(4, 84px); height: auto; }
.swtypes .seg button { height: var(--hit); padding: 0 4px; }
.rigs { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.rigs .pill { width: 100%; height: var(--hit); }
.chain { display: flex; align-items: center; gap: 5px; margin-top: 10px; font-size: 11px; font-weight: 900; text-transform: uppercase; letter-spacing: .05em; color: var(--bone); }
.chain i { font-style: normal; color: var(--lav); }
.chain { flex-wrap: wrap; margin-top: 3px; gap: 8px 4px; }
.chain .chip { border: var(--lw) solid; padding: 3px 5px; font-family: var(--font-seg14), var(--font-body); font-size: 11px; letter-spacing: var(--track-seg); }
.chain .chip.off { color: var(--ink-3); border-color: var(--ink-3); border-style: dashed; }
.chain .swap { background: none; border: var(--lw) solid var(--lav); color: var(--bone); font-weight: 900; min-height: var(--hit); min-width: var(--hit); cursor: pointer; padding: 0 3px; font-size: 11px; }
.chain .swap:hover { border-color: var(--bone); }
.plate .cap { font-size: 11px; color: var(--lav); font-weight: 750; }
/* tabs6: LIFE as a compact cell. The dial and the drift scope share a row while both fit; a narrower cell puts the
   scope (its full 280px or the cell's width) under the dial */
.life-row { flex-wrap: wrap; }
.life-side { flex: 1 1 180px; min-width: 0; }
.life-row .life-note { flex: 1 1 220px; min-width: 0; margin: 0; }
.life-read { font-size: 11px; font-weight: 800; color: var(--pc); margin-top: 6px; text-transform: uppercase; letter-spacing: .04em; line-height: 1.3; min-height: 2.6em; }   /* wraps beside the 144px Life dial on a phone */
.joypad { position: relative; width: 172px; height: 172px; flex: none; border: var(--lw) solid var(--pc); cursor: crosshair; touch-action: none; }
.joypad .jx, .joypad .jy { position: absolute; background: var(--pc); opacity: .35; }
.joypad .jx { left: 0; right: 0; top: 50%; height: var(--lw); }
.joypad .jy { top: 0; bottom: 0; left: 50%; width: var(--lw); }
.joypad b { position: absolute; width: 18px; height: 18px; margin: -9px; border: 2px solid var(--pc); left: 50%; top: 50%; }
/* audit-fix 10-22: CRASH is an action like any other: the outlined pill (fills only while it rings) */
.crash { flex: none; align-self: center; }
.crash:hover, .crash.on { background: var(--pc); color: #000; }
.plate { position: relative; background: transparent; border: var(--lw) solid var(--pc); padding: 8px 13px 6px; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.plate-body { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 10px; overflow: hidden; }
/* the pedal rack's chain row grew with the 48px swap buttons; this plate's row-mates are often taller (the
   Schaffer diagram), so its own grid row doesn't always get enough fr-share (same fr-equalization quirk as the
   library grid, 4a.1) -- it scrolls internally rather than clip (R§1.2 applied at plate scale) */
.plate[data-area="rig"] .plate-body { overflow-y: auto; overscroll-behavior: contain; }
/* the head grows to fit a 48px control parked in it (Free/Sync, Piano roll/Steps, Engine, Face views) and wraps it
   onto its own line when the title leaves no room, so nothing hangs outside the cell (4c-3) */
.plate-head { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 9px; min-height: 24px; flex: none; position: relative; margin-bottom: 8px; }
.plate-head > span { max-width: 100%; min-width: 0; flex-wrap: wrap; }
.plate-head .seg { flex: 0 1 auto; min-width: 0; max-width: 100%; }
.plate-head::after { content: ""; position: absolute; left: 0; right: 0; bottom: -5px; height: var(--bw);
  background: var(--pc); }   /* a module-colour title rule, not a rainbow (D11: one rainbow horizon, under the tab bar) */
.plate-head .mark { width: 20px; height: 20px; flex: none; color: var(--pc); }
.plate-head h2 { margin: 0; line-height: 1; }
.plate-head h2 .ttl { font-size: 16px; color: var(--pc); }
/* a row of knobs that doesn't fit wraps (every band) instead of being clipped by .plate-body's overflow:hidden (M8) */
.row { display: flex; align-items: flex-start; flex-wrap: wrap; row-gap: 14px; }
.rowlabel { width: 22px; flex: none; font-size: 20px; font-weight: 900; line-height: 1; padding-top: 30px; color: var(--pc); }   /* level with the 80 px dials' centre */

/* ---------- knobs: a circle, its arc and its pointer, all in the plate's colour ---------- */
/* 4c-3 (Benjamin's iPhone review): dials twice the 4b size (40/34/32 -> 80/68/64 px), each cell wider than its dial
   so neighbours sit apart; rows wrap to fewer knobs and the plate grows (the stage scrolls). The hero dial (Life,
   Volume) was already 96 px: 144. Labels wrap at spaces instead of running into the next knob. */
.ctl { --dial: 80px; width: calc(var(--dial) + 28px); flex: none; display: flex; flex-direction: column; align-items: center; user-select: none; touch-action: none; cursor: ns-resize; }
.ctl.s { --dial: 68px; }
.ctl.xs { --dial: 64px; }
.ctl.huge { --dial: 144px; }
.ctl svg.dial { width: var(--dial); height: var(--dial); display: block; cursor: ns-resize; overflow: visible; }
.ctl .lab { font-size: 13px; font-weight: 750; color: var(--kc); margin-top: 6px; white-space: normal; text-align: center; max-width: 100%; line-height: 15px; letter-spacing: .02em; }
.ctl .val { font-family: var(--font-seg7), var(--font-body); font-size: 13px; font-weight: 800; letter-spacing: var(--track-seg); line-height: 18px; white-space: nowrap; min-height: 18px; max-width: 100%; color: var(--vc, var(--kc)); }
/* a word value ("Always", "Legato", "osc 3") gets Panel 700 tnum instead of the segment face (D7/readouts rule) */
.ctl .val.txt, .sw .val.txt { font-family: var(--font-body), sans-serif; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: normal; }
.ctl.huge .val { font-size: 16px; line-height: 20px; }
.ctl { --kc: var(--pc); }   /* Source identity / function code, set by controlColours() in ui.js; neutral controls inherit the cell. */
/* colour pass, scheme C: label, disc and track wear the identity (--kc); the value arc, pointer, lit tick and readout (.ctl
   .val above) wear the shared value scale (--vc, set by the knob's draw() from a 257-step table, valueColour() in ui.js) */
/* stroke widths in viewBox units: a touch thinner than 4b's so the doubled dial reads as line work (~2-4 px), not 5 */
.dial .disc { fill: none; stroke: var(--kc); stroke-width: 1.1; }
.dial .ptr { stroke: var(--vc, var(--kc)); stroke-width: 1.8; stroke-linecap: butt; }
.dial .trk { fill: none; stroke: var(--kc); stroke-opacity: .22; stroke-width: 1.8; }
.dial .arc { fill: none; stroke: var(--vc, var(--kc)); stroke-width: 1.8; stroke-linecap: butt; }
.dial .tk { stroke: var(--kc); stroke-opacity: .25; stroke-width: 1.2; }
.dial .tk.on { stroke: var(--vc, var(--kc)); stroke-opacity: 1; stroke-width: 2; }
.ctl.drag .disc, .ctl:hover .disc { stroke-width: 1.8; }

/* switches: a square key with an LED dot, like the hardware's. 4c-3: the cell is as wide as a knob's and the key sits
   centred where a dial would be (dial height minus the key, halved), so its label and value line up with the knobs' */
.sw { --dial: 80px; display: flex; flex-direction: column; align-items: center; width: calc(var(--dial) + 28px); flex: none; user-select: none; }
.sw.s { --dial: 68px; }
.sw > .stamp, .sw > .rec { margin-top: calc((var(--dial) - var(--hit)) / 2); margin-bottom: calc((var(--dial) - var(--hit)) / 2); }
.stamp { width: var(--hit); height: var(--hit); border: var(--lw) solid var(--pc); background: transparent; cursor: pointer; padding: 0; position: relative; }
.stamp { display: inline-grid; place-items: center; }
.stamp::after { content: ""; display: block; width: var(--led); height: var(--led); border: var(--lw) solid var(--pc); }   /* Benjamin 10-20: grid-centred (the 50%/-margin version rounded off-centre at Windows display scaling) */   /* D18: square LED */
.stamp.on::after { background: var(--pc); }
.sw .lab { font-size: 13px; font-weight: 750; color: var(--pc); margin-top: 6px; line-height: 15px; white-space: normal; text-align: center; max-width: 100%; letter-spacing: .02em; }
.sw .val { font-family: var(--font-seg7), var(--font-body); font-size: 13px; font-weight: 800; letter-spacing: var(--track-seg); line-height: 18px; color: var(--pc); white-space: nowrap; max-width: 100%; }
.seg { display: inline-flex; flex-wrap: wrap; border: var(--lw) solid var(--pc); min-height: var(--hit); flex: none; }
.seg button { border: 0; background: transparent; padding: 0 9px; font-size: 11px; font-weight: 800; cursor: pointer; min-width: var(--hit); min-height: var(--hit); color: var(--pc); }
.seg button + button { border-left: var(--lw) solid var(--pc); }
.seg button.on { background: var(--pc); color: #000; }
.seg button:hover:not(.on) { background: color-mix(in srgb, var(--pc) 16%, #000); }
.segctl { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.segctl .lab { font-size: 11px; color: var(--pc); font-weight: 750; }
.picto { display: inline-flex; flex-wrap: wrap; gap: 3px; }
.picto button { width: var(--hit); height: var(--hit); border: var(--lw) solid var(--pc); background: transparent; padding: 2px; cursor: pointer; }
.picto button svg { width: 100%; height: 100%; display: block; }
.picto button svg path { fill: none; stroke: var(--pc); stroke-width: 2.2; stroke-linejoin: miter; stroke-linecap: butt; }
.picto button.on { background: var(--pc); }
.picto button.on svg path { stroke: #000; }
/* Syn Rise S2: a knob that does nothing now (PW off Pulse, Spread outside the Voice modes): the floor ink, still legible */
.ctl.off { --kc: var(--ink-3) !important; --vc: var(--ink-3) !important; }
.rowlabel.off { color: var(--ink-3); }   /* (Syn Rise S4: Contours' A row while the Shape env drives the VCA) */
.ctl.later { --kc: var(--ink-3) !important; --vc: var(--ink-3) !important; }   /* (Syn Rise S5: a matrix value from a later build) */
/* Syn Rise S5: the Matrix's 8 rows wrap across the cell (three or four a line on a desktop, one on a phone); inside a row the
   Src | Dst pair and the Amount | Via | x pair wrap under each other when the row is narrower than both */
.mtx-rows { display: flex; flex-wrap: wrap; gap: 14px 28px; }
.mtx-row { display: flex; align-items: flex-start; min-width: 0; max-width: 100%; }
.mtx-ctls { display: flex; flex-wrap: wrap; row-gap: 10px; min-width: 0; }
.mtx-pair { display: flex; align-items: flex-start; flex: none; }
.mtx-x, .mac-x { align-self: center; min-width: var(--hit); height: var(--hit); padding: 0; margin-top: 8px; display: grid; place-items: center; }
.mtx-x svg, .mac-x svg { width: 16px; height: 16px; }
/* Syn Rise S6b: the Macros. Four columns (knob, name, Lanes n); the open macro's lane drawer under them, full width: its Home,
   then one row a lane (Target picker, Lo, Hi, Curve, x), "+ Lane". The ghost ring: a thin arc on the dial's outer edge in the
   knob's own colour at the effective value (no blur, no glow); the home: a tick. A switch's effective step: outlined */
.mac-row { align-items: flex-start; }
.mac-col { display: flex; flex-direction: column; align-items: center; gap: 4px; flex: none; }
.mac-name { min-height: var(--hit); min-width: var(--hit); max-width: 100%; padding: 0 8px; border: var(--lw) solid transparent; background: transparent; color: var(--bone);
  font: 800 13px var(--font-body), sans-serif; letter-spacing: .06em; white-space: pre; cursor: text; }
button.mac-name:hover, button.mac-name:focus-visible { border-color: var(--pc); outline: none; }
.mac-pname { display: grid; place-items: center; cursor: default; }
.mac-name-in { width: 9ch; min-height: var(--hit); padding: 0 8px; border: var(--lw) solid var(--pc); border-radius: 0; background: #000; color: var(--bone);
  font: 800 13px var(--font-body), sans-serif; letter-spacing: .06em; text-align: center; outline: none; }
.mac-lanes.solid { background: var(--pc); color: #000; }
.mac-drawer { border-top: var(--lw) solid var(--pc); padding-top: 10px; margin-top: 4px; display: flex; flex-direction: column; gap: 10px; }
.mac-dhead { font-size: 13px; font-weight: 800; color: var(--pc); text-transform: uppercase; letter-spacing: .05em; }
.mac-home { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.mac-lanes-rows { display: flex; flex-wrap: wrap; gap: 10px 28px; }
.mac-lane { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 4px; min-width: 0; max-width: 100%; }
.mac-lane[hidden], .mac-home[hidden], .mac-drawer[hidden] { display: none; }
.mac-tgt-w { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.mac-tgt-w .lab { font-size: 11px; font-weight: 750; color: var(--pc); }
select.sel.mac-tgt { max-width: 240px; text-overflow: ellipsis; }
.mac-lane.later .mac-tgt-w, .mac-lane.later .rowlabel { color: var(--ink-3); }
.mac-lane.later select.sel.mac-tgt { color: var(--ink-3); border-color: var(--ink-3); }
.mac-lane.later .ctl { --kc: var(--ink-3) !important; --vc: var(--ink-3) !important; }
.mac-add { align-self: flex-start; }
.mac-add.dis { opacity: .45; cursor: not-allowed; }
.mac-also { color: var(--pc); }
.dial .ghost { fill: none; stroke: var(--kc); stroke-width: 2px; vector-effect: non-scaling-stroke; stroke-linecap: butt; }
.dial .home { stroke: var(--kc); stroke-width: 1.2; stroke-linecap: butt; }
:is(.seg button, .picto button, .stamp).ghost { outline: 2px solid var(--pc); outline-offset: -5px; }
@container frame (max-width: 599px) { .mac-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); justify-items: center; } }   /* (phones: two by two) */
.seg button.on.ghost { outline-color: #000; }
/* 4d-3: desktop: the 7 waves as 4 + 3 (two hit rows, the knob's height), so Range, Wave, Tune and Vintage keep one row */
@container frame (min-width: 1280px) and (min-height: 720px) { .picto.n7 { display: inline-grid; grid-template-columns: repeat(4, var(--hit)); } }
.pictoctl { display: flex; flex-direction: column; align-items: flex-start; padding-top: 6px; }
.pictoctl .lab { font-size: 11px; color: var(--pc); font-weight: 750; margin-top: 6px; }
.pictoctl .lab b { color: var(--pc); font-weight: 800; font-size: 11px; margin-left: 4px; }
canvas.graph { display: block; width: 100%; max-width: 100%; }   /* never wider than its cell (an inline px width included) */

/* ---------- library ---------- */
/* Benjamin 10-25: the icon + name lockup is the top left of the header, the quote starts under the icon's left edge, the INIT
   tile is top right (the same size as the grid's tiles: --init-w, ui.js) */
.lib-now { display: grid; grid-template-columns: minmax(0, 1fr) var(--init-w, var(--tile)); gap: 2px 16px; align-items: start; padding-bottom: 10px; }
.lib-now > .pnamerow { grid-column: 1; grid-row: 1; }
.lib-now > .quote { grid-column: 1; grid-row: 2; }
.lib-now > .ssline { grid-column: 1; grid-row: 3; }
.lib-now > .init-tile { grid-column: 2; grid-row: 1 / 4; align-self: start; justify-self: end; width: var(--init-w, var(--tile)); aspect-ratio: 1 / 1; }
/* the INIT button (Benjamin 10-25): a faint grey box at the page's one line weight (--lw, the grid tiles' border) while idle, the
   rainbow box (.pm.rainbow.cur, below) once it is the loaded sound; no black fill behind the chrome band's glisten */
.plate[data-area="lib"] .lib-now > .init-tile { background: transparent; border-color: var(--line-2); }
.plate[data-area="lib"] .lib-now > .init-tile::after { mix-blend-mode: screen; }
/* the icon: line work only, no outline of its own, as tall as the name's type (--mk, ui.js fitName), the name's line weight */
.lib-now .bigmark { width: var(--mk, 56px); height: var(--mk, 56px); flex: none; overflow: visible; }
.lib-now .bigmark * { stroke-width: 2px; vector-effect: non-scaling-stroke; }
.lib-now .pname { font-family: var(--font-head); font-size: 40px; font-weight: 800; letter-spacing: var(--track-head); text-transform: uppercase; line-height: 0.95; outline: none; white-space: nowrap; overflow: hidden; }
.lib-now .pname[contenteditable="true"] { color: var(--glow); }
.pnamerow { display: flex; align-items: center; gap: 8px; min-width: 0; }
.edited-tag { font-size: 11px; font-weight: 800; color: var(--y); border: var(--lw) solid var(--y); padding: 1px 6px; letter-spacing: .06em; }
.lib-now .quote { font-size: 13px; line-height: 1.35; max-width: 54em; min-height: calc(2 * 1.35em); color: var(--pc); overflow-wrap: anywhere; }
.lib-now .quote cite { font-style: normal; color: var(--lav); font-size: 11px; font-weight: 800; white-space: nowrap; text-transform: uppercase; letter-spacing: .04em; }
/* save-state (Benjamin 10-24): the loaded slot's playing, one line under the quote (the wheel line's type; hidden: none), and
   the tile mark: three squares rising, the coin colour, crisp 1 px edges, bottom-right */
.lib-now .ssline { font-size: 11px; color: var(--pc); font-weight: 800; text-transform: uppercase; letter-spacing: .04em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.plate[data-area="lib"] .pm .ssmark { position: absolute; right: 3px; bottom: 3px; width: 11px; height: 9px; line-height: 0; }
.plate[data-area="lib"] .pm .ssmark svg { display: block; width: 11px; height: 9px; fill: currentColor; shape-rendering: crispEdges; }
.lib-actions { display: flex; gap: 6px; flex-wrap: wrap; padding-bottom: 10px; }
.pill { border: var(--lw) solid var(--pc); background: transparent; min-height: var(--hit); padding: 0 11px; font-size: 11px; font-weight: 800; cursor: pointer; white-space: nowrap; color: var(--lav); }
.pill:hover { background: color-mix(in srgb, var(--pc) 16%, #000); }
.pill.solid { background: var(--pc); color: #000; }
.sys-danger { display: flex; margin-top: 6px; }
.pill.hold { position: relative; overflow: hidden; }
.pill.hold .hold-label { position: relative; z-index: 1; }
.pill.hold .hold-fill { position: absolute; left: 0; top: 0; bottom: 0; width: 100%; background: var(--dim); transform: scaleX(0); transform-origin: left; z-index: 0; }
.pill.hold.holding .hold-fill { transition: transform var(--hold-ms, 1000ms) linear; transform: scaleX(1); }
.pill.hold.danger { border-color: var(--track); color: var(--dim); }   /* secondary at rest: the warning shows while held */
.pill.hold.danger .hold-fill { background: var(--blood); opacity: .5; }
.pill.hold.danger.holding { color: var(--bone); }
.cats { display: flex; flex-wrap: wrap; gap: 2px; padding: 2px 0 8px; }
/* 4d-3 (Benjamin): PRESETS keeps the LIBRARY head and the category tabs pinned at the top of the stage; only the grid
   scrolls under them. Sticky inside #pages (still the one scroller, so the fades and the rainbow line read it); black
   behind them, the head's top edge lit in the plate colour while pinned (.stuck), the top fade placed under them over
   the grid (updateFade). --lib-pin = the head's height (libPin in ui.js) */
/* sky-v2: the pinned Library head and category box stay opaque (cards scroll under them) but paint the same viewport-fixed
   fade as body::before, so they no longer read as black boxes on the bluer sky. iOS Safari draws "fixed" as scroll: there they
   show the fade's top (black) rows, i.e. what they looked like before. */
.plate[data-area="lib"] { --lib-top: 0px; --lib-pin: 40px; }
.plate[data-area="lib"] { --sky-fill: transparent; }   /* mask-fade: pinned, the grid scrolls on its own and nothing goes under the head or the tabs, so they are see-through and any page background shows */
.page.patrick:not(.pin-lib *) .plate[data-area="lib"] { --sky-fill: #000 url(../img/sky-fade.png) repeat-x 0 0 / 64px 100vh fixed; }   /* (the sticky mode is not reached today: the Library is always pinned; kept as it was, an opaque head matching the sky) */
.plate[data-area="lib"] > .plate-body { overflow: visible; }
.plate[data-area="lib"] > .plate-head { position: sticky; top: var(--lib-top); z-index: 3; background: var(--sky-fill); margin: -8px -13px 3px; padding: 8px 13px 5px;
  border-top: var(--lw) solid transparent; }
.plate[data-area="lib"] > .plate-head::after { left: 13px; right: 13px; bottom: 0; }
.plate[data-area="lib"] > .plate-head.stuck { border-top-color: var(--pc); }
.plate[data-area="lib"] .pm { scroll-margin-top: var(--lib-cover, 0px); }   /* scrolled into view: clear of what is pinned */
.plate[data-area="lib"] .cats { position: sticky; top: calc(var(--lib-top) + var(--lib-pin)); z-index: 3; background: var(--sky-fill); }
.cats button { flex: 1; min-width: var(--hit); min-height: var(--hit); border: var(--lw) solid transparent; background: transparent; cursor: pointer; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; padding: 3px 0; }
.cats button svg { width: 22px; height: 22px; opacity: .55; }
.cats button span { font-size: 11px; color: var(--lav); font-weight: 800; opacity: .75; line-height: 1; }   /* centred by its ink, with the icon: opticalCentre() in ui.js */
.cats button.on, .cats button:hover { border-color: currentColor; }
.cats button.on svg, .cats button:hover svg { opacity: 1; }
.cats button.on span { color: currentColor; opacity: 1; }
/* 4c-4: no inner scroller. The bounded, overscroll-contained tile box (35vh / 60vh / 330px) trapped swipes on the
   tiles, so its last rows could stay under the deck (Benjamin); PATRICK holds only the Library since 4c-2, so the
   grid now grows and #pages is the one scroller (R§1.1). */
.grid-marks { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 64px; gap: 4px; }
.pm { border: var(--lw) solid transparent; background: transparent; cursor: pointer; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 3px; padding: 4px 2px 2px; min-width: 0; color: var(--lav); }
.pm svg { width: 26px; height: 26px; flex: none; }
.pm .n { font-size: 11px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; line-height: 13px; color: var(--bone); }
.pm .s { font-size: 11px; color: var(--dim); line-height: 11px; font-weight: 700; }
@media (hover: hover) { .pm:hover { border-color: var(--ring); } }   /* 4d-3g: no sticky touch hover (iOS kept it on whatever cell was under the finger) */
.pm.cur { border-color: currentColor; }
.pm.empty { cursor: default; opacity: .35; }

/* ---------- blocks ---------- */
/* audit-fix 10-22: the four steppers are equal columns (◀ name ▶, the name taking the rest), Play blocks / Pause after them */
.blk-top { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)) auto auto; align-items: end; gap: 8px 16px; min-height: 42px; margin-bottom: 4px; white-space: nowrap; padding-top: 2px; }
.blk-top .stepper { min-width: 0; }
.blk-top .stepper .nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; text-align: center; }
.blk-top .stepper .cap { padding-left: 0; text-align: center; }
.blk-top .play-big { margin-left: 0; }
.stepper { display: flex; flex-direction: column; gap: 2px; }
.stepper .cap { font-size: 11px; color: var(--lav); font-weight: 750; padding-left: 32px; }
.stepper .ctr { display: flex; align-items: center; gap: 6px; }
.stepper .nm { font-size: 13px; font-weight: 900; white-space: nowrap; color: var(--pc); }
.stepper .nm small { font-size: 11px; color: var(--pc); font-weight: 800; margin-left: 5px; }
.stepper .nm.btn { cursor: pointer; border-bottom: var(--lw) solid var(--pc); padding-bottom: 1px; }
.stepper .nm.btn:hover { color: var(--pc); }
.arrow { width: var(--hit); height: var(--hit); border: var(--lw) solid var(--pc); background: transparent; cursor: pointer; padding: 0; display: grid; place-items: center; flex: none; }
.arrow svg { width: 10px; height: 10px; }
.arrow svg path { fill: none; stroke: var(--pc); stroke-width: 2.4; }
.arrow:hover { background: var(--pc); }
.arrow:hover svg path { stroke: #000; }
.blk-main { display: grid; grid-template-columns: 1fr 352px; gap: 18px; flex: 1; min-height: 0; }
/* 4c-2: BLOCKS is half of PLAY now, so whether the chord editor fits beside the chords depends on the cell's own
   width, not the viewport's: under 720px the editor goes below them (as on a phone); the toolbar (four steppers,
   Play blocks, pause) needs ~1200px in one row, so under that it wraps */
.plate[data-area="blk"] { container-type: inline-size; }
@container (max-width: 1199px) { .blk-top { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 14px; } .blk-top .play-big { justify-self: stretch; } }
@container (max-width: 519px) { .blk-top { grid-template-columns: minmax(0, 1fr); } }
@container (max-width: 719px) { .blk-main { grid-template-columns: minmax(0, 1fr); gap: 14px; } }
.songstrip { display: flex; gap: 3px; height: 16px; margin-bottom: 6px; }
.songstrip i { flex: 1; border: var(--lw) solid var(--track); font-style: normal; font-size: 11px; font-weight: 800; color: var(--lav); display: flex; align-items: center; justify-content: center; overflow: hidden; white-space: nowrap; }
.songstrip i.pg { border-color: var(--pc); color: var(--bone); }
.songstrip i.now { background: var(--pc); border-color: var(--pc); color: #000; }
.tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.tile { position: relative; border: var(--lw) solid var(--pc); height: 86px; display: grid; cursor: pointer; background: transparent; overflow: visible; }
.tiles.song .tile { height: 70px; }
.tile.d1 { grid-template-columns: 1fr; }
.tile.d2 { grid-template-columns: 1fr 1fr; }
.tile.d4 { grid-template-columns: 1fr 1fr 1fr 1fr; }
.tile .cell { display: flex; flex-direction: column; justify-content: center; align-items: center; min-width: 0; padding: 12px 2px 4px; position: relative; }
.tile .cell + .cell { border-left: var(--lw) solid var(--pc); }
.tile .cell .ch { font-size: 25px; font-weight: 900; line-height: 1; white-space: nowrap; color: var(--pc); }
.tile.d2 .cell .ch { font-size: 20px; }
.tile.d4 .cell .ch { font-size: 14px; }
.tile .cell .ch sup { font-size: 0.5em; font-weight: 800; vertical-align: 0.75em; margin-left: 1px; color: var(--pc); }
.tile .cell .nu { font-size: 11px; color: var(--lav); font-weight: 800; margin-top: 3px; }
.tile .bn { position: absolute; left: 7px; top: 4px; font-size: 11px; font-weight: 900; z-index: 1; color: var(--pc); }
.tile .dv { position: absolute; right: 7px; top: 4px; font-size: 11px; font-weight: 800; color: var(--dim); z-index: 1; }
.tile .cell.play { background: var(--pc); }
.tile .cell.play .ch, .tile .cell.play .ch sup, .tile .cell.play .nu { color: #000; }
.tile .cell.sel::after { content: ""; position: absolute; left: 8px; right: 8px; bottom: 3px; height: 3px; background: var(--pc); }
/* audit-fix 10-22 (Benjamin): the selected block fills in the cell colour like every other selection (was a bone outline);
   on it the playing chord inverts (black, cell-colour ink) and the selected-chord bar turns black */
.tile.sel { border-color: var(--pc); background: var(--pc); }
.tile.sel .cell .ch, .tile.sel .cell .ch sup, .tile.sel .cell .nu, .tile.sel .bn, .tile.sel .dv { color: #000; }
.tile.sel .cell + .cell { border-left-color: #000; }
.tile.sel .cell.sel::after { background: #000; }
.tile.sel .cell.play { background: #000; }
.tile.sel .cell.play .ch, .tile.sel .cell.play .ch sup, .tile.sel .cell.play .nu { color: var(--pc); }
.beats { display: flex; gap: 4px; position: absolute; left: 0; right: 0; bottom: -9px; justify-content: center; }
.beats i { width: 5px; height: 5px; border: var(--bw-hair) solid var(--track); }   /* D18: square LED */
.beats i.on { background: var(--pc); border-color: var(--pc); }
.lanes { margin-top: 14px; height: 30px; }
.blk-edit { display: flex; flex-direction: column; gap: 6px; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.blk-edit .edit-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.blk-edit .cap { font-size: 11px; color: var(--lav); font-weight: 750; }
.blk-edit .seg button { padding: 0 8px; }
/* the root-note picker is a mini keyboard (V2 4c-1, >=48px every key): 14 half-columns, the 7 naturals span 2 each
   on the lower row, the 5 sharps span 2 on the upper row, offset by one (ui.js blkEdit's root list sets their
   grid-column), so every key is --hit square once the picker is >= 7 x --hit wide (the editor column is 352px) */
.rootkeys { display: grid; grid-template-columns: repeat(14, minmax(0, 1fr)); grid-template-rows: var(--hit) var(--hit); gap: 2px; min-width: calc(7 * var(--hit) + 12px); }
.rootkeys button { grid-row: 2; grid-column: span 2; border: var(--lw) solid var(--pc); background: transparent; cursor: pointer; font-size: 11px; font-weight: 800; padding: 0 0 3px; display: flex; align-items: flex-end; justify-content: center; color: var(--lav); }
.rootkeys button.blk { grid-row: 1; background: #000; color: var(--ink-2); }
.rootkeys button.on { background: var(--pc); color: #000; }
.typegrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3px; }
.typegrid button { border: var(--lw) solid var(--pc); background: transparent; height: var(--hit); font-size: 11px; font-weight: 800; cursor: pointer; padding: 0; color: var(--lav); }
.typegrid button.on { background: var(--pc); color: #000; }
.typegrid button:hover:not(.on) { background: color-mix(in srgb, var(--pc) 16%, #000); }
.play-big { white-space: nowrap; flex: none; height: var(--hit); border: var(--lw) solid var(--pc); background: transparent; color: var(--pc); font-weight: 900; font-size: 12px; padding: 0 12px; cursor: pointer; display: inline-flex; gap: 8px; align-items: center; justify-content: center; margin-left: auto; }
.play-big svg { width: 11px; height: 11px; }
.play-big svg path { fill: none; stroke: currentColor; stroke-width: 2.2; }
.play-big.on { background: var(--pc); color: #000; }
.pausebtn { margin-left: 0; min-width: 104px; }
.pausebtn:disabled { cursor: default; border-style: dashed; border-color: var(--ink-3); color: var(--ink-3); }   /* idle: the footswitch-off look, text at the 7.2:1 floor */

/* the progression book */
#book { position: fixed; z-index: 45; background: #000; border: var(--lw) solid var(--pc); padding: 18px 22px 16px; color: var(--bone); --pc: var(--cell-blk); width: 1160px; max-height: min(640px, calc(100cqh - 20px)); max-width: calc(100cqw - 20px); display: flex; flex-direction: column; }   /* the book opens from Play */
#book[hidden] { display: none; }
.book-head { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.book-head h3 { margin: 0; font-size: 20px; font-weight: 900; text-transform: uppercase; letter-spacing: .04em; color: var(--pc); }
.book-head p { margin: 0; font-size: 12px; color: var(--lav); max-width: 46em; }
.book-head .sp { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.book-cols { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0 18px; align-items: start; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: var(--ring) transparent; padding-right: 6px; }
.book-group { break-inside: avoid; margin-bottom: 12px; }
.book-group h4 { margin: 0 0 4px; font-size: 11px; font-weight: 900; color: var(--pc); }
.bk-item { display: block; width: 100%; min-height: var(--hit); text-align: left; border: var(--lw) solid transparent; background: transparent; padding: 3px 6px; cursor: pointer; color: var(--bone); }
.bk-item b { font-size: 12px; font-weight: 800; display: block; line-height: 15px; }
.bk-item span { font-size: 11px; color: var(--lav); display: block; line-height: 14px; overflow-wrap: anywhere; }   /* audit-fix: long progressions wrap at their bars */
.bk-item:hover { border-color: var(--ring); }
.bk-item.cur { border-color: var(--pc); }
.bk-item.cur b { color: var(--pc); }
.bk-note { font-size: 12px; color: var(--lav); margin: 10px 0 0; min-height: 16px; }

/* ---------- monitor: a stereo VU ladder and an LED spectrum ---------- */
.mon { display: grid; grid-template-columns: 112px minmax(0, 1fr); gap: 14px; flex: 1; min-height: 0; }
.mon canvas { display: block; max-width: 100%; }   /* the side column can be narrower than 150px (932x430: three plates a row) */
.voices { display: flex; gap: 4px; }
.voices i { width: 12px; height: 12px; background: color-mix(in srgb, var(--pc) var(--lvl-off), #000); }   /* dim solid, lit when the voice sounds (4c-3) */
.voices i.on { background: var(--pc); }
.voices i.off { opacity: .2; }
.mon-side { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.mon-side .cap { font-size: 11px; color: var(--lav); font-weight: 750; }
.mon-side .big { font-size: 12px; font-weight: 900; color: var(--pc); }
.rec { width: var(--hit); height: var(--hit); border: var(--lw) solid var(--blood); background: transparent; cursor: pointer; position: relative; padding: 0; }
.rec::after { content: ""; position: absolute; left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px; background: var(--blood); }   /* square: filled stop-style rec (V§4) */
.rec.on::after { animation: recblink 1s steps(2) infinite; }
@keyframes recblink { 50% { opacity: .35; } }
select.sel { appearance: none; border: var(--lw) solid var(--pc); background: transparent; min-height: var(--hit); padding: 0 24px 0 9px; font: 800 11px var(--font-body), sans-serif; color: var(--lav); max-width: 170px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23C9C4D6' stroke-width='1.6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: calc(100% - 8px) 50%; background-size: 9px 6px; }
select.sel option { color: var(--ink); background: #000; }   /* D16: no native white flash */

/* ---------- the deck (DECK region; fixed, never scrolls, R§1.1). V2 4c-1: ONE row of perf buttons on top (scrolls
   sideways inside itself if it's wider than the screen), the wheels and keys under it (--play-h per band); the
   keys toggle at the row's end folds wheels+keys away so the stage grows ---------- */
#deck { --play-h: 200px; position: relative; flex: none; display: flex; flex-direction: column;
  padding: 8px max(var(--page-gutter), var(--safe-r)) max(10px, var(--safe-b)) max(var(--page-gutter), var(--safe-l)); }
.deck-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* the 3px padding/-3px margin keeps the focus ring inside the scroller's clip */
.perf { flex: 1; min-width: 0; display: flex; gap: 6px; padding: 3px; margin: -3px; overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain; scrollbar-width: thin; scrollbar-color: var(--ring) transparent; touch-action: pan-x; }
.perf { touch-action: none; }
.keys-tog { flex: none; white-space: nowrap; }
/* UPGRADE: RIBBON-A-LOT, the pitch ribbon in the deck row: segments like the wheels, sharp edges, the middle gold */
.ribbon { flex: 0 0 clamp(100px, 24vw, 320px); height: var(--hit, 48px); min-height: 36px; position: relative; border: 2px solid #358AF2; background: #000; cursor: ew-resize; touch-action: none; user-select: none; -webkit-user-select: none; }
.ribbon canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.ribbon .rlab { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font: 800 11px/1 "Patrick Panel", sans-serif; letter-spacing: .14em; text-transform: uppercase; color: #000; background: #F6CF42; padding: 2px 6px; pointer-events: none; }
.ribbon:focus-visible { outline: 3px solid #F6CF42; outline-offset: 2px; }
@media (max-width: 520px) { .ribbon .rlab { display: none; } }
/* Benjamin 10-20 / audit-fix 10-22: the perf strip reads as a deliberate sideways scroller: HIDE KEYS stays pinned past a
   clean 8px gap, and while more buttons wait past the edge the strip itself fades to black over its last 56px (a mask,
   the same eased curve as the stage fade), so a cut button dissolves instead of stopping at a hard edge; scrolled away
   from its start it fades in on the left too */
.keys-tog { position: relative; }
.deck-row.perf-over .perf { -webkit-mask-image: linear-gradient(to left, rgba(0,0,0,0) 0, rgba(0,0,0,0) calc(var(--fade-perf-r) * 0.1), rgba(0,0,0,.08) calc(var(--fade-perf-r) * 0.2333), rgba(0,0,0,.3) calc(var(--fade-perf-r) * 0.4), rgba(0,0,0,.6) calc(var(--fade-perf-r) * 0.6), rgba(0,0,0,.86) calc(var(--fade-perf-r) * 0.8), rgba(0,0,0,1) var(--fade-perf-r));
  mask-image: linear-gradient(to left, rgba(0,0,0,0) 0, rgba(0,0,0,0) calc(var(--fade-perf-r) * 0.1), rgba(0,0,0,.08) calc(var(--fade-perf-r) * 0.2333), rgba(0,0,0,.3) calc(var(--fade-perf-r) * 0.4), rgba(0,0,0,.6) calc(var(--fade-perf-r) * 0.6), rgba(0,0,0,.86) calc(var(--fade-perf-r) * 0.8), rgba(0,0,0,1) var(--fade-perf-r)); }
.deck-row.perf-left .perf { -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,0) 0, rgba(0,0,0,.3) calc(var(--fade-perf-l) * 0.375), rgba(0,0,0,1) var(--fade-perf-l)); mask-image: linear-gradient(to right, rgba(0,0,0,0) 0, rgba(0,0,0,.3) calc(var(--fade-perf-l) * 0.375), rgba(0,0,0,1) var(--fade-perf-l)); }
.deck-row.perf-over.perf-left .perf { -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,0) 0, rgba(0,0,0,.3) calc(var(--fade-perf-l) * 0.375), rgba(0,0,0,1) var(--fade-perf-l), rgba(0,0,0,1) calc(100% - var(--fade-perf-r)), rgba(0,0,0,.86) calc(100% - calc(var(--fade-perf-r) * 0.8)), rgba(0,0,0,.6) calc(100% - calc(var(--fade-perf-r) * 0.6)), rgba(0,0,0,.3) calc(100% - calc(var(--fade-perf-r) * 0.4)), rgba(0,0,0,.08) calc(100% - calc(var(--fade-perf-r) * 0.2333)), rgba(0,0,0,0) calc(100% - calc(var(--fade-perf-r) * 0.1)));
  mask-image: linear-gradient(to right, rgba(0,0,0,0) 0, rgba(0,0,0,.3) calc(var(--fade-perf-l) * 0.375), rgba(0,0,0,1) var(--fade-perf-l), rgba(0,0,0,1) calc(100% - var(--fade-perf-r)), rgba(0,0,0,.86) calc(100% - calc(var(--fade-perf-r) * 0.8)), rgba(0,0,0,.6) calc(100% - calc(var(--fade-perf-r) * 0.6)), rgba(0,0,0,.3) calc(100% - calc(var(--fade-perf-r) * 0.4)), rgba(0,0,0,.08) calc(100% - calc(var(--fade-perf-r) * 0.2333)), rgba(0,0,0,0) calc(100% - calc(var(--fade-perf-r) * 0.1))); }
.deck-play { display: flex; gap: 12px; height: var(--play-h); margin-top: 8px; overflow: hidden;
  transition: height .18s ease-out, margin-top .18s ease-out, visibility 0s; }
#deck.keys-off .deck-play { height: 0; margin-top: 0; visibility: hidden;
  transition: height .18s ease-out, margin-top .18s ease-out, visibility 0s .18s; }
@media (prefers-reduced-motion: reduce) { .deck-play, #deck.keys-off .deck-play { transition: none; } }
.wheels { display: flex; gap: 8px; flex: none; }
.wheel { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 52px; }
.wheel .slot { width: 100%; flex: 1; min-height: 0; position: relative; cursor: ns-resize; touch-action: none; overflow: hidden; border: var(--lw) solid var(--ring); background: transparent; }
.wheel .slot canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.wheel .thumb { position: absolute; left: 3px; right: 3px; height: 14px; top: 60px; border: 2px solid var(--bone); background: #000; }
.wheel span { font-size: 11px; color: var(--lav); font-weight: 800; line-height: 12px; }
.pk { display: flex; flex: none; }
.pkb { min-width: var(--hit); height: var(--hit); flex-shrink: 0; border: var(--lw) solid var(--ring); cursor: pointer; position: relative; padding: 0 10px 0 25px; background: transparent; display: inline-flex; align-items: center; }
.pkb .lamp { position: absolute; left: 9px; top: 50%; width: 9px; height: 9px; margin-top: -4.5px; background: var(--lc); opacity: .25; transition: opacity .06s; }   /* D18: square LED */
.pkb.down { border-color: var(--lc); }
.pkb.down .lamp, .pkb .lamp.on { opacity: 1; }
.pk span { font-size: 11px; color: var(--lav); font-weight: 800; white-space: nowrap; }
.octro { height: var(--hit); align-items: center; gap: 6px; padding: 0 10px; border: var(--lw) solid var(--ring); }
.oct-ro { min-width: 2em; text-align: center; font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--glow); }   /* "+1": the body face */
#keys { position: relative; flex: 1; min-width: 0; touch-action: none; user-select: none; }
.sq { position: absolute; border: var(--lw) solid var(--ring); background: transparent; cursor: pointer; }
.sq.nat { border-color: var(--line-2); }   /* was #5B4B70 at 2.69:1, under the 3:1 non-text floor */
.sq.down { border-color: var(--kc); }
.led { position: absolute; left: 50%; top: 50%; width: 9px; height: 9px; margin: -4.5px; background: var(--kc); opacity: 0; pointer-events: none; }   /* D18: square LED */
.klab { position: absolute; font-size: 11px; color: var(--dim); font-weight: 800; pointer-events: none; transform: translateX(-50%); }
.klab.in { line-height: 11px; }

/* ---------- overlays ---------- */
.overlay { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: var(--safe-t) var(--safe-r) var(--safe-b) var(--safe-l); } /* above the toast (50): help/power cover it */
.overlay[hidden] { display: none; }
#power { background: transparent; cursor: pointer; }
.power-in { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 24px; max-width: 900px; padding: 40px; position: relative; }
.power-in .maker { font-size: 15px; letter-spacing: .45em; padding-left: .45em; }
#btn-power { background: transparent; color: var(--bone); border: 2px solid var(--bone); height: 52px; padding: 0 34px; font-size: 16px; font-weight: 900; cursor: pointer; text-transform: uppercase; letter-spacing: .12em; }
#btn-power:hover { background: var(--bone); color: #000; }
.power-fine { font-size: 13px; margin: 0; font-weight: 500; color: var(--lav); }
#power.leaving { transition: opacity .6s; opacity: 0; }
@media (prefers-reduced-motion: reduce) { #power.leaving { transition: none; } .drip { animation: none !important; } }
/* the blood: drops ooze from PATRICK's letters when it appears (flat blood red) */
.drip { transform-box: fill-box; transform-origin: top; animation: ooze 4.5s cubic-bezier(.5, 0, .3, 1) both; }
@keyframes ooze { from { transform: scaleY(0); } to { transform: scaleY(1); } }
.x { background: transparent; border: var(--lw) solid var(--ring); color: var(--lav); min-height: var(--hit); padding: 0 12px; font-size: 11px; font-weight: 800; cursor: pointer; }
.x:hover { border-color: var(--bone); color: var(--bone); }
#help { background: var(--scrim); }
/* 4c-4 Help: short tips, two to a row, headings in the colour of the tab/cell they describe (--hc); the body scrolls
   with its own rainbow line (Help in ui.js); a plain Close box top right, never over the text */
.help-in { background: #000; color: var(--bone); width: 900px; max-width: calc(100cqw - 16px); max-height: calc(100cqh - 16px);   /* 4c-6: the frame, not the viewport */
  position: relative; border: var(--lw) solid var(--ring); overflow: hidden; display: flex; flex-direction: column; }
.help-in::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: var(--bw-bold); background: var(--rainbow-fallback); background: var(--rainbow); }   /* the overlay's one flourish */
.help-top { flex: none; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 16px 10px 28px; }
.help-in h2 { font-size: 24px; font-weight: 900; text-transform: uppercase; letter-spacing: .04em; margin: 0; }
.help-in .x { flex: none; min-width: var(--hit); min-height: var(--hit); font-size: 12px; }
.help-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; scrollbar-width: none;
  padding: 4px calc(2 * var(--progress-w) + 22px) 20px 28px; }
.help-body::-webkit-scrollbar { display: none; }
.help-in .progress { position: absolute; }
.help-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 28px; }
.help-in h3 { font-size: 13px; margin: 0 0 3px; font-weight: 900; color: var(--hc, var(--ink)); text-transform: uppercase; letter-spacing: .05em; }
.help-in p { font-size: 14px; line-height: 1.4; margin: 0; color: var(--lav); }
.help-fine { margin-top: 18px !important; font-size: 12px !important; color: var(--dim) !important; }
kbd { font: 800 11px var(--font-body), sans-serif; border: var(--lw) solid var(--ring); padding: 0 4px; color: var(--bone); }
#sparkle { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 30; }
#tip { position: fixed; z-index: 60; pointer-events: none; background: #000; color: var(--bone); border: var(--lw) solid var(--ring); font-size: 11px; font-weight: 800; padding: 5px 8px; opacity: 0; transition: opacity .12s; white-space: nowrap; }
#tip.on { opacity: 1; }

/* ---------- the Super page ---------- */
.plate-note { margin: 0; font-size: 12px; line-height: 1.38; color: var(--lav); max-width: 46em; align-self: center; }
.starmodes .seg button { min-width: 74px; }
.scope-note { font-size: 11px; font-weight: 800; color: var(--lav); margin-top: 6px; line-height: 14px; overflow-wrap: anywhere; text-wrap: balance; }   /* audit-fix: wraps, never clips */
.xdiag { flex: 0 1 auto; min-width: 0; max-width: 100%; margin-left: auto; }   /* 4c-6: shrinks to its cell (727px landscape frame: three 225px columns) */
.xdiag svg { display: block; max-width: 100%; height: auto; }
.xdiag g { transition: opacity .15s; }
.wheel-wrap { display: flex; gap: 18px; flex: 1; min-height: 0; }
.bigwheel { position: relative; width: 46px; flex: none; height: 176px; border: var(--lw) solid var(--pc); background: transparent; cursor: ns-resize; touch-action: none; }
.bigwheel canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.routes { display: flex; flex-direction: column; gap: 6px; }
.route { align-items: center; gap: 6px; flex-wrap: wrap; }
.rcol { flex: 1 1 110px; min-width: 0;   /* under 110px the readout takes its own line instead of a 22px sliver */ display: flex; flex-direction: column; gap: 7px; padding-left: 10px; }
.rsay { font-size: 11px; font-weight: 800; color: var(--pc); line-height: 14px; min-height: 14px; overflow-wrap: anywhere; text-wrap: balance; }   /* audit-fix: wraps, never clips */
/* a wheel route: a dim solid trough (no outline, 4c-3), its reach at the top of the wheel a brighter band, now = lit */
/* the DOM bars share the canvas meters' block look (Benjamin 10-25): a ladder (green, yellow, orange, red) under a mask of 6 px
   blocks on an 8 px pitch, the unlit blocks the same dim (.18), the lit ones clipped to whole blocks by barClip() (ui.js).
   Route meter: from the middle out, red at both ends; the zero tick stays outside the mask. */
:root { --seg-mask: repeating-linear-gradient(90deg, #000 0 6px, transparent 6px 8px);
  --ladder-uni: linear-gradient(90deg, var(--meter-ok) 0 68%, var(--meter-hot) 68% 84%, var(--meter-warn) 84% 92%, var(--meter-clip) 92% 100%);
  --ladder-bi: linear-gradient(90deg, var(--meter-clip) 0 4%, var(--meter-warn) 4% 8%, var(--meter-hot) 8% 16%, var(--meter-ok) 16% 84%, var(--meter-hot) 84% 92%, var(--meter-warn) 92% 96%, var(--meter-clip) 96% 100%); }
.rmeter { position: relative; height: 12px; }
.rmeter::before { content: ""; position: absolute; left: calc(50% - var(--lw) / 2); top: -4px; bottom: -4px; width: var(--lw); background: var(--pc); z-index: 2; }
.rmeter::after, .rmeter i, .rmeter b { content: ""; position: absolute; inset: 0; background: var(--ladder-bi); -webkit-mask-image: var(--seg-mask); mask-image: var(--seg-mask); }
.rmeter::after { opacity: .18; }
.rmeter i { opacity: .55; clip-path: inset(0 100% 0 0); } .rmeter b { clip-path: inset(0 100% 0 0); }
.rmeter.off { opacity: .3; }
/* MIX (4c-2 shell): one strip per engine. The fader is a 48px-wide vertical track (the whole column is the grab area);
   the meter's segments are dim solid blocks, none lit until stage 6 gives each engine its own bus and tap */
.strips { display: flex; gap: var(--cell-gap); flex-wrap: wrap; align-items: stretch; justify-content: center; }
/* audit-fix 10-22: the strips share the cell (no 260px cap leaving wide side margins), the fader sits on the strip's
   centre line (the meter on its left, an equal spacer on its right), its value clear of the track */
.strip { flex: 1 1 120px; min-width: 0; max-width: 420px; display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 8px 6px; border: var(--lw) solid color-mix(in srgb, var(--pc) var(--lvl-idle), #000); }
.strip-name { font-family: var(--font-label); font-size: 12px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--pc); }
.strip-mid { display: flex; gap: 10px; align-items: stretch; height: 220px; }
.strip-mid::after { content: ""; width: 14px; flex: none; }   /* = the meter: the fader centred */
.smeter { width: 14px; display: flex; flex-direction: column; gap: 3px; }
.smeter i { flex: 1; --sc: var(--meter-ok); background: color-mix(in srgb, var(--sc) var(--lvl-off), #000); }
.smeter i.hot { --sc: var(--meter-hot); } .smeter i.red, .smeter i.clip { --sc: var(--meter-clip); }
.smeter i.clip { flex: 0 0 6px; margin-bottom: 3px; }
.smeter i.on { background: var(--sc); }
.fader { width: 56px; display: flex; flex-direction: column; align-items: center; gap: 8px; cursor: ns-resize; touch-action: none; }
.fader .ftrack { position: relative; flex: 1; width: 48px; }
.fader .ftrack i, .fader .ftrack::after { position: absolute; left: 50%; width: 6px; margin-left: -3px; bottom: 0; }
.fader .ftrack i { top: 0; background: color-mix(in srgb, var(--pc) var(--lvl-off), #000); }
.fader .ftrack::after { content: ""; height: calc(var(--f, 0) * (100% - 14px)); background: var(--vc, var(--pc)); }
.fader .ftrack b { position: absolute; left: 0; right: 0; height: 14px; bottom: calc(var(--f, 0) * (100% - 14px)); background: var(--vc, var(--pc)); }
.fader.drag .ftrack b { left: -4px; right: -4px; }
.fader .val { font-family: var(--font-seg7), var(--font-body); font-size: 11px; font-weight: 800; letter-spacing: var(--track-seg); line-height: 14px; min-height: 14px; white-space: nowrap; color: var(--vc, var(--pc)); }
.fader .val.txt { font-family: var(--font-body), sans-serif; font-weight: 700; letter-spacing: normal; }
.fader.off .val { color: var(--ink-3); }
.fader.off { cursor: default; }
.fader.off .ftrack b { background: color-mix(in srgb, var(--pc) var(--lvl-off), #000); }
.strip-btns { display: flex; gap: 6px; }
.strip-btns .pill:disabled { cursor: not-allowed; border-style: dashed; color: var(--ink-3); }
/* 4d-1: SOLO / MUTE are live: a square lamp (D18), the button fills in the strip's colour when on; a strip that isn't
   heard (muted, or another engine soloed) dims its fader and meter */
.strip-btns .sbtn { position: relative; padding-left: 25px; }
.sbtn .lamp { position: absolute; left: 9px; top: 50%; width: 9px; height: 9px; margin-top: -4.5px; background: var(--pc); opacity: .25; }
.sbtn.solid .lamp { background: #000; opacity: 1; }
.strip.quiet .fader, .strip.quiet .smeter { opacity: .35; }
.strip .plate-note { text-align: center; font-size: 11px; align-self: stretch; }
.plate-note.s6 { margin-top: 8px; text-align: center; max-width: none; }
.also { font-size: 12px; color: var(--lav); margin-top: 8px; min-height: 15px; }

/* ================================================================ the phone (iPhone 15 Pro Max and friends):
 * phone portrait and phone landscape share most of this sizing; the grid itself (columns, stacking, M8) is in the
 * ".page" rules above. No device class, no #win: these are the two phone media bands from tokens.css. */
#safe { position: fixed; inset: 0; pointer-events: none; visibility: hidden; padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px); }
#rotate { display: none; }
@container frame (max-width: 599px) or ((max-height: 500px) and (orientation: landscape)) {
  .orb, #stat-midi { display: none !important; }
  #bar { min-height: var(--hit); height: auto; gap: 8px; padding: var(--safe-t) max(2px, var(--safe-r)) 0 max(4px, var(--safe-l)); }
  #tabs { gap: 4px; }
  .tab { padding: 0 3px; gap: 0; }   /* the 3-letter codes in Patrick Turbo fit the 48px hit box */
  .tab svg { display: none; }
  .tab .ttl { font-size: 11px; }
  .ticker { height: 28px; font-size: 12px; padding: 0 8px; }
  .minispec { width: 52px; height: 28px; }
  .hbtn.icon { width: var(--hit); height: var(--hit); }
  .mdtypes .seg { grid-template-columns: repeat(7, 1fr); }
  .mdtypes .seg button { height: var(--hit); font-size: 11px; }
  .mdeng .seg button { height: var(--hit); font-size: 11px; }
  .plate[data-area="mdl"] .plate-note { display: none; }
  .plate[data-area="sng"] .plate-body { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto 1fr; column-gap: 18px; align-content: start; }
  .plate[data-area="sng"] .plate-body > :nth-child(1) { grid-column: 1; grid-row: 1; }
  .plate[data-area="sng"] .plate-body > :nth-child(2) { grid-column: 2; grid-row: 1; align-self: center; }
  .plate[data-area="sng"] .plate-body > :nth-child(3) { grid-column: 1 / 3; grid-row: 2; }
  .plate[data-area="sng"] .plate-body > :nth-child(5) { grid-column: 1; grid-row: 3; }
  .plate[data-area="sng"] .plate-body > :nth-child(7) { grid-column: 2; grid-row: 3; }
  .plate[data-area="vow"] .plate-body { display: grid; grid-template-columns: 330px 1fr; grid-template-rows: auto 1fr; column-gap: 14px; align-content: start; }
  .plate[data-area="vow"] .plate-body > canvas { grid-column: 1; grid-row: 1 / 3; height: 200px !important; }
  .plate[data-area="vow"] .plate-body > .segctl { grid-column: 2; grid-row: 1; }
  .plate[data-area="vow"] .plate-body > .row { grid-column: 2; grid-row: 2; align-self: start; }
  .plate[data-area="sng"] .sngnote, .plate[data-area="vow"] .vownote { display: none; }
  .plate[data-area="sng"] .sngcap, .sngwho { display: none; }
  .hstyles .seg { grid-template-columns: repeat(4, 1fr); } .hstyles .seg button { height: var(--hit); font-size: 11px; }
  .vowcv { height: 118px !important; } .stagecv { height: 80px !important; }
  .plate[data-area="sng"] .segctl .lab, .plate[data-area="sng"] > .plate-body > .cap { display: none; }
  .plate[data-area="sng"] .plate-body { gap: 3px; }
  .plate[data-area="sng"] .seg button { height: var(--hit); font-size: 11px; }
  .plate[data-area="sng"] .hstyles .seg button { height: var(--hit); }
  .plate[data-area="sng"] .row { margin: 0 !important; }
  .plate[data-area="vow"] .seg button { height: var(--hit); font-size: 11px; }
  .plate[data-area="fac"] canvas { height: 182px !important; }
  .sqpresets { margin: 4px 0 2px; }
  /* R§5: 16 steps don't fit >=48px each at phone widths, so both phone bands wrap to 8 steps x 2 rows
     (the 16 .sqcol children auto-flow into 2 rows of 8 once there are only 8 columns) */
  .sqgrid { grid-template-columns: repeat(8, 1fr); }
  .sqon { width: 48px; height: 48px; }
  .sqcol { gap: 2px; padding: 1px 0; }
  .sqnote { padding: 1px 0; font-size: 11px; }
  .sqlane { height: 60px !important; }
  .rollmode .plate-body { gap: 2px; }
  /* a wrapping toolbar, not a horizontal scroll strip: the stage never scrolls sideways (R§1.2) */
  .rollbar, .rollmode .sqpresets { flex-wrap: wrap; overflow: visible; margin: 0; gap: 5px; flex: none; }
  .rollbar .pill, .rollbar .seg button, .rollmode .sqpresets .pill { height: var(--hit); font-size: 11px; flex: none; white-space: nowrap; }
  .rollbar .seg { flex: none; } .rollbar .seqplay { min-width: 54px; }
  .rollcv { height: 112px !important; }
  .rolllane { height: 30px !important; }
  .rollmode .row { margin: 1px 0 !important; }
  .rlanes { height: 18px; } .rlanes button { height: var(--hit); font-size: 11px; }
  .rollhint { display: none; }
  .rollpats { top: 50px; max-height: 190px; padding: 6px; } .patcols { grid-template-columns: repeat(7, 1fr); gap: 4px; }
  .patnote { display: none; } .patcol .pill { height: var(--hit); font-size: 11px; }
  .plate[data-area="seq"] .row { margin: 2px 0 !important; }
  /* the deck's per-band sizing (--play-h) lives in the landscape and portrait blocks below */
  .power-in { gap: 12px; padding: 16px; }
  .power-lede { font-size: 15px; }
  #btn-power { height: var(--hit); font-size: 14px; }
  #book { left: max(8px, var(--safe-l)) !important; right: max(8px, var(--safe-r)) !important; top: max(8px, var(--safe-t)) !important; bottom: max(8px, var(--safe-b)); width: auto; max-height: none; padding: 12px 14px; }
  .book-cols { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .book-head p { display: none; }
  .logo { width: 30px; height: 30px; }
  .power-in { gap: 22px; padding: 12px; }
  .splash { --c: min(190px, 46cqmin); }
  select.sel.presetsel { font-size: 11px; max-width: 200px; }
}
/* phone landscape only (932x430): a short deck (one 48px row + a 112px wheels/keys strip) so the stage keeps
   its height; the keys toggle frees the rest (4c-1) */
@container frame (max-height: 500px) and (orientation: landscape) {
  /* audit-fix (Benjamin 10-22): the stage gets >= 55% of the height: a 36px perf row and a wheels/keys strip that
     scales with the height (97px at 430 tall, 81px at 393; buildKeys drops its label row under 104px) */
  #deck { --play-h: clamp(72px, calc(45cqh - 96px - var(--safe-b)), 100px); padding-top: 4px; padding-bottom: max(4px, var(--safe-b)); }
  .deck-play { margin-top: 4px; gap: 10px; }
  .deck-row :is(.pkb, .octro, .keys-tog) { height: 36px; min-height: 36px; }
  .wheel { gap: 2px; }
  /* one header row inside the side insets (59+59 on iPhone 15): a smaller coin, tighter gaps, a shorter ticker floor */
  #bar { gap: 6px; }
  #bar .logo { width: 32px; height: 32px; }
  /* 4c-6: the 16:9 frame is 727 wide on the iPhone 15 Pro Max (was 814 between the insets): the ticker may shrink,
     so the header stays one row (4d-2a: the CPU monitor is in MASTER > System now) */
  .ticker { min-width: 0; }
  .minispec { width: 32px; }   /* 4d-2b: a slim one here, so the ticker keeps its room for the patch name */
}

/* ---------- the logo (round 12): BENVENTIONS' rainbow coin. The splash spins it; it lands in the bar ---------- */
:root { --logo: url(../img/logo.webp); }
.logo { width: 42px; height: 42px; flex: none; display: block; border-radius: 50%; background: var(--logo) center / cover no-repeat; position: relative;
  cursor: pointer; transition: transform .25s; }   /* Benjamin: no drop-shadow glow */
.logo::before { content: ""; position: absolute; inset: 0; border-radius: 50%; background: radial-gradient(circle at 31% 26%, rgba(255,255,255,.42), rgba(255,255,255,0) 46%); }
.logo::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: linear-gradient(115deg, transparent 41%, rgba(255,255,255,.7) 50%, transparent 59%) 100% 0 / 300% 100% no-repeat; }
.logo:hover { transform: scale(1.07) rotate(-6deg); }
.logo.landing { visibility: hidden; }
.logo.flip { animation: lg-flip .9s cubic-bezier(.3, .1, .2, 1); }
.logo.spin { animation: lg-spin 1.2s cubic-bezier(.45, 0, .2, 1); }
.logo.wobble { animation: lg-wobble .95s ease-in-out; }
.logo.bounce { animation: lg-bounce .85s cubic-bezier(.3, 0, .3, 1); }
.logo.peek { animation: lg-peek 1.4s cubic-bezier(.4, 0, .2, 1); }
.logo.wink { animation: lg-wink .42s ease-in-out; }
.logo.land { animation: lg-land .7s cubic-bezier(.2, 1.6, .4, 1); }
.logo.shine::after, .logo.flip::after, .logo.land::after { animation: lg-shine .9s ease-in-out .1s; }
@keyframes lg-flip { from { transform: perspective(200px) rotateY(0); } to { transform: perspective(200px) rotateY(360deg); } }
@keyframes lg-spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }
@keyframes lg-wobble { 0%, 100% { transform: rotate(0); } 18% { transform: rotate(-16deg); } 38% { transform: rotate(12deg); } 58% { transform: rotate(-7deg); } 78% { transform: rotate(3deg); } }
@keyframes lg-bounce { 0%, 100% { transform: translateY(0) scale(1); } 22% { transform: translateY(1px) scale(1.14, .84); } 50% { transform: translateY(-11px) scale(.92, 1.1); } 76% { transform: translateY(0) scale(1.08, .92); } }
@keyframes lg-peek { 0%, 100% { transform: translateY(0); } 30%, 55% { transform: translateY(30px); } 80% { transform: translateY(-4px); } }
@keyframes lg-wink { 0%, 100% { transform: scaleY(1); } 45%, 55% { transform: scaleY(.08); } }
@keyframes lg-land { 0% { transform: scale(1.35); } 100% { transform: scale(1); } }
@keyframes lg-shine { from { background-position: 100% 0; } to { background-position: 0% 0; } }

/* the splash: the coin on its own, nothing else but the button (Benjamin: no glow or rays behind it) */
.power-in { gap: 40px; }
.splash { --c: min(300px, 44cqmin); position: relative; width: var(--c); height: var(--c); perspective: 1100px; }
.coin { position: absolute; inset: 0; transform-style: preserve-3d; animation: sp-float 6s ease-in-out infinite; will-change: transform; }
.coin i { position: absolute; inset: 0; border-radius: 50%; background: var(--logo) center / cover; backface-visibility: visible; }
.coin i.rim { filter: brightness(.42) saturate(1.3); }
.coin i.face::before { content: ""; position: absolute; inset: 0; border-radius: 50%; background: radial-gradient(circle at 31% 25%, rgba(255,255,255,.5), rgba(255,255,255,0) 44%), radial-gradient(circle at 70% 82%, rgba(0,0,0,.18), transparent 50%); }
.coin i.face::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: linear-gradient(115deg, transparent 41%, rgba(255,255,255,.6) 50%, transparent 59%) 100% 0 / 300% 100% no-repeat; animation: sp-sweep 5.5s ease-in-out infinite; }
#power.started .coin { animation: none; }
#power.started { pointer-events: none; }
#power.started #btn-power { opacity: 0; transform: scale(.9); transition: opacity .4s, transform .4s; }
#splash-fx { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2; }
.power-in { z-index: 1; }
#power.leaving { transition: opacity .7s; opacity: 0; }
body.boot-in #stage { animation: boot-in .9s ease-out; }
@keyframes boot-in { from { opacity: 0; } to { opacity: 1; } }   /* Benjamin: no blur/brightness glow */
@keyframes sp-float { 0%, 100% { transform: translateY(0) rotateY(-16deg) rotateX(4deg); } 50% { transform: translateY(-9px) rotateY(16deg) rotateX(-3deg); } }
@keyframes sp-sweep { 0%, 55% { background-position: 100% 0; } 85%, 100% { background-position: 0% 0; } }
@media (prefers-reduced-motion: reduce) { .coin, .coin i.face::after { animation: none !important; } }
/* the PATRICK logo on the splash (Benjamin's chrome lettering + crossed swords, Airbrush 10-21), shown the way PERFECTO is
   on benventions.com: the logo hovers, and now and then a chrome band sweeps across it, masked to the lettering
   (patrick-mask.svg, same construction as perfecto-mask.svg) and colour-dodged onto it. No shadow, blur or glow.
   Sized to fit under the coin and over the button without cropping: canvas 2540x1406. */
.plogo-wrap { --pl-c: min(300px, 44cqmin); --pl-res: 215px; --lw-logo: min(94cqw, 860px, calc((100cqh - var(--pl-c) - var(--pl-res)) * 2540 / 1406)); position: relative; margin: -14px 0 -10px; width: var(--lw-logo); height: calc(var(--lw-logo) * 1406 / 2540); font-size: 0; line-height: 0;
  animation: pl-hover 6s ease-in-out infinite; will-change: transform; }
.plogo { display: block; width: 100%; height: 100%; }
.plogo-sweep { position: absolute; inset: 0; pointer-events: none; mix-blend-mode: color-dodge; opacity: .9; overflow: hidden;
  -webkit-mask: url(../img/logo/patrick-mask.svg) center / 100% 100% no-repeat; mask: url(../img/logo/patrick-mask.svg) center / 100% 100% no-repeat; }
/* the chrome band, defined once (INIT tile: the splash's sweep, the rainbow tiles' wipe and the rainbow title's wipe all read it) */
:root { --chrome-band: linear-gradient(100deg, transparent 0%, transparent 38%, #F65DA2 42%, #F9B65C 46%, #FEF4DA 49%, #F9B65C 52%, #F65DA2 55%, transparent 58%, transparent 100%); }
.plogo-band { position: absolute; left: 0; top: 0; width: 300%; height: 100%; transform: translateX(-66.6667%); will-change: transform;
  background: var(--chrome-band);
  animation: pl-sweep 6s ease-in-out .4s infinite; }
@keyframes pl-hover { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
@keyframes pl-sweep { 0% { transform: translateX(-66.6667%); } 26%, 100% { transform: translateX(0); } }
/* logo-out (Benjamin 10-21): when the coin flies to the bar (#power.flying, the moment the synth page starts to show), the
   logo dips a touch, rises a touch above rest, then flies into the viewer, fading as it passes through the screen. 1.1 s,
   ending as the overlay goes (the coin's flight is 1.15 s). Transform and opacity only, on its own layer; the sweep is
   dropped for the flight so iPhone Safari composites one plain image. Reduced motion: a quick fade with the overlay. */
#power.flying .plogo-wrap { will-change: transform, opacity; }   /* the flight itself: plogoOut() in ui.js (WAAPI, sampled from one smooth curve) */
#power.flying .plogo-sweep { display: none; }
#power.leaving .plogo-wrap { animation: none; transition: opacity .3s; opacity: 0; }
@container frame (max-width: 599px) or ((max-height: 500px) and (orientation: landscape)) { .plogo-wrap { --pl-c: min(190px, 46cqmin); --pl-res: 140px; } }   /* the small-frame coin and padding (see .splash there) */
@media (prefers-reduced-motion: reduce) { .plogo-wrap, .plogo-band { animation: none !important; } }
/* splash-2 (Benjamin 10-22), mirroring the benventions.com hero lockup: the coin centred on the top third of the screen,
   PATRICK in front of it (its centre 0.6 coin below the coin's, 1.9 coins wide, as PERFECTO), SWITCH ON red at the bottom
   centre above the iPhone's home bar. One size (--pc) drives coin and logo; phones get a smaller coin, a phone on its side
   smaller again so the lockup stays clear of the button. Square, no shadow or glow. */
#power .power-in { position: absolute; inset: 0; display: block; max-width: none; padding: 0; --pc: min(250px, 34cqmin); }
#power .splash { --c: var(--pc); position: absolute; left: 50%; top: calc(100cqh / 3); margin: calc(var(--pc) / -2) 0 0 calc(var(--pc) / -2); z-index: 1; }
#power .plogo-wrap { --lw-logo: min(calc(var(--pc) * 1.9), 92cqw); position: absolute; left: 50%; top: calc(100cqh / 3 + var(--pc) * .6); z-index: 2;
  width: var(--lw-logo); height: calc(var(--lw-logo) * 1406 / 2540); margin: calc(var(--lw-logo) * -703 / 2540) 0 0 calc(var(--lw-logo) / -2); }
#power #btn-power { position: absolute; left: 50%; translate: -50% 0; bottom: max(28px, calc(var(--safe-b) + 16px)); z-index: 3;
  background: #FF2D2D; border-color: #FF2D2D; color: #000; }   /* the palette's red (--rec), black type 5.7:1 */
#power #btn-power:hover { background: #FF5A52; border-color: #FF5A52; color: #000; }
#power #btn-power:focus-visible { outline: 2px solid var(--bone); outline-offset: 3px; }
#power .power-fine { position: absolute; left: 16px; right: 16px; bottom: max(96px, calc(var(--safe-b) + 84px)); margin: 0; }
@container frame (max-width: 599px) { #power .power-in { --pc: min(176px, 40cqmin); } }
@container frame (max-height: 500px) and (orientation: landscape) { #power .power-in { --pc: min(150px, 34cqmin); } }
/* ---------- title card (Benjamin 10-22): a deadpan credits card over the splash, once per page load (TitleCard in ui.js).
   OLED black, square, flat colour; ships visible so the splash never flashes before ui.js runs. The failsafe hides it
   at 7 s whatever happens to the script (it isn't motion, so reduced motion keeps it). TitleCard.layout() sets the sizes
   (--fs caps, --ft technical lines, --fg SIGNAL, --fb SYNTHESIZER, --rh, --gs) and places .tc-box on the frame;
   during the chrome wipe it sets only --tc-bw / --tc-bx (and --tc-lx per letter). No shadow, blur or glow. ---------- */
#title { position: fixed; inset: 0; z-index: 70; background: #000; cursor: pointer; touch-action: manipulation; overflow: hidden;
  animation: tc-failsafe 0s linear 7s forwards;
  --tc-phos: #79EE5A;   /* the coin's own green (the 50 % stop of --rainbow): the card's only green, flat */
  --tc-chrome: linear-gradient(180deg, #FFFFFF 0%, #F4F1EA 36%, #B9B3C8 47%, #2A2633 50%, #5A556D 58%, #C9C4D6 80%, #FFFFFF 100%); }
#title[hidden] { display: none; }
#title.tc-clear { background: transparent; }   /* skipped: the splash shows, the layer still catches the tap's own click */
@keyframes tc-failsafe { to { visibility: hidden; pointer-events: none; } }
#title .tc-box { position: absolute; }
#title .tc-card { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; opacity: 0; }
#title .tc-card > *, #title .tc-l1 > * { position: relative; white-space: nowrap; text-transform: uppercase; }
#title .tc-cap { font: 700 var(--fs) var(--font-body); letter-spacing: .46em; padding-left: .46em; color: var(--ink); line-height: 1.5; }
#title .tc-tech { font: 400 var(--ft) var(--font-body); letter-spacing: .32em; padding-left: .32em; color: var(--ink-3); line-height: 1.5; }
#title .tc-rule { height: 1px; background: var(--ink-3); width: 0; margin: calc(var(--fs) * .9) auto; }
#title .tc-rule.rb { height: var(--rh); background: var(--rainbow-fallback); background: var(--rainbow); }
#title .tc-role { font: 400 var(--ft) var(--font-body); letter-spacing: .38em; padding-left: .38em; color: var(--ink-3); margin-top: calc(var(--fs) * 1.25); line-height: 1.5; }
#title .tc-role:first-child { margin-top: 0; }
#title .tc-name { font: 700 var(--fs) var(--font-body); letter-spacing: .46em; padding-left: .46em; color: var(--ink); margin-top: .35em; line-height: 1.5; }
#title .tc-robot { font: 400 var(--ft) var(--font-body); letter-spacing: .32em; padding-left: .32em; color: var(--ink-2); margin-top: .6em; line-height: 1.5; }
#title .tc-cr > * { opacity: 0; }
#title .tc-big { font: 900 var(--fb) var(--font-head); line-height: 1; height: 1em; margin-top: calc(var(--fs) * 1.1); }
#title .tc-big span { position: absolute; top: 0; display: block; color: transparent; -webkit-text-fill-color: transparent;
  background: var(--chrome-band) calc(var(--tc-bx, 0px) - var(--tc-lx, 0px)) 0 / var(--tc-bw, 300%) 100% no-repeat, var(--tc-chrome) 0 0 / 100% 100% no-repeat;
  -webkit-background-clip: text; background-clip: text; }
#title .tc-sig { margin-top: calc(var(--fs) * 1.05); font: 400 var(--fg) var(--font-seg14); letter-spacing: .18em; padding-left: .18em; color: var(--tc-phos); line-height: 1; }
#title .tc-sig i { font-style: normal; visibility: hidden; }
#title .tc-sigc { position: absolute; top: 0; width: .62em; height: 1em; background: var(--tc-phos); display: none; }
#title .tc-glint { position: absolute; width: var(--gs); height: var(--gs); margin: calc(var(--gs) / -2) 0 0 calc(var(--gs) / -2); display: none; pointer-events: none; }
/* ---------- the phone held upright: one column 430 wide, the pages scroll up and down, the keys along the bottom (R§3.A) ---------- */
@container frame (max-width: 599px) {
  #bar { position: relative; flex: none; height: auto; flex-wrap: wrap; gap: 6px 6px; padding: 4px max(2px, var(--safe-r)) 9px max(4px, var(--safe-l)); padding-top: max(4px, var(--safe-t)); }
  .brand { order: 0; }
  .ticker { order: 1; flex: 1; min-width: 0; }
  .status { order: 2; gap: 6px; }
  #tabs { order: 3; width: 100%; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; }   /* hdr-1 (Benjamin 10-21): the tabs on one row of squares, was two rows of four. tabs6: six now, so each is bigger */
  .tab { padding: 0 2px; justify-content: center; min-width: 0; height: auto; aspect-ratio: 1; max-height: 56px; }   /* (square while narrow; capped at 56px, +8 on the old 48, so PATRICK's pinned Library keeps its room: ~66x56 at 430) */
  .tab .ttl { font-size: 14px; }
  #pages { --pad-t: 8px; flex: 1; min-height: 0; padding: var(--pad-t) calc(var(--safe-r) + 2 * var(--progress-w) + var(--gap-r)) calc(var(--fade-b) + 6px) max(2px, var(--safe-l)); }
  .page.on { display: flex; flex-direction: column; gap: 10px; }
  .page > .plate { width: auto !important; height: auto !important; flex: none; min-height: 0; }
  .plate-body { overflow: visible; flex: none; }
  #deck { --play-h: 220px; padding: 6px max(2px, var(--safe-r)) max(6px, var(--safe-b)) max(2px, var(--safe-l)); }
  .deck-play { margin-top: 6px; gap: 8px; }
  .wheels { gap: 6px; }
  .seg { flex-wrap: wrap; min-height: var(--hit); height: auto; max-width: 100%; }
  /* the library: what's loaded, the actions, the categories, then the sounds */
  /* blocks: the steppers wrap, the chord editor goes under the tiles */
  .blk-top { flex-wrap: wrap; height: auto; gap: 8px 14px; white-space: normal; }
  .blk-main { grid-template-columns: 1fr; gap: 14px; }
  .tile { height: 78px; }
  /* sing: one column */
  .plate[data-area="sng"] .plate-body, .plate[data-area="vow"] .plate-body { display: flex; flex-direction: column; }
  .plate[data-area="sng"] .seg button { padding: 0 7px; }
  .hstyles .seg { grid-template-columns: repeat(4, 1fr); }
  .plate[data-area="vow"] .plate-body > canvas { height: 240px !important; }
  /* the sequencer: the roll gets the height; its tool rows wrap instead of scrolling sideways */
  .rollbar, .rollmode .sqpresets { flex-wrap: wrap; overflow: visible; gap: 5px; }
  .rollbar .pill, .rollbar .seg button, .rollmode .sqpresets .pill { height: var(--hit); font-size: 11px; }
  .rollcv { height: 330px !important; }
  .rolllane { height: 56px !important; }
  .rollpats { top: 96px; max-height: 330px; } .patcols { grid-template-columns: repeat(3, 1fr); }
  .sqbar { flex-wrap: wrap; row-gap: 6px; }
  .sqgrid { gap: 4px 2px; }
  .sqnote { font-size: 11px; }
  .sqlane { height: 90px !important; }
  /* the Schaffer's stage diagram is too fine to read this narrow */
  .plate[data-area="sv"] .plate-body > canvas.graph:first-child { display: none; }
  .help-top { padding: 10px 8px 6px 14px; } .help-in h2 { font-size: 20px; }
  .help-body { padding: 2px calc(2 * var(--progress-w) + 8px) 14px 14px; }
  .help-cols { gap: 12px 14px; } .help-in p { font-size: 13px; line-height: 1.35; }   /* still two to a row at 430 */
  .book-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  canvas.scene { height: 120px !important; }
  .plate[data-area="lfo"] canvas.scene { width: 100% !important; height: 110px !important; margin: 6px 0 0 !important; }
}
.plate[data-area="fac"] .plate-head .mark { display: none; }   /* room for the five views */
.splash .rays, .splash .halo { display: none !important; }   /* Ben: the coin on its own, no glow or rays behind it */
select.sel.presetsel { max-width: 230px; border-color: var(--pc); color: var(--bone); }

/* ---- V2 M9 (Benjamin 2026-10-19 hotfix): no zoom anywhere. Playable surfaces: none; chrome: manipulation; stage: pan-y ---- */
#keys, #keys *, .ctl, .ctl *, .wheel .slot, .bigwheel, .joypad, .vowcv, .rollcv, .rolllane, .sqlane, .sqcol, .sqstep,
.chain .chip, .stagecv, .fader, .xy { touch-action: none; }
button, [role="tab"], [role="button"], a, select, label, summary { touch-action: manipulation; }

/* ---- V2 stage 3b: one small toast for M1 (loaded X · undo), M2 (state cleared · undo) and S9 (MIDI messages);
   4c-3: Toast.show sets `bottom` from the deck's top edge so it floats above the deck (this bottom is the fallback) ---- */
.toast { position: fixed; left: 50%; bottom: calc(28px + var(--safe-b)); transform: translateX(-50%); z-index: 50; display: flex; align-items: center;
  gap: 10px; background: var(--space); border: var(--lw) solid var(--ring); padding: 8px 10px 8px 14px; max-width: min(92cqw, 420px); }
.toast span { font-size: 12px; font-weight: 800; color: var(--bone); }
.toast-btn { height: 48px; min-width: 48px; padding: 0 14px; border: var(--lw) solid var(--glow); background: transparent; color: var(--glow); font-size: 11px; font-weight: 900; cursor: pointer; letter-spacing: .04em; text-transform: uppercase; }
.toast-btn:hover { background: var(--glow); color: #000; }
/* 4d-2: the Model envelope's knobs dim while it is off (still turnable: set it up, then switch it on) */
.plate-body.envoff .ctl { opacity: .45; }
/* 4d-2 HOLD+: the lamp turns white-hot and the frame takes the lamp's colour (HOLD: the lamp alone) */
.pkb.plus { border-color: var(--lc); }
.pkb.plus .lamp { background: #FFFFFF; }
/* 4d-3b (Benjamin, iPhone): PATRICK's Library pins EVERYTHING above the patch grid (the LIBRARY head, what's loaded, the
   action buttons, the category tabs); only the grid scrolls, in its own region clipped at the line under the tabs, inside
   the plate's outline. #pages stops scrolling on this view (.pin-lib, set by libPinMode in ui.js only when the grid gets
   at least two rows of room; otherwise the 4d-3 sticky head + tabs over a scrolling stage stays). The stage fades and the
   rainbow line follow the grid then (updateFade). Last in the file so it wins over every band's library rules. */
#pages.pin-lib { overflow-y: hidden; padding-bottom: 8px; }
#pages.pin-lib > .page.patrick.on { display: flex; flex-direction: column; height: 100%; min-height: 0; align-self: stretch; }
#pages.pin-lib .plate[data-area="lib"] { flex: 1 1 auto; height: auto !important; min-height: 0; padding-bottom: 0; }   /* 4d-3e: the grid's clip edge IS the orange bottom line (no band under it) */
#pages.pin-lib .plate[data-area="lib"] > .plate-head, #pages.pin-lib .plate[data-area="lib"] .cats { position: relative; top: auto; }
#pages.pin-lib .plate[data-area="lib"] > .plate-body { flex: 1 1 auto; min-height: 0; overflow: hidden; }
#pages.pin-lib .plate[data-area="lib"] .lib-now, #pages.pin-lib .plate[data-area="lib"] .lib-actions, #pages.pin-lib .plate[data-area="lib"] .cats { flex: none; }
#pages.pin-lib .plate[data-area="lib"] .grid-marks { flex: 1 1 0; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain;
  touch-action: pan-y; scrollbar-width: none; align-content: start; padding-bottom: 4px; }
#pages.pin-lib .plate[data-area="lib"] .grid-marks::-webkit-scrollbar { display: none; }
#pages.pin-lib .plate[data-area="lib"] .pm { scroll-margin-top: 0; }
/* Syn Rise S6b: the macros' mirror (pmac) sits just under the pinned Library: the Library keeps its whole pinned height, as
   before, and the stage scrolls on to the mirror (the patch grid still scrolls on its own) */
#pages.pin-lib { overflow-y: auto; }
#pages.pin-lib .plate[data-area="lib"] { flex: 0 0 100%; }
#pages.pin-lib .plate[data-area="pmac"] { flex: none; }
/* (the Library's own layout, the rail and the square grid: ui-batch1, at the end of this file) */

/* ---------- 4d-3c (Benjamin 10-20): the header row. [logo] [tabs, where they share the row] [patch name] [spectrum, all
   the room that is left] [MIDI] [?] [full screen, where the browser has it; not on an upright phone]. Every box is the
   tabs' height (--hit), the gaps are the tab grid's (4px), square, no glow. The name box is as wide as the widest factory
   name (fitNameBox in ui.js sets --name-w) and gives way, with an ellipsis, only when the row is short of room */
#bar { gap: 4px; }
#bar .ticker { order: 0; flex: 0 1 var(--name-w, 220px); width: auto; min-width: 0; height: var(--hit); padding: 0 10px; }
#bar #ticker { max-width: 100%; }
#bar .minispec { flex: 1 1 0; width: auto; min-width: 56px; height: var(--hit); aspect-ratio: auto !important; }
/* meter-1 (Benjamin 10-22): no outline; the box keeps its size (border-box), so the bars grow into the edge it had. A tap
   swaps spectrum and stereo level (drawMiniStereo); keyboard focus shows an outline outside the box, never a glow */
#bar .minispec { border: 0; cursor: pointer; }
#bar .minispec:focus-visible { outline: 2px solid var(--bone); outline-offset: 2px; }
#bar .status { gap: 4px; }
#bar #stat-midi { display: inline-flex !important; height: var(--hit); padding: 0 10px; border: var(--lw) solid var(--ring); flex: none; }
#bar #stat-midi > span { max-width: none; }
#bar #stat-midi.on { color: var(--bone); }
#bar .hbtn.icon { height: var(--hit); }
@container frame (min-width: 1280px), (orientation: landscape) {
  /* one row: the name box gives way (then its text shrinks to fit), never a second line. hdr-1 (Benjamin 10-21): any
     landscape frame, so NO MIDI and ? always sit in the top row; the spectrum and the name box give way first */
  #bar { flex-wrap: nowrap; }
  #bar #tabs { flex-wrap: nowrap; }
  #bar .minispec { min-width: 32px; }
}
@container frame (max-height: 500px) and (orientation: landscape) {
  #bar #btn-full { display: none; }   /* full screen is a desktop control (Benjamin 10-20) */
  #bar .minispec { min-width: 40px; }
  #bar #stat-midi { padding: 0 7px; gap: 5px; }
  #bar .ticker { padding: 0 6px; }
}
@container frame (max-width: 599px) {
  #bar { gap: 4px; padding-bottom: 8px; }
  #bar .ticker { order: 1; }
  #bar .minispec { order: 2; min-width: 40px; }
  #bar .status { order: 3; }
  #bar #tabs { order: 4; }
  #bar #btn-full { display: none; }
  #bar #stat-midi { padding: 0 8px; gap: 5px; }
  #bar .ticker { padding: 0 6px; }
}

/* 4d-3d: HIDE KEYS breathes while the Library is cramped and the keys are shown (updateFade sets .breathe): a slow 3 s
   ease-in-out swell of its own outline and text to bone and a faint fill of the same; no glow. Reduced motion: held lit */
@keyframes keys-breathe { 0%, 100% { border-color: var(--ring); color: var(--lav); background-color: transparent; }
  50% { border-color: var(--bone); color: var(--bone); background-color: color-mix(in srgb, var(--bone) 10%, transparent); } }
.keys-tog.breathe { animation: keys-breathe 3s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .keys-tog.breathe { animation: none; border-color: var(--bone); color: var(--bone); background-color: color-mix(in srgb, var(--bone) 8%, transparent); }
}

/* 4d-3g: the quote is a fixed two-line box (longer ones end in an ellipsis), the author its own line below, so the block
   above the Library grid is the same height for every sound (every band) */
.plate[data-area="lib"] .lib-now .quote { display: block; overflow: visible; }
.plate[data-area="lib"] .lib-now .quote .qt, .plate[data-area="lib"] .lib-now .quote cite { display: inline; }   /* (Benjamin 10-25: the credit follows the quote after a dash) */
/* 4d-3g (Benjamin 10-20): MONITOR's meters (the +8 label, the red top segment, SPECTRUM) sat 5px under the heading rule
   with nothing between, so they read as touching it; 6px more puts their ink where the OUTPUT dial's arc and the other
   cells' first controls start (the cell's own height absorbs it) */
.plate[data-area="mon"] > .plate-body { padding-top: 6px; }

/* stage 7: the pedal rack (FX). The tab is one column: the rack's head (the signal-path readout, ALL FX OFF), the rack
   (the pedal cards in signal order, flowing left to right and wrapping; one per row on a portrait phone), then Rigs.
   No shadows, square corners, integer borders: a lifted card gets the bold outline and a 1.02 scale, nothing else. */
#pages .page.fx { grid-template-columns: minmax(0, 1fr); grid-template-areas: none; grid-template-rows: none; grid-auto-rows: auto; }
#pages .page.fx > * { grid-column: 1 / -1; grid-area: auto; }
.rack-head { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.rack-headrow { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.rack-headrow .cap { font-size: 11px; color: var(--lav); font-weight: 800; text-transform: uppercase; letter-spacing: .06em; }
.rack-all { --pc: var(--tab-fx); display: inline-flex; align-items: center; gap: 8px; text-transform: uppercase; letter-spacing: .06em; color: var(--pc); }
.rack-all .lamp { width: 10px; height: 10px; border: var(--lw) solid currentColor; flex: none; }
.rack-all.solid .lamp { background: #000; }
.rack-read { margin: 0; font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .05em; color: var(--bone); line-height: 1.6; overflow-wrap: anywhere; }
.rack-read i { font-style: normal; color: var(--lav); }
.rack-read .off { color: var(--ink-3); }
.rack-read .mst { color: var(--tab-master); }
.rack-read .alloff { color: var(--tab-fx); }
.rack { position: relative; display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--cell-gap); min-width: 0; }   /* audit-fix: cards keep their own height (no stretched voids) */
.rack > .rack-arrow { align-self: stretch; }
/* audit-fix: each card is its own width container, so a narrow card (Chorus at 1440) keeps its head on one row: the
   footswitch shrinks to its label (never under the 48px hit), the arrows keep their 48px */
.rack > .plate { container: card / inline-size; }
@container card (max-width: 470px) {
  .rack-hd { flex-wrap: nowrap; }
  .rack-hd .footsw { min-width: var(--hit); padding: 0 8px; gap: 6px; font-size: 11px; letter-spacing: .02em; }
}
/* a very narrow card: the controls take a tidy second row of their own, full width (arrows square, the switch the rest) */
@container card (max-width: 340px) {
  .rack-hd.rack-hd { flex-wrap: wrap; }
  .rack-hd .rack-ctl { flex: 1 0 100%; margin-left: 0; }
  .rack-hd .footsw { flex: 1; }
}
.rack > .plate { flex: 1 1 var(--rb, 300px); min-width: 0; max-width: 100%; }
.rack > .plate[data-area="sw"], .rack > .plate[data-area="sv"] { --rb: 560px; }
.rack > .plate[data-area="spr"], .rack > .plate[data-area="str"] { --rb: 360px; }
.rack-arrow { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-width: 40px;
  color: var(--lav); font-size: 11px; font-weight: 900; text-transform: uppercase; letter-spacing: .06em; }
.rack-arrow b { font-size: 20px; line-height: 1; color: var(--tab-fx); }
.rack-arrow.master { flex: 1 0 100%; flex-direction: row; justify-content: flex-start; gap: 8px; border-top: var(--lw) dashed var(--ink-3); padding-top: 6px; }
.rack-arrow.master .mst { color: var(--tab-master); }
/* stage 11a: the master is a slim divider card in the one flow (pedals cross it); MASTER OUT is fixed at the end, full width */
.rack-arrow.master { flex: 0 0 auto; flex-direction: column; justify-content: center; gap: 2px; min-width: 64px; padding: 6px 4px; border: var(--lw) dashed var(--tab-master); }
.rack > .plate.mo-card { flex: 1 0 100%; }
.mo-card .plate-head { flex-wrap: wrap; }
.mo-ctl { margin-left: auto; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.mo-sw .seg button { min-height: var(--hit); min-width: 96px; font-size: 13px; font-weight: 900; text-transform: uppercase; letter-spacing: .06em; }
.mo-sw .seg button:not(.on) { color: var(--pc); }
.mo-sw .seg button.on { background: var(--pc); color: #000; }
/* (audit-fix 10-22, Benjamin: RAW selects like every other choice, filled in the cell colour; was a bone outline) */
.mo-mono { --pc: var(--cell-mo); display: inline-flex; align-items: center; gap: 8px; text-transform: uppercase; letter-spacing: .06em; color: var(--pc); }
.mo-mono .lamp { width: 10px; height: 10px; border: var(--lw) solid currentColor; flex: none; }
.mo-mono.solid .lamp { background: #000; }
.mo-lat { font-family: var(--font-seg7), var(--font-body); font-size: 13px; font-weight: 800; letter-spacing: var(--track-seg); color: var(--pc); min-width: 7ch; text-align: right; white-space: nowrap; }
.mo-body { display: flex; flex-wrap: wrap; gap: var(--cell-gap); }
.mo-sec { flex: 1 1 520px; min-width: 0; border-top: var(--lw) solid color-mix(in srgb, var(--pc) 50%, #000); padding-top: 6px; }
.mo-sec-hd { font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .06em; color: var(--pc); margin-bottom: 4px; }
.mo-card.raw .mo-sec { filter: grayscale(.7) brightness(.82); }   /* RAW: none of it runs (dimmed like a bypassed pedal) */
/* stage 11b: MASTER OUT's meters (static canvases, redrawn from the snapshot) and the tap-to-reset readouts */
.mo-meter { flex: 0 1 200px; min-width: 120px; height: 48px; align-self: center; border: var(--lw) solid color-mix(in srgb, var(--pc) 40%, #000); }
.mo-lufs { display: flex; flex-direction: column; gap: 4px; flex: 0 1 200px; min-width: 120px; }
.mo-lufs .mo-meter { flex: none; width: 100%; }
.mo-reset { font-family: var(--font-seg7), var(--font-body); font-size: 13px; font-weight: 800; letter-spacing: var(--track-seg); color: var(--pc); white-space: nowrap; min-height: var(--hit); }
.mo-mirror .mo-sw { --pc: var(--cell-mo); }
.stat.mono-on { color: var(--cell-mo); border: var(--lw) solid var(--cell-mo); padding: 1px 5px; }
.stat.mono-on[hidden] { display: none; }
.rack-hd { cursor: grab; touch-action: none; }
.rack-hd:focus-visible { outline: var(--bw-bold) solid var(--pc); outline-offset: 2px; }
.rack-grip { display: flex; align-items: center; justify-content: center; width: var(--hit); height: var(--hit); margin: 0 -6px 0 -10px; flex: none;
  color: var(--pc); font-size: 22px; line-height: 1; cursor: grab; touch-action: none; user-select: none; }
.rack-note { font-size: 11px; font-weight: 800; color: var(--lav); text-transform: none; letter-spacing: .02em; white-space: nowrap; }   /* 11a: a stereo pedal before the master */
.rack-note[hidden] { display: none; }
.rack-tag { font-size: 11px; font-weight: 800; color: var(--lav); text-transform: uppercase; letter-spacing: .05em; white-space: nowrap; }
.rack-ctl { margin-left: auto; display: flex; flex: none; flex-wrap: nowrap; align-items: center; gap: 4px; }
.rack-mv { min-width: var(--hit); min-height: var(--hit); border: var(--lw) solid var(--pc); background: transparent; color: var(--pc); font-size: 14px; cursor: pointer; padding: 0; }
.rack-mv:hover:not(:disabled) { background: var(--pc); color: #000; }
.rack-mv:disabled { border-color: var(--ink-3); color: var(--ink-3); cursor: default; }
.footsw { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: var(--hit); min-width: 96px; padding: 0 10px; border: var(--lw) solid var(--pc); background: transparent;
  color: var(--pc); font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .06em; cursor: pointer; }
.footsw .led { width: 10px; height: 10px; flex: none; border: var(--lw) solid var(--pc); }
.footsw.lit .led { background: var(--pc); }
.footsw[aria-pressed="false"] { border-style: dashed; color: var(--ink-3); }
.plate.byp { border-style: dashed; }
.plate.byp > .plate-body { filter: grayscale(.7) brightness(.82); }   /* dimmed, the text still >= 4.5:1 (--ink-3 at .82: 4.8:1) */
.plate.lift { outline: var(--bw-bold) solid var(--pc); background: #000; z-index: 20; cursor: grabbing; }
.rack.dragging, .rack.dragging * { user-select: none; }
.vh { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* ---- MAGICATION (MG-S5b) ---- its two cards, fixed last before the master marker (no grip: the "fixed" tag says so);
   off (or ALL FX OFF): everything but ON dims like a bypassed pedal; HOLD a big lit switch; the slots small bars in the
   cell's own colour (not recoloured) */
.rack > .plate[data-area="mg"] { --rb: 640px; }
.rack > .plate[data-area="mgs"] { --rb: 360px; }
.mg-card .plate-head { flex-wrap: wrap; }
.mg-fixed { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; }
.mg-lock { width: 10px; height: 12px; flex: none; }
.mg-body { display: flex; gap: var(--cell-gap); align-items: flex-start; }
.mg-secs { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; gap: 8px var(--cell-gap); }
.mg-sec { flex: 1 1 auto; min-width: 0; border-top: var(--lw) solid color-mix(in srgb, var(--pc) 50%, #000); padding-top: 6px; }
.mg-sec > .row { gap: 2px; align-items: flex-start; flex-wrap: wrap; }
.mg-sec-hd { font-size: 12px; font-weight: 900; text-transform: uppercase; letter-spacing: .06em; color: var(--pc); margin-bottom: 4px; }
.mg-qual { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.mg-lat { font-family: var(--font-seg7), var(--font-body); font-size: 13px; font-weight: 800; letter-spacing: var(--track-seg); color: var(--pc); white-space: nowrap; }
.mg-later .stamp:disabled { border-style: dashed; border-color: var(--ink-3); cursor: default; }
.mg-later .stamp:disabled::after { border-color: var(--ink-3); }
.mg-later .lab, .mg-later .val { color: var(--ink-3); }
.plate.mg-off { border-style: dashed; }
.plate.mg-off .mg-dim { filter: grayscale(.7) brightness(.82); }   /* (as a bypassed pedal: the text still >= 4.5:1) */
.mg-hold { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-width: 120px; min-height: calc(var(--hit) * 1.5); font-size: 15px; font-weight: 900;
  text-transform: uppercase; letter-spacing: .08em; color: var(--pc); touch-action: none; user-select: none; }
.mg-hold .lamp { width: 12px; height: 12px; border: var(--lw) solid currentColor; flex: none; }
.mg-hold.solid .lamp { background: #000; }
.mg-slots { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.mg-slot { display: flex; flex-direction: column; gap: 3px; min-width: 0; border: var(--lw) solid color-mix(in srgb, var(--pc) 40%, #000); padding: 4px 6px; }
.mg-slot.full { border-color: var(--pc); }
.mg-slot b { font-size: 12px; font-weight: 900; color: var(--pc); }
.mg-sl-bar { display: block; position: relative; height: 8px; }
.mg-sl-bar::after, .mg-sl-bar i { content: ""; position: absolute; inset: 0; background: var(--ladder-uni); -webkit-mask-image: var(--seg-mask); mask-image: var(--seg-mask); }
.mg-sl-bar::after { opacity: .18; }
.mg-sl-bar i { display: block; clip-path: inset(0 100% 0 0); }
.mg-sl-t { font-family: var(--font-seg7), var(--font-body); font-size: 11px; font-weight: 800; letter-spacing: var(--track-seg); color: var(--lav); white-space: nowrap; overflow: hidden; }
.mg-slot.full .mg-sl-t { color: var(--pc); }
/* ---- end MAGICATION (MG-S5b) ---- */
@container frame (max-width: 599px) {
  /* audit-fix: MIX on a phone upright: shorter faders so SOLO / MUTE stay above the keys, the two buttons share the strip */
  .strip { flex-basis: 100px; padding: 6px 3px; gap: 6px; }
  .strip-mid { height: 150px; }
  .strip-btns { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; align-self: stretch; }
  .strip-btns .sbtn { padding: 0 0 0 14px; min-width: 0; letter-spacing: 0; }
  .strip-btns .sbtn .lamp { left: 4px; width: 7px; height: 7px; margin-top: -3.5px; }
  .rack > .plate { flex-basis: 100%; }
  /* audit-fix: a pedal's head stays one row on a phone upright: the slot tag goes (the arrow rows between the cards say
     where it sits), the arrows narrow to 40px, the footswitch to its label */
  .rack-hd { flex-wrap: nowrap; }
  .rack-hd .rack-tag { display: none; }
  .rack-mv { min-width: 40px; }
  .footsw { min-width: 0; padding: 0 8px; gap: 6px; font-size: 11px; letter-spacing: .02em; }
}
@container frame (max-width: 419px) {
  .rack-hd > svg { display: none; }
  .rack-hd h2 .ttl { font-size: 14px; }
  .rack-mv { min-width: 36px; }
  .footsw { padding: 0 6px; }
  .rack-arrow { flex: 1 0 100%; flex-direction: row; justify-content: flex-start; gap: 6px; min-width: 0; padding: 0 8px; }   /* audit-fix: inset like the master row, */
  .rack-arrow b { display: inline-block; width: 20px; text-align: center; transform: rotate(90deg); }   /* the turned arrow in a square box: never past the edge */
  .rack-arrow.master { flex: 1 0 100%; flex-direction: row; justify-content: flex-start; gap: 6px; padding: 2px 8px; }   /* (11a: a slim row) */
}

/* ---------- ui-batch1 (Benjamin 10-21): the PATRICK Library relayout. The loaded sound (mark, name, quote) stays on top,
   across the cell; under it a RAIL down the left (the action buttons, then the category tabs, both as small grids) and
   the patches on the right in their own scroll box. The patches are square tiles on a grid whose column count and tile
   size both come from the room it has (auto-fill, a --tile floor that grows with the frame, 1fr: a tile is never more
   than one column's share wider than the floor, so the grid never spreads out). Pinned (#pages.pin-lib, always on this
   view) the rail and the grid each scroll on their own, the grid under its mask fades (libGridMask), the rail under the
   same short masks the old block had. Phone on its side (and .lib-cols, a short landscape frame outside the phone band):
   the loaded sound moves to the top of the left column, the grid takes the full height on the right. ---------- */
.plate[data-area="lib"] > .plate-body { --rail-w: clamp(232px, 22%, 320px); --tile: clamp(106px, 7.2cqw, 136px);
  display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "now now" "rail grid"; column-gap: 14px; row-gap: 0; }
.plate[data-area="lib"] .lib-now { grid-area: now; min-width: 0; }
.plate[data-area="lib"] .lib-side { display: contents; }
.plate[data-area="lib"] .lib-rail { grid-area: rail; display: flex; flex-direction: column; gap: 8px; min-width: 0; min-height: 0; align-self: start; max-height: 100%;
  overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; touch-action: pan-y; scrollbar-width: none; padding-bottom: 2px; }
.plate[data-area="lib"] .lib-rail::-webkit-scrollbar, .plate[data-area="lib"] .lib-side::-webkit-scrollbar { display: none; }
.plate[data-area="lib"] :is(.lib-side, .lib-rail).more { -webkit-mask-image: linear-gradient(#000 calc(100% - var(--fade-side-b)), transparent); mask-image: linear-gradient(#000 calc(100% - var(--fade-side-b)), transparent); }
.plate[data-area="lib"] :is(.lib-side, .lib-rail).less { -webkit-mask-image: linear-gradient(transparent, #000 var(--fade-side-t)); mask-image: linear-gradient(transparent, #000 var(--fade-side-t)); }
.plate[data-area="lib"] :is(.lib-side, .lib-rail).more.less { -webkit-mask-image: linear-gradient(transparent, #000 var(--fade-side-t), #000 calc(100% - var(--fade-side-b)), transparent); mask-image: linear-gradient(transparent, #000 var(--fade-side-t), #000 calc(100% - var(--fade-side-b)), transparent); }
.plate[data-area="lib"] .lib-actions { display: grid; grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); gap: 4px; padding: 0; flex: none; }
.plate[data-area="lib"] .lib-actions .pill { min-width: 0; height: var(--hit); padding: 0 3px; font-size: 11px; letter-spacing: .02em; overflow: hidden; text-overflow: ellipsis; }
.plate[data-area="lib"] .cats { display: grid; grid-template-columns: repeat(auto-fill, minmax(54px, 1fr)); gap: 2px; padding: 0; flex: none; position: relative; top: auto; z-index: auto; }
.plate[data-area="lib"] .cats button { flex: none; min-width: 0; min-height: var(--hit); height: auto; padding: 4px 0; gap: 3px; }
.plate[data-area="lib"] .grid-marks { grid-area: grid; min-width: 0; min-height: 0; grid-template-columns: repeat(auto-fill, minmax(var(--tile), 1fr)); grid-auto-rows: auto; gap: 4px; align-content: start; }
#pages.pin-lib .plate[data-area="lib"] .grid-marks { min-height: 0; }
/* the tiles: square, the mark in the patch's colour, the name as before ui-batch1 (the body face) in plain white (Benjamin
   10-21: no same-colour overload), its slot in Segment */
.plate[data-area="lib"] .pm { aspect-ratio: 1 / 1; min-height: auto; justify-content: center; gap: 5px; padding: 6px 4px; }
.plate[data-area="lib"] .pm .n { color: #fff; }
.plate[data-area="lib"] .pm svg { width: 28px; height: 28px; }
/* the loaded sound's big title (Benjamin 10-21, DESIGHNUS's spec): Patrick Strike in the patch's own colour (--patch, lifted
   to >= 4.5:1 where it's dark: --patch-ink), mixed case, +.02em, a crisp outline in a darker shade of the same hue drawn
   under the fill (only its outer half shows, the script keeps its weight). No blur, no shadow. No paint-order: no outline
   (never a centred one). The padding keeps the outline and the script's swashes inside the clipping box: the slant's
   overhang + the outline's outer half reach .25em past the last glyph's advance (I, J, f, T, F, measured at 88px; Benjamin
   10-23: INIT's T was cut off) and .15em before the first (j), so .28em right and .16em left (the margin cancels the left
   padding, the letters stay where they were) */
.plate[data-area="lib"] .lib-now .pname { font-family: var(--font-script); font-weight: 400; text-transform: none; letter-spacing: .02em; line-height: 1.12;
  padding: .04em .28em .06em .16em; margin-left: -.16em; text-overflow: ellipsis; color: var(--patch-ink, var(--patch, var(--bone)));
  /* ui-fix 10-21 (Benjamin: 2x bigger): the size is a clamp() on the frame's width (cqi, the frame is the container) held
     in --pn; fitName() (ui.js) shrinks a long name to the room it has (--pn-fit) instead of clipping it */
  --pn: clamp(60px, 5.6cqi, 88px); font-size: var(--pn-fit, var(--pn)); min-width: 0; flex: 0 1 auto; }
/* Benjamin 10-25: the big name is OUTLINE ONLY, hollow letters, one crisp line in the patch's colour (the retro look from the
   earlier preview; --name-line is the same line weight as the icon's). The editable text keeps a transparent fill. */
.plate[data-area="lib"] .lib-now .pname { --name-line: 2px; color: transparent; -webkit-text-fill-color: transparent; -webkit-text-stroke: var(--name-line) var(--patch-ink, var(--patch, var(--bone))); }
.plate[data-area="lib"] .lib-now .pname[contenteditable="true"] { -webkit-text-fill-color: var(--glow); -webkit-text-stroke-width: 0; }   /* (while it is being renamed: plain, readable text) */
.plate[data-area="lib"] .pm .s { font-family: var(--font-seg14); font-weight: 400; letter-spacing: var(--track-seg); line-height: 1; }
/* tablet and phone upright: the bigger name the old 4d-3 band rules gave the loaded sound */
@container frame ((max-width: 1279px) and (min-height: 501px)) or (max-width: 599px) {
  .plate[data-area="lib"] .lib-now .pname { --pn: clamp(52px, 14cqi, 76px); text-overflow: ellipsis; }
}
/* phone upright: a narrower rail (two buttons, three tabs a row), two columns of patches */
@container frame (max-width: 599px) {
  /* audit-fix (Benjamin 10-22): all seven actions in view at 430x932 (two columns of 34px buttons, 145px; the categories
     follow in the same rail, which scrolls under its fade), the patches three to a row on a square grid sized by the
     screen (--tile from the frame's width), snapping to whole rows */
  .plate[data-area="lib"] > .plate-body { --rail-w: minmax(0, 37%); --tile: clamp(62px, 17cqi, 104px); column-gap: 8px; }
  .plate[data-area="lib"] .lib-now { padding-bottom: 6px; }
  .plate[data-area="lib"] .lib-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 3px; }
  .plate[data-area="lib"] .lib-actions .pill { height: 34px; min-height: 34px; padding: 0 1px; letter-spacing: 0; }
  #pages.pin-lib .plate[data-area="lib"] .grid-marks { scroll-snap-type: y mandatory; scroll-padding-top: 0; }
  #pages.pin-lib .plate[data-area="lib"] .pm { scroll-snap-align: start; }
  .plate[data-area="lib"] .pm { gap: 3px; padding: 4px 3px; }
  .plate[data-area="lib"] .pm svg { width: 24px; height: 24px; }
  .plate[data-area="lib"] .pm .n { white-space: normal; text-align: center; text-wrap: balance; overflow-wrap: anywhere; line-height: 12px; max-height: 24px; text-overflow: clip; }
  .plate[data-area="lib"] .cats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* phone on its side: the loaded sound tops the left column, the grid the full height beside it */
@container frame (max-height: 500px) and (orientation: landscape) {
  .plate[data-area="lib"] > .plate-body { --rail-w: min(300px, 40%); --tile: 90px; }
  .plate[data-area="lib"] .lib-side { display: flex; flex-direction: column; gap: 6px; grid-column: 1; grid-row: 1 / 3; min-width: 0; min-height: 0;
    overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; touch-action: pan-y; scrollbar-width: none; }
  .plate[data-area="lib"] .lib-rail { overflow: visible; max-height: none; gap: 6px; flex: none; }
  .plate[data-area="lib"] .grid-marks { grid-column: 2; grid-row: 1 / 3; }
  /* (INIT tile, D10: row 1 the mark, the slot line and the tile; the name on its own row across all three, then the quote) */
  .plate[data-area="lib"] .lib-now .pname { --pn: clamp(46px, 5.6vw, 56px); text-overflow: ellipsis; }
  .plate[data-area="lib"] .lib-actions { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 3px; }
  .plate[data-area="lib"] .cats { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .plate[data-area="lib"] .cats button { padding: 1px 0; gap: 1px; }
  .plate[data-area="lib"] .cats button svg { width: 16px; height: 16px; }
  .plate[data-area="lib"] .pm { gap: 3px; padding: 4px 3px; }
  .plate[data-area="lib"] .pm svg { width: 24px; height: 24px; }
}
#pages.lib-cols .plate[data-area="lib"] > .plate-body { --rail-w: min(320px, 40%); }
#pages.lib-cols .plate[data-area="lib"] .lib-side { display: flex; flex-direction: column; gap: 6px; grid-column: 1; grid-row: 1 / 3; min-width: 0; min-height: 0;
  overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; touch-action: pan-y; scrollbar-width: none; }
#pages.lib-cols .plate[data-area="lib"] .lib-rail { overflow: visible; max-height: none; gap: 6px; flex: none; }
#pages.lib-cols .plate[data-area="lib"] .grid-marks { grid-column: 2; grid-row: 1 / 3; }
#pages.lib-cols .plate[data-area="lib"] .lib-now .pname { --pn: clamp(46px, 5.6vw, 56px); text-overflow: ellipsis; }
#pages.lib-cols .plate[data-area="lib"] .lib-actions { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 3px; }
#pages.lib-cols .plate[data-area="lib"] .cats { grid-template-columns: repeat(6, minmax(0, 1fr)); }

/* ---------- INIT tile + rainbow user patches (Benjamin 10-22): the INIT tile and every filled user tile (.pm.rainbow), the
   loaded INIT / user sound's big mark and title (.rainbow), and the Yours tab's mark share one look: the coin's gradient
   (one hidden <linearGradient id="coin40">, every mark is 40x40), rainbow text, and the splash's chrome band wiping across
   now and then (color-dodge on OLED black lights only the strokes and the letters; transform only, on the compositor).
   Factory tiles keep their category colours. No shadow, blur or glow; square corners. ---------- */
.rainbow svg [stroke="currentColor"], svg.rainbow [stroke="currentColor"] { stroke: url(#coin40); }
.rainbow svg [fill="currentColor"], svg.rainbow [fill="currentColor"] { fill: url(#coin40); }
/* (INIT polish, Benjamin 10-22) the small tile names' own rainbow: --rainbow's stops from #F57837 to #566CEC (4.68:1 on
   black), re-spread evenly, so it never reaches the violets (#7539DF 3.32:1, #9836B8 3.49:1) below 4.5:1. Smooth, in oklch */
:root { --rainbow-text: linear-gradient(90deg in oklch, #F57837 0%, #F79137 10%, #F4B43B 20%, #F6CF42 30%, #D5E244 40%, #A9ED43 50%, #79EE5A 60%, #53E8B8 70%, #43D0EC 80%, #45A7EF 90%, #566CEC 100%);
  --rainbow-text-fallback: linear-gradient(90deg, #F57837, #F79137, #F4B43B, #F6CF42, #D5E244, #A9ED43, #79EE5A, #53E8B8, #43D0EC, #45A7EF, #566CEC); }
.plate[data-area="lib"] .pm.rainbow .n { background: var(--rainbow-text-fallback); background: var(--rainbow-text); -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent; }
.pm.rainbow { position: relative; clip-path: inset(0); background: #000; }   /* (clip-path, not overflow: hidden, which drops a grid tile's automatic minimum size and collapsed its row) */
.pm.rainbow.cur { border-image: var(--rainbow-fallback) 1; border-image: var(--rainbow) 1; }
@media (hover: hover) { .pm.rainbow:hover { border-color: var(--ring); } }
.pm.rainbow::after { content: ""; position: absolute; left: 0; top: 0; width: 300%; height: 100%; pointer-events: none; mix-blend-mode: color-dodge; opacity: .85;
  background: var(--chrome-band); transform: translateX(-66.667%); animation: init-wipe 11s ease-in-out var(--wd, 2.5s) infinite; }
.pm.rainbow.wipe::after { animation: init-wipe-now .9s ease-in-out; }   /* hover / tap: one sweep now, in place of the periodic one */
@keyframes init-wipe { 0%, 88% { transform: translateX(-66.667%); } 100% { transform: translateX(0); } }
@keyframes init-wipe-now { from { transform: translateX(-66.667%); } to { transform: translateX(0); } }
/* the big title, rainbow (INIT and user sounds): the same OUTLINE-ONLY look, the line itself rainbow with the chrome band
   crossing it (Benjamin 10-25). ::after repeats the text (data-text, kept by ui.js; its "/ ''" alt text keeps it out of the
   accessible name) BEHIND the title (z-index -1 inside the title's own stacking context) with the rainbow and the band
   clipped to its glyphs grown by a 2x-line stroke (a near-transparent stroke colour: background-clip:text counts the stroke only when it has some alpha); the title's own fill is the page black and covers the glyph interior, so
   only the outline ring of the rainbow shows. Same font, size (--pn-fit), padding and tracking by inheritance, so the two
   stay pixel-aligned; the band moves on ::after only. */
.plate[data-area="lib"] .lib-now .pname.rainbow { position: relative; z-index: 0; isolation: isolate; caret-color: #fff; --patch: #79EE5A; color: #000; -webkit-text-fill-color: #000; -webkit-text-stroke: 0; }
.plate[data-area="lib"] .lib-now .pname.rainbow[contenteditable="true"] { -webkit-text-fill-color: var(--glow); }
.plate[data-area="lib"] .lib-now .pname.rainbow::after { content: attr(data-text); content: attr(data-text) / ""; position: absolute; inset: 0; z-index: -1; padding: inherit;
  white-space: nowrap; overflow: hidden; text-overflow: clip; pointer-events: none; -webkit-user-select: none; user-select: none;
  color: transparent; -webkit-text-fill-color: transparent; -webkit-text-stroke: calc(2 * var(--name-line)) rgba(0, 0, 0, .01);
  background: var(--chrome-band) 100% 0 / 300% 100% no-repeat, var(--rainbow-fallback);
  background: var(--chrome-band) 100% 0 / 300% 100% no-repeat, var(--rainbow);
  -webkit-background-clip: text; background-clip: text; animation: init-title-wipe 9s ease-in-out 1.2s infinite; }
@keyframes init-title-wipe { 0%, 88% { background-position: 100% 0, 0 0; } 100% { background-position: 0% 0, 0 0; } }
/* the rename counter (after EDITED): the slot line's style, the cell colour when it's full */
.name-count { font-family: var(--font-seg14); font-size: 11px; color: var(--lav); letter-spacing: var(--track-seg); white-space: nowrap; flex: none; }
.name-count.full { color: var(--pc); }
@media (prefers-reduced-motion: reduce) { .pm.rainbow::after, .plate[data-area="lib"] .lib-now .pname.rainbow::after { animation: none !important; } }

/* (ui-fix 10-21, Benjamin: the portrait perf row is back to the one sideways-scrolling strip it was before 9b34de9;
   the two-row wrap there stretched OCT / KEYS+ / HIDE KEYS and ate the height the big title now uses) */
/* (fill-1080: a stray top-level "}" stood here; harmless while it was the file's last token, it would swallow the next rule) */

/* ---------- 1080p fill (Benjamin 10-22: on 1920x1080 the cells felt empty): from a 1800x1000 frame the stage's controls
   grow with the room (knobs ~1.3x, hit targets 56px, labels and readouts one step up), each cell's slack is shared
   between its rows instead of pooling at the bottom, the FX rack's cards take wider slots, and one primary knob per
   cell is a hero dial. A second step from 2400x1300 (2560x1440). The deck and the header keep their sizes. Phones,
   tablets and 1440x900 are untouched (all of it sits behind these two frame queries) ---------- */
@container frame (min-width: 1800px) and (min-height: 1000px) {
  #pages { --hit: 56px; }
  #pages .rootkeys { --hit: 48px; }   /* the root keyboard sizes its 14 columns off --hit; at 56 it outgrew the Blocks cell */
  #pages .ctl { --dial: 96px; } #pages .ctl.s { --dial: 84px; } #pages .ctl.xs { --dial: 76px; } #pages .ctl.huge { --dial: 176px; }
  #pages .ctl .lab { font-size: 15px; line-height: 17px; margin-top: 8px; }
  #pages .ctl .val { font-size: 15px; line-height: 20px; min-height: 20px; }
  #pages .ctl.huge .val { font-size: 19px; line-height: 24px; }
  #pages :is(.pill, .seg button, .footsw, .play-big) { font-size: 13px; }
  #pages .plate-head h2 .ttl { font-size: 19px; }
  #pages .plate { padding: 12px 18px 10px; }
  #pages .plate-body { gap: 16px; justify-content: space-evenly; }
  #pages .row { gap: 18px 22px; }
  /* Syn Rise S2: each oscillator row gained its PW knob; a little less space between the controls keeps a row on one line */
  #pages .plate[data-area="osc"] .row { column-gap: 14px; }
  /* the hero dial: one primary knob a cell (playful, the rest stay a size down) */
  #pages :is(.plate[data-area="lfo"] .ctl[aria-label="Rate"], .plate[data-area="arp"] .ctl[aria-label="Tempo"], .plate[data-area="dly"] .ctl[aria-label="Time"],
    .plate[data-area="cho"] .ctl[aria-label="Depth"], .plate[data-area="pha"] .ctl[aria-label="Rate"], .plate[data-area="spr"] .ctl[aria-label="Spring mix"],
    .plate[data-area="sw"] .ctl[aria-label="Sens"], .plate[data-area="star"] .ctl[aria-label="Shape"], .plate[data-area="flt"] .ctl[aria-label="Cutoff"],
    .plate[data-area="pwm"] .ctl[aria-label="Depth"], .plate[data-area="lfo2"] .ctl[aria-label="Rate"],
    .plate[data-area="jenv"] .ctl[aria-label="T1"], .plate[data-area="mtx"] .ctl[aria-label="Amount 1"],
    .plate:is([data-area="mac"], [data-area="pmac"]) .ctl[aria-label="Macro 1"],
    .plate[data-area="pdco"] .ctl[aria-label="Width"], .plate[data-area="pdc2"] .ctl[aria-label="Detune"], .plate[data-area="pflt"] .ctl[aria-label="Cutoff"],
    .plate[data-area="ppwm"] .ctl[aria-label="Depth"], .plate[data-area="pshp"] .ctl[aria-label="T1"], .plate[data-area="plf2"] .ctl[aria-label="Rate"],
    .plate[data-area="pens"] .ctl[aria-label="Depth"]):not(.huge) { --dial: 128px; }   /* (S7b: the PULSAR view's six) */
  .rack > .plate { --rb: 440px; }
  .rack > .plate[data-area="sw"], .rack > .plate[data-area="sv"] { --rb: 700px; }
  .rack > .plate[data-area="spr"], .rack > .plate[data-area="str"] { --rb: 520px; }
  /* the Library's patch marks grow into their 1fr tiles instead of floating small in them */
  .plate[data-area="lib"] .pm { gap: 6px; padding: 8px 4px 6px; }
  .plate[data-area="lib"] .pm svg { width: 38px; height: 38px; }
  .plate[data-area="lib"] .pm .n { font-size: 13px; line-height: 15px; }
  .plate[data-area="lib"] .lib-now > .init-tile { padding-top: 7px; padding-bottom: 7px; }   /* (INIT polish: its mark + name + P00 sat 1 px low here and at 2560; the grid tiles keep 8/6) */
  /* ---- MAGICATION (MG-S5b): wider slots; MIX the cell's hero dial */
  .rack > .plate[data-area="mg"] { flex: 1 0 100%; }   /* (a row of its own: its six groups in two lines) */
  .rack > .plate[data-area="mgs"] { --rb: 520px; }
  #pages .plate[data-area="mg"] .ctl[aria-label="Mix"]:not(.huge) { --dial: 128px; }
  /* ---- end MAGICATION (MG-S5b) ---- */
}
@container frame (min-width: 2400px) and (min-height: 1300px) {
  #pages { --hit: 60px; }
  #pages .ctl { --dial: 124px; } #pages .ctl.s { --dial: 104px; } #pages .ctl.xs { --dial: 96px; } #pages .ctl.huge { --dial: 220px; }
  #pages .ctl .lab { font-size: 17px; line-height: 19px; }
  #pages .ctl .val { font-size: 17px; line-height: 22px; min-height: 22px; }
  #pages .ctl.huge .val { font-size: 22px; line-height: 28px; }
  #pages :is(.pill, .seg button, .footsw, .play-big) { font-size: 14px; }
  #pages .plate[data-area="lib"] .lib-actions .pill { letter-spacing: 0; padding: 0 1px; }   /* (save-new: Previous / Save new were 1-2 px over at 14 px) */
  #pages .plate-head h2 .ttl { font-size: 22px; }
  #pages :is(.plate[data-area="lfo"] .ctl[aria-label="Rate"], .plate[data-area="arp"] .ctl[aria-label="Tempo"], .plate[data-area="dly"] .ctl[aria-label="Time"],
    .plate[data-area="cho"] .ctl[aria-label="Depth"], .plate[data-area="pha"] .ctl[aria-label="Rate"], .plate[data-area="spr"] .ctl[aria-label="Spring mix"],
    .plate[data-area="sw"] .ctl[aria-label="Sens"], .plate[data-area="star"] .ctl[aria-label="Shape"], .plate[data-area="flt"] .ctl[aria-label="Cutoff"],
    .plate[data-area="pwm"] .ctl[aria-label="Depth"], .plate[data-area="lfo2"] .ctl[aria-label="Rate"],
    .plate[data-area="jenv"] .ctl[aria-label="T1"], .plate[data-area="mtx"] .ctl[aria-label="Amount 1"],
    .plate:is([data-area="mac"], [data-area="pmac"]) .ctl[aria-label="Macro 1"],
    .plate[data-area="pdco"] .ctl[aria-label="Width"], .plate[data-area="pdc2"] .ctl[aria-label="Detune"], .plate[data-area="pflt"] .ctl[aria-label="Cutoff"],
    .plate[data-area="ppwm"] .ctl[aria-label="Depth"], .plate[data-area="pshp"] .ctl[aria-label="T1"], .plate[data-area="plf2"] .ctl[aria-label="Rate"],
    .plate[data-area="pens"] .ctl[aria-label="Depth"]):not(.huge) { --dial: 164px; }   /* (S7b) */
  .rack > .plate { --rb: 560px; }
  .rack > .plate[data-area="sw"], .rack > .plate[data-area="sv"] { --rb: 900px; }
  .rack > .plate[data-area="spr"], .rack > .plate[data-area="str"] { --rb: 660px; }
  .plate[data-area="lib"] .pm svg { width: 46px; height: 46px; }
  .plate[data-area="lib"] .pm .n { font-size: 14px; line-height: 16px; }
  /* ---- MAGICATION (MG-S5b) */
  .rack > .plate[data-area="mgs"] { --rb: 640px; }
  #pages .plate[data-area="mg"] .ctl[aria-label="Mix"]:not(.huge) { --dial: 164px; }
  /* ---- end MAGICATION (MG-S5b) ---- */
}

/* ---------- tabs-hdr (Benjamin 10-22): an UPRIGHT phone only (portrait, under 600 wide) puts the six page tabs in the
   header's top row as close-packed squares, no gaps (48px at 430 wide, 44 at the narrowest), where they had a spaced
   row of their own under it (header 120 -> 86px at 430). The rest of the header re-arranges, nothing is dropped:
     row 1 (48): [6 tabs] [spectrum, the room that is left, still a full-height tap target] [?]
     row 2 (22): [logo] [patch name, the whole width, 11px, so even the longest factory name is never cut] [MIDI LED, under ?]
   The name moves to its own slim line because next to the tabs it would have ~96px for up to ~127px of text.
   MIDI shows its square LED only (the words stay its title); full screen stays off as before. Landscape phones,
   tablets and desktops never match this block. Square, OLED black, no shadow or glow; the tab colours and the active
   fill are the tabs' own rules. */
@media (orientation: portrait) and (max-width: 599px) {
  @container frame (max-width: 599px) {
    /* --tq: the square's side, the full 48px hit (--hit) at 430 wide, never under 44 on the narrowest phones (375) */
    #bar { --tq: clamp(44px, calc((100cqw - 140px) / 6), var(--hit)); display: grid;
      grid-template-columns: 22px calc(6 * var(--tq) - 26px) minmax(0, 1fr) 22px var(--tq); grid-template-rows: var(--tq) 22px;
      gap: 4px; align-items: stretch; }
    #bar #tabs { grid-column: 1 / 3; grid-row: 1; width: calc(6 * var(--tq)); display: grid; grid-template-columns: repeat(6, var(--tq)); grid-template-rows: var(--tq); gap: 0; }
    #bar .tab { width: var(--tq); height: var(--tq); min-width: 0; max-height: none; aspect-ratio: auto; padding: 0; }
    #bar .tab .ttl { font-size: 11px; }
    #bar .tab:hover { outline: 0; }   /* close-packed: a phone's sticky tap-hover outline would sit on the next tab (keyboard focus keeps its ring) */
    #bar .minispec { grid-column: 3 / 5; grid-row: 1; width: 100%; min-width: 0; height: var(--tq); }
    #bar .status { display: contents; }
    #bar #btn-help { grid-column: 5; grid-row: 1; width: var(--tq); height: var(--tq); min-height: 0; }
    #bar .brand { grid-column: 1; grid-row: 2; }
    #bar #logo { width: 22px; height: 22px; }
    #bar .ticker { grid-column: 2 / 5; grid-row: 2; flex: none; width: auto; height: 22px; padding: 0 8px; }
    #bar #ticker { font-size: 11px !important; }
    #bar #stat-midi { grid-column: 5; grid-row: 2; justify-content: center; height: 22px; padding: 0; }
    #bar #stat-midi > span { display: none; }
  }
}

/* knob-fix (Benjamin 10-25): tap a value to type it. The field takes the readout's place (the readout steps aside), in its
   face and colour, a square 1 px box on black: no shadow, glow or rounding. 16 px on touch so iOS doesn't zoom the page. */
.ctl.editing .val, .fader.editing .val { display: none; }
.val-in { box-sizing: border-box; width: 100%; min-width: 0; margin: 0; padding: 0 2px; border: 1px solid var(--vc, var(--kc, var(--pc, currentColor))); border-radius: 0; background: #000; color: var(--vc, var(--kc, var(--pc, currentColor))); font: 800 13px/16px var(--font-seg7), var(--font-body); letter-spacing: var(--track-seg); text-align: center; outline: none; box-shadow: none; text-shadow: none; -webkit-appearance: none; appearance: none; user-select: text; -webkit-user-select: text; cursor: text; touch-action: manipulation; caret-color: currentColor; }
.val-in::selection { background: var(--vc, var(--kc, var(--pc, currentColor))); color: #000; }
.ctl.huge .val-in { font-size: 16px; line-height: 20px; }
.fader .val-in { font-size: 11px; line-height: 12px; }
@media (pointer: coarse) { .val-in, .ctl.huge .val-in, .fader .val-in { font-size: 16px; } }

/* ---------------------------------------------------------------- GOLDCHAIN (docs/stages/goldchain.md, PLAN section 3)
   MOD | GOLDCHAIN: two view states of the one MOD page; the five cells; the knobs' menu; the gold two-link badge; LINK mode.
   Square everywhere (the global rule), gold on black, bold capitals */
.page.mod:not(.sub-gch) > .plate[data-area^="gc"], .page.mod.sub-gch > .plate:not([data-area^="gc"]) { display: none; }
@container frame (max-width: 1279px) or ((max-height: 500px) and (orientation: landscape)) {
  .page.mod.sub-gch { grid-template-rows: auto; }
  .plate[data-area="gcs"], .plate[data-area="gct"] { grid-column: 1 / -1; }
}
.subtab.gc-subtab svg.gc-mk, .subtab svg.gc-mk { width: 14px; height: 14px; flex: none; margin-right: 5px; }
.gc-fig { color: var(--gc-gold); border-color: var(--gc-gold); }
.gc-lamp { display: inline-block; width: 9px; height: 9px; margin-left: 6px; border: 2px solid var(--gc-gold); vertical-align: middle; }
.gc-lamp.on { background: var(--gc-gold); }
.plate-head .gc-tlamp { margin-left: auto; width: 12px; height: 12px; }
.gc-tag { display: inline-flex; align-items: center; height: 24px; padding: 0 8px; border: 2px solid var(--ink-3); color: var(--ink-3); font-size: 11px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; }
.gc-tag.on { border-color: var(--gc-gold); color: var(--gc-gold); }
.pill.gc-link { display: inline-flex; align-items: center; gap: 6px; border-color: var(--gc-gold); color: var(--gc-gold); }
.pill.gc-link svg { width: 16px; height: 16px; }
.pill.gc-link.solid, .pill.gc-gatelane.solid { background: var(--gc-gold); color: #000; }
.gc-linkrow { gap: 10px; align-items: center; justify-content: space-between; }
.gc-linkcol { display: flex; flex-direction: column; gap: 6px; align-items: flex-end; }
.gc-seqrow { flex-wrap: wrap; gap: 8px 12px; align-items: flex-end; }
.gc-dim { opacity: .5; }
.plate[data-area^="gc"] .segctl.off, .plate[data-area^="gc"] .sw.off { opacity: .45; }
canvas.gc-env, canvas.gc-steps { width: 100%; height: 96px; display: block; }
canvas.gc-meter { width: 100%; height: 40px; display: block; }
canvas.gc-steps { cursor: pointer; touch-action: none; }
.gc-steprow { gap: 8px; flex-wrap: wrap; align-items: center; }
.gc-pats { display: flex; gap: 4px; flex-wrap: wrap; }
.pill.gc-pat { height: 32px; padding: 0 9px; font-size: 11px; }
.gc-rows { display: flex; flex-direction: column; gap: 4px; width: 100%; }
.gc-row { display: grid; grid-template-columns: 18px minmax(0, 1fr) auto auto auto auto; align-items: center; gap: 6px; min-height: 44px; }
.gc-row .gc-n { color: var(--gc-gold); font-weight: 800; font-size: 12px; }
.gc-row.empty :is(.ctl, .sw, .gc-x) { opacity: .3; }
.gc-row.steppy .gc-name::after { content: " · steppy"; color: var(--ink-3); }
.gc-who { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.gc-name { background: transparent; border: 0; padding: 0; color: var(--bone); font-weight: 800; font-size: 12px; text-transform: uppercase; letter-spacing: .03em; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; min-height: 20px; }
.gc-row.empty .gc-name { color: var(--ink-3); cursor: default; }
.gc-bar { display: block; height: 4px; background: #1C1C22; }
.gc-bar > b { display: block; height: 100%; width: 0; background: var(--gc-gold); }
.gc-addrow { gap: 8px; align-items: center; }
.sel.gc-add { flex: 1; min-width: 0; }
.x.gc-x { min-height: 32px; padding: 0 8px; }
/* the badge: two square links at the control's top-right; its track's edge in gold */
:is(.ctl, .sw, .segctl, .pictoctl).gc-chained { position: relative; }
.gc-badge { position: absolute; top: 0; right: 0; width: 15px; height: 15px; color: var(--gc-gold); pointer-events: none; z-index: 2; }
.gc-badge svg { width: 100%; height: 100%; display: block; }
.ctl.gc-chained .dial .trk { stroke: var(--gc-gold); }
.ctl.gc-chained .lab { color: var(--gc-gold); }
.gc-flash { animation: gc-flash .7s step-end 1; }
@keyframes gc-flash { 0%, 40% { outline: 2px solid var(--gc-gold); outline-offset: 2px; } 20%, 60%, 100% { outline: 0 solid transparent; } }
html.gc-linking #pages :is(.ctl, .sw, .segctl)[data-param] { outline: 1px dashed color-mix(in srgb, var(--gc-gold) 60%, transparent); outline-offset: 1px; cursor: copy; }
html.gc-linking #pages .plate[data-area^="gc"] :is(.ctl, .sw, .segctl)[data-param] { outline: 0; cursor: auto; }
/* iOS: no callout, no selection on a long-press over a control (the long-press is the menu's) */
:is(.ctl, .sw, .segctl, .pictoctl, .fader) { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
/* the menu */
.gc-menu { position: fixed; z-index: 70; min-width: 248px; max-width: 320px; background: #000; border: 2px solid var(--gc-gold); padding: 4px; display: flex; flex-direction: column; gap: 2px; }
.gc-menu[hidden] { display: none; }
.gc-mh { display: flex; align-items: center; gap: 8px; padding: 4px 6px 6px; border-bottom: 2px solid var(--gc-gold); margin-bottom: 2px; color: var(--gc-gold); font-weight: 800; font-size: 12px; letter-spacing: .05em; text-transform: uppercase; }
.gc-mh-mk { width: 16px; height: 16px; flex: none; } .gc-mh-mk svg { width: 100%; height: 100%; display: block; }
.gc-mi { display: grid; grid-template-columns: 12px 1fr; column-gap: 8px; align-items: center; text-align: left; background: transparent; border: 0; color: var(--bone); padding: 6px; min-height: 36px; cursor: pointer; font-size: 12px; }
.gc-mi b { font-weight: 800; letter-spacing: .05em; text-transform: uppercase; }
.gc-mi span { grid-column: 2; color: var(--ink-2, #A8A8B8); font-size: 11px; text-transform: uppercase; letter-spacing: .03em; }
.gc-mi-mk { width: 8px; height: 8px; border: 2px solid var(--gc-gold); }
.gc-mi.on .gc-mi-mk { background: var(--gc-gold); }
.gc-mi:is(:hover, :focus-visible):not(.dis) { background: var(--gc-gold); color: #000; outline: 0; }
.gc-mi:is(:hover, :focus-visible):not(.dis) span { color: #000; }
.gc-mi:is(:hover, :focus-visible):not(.dis) .gc-mi-mk { border-color: #000; }
.gc-mi.dis { color: var(--ink-3); cursor: not-allowed; } .gc-mi.dis .gc-mi-mk { border-color: var(--ink-3); }
.gc-amt { display: grid; grid-template-columns: auto 1fr 48px; gap: 8px; align-items: center; padding: 6px; font-size: 11px; font-weight: 800; text-transform: uppercase; color: var(--gc-gold); }
.gc-amt .gc-mv { text-align: right; color: var(--bone); }
.gc-note { padding: 0 6px 4px; font-size: 11px; color: var(--ink-3); text-transform: uppercase; }
.gc-amt input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; height: 22px; background: transparent; margin: 0; cursor: pointer; }
.gc-amt input[type="range"]::-webkit-slider-runnable-track { height: 4px; background: #3A3A44; }
.gc-amt input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 18px; margin-top: -7px; background: var(--gc-gold); border: 0; }
.gc-amt input[type="range"]::-moz-range-track { height: 4px; background: #3A3A44; }
.gc-amt input[type="range"]::-moz-range-thumb { width: 12px; height: 18px; background: var(--gc-gold); border: 0; }
.gc-amt input[type="range"]:focus-visible { outline: 2px solid var(--gc-gold); outline-offset: 2px; }
/* GOLDCHAIN: its long cell titles wrap on a phone instead of running out of the cell */
@container frame (max-width: 599px) { .plate[data-area^="gc"] .plate-head h2 .ttl { white-space: normal; line-height: 1.15; } .plate[data-area^="gc"] .plate-head { flex-wrap: wrap; } }
/* GOLDCHAIN: CHAINED's rows on a phone: the knob's name on its own line, its controls under it */
@container frame (max-width: 599px) {
  .gc-row { grid-template-columns: 18px auto auto auto minmax(0, 1fr) auto; grid-template-areas: "n who who who who x" "n amt inv boost . ."; row-gap: 4px; }
  .gc-row > .gc-n { grid-area: n; } .gc-row > .gc-who { grid-area: who; } .gc-row > .ctl { grid-area: amt; }
  .gc-row > :nth-child(4) { grid-area: inv; } .gc-row > :nth-child(5) { grid-area: boost; } .gc-row > .gc-x { grid-area: x; }
  #pages .gc-row :is(.ctl, .sw) { --dial: 56px; }
}
