/* =============================================================================
   SENOVA DS — "Ink & Ivory, Studio Cut"  (senova-ds.css)
   The Resend-grade component layer, built on senova-ui.css's tokens. Load AFTER
   senova-ui.css. Self-contained: adds the extended token set (design spec §1),
   the animated-icon motion (§2), and every component (§3). Both themes.
   ========================================================================== */

/* ----------------------------------------------------------------------- *
 * §1 — EXTENDED TOKENS
 * ----------------------------------------------------------------------- */
:root {
  --sn-ink-3:#75736D;                 /* corrected: 4.6:1 on ivory (was #8A8984) */
  --sn-hairline-strong:#D6D3C8;
  --sn-bg-deep:#141413;               /* cinematic floor (light-page media) */
  /* §68: derived, not a leftover ember rgba — this was still glowing orange behind empty states. */
  --sn-accent-glow:color-mix(in srgb, var(--sn-accent) 14%, transparent);

  --sn-ring:0 0 0 3px color-mix(in srgb, var(--sn-accent) 30%, transparent);
  --sn-ring-neutral:0 0 0 3px rgba(20,19,19,.10);

  --sn-hover:rgba(20,19,19,.04);
  --sn-active:rgba(20,19,19,.08);
  --sn-selected:color-mix(in srgb, var(--sn-accent) 8%, transparent);

  --sn-sidebar-bg:#F5F4EE;
  --sn-topbar-bg:rgba(250,249,245,.85);
  --sn-row-hover:rgba(20,19,19,.03);
  --sn-chip-bg:#EFEDE4;
  --sn-kbd-bg:#FFFFFF;
  --sn-kbd-border:#D6D3C8;
  --sn-code-bg:#F5F4EE;
  --sn-scrim:rgba(20,19,19,.44);
  --sn-tooltip-bg:#232220;
  --sn-tooltip-ink:#F5F4EF;

  --sn-success-soft:#E3EDE5; --sn-warn-soft:#F4EAD2; --sn-error-soft:#F6E1DB; --sn-info-soft:#EAE8DF;

  --sn-elev-0:none;
  --sn-elev-1:0 1px 2px rgba(20,19,19,.05);
  --sn-elev-2:0 1px 2px rgba(20,19,19,.04),0 8px 24px rgba(20,19,19,.07);
  --sn-elev-3:0 2px 6px rgba(20,19,19,.06),0 24px 64px rgba(20,19,19,.14);

  --sn-t-hover:120ms; --sn-t-press:80ms; --sn-t-micro:180ms;
  --sn-t-panel:320ms; --sn-t-toast-in:260ms; --sn-t-toast-out:180ms;
  --sn-ease:cubic-bezier(.2,.6,.2,1);
  --sn-ease-out:cubic-bezier(.16,1,.3,1);
  --sn-ease-in:cubic-bezier(.4,0,1,1);
  --sn-ease-spring:cubic-bezier(.34,1.4,.44,1);
}
[data-theme="studio"], [data-theme="dark"] {
  /* §63: neutral, matching senova-ui.css. `hairline-strong` is the line you use when 8% is genuinely
     not enough (a focused input, a selected row) — still low-contrast, still not a border-for-its-own-sake. */
  --sn-ink-3:#7C7C86;
  --sn-hairline-strong:rgba(255, 255, 255, .14);
  --sn-bg-deep:#070709;
  --sn-accent-glow:color-mix(in srgb, var(--sn-accent) 16%, transparent);

/* §68: derived from the one accent — these were live ember rgba values, so a blue app still had an
   ORANGE focus ring, orange selection and orange ambient glows. */
  --sn-ring:0 0 0 3px color-mix(in srgb, var(--sn-accent) 32%, transparent);
  --sn-ring-neutral:0 0 0 3px rgba(245,244,239,.10);

  --sn-hover:rgba(255,255,255,.05);
  --sn-active:rgba(255,255,255,.09);
  --sn-selected:color-mix(in srgb, var(--sn-accent) 12%, transparent);

  --sn-sidebar-bg:#161514;
  --sn-topbar-bg:rgba(18,17,16,.80);
  --sn-row-hover:rgba(245,244,239,.035);
  --sn-chip-bg:#2A2826;
  --sn-kbd-bg:#232220; --sn-kbd-border:#3A3833;
  --sn-code-bg:#1A1917;
  --sn-scrim:rgba(0,0,0,.60);
  --sn-tooltip-bg:#F5F4EF; --sn-tooltip-ink:#141413;

  --sn-success-soft:#1E2A21; --sn-warn-soft:#2E2617; --sn-error-soft:#33201B; --sn-info-soft:#242320;

  --sn-elev-1:0 1px 2px rgba(0,0,0,.30);
  --sn-elev-2:0 1px 2px rgba(0,0,0,.25),0 8px 24px rgba(0,0,0,.35);
  --sn-elev-3:0 2px 6px rgba(0,0,0,.35),0 24px 64px rgba(0,0,0,.55);
}

/* ----------------------------------------------------------------------- *
 * §2 — ANIMATED ICONS
 * The moving part is .sn-ic__m (transform) or .sn-ic__d (draw). Animations
 * fire on hover of an interactive host, or the icon itself. Reduced-motion off.
 * ----------------------------------------------------------------------- */
.sn-ic { width:1.25em; height:1.25em; display:inline-block; vertical-align:middle; flex:none; overflow:visible; }
.sn-ic__m, .sn-ic__m1, .sn-ic__m2, .sn-ic__m3, .sn-ic__m4, .sn-ic__spin, .sn-ic__wand {
  transition:transform var(--sn-t-micro) var(--sn-ease-spring), opacity var(--sn-t-micro) var(--sn-ease);
  transform-origin:12px 12px; transform-box:view-box;
}
.sn-ic__d, .sn-ic__d1, .sn-ic__d2, .sn-ic__d3, .sn-ic__dot {
  transition:stroke-dashoffset 300ms var(--sn-ease), opacity var(--sn-t-micro) var(--sn-ease);
}
/* draw prep — normalized pathLength=1 */
.sn-ic__d { stroke-dasharray:1; stroke-dashoffset:0; }

/* The hover scope: any interactive parent, or the icon itself. */
/* Each icon defines its own hovered transform below. */
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic,
.sn-ic:hover { }

