/* ==========================================================================
   WaveCraft — design system
   --------------------------------------------------------------------------
   A calm, instrument-grade interface: neutral surfaces, one accent, depth from
   layering rather than glow. Motion is a language, not decoration — state
   changes are animated, ambience is not.

   Layers: reset → tokens → base → layout → components → motion
   ========================================================================== */

/* Self-hosted variable fonts (latin subsets) */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("../fonts/space-grotesk-var.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter-var.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-var.woff2") format("woff2");
}

/* Typed custom properties so gradients and fills interpolate instead of
   snapping — the browser can only animate a value it knows the type of. */
@property --angle {
  syntax: "<angle>";
  initial-value: 90deg;
  inherits: false;
}
@property --fill {
  syntax: "<percentage>";
  initial-value: 0%;
  inherits: true;
}
/* Cross-document transitions: navigating Synth ↔ Studio cross-fades rather
   than flashing white, and the nav pill slides between the two tabs. */
@view-transition { navigation: auto; }

@layer reset, tokens, base, layout, components, motion;

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  body, figure, h1, h2, h3, h4, p, ul, ol { margin: 0; }
  ul, ol { padding: 0; list-style: none; }
  button, input, select, textarea { font: inherit; color: inherit; }
  button { background: none; border: 0; }
  img, svg, canvas { display: block; max-width: 100%; }
  [hidden] { display: none !important; }
}

@layer tokens {
  :root {
    /* Both schemes are real; light-dark() below picks per token. The toggle
       writes data-theme, which wins over the system preference. */
    color-scheme: light dark;

    /* ---- Surfaces: a cool near-neutral, four steps of elevation ---- */
    --bg:        light-dark(oklch(97.6% 0.004 265), oklch(15.5% 0.011 265));
    --bg-sunk:   light-dark(oklch(94.4% 0.006 265), oklch(12.4% 0.011 265));
    --surface:   light-dark(oklch(100% 0 0),        oklch(19.4% 0.013 265));
    --surface-2: light-dark(oklch(97.6% 0.005 265), oklch(23.2% 0.014 265));
    --surface-3: light-dark(oklch(94.6% 0.007 265), oklch(27.4% 0.015 265));

    /* ---- Ink ---- */
    --text:   light-dark(oklch(23% 0.016 265), oklch(96% 0.005 265));
    --text-2: light-dark(oklch(46% 0.015 265), oklch(75% 0.011 265));
    --text-3: light-dark(oklch(60% 0.013 265), oklch(60% 0.012 265));

    /* ---- Hairlines ---- */
    --line:   light-dark(oklch(20% 0.02 265 / 0.11), oklch(100% 0 0 / 0.085));
    --line-2: light-dark(oklch(20% 0.02 265 / 0.19), oklch(100% 0 0 / 0.17));

    /* ---- One accent, three semantics ----
       Azure carries identity and focus; signal-green means "live"; amber
       warns; rose destroys. Nothing else gets to be colourful. */
    --accent:     light-dark(oklch(54% 0.19 258), oklch(74% 0.15 253));
    --accent-2:   light-dark(oklch(50% 0.20 288), oklch(78% 0.14 288));
    --accent-ink: light-dark(oklch(99% 0 0),      oklch(17% 0.04 258));
    --accent-wash: light-dark(oklch(54% 0.19 258 / 0.09), oklch(74% 0.15 253 / 0.14));
    --signal: light-dark(oklch(58% 0.16 158), oklch(82% 0.17 158));
    --warn:   light-dark(oklch(60% 0.14 70),  oklch(84% 0.14 78));
    --danger: light-dark(oklch(55% 0.20 22),  oklch(72% 0.17 20));

    --brand-grad: linear-gradient(var(--angle), var(--accent), var(--accent-2));

    /* ---- Shape ---- */
    --r-xs: 8px;
    --r-sm: 12px;
    --r-md: 16px;
    --r-lg: 22px;
    --r-xl: 30px;
    --r-full: 999px;

    /* ---- Elevation: soft, layered, never a single hard drop ----
       light-dark() takes two *colours*, so the geometry is written once and
       only the shadow colours switch. Dark mode needs a much heavier alpha to
       read at all, hence two separate colour tokens rather than one. */
    --shade-near: light-dark(oklch(25% 0.03 265 / 0.07), oklch(0% 0 0 / 0.45));
    --shade-far:  light-dark(oklch(25% 0.03 265 / 0.16), oklch(0% 0 0 / 0.7));
    --shadow-1: 0 1px 2px var(--shade-near), 0 4px 12px -6px var(--shade-far);
    --shadow-2: 0 2px 5px var(--shade-near), 0 14px 36px -16px var(--shade-far);
    --shadow-3: 0 5px 12px var(--shade-near), 0 32px 70px -28px var(--shade-far);
    /* The 1px of light along a card's top edge that sells it as a surface */
    --bevel: inset 0 1px 0 light-dark(oklch(100% 0 0 / 0.9), oklch(100% 0 0 / 0.06));

    /* ---- Motion ---- */
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    /* A real spring, sampled: overshoots ~2% and settles. Used on anything
       the user pressed, so the UI answers rather than fades. */
    --ease-spring: linear(
      0, 0.006, 0.025 2.8%, 0.101 6.1%, 0.539 18.9%, 0.721 25.3%, 0.849 31.5%,
      0.937 38.1%, 0.968 41.8%, 0.991 45.7%, 1.006 50.1%, 1.015 55%, 1.017 63.9%,
      1.001 82.1%, 1);
    --dur-1: 0.12s;
    --dur-2: 0.22s;
    --dur-3: 0.4s;
    --dur-4: 0.7s;

    /* ---- Type ---- */
    --font-display: "Space Grotesk", system-ui, sans-serif;
    --font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

    --measure: 62ch;
    --gutter: clamp(1rem, 4vw, 2.5rem);

    /* ---- Backdrop ---- Alphas are baked into these colours rather than set
       with `opacity`, so a single rule covers both schemes. */
    --wash-1: light-dark(oklch(54% 0.19 258 / 0.11), oklch(74% 0.15 253 / 0.22));
    --wash-2: light-dark(oklch(50% 0.20 288 / 0.10), oklch(78% 0.14 288 / 0.18));
    --wash-3: light-dark(oklch(58% 0.16 158 / 0.07), oklch(82% 0.17 158 / 0.12));
    --grid-line: light-dark(oklch(20% 0.02 265 / 0.06), oklch(100% 0 0 / 0.035));

    /* ---- Keycaps ---- */
    --key-top: light-dark(oklch(100% 0 0), oklch(89% 0.006 265));
    --key-bottom: light-dark(oklch(93.5% 0.004 265), oklch(78% 0.008 265));
    --key-lip: light-dark(oklch(88% 0.006 265), oklch(68% 0.01 265));
    --knob-face: light-dark(oklch(100% 0 0), oklch(98% 0.004 265));
  }

  :root[data-theme="light"] { color-scheme: light; }
  :root[data-theme="dark"] { color-scheme: dark; }
}

