  :root, html[data-theme="paper"]{
    --paper:#F7F6F1; --ink:#171613; --ink-soft:#59564C; --ink-faint:#93907F;
    --hair:#DBD8CB; --hair-strong:#B8B4A2; --amber:#C6752B; --amber-soft:#F0DEC8;
    --rubric:#7C3238; --rubric-soft:#F3EEE9;
    --workspace:#EAE8E0;
    --ring: rgba(23,22,19,0.12);
    --shadow-sm: 0 1px 2px rgba(23,22,19,0.06);
    --shadow-md: 0 4px 12px -4px rgba(23,22,19,0.14), 0 1px 0 rgba(23,22,19,0.04);
    --radius: 6px;
    --radius-lg: 10px;
    --radius-pill: 999px;
    --font-xs: 11px;  /* eyebrow/meta labels — uppercase, small-caps text; small reads fine here */
    --font-sm: 12.5px; /* dense functional UI — rows, tabs, data values, dock text */
    --font: 15px;      /* primary controls & anything meant to be read carefully (tips, warnings) */
    --font-lg: 20px;   /* brand wordmark, major headers */
    --s1:8px; --s2:16px; --s3:24px; --s4:32px; --s6:48px;
    --glow1-a: rgba(198,117,43,0.22); --glow1-b: rgba(198,117,43,0.08);
    --glow2-a: rgba(157,182,157,0.26); --glow2-b: rgba(157,182,157,0.10);
    --sample-lane-white:#F2F0E8;
    --sample-lane-black:#C5C0B4;
    --sample-lane-edge:#B0AA9C;
    --sample-track-bg:var(--workspace);
    --piano-key-white:#F5F3EE;
    --piano-key-black:#1A1816;
    --piano-key-divider:#B8B4A2;
    /* Tint mixed into a white key's own background on hover/press — defaults to the accent
       color, but a theme where the accent itself is near-white (Noir) needs to override this
       to something dark, or the "lit up" state is invisible against the already-light key. */
    --piano-key-white-glow:var(--amber);
  }
  /* Slate — #222831 · #393E46 · #00ADB5 · #EEEEEE */
  html[data-theme="slate"]{
    --paper:#393E46; --ink:#EEEEEE; --ink-soft:#B0B6BE; --ink-faint:#7E868F;
    --hair:#2F353D; --hair-strong:#4A525C;
    --amber:#00ADB5; --amber-soft:#1A4044;
    --rubric:#00ADB5; --rubric-soft:#1A4044;
    --workspace:#222831;
    --ring: rgba(0,173,181,0.28);
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.4);
    --shadow-md: 0 8px 24px -8px rgba(0,0,0,0.55), 0 1px 0 rgba(255,255,255,0.04);
    --glow1-a: rgba(0,173,181,0.24); --glow1-b: rgba(0,173,181,0.09);
    --glow2-a: rgba(126,134,143,0.20); --glow2-b: rgba(126,134,143,0.07);
    --sample-lane-white:#3E454E;
    --sample-lane-black:#1A1E24;
    --sample-lane-edge:#4E5761;
    --sample-track-bg:#222831;
    --piano-key-white:#EEEEEE;
    --piano-key-black:#141820;
    --piano-key-divider:#4A525C;
  }
  /* Ink — warm dark paper */
  html[data-theme="ink"]{
    --paper:#161513; --ink:#F1EEE6; --ink-soft:#B8B4A6; --ink-faint:#726E64;
    --hair:#2B2925; --hair-strong:#3E3B35; --amber:#D9873C; --amber-soft:#3A2A18;
    --rubric:#B85A5F; --rubric-soft:#2A1C1A;
    --workspace:#0F0E0C;
    --ring: rgba(241,238,230,0.14);
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.35);
    --shadow-md: 0 8px 24px -8px rgba(0,0,0,0.55), 0 1px 0 rgba(255,255,255,0.03);
    --glow1-a: rgba(217,135,60,0.24); --glow1-b: rgba(217,135,60,0.09);
    --glow2-a: rgba(114,110,100,0.20); --glow2-b: rgba(114,110,100,0.07);
    --sample-lane-white:#383634;
    --sample-lane-black:#10100E;
    --sample-lane-edge:#2A2826;
    --sample-track-bg:#1A1A1A;
    --piano-key-white:#E6E2D9;
    --piano-key-black:#0C0B0A;
    --piano-key-divider:#4A4740;
  }
  /* Noir — true dark, black + white */
  html[data-theme="noir"]{
    --paper:#0A0A0A; --ink:#FFFFFF; --ink-soft:#C8C8C8; --ink-faint:#7A7A7A;
    --hair:#1A1A1A; --hair-strong:#2E2E2E;
    --amber:#FFFFFF; --amber-soft:#1F1F1F;
    --rubric:#FFFFFF; --rubric-soft:#1A1A1A;
    --workspace:#000000;
    --ring: rgba(255,255,255,0.18);
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.6);
    --shadow-md: 0 8px 28px -8px rgba(0,0,0,0.8), 0 1px 0 rgba(255,255,255,0.06);
    --glow1-a: rgba(255,255,255,0.12); --glow1-b: rgba(255,255,255,0.04);
    --glow2-a: rgba(122,122,122,0.18); --glow2-b: rgba(122,122,122,0.06);
    --sample-lane-white:#383838;
    --sample-lane-black:#0A0A0A;
    --sample-lane-edge:#2E2E2E;
    --sample-track-bg:#1A1A1A;
    --piano-key-white:#E8E8E8;
    --piano-key-black:#000000;
    --piano-key-divider:#2E2E2E;
    /* Noir's --amber is white, same as the key itself — mixing it into a white key on
       hover/press would be invisible, so this theme mixes toward dark instead. */
    --piano-key-white-glow:#3A3A3A;
  }
  *{ box-sizing:border-box; }
  html, body{ height:100%; margin:0; }
  body{
    background:var(--paper); color:var(--ink);
    font-family:'IBM Plex Sans', sans-serif; font-size:var(--font);
    transition:background-color .25s ease, color .25s ease;
    overflow:hidden;
    -webkit-font-smoothing:antialiased;
  }
  button, input, select{ font:inherit; color:inherit; }
  button{ cursor:pointer; }
  /* Native checkboxes otherwise render in the browser's default blue regardless of theme —
     accent-color is the one line needed to make them follow the app's own accent instead.
     Applied globally so every checkbox matches without a per-instance class (`.sample-map-check
     input` used to set this locally before this rule existed; still correct now, just redundant
     — left alone rather than churned for its own sake). */
  input[type="checkbox"]{ accent-color:var(--amber); cursor:pointer; }
  input[type="radio"]{ accent-color:var(--amber); cursor:pointer; }
  select{
    appearance:none; -webkit-appearance:none; -moz-appearance:none;
    background-color:var(--paper); color:var(--ink);
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    padding:5px 28px 5px 8px; cursor:pointer;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23726064' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
    background-repeat:no-repeat; background-position:right 8px center;
    transition:border-color .12s ease, box-shadow .12s ease;
  }
  select:hover{ border-color:var(--ink-faint); }
  select:focus{ outline:none; border-color:var(--amber); box-shadow:0 0 0 2px var(--ring); }
  select:disabled{ opacity:.45; cursor:not-allowed; }
  select option,
  select optgroup{
    background:var(--paper); color:var(--ink);
  }
  /* Scoped to the document root, not just `select` — declaring color-scheme only on form
     controls left native `<select>` rendering inconsistent (closed box staying light/white
     despite the explicit background-color override below) on Chromium/Windows. Root-level is
     also the spec-standard usage: it's a document-wide hint, not a per-control one. */
  html[data-theme="slate"],
  html[data-theme="ink"],
  html[data-theme="noir"]{ color-scheme:dark; }
  * { scrollbar-width: thin; scrollbar-color: var(--hair-strong) transparent; }
  ::-webkit-scrollbar{ width:10px; height:10px; }
  ::-webkit-scrollbar-track{ background:transparent; }
  ::-webkit-scrollbar-thumb{
    background:var(--hair-strong); border-radius:6px; border:2px solid var(--paper);
    background-clip:padding-box;
  }
  ::-webkit-scrollbar-thumb:hover{ background:var(--ink-faint); }
  ::-webkit-scrollbar-corner{ background:transparent; }
  .mono{ font-family:'IBM Plex Mono', monospace; }
  .material-symbols-outlined{
    font-family:'Material Symbols Outlined'; font-weight:normal; font-style:normal;
    font-size:16px; line-height:1; letter-spacing:normal; text-transform:none;
    display:inline-block; white-space:nowrap; word-wrap:normal; direction:ltr;
    -webkit-font-feature-settings:'liga'; -webkit-font-smoothing:antialiased; vertical-align:middle;
  }

  /* —— shell —— */
  .app{ height:100vh; display:flex; flex-direction:column; }
  /* Grid, not flex+space-between — with exactly 2 children, space-between pins them to the
     edges but can't center anything relative to the bar as a whole. 1fr/auto/1fr is the
     standard recipe for "center the middle item regardless of how wide its neighbors are":
     the two 1fr columns stay equal width (as long as neither's content overflows its share),
     which keeps the auto-width Mode column exactly centered in the bar. */
  .topbar{
    display:grid; grid-template-columns:1fr auto 1fr; align-items:center;
    column-gap:var(--s3); row-gap:8px;
    padding:10px var(--s3); border-bottom:1px solid var(--ink); flex-shrink:0;
    background:var(--paper);
  }
  .topbar > .brand{ justify-self:start; }
  .topbar > .topbar-right{ justify-self:end; }
  .brand{
    display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  }
  .brand-toolbar{ display:flex; align-items:center; gap:6px; }
  .brand-toolbar-sep{ width:1px; height:20px; background:var(--hair-strong); flex-shrink:0; }
  .brand-icon-btn{
    display:inline-flex; align-items:center; justify-content:center;
    width:34px; height:34px; padding:0; flex-shrink:0;
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:transparent; color:var(--ink-soft); cursor:pointer;
    transition:border-color .15s ease, color .15s ease, background .15s ease;
  }
  .brand-icon-btn:hover{ border-color:var(--ink-faint); color:var(--ink); background:var(--workspace); }
  .brand-icon-btn .material-symbols-outlined{ font-size:21px; }
  .brand-icon-btn-primary{ border-color:var(--amber); background:var(--amber-soft); color:var(--ink); }
  .brand-icon-btn-primary:hover{ border-color:var(--amber); background:var(--amber-soft); }
  .brand-title{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-lg); font-weight:500;
    letter-spacing:0.14em; color:var(--ink); text-decoration:none;
    white-space:nowrap; flex-shrink:0;
    transition:color .15s ease;
  }
  .brand-title:hover{ color:var(--amber); }
  .topbar-right{ display:flex; align-items:center; gap:var(--s3); flex-wrap:wrap; row-gap:8px; }
  .topbar-tour-wrap{ display:flex; align-items:center; gap:var(--s3); flex-wrap:wrap; row-gap:8px; }
  .topbar-group{
    display:flex; align-items:center; gap:8px; flex-shrink:0;
  }
  .topbar-group-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    letter-spacing:0.04em; white-space:nowrap;
  }

  /* —— mode segmented control —— */
  .mode-tabs{
    display:flex; padding:3px; gap:2px;
    border:1px solid var(--hair-strong); border-radius:var(--radius-pill);
    background:var(--workspace);
  }
  .mode-tab{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font);
    padding:5px 14px; background:transparent; color:var(--ink-soft);
    border:none; border-radius:var(--radius-pill);
    transition:background .15s ease, color .15s ease, box-shadow .15s ease;
  }
  .mode-tab:hover{ color:var(--ink); }
  .mode-tab.on{
    background:var(--ink); color:var(--paper);
    box-shadow:var(--shadow-sm);
  }
  body.mode-paint .mode-tab#paintModeBtn.on{
    background:var(--rubric); color:var(--workspace);
  }
  /* Icon-only variant — align/valign buttons in the label typography panel and any future
     icon-based segmented control, tighter than the default text-padded tab. */
  .mode-tab-icon{ padding:6px 10px; display:flex; align-items:center; justify-content:center; flex:1; }
  .mode-tab-icon .material-symbols-outlined{ font-size:16px; }

  /* —— layout —— */
  .shell{
    --shell-rail-w:200px;
    --shell-dock-w:280px;
    display:grid;
    grid-template-columns:var(--shell-rail-w) 6px 1fr 6px var(--shell-dock-w);
    flex:1; min-height:0; overflow:hidden;
  }
  body.mode-samples{
    --shell-rail-w:260px;
    --shell-dock-w:300px;
  }
  .panel-resizer{
    cursor:col-resize; touch-action:none;
    background:transparent; position:relative; z-index:4;
    transition:background .12s ease;
  }
  .panel-resizer::after{
    content:''; position:absolute; top:0; bottom:0; left:1px; width:3px;
    background:transparent; transition:background .12s ease;
  }
  .panel-resizer:hover::after,
  .panel-resizer.dragging::after{
    background:color-mix(in srgb, var(--amber) 45%, transparent);
  }
  body.panel-resizing{ cursor:col-resize; user-select:none; }
  body.panel-resizing *{ cursor:col-resize !important; }
  .shell > .rail,
  .shell > .workspace,
  .shell > .dock{ min-height:0; min-width:0; }
  .rail{
    border-right:1px solid var(--hair-strong);
    padding:var(--s3) var(--s2); overflow-y:auto;
    background:var(--paper);
  }
  .preset-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    text-transform:uppercase; letter-spacing:.08em; padding:0 4px; margin-bottom:10px;
  }
  .preset-btn{
    display:block; width:100%; text-align:left;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font);
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    padding:8px 10px; margin-bottom:6px;
    background:var(--paper); color:var(--ink-soft);
    transition:border-color .15s ease, background .15s ease, color .15s ease, box-shadow .15s ease;
  }
  .preset-btn:hover{
    border-color:var(--ink-faint); color:var(--ink); background:var(--workspace);
  }
  .preset-btn.active{
    border-color:var(--amber); color:var(--ink);
    background:var(--amber-soft); box-shadow:inset 2px 0 0 var(--amber);
  }
  .rail-sep{
    height:1px; background:var(--hair-strong); margin:var(--s2) 0; border:none;
  }
  .preset-search{
    width:100%; font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:7px 9px; margin-bottom:10px;
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); color:var(--ink);
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .preset-search::placeholder{ color:var(--ink-faint); }
  .preset-search:focus{ outline:none; border-color:var(--amber); box-shadow:0 0 0 3px var(--ring); }
  .plugin-meta-label{
    display:block;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    color:var(--ink-faint); letter-spacing:.04em; margin:0 0 4px;
  }
  .plugin-meta-field{
    width:100%; font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:7px 9px; margin-bottom:10px;
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); color:var(--ink);
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .plugin-meta-field:focus{ outline:none; border-color:var(--amber); box-shadow:0 0 0 3px var(--ring); }
  .plugin-meta-field:last-child{ margin-bottom:0; }
  .plugin-plug-field{
    max-width:88px; letter-spacing:.16em; text-transform:uppercase; font-weight:500;
  }
  .plugin-meta-field.invalid{
    border-color:var(--rubric);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--rubric) 28%, transparent);
  }
  .rail-section{ margin-bottom:6px; }
  .rail-section-header{
    display:flex; align-items:center; gap:6px; width:100%;
    background:transparent; border:none; padding:6px 4px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
    text-transform:uppercase; letter-spacing:.06em; cursor:pointer;
    transition:color .12s ease;
  }
  .rail-section-header:hover{ color:var(--ink); }
  .rail-section-header .chev{
    font-size:16px; transition:transform .15s ease; color:var(--ink-faint); flex-shrink:0;
  }
  .rail-section.collapsed .chev{ transform:rotate(-90deg); }
  .rail-section.collapsed .rail-section-body{ display:none; }
  .rail-section-body{ padding:2px 4px 8px; }
  .rail-section-body > .preset-btn{ margin-top:4px; }
  .preset-group{ margin-bottom:4px; }
  .preset-group-header{
    display:flex; align-items:center; gap:6px; width:100%;
    background:transparent; border:none; padding:6px 4px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
    text-transform:uppercase; letter-spacing:.06em; cursor:pointer;
    transition:color .12s ease;
  }
  .preset-group-header:hover{ color:var(--ink); }
  .preset-group-header .chev{
    font-size:16px; transition:transform .15s ease; color:var(--ink-faint); flex-shrink:0;
  }
  .preset-group.collapsed .chev{ transform:rotate(-90deg); }
  .preset-group.collapsed .preset-group-body{ display:none; }
  .pg-count{
    margin-left:auto; font-size:var(--font-xs); color:var(--ink-faint);
    background:var(--workspace); border-radius:var(--radius-pill); padding:1px 7px;
  }
  .preset-group-body{ display:flex; flex-direction:column; gap:2px; padding-left:4px; margin-bottom:4px; }
  .preset-row{
    display:block; width:100%; text-align:left;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:6px 9px; border:1px solid transparent; border-radius:var(--radius);
    background:transparent; color:var(--ink-soft); cursor:pointer;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
    transition:background .12s ease, color .12s ease, border-color .12s ease;
  }
  .preset-row:hover{ background:var(--workspace); color:var(--ink); }
  .preset-row.active{
    border-color:var(--amber); color:var(--ink);
    background:var(--amber-soft); box-shadow:inset 2px 0 0 var(--amber);
  }
  .preset-empty{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-faint);
    padding:8px 4px;
  }

  /* —— workspace —— */
  .workspace{
    background:var(--workspace); overflow:hidden;
    display:flex; align-items:flex-start; justify-content:center;
    padding:var(--s4) var(--s3) var(--s6);
    transition:background-color .25s ease;
    position:relative;
    isolation:isolate;
    min-height:0;
  }
  .workspace.needs-scroll{ overflow:auto; }
  /* quiet grid */
  .workspace::before{
    content:''; position:absolute; inset:0; pointer-events:none; z-index:0; opacity:0.22;
    background-image:radial-gradient(var(--hair-strong) 0.6px, transparent 0.6px);
    background-size:14px 14px;
  }
  /* glow lives in a clipped layer so it can't widen scroll */
  .workspace-glow{
    position:absolute; inset:0;
    overflow:hidden;
    pointer-events:none;
    z-index:0;
  }
  .workspace-glow::before,
  .workspace-glow::after{
    content:'';
    position:absolute;
    width:80%; height:70%;
    border-radius:50%;
    transform: translate3d(0,0,0);
    will-change: transform;
  }
  .workspace-glow::before{
    left:-15%; top:0%;
    background: radial-gradient(ellipse 70% 60% at 50% 50%,
      var(--glow1-a) 0%,
      var(--glow1-b) 35%,
      transparent 72%);
    animation: glowDriftA 10s ease-in-out infinite alternate;
  }
  .workspace-glow::after{
    right:-18%; bottom:-5%;
    background: radial-gradient(ellipse 75% 65% at 50% 50%,
      var(--glow2-a) 0%,
      var(--glow2-b) 40%,
      transparent 75%);
    animation: glowDriftB 13s ease-in-out infinite alternate;
  }
  @keyframes glowDriftA{
    from{ transform: translate3d(0, 0, 0) scale(1); }
    to{ transform: translate3d(30%, 24%, 0) scale(1.12); }
  }
  @keyframes glowDriftB{
    from{ transform: translate3d(0, 0, 0) scale(1); }
    to{ transform: translate3d(-26%, -20%, 0) scale(1.08); }
  }
  @media (prefers-reduced-motion: reduce){
    .workspace-glow::before,
    .workspace-glow::after{ animation:none; }
  }
  body.mode-paint .workspace{
    background: var(--workspace);
  }
  .canvas-column{
    display:flex; flex-direction:column; align-items:center;
    position:relative; z-index:1; flex-shrink:0;
  }
  body.mode-effects .canvas-column{ display:none !important; }
  body.mode-effects .workspace{
    flex-direction:column;
    align-items:stretch; justify-content:flex-start;
  }
  body.mode-effects .fx-workspace{
    display:flex !important;
    position:relative; z-index:1;
    flex:1; width:100%; min-height:0;
    max-width:none; margin:0;
  }
  /* —— Samples mode (instruments) —— */
  body.mode-samples #tourPluginType,
  body.mode-samples #tourPluginSetup,
  body.mode-samples #tourRailLayouts,
  body.mode-samples #tourFxRail{ display:none !important; }
  body.mode-samples #tourSamplesRail{ display:flex !important; }
  body.mode-samples #tourCanvasSize,
  body.mode-samples .dock-palette{ display:none !important; }
  body.mode-samples .dock-tabs{ display:none !important; }
  body.mode-samples #tourDock{ display:flex !important; flex:1; min-height:0; }
  body.mode-samples .canvas-column{ display:none !important; }
  body.mode-samples .workspace{
    flex-direction:column;
    align-items:stretch; justify-content:flex-start;
  }
  body.mode-samples .rail{
    display:flex; flex-direction:column; overflow:hidden;
  }
  #samplesModeBtn[hidden]{ display:none; }
  .samples-workspace{
    flex:1; display:none; flex-direction:column; min-height:0; min-width:0;
    width:100%; align-self:stretch; position:relative; z-index:1;
    padding:0; gap:0; color:var(--ink);
  }
  body.mode-samples .samples-workspace{
    display:flex !important;
  }
  .samples-file-hint{
    flex-shrink:0; padding:6px 10px; font-size:var(--font-sm); color:var(--ink-soft);
    background:var(--amber-soft); border-bottom:1px solid color-mix(in srgb, var(--amber) 35%, var(--hair));
  }
  .samples-workspace[hidden]{ display:none !important; }
  .samples-group-tabs[hidden],
  .samples-synth-panel[hidden]{ display:none !important; }
  .samples-panel{
    flex:1; display:flex; flex-direction:column; min-height:0;
    background:var(--paper); border:1px solid var(--hair-strong);
    border-radius:var(--radius-sm); overflow:hidden;
  }
  .samples-body{
    flex:1; min-height:0; display:flex; flex-direction:row;
  }
  .samples-vel-gutter{
    flex-shrink:0; width:32px; display:flex; flex-direction:column;
    border-right:1px solid var(--hair-strong); background:var(--paper);
  }
  .samples-vel-scale{
    position:relative; flex:1; min-height:0;
  }
  .samples-vel-num{
    position:absolute; right:3px; left:0; text-align:right; pointer-events:none;
    font-family:'IBM Plex Mono',monospace; font-size:7px;
    color:var(--ink-faint); letter-spacing:0; line-height:1;
    transform:translateY(-50%);
  }
  .samples-vel-num.edge-top{ top:6px; transform:none; }
  .samples-vel-num.edge-bottom{ top:auto; bottom:6px; transform:none; }
  .samples-vel-tabs-spacer{
    flex-shrink:0; height:38px;
    border-bottom:1px solid var(--hair);
    background:var(--paper);
  }
  /* Pitch bend / mod wheel — display-only for now (driven by a connected MIDI controller,
     see webMidi.handleMessage); not yet mouse-draggable, per the user's own "for now" scoping.
     Lives in this gutter (not next to the keyboard itself) because this column runs down the
     *left of* the lanes grid + keyboard as its own separately-laid-out strip — exactly how the
     velocity-scale numbers above already render outside the lanes without touching their
     alignment. Putting the wheels here means `.samples-keyboard` never has to give up any of
     its own width, so it stays in sync with `.samples-lanes-track` above (an earlier attempt
     that shrank the keyboard's own box broke that sync). Built entirely from the same theme
     variables everything else uses, so it re-skins across Paper/Slate/Ink/Noir for free. */
  .samples-vel-kb-spacer{
    /* margin-top:auto is a no-op in Sample Map view — .samples-vel-scale's own flex:1 already
       consumes all the space above this, so there's nothing left for auto-margin to grab. It's
       what keeps this pinned to the *bottom* of the gutter in Synth view instead, where the two
       siblings above it collapse (see renderSamples()) and would otherwise leave this — and the
       wheels inside it — stranded at the top instead of aligned with the keyboard below. */
    flex-shrink:0; height:72px; margin-top:auto;
    border-top:1px solid var(--hair-strong);
    background:var(--paper);
    display:flex; align-items:center; justify-content:center; gap:3px;
  }
  .samples-wheel-track{
    position:relative; width:9px; height:38px;
    background:var(--workspace); border:1px solid var(--hair-strong); border-radius:2px;
  }
  .samples-wheel-thumb{
    position:absolute; left:1px; right:1px; height:5px; top:16.5px;
    background:var(--amber); border-radius:1px;
    transition:top .05s linear;
  }
  .samples-lanes-scroll{
    flex:1; min-height:0; min-width:0; overflow:hidden;
    position:relative;
  }
  .samples-map-column{
    flex:1; min-height:0; min-width:0; display:flex; flex-direction:column;
  }
  .samples-group-tabs{
    flex-shrink:0; display:flex; align-items:center; gap:6px;
    padding:5px 8px; border-bottom:1px solid var(--hair);
    background:var(--paper); overflow-x:auto;
  }
  .samples-group-tab{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:4px 10px; border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); color:var(--ink-soft); cursor:pointer;
    white-space:nowrap; transition:border-color .12s ease, background .12s ease, color .12s ease;
  }
  .samples-group-tab:hover{ color:var(--ink); border-color:var(--ink-faint); }
  .samples-group-tab.on{
    background:var(--amber-soft); border-color:var(--amber); color:var(--ink);
  }
  .samples-group-add{
    flex-shrink:0; width:28px; height:28px; padding:0;
    display:flex; align-items:center; justify-content:center;
    border:1px dashed var(--hair-strong); border-radius:var(--radius);
    background:transparent; color:var(--ink-soft); cursor:pointer;
    transition:border-color .12s ease, color .12s ease, background .12s ease;
  }
  .samples-group-add:hover{ border-color:var(--amber); color:var(--ink); background:var(--amber-soft); }
  .samples-group-add .material-symbols-outlined{ font-size:16px; }
  .samples-map-inner{
    position:relative; width:100%;
    height:100%; display:flex; flex-direction:column;
  }
  .samples-lanes-track{
    position:relative; flex:1; min-height:0;
    background:var(--sample-track-bg, var(--workspace));
  }
  .samples-vel-bands{
    position:absolute; inset:0; pointer-events:none; z-index:0;
  }
  .samples-vel-band{
    position:absolute; left:0; right:0;
  }
  .samples-vel-band.v4{ background:color-mix(in srgb, #8B7FD4 14%, var(--paper)); }
  .samples-vel-band.v3{ background:color-mix(in srgb, #4A8FD9 12%, var(--paper)); }
  .samples-vel-band.v2{ background:color-mix(in srgb, var(--amber) 10%, var(--paper)); }
  .samples-vel-band.v1{ background:color-mix(in srgb, #C9A227 10%, var(--paper)); }
  .samples-note-guide{
    position:absolute; top:0; bottom:0; width:2px; margin-left:-1px;
    background:var(--amber); opacity:.75; pointer-events:none; z-index:4;
    box-shadow:0 0 6px color-mix(in srgb, var(--amber) 45%, transparent);
  }
  .samples-drop-preview{
    position:absolute; box-sizing:border-box; z-index:4; pointer-events:none;
    border:1px solid var(--amber);
    background:color-mix(in srgb, var(--amber) 18%, transparent);
    border-radius:2px;
  }
  .sample-lane{
    position:absolute; top:0; bottom:0;
    border-left:1px solid var(--sample-lane-edge, var(--hair-strong));
    box-sizing:border-box; z-index:1;
    pointer-events:none;
  }
  .sample-lane.white{ background:var(--sample-lane-white, var(--paper)); }
  .sample-lane.black{
    background:var(--sample-lane-black, color-mix(in srgb, var(--ink) 22%, var(--workspace)));
    border-left-color:var(--sample-lane-edge, var(--hair-strong));
    z-index:2;
  }
  .samples-synth-panel{
    flex:1; min-height:0; overflow-y:auto;
    background:var(--sample-track-bg, var(--workspace));
    padding:12px 16px; display:flex; flex-direction:column; gap:12px;
  }
  .synth-enable-left{ display:flex; align-items:center; gap:10px; cursor:pointer; }
  .synth-enable-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--ink-soft);
  }
  .synth-master-gain{ display:flex; align-items:center; gap:8px; }
  .synth-master-gain label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    white-space:nowrap;
  }
  .synth-osc-row{
    display:flex; gap:12px; flex-wrap:wrap;
  }
  .synth-filter-row{
    display:flex; gap:12px; flex-wrap:wrap;
  }
  /* Only 2 cards here vs. 3 in `.synth-osc-row` — without this, `flex:1` would let each one
     grow to fill half the row (wider than an oscillator card). Pinning to the same basis as
     the oscillator's own min-width keeps them the same size, leaving the rest of the row for
     the LFO stack below instead of the filters silently expanding to claim it. */
  .synth-filter-row .synth-osc-card{
    flex:0 1 280px;
  }
  /* The 3 LFOs stack vertically into whatever width the two pinned filter cards leave behind
     in the SAME row, rather than costing an entire extra full-width row of their own. */
  .synth-lfo-stack{
    display:flex; flex-direction:column; gap:6px; flex:1; min-width:240px;
  }
  /* space-between distributes whatever room is left evenly across every gap in the row
     (title→wave, wave→dest, dest→knobs) — `gap` is still the floor, so nothing crowds even
     on a narrow window. Replaces an earlier `margin-left:auto` on the knob-row, which dumped
     all the leftover space into one lump gap right before Rate instead of spreading it out. */
  /* `.synth-lfo-stack` already matches the filter row's height (flex row default is
     align-items:stretch, and the filter cards are taller) — but its 3 strips were
     content-sized, leaving empty space below the last one. flex:1 here makes them grow to
     fill that height evenly, so the stack's bottom edge lines up with the filter cards'. */
  .synth-lfo-strip{
    position:relative; flex:1;
    display:flex; align-items:center; gap:14px; flex-wrap:wrap; justify-content:space-between;
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); padding:6px 40px 6px 10px;
    transition:opacity .12s ease;
  }
  .synth-lfo-strip.disabled{ opacity:.5; }
  /* Top-right corner, same spot every other enable dot uses — not vertically centered, which
     forced extra right-padding across the whole row just to clear it. */
  .synth-lfo-strip .synth-osc-enable{
    position:absolute; top:8px; right:8px;
  }
  .synth-lfo-strip-title{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.08em; text-transform:uppercase; color:var(--ink-soft);
    flex:0 0 auto; white-space:nowrap;
  }
  /* No max-width cap — a rack-module strip should fill the available width evenly rather
     than leaving space unused when the panel is wide (Actuate reference: wide generator
     rows, not narrow stacked cards). */
  .synth-osc-card{
    position:relative;
    flex:1; min-width:280px;
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); padding:10px 12px;
    display:flex; flex-direction:column; gap:8px;
    transition:opacity .12s ease;
  }
  .synth-osc-card.disabled{ opacity:.5; }
  .synth-osc-enable{
    position:absolute; top:8px; right:8px; width:12px; height:12px;
    border-radius:50%; background:var(--amber); border:2px solid var(--paper);
    cursor:pointer; z-index:1;
  }
  .synth-osc-enable.off{ background:var(--hair-strong); }
  .synth-osc-title{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.08em; text-transform:uppercase; color:var(--ink-soft);
    margin-bottom:2px; padding-right:18px;
  }
  .synth-osc-num{
    display:inline-flex; align-items:center; justify-content:center;
    width:16px; height:16px; margin-left:2px; margin-right:6px;
    border:1px solid var(--hair-strong); border-radius:4px;
    font-size:9px; color:var(--ink-soft); letter-spacing:0; text-transform:none;
    vertical-align:middle;
  }
  .synth-field-row{
    display:flex; align-items:center; gap:8px;
  }
  .synth-field-row label{
    flex:0 0 64px; font-size:var(--font-xs); color:var(--ink-faint);
  }
  .synth-field-row input[type="range"]{
    flex:1; min-width:0;
  }
  /* Master Gain doesn't need much width to be usable — shortened further (was 140px) once it
     moved into the samples-head row alongside the view tabs and action buttons, which needed
     the space back more than this slider needed the extra travel. */
  #synthGainRange{
    flex:0 0 auto; width:90px;
  }
  .synth-field-row .synth-range-value{
    flex:0 0 40px; text-align:right;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
  }
  .synth-wave-row{
    display:flex; align-items:center; gap:8px;
  }
  /* `.fx-param-label` sets order:3 for its normal column-flex home inside `.fx-param` — reset
     it here since this row is a plain row-flex container, not that column context. */
  .synth-wave-row .fx-param-label{ flex:0 0 auto; order:0; }
  /* LFO's Wave + Dest steppers sit side by side in one row instead of two stacked rows —
     same height-saving reasoning as the ADSR knob conversion. */
  .synth-lfo-select-cell{
    display:flex; align-items:center; gap:6px; flex:0 1 auto; min-width:0;
  }
  .synth-lfo-select-cell .fx-param-label{ flex:0 0 auto; order:0; }
  /* Fixed basis, not the shared `flex:1` wide-stepper rule below — that rule is `flex-grow:1
     flex-basis:0%`, which in this nested-flex context rendered narrower/less predictably than
     a plain fixed width. A fixed basis (still roomy — every waveform/destination word here is
     short) renders reliably and leaves the rest of the row's math unambiguous. */
  .synth-lfo-select-cell .synth-stepper{
    flex:0 0 150px; width:150px; max-width:none;
  }
  /* Portamento's Always/Scaled — a plain labeled checkbox, distinct from the round enable dot
     (`.synth-osc-enable`) since these are ordinary boolean fields, not a whole-card disable. */
  .synth-porta-toggles{
    flex-direction:column; align-items:flex-start; gap:4px;
  }
  .synth-bool-toggle{
    display:inline-flex; align-items:center; gap:6px; cursor:pointer; user-select:none;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); letter-spacing:.06em;
    text-transform:uppercase; color:var(--ink-faint); white-space:nowrap;
  }
  .synth-bool-toggle-box{
    width:12px; height:12px; flex:0 0 auto;
    border:2px solid var(--hair-strong); border-radius:3px; background:var(--paper);
    transition:background .12s ease, border-color .12s ease;
  }
  .synth-bool-toggle.active{ color:var(--ink-soft); }
  .synth-bool-toggle.active .synth-bool-toggle-box{
    background:var(--amber); border-color:var(--amber);
  }
  /* Stepper (octave, waveform) — deliberately not a knob or slider: octave is a discrete
     whole-step value and waveform a fixed cycle, both better served by +/- buttons. */
  .synth-stepper{
    display:flex; align-items:center; justify-content:space-between; gap:2px;
    width:60px; height:28px; padding:0 2px; flex-shrink:0;
    border:2px solid var(--hair-strong); border-radius:14px; background:var(--paper);
    box-shadow:inset 0 2px 6px rgba(0,0,0,.10);
  }
  .synth-wave-stepper,
  .synth-filter-type-stepper,
  .synth-lfo-dest-stepper,
  .synth-filter-routing-stepper{
    width:auto; flex:1; border-radius:var(--radius); justify-content:space-between;
  }
  .synth-stepper-btn{
    width:16px; height:16px; flex-shrink:0; border-radius:50%; border:none; padding:0;
    background:transparent; color:var(--ink-soft);
    font-family:'IBM Plex Mono',monospace; font-size:12px; line-height:1;
    cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition:background .12s ease, color .12s ease;
  }
  .synth-stepper-btn:hover{ background:var(--amber-soft); color:var(--ink); }
  .synth-stepper-val{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink);
    min-width:18px; text-align:center; white-space:nowrap;
  }
  /* Octave's up/down pair, sized to sit at the same height as a knob beside it. */
  .synth-octave-stepper{
    /* Was 32x52px, sized to match the old full-size (52px) knob height — now matches
       .fx-param-knob.small's 34px so it doesn't tower over every knob beside it. */
    display:flex; flex-direction:column; width:26px; height:34px; flex-shrink:0;
    /* var(--radius), not --radius-sm — that token is referenced elsewhere in this file but
       never actually defined, so it silently drops the whole border-radius declaration and
       renders sharp square corners instead of the intended rounding. */
    border:2px solid var(--hair-strong); border-radius:var(--radius); overflow:hidden;
    background:var(--paper); box-shadow:inset 0 2px 6px rgba(0,0,0,.10);
  }
  .synth-octave-btn{
    flex:1; border:none; background:transparent; padding:0;
    color:var(--ink-soft); font-size:9px; line-height:1;
    cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition:background .12s ease, color .12s ease;
  }
  .synth-octave-btn:first-child{ border-bottom:1px solid var(--hair); }
  .synth-octave-btn:hover{ background:var(--amber-soft); color:var(--ink); }
  /* Evenly filling the card's width (not clustering to the left) is the whole point of the
     rack-strip layout — flex:1 on each cell plus a max-width keeps them from overgrowing on
     a very wide card. */
  .synth-knob-row{
    display:flex; gap:8px; align-items:flex-end; justify-content:space-between;
  }
  /* The filter card only ever has 2 cells (Cutoff, Resonance) — `space-between` would shove
     them to opposite edges of the card and leave a dead gap in the middle; `flex-start` looked
     lopsided too (clung to the left with empty space on the right). Centered reads as
     deliberate either way. This rule is scoped by `.synth-knob-row` specifically (not the
     ADSR row, which uses `.synth-adsr-knob-row`), so it doesn't touch the 4-knob ADSR rows
     also nested under `.synth-filter-row` (filter's own, or the LFO stack's Rate/Depth row —
     the latter is unaffected in practice since it's a content-sized item in a wrapping row,
     not a full-width row with dead space to redistribute). */
  .synth-filter-row .synth-knob-row{
    justify-content:center; gap:28px;
  }
  /* Compound selector, not just `.synth-param` — `.fx-param`'s own `min-width:56px` is defined
     later in the stylesheet and would otherwise win at equal specificity regardless of source
     order here. */
  .fx-param.synth-param{ min-width:0; flex:1; max-width:96px; display:flex; align-items:center; justify-content:center; }
  /* ADSR as knobs, not faders — traded the "envelope shape at a glance" of vertical faders
     for real height savings (a knob's height is bounded by its own diameter regardless of
     range, where a fader needs vertical throw to stay usable). Same row shape as the main
     knob row above, just a separate class so the filter's 2-item `space-between` override
     above doesn't bleed into this always-4-item row. */
  .synth-adsr-knob-row{
    display:flex; gap:8px; align-items:flex-end; justify-content:space-between;
    padding-top:8px; border-top:1px solid var(--hair);
  }
  .samples-keyboard-wrap{
    flex-shrink:0; border-top:1px solid var(--hair-strong);
    background:var(--paper); padding:0;
  }
  .samples-keyboard{
    position:relative; height:72px; width:100%;
    overflow:hidden;
  }
  .samples-piano-inner{
    position:relative; width:100%; height:100%;
    background:var(--piano-key-white); overflow:hidden;
  }
  .samples-piano-white{
    position:absolute; top:0; height:100%; padding:0; margin:0;
    border:none; border-radius:0; box-sizing:border-box;
    background:var(--piano-key-white); cursor:pointer;
  }
  .samples-piano-divider{
    position:absolute; top:0; bottom:0; width:1px;
    background:var(--piano-key-divider); pointer-events:none; z-index:1;
  }
  .samples-piano-black{
    position:absolute; top:0; padding:0; margin:0;
    border:none; border-radius:0; box-sizing:border-box;
    background:var(--piano-key-black); cursor:pointer; z-index:2;
  }
  .samples-piano-white:focus,
  .samples-piano-black:focus{ outline:none; }
  .samples-piano-white:focus-visible,
  .samples-piano-black:focus-visible{
    outline:2px solid var(--amber); outline-offset:-2px;
  }
  .samples-piano-white.selected,
  .samples-piano-black.selected{
    outline:2px solid var(--amber); outline-offset:-2px;
  }
  .samples-piano-white.root,
  .samples-piano-black.root{
    outline:2px solid var(--rubric); outline-offset:-2px;
    box-shadow:inset 0 -3px 0 color-mix(in srgb, var(--rubric) 55%, transparent);
  }
  .samples-piano-white.root.selected,
  .samples-piano-black.root.selected{
    outline:2px solid var(--rubric);
    box-shadow:inset 0 0 0 1px var(--amber), inset 0 -3px 0 color-mix(in srgb, var(--rubric) 55%, transparent);
  }
  .samples-piano-white:hover{
    background:color-mix(in srgb, var(--piano-key-white) 80%, var(--piano-key-white-glow) 20%);
  }
  .samples-piano-black:hover{
    background:color-mix(in srgb, var(--piano-key-black) 80%, var(--amber) 35%);
  }
  .samples-piano-white:active,
  .samples-piano-black:active,
  .samples-piano-white.key-pressed,
  .samples-piano-black.key-pressed{ transform:translateY(1px); }
  .samples-piano-white.key-pressed{
    background:color-mix(in srgb, var(--piano-key-white) 55%, var(--piano-key-white-glow) 45%);
  }
  .samples-piano-black.key-pressed{
    background:color-mix(in srgb, var(--piano-key-black) 55%, var(--amber) 45%);
  }
  .samples-key-label{
    position:absolute; left:50%; bottom:5px; transform:translateX(-50%);
    font-family:'IBM Plex Mono',monospace; font-size:7px;
    letter-spacing:.02em; color:var(--ink-faint); pointer-events:none;
    white-space:nowrap; line-height:1;
  }
  .samples-piano-white.selected .samples-key-label{ color:var(--ink); }
  .samples-head{
    display:flex; align-items:center; justify-content:space-between;
    flex-wrap:wrap; row-gap:6px;
    padding:8px 12px; border-bottom:1px solid var(--hair);
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.08em; text-transform:uppercase; color:var(--ink-soft);
    flex-shrink:0;
  }
  /* Enable toggle + Master Gain, relocated here from their own dedicated row inside the Synth
     panel to reclaim that vertical space — only shown in Synth view (toggled in renderSamples()
     alongside the view tabs). Resets text-transform/letter-spacing, same as `.samples-head-btn`
     already does — without it these would inherit `.samples-head`'s uppercase/letter-spaced
     label styling, which the original panel-row design never had. */
  .samples-head-synth{
    display:flex; align-items:center; gap:10px; flex-shrink:0;
    text-transform:none; letter-spacing:0;
  }
  .samples-head-synth[hidden]{ display:none !important; }
  .samples-head-actions{
    display:flex; align-items:center; gap:10px; flex-shrink:0;
  }
  .samples-head-btn{
    display:inline-flex; align-items:center; justify-content:center; gap:6px;
    width:auto; flex:0 0 auto; margin:0; white-space:nowrap;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    text-align:center; text-transform:none; letter-spacing:0;
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    padding:6px 12px;
    background:var(--paper); color:var(--ink-soft);
    transition:border-color .15s ease, background .15s ease, color .15s ease, box-shadow .15s ease;
  }
  .samples-head-btn:hover{
    border-color:var(--ink-faint); color:var(--ink); background:var(--workspace);
  }
  .samples-head-btn .material-symbols-outlined{ font-size:16px; }
  .samples-head-btn-primary{
    border-color:var(--amber); background:var(--amber-soft); color:var(--ink); font-weight:500;
  }
  .samples-head-btn-primary:hover{ border-color:var(--amber); background:var(--amber-soft); }
  .samples-view-tabs{
    display:flex; align-items:center; gap:6px; flex-shrink:0;
  }
  .samples-view-tab{
    display:inline-flex; align-items:center; gap:6px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.08em; text-transform:uppercase;
    padding:5px 10px; border:1px solid transparent; border-radius:var(--radius);
    background:transparent; color:var(--ink-faint); cursor:pointer;
    transition:border-color .12s ease, background .12s ease, color .12s ease;
  }
  .samples-view-tab .material-symbols-outlined{ font-size:16px; }
  .samples-view-tab:hover{ color:var(--ink-soft); }
  .samples-view-tab.on{
    background:var(--amber-soft); border-color:var(--amber); color:var(--ink);
  }
  #tourSamplesRail,
  .samples-rail{
    display:none; flex-direction:column; gap:var(--s2);
    padding:0 4px 8px; min-height:0; flex:1;
  }
  #tourSamplesRail[hidden]{ display:none !important; }
  .samples-rail-head{
    display:flex; align-items:center; justify-content:space-between; gap:6px;
    padding:2px 2px 0;
  }
  .samples-rail-title{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.08em; text-transform:uppercase; color:var(--ink-soft);
  }
  .samples-rail-imports{
    display:flex; align-items:center; gap:4px; flex-shrink:0;
  }
  .samples-rail-import{
    flex-shrink:0; width:28px; height:28px; padding:0;
    display:flex; align-items:center; justify-content:center;
    border:1px dashed var(--hair-strong); border-radius:var(--radius);
    background:transparent; color:var(--ink-soft); cursor:pointer;
  }
  .samples-rail-import:hover{ border-color:var(--amber); color:var(--ink); background:var(--amber-soft); }
  .samples-rail-import .material-symbols-outlined{ font-size:17px; }
  .samples-library.drop-target{
    outline:1px dashed var(--amber); outline-offset:-2px;
    background:color-mix(in srgb, var(--amber-soft) 35%, var(--workspace));
  }
  .samples-rail-search{
    width:100%; font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:7px 9px; border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); color:var(--ink);
  }
  .samples-rail-search:focus{ outline:none; border-color:var(--amber); box-shadow:0 0 0 3px var(--ring); }
  .samples-rail-group{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    color:var(--ink-faint); padding:0 2px;
  }
  .samples-rail-actions{
    display:flex; align-items:center; gap:4px;
    padding:0 2px 4px;
  }
  .samples-rail-actions[hidden]{ display:none; }
  .samples-rail-chip{
    flex-shrink:0; padding:3px 7px;
    border:1px solid var(--hair-strong); border-radius:var(--radius-sm);
    background:var(--paper); color:var(--ink-soft);
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    line-height:1.2; cursor:pointer;
  }
  .samples-rail-chip:hover:not(:disabled){
    border-color:var(--amber); color:var(--ink); background:var(--amber-soft);
  }
  .samples-rail-chip:disabled{ opacity:.4; cursor:default; }
  .samples-rail-chip.muted{
    border-color:transparent; background:transparent; color:var(--ink-faint);
    cursor:default; min-width:1.5em; text-align:center; padding-left:4px; padding-right:4px;
  }
  .samples-rail-chip.primary{ margin-left:auto; }
  .samples-library{
    flex:1; min-height:0; overflow-y:auto;
    border:1px solid var(--hair); border-radius:var(--radius-sm);
    background:var(--workspace); padding:6px;
  }
  .samples-lib-empty{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--ink-faint); padding:8px 4px; line-height:1.45;
  }
  .samples-lib-item{
    display:flex; align-items:center; gap:6px; width:100%;
    padding:6px 7px; margin-bottom:4px;
    border:1px solid var(--hair); border-radius:var(--radius-sm);
    background:var(--paper); color:var(--ink-soft);
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    text-align:left; cursor:grab; transition:border-color .12s ease, background .12s ease;
  }
  .samples-lib-item:last-child{ margin-bottom:0; }
  .samples-lib-item:hover{ border-color:var(--hair-strong); color:var(--ink); }
  .samples-lib-item.on{ border-color:var(--amber); background:var(--amber-soft); color:var(--ink); }
  .samples-lib-item.mapped:not(.on){
    border-left:2px solid color-mix(in srgb, var(--amber) 70%, var(--hair-strong));
    padding-left:6px;
  }
  .samples-lib-item.dragging{
    opacity:.55; border-color:var(--amber); cursor:grabbing;
  }
  .samples-lib-item .material-symbols-outlined{ font-size:15px; flex-shrink:0; opacity:.75; }
  .samples-lib-name{
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0;
  }
  .samples-lib-folder{
    display:flex; align-items:center; gap:6px; width:100%;
    padding:5px 7px; margin-bottom:2px;
    border:none; border-radius:var(--radius-sm);
    background:transparent; color:var(--ink-soft);
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    text-align:left; cursor:pointer;
  }
  .samples-lib-folder:hover{ background:color-mix(in srgb, var(--ink) 6%, transparent); color:var(--ink); }
  .samples-lib-folder .material-symbols-outlined{ font-size:16px; flex-shrink:0; opacity:.85; }
  .samples-lib-folder-count{
    margin-left:auto; font-size:var(--font-xs); color:var(--ink-faint);
  }
  .samples-lib-loose-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.06em; text-transform:uppercase;
    color:var(--ink-faint); padding:6px 7px 2px;
  }
  .sample-zone{
    position:absolute; box-sizing:border-box; z-index:3;
    border:1px solid color-mix(in srgb, var(--amber) 45%, var(--hair-strong));
    border-radius:3px; padding:2px 3px; overflow:hidden;
    background:color-mix(in srgb, var(--amber-soft) 35%, var(--sample-lane-white));
    cursor:grab; text-align:left; touch-action:none;
    box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--sample-lane-white) 40%, transparent);
  }
  .sample-zone.on-black{
    background:color-mix(in srgb, var(--amber-soft) 28%, var(--sample-lane-black));
    border-color:color-mix(in srgb, var(--amber) 38%, var(--sample-lane-edge));
    box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--sample-lane-black) 50%, transparent);
  }
  .sample-zone.b-v4{ background:color-mix(in srgb, #8B7FD4 28%, var(--sample-lane-white)); border-color:color-mix(in srgb, #8B7FD4 50%, var(--hair-strong)); }
  .sample-zone.on-black.b-v4{ background:color-mix(in srgb, #8B7FD4 32%, var(--sample-lane-black)); border-color:color-mix(in srgb, #8B7FD4 45%, var(--sample-lane-edge)); }
  .sample-zone.b-v3{ background:color-mix(in srgb, #4A8FD9 24%, var(--sample-lane-white)); border-color:color-mix(in srgb, #4A8FD9 45%, var(--hair-strong)); }
  .sample-zone.on-black.b-v3{ background:color-mix(in srgb, #4A8FD9 28%, var(--sample-lane-black)); border-color:color-mix(in srgb, #4A8FD9 40%, var(--sample-lane-edge)); }
  .sample-zone.b-v2{ background:color-mix(in srgb, var(--amber) 22%, var(--sample-lane-white)); border-color:color-mix(in srgb, var(--amber) 40%, var(--hair-strong)); }
  .sample-zone.on-black.b-v2{ background:color-mix(in srgb, var(--amber) 26%, var(--sample-lane-black)); border-color:color-mix(in srgb, var(--amber) 35%, var(--sample-lane-edge)); }
  .sample-zone.b-v1{ background:color-mix(in srgb, #C9A227 22%, var(--sample-lane-white)); border-color:color-mix(in srgb, #C9A227 40%, var(--hair-strong)); }
  .sample-zone.on-black.b-v1{ background:color-mix(in srgb, #C9A227 26%, var(--sample-lane-black)); border-color:color-mix(in srgb, #C9A227 35%, var(--sample-lane-edge)); }
  .sample-zone.selected{
    border-color:var(--amber);
    box-shadow:0 0 0 1px var(--amber), inset 0 0 0 1px color-mix(in srgb, var(--amber) 25%, transparent);
  }
  .sample-zone.dragging,
  .sample-zone.resizing{
    opacity:.88; z-index:5;
  }
  .sample-zone.dragging{ cursor:grabbing !important; }
  .samples-marquee{
    position:absolute; display:none; pointer-events:none; z-index:6;
    border:1px solid var(--amber);
    background:color-mix(in srgb, var(--amber) 14%, transparent);
    box-sizing:border-box;
  }
  .samples-marquee.show{ display:block; }
  .sample-zone-label{
    display:block; font-family:'IBM Plex Mono',monospace; font-size:7px;
    line-height:1.2; color:var(--ink); overflow:hidden;
    text-overflow:ellipsis; white-space:nowrap; pointer-events:none;
  }
  .samples-lanes-track.drop-target{ outline:1px dashed var(--amber); outline-offset:-2px; }
  .screen-strip{
    display:flex; align-items:center; gap:6px;
    padding:0 0 10px; flex-wrap:wrap; justify-content:center;
  }
  .screen-tab{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:5px 12px; border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); color:var(--ink-soft);
    transition:border-color .12s ease, background .12s ease, color .12s ease;
  }
  .screen-tab:hover{ color:var(--ink); border-color:var(--ink-faint); }
  .screen-tab.on{
    background:var(--amber-soft); border-color:var(--amber); color:var(--ink);
  }
  .screen-actions{
    display:flex; align-items:center; gap:4px; margin-left:2px;
  }
  .screen-action{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    min-width:28px; height:28px; padding:0 7px;
    border:1px dashed var(--hair-strong); border-radius:var(--radius);
    background:transparent; color:var(--ink-soft);
    transition:border-color .12s ease, color .12s ease, background .12s ease;
  }
  .screen-action:hover:not(:disabled){ border-color:var(--amber); color:var(--ink); background:var(--amber-soft); }
  .screen-action:disabled{ opacity:.35; cursor:not-allowed; }
  .screen-action.dup,
  .screen-action.add,
  .screen-action.remove{
    padding:0;
    display:flex; align-items:center; justify-content:center;
  }
  .screen-action.dup .material-symbols-outlined,
  .screen-action.add .material-symbols-outlined,
  .screen-action.remove .material-symbols-outlined{ font-size:15px; }
  .screen-action.remove:hover:not(:disabled){ border-color:var(--rubric); color:var(--rubric); background:var(--rubric-soft); }
  .plugin-type-tabs{ width:100%; margin-bottom:var(--s2); }
  .plugin-type-tabs .mode-tab{ flex:1; padding:6px 8px; font-size:var(--font-sm); }
  /* Every segmented-toggle button embedded in a Properties-panel card (strip orientation,
     meter/visualizer channel, frame count, etc.) — same oversized-toolbar-button problem
     `.plugin-type-tabs` already solved above, generalized by container instead of one ID at a
     time, so a new toggle dropped into an `.insp-body` card is compact by default. */
  .insp-body .mode-tabs .mode-tab{ flex:1; padding:6px 8px; font-size:var(--font-sm); }
  .plugin-type-tabs.locked .mode-tab:not(.on){ opacity:.55; }
  .plugin-type-note{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    margin:-4px 4px var(--s2); line-height:1.35;
  }
  .canvas-frame{ flex-shrink:0; position:relative; }
  .canvas-scale-wrap{
    position:relative;
  }
  .dims{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
    display:flex; align-items:center; gap:10px;
  }
  .toolbar-group{
    display:flex; align-items:center; gap:2px;
    padding:2px; border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper);
  }
  .zoom-btn{
    width:24px; height:24px; border:none; border-radius:4px;
    background:transparent; color:var(--ink-soft);
    font-family:'IBM Plex Mono',monospace; font-size:var(--font);
    display:flex; align-items:center; justify-content:center;
    transition:background .12s ease, color .12s ease;
  }
  .zoom-btn:hover{ background:var(--workspace); color:var(--ink); }
  .zoom-btn:focus-visible{ outline:2px solid var(--amber); outline-offset:1px; }
  .zoom-btn:disabled{ opacity:.35; cursor:not-allowed; }
  .zoom-btn:disabled:hover{ background:transparent; color:var(--ink-soft); }
  .zoom-pct{
    width:44px; text-align:center; cursor:pointer; color:var(--ink-soft);
    border-radius:4px; padding:2px 0;
  }
  .zoom-pct:hover{ color:var(--ink); background:var(--workspace); }
  .dims-text{ color:var(--ink-faint); padding-left:4px; display:flex; align-items:center; gap:5px; }
  .dims-input{
    width:52px; font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--ink); background:var(--paper); border:1px solid var(--hair-strong);
    border-radius:4px; padding:2px 4px; text-align:center;
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .dims-input:focus{ outline:none; border-color:var(--amber); box-shadow:0 0 0 3px var(--ring); }
  /* native spinner arrows can't be restyled to match — hide them entirely rather than
     leave inconsistent browser chrome; scroll-wheel and arrow keys still adjust the value */
  .dims-input::-webkit-inner-spin-button,
  .dims-input::-webkit-outer-spin-button{ -webkit-appearance:none; margin:0; }
  .dims-input{ -moz-appearance:textfield; appearance:textfield; }
  #aspectLock.locked{ color:var(--amber); }
  .aspect-lock-btn.locked{ color:var(--amber); }

  .canvas{
    position:relative; width:684px; height:483px; background:var(--paper);
    border:1px solid var(--hair-strong); border-radius:2px;
    box-shadow: var(--shadow-md);
    background-image:
      linear-gradient(var(--hair) 1px, transparent 1px),
      linear-gradient(90deg, var(--hair) 1px, transparent 1px);
    background-size:8px 8px;
    transform-origin: top left;
    transition:box-shadow .25s ease, border-color .25s ease;
    overflow:visible;
  }
  body.mode-paint .canvas{
    border-color: color-mix(in srgb, var(--hair-strong) 70%, var(--rubric));
    box-shadow: 0 4px 20px -6px color-mix(in srgb, var(--rubric) 28%, transparent), var(--shadow-md);
  }
  .canvas.no-grid{ background-image:none; }
  .warn{
    position:absolute; top:10px; right:10px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font); color:var(--amber);
    background:var(--amber-soft); border:1px solid color-mix(in srgb, var(--amber) 35%, transparent);
    border-radius:var(--radius); padding:5px 9px;
    opacity:0; transform:translateY(-4px);
    transition:opacity .2s ease, transform .2s ease; z-index:2; pointer-events:none;
  }
  .warn.show{ opacity:1; transform:translateY(0); }

  /* —— palette —— */
  /* Layout-XML import/export lives here (moved off the header toolbar to free up space there) —
     relevant only to Wireframe/Skin (the layout itself); hidden in Sound/Effects where the dock's
     other content takes over. */
  .dock-xml-io{
    padding:var(--s2); border-bottom:1px solid var(--hair-strong); flex-shrink:0;
  }
  body.mode-samples .dock-xml-io, body.mode-effects .dock-xml-io{ display:none; }
  .dock-xml-io-row{ display:flex; gap:6px; }
  /* Same visual language as .chip (the Components palette directly below this section) —
     pill shape, shadow-sm/md hover lift, 14px icon at 0.75 opacity — so this reads as one
     coherent button language instead of a one-off style invented just for these two buttons. */
  .dock-xml-io-btn{
    flex:1; display:inline-flex; align-items:center; justify-content:center; gap:6px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    border:1px solid var(--hair-strong); border-radius:var(--radius-pill);
    padding:6px 12px; cursor:pointer;
    background:var(--paper); color:var(--ink-soft);
    box-shadow:var(--shadow-sm);
    transition:border-color .12s ease, color .12s ease, background .12s ease, transform .12s ease, box-shadow .12s ease;
  }
  .dock-xml-io-btn:hover{
    border-color:var(--ink-faint); color:var(--ink);
    box-shadow:var(--shadow-md); transform:translateY(-1px);
  }
  .dock-xml-io-btn .material-symbols-outlined{ font-size:14px; opacity:0.75; }
  .dock-canvas-size{
    padding:var(--s2); border-bottom:1px solid var(--hair-strong); flex-shrink:0;
  }
  .canvas-size-row{ display:flex; align-items:center; gap:6px; }
  .dims-label{ font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-faint); }
  .dock-canvas-size .dims-input{ flex:1; min-width:0; width:auto; }
  .dock-canvas-bg{
    /* No border-bottom here — the card inside (.insp-section) already draws its own full
       boundary right up against this section's bottom edge, so a second divider directly below
       it just doubled the line. .rail-section's own margin-bottom is enough separation. */
    padding:var(--s2); flex-shrink:0; display:none;
  }
  .dock-canvas-bg.show{ display:block; }
  .dock-palette{
    padding:var(--s2) var(--s2) var(--s1); border-bottom:1px solid var(--hair-strong); flex-shrink:0;
  }
  .palette-section{ margin-top:var(--s2); }
  .palette-section:first-child{ margin-top:0; }
  .palette-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    text-transform:uppercase; letter-spacing:.08em; margin-bottom:8px;
  }
  .palette-row{ display:flex; gap:6px; flex-wrap:wrap; width:100%; }
  .chip{
    display:inline-flex; align-items:center; gap:6px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    border:1px solid var(--hair-strong); border-radius:var(--radius-pill);
    padding:6px 12px 6px 9px; cursor:grab;
    background:var(--paper); color:var(--ink-soft);
    box-shadow:var(--shadow-sm);
    transition:border-color .12s ease, color .12s ease, background .12s ease, transform .12s ease, box-shadow .12s ease;
  }
  .chip:hover{
    border-color:var(--ink-faint); color:var(--ink);
    box-shadow:var(--shadow-md); transform:translateY(-1px);
  }
  .chip:active{ cursor:grabbing; transform:translateY(0); }
  .chip .material-symbols-outlined{ font-size:14px; opacity:0.75; }

  /* —— widgets —— */
  .widget{ position:absolute; cursor:grab; user-select:none; overflow:visible; }
  .widget:active{ cursor:grabbing; }
  .widget.selected{
    outline:1.5px dashed var(--amber); outline-offset:3px;
  }
  .widget.selected.scrubbing{ outline:none; }
  body.mode-paint .widget.selected{ outline-color:var(--rubric); outline-style:solid; }
  body.mode-paint .widget.selected.scrubbing{ outline:none; }
  /* Rotary knob — same visual language as the Effects-mode rack knob (.fx-param-knob),
     just sized relative to the widget's own box instead of a fixed 52px, so it works as a
     Wireframe-mode placeholder at any size, not only in the fixed-size FX rack strip. */
  .w-knob{
    border-radius:50%; border:2px solid var(--hair-strong); background:var(--paper);
    box-shadow:inset 0 2px 6px rgba(0,0,0,.12), 0 1px 0 rgba(255,255,255,.06);
    position:relative; width:100%; height:100%;
  }
  .w-knob-dial{
    width:100%; height:100%; display:flex; align-items:flex-start; justify-content:center;
    padding-top:9%; pointer-events:none;
  }
  .w-knob i{
    width:8%; max-width:3px; min-width:1.5px; height:22%; border-radius:1px;
    background:var(--amber); box-shadow:0 0 4px color-mix(in srgb, var(--amber) 45%, transparent);
  }
  .w-box{ border:1.5px solid var(--ink); background:transparent; width:100%; height:100%; border-radius:2px; }
  /* Fader (vertical) / sliderh (horizontal) — track + fill + thumb, same border/shadow/amber
     language as the knob above. Fill grows from the bottom/left normally, or from the
     center outward for pan widgets (w.pan) — a centered fader visually reads as "deviation
     from center" rather than "how far from one fixed end." */
  .w-fader, .w-sliderh{
    border:2px solid var(--hair-strong); background:var(--paper); border-radius:3px;
    box-shadow:inset 0 2px 6px rgba(0,0,0,.10);
    width:100%; height:100%; position:relative; overflow:hidden;
  }
  .w-fader-fill{ position:absolute; background:color-mix(in srgb, var(--amber) 22%, transparent); }
  .w-fader .w-fader-fill{ left:0; right:0; }
  .w-sliderh .w-fader-fill{ top:0; bottom:0; }
  .w-fader-thumb{
    position:absolute; background:var(--amber); border-radius:1px;
    box-shadow:0 0 4px color-mix(in srgb, var(--amber) 45%, transparent);
  }
  .w-fader .w-fader-thumb{ left:0; right:0; height:3px; transform:translateY(50%); }
  .w-sliderh .w-fader-thumb{ top:0; bottom:0; width:3px; transform:translateX(-50%); }
  .w-menu{
    border:1.5px solid var(--ink); background:transparent; width:100%; height:100%;
    display:flex; align-items:center; justify-content:flex-end; padding-right:6px;
    font-size:var(--font-sm); color:var(--ink-faint); border-radius:2px;
  }
  /* Font/size/weight/spacing/color/align/valign all come from inline styles set per-instance
     (textWidgetHTML/applyTextStyleToEl in vellum-app.html) — this rule only handles layout:
     fill the widget's box and let justify-content/align-items (both set inline, driven by the
     horizontal/vertical align choice) position the text. */
  .w-text{
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
    width:100%; height:100%; box-sizing:border-box;
    display:flex; align-items:center;
  }
  .w-visualizer{ border:none; width:100%; height:100%; border-radius:2px; overflow:hidden; }
  body:not(.mode-paint) .w-visualizer{ border:1.5px dashed var(--ink-faint); }
  .w-visualizer canvas{ display:block; width:100%; height:100%; }
  /* Unskinned `image` widget — only ever shown before a PNG/JPG/SVG is uploaded; once one
     exists, paintSkinOnEl takes over and this placeholder is never rendered, in either mode
     (unlike visualizer's own dashed treatment, which is mode-gated because it shows a live
     canvas in Paint instead — image has no such live-preview alternative to switch to). */
  .w-image-placeholder{
    width:100%; height:100%; box-sizing:border-box;
    border:1.5px dashed var(--ink-faint); border-radius:4px;
    display:flex; align-items:center; justify-content:center;
    color:var(--ink-faint);
  }
  .w-image-placeholder .material-symbols-outlined{ font-size:28px; }
  /* `chart` widget canvas — background/text/grid/line all come from skin colors baked into the
     canvas bitmap itself (drawChartCanvas in vellum-app.html), so this rule only needs to size
     the element and set the drag cursor; there's no CSS-level fallback color to pick since an
     unskinned chart already defaults to black/white/gray inside drawChartCanvas. */
  .w-chart-canvas{ display:block; width:100%; height:100%; border-radius:2px; cursor:crosshair; }
  /* `xypad` widget — pure DOM/CSS, no canvas (unlike chart): the grid is a CSS background
     gradient (colors baked in inline via xyPadWidgetHTML), the thumb is one absolutely
     positioned circle. pointer-events:none on the thumb so drag events always land on the pad
     itself, not the dot, matching the mockup's own delegation to the pad. */
  .w-xypad{ position:relative; width:100%; height:100%; border-radius:2px; cursor:crosshair; touch-action:none; box-sizing:border-box; overflow:hidden; }
  .w-xypad-thumb{ position:absolute; border-radius:50%; border:2px solid; transform:translate(-50%,-50%); pointer-events:none; box-sizing:border-box; }
  /* `camtracker` widget — a live-drawn canvas (camera frame + hand skeleton, see
     drawCamTrackerCanvas) plus one overlay button toggling the shared tracking pipeline on/off.
     Designer-only for now — see this widget's own plan doc. */
  .w-camtracker{ position:relative; width:100%; height:100%; border-radius:2px; overflow:hidden; }
  .w-camtracker-canvas{ display:block; width:100%; height:100%; }
  .w-camtracker-toggle{
    position:absolute; left:50%; bottom:6px; transform:translateX(-50%);
    font-family:'IBM Plex Mono',monospace; font-size:10px;
    padding:4px 10px; border-radius:var(--radius-sm);
    border:1px solid rgba(255,255,255,0.35); background:rgba(0,0,0,0.55); color:#fff;
    cursor:pointer;
  }
  .w-camtracker-toggle:hover{ background:rgba(0,0,0,0.75); }
  .w-camtracker-toggle:disabled{ opacity:0.6; cursor:default; }
  /* Primitive `shape` widget — fill/stroke/corner-radius/inset-shadow filter all live on the
     inner SVG shape element itself (shapeWidgetHTML in vellum-app.html); the drop shadow is a
     CSS `filter:drop-shadow()` set inline on this wrapper (not the SVG shape) since CSS filters
     on an element apply after that element's own children render, so the shadow follows the
     shape's real silhouette (including the triangle's clip) rather than its bounding box the
     way `box-shadow` would. */
  .w-shape-wrap{ width:100%; height:100%; }
  .w-shape-svg{ display:block; width:100%; height:100%; overflow:visible; }
  .w-meter{ border:1.5px solid var(--ink); width:100%; height:100%; background:linear-gradient(to top, var(--ink) 45%, transparent 45%); border-radius:2px; position:relative; }
  .w-meter-ch{
    position:absolute; left:2px; top:2px;
    font-family:'IBM Plex Mono',monospace; font-size:9px; line-height:1;
    color:var(--ink-soft); pointer-events:none;
  }
  /* Pad Row style for the `keys` widget (padRowHTML in vellum-app.html) — rounded-key
     alternative to the classic piano look: small circles for sharps sitting in the real gaps
     between pill-shaped naturals, matching an actual keybed's layout. `.w-pad`'s own resting/
     active fill comes from inline `background` (set per-instance via data-rest/data-active, see
     setPianoWidgetKeyActive), so nothing here needs a skin-color-specific rule — this file only
     adds what a flat background swap can't: the outline stroke, glow halo behind a lit key, and
     the label/nav-button chrome. */
  /* Border/box-sizing now set inline per-instance (padTwoRowHTML's own `outline` variable, from
     skin.keyOutlineColor) so it can be customized per widget — this rule only adds the glow
     transition, which is genuinely universal and not skin-specific. */
  .w-pad{ transition:box-shadow .08s ease; }
  .w-pad.key-active{ box-shadow:0 0 14px 4px color-mix(in srgb, var(--amber) 65%, transparent); }
  .w-pad-label{
    font-family:'IBM Plex Mono',monospace; font-size:8px; letter-spacing:.02em;
    line-height:1; pointer-events:none; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .w-pad-nav{
    background:transparent; color:var(--amber); border:none;
    font-size:18px; font-weight:600; line-height:1; cursor:pointer; padding:0;
    transition:transform .08s ease, color .08s ease;
  }
  .w-pad-nav:hover:not(:disabled){ transform:scale(1.2); }
  .w-pad-nav:disabled{ color:var(--piano-key-divider); cursor:default; }
  .resize-handle{
    position:absolute; right:-4px; bottom:-4px; width:8px; height:8px;
    background:var(--ink); border-radius:2px; cursor:nwse-resize;
    box-shadow:0 0 0 2px var(--paper);
  }
  .guide{ position:absolute; background:var(--amber); pointer-events:none; opacity:0; z-index:3; }
  .guide.v{ width:1px; top:0; bottom:0; } .guide.h{ height:1px; left:0; right:0; }
  .guide.show{ opacity:.9; }
  .frame-line{
    position:absolute; z-index:2;
    background:var(--hair-strong);
    transition:background .12s ease;
  }
  .frame-line.selected{ background:var(--amber); z-index:3; }
  body.mode-paint .frame-line,
  body.mode-paint .frame-line-handle{ pointer-events:none !important; }
  .frame-line-handle{
    position:absolute; z-index:4;
    width:8px; height:8px;
    background:var(--amber);
    border:2px solid var(--paper);
    border-radius:2px;
    box-shadow:var(--shadow-sm);
  }
  .frame-line-handle.start{ cursor:grab; }
  .frame-line-handle.end{ cursor:grab; }
  .frame-line[data-orient="v"]{ cursor:ew-resize; }
  .frame-line[data-orient="h"]{ cursor:ns-resize; }
  .marquee{
    position:absolute; z-index:4; pointer-events:none; display:none;
    border:1px solid var(--amber);
    background: color-mix(in srgb, var(--amber) 18%, transparent);
  }
  body.mode-paint .marquee{ border-color:var(--rubric); background: color-mix(in srgb, var(--rubric) 16%, transparent); }
  .marquee.show{ display:block; }

  /* —— dock / inspector —— */
  .dock{
    border-left:1px solid var(--hair-strong);
    display:flex; flex-direction:column; min-height:0; overflow:hidden;
    background:var(--paper);
  }
  #tourCanvasSize{ flex-shrink:0; }
  #tourDock{
    flex:1; min-height:0; display:flex; flex-direction:column; overflow:hidden;
  }
  #tourProperties{
    flex:1; min-height:0; display:flex; flex-direction:column; overflow:hidden;
  }
  .dock-tabs{
    display:flex; border-bottom:1px solid var(--hair-strong); flex-shrink:0;
    padding:0 4px;
  }
  .dock-tab{
    flex:1; text-align:center; padding:10px 8px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font); color:var(--ink-faint);
    cursor:pointer; border-bottom:2px solid transparent; margin-bottom:-1px;
    transition:color .15s ease, border-color .15s ease;
  }
  .dock-tab:hover{ color:var(--ink-soft); }
  .dock-tab.on{ color:var(--ink); border-bottom-color:var(--amber); }
  body.mode-paint .dock-tab.on{ border-bottom-color:var(--rubric); }
  .dock-body{
    padding:var(--s2); flex:1; overflow-y:auto; min-height:0;
    transition:background-color .25s ease;
  }
  body.mode-paint .dock-body{ background:var(--paper); }

  .layer-row{
    display:flex; align-items:center; gap:6px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:7px 9px; border-radius:var(--radius); cursor:pointer; color:var(--ink-soft);
    transition:background .12s ease, color .12s ease;
  }
  .layer-row:hover{ background:var(--workspace); color:var(--ink); }
  .layer-row.on{ background:var(--amber-soft); color:var(--ink); }
  body.mode-paint .layer-row.on{ background: color-mix(in srgb, var(--amber-soft) 70%, var(--paper)); }
  /* Dragged row fades in place (native DnD already shows its own drag-image ghost, so this
     just marks the source slot); the row currently under the cursor gets a top edge rule as an
     insertion cue — cheap to read at a glance without a full placeholder-row reflow scheme. */
  .layer-row.dragging{ opacity:.4; }
  .layer-row.drag-over{ box-shadow:inset 0 1.5px 0 0 var(--amber); }
  .layer-drag{
    flex-shrink:0; width:14px; height:18px; font-size:15px;
    display:flex; align-items:center; justify-content:center;
    color:var(--ink-faint); cursor:grab; opacity:0; transition:opacity .12s ease, color .12s ease;
  }
  .layer-row:hover .layer-drag{ opacity:.85; }
  .layer-drag:hover{ color:var(--ink); }
  .layer-eye{
    flex-shrink:0; width:18px; height:18px;
    display:flex; align-items:center; justify-content:center;
    border-radius:4px; color:var(--ink-soft); cursor:pointer;
    opacity:.9; transition:opacity .12s ease, background .12s ease, color .12s ease;
  }
  .layer-eye:hover{ background:var(--hair); color:var(--ink); opacity:1; }
  .layer-eye.off{ opacity:.32; }
  .layer-eye.off:hover{ opacity:.55; }
  .layer-name{
    flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .layer-del{
    color:var(--ink-faint); cursor:pointer; opacity:0; width:18px; height:18px;
    display:flex; align-items:center; justify-content:center; border-radius:4px;
    transition:opacity .12s ease, background .12s ease, color .12s ease;
  }
  .layer-row:hover .layer-del{ opacity:1; }
  .layer-del:hover{ background:var(--hair); color:var(--ink); }

  .insp-section{
    margin-bottom:12px;
    padding:0;
    border:1px solid var(--hair-strong);
    border-radius:var(--radius);
    background:var(--workspace);
    overflow:hidden;
  }
  .insp-section:last-child{ margin-bottom:0; }
  .insp-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink);
    text-transform:uppercase; letter-spacing:.06em;
    padding:10px 12px;
    border-bottom:1px solid var(--hair-strong);
    background:var(--paper);
  }
  .insp-body{ padding:12px; }
  .insp-row{
    font-size:var(--font-sm); color:var(--ink-soft); margin-bottom:8px;
    font-family:'IBM Plex Mono',monospace;
    display:flex; justify-content:space-between; gap:8px;
  }
  .insp-row:last-child{ margin-bottom:0; }
  .insp-row span:last-child{ color:var(--ink); text-align:right; word-break:break-all; }
  .insp-empty{
    font-size:var(--font-sm); color:var(--ink-faint); font-family:'IBM Plex Mono',monospace;
    line-height:1.5; padding:12px;
  }
  .insp-file{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--ink-faint); margin-top:8px;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .insp-actions{ margin-top:10px; display:flex; flex-direction:column; gap:8px; }

  /* —— samples zone properties — compact row inspector —— */
  .zone-props .insp-label.zone-props-head{
    text-transform:uppercase; letter-spacing:.08em; font-size:var(--font-xs);
    color:var(--ink-soft); padding:8px 12px;
  }
  .zone-props-title{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font); color:var(--ink);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    margin:-2px 0 6px;
  }
  .zone-props-body{ display:flex; flex-direction:column; gap:0; }
  .zone-props-map{
    display:flex; flex-direction:column; gap:0;
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:color-mix(in srgb, var(--workspace) 65%, var(--paper));
    overflow:hidden;
  }
  .zone-props-line{
    display:grid; grid-template-columns:44px 1fr; gap:8px; align-items:center;
    min-height:36px; padding:0 10px;
    border-bottom:1px solid var(--hair-strong);
  }
  .zone-props-line:last-child{ border-bottom:none; }
  .zone-props-k{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--ink-soft); letter-spacing:.02em;
  }
  .zone-props-k.root::before{
    content:''; display:inline-block; width:5px; height:5px; margin-right:3px;
    border-radius:50%; background:var(--rubric); vertical-align:1px;
  }
  .zone-props-ctl{
    display:flex; align-items:center; justify-content:flex-end; gap:3px; min-width:0;
  }
  .zone-props-ctl-range{ gap:3px; flex-wrap:nowrap; }
  .zone-props-range-end{
    display:flex; align-items:center; gap:0; flex-shrink:0;
  }
  .zone-props-spin{
    display:flex; flex-direction:column; width:16px; height:28px; flex-shrink:0;
    border:1px solid var(--hair-strong); border-left:none;
    border-radius:0 4px 4px 0; overflow:hidden;
    background:var(--paper);
  }
  .zone-props-spin-btn{
    flex:1; min-height:0; padding:0; margin:0; border:none;
    background:transparent; cursor:pointer; position:relative;
    transition:background .12s ease;
  }
  .zone-props-spin-btn + .zone-props-spin-btn{ border-top:1px solid var(--hair-strong); }
  .zone-props-spin-btn:hover{ background:var(--workspace); }
  .zone-props-spin-btn::after{
    content:''; position:absolute; left:50%; transform:translateX(-50%);
    width:0; height:0; border-left:3.5px solid transparent; border-right:3.5px solid transparent;
  }
  .zone-props-spin-btn[data-delta="1"]::after{
    bottom:2px; border-bottom:4px solid var(--ink-soft);
  }
  .zone-props-spin-btn[data-delta="-1"]::after{
    top:2px; border-top:4px solid var(--ink-soft);
  }
  .zone-props-spin-btn[data-delta="1"]:hover::after{ border-bottom-color:var(--ink); }
  .zone-props-spin-btn[data-delta="-1"]:hover::after{ border-top-color:var(--ink); }
  .zone-props-num{
    width:42px; font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:4px 0; border:1px solid var(--hair-strong); border-radius:4px 0 0 4px;
    border-right:none;
    background:var(--paper); color:var(--ink); text-align:center;
    -moz-appearance:textfield; appearance:textfield;
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .zone-props-num::-webkit-outer-spin-button,
  .zone-props-num::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0; }
  .zone-props-num:focus{
    outline:none; border-color:var(--amber);
    box-shadow:0 0 0 2px var(--ring);
  }
  .zone-props-num:focus + .zone-props-spin{
    border-color:var(--amber);
    box-shadow:2px 0 0 0 var(--ring);
  }
  .zone-props-dash{ font-size:var(--font-xs); color:var(--ink-faint); padding:0 3px; flex-shrink:0; }
  .zone-props-meta{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    color:var(--ink-soft); line-height:1.45; margin-top:8px;
  }
  .zone-props-details{
    margin-top:10px; border-top:1px solid var(--hair-strong); padding-top:8px;
  }
  .zone-props-details summary{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    color:var(--ink-soft); letter-spacing:.06em; text-transform:uppercase;
    cursor:pointer; list-style:none; display:flex; align-items:center; gap:6px;
    user-select:none; padding:0 0 8px;
  }
  .zone-props-details summary::-webkit-details-marker{ display:none; }
  .zone-props-details summary::before{
    /* Was --font-xs (11px) at --ink-faint — the only visual cue this whole section is
       collapsible, so being both small and low-contrast made it easy to miss entirely. */
    content:'▸'; font-size:15px; color:var(--ink-soft); transition:transform .12s ease;
  }
  .zone-props-details[open] summary::before{ transform:rotate(90deg); }
  .zone-props-details-body{
    display:flex; flex-direction:column; gap:0;
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:color-mix(in srgb, var(--workspace) 65%, var(--paper));
    overflow:hidden;
  }
  .zone-props-stub{
    display:grid; grid-template-columns:44px 1fr auto; gap:8px; align-items:center;
    min-height:36px; padding:0 10px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
    border-bottom:1px solid var(--hair-strong);
  }
  .zone-props-stub:last-child{ border-bottom:none; }
  .zone-props-stub span:nth-child(2){ color:var(--ink); text-align:right; font-size:var(--font-sm); }
  .zone-props-stub span:last-child{
    color:var(--ink-soft); font-size:var(--font-xs); text-align:right; min-width:48px;
  }
  .zone-props-play-line{
    display:grid; grid-template-columns:52px 1fr 52px; gap:8px; align-items:center;
    min-height:36px; padding:0 10px; border-bottom:1px solid var(--hair-strong);
  }
  .zone-props-play-line:last-child{ border-bottom:none; }
  .zone-props-play-line .zone-props-ctl{ justify-content:flex-end; }
  .zone-props-u{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    color:var(--ink-soft); text-align:right;
  }
  .zone-props-num-wide{ width:74px; }
  .zone-props-loop-line{
    display:grid; grid-template-columns:44px 1fr; gap:8px; align-items:center;
    min-height:36px; padding:0 10px; border-bottom:1px solid var(--hair-strong);
  }
  .zone-props-seg{ display:flex; gap:3px; justify-content:flex-end; flex-wrap:nowrap; }
  .zone-props-seg-btn{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); line-height:1.25;
    padding:5px 7px; border:1px solid var(--hair-strong); border-radius:3px;
    background:var(--paper); color:var(--ink-soft); cursor:pointer;
    transition:background .12s ease, border-color .12s ease, color .12s ease;
  }
  .zone-props-seg-btn:hover{ border-color:var(--ink-faint); color:var(--ink); }
  .zone-props-seg-btn.on{
    background:color-mix(in srgb, var(--amber) 70%, var(--paper));
    color:var(--ink); border-color:var(--amber);
  }
  .zone-props-play-line .zone-props-seg{ width:100%; }
  .zone-props-select{
    width:100%; min-width:0; max-width:100%;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    padding:4px 24px 4px 8px;
  }
  .zone-props-play-line.is-disabled{ opacity:.45; pointer-events:none; }
  .zone-props-bar-wrap{
    position:relative; width:100%; min-width:0; height:26px;
  }
  .zone-props-bar{
    position:absolute; inset:0; border-radius:3px;
    background:color-mix(in srgb, var(--hair-strong) 80%, var(--paper));
    overflow:hidden; pointer-events:none;
  }
  .zone-props-bar::before{
    content:''; position:absolute; left:0; top:0; bottom:0;
    width:var(--fill, 0%); max-width:100%;
    background:color-mix(in srgb, var(--ink-faint) 40%, var(--paper));
  }
  .zone-props-bar-val{
    position:absolute; inset:0; z-index:1;
    display:flex; align-items:center; justify-content:center;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink);
    pointer-events:none;
  }
  .zone-props-range{
    position:absolute; inset:0; width:100%; height:100%;
    margin:0; opacity:0; cursor:pointer; z-index:2;
  }
  .zone-props-range-plain{
    position:relative; opacity:1; z-index:0;
    -webkit-appearance:none; appearance:none; width:100%; height:4px;
    background:var(--hair-strong); border-radius:var(--radius-pill);
    outline:none; margin:9px 0;
  }
  .zone-props-range-plain::-webkit-slider-thumb{
    -webkit-appearance:none; width:8px; height:14px; border-radius:2px;
    background:var(--amber); border:1px solid color-mix(in srgb, var(--amber) 60%, var(--ink));
    cursor:pointer; box-shadow:var(--shadow-sm);
  }
  .zone-props-range-plain::-moz-range-thumb{
    width:8px; height:14px; border-radius:2px; border:none;
    background:var(--amber); cursor:pointer;
  }

  /* form controls — shadcn tone */
  .field{ margin-bottom:0; }
  .skin-file{
    /* --font-sm, not --font — same reasoning as .skin-num right below: this lives in the same
       dense inspector cards, and the browser's own native file-input chrome (button + filename
       text) inherits this size directly, so the default --font made the whole control read as
       oversized next to every other compact control around it. */
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); width:100%;
    color:var(--ink-soft); padding:6px 9px; border:1px dashed var(--hair-strong);
    border-radius:var(--radius); background:var(--paper); cursor:pointer;
    transition:border-color .15s ease, background .15s ease;
  }
  .skin-file:hover{ border-color:var(--ink-faint); background: color-mix(in srgb, var(--paper) 70%, var(--workspace)); }
  /* Restyles the native file-input's own button portion (Chromium/WebView2 support
     ::file-selector-button) to match this app's pill-chip buttons instead of the OS-default
     boxy button — the single biggest visual mismatch in these cards otherwise, since this part
     of the control can't be reached by font-size/padding on the input itself. */
  .skin-file::file-selector-button{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    border:1px solid var(--hair-strong); border-radius:var(--radius-pill);
    padding:4px 10px; margin-right:8px;
    background:var(--workspace); color:var(--ink-soft); cursor:pointer;
    transition:border-color .12s ease, color .12s ease, background .12s ease;
  }
  .skin-file:hover::file-selector-button{ border-color:var(--ink-faint); color:var(--ink); }
  .skin-num{
    /* --font-sm, not --font — this class lives in dense inspector side panels (menu-style
       dropdown size, skin frame counts/gutter) where --font (15px, meant for controls read
       carefully at a distance) renders visibly oversized next to every --font-sm label/row
       around it. */
    width:100%; font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    padding:7px 9px; background:var(--paper); color:var(--ink);
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .skin-num:focus{
    outline:none; border-color:var(--amber);
    box-shadow:0 0 0 3px var(--ring);
  }
  body.mode-paint .skin-num:focus{ border-color:var(--rubric); }
  .frame-row{ display:flex; gap:8px; align-items:center; }
  .frame-row .skin-num{ flex:1; }
  input[type="range"]{
    -webkit-appearance:none; appearance:none; width:100%; height:4px;
    background:var(--hair-strong); border-radius:var(--radius-pill); outline:none; margin:4px 0 0;
  }
  input[type="range"]::-webkit-slider-thumb{
    -webkit-appearance:none; width:14px; height:14px; border-radius:50%;
    background:var(--ink); border:2px solid var(--paper); cursor:pointer;
    box-shadow:var(--shadow-sm);
  }
  body.mode-paint input[type="range"]::-webkit-slider-thumb{ background:var(--rubric); }
  .btn-ghost{
    display:block; width:100%; text-align:center;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font);
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    padding:7px 10px; margin-top:0;
    background:var(--paper); color:var(--ink-soft);
    transition:border-color .15s ease, color .15s ease, background .15s ease;
  }
  .btn-ghost:hover{ border-color:var(--ink-faint); color:var(--ink); }

  /* —— paint context menu —— */
  .ctx-menu{
    position:fixed; z-index:100; min-width:168px;
    background:var(--paper); border:1px solid var(--hair-strong);
    border-radius:var(--radius); box-shadow:var(--shadow-md);
    padding:4px; display:none;
  }
  .ctx-menu.open{ display:block; }
  .ctx-item{
    display:block; width:100%; text-align:left;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:7px 10px; border:none; border-radius:4px;
    background:transparent; color:var(--ink); cursor:pointer;
  }
  .ctx-item:hover{ background:var(--workspace); }
  .ctx-item:disabled{ color:var(--ink-faint); cursor:default; }
  .ctx-item:disabled:hover{ background:transparent; }
  .ctx-sep{ height:1px; background:var(--hair-strong); margin:4px 2px; border:none; }

  /* —— instrument presets dropdown —— */
  /* Deliberately NOT sharing classes with .preset-row/.preset-btn (the Sketch-mode layout
     picker) or the FX-chain preset <select> — those are unrelated "preset" concepts already in
     this file; sharing classes would mean a future restyle of one accidentally restyles this
     list too. New .ip- prefix instead, though it borrows the same tokens/visual language. */
  /* position:fixed + JS-computed left/top (see instrumentPresetsMenuBtn's click handler), not
     a simple `position:absolute` under the trigger button — `.samples-panel` (an ancestor) has
     `overflow:hidden`, which would clip an absolutely-positioned dropdown extending below the
     header; fixed positioning escapes that since it's relative to the viewport, not any
     ancestor's box. */
  .ip-panel{
    position:fixed; z-index:100; min-width:200px; max-width:280px;
    background:var(--paper); border:1px solid var(--hair-strong);
    border-radius:var(--radius); box-shadow:var(--shadow-md);
    padding:4px; display:none;
  }
  .ip-panel.open{ display:block; }
  .ip-list{ display:flex; flex-direction:column; gap:2px; max-height:280px; overflow-y:auto; }
  .ip-row{
    display:block; width:100%; text-align:left;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:6px 9px; border:1px solid transparent; border-radius:var(--radius);
    background:transparent; color:var(--ink-soft); cursor:pointer;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
    transition:background .12s ease, color .12s ease;
  }
  .ip-row:hover{ background:var(--workspace); color:var(--ink); }
  .ip-empty{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-faint);
    padding:8px 6px;
  }
  .ip-row-badge{ opacity:.6; margin-left:4px; font-size:.9em; }

  /* —— confirm dialog (shadcn AlertDialog pattern, built on our own tokens) —— */
  .dialog-overlay{
    position:fixed; inset:0; z-index:200;
    background:rgba(0,0,0,0.45);
    -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
    display:none; align-items:center; justify-content:center;
    animation:dialogFadeIn .15s ease;
  }
  .dialog-overlay.open{ display:flex; }
  @keyframes dialogFadeIn{ from{ opacity:0; } to{ opacity:1; } }
  .dialog-card{
    width:380px; max-width:calc(100vw - 48px);
    background:var(--paper); color:var(--ink);
    border:1px solid var(--hair-strong); border-radius:var(--radius-lg);
    box-shadow:var(--shadow-md);
    padding:20px 20px 16px;
    animation:dialogPop .15s ease;
  }
  @keyframes dialogPop{ from{ opacity:0; transform:translateY(4px) scale(0.98); } to{ opacity:1; transform:none; } }
  .dialog-title{
    font-family:'IBM Plex Sans', sans-serif; font-weight:600; font-size:var(--font-lg);
    margin-bottom:8px;
  }
  .dialog-desc{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
    line-height:1.5; white-space:pre-line;
  }
  .dialog-actions{
    display:flex; justify-content:flex-end; gap:8px; margin-top:20px;
  }
  .dialog-btn{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:7px 14px; border-radius:var(--radius); border:1px solid var(--hair-strong);
    cursor:pointer; transition:border-color .15s ease, background .15s ease, color .15s ease;
  }
  .dialog-btn-ghost{ background:var(--paper); color:var(--ink-soft); }
  .dialog-btn-ghost:hover{ border-color:var(--ink-faint); color:var(--ink); background:var(--workspace); }
  .dialog-btn-primary{ background:var(--ink); color:var(--paper); border-color:var(--ink); }
  .dialog-btn-primary:hover{ background:color-mix(in srgb, var(--ink) 85%, var(--amber)); }
  .dialog-btn:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }
  .auth-google-btn{
    display:flex; align-items:center; justify-content:center; gap:10px; width:100%;
    font-family:'IBM Plex Sans', sans-serif; font-weight:500; font-size:var(--font-sm);
    padding:9px 14px; border-radius:var(--radius); border:1px solid var(--hair-strong);
    background:var(--paper); color:var(--ink); cursor:pointer; margin-top:16px;
    transition:border-color .15s ease, background .15s ease;
  }
  .auth-google-btn:hover{ border-color:var(--ink-faint); background:var(--workspace); }
  .auth-google-btn:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }
  .auth-gate-divider{
    display:flex; align-items:center; gap:10px; margin:14px 0 0;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    text-transform:uppercase; letter-spacing:.04em;
  }
  .auth-gate-divider::before, .auth-gate-divider::after{
    content:''; flex:1; height:1px; background:var(--hair-strong);
  }
  .auth-gate-fields{ display:flex; flex-direction:column; gap:2px; margin-top:14px; }
  .auth-gate-fields .plugin-meta-field{ margin-bottom:10px; }
  .auth-gate-error{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--rubric);
    margin-top:4px; line-height:1.4;
  }
  .account-dialog{ width:640px; max-width:calc(100vw - 48px); }
  .account-dialog-header{
    display:flex; align-items:flex-start; justify-content:space-between; gap:12px;
  }
  .dialog-icon-close{
    display:flex; align-items:center; justify-content:center;
    width:28px; height:28px; flex-shrink:0; margin-top:-2px;
    border:none; border-radius:var(--radius); background:transparent; color:var(--ink-faint);
    cursor:pointer; transition:color .15s ease, background .15s ease;
  }
  .dialog-icon-close:hover{ color:var(--ink); background:var(--workspace); }
  .dialog-icon-close .material-symbols-outlined{ font-size:18px; }
  .account-dialog-body{
    display:flex; gap:18px; margin-top:16px; padding-top:16px;
    border-top:1px solid var(--hair-strong);
  }
  .account-nav{
    display:flex; flex-direction:column; gap:2px; width:150px; flex-shrink:0;
  }
  .account-nav-item{
    display:flex; align-items:center; gap:8px; width:100%; text-align:left;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
    border:none; border-radius:var(--radius); background:transparent;
    padding:8px 10px; cursor:pointer;
    transition:background .15s ease, color .15s ease;
  }
  .account-nav-item .material-symbols-outlined{ font-size:16px; opacity:0.75; }
  .account-nav-item:hover{ background:var(--workspace); color:var(--ink); }
  .account-nav-item.on{ background:var(--amber-soft); color:var(--ink); }
  .account-panels{ flex:1; min-width:0; min-height:220px; max-height:50vh; overflow-y:auto; }
  .account-panel{ display:none; }
  .account-panel.on{ display:block; }
  .account-section-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    text-transform:uppercase; letter-spacing:.08em; margin-bottom:10px;
  }
  .account-profile-row{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink);
    margin-bottom:14px;
  }
  .account-integrations-status{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-faint);
    margin-top:4px; line-height:1.4;
  }
  .account-integrations-intro{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
    line-height:1.5; margin-bottom:16px;
  }
  .integrations-service{ margin-bottom:20px; }
  .integrations-service-label{
    font-family:'IBM Plex Sans', sans-serif; font-weight:600; font-size:var(--font-sm);
    margin-bottom:8px;
  }
  .integrations-product-list{ display:flex; flex-direction:column; gap:8px; }
  .integrations-product-row{
    display:grid; grid-template-columns:1fr 1fr 1fr auto; gap:6px; align-items:center;
  }
  .integrations-product-row .plugin-meta-field{ margin-bottom:0; }
  .integrations-remove-btn{
    display:flex; align-items:center; justify-content:center;
    width:28px; height:28px; flex-shrink:0;
    border:1px solid var(--hair-strong); border-radius:var(--radius); background:var(--paper);
    color:var(--ink-faint); cursor:pointer;
    transition:border-color .15s ease, color .15s ease, background .15s ease;
  }
  .integrations-remove-btn:hover{ border-color:var(--rubric); color:var(--rubric); background:var(--workspace); }
  .integrations-remove-btn .material-symbols-outlined{ font-size:16px; }
  .integrations-add-btn{
    display:inline-flex; align-items:center; gap:4px; margin-top:8px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
    border:1px dashed var(--hair-strong); border-radius:var(--radius); background:transparent;
    padding:6px 10px; cursor:pointer;
    transition:border-color .15s ease, color .15s ease, background .15s ease;
  }
  .integrations-add-btn:hover{ border-color:var(--ink-faint); color:var(--ink); background:var(--workspace); }
  .my-builds-dialog{ width:440px; }
  .my-builds-list{
    margin-top:14px; max-height:320px; overflow-y:auto;
    display:flex; flex-direction:column; gap:8px;
  }
  .my-builds-row{
    border:1px solid var(--hair-strong); border-radius:var(--radius);
    padding:10px 12px; background:var(--workspace);
  }
  .my-builds-row-top{ display:flex; justify-content:space-between; align-items:center; gap:8px; }
  .my-builds-row-name{
    font-family:'IBM Plex Sans', sans-serif; font-weight:600; font-size:var(--font-sm);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .my-builds-row-status{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); text-transform:uppercase;
    letter-spacing:.06em; padding:2px 8px; border-radius:var(--radius-pill); flex-shrink:0;
    background:var(--hair-strong); color:var(--ink-soft);
  }
  .my-builds-row-status.status-done{ background:color-mix(in srgb, #4caf50 25%, transparent); color:#2e7d32; }
  .my-builds-row-status.status-error{ background:color-mix(in srgb, var(--rubric) 20%, transparent); color:var(--rubric); }
  .my-builds-row-status.status-building,
  .my-builds-row-status.status-queued{ background:color-mix(in srgb, var(--amber) 25%, transparent); color:var(--ink); }
  .my-builds-row-meta{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    margin-top:4px;
  }
  .my-builds-row-downloads{ display:flex; gap:8px; margin-top:8px; flex-wrap:wrap; }
  .my-builds-row-downloads a{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    padding:4px 10px; border-radius:var(--radius-pill); border:1px solid var(--hair-strong);
    color:var(--ink); text-decoration:none; transition:border-color .12s ease, background .12s ease;
  }
  .my-builds-row-downloads a:hover{ border-color:var(--ink-faint); background:var(--paper); }
  .my-builds-empty{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-faint);
    text-align:center; padding:20px 0;
  }
  .sample-map-dialog{ width:420px; }
  .sample-map-fields{ display:flex; flex-direction:column; gap:10px; margin-top:14px; }
  .sample-map-row{
    display:grid; grid-template-columns:92px 1fr 28px 28px; gap:6px; align-items:center;
  }
  .sample-map-row label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-soft);
  }
  .sample-map-row input{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:6px 8px; border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); color:var(--ink); width:100%; box-sizing:border-box;
  }
  .sample-map-step{
    width:28px; height:28px; padding:0; border:1px solid var(--hair-strong); border-radius:var(--radius);
    background:var(--paper); color:var(--ink-soft); cursor:pointer; font-size:14px; line-height:1;
  }
  .sample-map-step:hover{ border-color:var(--ink-faint); color:var(--ink); background:var(--workspace); }
  .sample-map-note{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-faint); margin-top:4px;
  }
  .sample-map-detect{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--amber); margin-top:6px;
  }
  .sample-map-batch{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--ink-soft); margin-top:6px; line-height:1.45;
  }
  .sample-map-options{ display:flex; flex-direction:column; gap:8px; margin-top:12px; }
  .sample-map-check{
    display:flex; align-items:flex-start; gap:8px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--ink-soft); cursor:pointer; line-height:1.4;
  }
  .sample-map-check input{ margin-top:2px; accent-color:var(--amber); flex-shrink:0; }
  .sample-map-vel-fields[hidden]{ display:none; }
  .bg-color-row{ display:flex; align-items:center; gap:8px; }
  .color-swatch{
    width:32px; height:28px; padding:0; border:1px solid var(--hair-strong); border-radius:4px;
    background:none; cursor:pointer;
  }
  .color-swatch::-webkit-color-swatch-wrapper{ padding:2px; }
  .color-swatch::-webkit-color-swatch{ border:none; border-radius:2px; }
  .bg-color-label{ font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); color:var(--ink-faint); flex:1; }

  /* —— cloud build dialog —— */
  .cloud-build-spinner{
    width:28px; height:28px; margin:18px auto 4px;
    border:3px solid var(--hair-strong); border-top-color:var(--amber);
    border-radius:50%; animation:cloudBuildSpin .8s linear infinite;
  }
  .cloud-build-spinner[hidden]{ display:none; }
  @keyframes cloudBuildSpin{ to{ transform:rotate(360deg); } }
  .cloud-build-downloads{ display:flex; flex-direction:column; gap:8px; margin-top:16px; }
  .cloud-build-downloads[hidden]{ display:none; }
  .cloud-build-download-link{
    display:block; text-align:center; text-decoration:none;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:8px 14px; border-radius:var(--radius);
    background:var(--ink); color:var(--paper);
  }
  .cloud-build-download-link:hover{ background:color-mix(in srgb, var(--ink) 85%, var(--amber)); }

  /* Toolbar icon status tint — fixed stoplight colors rather than theme-derived ones on
     purpose: this is a semantic (in-progress/error/done) signal, not a branding accent, so it
     should read the same regardless of which of the four artboard themes is active. */
  #buildCloud.cloud-build-building .material-symbols-outlined{ color:#D9A62E; }
  #buildCloud.cloud-build-error .material-symbols-outlined{ color:#D64545; }
  #buildCloud.cloud-build-done .material-symbols-outlined{ color:#3FA76B; }

  /* —— tip strip —— */
  .tipbar{
    flex-shrink:0; border-top:1px solid var(--hair-strong);
    padding:8px var(--s3); height:40px;
    display:flex; align-items:center; overflow:hidden;
    background:var(--paper);
  }
  .tipbar-text{
    flex:1; min-width:0;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font);
    color:var(--ink-faint); line-height:1.35;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .tipbar-text.on{ color:var(--ink-soft); }
  body.tour-open .tipbar-text{ opacity:0; }

  /* —— audio preview —— */
  #previewToggle.on{ background:var(--amber-soft); border-color:var(--amber); color:var(--ink); }
  body.mode-paint #previewToggle.on{ background:var(--glow1-a); border-color:var(--amber); }

  /* —— Effects mode — center column only; rail + dock stay visible —— */
  body.mode-effects #tourPluginType,
  body.mode-effects #tourPluginSetup,
  body.mode-effects #tourRailLayouts{ display:none !important; }
  body.mode-effects #fxRail,
  body.mode-effects #tourFxRail{ display:flex !important; }
  body.mode-effects #tourCanvasSize,
  body.mode-effects .dock-palette{ display:none !important; }
  body.mode-effects #tourDock{ display:flex !important; flex:1; min-height:0; }
  body.mode-effects #tabLayers,
  body.mode-effects #tabProps{ display:none !important; }
  body.mode-effects #tabBind{ display:block !important; }
  #effectsModeBtn[hidden]{ display:none; }
  body.mode-effects .rail{
    display:flex; flex-direction:column; overflow:hidden;
  }
  #fxRail,
  #tourFxRail{
    display:none; flex-direction:column; gap:var(--s3);
    padding:0 4px 8px; min-height:0; flex:1;
  }
  #fxRail[hidden],
  #tourFxRail[hidden]{ display:none !important; }
  .fx-rail-toolbar{ margin-bottom:2px; }
  .fx-rail-toolbar .fx-dsp{ margin-left:0; margin-top:6px; display:inline-block; }
  .fx-rail-toolbar select{ width:100%; min-width:0; }
  #fxRail .fx-browser,
  #tourFxRail .fx-browser{ flex:1; min-height:0; }
  .fx-workspace{
    flex:1; display:flex; flex-direction:column; min-height:0; min-width:0;
    width:100%; align-self:stretch;
    padding:0; gap:var(--s3); color:var(--ink);
  }
  .fx-workspace[hidden]{ display:none !important; }
  /* Master/Group Effects panels — rendered into the real right dock (#dockBody) alongside
     the Bind section, not a standalone sidebar; sizing here assumes that narrower column. */
  .fx-bus-card{
    background:var(--paper); border:1px solid var(--hair); border-radius:var(--radius-lg);
    display:flex; flex-direction:column; overflow:hidden; flex:none; cursor:pointer;
    transition:border-color .15s ease, box-shadow .15s ease; margin-bottom:var(--s2);
  }
  /* Same glow language as an armed control on the plugin face (.fx-armed-target/
     fx-arm-pulse) — this card is "listening": the Signal Path rack, FX library, and
     preset dropdown are all currently pointed at it. */
  .fx-bus-card.active-scope{
    border-color:var(--amber);
    outline:2px solid var(--amber); outline-offset:2px;
    animation:fx-arm-pulse 1.2s ease-in-out infinite;
  }
  .fx-bus-card-head{ padding:12px 14px 10px; border-bottom:1px solid var(--hair); }
  .fx-bus-card-title{ display:flex; align-items:baseline; justify-content:space-between; gap:8px; }
  .fx-bus-card-title h3{
    margin:0; font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.08em; text-transform:uppercase; color:var(--ink);
  }
  .fx-bus-badge{
    font-family:'IBM Plex Mono',monospace; font-size:9.5px; letter-spacing:.05em;
    text-transform:uppercase; color:var(--ink-faint); border:1px solid var(--hair-strong);
    border-radius:999px; padding:1px 7px; white-space:nowrap;
  }
  .fx-bus-card.master .fx-bus-badge{ color:var(--amber); border-color:var(--amber); }
  .fx-bus-caption{ margin:5px 0 0; font-size:11.5px; color:var(--ink-faint); line-height:1.4; }
  .fx-bus-caption b{ color:var(--ink-soft); font-weight:600; }
  .fx-bus-select-row{ margin-top:9px; }
  .fx-bus-select{
    width:100%; background:var(--workspace); border:1px solid var(--hair-strong); color:var(--ink);
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); padding:6px 9px;
    border-radius:var(--radius); cursor:pointer;
  }
  .fx-bus-list-wrap{ position:relative; }
  .fx-bus-list{ list-style:none; margin:0; padding:6px; max-height:190px; overflow-y:auto; }
  .fx-bus-list:empty::after{
    content:'No effects yet'; display:block; padding:10px 6px; font-size:12px; color:var(--ink-faint);
  }
  .fx-bus-row{
    display:flex; align-items:center; gap:9px; padding:7px 8px; border-radius:var(--radius);
    margin-bottom:2px; cursor:pointer;
  }
  .fx-bus-row:hover{ background:var(--hair); }
  .fx-bus-row-idx{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    width:14px; flex:none;
  }
  .fx-bus-row-name{ flex:1; font-size:var(--font-sm); color:var(--ink); }
  .fx-bus-row.bypassed .fx-bus-row-name{ color:var(--ink-faint); }
  .fx-bus-row.bypassed .fx-slot-icon,
  .fx-bus-row.bypassed .fx-chip-icon{ opacity:.4; }
  .fx-bus-row-led{
    width:9px; height:9px; border-radius:50%; background:var(--amber); border:none;
    flex:none; cursor:pointer; padding:0;
  }
  .fx-bus-row.bypassed .fx-bus-row-led{ background:var(--hair-strong); }
  .fx-bus-dock-sep{ height:1px; background:var(--hair-strong); margin:var(--s2) 0; }
  .fx-toolbar{
    display:flex; align-items:center; gap:10px; flex-wrap:wrap;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.04em; text-transform:uppercase;
  }
  .fx-toolbar label{ color:var(--ink-soft); }
  .fx-toolbar select{
    font-family:inherit; font-size:var(--font-sm); letter-spacing:0; text-transform:none;
    min-width:160px;
  }
  .fx-dsp{
    margin-left:auto; padding:4px 10px; border-radius:999px;
    background:var(--paper); border:1px solid var(--hair); color:var(--ink-soft);
  }
  .fx-dsp.warn{ border-color:var(--amber); color:var(--amber); background:var(--amber-soft); }
  .fx-main{
    flex:1; display:flex; flex-direction:column; min-height:0;
  }
  .fx-browser-toggle{
    display:flex; align-items:center; gap:6px; flex-shrink:0; margin-bottom:8px;
  }
  .fx-browser{
    background:var(--paper); border:1px solid var(--hair); border-radius:var(--radius-sm);
    padding:8px; overflow-y:auto; min-height:0;
  }
  /* Chip-level armed state — the FX library's own chips never needed this before (arming
     happens on a selected slot's params, not on library chips), but the synth-param browser
     reuses `.fx-chip` directly as its own list of armable targets. */
  .fx-chip.armed{
    border-color:var(--amber); background:var(--amber-soft); color:var(--ink);
  }
  /* Synth-param chips only — the FX library's own chips are icon+name with no value to show,
     but a synth param chip is a live control's stand-in, so showing its current value is
     what makes "did my drag on the Plugin Face actually do anything" visible from here too. */
  .fx-chip-label{ flex:1; }
  .fx-chip-value{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); color:var(--ink-faint);
    white-space:nowrap;
  }
  .fx-browser-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.08em; text-transform:uppercase; color:var(--ink-soft);
    margin-bottom:8px;
  }
  .fx-cat{ margin-bottom:10px; }
  .fx-cat-name{
    font-size:10px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--ink-faint); margin-bottom:5px;
  }
  .fx-chip{
    display:flex; align-items:center; gap:6px;
    width:100%; padding:5px 7px; margin-bottom:4px;
    border:1px solid var(--hair); border-radius:var(--radius-sm); background:var(--workspace);
    color:var(--ink); font-size:var(--font-sm); cursor:grab; text-align:left;
    transition:border-color .12s ease, background .12s ease;
  }
  .fx-chip:hover{ border-color:var(--hair-strong); background:var(--paper); }
  .fx-chip:active{ cursor:grabbing; }
  .fx-chip-icon{
    width:26px; height:26px; border-radius:4px; flex-shrink:0;
    display:flex; align-items:center; justify-content:center;
    background:var(--paper); border:1px solid var(--hair);
    --fx-c:var(--ink-soft);
  }
  .fx-chip-icon .material-symbols-outlined,
  .fx-slot-icon .material-symbols-outlined{
    font-weight:300;
    font-variation-settings:'FILL' 0,'wght' 300,'GRAD' 0,'opsz' 20;
    color:var(--fx-c);
    transition:color .15s ease, filter .15s ease;
  }
  .fx-chip-icon .material-symbols-outlined{ font-size:17px; }
  .fx-chip-icon[data-family="yellow"],
  .fx-slot-icon[data-family="yellow"]{ --fx-c:#dcc050; background:color-mix(in srgb, #dcc050 16%, var(--paper)); border-color:color-mix(in srgb, #dcc050 42%, var(--hair)); }
  .fx-chip-icon[data-family="mod"],
  .fx-slot-icon[data-family="mod"]{ --fx-c:#7ec8e8; background:color-mix(in srgb, #7ec8e8 16%, var(--paper)); border-color:color-mix(in srgb, #7ec8e8 42%, var(--hair)); }
  .fx-chip-icon[data-family="delay"],
  .fx-slot-icon[data-family="delay"]{ --fx-c:#6dc86d; background:color-mix(in srgb, #6dc86d 16%, var(--paper)); border-color:color-mix(in srgb, #6dc86d 42%, var(--hair)); }
  .fx-chip-icon[data-family="reverb"],
  .fx-slot-icon[data-family="reverb"]{ --fx-c:#e8944a; background:color-mix(in srgb, #e8944a 16%, var(--paper)); border-color:color-mix(in srgb, #e8944a 42%, var(--hair)); }
  .fx-chip-icon[data-family="purple"],
  .fx-slot-icon[data-family="purple"]{ --fx-c:#b080d0; background:color-mix(in srgb, #b080d0 16%, var(--paper)); border-color:color-mix(in srgb, #b080d0 42%, var(--hair)); }
  .fx-chip-icon[data-family="amp"],
  .fx-slot-icon[data-family="amp"]{ --fx-c:#e06060; background:color-mix(in srgb, #e06060 16%, var(--paper)); border-color:color-mix(in srgb, #e06060 42%, var(--hair)); }
  .fx-chip-icon[data-family="aqua"],
  .fx-slot-icon[data-family="aqua"]{ --fx-c:#58d0d0; background:color-mix(in srgb, #58d0d0 16%, var(--paper)); border-color:color-mix(in srgb, #58d0d0 42%, var(--hair)); }
  .fx-chip-icon[data-family="looper"],
  .fx-slot-icon[data-family="looper"]{ --fx-c:#f0f0f0; background:color-mix(in srgb, #f0f0f0 12%, var(--paper)); border-color:color-mix(in srgb, #f0f0f0 35%, var(--hair)); }
  .fx-path-panel{ display:flex; flex-direction:column; gap:8px; flex-shrink:0; width:100%; }
  .fx-path-head{
    display:flex; align-items:baseline; justify-content:space-between; gap:12px; flex-wrap:wrap;
  }
  .fx-path-header{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.08em; text-transform:uppercase; color:var(--ink-soft); flex-shrink:0;
  }
  .fx-path{
    display:flex; align-items:flex-start; gap:12px; flex-wrap:nowrap;
    background:var(--paper); border:1px solid var(--hair-strong); border-radius:var(--radius-sm);
    padding:14px 16px; width:100%;
  }
  .fx-io{
    display:flex; align-items:center; justify-content:center;
    width:32px; height:32px; flex-shrink:0; color:var(--ink-faint);
    margin-top:14px;
  }
  .fx-io .material-symbols-outlined{
    font-size:22px; font-weight:300;
    font-variation-settings:'FILL' 0,'wght' 300,'GRAD' 0,'opsz' 24;
  }
  .fx-slots-stack{
    display:flex; flex-direction:column; align-items:stretch; gap:6px;
    flex:1; min-width:0;
  }
  .fx-slots{
    display:grid; grid-template-columns:repeat(8, minmax(0, 1fr));
    align-items:start; gap:12px; width:100%; position:relative;
  }
  #fxSlotsRow1::before,
  #fxSlotsRow2.is-open:not(:empty)::before{
    content:''; position:absolute; z-index:0; pointer-events:none;
    left:calc(100% / 16); right:calc(100% / 16);
    top:30px; height:1px; background:var(--hair-strong);
  }
  #fxSlotsRow2{ display:none; }
  #fxSlotsRow2.is-open{ display:grid; }
  .fx-row-add,
  .fx-row-remove{
    align-self:center; width:100%; max-width:320px; min-height:28px;
    border:1px dashed color-mix(in srgb, var(--ink-faint) 35%, transparent);
    border-radius:var(--radius-sm); background:transparent;
    color:color-mix(in srgb, var(--ink-faint) 55%, transparent);
    font-size:22px; line-height:1; cursor:pointer; padding:2px 0;
    transition:border-color .12s, color .12s, background .12s;
  }
  .fx-row-add:hover,
  .fx-row-remove:hover{
    border-color:var(--ink-faint); color:var(--ink-soft);
    background:color-mix(in srgb, var(--ink-faint) 6%, transparent);
  }
  .fx-row-remove{ font-size:var(--font-sm); letter-spacing:.04em; }
  .fx-slot{
    width:100%; max-width:72px; justify-self:center; position:relative; z-index:1;
    border-radius:var(--radius-sm);
    border:2px dashed var(--hair-strong); background:var(--workspace);
    display:flex; flex-direction:column; align-items:center; justify-content:flex-start;
    gap:4px; padding:6px 4px 4px;
    cursor:pointer; transition:border-color .12s, background .12s;
    min-height:60px;
  }
  .fx-slot:not(.filled){
    aspect-ratio:1; max-height:60px; max-width:60px; justify-content:center; padding:0;
  }
  .fx-slot:hover{ border-color:var(--ink-faint); }
  .fx-slot.filled{ border-style:solid; border-color:var(--hair-strong); background:var(--paper); }
  .fx-slot.selected{ outline:2px solid var(--amber); outline-offset:2px; }
  .fx-slot.drag-over{ border-color:var(--amber); background:var(--amber-soft); }
  .fx-slot-icon{
    width:52px; height:52px; flex-shrink:0; border-radius:4px;
    display:flex; align-items:center; justify-content:center;
    background:var(--workspace); border:1px solid var(--hair);
    --fx-c:var(--ink-soft);
  }
  .fx-slot-icon .material-symbols-outlined{
    font-size:clamp(18px, 2.2vw, 26px);
    font-variation-settings:'FILL' 0,'wght' 300,'GRAD' 0,'opsz' 24;
  }
  .fx-slot.selected .fx-slot-icon{
    border-color:var(--amber);
    box-shadow:0 0 0 1px color-mix(in srgb, var(--amber) 35%, transparent);
  }
  .fx-slot.selected .fx-slot-icon .material-symbols-outlined{ filter:brightness(1.12); }
  .fx-slot-empty{ font-size:clamp(16px, 2vw, 22px); color:var(--ink-faint); line-height:1; }
  .fx-slot-name{
    font-family:'IBM Plex Mono',monospace; font-size:9px; letter-spacing:.04em;
    color:var(--ink-soft); text-align:center; line-height:1.2;
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .fx-slot.selected .fx-slot-name{ color:var(--ink); }
  .fx-slot.bypassed .fx-slot-name{ opacity:.45; }
  .fx-slot-bypass{
    position:absolute; top:-6px; right:-6px; width:14px; height:14px;
    border-radius:50%; background:var(--amber); border:2px solid var(--paper);
    cursor:pointer;
  }
  .fx-slot.filled .fx-slot-bypass{ top:2px; right:calc(50% - 30px); }
  .fx-slot.bypassed .fx-slot-icon{ opacity:.45; }
  .fx-slot.bypassed .fx-slot-bypass{ background:var(--hair-strong); }
  .fx-face-panel{
    flex:1; display:flex; flex-direction:column; gap:4px; min-height:0;
    padding:0;
  }
  .fx-face-head{
    display:flex; align-items:center; gap:10px; flex-wrap:wrap;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.06em; text-transform:uppercase; color:var(--ink-soft);
  }
  .fx-face-head select{
    font-family:inherit; font-size:var(--font-sm); letter-spacing:0; text-transform:none;
    min-width:120px;
  }
  .fx-face-armed{
    margin-left:auto; font-size:var(--font-xs); letter-spacing:0; text-transform:none;
    color:var(--amber); padding:3px 8px; border-radius:var(--radius-sm);
    background:var(--amber-soft); border:1px solid color-mix(in srgb, var(--amber) 35%, transparent);
  }
  .fx-face-stage{
    flex:1; display:flex; align-items:center; justify-content:center;
    min-height:0; overflow:hidden; background:transparent; padding:0;
  }
  .fx-face-scale-wrap{ flex-shrink:0; position:relative; }
  .fx-face-scale{ position:relative; transform-origin:top left; }
  .fx-face-canvas{
    position:relative; background:var(--paper);
    border-radius:2px;
  }
  .fx-face-canvas .widget{ cursor:pointer; pointer-events:auto; }
  .fx-face-canvas .widget.fx-bindable:hover{ outline:2px solid var(--ink-faint); outline-offset:1px; }
  .fx-face-canvas .widget.fx-bound{ outline:2px solid color-mix(in srgb, var(--amber) 55%, transparent); outline-offset:1px; }
  .fx-face-canvas .widget.fx-armed-target{ outline:2px solid var(--amber); outline-offset:2px; animation:fx-arm-pulse 1.2s ease-in-out infinite; }
  @keyframes fx-arm-pulse{ 0%,100%{ outline-color:var(--amber); } 50%{ outline-color:color-mix(in srgb, var(--amber) 40%, transparent); } }
  .fx-face-note{ font-size:var(--font-xs); color:var(--ink-faint); line-height:1.45; }
  .fx-bind-section{ margin-bottom:12px; }
  .fx-bind-section:last-child{ margin-bottom:0; }
  .fx-bind-label{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.06em; text-transform:uppercase; color:var(--ink-soft);
    margin-bottom:6px;
  }
  .fx-bind-params{ display:flex; flex-wrap:wrap; gap:6px; }
  .fx-bind-chip{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    padding:4px 9px; border-radius:var(--radius-sm);
    border:1px solid var(--hair-strong); background:var(--workspace); color:var(--ink-soft);
    cursor:pointer; transition:border-color .12s, background .12s, color .12s;
  }
  .fx-bind-chip:hover{ border-color:var(--ink-faint); color:var(--ink); }
  .fx-bind-chip.bound{ border-color:color-mix(in srgb, var(--amber) 45%, var(--hair)); color:var(--ink); }
  .fx-bind-chip.armed{ border-color:var(--amber); background:var(--amber-soft); color:var(--ink); }
  /* Deliberately NOT another .fx-bind-chip — that's exactly the bug: a whole-block bind that
     matters as much as any single param chip was sitting styled identically to all 18 of them,
     lost in the wrap. Full-width, bordered, its own row above the chip grid instead. */
  .fx-bind-chart-row{ margin-bottom:10px; }
  .fx-bind-chart-btn{
    width:100%; display:flex; align-items:center; gap:8px; justify-content:center;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm); font-weight:600;
    padding:9px 12px; border-radius:var(--radius-sm);
    border:1.5px dashed var(--amber); background:var(--amber-soft); color:var(--ink);
    cursor:pointer; transition:border-style .12s, background .12s;
  }
  .fx-bind-chart-btn:hover{ background:color-mix(in srgb, var(--amber-soft) 70%, var(--amber)); }
  .fx-bind-chart-btn.armed{ border-style:solid; background:var(--amber); color:var(--paper); }
  .fx-bind-chart-btn .material-symbols-outlined{ font-size:17px; }
  .fx-bind-row{
    display:flex; align-items:center; gap:8px; padding:6px 8px; margin-bottom:4px;
    border-radius:var(--radius-sm); border:1px solid var(--hair);
    background:var(--workspace); font-size:var(--font-sm); color:var(--ink-soft);
    transition:border-color .12s, background .12s;
  }
  .fx-bind-row.pickable{ cursor:pointer; }
  .fx-bind-row.pickable:hover{ border-color:var(--amber); background:var(--amber-soft); }
  .fx-param-label.armable{ cursor:pointer; }
  .fx-param-label.armable:hover{ color:var(--ink); }
  .fx-param-label.armed{ color:var(--amber); }
  .fx-bind-row .name{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--ink); }
  .fx-bind-row .target{ font-family:'IBM Plex Mono',monospace; font-size:10px; color:var(--ink-faint); }
  .fx-bind-row .target.on{ color:var(--amber); }
  .fx-bind-clear{
    font-size:10px; color:var(--ink-faint); cursor:pointer; padding:2px 4px;
    border:none; background:transparent;
  }
  .fx-bind-clear:hover{ color:var(--rubric); }
  /* Direct mode's own invert toggle — one checkbox, flips whether the destination rises or
     falls with the source (an xy pad axis, or a Cam Tracker channel). */
  .fx-bind-invert-toggle{
    display:inline-flex; align-items:center; gap:3px; flex-shrink:0;
    font-family:'IBM Plex Mono',monospace; font-size:10px; color:var(--ink-faint); cursor:pointer;
  }
  .fx-bind-invert-toggle input{ width:auto; margin:0; cursor:pointer; }
  /* xy pad's row — two independent bindings, each in its OWN box, stacked vertically (never
     crammed side by side into one shared line) — the whole point being that X and Y read as two
     clearly separate things even before either one grows into a multi-row Macro table. Overrides
     .fx-bind-row's own flex layout, which assumes a single name+target line every other kind
     here uses. */
  .fx-bind-row.xypad-row{ display:block; }
  .fx-bind-row-name{ color:var(--ink); margin-bottom:8px; }
  .fx-bind-xy-axes{ display:flex; flex-direction:column; gap:10px; }
  .fx-bind-axis-box{
    display:flex; align-items:center; gap:6px; padding:6px 8px; border-radius:var(--radius-sm);
    border:1px solid var(--hair-strong); background:var(--paper);
  }
  .fx-bind-axis-chip{
    font-family:'IBM Plex Mono',monospace; font-size:10px;
    padding:3px 7px; border-radius:var(--radius-sm);
    border:1px solid var(--hair-strong); background:var(--workspace); color:var(--ink-faint);
    cursor:default; transition:border-color .12s, background .12s, color .12s;
    max-width:120px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .fx-bind-axis-chip.on{ border-color:color-mix(in srgb, var(--amber) 45%, var(--hair)); color:var(--ink); }
  .fx-bind-axis-chip.pickable{ cursor:pointer; }
  .fx-bind-axis-chip.pickable:hover{ border-color:var(--amber); background:var(--amber-soft); color:var(--ink); }
  .fx-bind-axis-chip.small{ padding:3px 6px; max-width:none; flex-shrink:0; }
  /* Macro mode's per-axis table — replaces the single Direct chip for that axis once it has any
     weighted destinations (xyAxisBindRowHtml decides which of the two to render). A grid, not a
     flex row, so the header labels (PARAM TARGET / DEPTH % / INVERT) line up with every data row
     regardless of how long a param id happens to be — the earlier single-line chip+slider
     version had nothing to align against and read as a wall of controls. */
  .fx-bind-macro-axis{
    width:100%; padding:8px 9px; border-radius:var(--radius-sm);
    border:1px solid var(--hair-strong); background:var(--workspace);
  }
  .fx-bind-macro-axis-head{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs); font-weight:600;
    letter-spacing:.06em; text-transform:uppercase; color:var(--ink);
    margin-bottom:8px;
  }
  .fx-bind-macro-table-head, .fx-bind-macro-dest{
    display:grid; grid-template-columns:1fr 40px 46px 18px; align-items:center; gap:8px;
  }
  .fx-bind-macro-table-head{
    font-family:'IBM Plex Mono',monospace; font-size:9px; letter-spacing:.05em;
    text-transform:uppercase; color:var(--ink-faint); padding-bottom:4px;
    border-bottom:1px solid var(--hair);
  }
  .fx-bind-macro-table-head span:nth-child(2){ text-align:center; }
  .fx-bind-macro-table-head span:nth-child(3){ text-align:center; }
  .fx-bind-macro-dest{ padding:5px 0; border-bottom:1px solid var(--hair); }
  .fx-bind-macro-dest:last-of-type{ border-bottom:none; }
  .fx-bind-macro-dest-label{
    min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--ink);
  }
  .fx-bind-macro-depth{
    width:40px; text-align:center; font-family:'IBM Plex Mono',monospace; font-size:10.5px;
    padding:2px 0; border:1px solid var(--hair-strong); border-radius:var(--radius-sm);
    background:var(--paper); color:var(--ink);
  }
  .fx-bind-macro-invert{ justify-self:center; width:auto; margin:0; cursor:pointer; }
  .fx-bind-macro-add{
    width:100%; margin-top:8px; padding:6px 0; border-radius:var(--radius-sm);
    border:1px dashed var(--hair-strong); background:transparent; color:var(--ink-soft);
    font-family:'IBM Plex Mono',monospace; font-size:10.5px; cursor:default;
    transition:border-color .12s, background .12s, color .12s;
  }
  .fx-bind-macro-add.pickable{ cursor:pointer; }
  .fx-bind-macro-add.pickable:hover{ border-style:solid; border-color:var(--amber); background:var(--amber-soft); color:var(--ink); }
  .fx-params{
    background:var(--paper); border:1px solid var(--hair); border-radius:var(--radius-sm);
    padding:10px 12px 12px; flex-shrink:0;
  }
  .fx-params-head{
    display:flex; align-items:center; gap:10px; margin-bottom:10px;
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    letter-spacing:.06em; text-transform:uppercase;
  }
  .fx-params-head .name{ color:var(--ink); font-size:var(--font-sm); letter-spacing:0; text-transform:none; }
  .fx-params-title{
    display:inline-flex; align-items:center; gap:8px;
  }
  .fx-params-row{ display:flex; gap:18px; flex-wrap:wrap; align-items:flex-end; padding:4px 0 2px; }
  .fx-param{ display:flex; flex-direction:column; align-items:center; gap:6px; min-width:56px; cursor:pointer; border-radius:var(--radius-sm); padding:4px 6px 2px; transition:background .12s, box-shadow .12s; }
  .fx-param:hover{ background:color-mix(in srgb, var(--amber-soft) 35%, transparent); }
  .fx-param.armed{
    background:var(--amber-soft);
    box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--amber) 45%, transparent);
  }
  .fx-param.armed .fx-param-knob{ border-color:var(--amber); }
  .fx-param-label{
    font-size:10px; letter-spacing:.06em; text-transform:uppercase; color:var(--ink-soft);
    order:3;
  }
  .fx-param-knob{
    width:52px; height:52px; border-radius:50%; padding:0; flex-shrink:0;
    border:2px solid var(--hair-strong); background:var(--paper);
    box-shadow:inset 0 2px 6px rgba(0,0,0,.12), 0 1px 0 rgba(255,255,255,.06);
    cursor:pointer; position:relative; display:flex; align-items:center; justify-content:center;
    transition:border-color .12s ease, box-shadow .12s ease;
  }
  .fx-param-knob:hover{ border-color:var(--ink-faint); }
  .fx-param-knob:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }
  .fx-param-dial{
    width:100%; height:100%; display:flex; align-items:flex-start; justify-content:center;
    padding-top:7px; transform:rotate(-135deg); pointer-events:none;
  }
  .fx-param-needle{
    width:2px; height:15px; border-radius:1px; background:var(--amber);
    box-shadow:0 0 4px color-mix(in srgb, var(--amber) 45%, transparent);
  }
  /* Small variant — LFO Rate/Depth only, not the FX rack or any other synth knob. A knob's
     own height (not its label/value text) is what drives a whole card/strip's height, so
     this is the single biggest lever for compacting the LFO stack specifically. */
  .fx-param-knob.small{ width:34px; height:34px; }
  .fx-param-knob.small .fx-param-dial{ padding-top:4px; }
  .fx-param-knob.small .fx-param-needle{ height:10px; }
  .fx-param.small{ gap:3px; }
  /* Same size as `.fx-param-label` at minimum (was equal at 10px already, but the dimmer
     --ink-faint color next to the label's --ink-soft made the value read as smaller/harder
     to read even at identical font-size) — bumped a notch larger and matched the label's
     color/contrast so it doesn't read as secondary to the label underneath it. */
  .fx-param-val{
    font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--ink-soft); order:2;
    min-height:14px; white-space:nowrap;
  }
  .fx-params-empty, .fx-params-note{
    color:var(--ink-faint); font-size:var(--font-sm); line-height:1.5; padding:4px 0;
  }
  .fx-params-note{ margin-top:8px; padding-top:8px; border-top:1px solid var(--hair); font-size:var(--font-xs); }
  .fx-bypass-btn{
    font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:.06em;
    text-transform:uppercase; padding:4px 10px; border-radius:var(--radius-sm);
    border:1px solid var(--hair-strong); background:var(--workspace); color:var(--ink-soft); cursor:pointer;
  }
  .fx-bypass-btn.on{ border-color:var(--amber); color:var(--amber); background:var(--amber-soft); }

  /* —— first-run tour —— */
  .tour-overlay{
    position:fixed; inset:0; z-index:300;
    pointer-events:none;
  }
  .tour-overlay.open{ pointer-events:auto; }
  .tour-overlay[hidden]{ display:none; }
  .tour-spotlight{
    position:fixed;
    border-radius:var(--radius-lg);
    box-shadow:0 0 0 9999px rgba(0,0,0,0.74);
    pointer-events:none;
    transition:top .28s ease, left .28s ease, width .28s ease, height .28s ease;
    z-index:301;
  }
  .tour-card{
    position:fixed; z-index:302;
    width:min(320px, calc(100vw - 32px));
    background:var(--paper); color:var(--ink);
    border:1px solid var(--hair-strong); border-radius:var(--radius-lg);
    box-shadow:var(--shadow-md);
    padding:16px 16px 14px;
    pointer-events:auto;
    transition:top .28s ease, left .28s ease, opacity .2s ease;
  }
  .tour-step{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-xs);
    color:var(--ink-faint); letter-spacing:.08em; text-transform:uppercase;
    margin-bottom:8px;
  }
  .tour-title{
    font-family:'IBM Plex Sans',sans-serif; font-weight:600; font-size:var(--font);
    margin-bottom:8px;
  }
  .tour-desc{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    color:var(--ink-soft); line-height:1.55; margin:0;
  }
  .tour-actions{
    display:flex; align-items:center; justify-content:flex-end; gap:8px;
    margin-top:16px;
  }
  .tour-actions-left{ margin-right:auto; }
  .tour-btn-link{
    font-family:'IBM Plex Mono',monospace; font-size:var(--font-sm);
    padding:6px 10px; border:none; border-radius:var(--radius);
    background:transparent; color:var(--ink-faint); cursor:pointer;
  }
  .tour-btn-link:hover{ color:var(--ink); }