/* helper so per-icon rules stay terse: HOST = the :is() list */
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--home .sn-ic__m, .sn-ic--home:hover .sn-ic__m { transform:translateY(-1.5px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--spark .sn-ic__m, .sn-ic--spark:hover .sn-ic__m { transform:scale(1.35); opacity:1; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--spark .sn-ic__spin, .sn-ic--spark:hover .sn-ic__spin { transform:rotate(9deg); }
.sn-ic--spark .sn-ic__m { transform:scale(.4); opacity:.4; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--image .sn-ic__d, .sn-ic--image:hover .sn-ic__d { animation:sn-redraw 480ms var(--sn-ease); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--video .sn-ic__m, .sn-ic--video:hover .sn-ic__m { transform:translateX(1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--library .sn-ic__m, .sn-ic--library:hover .sn-ic__m { transform:translate(.8px,.8px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--folder .sn-ic__m, .sn-ic--folder:hover .sn-ic__m { opacity:1; transform:translateY(-1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--settings .sn-ic__m, .sn-ic--settings:hover .sn-ic__m { transform:rotate(30deg); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--billing .sn-ic__m, .sn-ic--billing:hover .sn-ic__m { animation:sn-coin 460ms var(--sn-ease); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--apikey .sn-ic__m, .sn-ic--apikey:hover .sn-ic__m { transform:rotate(12deg); transform-origin:7px 12px; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--connect .sn-ic__m1, .sn-ic--connect:hover .sn-ic__m1 { transform:translateX(1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--connect .sn-ic__m2, .sn-ic--connect:hover .sn-ic__m2 { transform:translateX(-1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--connect .sn-ic__m, .sn-ic--connect:hover .sn-ic__m { opacity:1; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--search .sn-ic__d, .sn-ic--search:hover .sn-ic__d { animation:sn-redraw 420ms var(--sn-ease); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--filter .sn-ic__m1, .sn-ic--filter:hover .sn-ic__m1 { transform:translateX(3px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--filter .sn-ic__m2, .sn-ic--filter:hover .sn-ic__m2 { transform:translateX(-3px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--filter .sn-ic__m3, .sn-ic--filter:hover .sn-ic__m3 { transform:translateX(4px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--plus .sn-ic__m, .sn-ic--plus:hover .sn-ic__m { transform:rotate(90deg); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--download .sn-ic__m, .sn-ic--download:hover .sn-ic__m { transform:translateY(2px); opacity:.7; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--upload .sn-ic__m, .sn-ic--upload:hover .sn-ic__m { transform:translateY(-2px); opacity:.7; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--copy .sn-ic__m, .sn-ic--copy:hover .sn-ic__m { transform:translate(-1.2px,-1.2px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--trash .sn-ic__m, .sn-ic--trash:hover .sn-ic__m { transform:translateY(-1px) rotate(7deg); transform-origin:19px 6.4px; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--more .sn-ic__d1, .sn-ic--more:hover .sn-ic__d1 { transform:scale(1.35); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--more .sn-ic__d2, .sn-ic--more:hover .sn-ic__d2 { transform:scale(1.35); transition-delay:60ms; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--more .sn-ic__d3, .sn-ic--more:hover .sn-ic__d3 { transform:scale(1.35); transition-delay:120ms; }
.sn-ic--more .sn-ic__d1,.sn-ic--more .sn-ic__d2,.sn-ic--more .sn-ic__d3 { transform-box:view-box; transition:transform 150ms var(--sn-ease-spring); }
.sn-ic--more .sn-ic__d1{transform-origin:5.5px 12px}.sn-ic--more .sn-ic__d2{transform-origin:12px 12px}.sn-ic--more .sn-ic__d3{transform-origin:18.5px 12px}
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--chevronDown .sn-ic__m, .sn-ic--chevronDown:hover .sn-ic__m { transform:translateY(1.5px); }
.sn-ic--chevronDown.is-open .sn-ic__m { transform:rotate(180deg); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--chevronRight .sn-ic__m, .sn-ic--chevronRight:hover .sn-ic__m { transform:translateX(1.5px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--close .sn-ic__m, .sn-ic--close:hover .sn-ic__m { transform:rotate(90deg) scale(.92); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--check .sn-ic__d, .sn-ic--check:hover .sn-ic__d { animation:sn-redraw 340ms var(--sn-ease); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--play .sn-ic__m, .sn-ic--play:hover .sn-ic__m { transform:translateX(1px) scale(1.05); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--lens .sn-ic__m, .sn-ic--lens:hover .sn-ic__m { transform:rotate(15deg); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--wand .sn-ic__m, .sn-ic--wand:hover .sn-ic__m { opacity:1; transform:scale(1.15); transform-origin:18px 5.5px; transition-delay:80ms; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--wand .sn-ic__wand, .sn-ic--wand:hover .sn-ic__wand { transform:translate(.5px,-.5px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--user .sn-ic__m, .sn-ic--user:hover .sn-ic__m { transform:translateY(-.75px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--help .sn-ic__d, .sn-ic--help:hover .sn-ic__d { animation:sn-redraw 380ms var(--sn-ease); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--external .sn-ic__m, .sn-ic--external:hover .sn-ic__m { transform:translate(1px,-1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--sun .sn-ic__m, .sn-ic--sun:hover .sn-ic__m { transform:rotate(22.5deg); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--moon .sn-ic__m, .sn-ic--moon:hover .sn-ic__m { transform:rotate(-10deg); transform-origin:12px 12px; }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--grid .sn-ic__m1, .sn-ic--grid:hover .sn-ic__m1 { transform:translate(-1px,-1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--grid .sn-ic__m4, .sn-ic--grid:hover .sn-ic__m4 { transform:translate(1px,1px); }
.sn-ic--grid rect{transform-box:view-box;transition:transform 180ms var(--sn-ease-spring)}
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--scene .sn-ic__m1, .sn-ic--scene:hover .sn-ic__m1 { transform:translateY(-1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--scene .sn-ic__m2, .sn-ic--scene:hover .sn-ic__m2 { transform:translateY(1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--voice .sn-ic__m, .sn-ic--voice:hover .sn-ic__m { transform:translateY(-1px); }
:is(.snh,a,button,label,summary,[role=menuitem],.sn-nav-item,.sn-row):hover .sn-ic--collapse .sn-ic__m, .sn-ic--collapse:hover .sn-ic__m { transform:translateX(-1.5px); }

@keyframes sn-redraw { 0%{stroke-dashoffset:1} 100%{stroke-dashoffset:0} }
@keyframes sn-coin { 0%{transform:scaleX(1)} 45%{transform:scaleX(.14)} 100%{transform:scaleX(1)} }
@keyframes sn-spark-pulse { 0%,100%{transform:scale(.4);opacity:.35} 50%{transform:scale(1.3);opacity:1} }
.sn-ic--spark.is-generating .sn-ic__m { animation:sn-spark-pulse 1.2s var(--sn-ease) infinite; }

@media (prefers-reduced-motion:reduce) {
  .sn-ic__m,.sn-ic__m1,.sn-ic__m2,.sn-ic__m3,.sn-ic__m4,.sn-ic__spin,.sn-ic__wand,.sn-ic__d,.sn-ic--grid rect,.sn-ic--more circle { transition:none !important; animation:none !important; transform:none !important; }
  .sn-ic--spark .sn-ic__m { opacity:1; transform:none; }
  .sn-ic--connect .sn-ic__m,.sn-ic--folder .sn-ic__m,.sn-ic--wand .sn-ic__m { opacity:1; }
}

/* ----------------------------------------------------------------------- *
 * §3.1 — BUTTONS (refines senova-ui.css .sn-btn to the Resend density)
 * ----------------------------------------------------------------------- */
/* §93 — `appearance:none` IS LOAD-BEARING, NOT TIDINESS. Without it Chrome's native button widget
   wins over the author `background`, so `.sn-btn-primary` rendered as a grey UA button on any page
   that did not also load senova-ui.css. Measured: identical markup came out rgb(240,240,240) with
   console.css + this file, and rgb(20,20,19) the moment `appearance:none` was added. shadcn gets
   this from Tailwind's preflight; a vanilla port has to say it. */
.sn-btn {
  appearance:none; -webkit-appearance:none;
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  height:32px; padding:0 12px; border:1px solid transparent; border-radius:var(--sn-r-input);
  font:500 .875rem/1 var(--sn-sans); letter-spacing:0; text-decoration:none; cursor:pointer;
  transition:background var(--sn-t-hover) var(--sn-ease), border-color var(--sn-t-hover) var(--sn-ease), color var(--sn-t-hover) var(--sn-ease), transform var(--sn-t-press) var(--sn-ease), box-shadow var(--sn-t-hover) var(--sn-ease);
  white-space:nowrap; -webkit-user-select:none; user-select:none;
}
.sn-btn:active { transform:scale(.985); }
.sn-btn:focus-visible { outline:none; box-shadow:var(--sn-ring-neutral); }
.sn-btn-sm { height:28px; padding:0 10px; font-size:.8125rem; border-radius:var(--sn-r-input); }
.sn-btn-lg { height:40px; padding:0 16px; font-size:.9375rem; }
.sn-btn-primary { background:var(--sn-ink); color:var(--sn-bg); border-color:var(--sn-ink); }
.sn-btn-primary:hover { opacity:.9; background:var(--sn-ink); }
/* §68 — THE HOME'S HERO CTA WEARS THE MARK. In the dark studio `.sn-btn-primary` inverted to a cream
   slab, which is why "Create your own" showed no brand colour at all — Rob looked for the gradient primary
   and found a beige button. It is the single hero action on the Producer home, so it is exactly the place
   the logo gradient is earned. Every OTHER .sn-btn-primary in the studio keeps the inverted treatment. */
[data-theme="studio"] .sn-btn-primary { background:#F5F4EF; color:#141413; border-color:#F5F4EF; }
[data-theme="studio"] .sn-btn-primary.pd-lib-cta,
[data-theme="studio"] .pd-root .sn-btn-primary { background:var(--sn-accent); color:#fff; border-color:transparent; }
[data-theme="studio"] .sn-btn-primary.pd-lib-cta:hover,
[data-theme="studio"] .pd-root .sn-btn-primary:hover { background:var(--sn-accent); filter:brightness(1.1); }
/* §68: this sheet loads AFTER senova-ui.css, so it was overriding the gradient back to a flat fill —
   which is exactly the "one source of truth" failure §65 fixed for the HUE, repeating for the SURFACE.
   Both accent buttons now carry the mark's gradient; the solid stays for text, tints and hairlines. */
.sn-btn-accent { background:var(--sn-accent); color:#FFF8F5; border-color:transparent; }
.sn-btn-accent:hover { background:color-mix(in srgb, var(--sn-accent) 90%, transparent); border-color:transparent; }
.sn-btn-accent:focus-visible { box-shadow:var(--sn-ring); }
.sn-btn-secondary { background:var(--sn-surface); color:var(--sn-ink); border-color:var(--sn-hairline-strong); box-shadow:var(--sn-elev-1); }
.sn-btn-secondary:hover { background:var(--sn-bg-raised); border-color:var(--sn-hairline-strong); }
.sn-btn-ghost { background:transparent; color:var(--sn-ink-2); border-color:transparent; box-shadow:none; }
.sn-btn-ghost:hover { background:var(--sn-hover); color:var(--sn-ink); }
.sn-btn-danger { background:transparent; color:var(--sn-error); border-color:transparent; }
.sn-btn-danger:hover { background:var(--sn-error-soft); }
.sn-btn[disabled], .sn-btn:disabled { opacity:.5; pointer-events:none; }
.sn-btn .sn-ic { width:1em; height:1em; }
.sn-btn-icon { width:32px; height:32px; padding:0; }
.sn-btn-icon.sn-btn-sm { width:28px; height:28px; }

/* kbd chip inside a button */
.sn-btn kbd, .sn-kbd-in {
  display:inline-flex; align-items:center; margin-left:4px; padding:2px 5px; border-radius:5px;
  font:500 .6875rem/1 var(--sn-mono); letter-spacing:.02em;
}
.sn-btn-primary kbd, .sn-btn-accent kbd { background:rgba(255,255,255,.16); color:inherit; opacity:.85; }
[data-theme="studio"] .sn-btn-primary kbd { background:rgba(20,19,19,.12); }
.sn-btn-secondary kbd, .sn-btn-ghost kbd, .sn-btn-danger kbd { background:var(--sn-kbd-bg); border:1px solid var(--sn-kbd-border); color:var(--sn-ink-2); }

/* standalone kbd */
.sn-kbd {
  display:inline-flex; align-items:center; padding:2px 6px; border-radius:5px;
  background:var(--sn-kbd-bg); border:1px solid var(--sn-kbd-border); border-bottom-width:2px;
  font:500 .6875rem/1 var(--sn-mono); color:var(--sn-ink-2);
}

/* ----------------------------------------------------------------------- *
 * §3.2 — INPUTS
 * ----------------------------------------------------------------------- */
.sn-field { display:flex; flex-direction:column; gap:6px; }
.sn-label { font:500 .8125rem/1 var(--sn-sans); color:var(--sn-ink-2); }
.sn-input, .sn-textarea, .sn-select {
  width:100%; height:32px; padding:0 12px; border-radius:var(--sn-r-input);
  background:var(--sn-surface); border:1px solid var(--sn-hairline-strong);
  font:.875rem/1 var(--sn-sans); color:var(--sn-ink);
  transition:border-color var(--sn-t-hover) var(--sn-ease), box-shadow var(--sn-t-hover) var(--sn-ease);
}
.sn-input::placeholder, .sn-textarea::placeholder { color:var(--sn-ink-3); }
.sn-input:hover, .sn-textarea:hover, .sn-select:hover { border-color:#C7C4B8; }
[data-theme="studio"] .sn-input:hover, [data-theme="studio"] .sn-textarea:hover { border-color:#4A4741; }
.sn-input:focus, .sn-textarea:focus, .sn-select:focus { outline:none; border-color:var(--sn-accent); box-shadow:var(--sn-ring); }
.sn-input-lg { height:40px; }
.sn-textarea { height:auto; min-height:96px; padding:10px 12px; line-height:1.55; resize:vertical; }
.sn-field.is-error .sn-input, .sn-field.is-error .sn-textarea { border-color:var(--sn-error); box-shadow:0 0 0 3px rgba(179,64,46,.18); }
.sn-field-msg { font:.8125rem/1.4 var(--sn-sans); color:var(--sn-error); display:flex; gap:6px; align-items:center; }
.sn-input-icon { position:relative; display:block; }
/* The leading icon sits INSIDE the pill, left. The icon is authored as <span class="sn-ic-slot"> and
   hydrated to <span class="sn-ic-slot"><svg class="sn-ic">…</svg></span>, so the svg is a GRANDCHILD —
   `> .sn-ic` never matched and the icon fell into normal flow OUTSIDE the field. Position the SLOT
   (and keep .sn-ic for any direct-svg usage) so it's enclosed on the input's left edge, everywhere. */
.sn-input-icon > .sn-ic, .sn-input-icon > .sn-ic-slot { position:absolute; left:11px; top:50%; transform:translateY(-50%);
  width:16px; height:16px; color:var(--sn-ink-3); pointer-events:none; z-index:1; display:block; }
.sn-input-icon > .sn-ic-slot > svg, .sn-input-icon > .sn-ic-slot > .sn-ic { width:16px; height:16px; display:block; }
.sn-input-icon .sn-input { padding-left:34px; }
.sn-input-affix { display:flex; align-items:stretch; border:1px solid var(--sn-hairline-strong); border-radius:var(--sn-r-input); background:var(--sn-surface); overflow:hidden; transition:border-color var(--sn-t-hover),box-shadow var(--sn-t-hover); }
.sn-input-affix:focus-within { border-color:var(--sn-accent); box-shadow:var(--sn-ring); }
.sn-input-affix .sn-affix { display:flex; align-items:center; padding:0 10px; background:var(--sn-bg-raised); color:var(--sn-ink-2); font:.8125rem var(--sn-mono); }
.sn-input-affix .sn-affix + .sn-input { border-left:1px solid var(--sn-hairline); }
.sn-input-affix .sn-input { border:none; box-shadow:none; border-radius:0; }
.sn-input-affix .sn-input:focus { box-shadow:none; }

/* ----------------------------------------------------------------------- *
 * §3.3 — MENUS / DROPDOWNS
 * ----------------------------------------------------------------------- */
.sn-menu {
  min-width:200px; background:var(--sn-surface); border:1px solid var(--sn-hairline);
  border-radius:var(--sn-r-card); box-shadow:var(--sn-elev-2); padding:4px;
  animation:sn-menu-in 160ms var(--sn-ease-out);
}
@keyframes sn-menu-in { from{opacity:0; transform:translateY(-4px) scale(.98)} to{opacity:1; transform:none} }
.sn-menu-item {
  display:flex; align-items:center; gap:8px; height:32px; padding:0 8px; border-radius:var(--sn-r-input);
  font:.875rem/1 var(--sn-sans); color:var(--sn-ink-2); cursor:pointer; text-decoration:none; border:none; background:none; width:100%; text-align:left;
  transition:background var(--sn-t-hover) var(--sn-ease), color var(--sn-t-hover) var(--sn-ease);
}
.sn-menu-item:hover, .sn-menu-item:focus-visible { background:var(--sn-hover); color:var(--sn-ink); outline:none; }
.sn-menu-item .sn-ic { width:16px; height:16px; color:var(--sn-ink-3); }
.sn-menu-item.is-selected { color:var(--sn-ink); }
.sn-menu-item .sn-menu-check { margin-left:auto; width:16px; height:16px; color:var(--sn-accent); opacity:0; }
.sn-menu-item.is-selected .sn-menu-check { opacity:1; }
.sn-menu-item.is-danger { color:var(--sn-error); }
.sn-menu-item.is-danger:hover { background:var(--sn-error-soft); }
.sn-menu-sep { height:1px; background:var(--sn-hairline); margin:4px -4px; }

/* ----------------------------------------------------------------------- *
 * §3.4 — DATA TABLE
 * ----------------------------------------------------------------------- */
.sn-table-wrap { border:1px solid var(--sn-hairline); border-radius:var(--sn-r-card); background:var(--sn-surface); overflow:clip; }
.sn-table-toolbar { display:flex; align-items:center; gap:8px; height:52px; padding:0 16px; border-bottom:1px solid var(--sn-hairline); }
.sn-table-toolbar .sn-input-icon { width:240px; }
.sn-table-toolbar .sn-input { background:var(--sn-bg); height:30px; }
.sn-table-toolbar .sn-spacer { flex:1; }
.sn-table { width:100%; border-collapse:collapse; }
.sn-table thead th {
  height:40px; padding:0 16px; text-align:left; background:var(--sn-bg-raised);
  border-bottom:1px solid var(--sn-hairline);
  font:500 .75rem/40px var(--sn-sans); letter-spacing:.04em; text-transform:uppercase; color:var(--sn-ink-3); white-space:nowrap;
}
.sn-table thead th.is-sortable { cursor:pointer; user-select:none; }
.sn-table thead th .sn-sort { display:inline-block; margin-left:6px; opacity:0; transition:opacity var(--sn-t-hover),transform var(--sn-t-micro); }
.sn-table thead th:hover .sn-sort { opacity:.4; }
.sn-table thead th.is-sorted { color:var(--sn-ink-2); }
.sn-table thead th.is-sorted .sn-sort { opacity:1; }
.sn-table tbody td { height:48px; padding:0 16px; border-bottom:1px solid var(--sn-hairline); font:.875rem/1.4 var(--sn-sans); color:var(--sn-ink); vertical-align:middle; }
.sn-table tbody tr:last-child td { border-bottom:none; }
.sn-table tbody tr { transition:background var(--sn-t-hover) var(--sn-ease); }
.sn-table tbody tr:hover { background:var(--sn-row-hover); }
.sn-table td.sn-td-muted { color:var(--sn-ink-2); }
.sn-table td.sn-td-mono { font:.8125rem var(--sn-mono); color:var(--sn-ink-2); }
.sn-table .sn-rowmenu { opacity:0; transition:opacity var(--sn-t-hover); }
.sn-table tbody tr:hover .sn-rowmenu { opacity:1; }
.sn-status { display:inline-flex; align-items:center; gap:7px; font:.8125rem var(--sn-sans); color:var(--sn-ink-2); }
.sn-status::before { content:""; width:6px; height:6px; border-radius:50%; background:var(--sn-ink-3); }
.sn-status.ok::before { background:var(--sn-success); }
.sn-status.warn::before { background:var(--sn-warn); }
.sn-status.err::before { background:var(--sn-error); }
.sn-table-foot { display:flex; align-items:center; justify-content:space-between; height:48px; padding:0 16px; border-top:1px solid var(--sn-hairline); }
.sn-table-foot .sn-pageinfo { font:.8125rem var(--sn-sans); color:var(--sn-ink-2); }
.sn-table-foot .sn-pager { display:flex; gap:6px; }

/* ----------------------------------------------------------------------- *
 * §3.5 — MODAL
 * ----------------------------------------------------------------------- */
.sn-scrim { position:fixed; inset:0; z-index:1200; background:var(--sn-scrim); backdrop-filter:blur(2px); -webkit-backdrop-filter:blur(2px); display:grid; place-items:center; padding:16px; animation:sn-fade 200ms var(--sn-ease); }
@keyframes sn-fade { from{opacity:0} to{opacity:1} }
.sn-modal { width:min(480px,calc(100vw - 32px)); background:var(--sn-surface); border:1px solid var(--sn-hairline); border-radius:var(--sn-r-panel); box-shadow:var(--sn-elev-3); animation:sn-modal-in 240ms var(--sn-ease-out); }
@keyframes sn-modal-in { from{opacity:0; transform:translateY(8px) scale(.96)} to{opacity:1; transform:none} }
.sn-modal-head { position:relative; padding:20px 24px 0; }
.sn-modal-title { font:600 1.125rem/1.3 var(--sn-serif); color:var(--sn-ink); margin:0; }
.sn-modal-x { position:absolute; top:16px; right:16px; }
.sn-modal-body { padding:16px 24px; font:.875rem/1.55 var(--sn-sans); color:var(--sn-ink-2); }
.sn-modal-foot { display:flex; justify-content:flex-end; gap:8px; padding:16px 24px 20px; border-top:1px solid var(--sn-hairline); margin-top:8px; }

/* ----------------------------------------------------------------------- *
 * §3.6 — VERTICAL STEPPER
 * ----------------------------------------------------------------------- */
.sn-stepper { list-style:none; margin:0; padding:0; }
.sn-stepper li { position:relative; display:grid; grid-template-columns:28px 1fr; gap:16px; padding-bottom:32px; }
.sn-stepper li:last-child { padding-bottom:0; }
.sn-stepper li::before { content:""; position:absolute; left:13.5px; top:32px; bottom:0; width:1px; background:var(--sn-hairline); }
.sn-stepper li:last-child::before { display:none; }
.sn-stepper li.is-complete::before { background:var(--sn-ink-2); }
.sn-step__node { width:28px; height:28px; border-radius:50%; display:grid; place-items:center; background:var(--sn-surface); border:1px solid var(--sn-hairline-strong); font:600 .8125rem var(--sn-sans); color:var(--sn-ink-3); z-index:1; }
.sn-stepper li.is-active .sn-step__node { border-color:var(--sn-accent); color:var(--sn-accent); box-shadow:0 0 0 4px var(--sn-accent-soft); }
.sn-stepper li.is-complete .sn-step__node { background:var(--sn-ink); border-color:var(--sn-ink); color:var(--sn-bg); }
[data-theme="studio"] .sn-stepper li.is-complete .sn-step__node { background:#F5F4EF; border-color:#F5F4EF; color:#141413; }
.sn-step__node .sn-ic { width:15px; height:15px; }
.sn-step__body h4 { font:600 .9375rem/1.3 var(--sn-sans); color:var(--sn-ink); margin:4px 0 0; }
.sn-stepper li:not(.is-active):not(.is-complete) .sn-step__body h4 { color:var(--sn-ink-3); }
.sn-step__body p { font:.875rem/1.55 var(--sn-sans); color:var(--sn-ink-2); margin:6px 0 0; }
.sn-step__extra { margin-top:12px; }

/* ----------------------------------------------------------------------- *
 * §3.7 — CARDS
 * ----------------------------------------------------------------------- */
.sn-card { background:var(--sn-surface); border:1px solid var(--sn-hairline); border-radius:var(--sn-r-card); padding:20px; box-shadow:var(--sn-elev-1); }
.sn-card-hover { transition:box-shadow var(--sn-t-micro) var(--sn-ease), transform var(--sn-t-micro) var(--sn-ease), border-color var(--sn-t-micro) var(--sn-ease); cursor:pointer; }
.sn-card-hover:hover { box-shadow:var(--sn-elev-2); transform:translateY(-1px); border-color:var(--sn-hairline-strong); }
.sn-media-card { position:relative; border-radius:var(--sn-r-media); overflow:clip; padding:0; background:var(--sn-bg-deep); border:1px solid var(--sn-hairline); box-shadow:var(--sn-elev-1); }
.sn-media-card > img, .sn-media-card > video { display:block; width:100%; height:100%; object-fit:cover; transition:transform var(--sn-t-panel) var(--sn-ease); }
.sn-media-card:hover > img, .sn-media-card:hover > video { transform:scale(1.012); }
.sn-media-card .sn-media-overlay { position:absolute; inset:auto 0 0 0; padding:28px 12px 12px; background:linear-gradient(transparent,rgba(12,11,10,.78)); color:#F5F4EF; opacity:0; transform:translateY(6px); transition:opacity var(--sn-t-micro),transform var(--sn-t-micro); }
.sn-media-card:hover .sn-media-overlay { opacity:1; transform:none; }
.sn-media-card .sn-media-prompt { font:.8125rem/1.4 var(--sn-sans); display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.sn-media-card .sn-media-meta { margin-top:6px; font:.6875rem var(--sn-mono); color:rgba(245,244,239,.65); display:flex; gap:8px; }
.sn-media-actions { position:absolute; top:8px; right:8px; display:flex; gap:6px; opacity:0; transition:opacity var(--sn-t-micro); }
.sn-media-card:hover .sn-media-actions { opacity:1; }
.sn-media-actions button { width:28px; height:28px; display:grid; place-items:center; border:none; border-radius:8px; background:rgba(20,19,19,.55); backdrop-filter:blur(6px); color:#F5F4EF; cursor:pointer; }
.sn-media-actions button:hover { background:rgba(20,19,19,.75); }

/* ----------------------------------------------------------------------- *
 * §3.8 — CODE BLOCK
 * ----------------------------------------------------------------------- */
.sn-code { background:var(--sn-code-bg); border:1px solid var(--sn-hairline); border-radius:var(--sn-r-card); overflow:clip; }
.sn-code-tabs { position:relative; display:flex; align-items:center; height:40px; padding:0 8px; border-bottom:1px solid var(--sn-hairline); }
.sn-code-tab { height:40px; padding:0 12px; border:none; background:none; font:500 .8125rem var(--sn-sans); color:var(--sn-ink-3); cursor:pointer; position:relative; }
.sn-code-tab.is-active { color:var(--sn-ink); }
.sn-code-tab.is-active::after { content:""; position:absolute; left:8px; right:8px; bottom:-1px; height:1.5px; background:var(--sn-accent); border-radius:2px; }
.sn-code-copy { margin-left:auto; }
.sn-code pre { margin:0; padding:16px 20px; font:.8125rem/1.65 var(--sn-mono); color:var(--sn-ink); tab-size:2; overflow-x:auto; }
.sn-code .tok-key { color:var(--sn-accent-ink); }
.sn-code .tok-str { color:var(--sn-success); }
.sn-code .tok-com { color:var(--sn-ink-3); font-style:italic; }
.sn-code .tok-num { color:var(--sn-warn); }
.sn-code .tok-pun { color:var(--sn-ink-2); }

/* ----------------------------------------------------------------------- *
 * §3.9 — TOAST
 * ----------------------------------------------------------------------- */
.sn-toasts { position:fixed; right:24px; bottom:24px; z-index:1400; display:flex; flex-direction:column-reverse; gap:8px; pointer-events:none; }
.sn-toast { pointer-events:auto; min-width:280px; max-width:380px; background:var(--sn-surface); border:1px solid var(--sn-hairline); border-radius:var(--sn-r-card); padding:12px 14px; box-shadow:var(--sn-elev-3); display:flex; gap:10px; align-items:flex-start; animation:sn-toast-in var(--sn-t-toast-in) var(--sn-ease-out); }
@keyframes sn-toast-in { from{opacity:0; transform:translateY(12px)} to{opacity:1; transform:none} }
.sn-toast.is-out { animation:sn-toast-out var(--sn-t-toast-out) var(--sn-ease-in) forwards; }
@keyframes sn-toast-out { to{opacity:0; transform:translateX(16px)} }
.sn-toast .sn-ic { width:18px; height:18px; margin-top:1px; }
.sn-toast.ok .sn-ic { color:var(--sn-success); }
.sn-toast.err .sn-ic { color:var(--sn-error); }
.sn-toast-title { font:500 .875rem/1.3 var(--sn-sans); color:var(--sn-ink); }
.sn-toast-msg { font:.8125rem/1.4 var(--sn-sans); color:var(--sn-ink-2); margin-top:2px; }

/* ----------------------------------------------------------------------- *
 * §3.10 — SIDEBAR NAV ITEM
 * ----------------------------------------------------------------------- */
.sn-nav-item {
  display:flex; align-items:center; gap:8px; height:32px; padding:0 10px; border-radius:calc(0.625rem - 2px);
  font:500 .875rem/1 var(--sn-sans); color:var(--sn-ink-2); text-decoration:none; border:1px solid transparent;
  transition:background var(--sn-t-hover) var(--sn-ease), color var(--sn-t-hover) var(--sn-ease);
}
/* 🔴 §103 — THE `hidden` ATTRIBUTE MUST WIN OVER THE display:flex ABOVE.
   A class selector beats the UA's `[hidden] { display: none }` at equal specificity, so EVERY nav row
   a gate hides with `el.hidden = true` kept rendering. Found on live staging as the Math row: the route
   correctly refused #math and bounced to #generate, but the sidebar link was still there — a link that
   dangles to somewhere else, which is worse than either state on its own.
   ⚠️ IT WAS NEVER MATH-SPECIFIC. applyAdCenterGate and applyBizSuiteGate hide their rows the same way,
   so the Ad Center lockdown and the Business Suite surface gates had the same leak: the wall held (the
   route refused) while the door stayed visible.
   console.css already carries this exact fix for `.cx-navlink` with the same reasoning written beside
   it — the studio's own nav simply never got it. No !important needed: (0,2,0) beats (0,1,0). */
.sn-nav-item[hidden] { display: none; }
.sn-nav-item .sn-ic { width:16px; height:16px; color:var(--sn-ink-3); }
.sn-nav-item:hover { background:var(--sn-hover); color:var(--sn-ink); }
.sn-nav-item:hover .sn-ic { color:var(--sn-ink-2); }
/* §71 — shadcn's SIDEBAR active state is `bg-sidebar-accent text-sidebar-accent-foreground`: a MUTED
   raised surface, not a coloured item. Ours also tinted the ICON with the brand, which would have been a
   THIRD place the accent appears — Rob's rule is "the active state and the single primary", and the editor
   already spends both on the view switcher and the primary button. A neutral sidebar keeps that true. */
.sn-nav-item.is-active { background:var(--sn-bg-raised); border-color:transparent; box-shadow:none; color:var(--sn-ink); }
.sn-nav-item.is-active .sn-ic { color:var(--sn-ink); }
.sn-nav-label { font:600 .6875rem/1 var(--sn-sans); text-transform:uppercase; letter-spacing:.06em; color:var(--sn-ink-3); padding:16px 10px 6px; }

/* ----------------------------------------------------------------------- *
 * §3.11 — TOP BAR + workspace switcher
 * ----------------------------------------------------------------------- */
.sn-topbar { display:flex; align-items:center; gap:12px; height:56px; padding:0 20px; background:var(--sn-topbar-bg); backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px); border-bottom:1px solid var(--sn-hairline); position:sticky; top:0; z-index:100; }
.sn-ws { display:inline-flex; align-items:center; gap:8px; height:32px; padding:0 8px 0 6px; border-radius:var(--sn-r-input); border:none; background:none; cursor:pointer; color:var(--sn-ink); font:500 .875rem var(--sn-sans); transition:background var(--sn-t-hover); }
.sn-ws:hover { background:var(--sn-hover); }
/* §65: the workspace avatar wears the BRAND gradient, not a hard-coded ember pair. */
.sn-ws-avatar { width:20px; height:20px; border-radius:6px; display:grid; place-items:center; background:var(--sn-accent); color:#fff; font:600 .6875rem var(--sn-sans); }
.sn-topbar-right { margin-left:auto; display:flex; align-items:center; gap:12px; }
.sn-toplink { display:inline-flex; align-items:center; gap:5px; font:500 .8125rem var(--sn-sans); color:var(--sn-ink-2); text-decoration:none; transition:color var(--sn-t-hover); }
.sn-toplink:hover { color:var(--sn-ink); }
.sn-toplink .sn-ic { width:14px; height:14px; }
.sn-topdiv { width:1px; height:20px; background:var(--sn-hairline); }

/* ----------------------------------------------------------------------- *
 * §3.12 — BADGES, SEGMENTED, TOOLTIP
 * ----------------------------------------------------------------------- */
.sn-badge { display:inline-flex; align-items:center; gap:5px; height:20px; padding:0 8px; border-radius:999px; font:500 .6875rem/1 var(--sn-sans); letter-spacing:.02em; background:var(--sn-chip-bg); color:var(--sn-ink-2); }
.sn-badge.ok { background:var(--sn-success-soft); color:var(--sn-success); }
.sn-badge.warn { background:var(--sn-warn-soft); color:var(--sn-warn); }
.sn-badge.err { background:var(--sn-error-soft); color:var(--sn-error); }
.sn-badge.accent { background:var(--sn-accent-soft); color:var(--sn-accent-ink); }
.sn-badge .dot { width:5px; height:5px; border-radius:50%; background:currentColor; }
.sn-seg { display:inline-flex; align-items:center; gap:2px; padding:2px; background:var(--sn-bg-raised); border:1px solid var(--sn-hairline); border-radius:var(--sn-r-input); }
.sn-seg button { height:26px; padding:0 12px; border:none; background:none; border-radius:8px; font:500 .8125rem var(--sn-sans); color:var(--sn-ink-2); cursor:pointer; transition:color var(--sn-t-hover); }
.sn-seg button.is-active { background:var(--sn-surface); box-shadow:var(--sn-elev-1); color:var(--sn-ink); }
[data-sn-tooltip] { position:relative; }
[data-sn-tooltip]::after { content:attr(data-sn-tooltip); position:absolute; bottom:calc(100% + 6px); left:50%; transform:translateX(-50%) translateY(2px); background:var(--sn-tooltip-bg); color:var(--sn-tooltip-ink); padding:5px 9px; border-radius:6px; font:500 .75rem var(--sn-sans); white-space:nowrap; box-shadow:var(--sn-elev-2); opacity:0; pointer-events:none; transition:opacity 140ms var(--sn-ease),transform 140ms var(--sn-ease); z-index:1500; }
[data-sn-tooltip]:hover::after { opacity:1; transform:translateX(-50%); transition-delay:.35s; }

/* ----------------------------------------------------------------------- *
 * §3.13 — EMPTY STATE
 * ----------------------------------------------------------------------- */
.sn-empty { display:flex; flex-direction:column; align-items:center; text-align:center; gap:0; max-width:360px; margin:0 auto; padding:48px 0; }
.sn-empty-ic { width:48px; height:48px; border-radius:50%; background:var(--sn-bg-raised); display:grid; place-items:center; color:var(--sn-ink-3); margin-bottom:16px; }
.sn-empty-ic .sn-ic { width:24px; height:24px; }
.sn-empty h4 { font:600 1.125rem/1.3 var(--sn-serif); color:var(--sn-ink); margin:0; }
.sn-empty p { font:.875rem/1.55 var(--sn-sans); color:var(--sn-ink-2); margin:8px 0 16px; }
.sn-empty.glow .sn-empty-ic { box-shadow:0 0 48px var(--sn-accent-glow); }

/* utility */
.sn-hstack { display:flex; align-items:center; gap:var(--sn-3,12px); }
.sn-vstack { display:flex; flex-direction:column; gap:var(--sn-3,12px); }

/* =========================================================================
 * §92 — FILLING THE GAPS IN THE CANONICAL LAYER, BEFORE ADOPTING IT EVERYWHERE.
 * =========================================================================
 *
 * Rob: redesign the site's components on canonical shadcn/ui and kill the ad-hoc per-page controls.
 * The inventory that opened this pass, counted mechanically out of public/css:
 *
 *     button 150 distinct classes | card 239 | badge 186 | table 169 | input 73 | menu 70 | dialog 66
 *     across 20 stylesheets. workspace.css alone defines 459 of them.
 *
 * THE FIRST FINDING IS THAT THE SYSTEM ROB IS ASKING FOR ALREADY EXISTS, AND IT IS THIS FILE.
 * senova-ds.css is already shadcn-shaped: 126 primitives with a focus ring, disabled states, modal,
 * menu, toast, table, select, segmented control and topbar. The problem was never that we lacked a
 * component system. It is that 8 of 64 pages load it. 47 pages load neither this nor senova-ui.css,
 * and those 47 include settings, keys, credits, usage and billing-setup -- the whole Account area --
 * plus docs and developers. Every one of them therefore hand-rolls its own buttons and inputs, which
 * is precisely where the 150 button classes came from.
 *
 * AND THERE ARE TWO FOUNDATIONS, WHICH HAD TO BE MEASURED RATHER THAN ASSUMED. senova-ui.css and this
 * file both define .sn-btn, .sn-input, .sn-card-hover, .sn-table and 9 more. On the 8 pages that load
 * both, this file loads second and wins: a .sn-btn there computes to 32px tall with an 8px radius, NOT
 * the 999px pill senova-ui.css asks for. So senova-ui.css governs the 8 pages that load only it, this
 * file governs the 8 that load both, and a funder clicking from the landing page into the studio
 * crosses between two different button systems. Reconciling those two is the NEXT chunk; this one does
 * not touch either definition, because a reconciliation done in the same breath as an extension is
 * unreviewable.
 *
 * SO THIS BLOCK IS PURELY ADDITIVE: the shadcn primitives this layer does not have yet. Every name
 * below was checked against the 126 already defined here -- switch, checkbox, tooltip and aria-invalid
 * appear ZERO times in this file, which is why they are the gaps worth filling before adoption starts.
 * Nothing existing is redefined, so no page that loads this file can change appearance from this
 * commit alone. That is the property the test asserts.
 * ---------------------------------------------------------------------- */

/* -- SWITCH (shadcn Switch) ------------------------------------------------------------------------
   A real <input type="checkbox"> stays the control, so the keyboard, the label and the form all keep
   working; `appearance: none` lets that same element BE the visual. A div with a click handler would
   have been faster to write and would not be operable without a mouse. */
.sn-switch { appearance:none; -webkit-appearance:none; flex:none; width:36px; height:20px; border-radius:999px;
  background:var(--sn-hairline-strong, var(--sn-hairline)); border:1px solid transparent; cursor:pointer;
  position:relative; transition:background var(--sn-micro, 120ms) var(--sn-ease, ease); }
.sn-switch::after { content:""; position:absolute; top:1px; left:1px; width:16px; height:16px; border-radius:50%;
  background:var(--sn-surface); box-shadow:0 1px 2px rgba(0,0,0,.25);
  transition:transform var(--sn-micro, 120ms) var(--sn-ease, ease); }
.sn-switch:checked { background:var(--sn-accent); }
.sn-switch:checked::after { transform:translateX(16px); }

/* -- CHECKBOX (shadcn Checkbox) -------------------------------------------------------------------- */
.sn-checkbox { appearance:none; -webkit-appearance:none; flex:none; width:16px; height:16px; border-radius:4px;
  border:1px solid var(--sn-ink-3); background:var(--sn-surface); cursor:pointer; display:grid; place-items:center; }
.sn-checkbox:checked { background:var(--sn-accent); border-color:var(--sn-accent); }
.sn-checkbox:checked::after { content:""; width:9px; height:5px; border-left:2px solid #fff; border-bottom:2px solid #fff;
  transform:rotate(-45deg) translate(1px,-1px); }

/* Both get the ring this file already uses, and both halves of disabled -- `pointer-events:none`
   without the opacity is a control that looks live and is not, which is worse than either alone. */
.sn-switch:focus-visible, .sn-checkbox:focus-visible { outline:none; box-shadow:var(--sn-ring); }
.sn-switch:disabled, .sn-checkbox:disabled { opacity:.5; pointer-events:none; }

/* -- INVALID STATE (shadcn's aria-invalid styling) -------------------------------------------------
   `.sn-field.is-error` already exists here and styles the field from a CLASS on its wrapper. That
   works only where markup opts in; `aria-invalid` is what a form sets when it actually fails, and it
   is what a screen reader reads. Styling it means the visual and the announced state cannot disagree. */
.sn-input[aria-invalid="true"], .sn-textarea[aria-invalid="true"], .sn-select[aria-invalid="true"] { border-color:var(--sn-error); }
.sn-input[aria-invalid="true"]:focus-visible, .sn-textarea[aria-invalid="true"]:focus-visible,
.sn-select[aria-invalid="true"]:focus-visible { box-shadow:0 0 0 3px color-mix(in srgb, var(--sn-error) 25%, transparent); }

/* -- TOOLTIP (shadcn Tooltip) ----------------------------------------------------------------------
   CSS-only, driven by hover/focus on the trigger, so it needs no JS and works on keyboard focus too.
   `pointer-events:none` on the bubble stops it eating the hover that summoned it. */
.sn-tip { position:relative; display:inline-flex; }
.sn-tip__b { position:absolute; bottom:calc(100% + 6px); left:50%; transform:translateX(-50%) translateY(2px);
  z-index:60; pointer-events:none; opacity:0; white-space:nowrap;
  padding:5px 9px; border-radius:6px; background:var(--sn-ink); color:var(--sn-bg);
  font:500 .75rem/1.35 var(--sn-sans); box-shadow:var(--sn-elev-2, 0 4px 12px rgba(0,0,0,.18));
  transition:opacity var(--sn-micro, 120ms) var(--sn-ease, ease), transform var(--sn-micro, 120ms) var(--sn-ease, ease); }
.sn-tip:hover .sn-tip__b, .sn-tip:focus-within .sn-tip__b { opacity:1; transform:translateX(-50%) translateY(0); }
@media (prefers-reduced-motion: reduce) { .sn-tip__b { transition:none; } }

/* -- THE FOCUS SAFETY NET --------------------------------------------------------------------------
   COUNTED ACROSS public/css: 126 rules kill the focus outline (`outline: none`) and only 75
   `:focus-visible` rules give a ring back. workspace.css kills 28 and restores 2; builder.css and
   landing.css kill 7 between them and restore none. On a large part of this product, tabbing shows
   nothing -- an accessibility failure, and the most visible way our controls diverge from shadcn,
   whose every primitive rings.
   `:where()` contributes ZERO specificity, so this styles only elements NOTHING else has an opinion
   about. It cannot fight a page that already rings, and it deliberately cannot fight those 126
   `outline:none` rules either (`.foo:focus` outranks it) -- those die as each area adopts these
   primitives, which is the actual work. This is for the long tail, and it is keyboard-only: a clicked
   button never rings. */
:where(button, [role="button"], a[href], input, select, textarea, summary, [tabindex]:not([tabindex="-1"])):focus-visible {
  outline:2px solid var(--sn-ink-3); outline-offset:2px;
}

/* =========================================================================
 * §93 — THE CANONICAL LAYER HAS TO STAND ON ITS OWN.
 * =========================================================================
 *
 * FOUND BY CONVERTING SETTINGS, AND IT WOULD HAVE MADE THE PAGE LOOK WORSE, NOT BETTER.
 *
 * This file USES 51 design tokens and DEFINES 32 of them. The other 19 -- including `--sn-ink`,
 * `--sn-surface`, `--sn-hairline`, `--sn-accent`, `--sn-sans` and `--sn-r-input` -- have always come
 * from senova-ui.css. That is invisible on the 8 pages that load both files, and fatal anywhere else:
 * Settings loads console.css + this file and NO senova-ui.css, so every one of those 19 resolved to
 * nothing. Measured in an iframe against the deployed sheets, `.sn-input` there came out with a 0px
 * radius and no font-family -- browser defaults wearing our class names.
 *
 * So the reason this pass has been "load senova-ds.css on more pages" was never going to work as
 * stated: the layer was not adoptable on its own. It is now.
 *
 * ⚠️ THE VALUES ARE COPIED FROM senova-ui.css EXACTLY, light and dark, and that is the whole safety
 * argument. On a page loading both, this block sits later in the cascade and therefore wins -- with
 * byte-identical values, so nothing can move. On a page loading only this file, it is the difference
 * between a design system and a set of class names.
 *
 * ⚠️ AND IT GOES AT THE TOP OF THE FILE'S CASCADE ORDER FOR TOKENS, NOT THE BOTTOM: a page that wants
 * to re-theme (the studio's `[data-theme]`, a future brand skin) still overrides these by loading after
 * or by specificity, exactly as before. Nothing here is `!important` and nothing is scoped harder than
 * `:root`.
 * ---------------------------------------------------------------------- */
:root {
  --sn-sans: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --sn-serif: "Source Serif 4", Georgia, "Times New Roman", serif;
  --sn-mono: "Roboto Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --sn-bg: #FAF9F5;
  --sn-bg-raised: #F0EEE6;
  --sn-surface: #FFFFFF;
  --sn-ink: #141413;
  --sn-ink-2: #5E5D59;
  --sn-hairline: #E5E3DA;
  --sn-accent: #4438B4;
  --sn-accent-ink: #372C93;
  --sn-accent-soft: #EAE6F9;
  --sn-success: #4C7C59;
  --sn-warn: #B9862F;
  --sn-error: #B3402E;
  --sn-3: 12px;
  --sn-micro: 180ms;
  --sn-r-input: 10px;
  --sn-r-media: 14px;
  --sn-r-panel: 18px;
  --sn-r-card: 14px;
}
[data-theme="studio"], [data-theme="dark"] {
  --sn-bg: #0B0B0D;
  --sn-bg-raised: #0F0F12;
  --sn-surface: #141417;
  --sn-ink: #F2F2F4;
  --sn-ink-2: #A8A8B0;
  --sn-hairline: rgba(255, 255, 255, .08);
  --sn-accent: #6455D6;
  --sn-accent-ink: #A79BF5;
  --sn-accent-soft: #1B1733;
  --sn-success: #6FA07D;
  --sn-error: #DB6B54;
}

/* §93 — THE APPEARANCE RESET, SPLIT BY ELEMENT, BECAUSE `select` IS NOT LIKE THE OTHERS.
   `appearance:none` is what stops the native widget beating the author background (see the note on
   .sn-btn). On a <select> it ALSO removes the dropdown arrow, and this file supplies none — so applying
   it to all three would have traded a background bug for a select with no affordance at all. Text fields
   get the reset; the select gets the reset AND a chevron drawn back in, inline so it needs no asset. */
.sn-input, .sn-textarea { appearance:none; -webkit-appearance:none; }
.sn-select {
  appearance:none; -webkit-appearance:none;
  padding-right:30px;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%235E5D59' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 10px center;
}

/* =========================================================================
   §96 — BILLING, LOUD — ON THE SURFACE THAT ACTUALLY RENDERS.
   =========================================================================

   §95 shipped this treatment into billing.css scoped to `.sn-billing`, and it was completely INERT.
   Two reasons, both of which I should have caught by looking at the live page instead of the file:

     1. `.sn-billing` is the wrapper in public/billing.html — a STANDALONE page. The Billing anybody
        opens is the in-app view rendered by studio-live.js into `#sl-bill`, whose hero is `.bill-hero`.
     2. billing.css is not even loaded by the studio, so no selector in it could ever have applied.

   I asserted the 36 selectors were scoped and never asserted the scope matched a RENDERED element.
   That is "only running proves it" in its CSS form: matching the stylesheet text is not matching a
   live node.

   So the block lives HERE — senova-ds.css is the one sheet BOTH surfaces load — and the in-app class
   names are styled alongside the standalone ones. Still every rule under `.sn-billing`, which the
   billing view now puts on its own wrapper, so the blast radius is still exactly one view.

   ⚠️ NO FIGURE, COLUMN OR CONTROL BEHAVIOUR IS TOUCHED. Colour, type, spacing, elevation, states.
   ------------------------------------------------------------------------ */

/* ── 1. ELEVATION — the single most visible change ──────────────────────────────────────────────
   Measured: page #0B0B0D is L* 3.07 and the card surface #141417 is L* 6.42 — a step of 3.35, about
   two JND. That is Rob's "they barely separate", and contrast RATIOS hide it entirely (1.05:1).
   #202027 is L* 12.52 — a step of 9.46, 2.8× the current one. */
/* ⚠️ `.app` PREFIX IS SPECIFICITY, NOT DECORATION. studio-system.css carries
   `.app .sn-card { border-radius: 18px }` at (0,2,1), which outranks a bare `.sn-billing .sn-card`
   at (0,2,0) — measured on the rendered page, where the hero came back 18px instead of 14px. Adding
   `.app` takes this to (0,3,0) and wins on class count. Real specificity beats !important here
   because the studio may still re-theme these surfaces later. */
.app .sn-billing .sn-card,
.app .sn-billing .bill-hero,
.sn-billing .sn-card,
.sn-billing .bill-hero {
  background: #202027;
  border: 1px solid rgba(255, 255, 255, .10);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .40),
              0 10px 28px -10px rgba(0, 0, 0, .65),
              inset 0 1px 0 rgba(255, 255, 255, .055);
  padding: 28px;
}
/* The hero keeps its accent bloom, now over the lifted surface rather than over the page colour. */
.sn-billing .bill-hero {
  background: radial-gradient(120% 140% at 0% 0%, rgba(100, 85, 214, .16), transparent 55%), #202027;
  margin-bottom: 22px;
}
:root:not([data-theme="studio"]):not([data-theme="dark"]) .sn-billing .sn-card,
:root:not([data-theme="studio"]):not([data-theme="dark"]) .sn-billing .bill-hero {
  background: #FFFFFF;
  border-color: rgba(20, 19, 19, .09);
  box-shadow: 0 1px 2px rgba(20, 19, 19, .06),
              0 10px 28px -12px rgba(20, 19, 19, .16),
              inset 0 1px 0 rgba(255, 255, 255, .9);
}

/* ── 2. TYPE — a ramp you can see ───────────────────────────────────────────────────────────────
   The h1 comes from viewHead and is a SIBLING of #sl-bill, which is why the scope class sits on the
   view wrapper rather than on the billing host. */
/* The heading is `.view-head h1`, styled by an inline sheet with the `font` SHORTHAND — which sets
   weight as well as size, at equal specificity and later in document order, so it won the weight and
   my h1 came back 600. Naming `.view-head` takes this to (0,2,1) and wins outright; the !important
   on font-size is no longer needed and is gone. */
.sn-billing h1,
.sn-billing .view-head h1 {
  font-size: clamp(32px, 4.2vw, 44px);
  font-weight: 700;
  letter-spacing: -.028em;
  line-height: 1.04;
}
.sn-billing .sn-card__title,
.sn-billing .bill-k { font-size: 17px; font-weight: 650; letter-spacing: -.014em; }
.sn-billing .sn-card__note,
.sn-billing .bill-meter-cap { font-size: 13px; line-height: 1.6; }
/* Genuinely muted, and still clear of the 4.5:1 floor on the new #202027 surface. The tokens these
   replace (--sn-ink-3) are BORDER/placeholder colours and fail AA for prose — the rule billing.css
   states in its own header, applied here. */
.sn-billing .sn-lede,
.sn-billing .bill-bal-lbl,
.sn-billing .bill-meter-cap,
.sn-billing .sn-card__note { color: #9A9AA6; }

/* ── 3. SPACING ─────────────────────────────────────────────────────────────────────────────────*/
.sn-billing .bill-cols { gap: 20px; }
.sn-billing .sn-card__head, .sn-billing .bill-plan-head { margin-bottom: 20px; }

/* ── 4. ACCENT WITH INTENT ──────────────────────────────────────────────────────────────────────
   THE METER IS THE RIGHT PLACE and it exists on this surface — I said it did not, having looked at
   the standalone page. It is the one element that reports a real proportion, so it gets the full
   brand ramp and enough height to read as a bar rather than a hairline. */
.sn-billing .bill-meter-track { height: 10px; background: rgba(255, 255, 255, .07); }
.sn-billing .bill-meter-track > span {
  background: linear-gradient(90deg, #0F6BA6 0%, #3D4ED0 55%, #6455D6 100%);
  box-shadow: 0 0 12px -2px rgba(100, 85, 214, .65);
}
/* The balance is the number the page exists to report. */
.sn-billing .bill-bal-num,
.sn-billing .sn-balance {
  font-size: 56px; font-weight: 600; letter-spacing: -.03em; line-height: 1;
  background: linear-gradient(120deg, #7FB4E8 0%, #8E9BF0 45%, #A78BFA 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
/* ⚠️ THE LOW-BALANCE WARNING MUST SURVIVE THE GRADIENT — clipping to text would swallow the amber
   and turn a warning into decoration. The fill is given back exactly where the state matters. */
.sn-billing .sn-balance[data-low="1"], .sn-billing .bill-bal-num[data-low="1"] {
  background: none; -webkit-text-fill-color: var(--sn-warn); color: var(--sn-warn);
}
.sn-billing .sn-pack[aria-current="true"] {
  border-color: #6455D6; background: rgba(100, 85, 214, .10);
  box-shadow: 0 0 0 1px #6455D6, 0 6px 20px -8px rgba(100, 85, 214, .55);
}
.sn-billing :where(button, a[href], input, select, [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: 2px solid var(--sn-accent); outline-offset: 2px;
}

/* ── 5. CONTROLS + TABLE ────────────────────────────────────────────────────────────────────────*/
.sn-billing .bill-quick-chip {
  height: 38px; border-radius: var(--sn-r-input);
  border: 1px solid var(--sn-hairline-strong);
  background: var(--sn-bg-raised);
  font-weight: 600;
  transition: border-color 140ms var(--sn-ease), background 140ms var(--sn-ease), transform 140ms var(--sn-ease);
}
.sn-billing .bill-quick-chip:hover {
  border-color: var(--sn-accent); background: var(--sn-accent-soft); transform: translateY(-1px);
}
.sn-billing .sn-table-wrap { border: 1px solid var(--sn-hairline); border-radius: var(--sn-r-card); overflow: hidden; }
.sn-billing .sn-table thead th {
  background: var(--sn-bg-raised);
  font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--sn-ink-3); padding: 12px 16px;
  border-bottom: 1px solid var(--sn-hairline);
}
.sn-billing .sn-table td { padding: 12px 16px; border-bottom: 1px solid var(--sn-hairline); }
.sn-billing .sn-table tbody tr { transition: background 120ms var(--sn-ease); }
.sn-billing .sn-table tbody tr:hover { background: var(--sn-row-hover); }

@media (prefers-reduced-motion: reduce) {
  .sn-billing .bill-quick-chip, .sn-billing .sn-table tbody tr { transition: none; }
  .sn-billing .bill-quick-chip:hover { transform: none; }
}

/* =========================================================================
   §100 — "ELEVATED SHADCN ON DARK": the billing treatment, promoted to a shared language.
   =========================================================================

   §95/§96 built a bold treatment for Billing and Rob could finally SEE the system land. This promotes
   the parts of it that are not about billing into one opt-in scope, so every other page group can adopt
   the same language by adding a class instead of by copying CSS. Copying it would have produced a
   seventh dialect, which is the thing this whole pass exists to delete.

   ── HOW TO ADOPT IT ────────────────────────────────────────────────────────────────────────────────
   Put `sn-elev` on the wrapper the page ACTUALLY RENDERS, then use `.sn-card`, `.sn-btn`, `.sn-input`
   and friends normally. That is the whole contract.

   ⚠️ AND THE WORD "ACTUALLY" IS DOING WORK. §95 shipped 36 correct selectors under a class nothing
   emitted and the page did not move a pixel; §96 found it only by dumping the rendered DOM. So every
   adoption of this scope is verified on the RENDERED page, and a test asserts the emitting renderer and
   the loading page for each one.

   ── THE ONE MEASUREMENT THE SURFACE VALUE COMES FROM ───────────────────────────────────────────────
   On the dark ground the page is #0B0B0D (L* 3.07) and the old card surface #141417 (L* 6.42) — a step
   of 3.35, about two JND, which is why Rob read cards as "barely separating". #202027 is L* 12.52, a
   step of 9.46: 2.8x. Contrast RATIOS hide this completely (1.05:1 at either value); L* is the metric
   that matches the eye at the dark end and is the one these values were chosen against.
   ------------------------------------------------------------------------ */

:root {
  --sn-elev-surface: #202027;
  --sn-elev-line: rgba(255, 255, 255, .10);
  /* Three layers, which is what separates "a lighter rectangle" from "a panel above a page": a contact
     shadow, a soft ambient cast, and a 1px rim of light along the top edge where a raised surface
     would catch it. */
  --sn-elev-shadow: 0 1px 2px rgba(0, 0, 0, .40), 0 10px 28px -10px rgba(0, 0, 0, .65),
                    inset 0 1px 0 rgba(255, 255, 255, .055);
  --sn-elev-r: 14px;
  --sn-elev-pad: 28px;
  /* The secondary ramp. `--sn-ink-3` is a BORDER/placeholder token and fails AA for prose (billing.css
     states that rule in its own header) — these are text colours, checked against the new surface. */
  --sn-elev-ink-2: #9A9AA6;
  --sn-elev-ink-3: #8E8E9A;
  --sn-elev-accent: #6455D6;
  --sn-elev-accent-soft: rgba(100, 85, 214, .10);
  --sn-elev-ring: #7C6BE8;
}

/* ── SURFACES ───────────────────────────────────────────────────────────────────────────────────────
   ⚠️ `.app` IS SPECIFICITY, NOT DECORATION. studio-system.css carries `.app .sn-card { border-radius:
   18px }` at (0,2,1), which outranks a bare `.sn-elev .sn-card` at (0,2,0) — measured on the rendered
   page in §96, where the hero came back 18px instead of 14px. Both spellings are listed so the scope
   wins inside the studio shell and outside it. */
.app .sn-elev .sn-card,
.sn-elev .sn-card {
  background: var(--sn-elev-surface);
  border: 1px solid var(--sn-elev-line);
  border-radius: var(--sn-elev-r);
  box-shadow: var(--sn-elev-shadow);
  padding: var(--sn-elev-pad);
}
/* Light mode gets the same idea inverted — a white card lifted off an ivory ground, not a dark card. */
:root:not([data-theme="studio"]):not([data-theme="dark"]) .sn-elev .sn-card {
  background: #FFFFFF;
  border-color: rgba(20, 19, 19, .09);
  box-shadow: 0 1px 2px rgba(20, 19, 19, .06), 0 10px 28px -12px rgba(20, 19, 19, .16),
              inset 0 1px 0 rgba(255, 255, 255, .9);
}

/* ── TYPE — a ramp you can see, not 1px differences ─────────────────────────────────────────────────
   The `.view-head h1` spelling is here for the same reason `.app` is above: the studio's own inline
   sheet styles that selector with the `font` SHORTHAND, which sets weight as well as size at equal
   specificity and later in document order. Naming it takes this to (0,2,1) and wins outright. */
.sn-elev h1,
.sn-elev .view-head h1,
.sn-elev .cx-page-head h1 {
  font-size: clamp(30px, 3.6vw, 40px);
  font-weight: 700;
  letter-spacing: -.026em;
  line-height: 1.06;
}
.sn-elev h2,
.sn-elev .sn-card__title { font-size: 17px; font-weight: 650; letter-spacing: -.014em; }
.sn-elev .sn-muted,
.sn-elev .cx-tagline,
.sn-elev .sn-lede { color: var(--sn-elev-ink-2); font-size: 15px; line-height: 1.6; }
.sn-elev .sn-card__note,
.sn-elev .sn-field-note { color: var(--sn-elev-ink-3); font-size: 13px; line-height: 1.6; }

/* ── ACCENT WITH INTENT — selection, progress and focus. Never chrome. ─────────────────────────────*/
.sn-elev :where(button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: 2px solid var(--sn-elev-ring);
  outline-offset: 2px;
}
.sn-elev [aria-current="true"],
.sn-elev .is-selected {
  border-color: var(--sn-elev-accent);
  background: var(--sn-elev-accent-soft);
  box-shadow: 0 0 0 1px var(--sn-elev-accent), 0 6px 20px -8px rgba(100, 85, 214, .55);
}

/* ── CONTROLS + TABLE ──────────────────────────────────────────────────────────────────────────────*/
.sn-elev .sn-btn-ghost { border: 1px solid rgba(255, 255, 255, .12); }
.sn-elev .sn-btn-ghost:hover { background: rgba(255, 255, 255, .06); border-color: rgba(255, 255, 255, .22); }
.sn-elev .sn-table-wrap { border: 1px solid rgba(255, 255, 255, .08); border-radius: 12px; overflow: hidden; }
.sn-elev .sn-table thead th {
  background: rgba(255, 255, 255, .035);
  font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--sn-elev-ink-3); padding: 11px 14px;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}
.sn-elev .sn-table td { padding: 13px 14px; border-bottom: 1px solid rgba(255, 255, 255, .055); }
.sn-elev .sn-table tbody tr { transition: background 120ms var(--sn-ease); }
.sn-elev .sn-table tbody tr:hover { background: rgba(255, 255, 255, .04); }

@media (prefers-reduced-motion: reduce) {
  .sn-elev .sn-table tbody tr { transition: none; }
}