@layer base {
  html { scrollbar-gutter: stable; }

  body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.55;
    font-synthesis-weight: none;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 600;
    /* Display type in 2026 sits tight; body stays neutral */
    letter-spacing: -0.02em;
    line-height: 1.12;
    text-wrap: balance;
  }
  p { text-wrap: pretty; }

  a { color: var(--accent); text-underline-offset: 0.2em; }

  code, pre, kbd, .tnum { font-family: var(--font-mono); }
  .tnum { font-variant-numeric: tabular-nums; }

  ::selection { background: var(--accent-wash); }

  :focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--r-xs);
  }

  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb {
    background: var(--line-2);
    border: 3px solid transparent;
    background-clip: content-box;
    border-radius: var(--r-full);
  }
  ::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: content-box; }
  * { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
}

@layer layout {
  main {
    max-width: 1180px;
    margin: 0 auto;
    padding: clamp(1.75rem, 5vw, 3.5rem) var(--gutter) 5rem;
    position: relative;
    z-index: 1;
    display: flow-root;
  }

  main > section + section { margin-top: clamp(3.5rem, 8vw, 6rem); }

  /* Section header: an eyebrow, a title, and a line of context */
  .section-head { max-width: var(--measure); margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
  .section-head h2 { font-size: clamp(1.5rem, 3.2vw, 2.1rem); }
  .section-head .lede { margin-top: 0.75rem; }

  .eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-3);
    margin-bottom: 0.9rem;
  }
  .eyebrow::before {
    content: "";
    width: 1.5rem;
    height: 1px;
    background: currentColor;
    opacity: 0.5;
  }

  .lede {
    font-size: clamp(1rem, 1.4vw, 1.1rem);
    line-height: 1.6;
    color: var(--text-2);
    max-width: var(--measure);
  }
  .lede em { color: var(--text); font-style: italic; }

  footer {
    position: relative;
    z-index: 1;
    border-top: 1px solid var(--line);
    padding: 2.25rem var(--gutter) 3rem;
  }
  .footer-inner {
    max-width: 1180px;
    margin: 0 auto;
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1.5rem;
    align-items: center;
    justify-content: space-between;
    color: var(--text-3);
    font-size: 0.82rem;
  }
  footer a { color: var(--text-2); text-decoration: none; }
  footer a:hover { color: var(--accent); }
}

@layer components {
  /* ======================================================================
     Ambience — the backdrop
     A slow accent-tinted wash and a masked grid. Two layers, both under 10%
     opacity: enough to give the page air, never enough to fight the UI.
     ====================================================================== */
  .ambient {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
    contain: strict;
  }
  .ambient-glow {
    position: absolute;
    inset: -25%;
    background:
      radial-gradient(30% 26% at 15% 8%,  var(--wash-1), transparent 68%),
      radial-gradient(28% 24% at 88% 14%, var(--wash-2), transparent 68%),
      radial-gradient(40% 30% at 62% 92%, var(--wash-3), transparent 70%);
    filter: blur(60px);
  }
  /* The "visible grid" of 2026 — structure you can feel, radially masked so
     it never reads as a table */
  .ambient-grid {
    position: absolute;
    inset: 0;
    background-image:
      linear-gradient(var(--grid-line) 1px, transparent 1px),
      linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
    background-size: 72px 72px;
    mask-image: radial-gradient(120% 90% at 50% 0%, black, transparent 72%);
    -webkit-mask-image: radial-gradient(120% 90% at 50% 0%, black, transparent 72%);
  }
  /* Film grain — a data-URI turbulence, no request, and it takes the flat
     gradients out of "CSS blob" territory.
     No blend mode on purpose: .ambient is its own stacking context, so a
     blended layer inside it composites against transparency rather than
     against the page, and lands as a flat grey sheet. Straight alpha over a
     desaturated, alpha-flattened noise is predictable in both themes. */
  .ambient::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='table' tableValues='1 1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    opacity: 0.04;
  }

  /* ======================================================================
     Header
     ====================================================================== */
  .site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: clamp(0.75rem, 2vw, 1.5rem);
    padding: 0.7rem var(--gutter);
    background: light-dark(oklch(100% 0 0 / 0.72), oklch(15.5% 0.011 265 / 0.68));
    backdrop-filter: blur(18px) saturate(180%);
    -webkit-backdrop-filter: blur(18px) saturate(180%);
    border-bottom: 1px solid var(--line);
  }

  .brand {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    text-decoration: none;
    color: inherit;
    view-transition-name: brand;
  }
  .brand-mark {
    display: grid;
    place-items: center;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: 10px;
    background: var(--brand-grad);
    color: var(--accent-ink);
    box-shadow: var(--shadow-1), var(--bevel);
    flex: none;
  }
  .brand-mark svg { width: 1.15rem; height: 1.15rem; }
  .brand-name {
    display: block;
    font-family: var(--font-display);
    font-size: 1.02rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1.15;
  }
  .brand-sub {
    display: block;
    font-size: 0.7rem;
    color: var(--text-3);
    line-height: 1.2;
  }

  /* Segmented nav — the active pill carries a view-transition-name, so it
     slides across when you navigate between the two pages */
  .seg {
    display: flex;
    gap: 0.15rem;
    padding: 0.2rem;
    border-radius: var(--r-full);
    background: var(--bg-sunk);
    border: 1px solid var(--line);
  }
  .seg-item {
    position: relative;
    padding: 0.34rem 0.9rem;
    border-radius: var(--r-full);
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-2);
    text-decoration: none;
    white-space: nowrap;
    transition: color var(--dur-2) var(--ease-out);
  }
  .seg-item:hover { color: var(--text); }
  .seg-item[aria-current="page"] { color: var(--text); }
  .seg-item[aria-current="page"]::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: var(--surface);
    box-shadow: var(--shadow-1), var(--bevel);
    z-index: -1;
    view-transition-name: nav-pill;
  }

  .header-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: auto;
  }

  /* The header carries five things; below a laptop they shed in order of how
     little they are missed — the subtitle, then the status wording, then the
     nav drops to its own row. */
  @media (max-width: 1000px) {
    .brand-sub { display: none; }
    .brand-name { font-size: 1.05rem; }
  }
  @media (max-width: 820px) {
    #mcp-status-label, .mcp-activity { display: none; }
    .mcp-indicator { padding: 0.42rem; }
  }
  @media (max-width: 640px) {
    .site-header { flex-wrap: wrap; row-gap: 0.55rem; padding-bottom: 0.55rem; }
    .seg { order: 3; width: 100%; justify-content: center; }
    .header-actions { gap: 0.4rem; }
    #upgrade-btn { padding-inline: 0.8rem; }
  }

  /* ---- Status pill ---- */
  .mcp-indicator {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.78rem;
    color: var(--text-2);
    padding: 0.3rem 0.7rem 0.3rem 0.6rem;
    border: 1px solid var(--line);
    border-radius: var(--r-full);
    background: var(--surface);
    white-space: nowrap;
  }
  #mcp-status {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--text-3);
    flex: none;
    transition: background var(--dur-3) var(--ease-out), box-shadow var(--dur-3) var(--ease-out);
  }
  #mcp-status[data-status="connected"] {
    background: var(--signal);
    box-shadow: 0 0 0 3px oklch(from var(--signal) l c h / 0.22);
  }
  #mcp-status[data-status="connecting"] {
    background: var(--warn);
    box-shadow: 0 0 0 3px oklch(from var(--warn) l c h / 0.22);
  }
  .mcp-activity {
    font-size: 0.7rem;
    color: var(--accent);
    max-width: 0;
    overflow: hidden;
    opacity: 0;
    transition: max-width var(--dur-4) var(--ease-out), opacity var(--dur-2) var(--ease-out);
  }
  .mcp-activity.flash { max-width: 16rem; opacity: 1; }

  /* ======================================================================
     Buttons
     ====================================================================== */
  .btn-primary,
  .btn-secondary,
  .btn-ghost,
  .icon-btn {
    --lift: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    border-radius: var(--r-full);
    padding: 0.48rem 1.05rem;
    font-size: 0.88rem;
    font-weight: 550;
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    text-decoration: none;
    translate: 0 var(--lift);
    transition:
      translate var(--dur-2) var(--ease-spring),
      background-color var(--dur-2) var(--ease-out),
      border-color var(--dur-2) var(--ease-out),
      box-shadow var(--dur-2) var(--ease-out),
      color var(--dur-2) var(--ease-out),
      --angle var(--dur-4) var(--ease-out);
  }
  .btn-primary {
    background: var(--brand-grad);
    color: var(--accent-ink);
    box-shadow: var(--shadow-1), var(--bevel);
  }
  .btn-primary:hover { --lift: -1px; --angle: 200deg; box-shadow: var(--shadow-2), var(--bevel); }
  .btn-primary:active { --lift: 1px; box-shadow: var(--shadow-1); }

  .btn-secondary {
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--line-2);
    box-shadow: var(--shadow-1);
  }
  .btn-secondary:hover { --lift: -1px; border-color: var(--accent); color: var(--accent); }
  .btn-secondary:active { --lift: 1px; }

  .btn-ghost {
    color: var(--text-2);
    border: 1px solid transparent;
  }
  .btn-ghost:hover { color: var(--text); background: var(--surface-2); }

  .icon-btn {
    width: 2.15rem;
    height: 2.15rem;
    padding: 0;
    border-radius: var(--r-full);
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--text-2);
  }
  .icon-btn:hover { color: var(--text); border-color: var(--line-2); --lift: -1px; }
  .icon-btn svg { width: 1.05rem; height: 1.05rem; }

  /* The theme toggle swaps its two glyphs; only the relevant one is drawn */
  #theme-toggle .icon-moon { display: none; }
  :root[data-theme="dark"] #theme-toggle .icon-moon,
  :root:not([data-theme="light"]) #theme-toggle .icon-moon { display: block; }
  :root[data-theme="dark"] #theme-toggle .icon-sun,
  :root:not([data-theme="light"]) #theme-toggle .icon-sun { display: none; }
  :root[data-theme="light"] #theme-toggle .icon-sun { display: block; }
  :root[data-theme="light"] #theme-toggle .icon-moon { display: none; }
  @media (prefers-color-scheme: light) {
    :root:not([data-theme]) #theme-toggle .icon-sun { display: block; }
    :root:not([data-theme]) #theme-toggle .icon-moon { display: none; }
  }

  /* ======================================================================
     Hero
     Compact on purpose: the instrument is the product, so it stays as close
     to the fold as a headline allows.
     ====================================================================== */
  /* Deliberately shallow: the instrument is the product, so the headline gets
     exactly as much room as it needs and no more. */
  .hero > h1, .hero > .hero-sub, .hero > .eyebrow { max-width: 46ch; }
  .hero + .panel { margin-top: clamp(1.75rem, 4vw, 2.75rem); }
  .hero h1 {
    font-size: clamp(2.1rem, 5.4vw, 3.15rem);
    letter-spacing: -0.035em;
    line-height: 1.04;
  }
  /* The one word that gets colour on the whole page */
  .hero h1 em {
    font-style: normal;
    background: linear-gradient(100deg, var(--accent) 20%, var(--accent-2) 80%);
    background-clip: text;
    -webkit-background-clip: text;
    color: transparent;
  }
  .hero-sub {
    margin-top: 1rem;
    font-size: clamp(0.98rem, 1.5vw, 1.12rem);
    color: var(--text-2);
    max-width: 46ch;
  }

  .value-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1.6rem;
  }
  .value-strip li {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.34rem 0.8rem 0.34rem 0.6rem;
    font-size: 0.8rem;
    color: var(--text-2);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-full);
    box-shadow: var(--shadow-1);
  }
  .value-strip li::before {
    content: "";
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
  }
  .value-strip li:nth-child(2)::before { background: var(--accent-2); }
  .value-strip li:nth-child(3)::before { background: var(--signal); }
  .value-strip li:nth-child(4)::before { background: var(--warn); }

  /* ======================================================================
     Panels — the shared card
     ====================================================================== */
  .panel {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    box-shadow: var(--shadow-2), var(--bevel);
    padding: clamp(1rem, 2.5vw, 1.6rem);
  }

  .panel-head {
    display: flex;
    align-items: center;
    gap: 0.6rem 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
  }
  .panel-label {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    font-weight: 500;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--text-3);
  }
  .panel-head .spacer { flex: 1; }
  .panel-head.stack {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.2rem;
  }
  .panel-title { font-size: clamp(1.1rem, 2.2vw, 1.3rem); }

  /* ---- The instrument ---- */
  .synth-panel {
    container-type: inline-size;
    container-name: synth;
    scroll-margin-top: 5rem;
  }

  .preset-picker {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-3);
  }
  .preset-description {
    flex: 1 1 14rem;
    min-width: 0;
    font-size: 0.82rem;
    color: var(--text-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  select,
  input[type="text"],
  textarea {
    background: var(--bg-sunk);
    color: var(--text);
    border: 1px solid var(--line-2);
    border-radius: var(--r-sm);
    padding: 0.38rem 0.6rem;
    letter-spacing: normal;
    text-transform: none;
    transition: border-color var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
  }
  select:hover, input[type="text"]:hover, textarea:hover { border-color: var(--text-3); }
  select:focus-visible, input:focus-visible, textarea:focus-visible {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-wash);
  }

  /* ---- Scope: the live spectrum, drawn from an AnalyserNode ---- */
  .scope {
    position: relative;
    height: 84px;
    margin-bottom: 1.2rem;
    border-radius: var(--r-md);
    background: var(--bg-sunk);
    border: 1px solid var(--line);
    overflow: hidden;
  }
  .scope canvas { width: 100%; height: 100%; }
  .scope::after {
    /* a hairline "floor" so the bars have something to stand on */
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 1px;
    background: var(--line-2);
  }
  .audio-hint {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    margin: 0;
    font-size: 0.82rem;
    color: var(--text-2);
    background: light-dark(oklch(100% 0 0 / 0.55), oklch(12.4% 0.011 265 / 0.55));
    backdrop-filter: blur(2px);
    transition: opacity var(--dur-3) var(--ease-out);
  }
  .audio-hint kbd { margin: 0 0.15em; }

  /* ---- Control modules ---- */
  .controls {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 0.9rem;
    margin-bottom: 1.3rem;
    align-items: start;
  }
  @container synth (max-width: 560px) {
    .controls { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
    /* On a phone the panel head is four stacked rows; drop the label the card
       does not need and let the preset menu take the width it deserves. */
    .synth-panel > .panel-head > .panel-label { display: none; }
    .synth-panel .preset-picker { flex: 1; }
    .synth-panel .preset-picker select { flex: 1; min-width: 0; }
    .synth-panel .preset-description { order: 9; flex-basis: 100%; }
  }

  fieldset {
    border: 1px solid var(--line);
    background: var(--surface-2);
    border-radius: var(--r-md);
    padding: 0.7rem 0.75rem 0.5rem;
    margin: 0;
    min-width: 0;
    transition: border-color var(--dur-2) var(--ease-out), background-color var(--dur-2) var(--ease-out);
  }
  /* Light up the module you are touching — the only "glow" left in the UI,
     and it means something */
  fieldset:has(input:focus-visible, select:focus-visible, input:active) {
    border-color: oklch(from var(--accent) l c h / 0.55);
    background: var(--surface-3);
  }
  legend {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    float: left;
    width: 100%;
    padding: 0 0 0.55rem;
    font-family: var(--font-mono);
    font-size: 0.62rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-3);
    transition: color var(--dur-2) var(--ease-out);
  }
  legend::before {
    content: "";
    width: 5px;
    height: 5px;
    border-radius: 1px;
    background: var(--line-2);
    rotate: 45deg;
    transition: background-color var(--dur-2) var(--ease-out), rotate var(--dur-3) var(--ease-spring);
  }
  fieldset:has(input:focus-visible, select:focus-visible, input:active) legend { color: var(--text); }
  fieldset:has(input:focus-visible, select:focus-visible, input:active) legend::before {
    background: var(--accent);
    rotate: 135deg;
  }
  .fieldset-body { clear: both; }

  /* Name and value share a row; the control spans underneath */
  fieldset label {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: 0 0.4rem;
    font-size: 0.72rem;
    color: var(--text-2);
    margin-bottom: 0.55rem;
  }
  fieldset label:last-child { margin-bottom: 0.2rem; }
  fieldset label input,
  fieldset label select { grid-column: 1 / -1; }
  fieldset select { width: 100%; margin-top: 0.2rem; font-size: 0.76rem; padding: 0.25rem 0.4rem; }
  .control-value {
    text-align: right;
    color: var(--text);
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.64rem;
  }

  /* ---- Sliders: a filled track, a thumb that grows under the finger ----
     --fill is written by controls.js on every change, so the filled portion
     always shows the value the engine actually applied. */
  input[type="range"] {
    --track-h: 5px;
    --thumb: 13px;
    width: 100%;
    margin: 0.35rem 0 0;
    appearance: none;
    -webkit-appearance: none;
    height: var(--thumb);
    background: transparent;
    cursor: ew-resize;
  }
  input[type="range"]::-webkit-slider-runnable-track {
    height: var(--track-h);
    border-radius: var(--r-full);
    background:
      linear-gradient(90deg, var(--accent) 0 var(--fill), transparent var(--fill)),
      var(--bg-sunk);
    box-shadow: inset 0 0 0 1px var(--line);
  }
  input[type="range"]::-moz-range-track {
    height: var(--track-h);
    border-radius: var(--r-full);
    background:
      linear-gradient(90deg, var(--accent) 0 var(--fill), transparent var(--fill)),
      var(--bg-sunk);
    box-shadow: inset 0 0 0 1px var(--line);
  }
  input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: var(--thumb);
    height: var(--thumb);
    margin-top: calc((var(--track-h) - var(--thumb)) / 2);
    border-radius: 50%;
    background: var(--knob-face);
    box-shadow: 0 0 0 1px var(--line-2), var(--shadow-1);
    transition: scale var(--dur-2) var(--ease-spring), box-shadow var(--dur-2) var(--ease-out);
  }
  input[type="range"]::-moz-range-thumb {
    width: var(--thumb);
    height: var(--thumb);
    border: 0;
    border-radius: 50%;
    background: var(--knob-face);
    box-shadow: 0 0 0 1px var(--line-2), var(--shadow-1);
  }
  input[type="range"]:hover::-webkit-slider-thumb { scale: 1.12; }
  input[type="range"]:active::-webkit-slider-thumb {
    scale: 1.25;
    box-shadow: 0 0 0 1px var(--accent), 0 0 0 5px var(--accent-wash);
  }
  input[type="range"]:active::-moz-range-thumb {
    box-shadow: 0 0 0 1px var(--accent), 0 0 0 5px var(--accent-wash);
  }
  input[type="checkbox"] { accent-color: var(--accent); }

  /* The FX rack carries as many parameters as three other modules */
  .controls fieldset[data-group="fx"] { grid-column: span 2; }
  .controls fieldset[data-group="fx"] .fieldset-body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(115px, 1fr));
    gap: 0 0.85rem;
  }
  @container synth (max-width: 420px) {
    .controls fieldset[data-group="fx"] { grid-column: span 1; }
  }

  /* ======================================================================
     Keyboard
     ====================================================================== */
  .keyboard {
    display: flex;
    position: relative;
    height: clamp(120px, 18vw, 164px);
    user-select: none;
    touch-action: none;
    padding: 0.5rem 0.5rem 0.6rem;
    border-radius: var(--r-md);
    background: var(--bg-sunk);
    border: 1px solid var(--line);
    box-shadow: inset 0 1px 12px light-dark(oklch(25% 0.03 265 / 0.08), oklch(0% 0 0 / 0.5));
  }
  .key { padding: 0; cursor: pointer; }
  .key.white {
    flex: 1;
    margin: 0 1.5px;
    border-radius: 3px 3px 7px 7px;
    background: linear-gradient(var(--key-top), var(--key-bottom));
    box-shadow:
      0 1px 0 var(--shade-far),
      inset 0 -3px 0 var(--key-lip);
    transition: background var(--dur-1) linear, box-shadow var(--dur-1) linear, translate var(--dur-1) var(--ease-out);
  }
  .key.white:active, .key.white.active {
    background: linear-gradient(oklch(from var(--accent) calc(l + 0.12) c h), var(--accent));
    box-shadow: 0 0 0 1px var(--accent), 0 0 18px -2px oklch(from var(--accent) l c h / 0.7);
    translate: 0 1px;
  }
  .key.black {
    flex: 0 0 0;
    position: relative;
    width: 0;
    z-index: 2;
    background: none;
  }
  .key.black::after {
    content: "";
    position: absolute;
    top: 0;
    left: -12px;
    width: 24px;
    height: 58%;
    border-radius: 2px 2px 6px 6px;
    background: linear-gradient(oklch(32% 0.014 265), oklch(17% 0.012 265) 78%);
    box-shadow: 0 3px 7px oklch(0% 0 0 / 0.45), inset 0 -2px 0 oklch(0% 0 0 / 0.6);
    transition: background var(--dur-1) linear, box-shadow var(--dur-1) linear;
  }
  .key.black:active::after, .key.black.active::after {
    background: linear-gradient(var(--accent-2), oklch(from var(--accent-2) calc(l - 0.18) c h));
    box-shadow: 0 0 18px -2px oklch(from var(--accent-2) l c h / 0.75);
  }

  .hint { color: var(--text-3); font-size: 0.8rem; margin-top: 0.85rem; }
  kbd {
    display: inline-block;
    min-width: 1.5em;
    text-align: center;
    background: var(--surface-2);
    border: 1px solid var(--line-2);
    border-bottom-width: 2px;
    border-radius: 5px;
    padding: 0 0.3em;
    font-size: 0.8em;
    color: var(--text-2);
  }

  /* ======================================================================
     Drum machine
     ====================================================================== */
  .drum-machine { container-type: inline-size; }
  .drum-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
  }
  .drum-controls label.bpm {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.75rem;
    color: var(--text-3);
    padding: 0.2rem 0.7rem 0.2rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--r-full);
    background: var(--surface-2);
  }
  /* The groove and kit menus sit in a row of pill buttons, so they wear the
     same shape rather than looking like leftover form controls. */
  .drum-controls select {
    border-radius: var(--r-full);
    background: var(--surface);
    padding: 0.42rem 0.9rem;
    font-size: 0.85rem;
  }
  .drum-controls label.bpm input { width: 120px; margin: 0; }
  .drum-controls label.bpm .control-value { min-width: 4.2rem; }

  .drum-grid {
    display: flex;
    flex-direction: column;
    gap: 0.28rem;
    overflow-x: auto;
    padding-bottom: 0.4rem;
  }
  .drum-row { display: flex; align-items: center; gap: 0.28rem; }
  .drum-pad {
    flex: 0 0 7.5rem;
    text-align: left;
    background: var(--surface-2);
    color: var(--text-2);
    border: 1px solid var(--line);
    border-radius: var(--r-xs);
    padding: 0.34rem 0.6rem;
    font-size: 0.74rem;
    cursor: pointer;
    transition: border-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out), translate var(--dur-2) var(--ease-spring);
  }
  .drum-pad:hover { border-color: var(--accent); color: var(--text); translate: 1px 0; }
  .drum-pad:active { scale: 0.98; }

  .drum-cell {
    flex: 1 1 1.4rem;
    min-width: 1.4rem;
    height: 1.9rem;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--bg-sunk);
    cursor: pointer;
    padding: 0;
    transition:
      background-color var(--dur-1) linear,
      border-color var(--dur-1) linear,
      box-shadow var(--dur-2) var(--ease-out),
      scale var(--dur-2) var(--ease-spring);
  }
  .drum-cell:hover { border-color: var(--text-3); }
  /* Downbeats read a shade brighter, so 16 steps still parse as 4 beats */
  .drum-cell.beat { background: var(--surface-2); }
  .drum-cell.on {
    background: var(--accent);
    border-color: var(--accent);
  }
  .drum-cell.on.accent {
    background: var(--accent-2);
    border-color: var(--accent-2);
    box-shadow: 0 0 14px -4px oklch(from var(--accent-2) l c h / 0.8);
  }
  /* The step under the playhead lifts rather than flashes */
  .drum-cell.playing {
    box-shadow: 0 0 0 2px light-dark(oklch(30% 0.02 265 / 0.5), oklch(100% 0 0 / 0.7));
    scale: 1.08;
  }
  .drum-remove {
    color: var(--text-3);
    cursor: pointer;
    font-size: 0.75rem;
    padding: 0.2rem 0.3rem;
    border-radius: var(--r-xs);
    transition: color var(--dur-2) var(--ease-out), background-color var(--dur-2) var(--ease-out);
  }
  .drum-remove:hover { color: var(--danger); background: oklch(from var(--danger) l c h / 0.12); }

  /* ======================================================================
     Code block with a copy button
     ====================================================================== */
  .code-block {
    position: relative;
    margin: 1.25rem 0;
    border-radius: var(--r-md);
    border: 1px solid var(--line);
    background: var(--bg-sunk);
    overflow: hidden;
  }
  .code-block pre {
    margin: 0;
    padding: 1rem 3.4rem 1rem 1.1rem;
    font-size: 0.84rem;
    color: var(--text);
    /* Wrapped rather than scrolled: a scroll container's right padding sits at
       the end of the scrollable area, so a long command would run underneath
       the copy button instead of stopping short of it. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }
  .code-block code { color: inherit; }
  .copy-btn {
    position: absolute;
    top: 0.55rem;
    right: 0.55rem;
    width: 2rem;
    height: 2rem;
    display: grid;
    place-items: center;
    border-radius: var(--r-xs);
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--text-3);
    cursor: pointer;
    transition: color var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out), scale var(--dur-2) var(--ease-spring);
  }
  .copy-btn:hover { color: var(--text); border-color: var(--line-2); }
  .copy-btn:active { scale: 0.92; }
  .copy-btn svg { width: 0.95rem; height: 0.95rem; }
  .copy-btn .icon-check { display: none; color: var(--signal); }
  .copy-btn.copied .icon-check { display: block; }
  .copy-btn.copied .icon-copy { display: none; }

  /* ======================================================================
     Bento — the benefits grid
     Asymmetric by design: the two claims that matter get twice the room.
     ====================================================================== */
  .bento {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 0.9rem;
    margin-top: 2rem;
  }
  .bento li {
    grid-column: span 2;
    position: relative;
    isolation: isolate;
    padding: 1.15rem 1.2rem 1.25rem;
    border-radius: var(--r-lg);
    background: var(--surface);
    border: 1px solid var(--line);
    box-shadow: var(--shadow-1), var(--bevel);
    overflow: hidden;
    transition: translate var(--dur-3) var(--ease-spring), box-shadow var(--dur-3) var(--ease-out), border-color var(--dur-3) var(--ease-out);
  }
  /* 4+2 / 2+4 / 3+3 — every row fills the six columns, and the alternating
     wide cell is what keeps it from reading as a plain two-up. */
  .bento li:nth-child(1), .bento li:nth-child(4) { grid-column: span 4; }
  .bento li:nth-child(2), .bento li:nth-child(3) { grid-column: span 2; }
  .bento li:nth-child(5), .bento li:nth-child(6) { grid-column: span 3; }
  .bento li:hover {
    translate: 0 -3px;
    box-shadow: var(--shadow-3), var(--bevel);
    border-color: var(--line-2);
  }
  /* A gradient wash that wakes up on hover — depth, not decoration */
  .bento li::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: radial-gradient(80% 60% at 12% 0%, var(--accent-wash), transparent 70%);
    opacity: 0;
    transition: opacity var(--dur-3) var(--ease-out);
  }
  .bento li:hover::before { opacity: 1; }
  .bento h3 {
    font-size: 1rem;
    margin-bottom: 0.45rem;
    display: flex;
    align-items: center;
    gap: 0.55rem;
  }
  .bento h3::before {
    counter-increment: bento;
    content: counter(bento, decimal-leading-zero);
    font-family: var(--font-mono);
    font-size: 0.62rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    color: var(--accent);
    padding: 0.15rem 0.4rem;
    border-radius: 5px;
    background: var(--accent-wash);
  }
  .bento { counter-reset: bento; }
  .bento p { font-size: 0.88rem; color: var(--text-2); }
  .bento code { font-size: 0.9em; color: var(--accent); }

  @media (max-width: 900px) {
    .bento { grid-template-columns: repeat(4, 1fr); }
    .bento li:nth-child(n) { grid-column: span 2; }
  }
  @media (max-width: 560px) {
    .bento { grid-template-columns: 1fr; }
    .bento li:nth-child(n) { grid-column: span 1; }
  }

  /* ======================================================================
     Split — the MCP promo
     ====================================================================== */
  .split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
  }
  @media (max-width: 860px) { .split { grid-template-columns: 1fr; } }
  .split-aside {
    padding: 1.25rem;
    border-radius: var(--r-lg);
    background: var(--surface);
    border: 1px solid var(--line);
    box-shadow: var(--shadow-1), var(--bevel);
  }
  .split-aside .code-block { margin-top: 0.9rem; }
  .split-aside p { font-size: 0.86rem; color: var(--text-2); }
  .split-aside p + p { margin-top: 0.7rem; }
  .split > .prose p + p { margin-top: 0.9rem; }
  .split > .prose p { color: var(--text-2); }

  /* ======================================================================
     Comparison table
     ====================================================================== */
  .compare-wrap {
    margin-top: 2.5rem;
    border-radius: var(--r-lg);
    border: 1px solid var(--line);
    background: var(--surface);
    box-shadow: var(--shadow-1), var(--bevel);
    overflow-x: auto;
  }
  .compare {
    width: 100%;
    min-width: 34rem;
    border-collapse: collapse;
    font-size: 0.86rem;
  }
  .compare caption {
    text-align: left;
    font-family: var(--font-mono);
    font-size: 0.66rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.13em;
    color: var(--text-3);
    padding: 1rem 1.2rem 0.7rem;
  }
  .compare th, .compare td {
    text-align: left;
    vertical-align: top;
    padding: 0.75rem 1.2rem;
    border-bottom: 1px solid var(--line);
  }
  .compare thead th {
    font-family: var(--font-display);
    font-size: 0.8rem;
    letter-spacing: -0.01em;
    color: var(--text-2);
    position: sticky;
    top: 0;
    background: var(--surface-2);
  }
  .compare tbody th { font-weight: 500; color: var(--text-2); width: 11rem; }
  .compare td { color: var(--text-3); }
  /* The column the eye should land on gets a tinted lane of its own */
  .compare th:last-child, .compare td:last-child {
    background: var(--accent-wash);
    color: var(--text);
  }
  .compare thead th:last-child { color: var(--accent); }
  .compare tr:last-child th, .compare tr:last-child td { border-bottom: 0; }

  @media (max-width: 730px) {
    .compare { min-width: 0; }
    .compare thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
    .compare tr { display: block; padding: 0.85rem 1.2rem; border-bottom: 1px solid var(--line); }
    .compare tr:last-child { border-bottom: 0; }
    .compare tbody th {
      display: block;
      width: auto;
      padding: 0 0 0.5rem;
      border-bottom: 0;
      font-family: var(--font-display);
      font-size: 0.95rem;
      color: var(--text);
    }
    .compare td {
      display: grid;
      grid-template-columns: 5.5rem 1fr;
      gap: 0.6rem;
      padding: 0.3rem 0.5rem;
      border-bottom: 0;
      border-radius: var(--r-xs);
    }
    .compare td::before {
      content: attr(data-label);
      color: var(--text-3);
      font-size: 0.74rem;
    }
    .compare td[data-label="WaveCraft"]::before { color: var(--accent); }
  }

  .caveat {
    margin-top: 2rem;
    padding: 1rem 1.2rem;
    border-left: 2px solid var(--accent);
    border-radius: 0 var(--r-md) var(--r-md) 0;
    background: var(--surface-2);
    color: var(--text-2);
    font-size: 0.88rem;
    max-width: 52rem;
  }
  .caveat strong { color: var(--text); }

  /* ======================================================================
     Gear
     ====================================================================== */
  .gear-intro { color: var(--text-2); }
  .gear-disclosure { display: block; font-size: 0.75rem; color: var(--text-3); margin-top: 0.3rem; }
  .gear-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
    gap: 0.9rem;
    margin-top: 1.75rem;
  }
  .gear-card {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 1.1rem;
    border-radius: var(--r-lg);
    background: var(--surface);
    border: 1px solid var(--line);
    box-shadow: var(--shadow-1), var(--bevel);
    color: var(--text);
    text-decoration: none;
    transition: translate var(--dur-3) var(--ease-spring), box-shadow var(--dur-3) var(--ease-out), border-color var(--dur-3) var(--ease-out);
  }
  .gear-card:hover { translate: 0 -3px; box-shadow: var(--shadow-3), var(--bevel); border-color: var(--line-2); }
  .gear-card h3 { font-size: 0.98rem; }
  .gear-card p { margin: 0; color: var(--text-2); font-size: 0.85rem; flex: 1; }
  .gear-cta {
    color: var(--accent);
    font-size: 0.82rem;
    font-weight: 550;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
  }
  .gear-card:hover .gear-cta .arrow { translate: 3px 0; }
  .gear-cta .arrow { transition: translate var(--dur-2) var(--ease-spring); }

  /* ======================================================================
     Ad slot
     ----------------------------------------------------------------------
     A third-party frame, so it gets a reserved box the exact size of the
     unit — the page never reflows when it loads — and a label, so it reads
     as paid placement rather than as part of the site.
     ====================================================================== */
  .ad-slot {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    /* Set here rather than leaning on `section + section`, so the slot is
       spaced the same on Browse where it follows a div. */
    margin-top: clamp(2.75rem, 6vw, 4.5rem);
  }
  .ad-label {
    font-size: 0.68rem;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-3);
  }
  .ad-slot iframe {
    display: block;
    min-height: 130px;
    border-radius: var(--r-md);
    color-scheme: light;
  }

  /* ======================================================================
     Dialog
     ====================================================================== */
  dialog {
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    padding: 1.75rem;
    max-width: 27rem;
    width: calc(100vw - 2rem);
    box-shadow: var(--shadow-3), var(--bevel);
  }
  dialog::backdrop {
    background: light-dark(oklch(60% 0.02 265 / 0.35), oklch(8% 0.01 265 / 0.6));
    backdrop-filter: blur(6px);
  }
  dialog h2 { font-size: 1.35rem; margin-bottom: 0.5rem; }
  dialog > p { color: var(--text-2); font-size: 0.9rem; }
  dialog .close {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    width: 1.9rem;
    height: 1.9rem;
    display: grid;
    place-items: center;
    border-radius: var(--r-full);
    color: var(--text-3);
    cursor: pointer;
    transition: color var(--dur-2) var(--ease-out), background-color var(--dur-2) var(--ease-out);
  }
  dialog .close:hover { color: var(--text); background: var(--surface-2); }
  .error { color: var(--danger); font-size: 0.83rem; min-height: 1.2em; margin-top: 0.4rem; }

  /* ======================================================================
     Scroll progress — a hairline that fills as you read
     ====================================================================== */
  .scroll-progress {
    position: fixed;
    inset: 0 0 auto 0;
    height: 2px;
    z-index: 60;
    background: var(--brand-grad);
    transform-origin: 0 50%;
    scale: 0 1;
    pointer-events: none;
  }

  /* ======================================================================
     Account chrome and the library — shared by every page, because saving,
     signing in and browsing published work happen on all of them.
     ====================================================================== */
  .ai-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.78rem;
    padding: 0.3rem 0.75rem;
    border-radius: var(--r-full);
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--text-2);
    white-space: nowrap;
  }
  .ai-badge::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--text-3);
    transition: background-color var(--dur-3) var(--ease-out), box-shadow var(--dur-3) var(--ease-out);
  }
  .ai-badge[data-state="ready"]::before {
    background: var(--signal);
    box-shadow: 0 0 0 3px oklch(from var(--signal) l c h / 0.22);
  }
  .ai-badge[data-state="offline"]::before { background: var(--warn); }

  .chip {
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--text-2);
    border-radius: var(--r-full);
    padding: 0.33rem 0.85rem;
    cursor: pointer;
    font-size: 0.82rem;
    box-shadow: var(--shadow-1);
    transition:
      color var(--dur-2) var(--ease-out),
      border-color var(--dur-2) var(--ease-out),
      translate var(--dur-2) var(--ease-spring);
  }
  .chip:hover { color: var(--text); border-color: var(--accent); translate: 0 -2px; }
  .chip:active { translate: 0 0; }

  /* ======================================================================
     Account: the header control
     ====================================================================== */
  .account-menu { display: flex; align-items: center; gap: 0.5rem; }
  .btn-sm { padding: 0.36rem 0.85rem; font-size: 0.82rem; }
  .linkish {
    color: var(--text-2);
    font-size: 0.83rem;
    cursor: pointer;
    padding: 0.2rem;
    border-radius: var(--r-xs);
    text-decoration: underline;
    text-decoration-color: var(--line-2);
    text-underline-offset: 3px;
  }
  .linkish:hover { color: var(--accent); text-decoration-color: currentColor; }

  .account-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.7rem 0.25rem 0.3rem;
    border-radius: var(--r-full);
    border: 1px solid var(--line);
    background: var(--surface);
    cursor: pointer;
    transition: border-color var(--dur-2) var(--ease-out);
  }
  .account-chip:hover { border-color: var(--accent); }
  .account-avatar {
    width: 1.6rem;
    height: 1.6rem;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--brand-grad);
    color: var(--accent-ink);
    font-size: 0.78rem;
    font-weight: 650;
  }
  .account-chip-text { display: grid; text-align: left; line-height: 1.15; }
  .account-plan { font-size: 0.78rem; font-weight: 600; }
  .account-left { font-size: 0.67rem; color: var(--text-3); }
  .account-left.low { color: var(--warn); }

  /* ======================================================================
     Account: the dialog
     ====================================================================== */
  .account-modal { max-width: 30rem; }
  .account-modal .account-eyebrow::before { display: none; }
  .account-modal h2 { margin-bottom: 0.35rem; letter-spacing: -0.02em; }
  .account-reason {
    color: var(--text-2);
    font-size: 0.88rem;
    line-height: 1.55;
    margin: 0.55rem 0 0;
    padding-left: 0.8rem;
    border-left: 2px solid var(--accent);
  }
  .account-perks { display: grid; gap: 0.45rem; margin: 1rem 0 1.1rem; }
  .account-perks li {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    font-size: 0.88rem;
    color: var(--text-2);
  }
  .account-perks li::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--signal);
    translate: 0 -1px;
  }
  .account-form { display: grid; gap: 0.7rem; }
  .account-form .field { display: grid; gap: 0.3rem; }
  .account-form .field > span {
    font-family: var(--font-mono);
    font-size: 0.66rem;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--text-3);
  }
  .account-form input {
    width: 100%;
    padding: 0.55rem 0.8rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--line-2);
    background: var(--bg-sunk);
  }
  .account-form .btn-primary { justify-content: center; width: 100%; }
  .account-error { color: var(--danger); font-size: 0.84rem; min-height: 1.1em; margin: 0; }
  .account-error:empty { min-height: 0; }
  .account-switch { color: var(--text-3); font-size: 0.84rem; margin-top: 0.9rem; }
  .account-switch:empty { margin: 0; }
  .account-fineprint { color: var(--text-3); font-size: 0.78rem; line-height: 1.55; margin-top: 0.9rem; }
  .account-note { color: var(--text-2); font-size: 0.88rem; line-height: 1.55; margin: 0.6rem 0; }
  .account-body { display: grid; gap: 0.2rem; }
  .account-body .btn-secondary { justify-self: start; margin-top: 0.9rem; }
  .account-upgrade {
    margin-top: 1rem;
    padding: 1rem;
    border-radius: var(--r-md);
    border: 1px solid var(--line);
    background: var(--surface-2);
  }
  .account-upgrade h3 { font-size: 1rem; letter-spacing: -0.01em; }
  .account-upgrade .account-perks { margin: 0.7rem 0; }
  .upgrade-form { display: flex; gap: 0.5rem; margin-top: 0.7rem; }
  .upgrade-form input {
    flex: 1;
    min-width: 0;
    padding: 0.5rem 0.85rem;
    border-radius: var(--r-full);
    border: 1px solid var(--line-2);
    background: var(--bg-sunk);
    font-family: var(--font-mono);
    font-size: 0.82rem;
  }

  /* ======================================================================
     The save dialog — one form, on the Studio and the synth alike
     ====================================================================== */
  .save-modal { max-width: 32rem; }
  .save-modal textarea {
    padding: 0.6rem 0.9rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--line-2);
    background: var(--bg-sunk);
    color: inherit;
    font: inherit;
    font-size: 0.9rem;
    resize: vertical;
  }
  .field-hint { color: var(--text-3); font-style: normal; font-weight: 400; text-transform: none; letter-spacing: 0; }
  .save-public {
    display: flex;
    gap: 0.65rem;
    align-items: start;
    padding: 0.75rem 0.9rem;
    border-radius: var(--r-md);
    border: 1px solid var(--line);
    background: var(--surface-2);
    cursor: pointer;
  }
  .save-public input { margin-top: 0.15rem; accent-color: var(--accent); }
  .save-public strong { display: block; font-size: 0.9rem; }
  .save-public em { display: block; color: var(--text-3); font-style: normal; font-size: 0.78rem; line-height: 1.5; margin-top: 0.15rem; }
  .save-switch { color: var(--text-3); font-size: 0.82rem; margin-top: 0.8rem; }
  .save-links { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.9rem; }
  .save-url { display: block; margin-top: 0.5rem; font-size: 0.78rem; word-break: break-all; }

  /* ======================================================================
     Browse and account: the library pages
     ====================================================================== */
  .library-main { max-width: 1180px; }
  .library-head { max-width: var(--measure); }
  .library-head h1 { font-size: clamp(1.8rem, 4vw, 2.6rem); letter-spacing: -0.025em; }
  .library-head .lede { margin-top: 0.75rem; }
  .library-head p + p { margin-top: 1.1rem; }
  .library-head .btn-primary + .btn-secondary { margin-left: 0.5rem; }

  .library-search {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin-top: clamp(1.5rem, 4vh, 2.25rem);
  }
  .library-search-field { flex: 1 1 18rem; display: grid; }
  .library-search input {
    width: 100%;
    padding: 0.6rem 1rem;
    border-radius: var(--r-full);
    border: 1px solid var(--line-2);
    background: var(--surface);
    color: inherit;
    font: inherit;
    font-size: 0.9rem;
    box-shadow: var(--shadow-1);
  }
  .library-kinds { display: flex; gap: 0.35rem; }
  /* The selected filter reads as pressed, not merely hovered. */
  .chip.is-on {
    color: var(--accent-ink);
    background: var(--accent);
    border-color: var(--accent);
  }
  .chip.is-on:hover { color: var(--accent-ink); }

  .library-status { color: var(--text-2); font-size: 0.86rem; margin-top: 1rem; min-height: 1.3em; }
  .library-status.error { color: var(--danger); }

  .library-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
    gap: 1rem;
    margin-top: 0.9rem;
  }
  .library-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    padding: 1.05rem 1.15rem 1rem;
    border-radius: var(--r-lg);
    border: 1px solid var(--line);
    background: var(--surface);
    box-shadow: var(--shadow-1), var(--bevel);
    translate: 0 var(--lift, 0);
    transition: translate var(--dur-2) var(--ease-spring), border-color var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
  }
  .library-card:hover { --lift: -3px; border-color: var(--accent); box-shadow: var(--shadow-2), var(--bevel); }
  .library-card-link { display: grid; gap: 0.4rem; color: inherit; text-decoration: none; }
  .library-card-link:hover .library-card-title { color: var(--accent); }
  .library-card-title {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: -0.015em;
    transition: color var(--dur-2) var(--ease-out);
  }
  .library-kind,
  .library-visibility {
    display: inline-block;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.18rem 0.55rem;
    border-radius: var(--r-full);
    border: 1px solid var(--line-2);
    color: var(--text-3);
  }
  .library-kind[data-kind="song"] { color: var(--accent); border-color: var(--accent); }
  .library-kind[data-kind="patch"] { color: var(--accent-2); border-color: var(--accent-2); }
  .library-visibility { position: absolute; top: 1.05rem; right: 1.15rem; }
  .library-visibility[data-public="true"] { color: var(--signal); border-color: var(--signal); }
  .library-meta { color: var(--text-2); font-size: 0.82rem; font-family: var(--font-mono); }
  .library-desc { color: var(--text-2); font-size: 0.86rem; line-height: 1.5; }
  .library-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; }
  .library-tag {
    font-size: 0.72rem;
    color: var(--text-3);
    background: var(--surface-2);
    border-radius: var(--r-full);
    padding: 0.15rem 0.5rem;
  }
  .library-byline {
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
    color: var(--text-3);
    font-size: 0.76rem;
    margin-top: auto;
    padding-top: 0.2rem;
  }
  .library-open { color: var(--accent); font-size: 0.83rem; font-weight: 550; text-decoration: none; }
  .library-open .arrow { display: inline-block; transition: translate var(--dur-2) var(--ease-spring); }
  .library-card:hover .library-open .arrow { translate: 3px 0; }
  .library-actions { display: flex; flex-wrap: wrap; gap: 0.35rem; }
  .library-actions .btn-secondary.danger:hover { border-color: var(--danger); color: var(--danger); }
  .library-more { display: flex; justify-content: center; margin-top: 1.25rem; }

  .account-panel { margin-top: clamp(1.5rem, 4vh, 2.25rem); }
  .account-panel-body { display: grid; gap: 0.9rem; padding-top: 0.4rem; }
  .account-name-form { display: flex; flex-wrap: wrap; align-items: end; gap: 0.6rem; }
  .account-name-form .field { display: grid; gap: 0.3rem; flex: 1 1 18rem; }
  .account-name-form .field > span { font-size: 0.78rem; color: var(--text-2); }
  .account-name-form input {
    width: 100%;
    padding: 0.5rem 0.9rem;
    border-radius: var(--r-full);
    border: 1px solid var(--line-2);
    background: var(--bg-sunk);
    color: inherit;
    font: inherit;
    font-size: 0.88rem;
  }
  .account-name-form .account-note { flex-basis: 100%; margin: 0; font-size: 0.82rem; }
  .account-name-form .account-note.error { color: var(--danger); }

  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@layer motion {
  /* Every animation below is opt-in on prefers-reduced-motion: the layout,
     the colours and the depth are all still there without it. */

  @supports (animation-timeline: scroll()) {
    .scroll-progress {
      animation: progress-grow linear both;
      animation-timeline: scroll(root block);
    }
  }
  @keyframes progress-grow { to { scale: 1 1; } }

  @media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }

    /* The ambient wash drifts slowly enough that you notice it only if you
       stop and look */
    .ambient-glow { animation: drift 34s var(--ease-in-out) infinite alternate; }

    /* Sections rise as they enter — scroll-driven, so it runs off the main
       thread and stays glued to the scrollbar */
    @supports (animation-timeline: view()) {
      main > section:not(.hero):not(.synth-panel),
      .bento li,
      .gear-card {
        animation: rise-in both;
        animation-timeline: view();
        animation-range: entry 5% entry 42%;
      }
      /* The instrument is above the fold; it must be there on paint */
      .hero > * {
        animation: rise-in both var(--dur-4) var(--ease-out);
        animation-timeline: auto;
      }
      .hero h1 { animation-delay: 0.04s; }
      .hero .value-strip { animation-delay: 0.1s; }
    }

    /* Entry animation for the dialog, including the discrete display swap —
       @starting-style is what makes an element animate *in*, not just out */
    dialog {
      transition:
        opacity var(--dur-3) var(--ease-out),
        translate var(--dur-3) var(--ease-spring),
        scale var(--dur-3) var(--ease-spring),
        display var(--dur-3) allow-discrete,
        overlay var(--dur-3) allow-discrete;
      opacity: 0;
      scale: 0.96;
      translate: 0 8px;
    }
    dialog[open] { opacity: 1; scale: 1; translate: 0 0; }
    @starting-style {
      dialog[open] { opacity: 0; scale: 0.96; translate: 0 8px; }
    }
    dialog::backdrop {
      transition: opacity var(--dur-3) var(--ease-out), display var(--dur-3) allow-discrete, overlay var(--dur-3) allow-discrete;
      opacity: 0;
    }
    dialog[open]::backdrop { opacity: 1; }
    @starting-style { dialog[open]::backdrop { opacity: 0; } }
  }

  @keyframes rise-in {
    from { opacity: 0; translate: 0 18px; }
    to   { opacity: 1; translate: 0 0; }
  }
  @keyframes drift {
    from { transform: translate3d(-2%, -1%, 0) scale(1); }
    to   { transform: translate3d(2%, 2%, 0) scale(1.08); }
  }

  /* ---- View transitions ----
     Cross-document navigation gets a short cross-fade; the brand mark and
     the nav pill are shared elements, so they move instead of blinking. */
  @media (prefers-reduced-motion: no-preference) {
    ::view-transition-old(root) { animation: vt-out 0.2s var(--ease-out) both; }
    ::view-transition-new(root) { animation: vt-in 0.28s var(--ease-out) both; }
    ::view-transition-group(brand),
    ::view-transition-group(nav-pill) { animation-duration: 0.32s; animation-timing-function: var(--ease-spring); }
  }
  @keyframes vt-out { to { opacity: 0; } }
  @keyframes vt-in { from { opacity: 0; translate: 0 8px; } }

  /* The theme swap: a circle wiping out from the toggle. The old frame is
     held still and the new one is clipped over it — the clip itself is
     animated from JS, which is the only way to know where the button was. */
  html.theme-switching::view-transition-old(root),
  html.theme-switching::view-transition-new(root) {
    animation: none;
    mix-blend-mode: normal;
  }
  html.theme-switching::view-transition-old(root) { z-index: 0; }
  html.theme-switching::view-transition-new(root) { z-index: 1; }
}
