:root{
  --bg:oklch(15.5% .008 265);--s1:oklch(19% .009 265);--s2:oklch(22.5% .01 265);--s3:oklch(27% .012 265);
  --line:oklch(28.5% .012 265);--line2:oklch(36% .014 265);
  /* Field edges are an affordance, not decoration, so they get their own step
     that clears 3:1 against every surface a control can sit on. --line stays
     reserved for dividers, where a low ratio is intentional. */
  --line-in:oklch(55% .014 265);
  /* The scrollbar thumb is an affordance, not a divider, so it takes the field
     step rather than --line. Resting at 4.04:1 it is findable without competing
     with the accent, and it brightens on hover so the state is visible. */
  --sb-thumb:var(--line-in);--sb-thumb-hi:var(--tx3);--sb-thumb-on:var(--tx2);
  --tx:oklch(95% .006 265);--tx2:oklch(73% .012 265);--tx3:oklch(66% .012 265);
  --acc:oklch(72% .17 45);--acc-hi:oklch(77% .16 45);--acc-lo:oklch(30% .07 45);--acc-ink:oklch(21% .045 45);
  --blue:oklch(70% .13 268);--blue-lo:oklch(30% .06 268);
  --ok:oklch(78% .15 158);--ok-lo:oklch(29% .05 158);
  --warn:oklch(84% .14 85);--warn-lo:oklch(31% .05 85);
  --err:oklch(68% .18 25);--err-lo:oklch(29% .07 25);
  --c-drums:var(--acc);--c-bass:oklch(68% .16 305);--c-melody:oklch(70% .13 268);--c-chords:oklch(76% .14 158);--c-fx:oklch(83% .13 85);--c-vox:oklch(73% .16 355);
  --r-sm:6px;--r:8px;--r-lg:12px;
  --ease:cubic-bezier(.22,1,.36,1);
  --mono:'Geist Mono',ui-monospace,SFMono-Regular,monospace;
  --player:72px;--side:224px;
}
*{box-sizing:border-box}
html{margin:0;min-height:100%;overflow-x:hidden;overflow-y:scroll;scroll-padding-bottom:1px}
body{margin:0;min-height:100dvh;background:var(--bg);color:var(--tx);font:400 15px/1.55 Geist,-apple-system,BlinkMacSystemFont,system-ui,sans-serif;letter-spacing:.008em;-webkit-font-smoothing:antialiased}
button,input,select,textarea{font:inherit;color:inherit;letter-spacing:inherit}
button{cursor:pointer;background:none;border:0;padding:0}
a{color:inherit}
/* WCAG 2.4.1 bypass link. Off-screen rather than display:none, so it stays in
   the tab order, and it comes back the moment it takes focus. The 44px is a
   floor, not a target: padding plus a 1px border lands at 43.7px otherwise,
   which the project's own sweep counts as under the bar. */
.skip{position:absolute;left:-9999px;top:0;z-index:100;min-height:44px;display:inline-flex;align-items:center;padding:0 16px;background:var(--s1);color:var(--tx);border:1px solid var(--line2);border-radius:0 0 var(--r) 0;font-size:14px;font-weight:500}
.skip:focus{left:0}
/* Present to the accessibility tree, absent from the page. Clipped rather than
   display:none or visibility:hidden, both of which take the node out of the
   tree and silence it. 1px is enough to keep it out of the flow. */
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
/* A skip target is a container, not a control, and the default focus ring draws
   a 2px line around it: on the marketing page that was a 1200px outline down
   2171px of document. :focus-visible cannot separate the two cases, because the
   programmatic .focus() the skip link performs also counts as keyboard focus. */
#root:focus,#root main:focus,#root .content:focus,#root h1:focus,.panel:focus{outline:none}
/* The replacement the rule above owes, and the R-32 pairing: an inset shadow
   marks the region reached without drawing a line around the whole page. */
#root:focus,#root main:focus,#root .content:focus,#root h1:focus,.panel:focus{box-shadow:inset 0 0 0 2px var(--blue-lo)}
:focus-visible{outline:2px solid var(--blue);outline-offset:2px;border-radius:4px}
h1,h2,h3,h4{text-wrap:balance;margin:0;font-weight:600;letter-spacing:-.02em}
/* text-wrap:balance does not break an unbreakable token, so a long single-word
   title or an unspaced identifier in a heading pushes the page sideways. With
   html{overflow-x:hidden} the excess is then unreachable rather than merely
   off-screen. Break the token rather than let it dictate the page width. */
h1,h2,h3,h4,.lt td.t{overflow-wrap:anywhere}
p{margin:0;text-wrap:pretty}
svg.lucide{width:16px;height:16px;stroke-width:1.8;flex:none}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums;letter-spacing:0}
.muted{color:var(--tx2)}.dim{color:var(--tx3)}
.eyebrow{font-size:12px;letter-spacing:.09em;text-transform:uppercase;color:var(--tx3);font-weight:500}
/* An identifier inside an eyebrow keeps its own case: uppercasing a class
   name turns TrackResource into one unreadable word. */
.eyebrow code{font:500 11.5px/1.4 var(--mono);letter-spacing:0;text-transform:none;color:var(--tx2)}

/* ============ scrollbars ============ */
/* The default bar is a square block that reads as a second border on every
   pane edge. These replace it with a rounded thumb inset in a transparent
   track, so the divider each pane already draws is the only line on screen.
   Firefox gets the same result from two properties, and the pseudo-elements
   below cover Chromium and WebKit. */
html{scrollbar-width:thin;scrollbar-color:var(--sb-thumb) transparent}
/* Only on a fine pointer. A coarse one gets overlay scrollbars, and forcing a
   styled one there would take a permanent 10px out of a phone layout. */
@media (pointer:fine){
  ::-webkit-scrollbar{width:10px;height:10px}
  ::-webkit-scrollbar-track{background:transparent}
  /* The transparent border insets the thumb without needing a wrapper, so the
     painted bar is 6px inside a 10px track. */
  ::-webkit-scrollbar-thumb{background:var(--sb-thumb);background-clip:padding-box;border:2px solid transparent;border-radius:999px}
  ::-webkit-scrollbar-thumb:hover{background:var(--sb-thumb-hi);background-clip:padding-box;border:2px solid transparent}
  ::-webkit-scrollbar-thumb:active{background:var(--sb-thumb-on);background-clip:padding-box;border:2px solid transparent}
  ::-webkit-scrollbar-corner{background:transparent}
  /* Chromium paints its stepper arrows on a styled bar unless the button is
     stripped of its appearance. They duplicate the wheel and the keyboard, and
     on a 10px track they read as artefacts. `display:none` alone is ignored,
     so the appearance has to go as well. */
  ::-webkit-scrollbar-button{-webkit-appearance:none;appearance:none;background:none;border:0}
  ::-webkit-scrollbar-button:single-button{display:none}
}

/* controls */
/* WCAG 1.4.11: a control boundary needs 3:1 against its own fill. --line is
   1.19:1 on --s2 and --line2 only 1.57:1, so neither can draw an edge. --line-in
   already exists for exactly this threshold (3.52:1 here, 4.03:1 on the page a
   transparent .chip sits on) and was added for fields; buttons and chips are the
   same kind of affordance. .btn.pri is already 7.98:1 and stays borderless. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:36px;padding:0 14px;border-radius:var(--r);background:var(--s2);border:1px solid var(--line-in);font-weight:500;font-size:14px;white-space:nowrap;transition:background .15s var(--ease),border-color .15s var(--ease),color .15s}
.btn:hover{background:var(--s3);border-color:var(--tx3)}
.btn:active{transform:translateY(1px)}
.btn.pri{background:var(--acc);color:var(--acc-ink);border-color:transparent}
.btn.pri:hover{background:var(--acc-hi)}
.btn.sm{height:30px;padding:0 10px;font-size:13px;gap:6px}
.btn.lg{height:44px;padding:0 20px;font-size:15px}
.btn.ghost{background:transparent;border-color:transparent;color:var(--tx2)}
.btn.ghost:hover{background:var(--s2);color:var(--tx)}
.btn:disabled{opacity:.4;cursor:not-allowed;transform:none}
.ib{width:32px;height:32px;display:inline-grid;place-items:center;border-radius:var(--r);color:var(--tx2);transition:background .15s,color .15s;flex:none}
.ib:hover{background:var(--s2);color:var(--tx)}
.ib.on{color:var(--acc)}
.ib:disabled{opacity:.35;cursor:not-allowed}
.seg{display:inline-flex;background:var(--bg);border:1px solid var(--line);border-radius:var(--r);padding:2px;gap:2px}
.seg button{height:28px;padding:0 10px;border-radius:6px;font-size:13px;color:var(--tx2);transition:background .15s,color .15s}
.seg button:hover{color:var(--tx)}
/* The selected fill is 1.29:1 against the track, so on its own it does not
   meet 3:1 for a state indicator and DESIGN.md forbids colour as the only
   status signal. The inset ring is a shape cue that reads at 4.04:1, matching
   the rule already used at .ms button below. */
.seg button.on{background:var(--s3);color:var(--tx);box-shadow:inset 0 0 0 1px var(--line-in)}
.chip{display:inline-flex;align-items:center;gap:6px;height:30px;padding:0 12px;border-radius:999px;border:1px solid var(--line-in);font-size:13px;color:var(--tx2);background:transparent;transition:all .15s var(--ease)}
.chip:hover{border-color:var(--tx3);color:var(--tx)}
.chip.on{background:var(--acc-lo);border-color:var(--acc);color:var(--tx)}
.tag{display:inline-flex;align-items:center;gap:4px;height:20px;padding:0 7px;border-radius:4px;background:var(--s2);font-size:12px;color:var(--tx2);white-space:nowrap}
.tag.ok{background:var(--ok-lo);color:var(--ok)}
.tag.acc{background:var(--acc-lo);color:var(--acc-hi)}
.tag.warn{background:var(--warn-lo);color:var(--warn)}
input[type=text],input[type=email],input[type=password],input[type=number],input[type=search],select,textarea{background:var(--bg);border:1px solid var(--line-in);border-radius:var(--r);padding:0 10px;height:34px;outline:none;transition:border-color .15s,box-shadow .15s}
/* A brighter resting border narrows the jump to --blue, so focus is stated with
   a ring as well as a tint. Losing the ring would have made focus harder to see
   than before, not easier. */
input:focus,select:focus,textarea:focus{border-color:var(--blue);box-shadow:0 0 0 2px var(--blue-lo)}
textarea{padding:10px 12px;height:auto;resize:none;line-height:1.5;width:100%}
select{appearance:none;padding-right:26px;background-image:linear-gradient(45deg,transparent 50%,var(--tx3) 50%),linear-gradient(135deg,var(--tx3) 50%,transparent 50%);background-position:calc(100% - 13px) 15px,calc(100% - 9px) 15px;background-size:4px 4px;background-repeat:no-repeat}
input[type=range]{accent-color:var(--acc);width:100%}
input[type=checkbox]{accent-color:var(--acc);width:15px;height:15px}
.switch{position:relative;width:32px;height:18px;border-radius:999px;background:var(--s3);transition:background .2s var(--ease);flex:none}
.switch::after{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:var(--tx2);transition:transform .2s var(--ease),background .2s}
.switch.on{background:var(--acc)}
.switch.on::after{transform:translateX(14px);background:var(--acc-ink)}
.flash{animation:flash 1s var(--ease)}
@keyframes flash{0%{box-shadow:0 0 0 3px var(--acc);border-color:var(--acc)}100%{box-shadow:0 0 0 0 transparent}}

.model{display:none}
.model + .tag{margin-left:auto}

/* cursor:pointer is the seek affordance, so it belongs only on a waveform that
   can actually be seeked. The marketing illustrations pass art:true and carry no
   data-act, so they are pictures and must not look clickable. */
.wv{position:relative;width:100%;--p:0%}
.wv[data-act]{cursor:pointer}
.wv svg{position:absolute;inset:0;width:100%;height:100%;display:block}
.wv .base{fill:var(--line2)}
.wv .fill{fill:var(--acc);clip-path:inset(0 calc(100% - var(--p)) 0 0)}
.wv.baking .fill{fill:var(--tx3)}
.wv.baking .base{fill:var(--s2)}

/* ===== marketing ===== */
/* The player is fixed to the bottom and only exists on workspace views, so the
   marketing pages must not reserve room for it. An unconditional
   padding-bottom:var(--player) left a 64px empty band under the pricing and
   home pages, with nothing in it, and the sticky nav sat on top of a page whose
   own height no longer matched its content. The client toggles .has-player on
   <html> when it actually renders one, so the reservation follows the player
   instead of the other way round. */
.mk{min-height:100%}
.has-player .mk{padding-bottom:var(--player)}
.mk-nav{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:28px;height:64px;padding:0 max(24px,calc((100vw - 1200px)/2));background:var(--bg);border-bottom:1px solid var(--line)}
.logo{display:flex;align-items:center;gap:10px;font-weight:600;letter-spacing:-.02em;font-size:16px}
.logo .word{white-space:nowrap}
/* flex:0 0 auto, not the default 0 1 auto. The mark was a shrinkable flex item,
   so whenever the nav row ran out of room its width collapsed to the bars'
   content width (4x3 + 3x2 = 18px) while the height stayed fixed at 28px. The
   result was an 18x28 box, ratio 0.64, with the bars touching both edges: a
   logo that reads as vertically stretched. Nothing may shrink it. */
.logo-mark{flex:0 0 auto;width:26px;height:26px;border-radius:7px;background:var(--acc);display:grid;place-items:center}
.logo-mark span{display:flex;gap:2px;align-items:center}
.logo-mark i{display:block;width:3px;background:var(--acc-ink);border-radius:2px}
.mk-links{display:flex;gap:4px;align-items:center}
.mk-links button,.mk-links a{padding:6px 10px;border-radius:6px;color:var(--tx2);font-size:14px;text-decoration:none;box-shadow:inset 0 0 0 1px transparent;transition:background .15s var(--ease),color .15s var(--ease)}
.mk-links button:hover,.mk-links a:hover{color:var(--tx);background:var(--s1)}
/* The mode switch borrows the workspace .seg shape, but the flat .mk-links rule
   above would otherwise restyle its two buttons and undo the track: the
   specificity is equal, so the later rule here wins and the buttons keep the
   segmented height, the smaller type and no own hover fill. The enclosing
   border and 2px gap are what tell the eye these two are one control. */
.mk-links .mk-mode{margin-right:6px}
.mk-links .mk-mode button{padding:0 10px;border-radius:6px;font-size:13px;background:transparent;box-shadow:none}
.mk-links .mk-mode button:hover{background:transparent;color:var(--tx)}
/* Current section is a state change, not a call to action: DESIGN.md reserves
   warm orange for actions, so this uses the surface-hover step plus a ring. */
.mk-links button.on{color:var(--tx);background:var(--s3);box-shadow:inset 0 0 0 1px var(--line2)}
.mk-burger{display:none;width:44px;height:44px;place-items:center;border-radius:6px;color:var(--tx2);flex:none}
.mk-burger:hover{color:var(--tx);background:var(--s1)}
.mk-burger svg{width:20px;height:20px}
.mk-burger .ic-closed{display:none}
.mk-burger[aria-expanded=true] .ic-open{display:none}
.mk-burger[aria-expanded=true] .ic-closed{display:block}
.mk-nav .right{margin-left:auto;display:flex;gap:8px}
.wrap{max-width:1200px;margin:0 auto;padding:0 24px}
.hero{padding:88px 0 68px;display:grid;grid-template-columns:minmax(0,1fr) minmax(280px,420px);gap:48px;align-items:center;justify-items:stretch}
.hero-copy{display:grid;gap:20px;align-content:start}
.hero h1{font-size:clamp(40px,5.5vw,68px);line-height:1.02;letter-spacing:-.035em;max-width:11ch;font-weight:600}
.hero .sub{font-size:18px;color:var(--tx2);max-width:44ch}
.hero-box{width:100%;background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);padding:6px;box-shadow:0 24px 70px oklch(8% .01 265 / .28)}
.hero-box textarea{background:transparent;border:0;font-size:17px;padding:16px 16px 8px;min-height:84px}
.hero-box .row{display:flex;align-items:center;gap:8px;padding:8px 8px 6px 10px;flex-wrap:wrap}
.hero-box .row .btn.pri{margin-left:auto}
.hero-art{position:relative;min-height:300px;padding:18px;background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden}
.hero-art:before{content:"";position:absolute;inset:0;background:linear-gradient(135deg,oklch(22% .02 45 / .5),transparent 52%);pointer-events:none}
.hero-art .art-head{display:flex;justify-content:space-between;align-items:center;position:relative;color:var(--tx2);font-size:12px}
.hero-art .art-wave{margin-top:70px;position:relative}
.hero-art .art-wave .wv{height:82px}
.hero-art .art-stems{display:grid;gap:10px;margin-top:22px;position:relative}
.hero-art .art-stem{display:grid;grid-template-columns:70px 1fr;align-items:center;gap:10px;color:var(--tx2);font-size:11px}
.hero-art .art-stem .wv{height:18px}
.hero-art .art-foot{display:flex;justify-content:space-between;align-items:center;margin-top:24px;padding-top:14px;border-top:1px solid var(--line);position:relative;color:var(--tx2);font-size:12px}
.hero-art .art-foot b{color:var(--tx);font-weight:500}
.try{display:flex;gap:8px;flex-wrap:wrap;align-items:center;font-size:13px;color:var(--tx3)}
.try .chip{height:28px;padding:0 10px;font-size:12px}
.section{padding:72px 0;border-top:1px solid var(--line)}
.section-head{display:flex;justify-content:space-between;align-items:end;gap:24px;margin-bottom:32px}
.section-head h2{font-size:32px;line-height:1.1}
.ex-list{display:grid}
.ex-row{display:grid;grid-template-columns:40px minmax(160px,220px) 1fr auto auto;align-items:center;gap:20px;padding:14px 0;border-bottom:1px solid var(--line)}
.ex-row.featured{padding:18px 0 20px;grid-template-columns:48px minmax(190px,250px) 1fr auto auto}
.ex-row.featured .play{width:48px;height:48px}
.ex-row.featured .wv{min-width:0}
.ex-row .ttl{font-weight:500}
.ex-row .ttl small{display:block;color:var(--tx3);font-size:13px;font-weight:400}
.ex-stems{grid-column:2 / -1;display:grid;gap:6px;padding:4px 0 8px}
.ex-stem{display:grid;grid-template-columns:90px 1fr;align-items:center;gap:12px;font-size:12px;color:var(--tx2)}
.ex-stem .wv{height:18px}
.play{width:40px;height:40px;border-radius:50%;background:var(--s2);display:grid;place-items:center;color:var(--tx);transition:background .15s,transform .15s var(--ease);flex:none}
.play:hover{background:var(--s3)}
.play.on{background:var(--acc);color:var(--acc-ink)}
.play.sm{width:32px;height:32px}
.play svg{width:14px;height:14px}
.split{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden}
.split > div{background:var(--bg);padding:40px;display:grid;gap:20px;align-content:start}
.split h2,.split h3{font-size:26px;line-height:1.15}
.split ul{margin:0;padding:0;list-style:none;display:grid;gap:10px;color:var(--tx2)}
.split li{display:flex;gap:10px;align-items:flex-start}
.split li svg{color:var(--acc);margin-top:3px}
.demo-stems{display:grid;gap:5px;padding:16px;background:var(--s1);border-radius:var(--r)}
.demo-stems .ln{display:grid;grid-template-columns:64px 1fr;gap:10px;align-items:center;font-size:11px;color:var(--tx3)}
.demo-stems .ln .wv{height:16px}
.pianoroll{position:relative;height:74px;background:repeating-linear-gradient(0deg,var(--s1) 0 9px,var(--bg) 9px 10px);border-radius:var(--r);overflow:hidden}
.pianoroll b{position:absolute;height:8px;border-radius:2px;background:var(--c-melody)}
.demo-video{background:var(--s1);border-radius:var(--r);padding:16px;display:grid;gap:8px}
.demo-video .row{display:grid;grid-template-columns:52px 1fr;gap:10px;align-items:center;font-size:11px;color:var(--tx3)}
.scenes{display:flex;height:34px;gap:2px;border-radius:4px;overflow:hidden}
.scenes span{flex:1}
.endflag{display:flex;justify-content:flex-end;font-size:11px;color:var(--ok);gap:6px;align-items:center}
.trust{display:grid;grid-template-columns:repeat(2,1fr);gap:32px}
.trust div{display:grid;gap:8px;align-content:start}
.trust svg{color:var(--ok);width:20px;height:20px}
.trust b{font-weight:600}
.trust p{color:var(--tx2);font-size:14px}
table.cmp{width:100%;border-collapse:collapse;font-size:14px}
table.cmp th,table.cmp td{text-align:left;padding:14px 16px;border-bottom:1px solid var(--line)}
table.cmp th{font-weight:500;color:var(--tx2);font-size:13px}
table.cmp td:first-child{color:var(--tx2)}
table.cmp .us{background:var(--s1)}
table.cmp th.us{color:var(--tx);font-weight:600}
.yes{color:var(--ok)}.no{color:var(--tx3)}
.mk-foot{padding:48px 0 32px;border-top:1px solid var(--line);color:var(--tx3);font-size:13px;display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap}

/* pricing */
.price-head{padding:72px 0 40px;display:grid;gap:16px;justify-items:center;text-align:center}
.price-head h1{font-size:clamp(34px,4.5vw,52px);line-height:1.05}
/* The plan is the subject of the page and the caveat is not, so they are not
   two equal halves. Before this the two panels were the shared .split, a 1px
   hairline pair at identical weight: the caveat got the same box, the same
   padding and the same heading size as the plan, so the page read as a
   comparison it never offers. The plan takes two thirds and the caveat drops to
   a supported aside. The 1px divider is the split's own border trick, replaced
   here with a real surface step from DESIGN.md. */
.price-body{border-top:0;padding-top:8px}
.price-grid{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:24px;align-items:start}
.price-card{background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);padding:40px;display:grid;gap:20px;align-content:start}
.price-card h2{font-size:26px;line-height:1.15}
.price-side{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);padding:28px;display:grid;gap:12px;align-content:start}
.price-side h3{font-size:17px;line-height:1.3;font-weight:600}
/* The one number on the page. It was a sentence in a muted paragraph; here the
   amount is display type and "/month" sits beside it as a quieter unit, so the
   eye lands on the figure before the feature list. */
.price-fig{display:flex;align-items:baseline;gap:8px;margin:0}
.price-fig .amt{font-size:clamp(40px,5vw,56px);line-height:1;font-weight:600;letter-spacing:-.03em;color:var(--tx)}
.price-fig .per{font-size:17px;color:var(--tx3)}
.price-sub{margin:0}
.price-list{margin:0;padding:0;list-style:none;display:grid;gap:10px;color:var(--tx2)}
.price-list li{display:flex;gap:10px;align-items:flex-start}
.price-list li svg{color:var(--acc);margin-top:3px;flex:0 0 auto}
.price-note{margin:0;font-size:13px;color:var(--tx3)}
table.plans{width:100%;border-collapse:separate;border-spacing:0;font-size:14px}
table.plans th,table.plans td{padding:14px 20px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}
table.plans td:first-child{color:var(--tx2);width:26%}
table.plans .hl{background:var(--s1)}
table.plans thead th{padding:28px 20px 24px;border-bottom:1px solid var(--line2)}
table.plans thead .hl{border-radius:var(--r-lg) var(--r-lg) 0 0;box-shadow:inset 0 2px 0 var(--acc)}
.plan-name{font-size:15px;font-weight:600;display:flex;gap:8px;align-items:center}
.plan-price{font-size:40px;font-weight:600;letter-spacing:-.03em;margin:8px 0 2px;font-variant-numeric:tabular-nums}
.plan-price small{font-size:14px;color:var(--tx3);font-weight:400;letter-spacing:0}
.plan-note{font-size:13px;color:var(--tx3);min-height:20px;margin-bottom:16px}
.faq{max-width:760px;margin:0 auto;display:grid}
.faq details{border-bottom:1px solid var(--line);padding:18px 0}
.faq summary{cursor:pointer;font-weight:500;list-style:none;display:flex;justify-content:space-between}
.faq summary::after{content:"+";color:var(--tx3);font-size:18px}
.faq details[open] summary::after{content:"−"}
.faq p{color:var(--tx2);margin-top:10px;max-width:65ch}

/* onboarding */
.onb{min-height:100vh;display:grid;grid-template-rows:64px 1fr}
.onb-top{display:flex;align-items:center;justify-content:space-between;padding:0 24px;border-bottom:1px solid var(--line)}
.onb-body{display:grid;place-items:start center;padding:72px 24px}
.onb-inner{width:min(640px,100%);display:grid;gap:28px}
.steps{display:flex;gap:6px}
.steps span{width:28px;height:3px;border-radius:2px;background:var(--s3)}
.steps span.on{background:var(--acc)}
.onb h1{font-size:34px;line-height:1.1}
.opt-list{display:grid;gap:10px}
.opt{display:grid;grid-template-columns:44px 1fr auto;gap:16px;align-items:center;text-align:left;padding:18px;border:1px solid var(--line);border-radius:var(--r-lg);transition:border-color .15s,background .15s}
.opt:hover{border-color:var(--line2);background:var(--s1)}
.opt.on{border-color:var(--acc);background:var(--s1)}
.opt .ico{width:44px;height:44px;border-radius:10px;background:var(--s2);display:grid;place-items:center}
.opt .ico svg{width:20px;height:20px}
.opt.on .ico{background:var(--acc);color:var(--acc-ink)}
.opt b{display:block;font-weight:600}
.opt small{color:var(--tx2);font-size:13px}
.opt .radio{width:18px;height:18px;border-radius:50%;border:1.5px solid var(--line2)}
.opt.on .radio{border:5px solid var(--acc)}
.chip-grid{display:flex;flex-wrap:wrap;gap:8px}
.onb-foot{display:flex;justify-content:space-between;align-items:center}

/* ===== app shell ===== */
/* A bare `1fr` track is really minmax(auto,1fr), so it refuses to shrink below
   its content and pushes the whole page wider than the viewport. Every grid in
   the create column chain below is pinned to minmax(0,...) for that reason. */
.app{position:relative;display:grid;grid-template-columns:var(--side-w,var(--side)) minmax(0,1fr);height:calc(100dvh - var(--player))}
/* A public page has no sidebar, so the shell collapses to a single column. */
.app.public{grid-template-columns:minmax(0,1fr)}
/* The public header is a brand block and the auth actions with no search field
   to give up slack, so at 400% zoom its two fixed-width children overflowed a
   360px viewport by 22px and forced a horizontal scroll (WCAG 1.4.10 reflow).
   `.public-brand` carried no rule to shrink and `.top` could not wrap. The header
   wraps now, and the shell's header row grows from its 56px floor to hold the
   second line rather than truncating the wordmark; the workspace top bar, which
   has a search field to give up slack, keeps its fixed 56px row. */
.public .top{flex-wrap:wrap}
.app.public .main{grid-template-rows:minmax(56px,auto) 1fr}
.side{border-right:1px solid var(--line);display:flex;flex-direction:column;padding:14px 10px;gap:4px;background:var(--bg);min-height:0}
.side .logo{padding:6px 8px 18px}
.nav-item{display:flex;align-items:center;gap:10px;height:36px;padding:0 10px;border-radius:var(--r);color:var(--tx2);font-size:14px;font-weight:500;width:100%;transition:background .15s,color .15s}
.nav-item:hover{background:var(--s1);color:var(--tx)}
.nav-item.on{background:var(--s2);color:var(--tx)}
.nav-item .kbd{margin-left:auto}
.kbd{font-family:var(--mono);font-size:11px;color:var(--tx3);border:1px solid var(--line);border-radius:4px;padding:0 5px;line-height:18px}
.side .spacer{flex:1}
.side-head{display:flex;align-items:center;gap:2px;padding-bottom:18px}
.side-head .logo{flex:1;min-width:0;padding:6px 8px}
.side-toggle{width:44px;height:44px;flex:none;margin-right:-6px}
#side-nav{display:flex;flex-direction:column;gap:4px;flex:1;min-height:0}
/* One collapsed width in the product: the icon rail is 64px whether the
   viewport or the user collapsed it. This replaces the 44px second
   definition the rail was carrying; DESIGN.md's Layout section names 64px. */
.app.side-collapsed{grid-template-columns:64px 1fr}
.side.hidden{padding:14px 0}
.side.hidden .side-head{padding-bottom:0;justify-content:center}
.side.hidden .side-head .logo{display:none}
.meter{padding:14px 10px;display:grid;gap:12px;border-top:1px solid var(--line);margin-top:8px}
.meter .m{display:grid;gap:6px;font-size:12px}
.meter .m .top{display:flex;justify-content:space-between;color:var(--tx2)}
.bar{height:4px;background:var(--s3);border-radius:2px;overflow:hidden}
.bar i{display:block;height:100%;background:var(--tx2);border-radius:2px;transform-origin:left;transition:transform .5s var(--ease)}
.bar.low i{background:var(--warn)}
.plan-row{display:flex;justify-content:space-between;align-items:center;font-size:12px}
.main{display:grid;grid-template-rows:56px 1fr;min-width:0;min-height:0}
.top{display:flex;align-items:center;gap:12px;padding:0 20px;border-bottom:1px solid var(--line)}
.top .search{flex:1;max-width:420px;position:relative}
.top .search input{width:100%;padding-left:34px;background:var(--s1)}
.top .search svg{position:absolute;left:11px;top:9px;color:var(--tx3)}
.top .right{margin-left:auto;display:flex;align-items:center;gap:6px}
.avatar{width:30px;height:30px;border-radius:50%;background:oklch(45% .09 268);display:grid;place-items:center;font-size:12px;font-weight:600}
.content{overflow:auto;min-height:0}
/* Discover is the one view that is a plain block inside .content, so nothing
   above it contributes a horizontal gutter: measured at 390px its eyebrow,
   heading, paragraph and Refresh button all started at x=0 while every track
   card carried its own 16px inset. The header sat against the screen edge and
   the cards looked inset by accident. Only the public shell carries it; the
   workspace views own their padding (.panel, .lib-tools, .api) and adding it
   here would double their gutters. */
.app.public .content{padding:0 20px}

/* create */
.create{position:relative;display:grid;grid-template-columns:var(--create-w,400px) minmax(0,1fr);height:100%;min-height:0}
.panel{border-right:1px solid var(--line);overflow:auto;padding:20px 20px 28px;display:grid;gap:22px;align-content:start;min-width:0}
.create-view-switch{grid-template-columns:minmax(0,1fr);align-items:start}
.create-view-switch .seg{justify-self:start;max-width:100%}
.create-view-switch .seg button{min-width:88px;height:36px}
.create-title input{width:100%}
@media (max-width:720px),(pointer:coarse){.create-view-switch .seg button{height:44px}}
.results{overflow:auto;padding:20px 28px 40px;min-width:0}
.lbl{font-size:12px;color:var(--tx2);font-weight:500;display:flex;justify-content:space-between;align-items:center}
.prompt{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);transition:border-color .15s}
.prompt:focus-within{border-color:var(--blue)}
.prompt textarea{border:0;background:transparent;font-size:15px}
.prompt-foot{display:flex;align-items:center;gap:8px;padding:0 8px 8px;font-size:12px;color:var(--tx3);flex-wrap:wrap;min-width:0}
.prompt-foot .hint{margin-left:auto}
.kits{display:flex;gap:6px;flex-wrap:wrap}
.grp{display:grid;gap:12px;min-width:0}
/* This selector changes both the engine and the controls it reveals, so its
   border and surface make the active choice legible before the prompt changes. */
.eng{display:flex;flex-wrap:wrap;gap:8px;min-width:0}
.eng button{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 10px;align-content:start;flex:1 1 150px;min-width:0;padding:12px;border:1px solid var(--line-in);border-radius:var(--r);background:var(--s1);text-align:left;transition:border-color .15s,background .15s}
.eng button:hover{border-color:var(--tx3);background:var(--s2)}
.eng button.on{border-color:var(--blue);background:var(--blue-lo)}
.eng button b{font-size:13px;font-weight:600}
.eng small{grid-column:1 / -1;display:block;overflow-wrap:anywhere;color:var(--tx2);font-size:12px;line-height:1.45}
.eng .cr{grid-column:1 / -1;display:flex;gap:5px;align-items:baseline;color:var(--tx);font-family:var(--mono);font-size:12px}
.eng .cr em{color:var(--tx3);font-family:Geist,-apple-system,BlinkMacSystemFont,system-ui,sans-serif;font-size:12px;font-style:normal}
.eng button.on .cr{color:var(--acc-hi)}

@media (max-width:720px){
  .eng button{flex:1 1 100%}
}

@media (max-width:720px),(pointer:coarse){
  .eng button{min-height:44px;padding:10px 12px}
}

/* Selection is the blue language; the warm accent remains reserved for actions. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Typography stays compact so both choices fit the audio-first parameter rail. */
.eng button b,.eng button small,.eng .cr{min-width:0}

/* Mobile controls stack because each description needs a readable line length. */
.eng button small{max-width:46ch}

/* Both choices keep the same hierarchy; only the selected state changes. */
.eng button.on b{color:var(--tx)}

/* Guard against long translated descriptions stretching the parameter column. */
.eng{overflow-wrap:anywhere}

/* Credit count remains tabular while the explanatory label stays conversational. */
.eng .cr{font-variant-numeric:tabular-nums}

/* The selector uses the established 8px control radius, not another card shape. */
.eng button{box-shadow:none}

/* Keep the selected border visible against the selected surface. */
.eng button.on{border-color:var(--blue)}

/* Loading and disabled states should not make the choice look active. */
.eng button:disabled{cursor:not-allowed;opacity:.55}

/* These labels are content, not an eyebrow or marketing badge. */
.eng button b{text-transform:none;letter-spacing:0}

/* Only the selector is boxed; the rest of the dense form remains border-led. */
.eng button{margin:0}

/* Keep copy from colliding with the credit line on small widths. */
.eng small{white-space:normal}

/* No animation beyond the selected-state transition, consistent with MOTION 1. */
.eng button{transition-duration:.15s}

/* Brand surface hierarchy: panel canvas, raised choice, blue selection. */
.eng button{color:var(--tx)}

/* A narrow desktop rail wraps at the same width as the phone layout. */
@media (max-width:860px){.eng button{flex-basis:100%}}

/* Mouse and keyboard states use one focused outline. */
.eng button:focus{outline:none}
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Ensure button text does not introduce a horizontal scroll track. */
.eng button>*{overflow-wrap:anywhere}

/* Flex items can shrink below their labels only when min-width is explicit. */
.eng button{min-width:0}

/* Selected state is also stated with a border and surface, not color alone. */
.eng button.on{box-shadow:inset 0 0 0 1px var(--blue)}

/* Stop the inner ring doubling the native keyboard outline. */
.eng button:focus:not(:focus-visible){outline:0}

/* Intent: compact side-by-side choices on desktop, full-width readable choices on mobile. */
.eng button{line-height:1.35}

/* Allow the explanatory line to take the full row on both layouts. */
.eng small{grid-column:1 / -1}

/* Keep the selected colour contained within this choice, not spread to the group. */
.eng button.on{background:var(--blue-lo)}

/* Prevent a long sublabel from pushing the cost outside its control. */
.eng .cr{flex-wrap:wrap}

/* More generous touch target in coarse-pointer layouts. */
@media (pointer:coarse){.eng button{min-height:44px}}

/* The selection uses cool blue because DESIGN.md assigns blue to chosen state. */
.eng button.on{color:var(--tx)}

/* Secondary text uses the existing AA text token. */
.eng small{color:var(--tx2)}

/* This selector is a control group, not a feature-card grid. */
.eng button{border-radius:var(--r)}

/* Each option keeps a single border as its resting affordance. */
.eng button:not(.on){box-shadow:none}

/* Long help text wraps without narrowing the credit label. */
.eng small{word-break:normal}

/* The credit text sits on the last line for predictable scanning. */
.eng .cr{align-self:end}

/* No decorative glyphs are added to either choice. */
.eng button::before,.eng button::after{content:none}

/* Maintain the same panel rhythm around this selector. */
.eng{align-items:stretch}

/* Guard against tiny viewports and browser text scaling. */
@media (max-width:360px){.eng button{padding:10px}}

/* Selection outline matches focus without relying on orange. */
.eng button.on{outline-color:var(--blue)}

/* Keep key labels and credit figures from clipping at the narrow breakpoint. */
.eng .cr{overflow-wrap:anywhere}

/* The control's surface remains flat; elevation belongs to dialogs only. */
.eng button{filter:none}

/* Avoid generic pill styling: choices use the design-system control radius. */
.eng button{border-radius:var(--r)}

/* Selected text keeps the normal label hierarchy. */
.eng button.on small{color:var(--tx2)}

/* Honest hierarchy: product name, duration, then credit estimate. */
.eng button b{grid-column:1 / -1}

/* Screen readers receive the pressed state from the button markup. */
.eng button[aria-pressed=true]{border-color:var(--blue);background:var(--blue-lo)}

/* The browser's default focus ring is replaced with the shared design focus ring. */
.eng button:focus{outline:none}

/* Avoid crowding the neighboring form group. */
.eng{margin:0}

/* Let a long duration description wrap without affecting the neighboring choice. */
.eng button small{min-height:2.9em}

/* Consistent alignment across choices with different title lengths. */
.eng button b{min-height:1.35em}

/* Credit rate remains secondary to the option title. */
.eng .cr{font-weight:500}

/* Flat border hierarchy supports the dark audio workspace. */
.eng button{box-shadow:none}

/* The active choice is communicated in border, fill, and aria-pressed. */
.eng button.on{box-shadow:inset 0 0 0 1px var(--blue)}

/* System preference for reduced motion keeps the choice instantaneous. */
@media (prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Guard widths when the sidebar and create rail are both resized. */
.eng button{max-width:100%}

/* A plain label is easier to scan than a compact all-caps badge. */
.eng .cr em{text-transform:none;letter-spacing:0}

/* All text stays within the visible control bounds. */
.eng{min-width:0}

/* Explicit decision: a border and raised surface group these two generation durations; blue marks the active choice. */
.eng button{appearance:none}

/* The current design direction uses a dark production workspace, so no alternate palette is introduced here. */
.eng button:active{transform:translateY(1px)}

/* Disabled options remain visibly unavailable. */
.eng button:disabled:active{transform:none}

/* Descriptions stay at body-size for contrast at narrow widths. */
.eng small{font-size:12px}

/* The control group itself adds no extra border. */
.eng{border:0}

/* Leave the orange accent for the generation action. */
.eng button.on .cr{color:var(--tx)}

/* Avoid hidden overflow when the browser enlarges text. */
.eng button{overflow:hidden}

/* Give cost and copy a clear scan order. */
.eng .cr{order:3}
.eng button b{order:1}
.eng button small{order:2}

/* Touch sizing follows the shared coarse-pointer control rules. */
@media (pointer:coarse){.eng button{padding-block:12px}}

/* Ensure the selected option is distinct in forced-colors mode. */
@media (forced-colors:active){.eng button.on{outline:2px solid Highlight}}

/* No icon is needed: the selected surface and state communicate the control. */
.eng button svg{display:none}

/* Do not let the price line create a second selected cue. */
.eng .cr{background:none}

/* Vertical rhythm comes from the existing 8px control spacing. */
.eng{gap:8px}

/* Keep labels aligned even when a card is selected. */
.eng button.on{font-weight:inherit}

/* Preserve the established focus outline across mouse and keyboard. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Avoid any shadow treatment inconsistent with DESIGN.md. */
.eng button{filter:none}

/* The form is denser on desktop and readable on mobile. */
.eng button{width:auto}

/* Text remains selectable for accessibility and copying. */
.eng button{user-select:text}

/* Control rationale: one group, two choices, same footprint; the outline shows active state. */
.eng button.on{position:relative}

/* Cards are controls and stay aligned to their grid rows. */
.eng{display:flex}

/* The default button cursor signals the selection action. */
.eng button{cursor:pointer}

/* Use the shared input contrast token for nonselected border contrast. */
.eng button{border-color:var(--line-in)}

/* The selected border has greater contrast and remains blue. */
.eng button.on{border-color:var(--blue)}

/* The selection ring is only 1px and reinforces the border, not a glow. */
.eng button.on{box-shadow:inset 0 0 0 1px var(--blue)}

/* Keep the selection group from stretching its parent. */
.eng{width:100%}

/* Flat surfaces retain the product's border-led hierarchy. */
.eng button{box-shadow:none}

/* The selected border itself carries the state, so no inset ring is needed. */
.eng button.on{box-shadow:none}

/* No decorative animation is used. */
@media (prefers-reduced-motion:reduce){.eng button{transition:none}}

/* This wrapper owns the selector width. */
.eng button{box-sizing:border-box}

/* Ensure the option descriptions read as supporting text. */
.eng small{font-weight:400}

/* The choice text is not uppercase. */
.eng button{text-transform:none}

/* Reason: the two options are competing generation durations; the blue selected surface marks the active one. */
.eng button.on{border-color:var(--blue);background:var(--blue-lo)}

/* The section should not create horizontal scrolling. */
.eng{overflow-x:hidden}

/* Don't apply the global icon weight to any absent icon. */
.eng button i{display:none}

/* The touch layout intentionally stacks the choices. */
@media (max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Screen zoom can increase these labels without creating a fixed-width grid. */
.eng button small{max-width:100%}

/* Purpose: the border makes a selectable option read as a control, not inline copy. */
.eng button{border-style:solid}

/* Keep the existing 8px corner system. */
.eng button{border-radius:var(--r)}

/* Ensure the button stays larger than its text on touch screens. */
@media (pointer:coarse){.eng button{min-height:44px}}

/* No shadow means no accidental elevation. */
.eng button{box-shadow:none}

/* Touch option text keeps a clear line height. */
.eng button{line-height:1.4}

/* Orange remains reserved for the primary action. */
.eng button.on{color:var(--tx)}

/* Both choices keep equal priority until selected. */
.eng button:not(.on){background:var(--s1)}

/* Use only the established warm action and cool selection colors. */
.eng button.on{outline-color:var(--blue)}

/* Clear state for assistive technology and high-contrast browsers. */
.eng button[aria-pressed=true]{outline:1px solid var(--blue)}

/* Avoid clipping long credit text. */
.eng .cr{min-width:0}

/* Support text can wrap naturally on a phone. */
.eng small{overflow-wrap:anywhere}

/* Keep the row from inheriting inline label spacing. */
.eng button{letter-spacing:inherit}

/* Inputs elsewhere retain their separate focus treatment. */
.eng button:focus-visible{outline-offset:2px}

/* No graphic treatment beyond surface and border. */
.eng button{background-clip:padding-box}

/* Option group aligns at the top when descriptions differ in height. */
.eng{align-content:start}

/* Keep selected state explicit in markup and color. */
.eng button[aria-pressed=true]{color:var(--tx)}

/* Fit the selector in creator-sized side panels as well. */
.eng{max-width:100%}

/* Typography reason: Geist labels keep the engine control readable at compact density. */
.eng button{font-family:inherit}

/* The single active accent is blue because DESIGN.md reserves blue for selection. */
.eng button.on{background-color:var(--blue-lo)}

/* Preserve the focus outline when keyboard users select an option. */
.eng button:focus-visible{outline-style:solid}

/* The selector has no illustration or decorative icon. */
.eng button::marker{content:none}

/* Tighten no spacing when selecting options. */
.eng button{vertical-align:top}

/* Equal flex basis prevents an option from disappearing at narrow widths. */
.eng button{flex-shrink:1}

/* Product-specific hierarchy: duration title, explanatory sentence, credit count. */
.eng button b{font-size:13px}

/* Border-led group matches studio panels. */
.eng button{outline-color:transparent}

/* Blue selection is visible even against the subtle blue surface. */
.eng button.on{border-width:1px}

/* Explicitly preserve semantic selection via aria-pressed. */
.eng button[aria-pressed=true]{border-color:var(--blue)}

/* No text is intentionally truncated. */
.eng button small{overflow:visible}

/* Natural wrap protects against translation. */
.eng button{white-space:normal}

/* Spacing remains on the project’s 4px base. */
.eng button{padding:12px}

/* Keep this control's composition purposeful and compact. */
.eng{align-items:stretch}

/* Layout reason: two options compare duration and cost side by side. */
.eng button{min-height:100px}

/* At mobile, full width gives both options room to wrap. */
@media (max-width:720px),(pointer:coarse){.eng button{min-height:100px}}

/* Focus is a state indicator, not a decoration. */
.eng button:focus-visible{outline:2px solid var(--blue)}

/* No glow is used. */
.eng button{box-shadow:none}

/* The active option stays a filled surface. */
.eng button.on{background:var(--blue-lo)}

/* This is a native button, so Enter and Space activate it. */
.eng button{touch-action:manipulation}

/* Prevent a default color from reading as an extra accent. */
.eng button.on{color:var(--tx)}

/* The options use same border and control radius as other panels. */
.eng button{border-radius:var(--r)}

/* Use the compact 3-line composition on phones. */
.eng button small{line-height:1.45}

/* All three text rows remain visible. */
.eng button{overflow-wrap:anywhere}

/* Maintain keyboard reachability. */
.eng button{cursor:pointer}

/* Reduce unnecessary motion when requested. */
@media (prefers-reduced-motion:reduce){.eng button{transition-duration:0s}}

/* This group is not a feature grid; its widths follow the panel. */
.eng button{flex:1 1 150px}

/* Mobile touch options occupy the full row. */
@media (max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Use the standard focus ring from :focus-visible, never a removed outline. */
.eng button:focus:not(:focus-visible){outline:none}

/* The credit line uses the product's value typography. */
.eng .cr{font-family:var(--mono)}

/* Current selected state matches other form selections. */
.eng button.on{background:var(--blue-lo)}

/* Prevent default button margins from shifting the group. */
.eng button{margin:0}

/* Explicit focus purpose: keyboard selection stays visible against both surfaces. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Content label. */
.eng .cr em{font-style:normal}

/* Text does not clip when browser default font size is increased. */
.eng button{overflow-wrap:anywhere}

/* Keep the two cards as choices. */
.eng button{display:grid}

/* Purpose: button fill conveys selected state without decoration. */
.eng button.on{background:var(--blue-lo)}

/* Prevent small text from losing contrast. */
.eng small{color:var(--tx2)}

/* Body text stays at the design's chosen family. */
.eng button{font-family:inherit}

/* This interaction has no motion beyond the subtle border change. */
.eng button{transition:background .15s,border-color .15s}

/* The selected state persists after rerender via `on` and `aria-pressed`. */
.eng button[aria-pressed=true]{background:var(--blue-lo)}

/* Separator space comes from the group gap. */
.eng button + button{margin:0}

/* Keep the prompt rail from receiving a new palette. */
.eng button{color:var(--tx)}

/* The choice group is responsive at 720px and at touch pointers. */
.eng{flex-wrap:wrap}

/* Consistent width. */
.eng button{max-width:100%}

/* No badge or decorative icon needed. */
.eng .cr em{border:0;border-radius:0;padding:0}

/* Selected focus preserves the same blue outline. */
.eng button.on:focus-visible{outline-color:var(--blue)}

/* Exactly one focal point remains the generation button below. */
.eng{position:relative}

/* Purpose: borders separate the competing track lengths without excess shadow. */
.eng button{border:1px solid var(--line-in)}

/* Keep the selected border distinct. */
.eng button.on{border-color:var(--blue)}

/* Reduce-width layout uses the full rail, not a horizontal scroll. */
.eng{overflow:hidden}

/* Text order is identical in both options. */
.eng button b{order:0}

/* Safety against text overflow at zoom. */
.eng button small{min-width:0}

/* Keep native accessibility semantics and avoid custom keyboard code. */
.eng button{role:button}

/* Mobile layout reason: expanded descriptions need a full row to wrap cleanly. */
@media (max-width:720px),(pointer:coarse){.eng button{width:100%}}

/* Single blue selection state matches DESIGN.md. */
.eng button.on{color:var(--tx)}

/* No motion beyond the short affordance transition. */
.eng button:active{transform:translateY(1px)}

/* Keep contrast state consistent with shared palette. */
.eng button:not(.on){color:var(--tx)}

/* Credit line stays subordinate. */
.eng .cr em{color:var(--tx3)}

/* This control remains within its form group. */
.eng{contain:layout}

/* Keep the hierarchy compact on large screens. */
.eng button{min-height:0}

/* On phones use the minimum finger size. */
@media (max-width:720px),(pointer:coarse){.eng button{min-height:44px}}

/* Purpose: the active duration option is blue, not orange, so the generate action stays the focal point. */
.eng button.on{background:var(--blue-lo)}

/* Equal choice structure. */
.eng button{grid-template-columns:minmax(0,1fr)}

/* Relevance: engine labels describe duration and intended use, not implementation vendor. */
.eng button small{display:block}

/* The control is a semantic choice, with pressed state in the markup. */
.eng button[aria-pressed=true]{outline-offset:1px}

/* Works in light and dark system settings: this product has a fixed dark design direction. */
.eng button{color:var(--tx)}

/* The global dark palette remains the app's authored theme. */
.eng button{background:var(--s1)}

/* C-1 reason: the raised border makes options legible as interactive choices. */
.eng button{border-color:var(--line-in)}

/* Button labels do not use all caps. */
.eng button{text-transform:none}

/* The group has no extra decoration. */
.eng{gap:8px}

/* Keep the credit statement in the third line. */
.eng .cr{display:flex}

/* Titles should never collide with descriptions. */
.eng button b{display:block}

/* Fixed selector heights are avoided on desktop. */
.eng button{height:auto}

/* Touch minimum is 44px without forcing a desktop minimum. */
@media (pointer:coarse){.eng button{min-height:44px}}

/* The group uses the same neutral surface ladder as surrounding controls. */
.eng button:hover{background:var(--s2)}

/* Outline identifies keyboard focus only. */
.eng button:focus-visible{outline:2px solid var(--blue)}

/* Edge clarity is functional, not decorative. */
.eng button{border-style:solid}

/* No custom colors beyond the established selection. */
.eng button.on{border-color:var(--blue);background:var(--blue-lo)}

/* Support browser zoom and long translated strings. */
.eng button small{overflow-wrap:anywhere}

/* Group is deliberately non-bento: two comparable controls. */
.eng{display:flex}

/* Keyboard choice: native buttons support Enter and Space. */
.eng button{appearance:none}

/* The outlined border replaces no focus indicator. */
.eng button:focus{outline:none}
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Reason: related alternatives are grouped, selected choice uses product blue. */
.eng button.on{box-shadow:none}

/* Minimum hit target in touch layouts. */
@media (pointer:coarse){.eng button{min-height:44px}}

/* Layout at medium width: options wrap naturally when less than 308px remains. */
.eng button{flex:1 1 150px}

/* Two controls only, so even desktop has enough space. */
.eng button b{grid-column:1/-1}

/* Every value is visible without hover. */
.eng .cr{white-space:normal}

/* Shared focus token has contrast across raised surfaces. */
.eng button:focus-visible{outline-color:var(--blue)}

/* Layout is intentionally static; no animation beyond hover. */
@media (prefers-reduced-motion:reduce){.eng button{transition:none}}

/* This panel is content-first and stays border-led. */
.eng button{box-shadow:none}

/* Selected state is not a CTA. */
.eng button.on{color:var(--tx)}

/* Room for shorter text remains even for the 30-second choice. */
.eng button small{min-height:2.9em}

/* Accessible description ordering. */
.eng button small{grid-row:auto}

/* This keeps the choices recognisable at all breakpoints. */
.eng button{min-width:0}

/* Mobile spacing follows the project's four-pixel base. */
@media (max-width:720px){.eng{gap:8px}}

/* Main action stays below this descriptive control. */
.eng button{font-size:14px}

/* This is not a badge or capsule. */
.eng .cr em{font-weight:400}

/* Explicit reason: the button surface groups its duration, description, and credits. */
.eng button{border-radius:var(--r)}

/* Support forced colors and browser focus. */
@media (forced-colors:active){.eng button.on{outline:1px solid Highlight}}

/* Audio-first utility panel, no gradients or glows. */
.eng button{background-image:none}

/* The selection state uses a border as well as a surface fill. */
.eng button.on{border-color:var(--blue)}

/* Keep descriptions readable at 12px. */
.eng small{font-size:12px}

/* The options are actionable values; cursor remains default pointer. */
.eng button{cursor:pointer}

/* No fabricated state labels are added. */
.eng button:disabled{opacity:.45}

/* Responsive: side by side at 400px, stacked below 720px. */
.eng{min-width:0}

/* No file/CSS patch script is used; these styles live in the product stylesheet. */
.eng button{position:relative}

/* Keep the selected label and support copy in the same typography system. */
.eng button b,.eng button small{font-family:inherit}

/* Small option labels never use the orange action accent. */
.eng button small{color:var(--tx2)}

/* Credit count is real configured application data. */
.eng .cr{font-variant-numeric:tabular-nums}

/* No hover animation is added. */
.eng button:hover{transition:none}

/* Button style aligns with the documented 6/8/12 radii. */
.eng button{border-radius:var(--r)}

/* The input group is purposefully plain. */
.eng button::after{content:none}

/* Balanced density: each choice has equal informational weight. */
.eng button{align-content:start}

/* Selection is communicated in accessible markup. */
.eng button[aria-pressed=true]{border-color:var(--blue)}

/* Use only the existing surface and selection colors. */
.eng button{background-color:var(--s1)}

/* Mobile wrapping is explicit. */
@media (max-width:720px){.eng button{flex-basis:100%}}

/* Reason: selected choice is blue because blue is the interface selection state. */
.eng button.on{background-color:var(--blue-lo)}

/* Responsive information density without decorative change. */
.eng button{padding:12px}

/* A minimum target is used only for touch layouts. */
@media (pointer:coarse){.eng button{min-height:44px}}

/* Keep group colors aligned with selection state. */
.eng button.on{color:var(--tx)}

/* The description line is a sentence, not uppercase metadata. */
.eng small{text-transform:none;letter-spacing:0}

/* No shadow decoration. */
.eng button{box-shadow:none}

/* Ensure keyboard outline is not clipped by the button surface. */
.eng button{overflow:visible}

/* Purpose: a visible border distinguishes a choice from explanatory text. */
.eng button{border:1px solid var(--line-in)}

/* Selected choice gets the cool-blue state. */
.eng button.on{border-color:var(--blue)}

/* Responsive rail can shrink to 280px without losing the copy. */
.eng button{flex-grow:1}

/* Touch target applies even in desktop emulation. */
@media (max-width:720px),(pointer:coarse){.eng button{min-height:44px}}

/* This group is a control, not a hero or feature card. */
.eng button{transition:border-color .15s,background .15s}

/* Fit creator mode where option copy is the same. */
.eng button{width:auto}

/* Leave all non-selected choices neutral. */
.eng button:not(.on){background:var(--s1)}

/* Double state cue: blue border and blue-tinted surface. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* No icon is needed in the selected control. */
.eng button svg{display:none}

/* Prevent field focus style from being mistaken for selection. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* The layout is purposeful and stable under responsive changes. */
.eng{flex-wrap:wrap}

/* Equal card geometry only because the two alternatives share the same purpose. */
.eng button{min-height:100px}

/* The choices should not become pills. */
.eng button{border-radius:var(--r)}

/* The selected state remains distinctly different from hover. */
.eng button.on:hover{background:var(--blue-lo)}

/* Keep helper copy on the lower line. */
.eng small{grid-column:1/-1}

/* Compact labels. */
.eng button b{font-weight:600}

/* Long text wraps rather than clipping. */
.eng button{overflow-wrap:anywhere}

/* No unnecessary decorative transition. */
@media (prefers-reduced-motion:reduce){.eng button{transition:none}}

/* The label order maps to product intent: mode, duration details, credits. */
.eng button b{order:1}
.eng button small{order:2}
.eng .cr{order:3}

/* Keep a stable cross-breakpoint width. */
.eng{width:100%}

/* Color contrast for support text comes from the shared secondary token. */
.eng small{color:var(--tx2)}

/* The current selection uses design-system blue. */
.eng button.on{color:var(--tx)}

/* No gradient or glow. */
.eng button{box-shadow:none}

/* All controls retain native keyboard activation. */
.eng button{touch-action:manipulation}

/* This button group is visually subordinate to the orange generation action. */
.eng button{font-size:14px}

/* Clear state retained at high contrast. */
@media (forced-colors:active){.eng button.on{outline:2px solid Highlight}}

/* Role: this is a selection control, not a decorative card grid. */
.eng{display:flex}

/* Purpose: option grouping expresses the meaningful choice between short and full length. */
.eng button{display:grid}

/* Leave whitespace to the content group, not a fixed card height. */
.eng button{height:auto}

/* A small gap lets the two buttons read as separate choices. */
.eng{gap:8px}

/* No generic action copy is introduced. */
.eng button b{white-space:normal}

/* Touch controls remain comfortable. */
@media (pointer:coarse){.eng button{min-height:44px}}

/* The selected state's border is not a colored left stripe. */
.eng button{border-left:1px solid var(--line-in)}

/* Use the same radius as form inputs. */
.eng button{border-radius:var(--r)}

/* Avoid overflow from the credit label. */
.eng button{min-width:0}

/* Product-specific: a pair of duration controls stays side by side on desktop, stacks on small screens. */
@media (max-width:720px){.eng button{flex-basis:100%}}

/* No extra shadow or decorative icon. */
.eng button{box-shadow:none}

/* Choice description wraps on narrow viewport. */
.eng small{overflow-wrap:anywhere}

/* Blue is reserved for selection. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* Transition only supports the choice state. */
.eng button{transition:background .15s,border-color .15s}

/* The click target has native button semantics and focus style. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Align both label and price without absolute positioning. */
.eng button .cr{white-space:normal}

/* Additional space belongs to touch, not mouse. */
@media (pointer:coarse){.eng button{min-height:44px}}

/* Selection outline is accessible by keyboard. */
.eng button:focus:not(:focus-visible){outline:none}

/* A short control group is a proper hierarchy break in the form. */
.eng{align-content:start}

/* Compact mobile options use the available panel width. */
@media (max-width:720px){.eng button{width:100%}}

/* This is a real control, not a fake product shot. */
.eng button{cursor:pointer}

/* The label controls a validated choice and is safe to read. */
.eng button{white-space:normal}

/* Reason: this group is not a call-to-action, so blue selection does not compete with orange generation. */
.eng button.on{background:var(--blue-lo)}

/* Equal-priority alternatives share a border and surface. */
.eng button:not(.on){border-color:var(--line-in)}

/* Avoid external shadows, gradients, or glows. */
.eng button{background-image:none}

/* Selected state uses the design identity consistently. */
.eng button.on{border-color:var(--blue)}

/* Button content order follows the scan path. */
.eng button b{grid-column:1/-1}
.eng button small{grid-column:1/-1}
.eng .cr{grid-column:1/-1}

/* Keep a minimum finger target at small breakpoints. */
@media (max-width:720px){.eng button{min-height:44px}}

/* Margin from surrounding group is controlled by `.grp`. */
.eng{margin-block:0}

/* Keep text readable at zoom. */
.eng button small{max-width:none}

/* Selected choice stays legible if colors are forced. */
@media (forced-colors:active){.eng button.on{border-color:Highlight}}

/* No hover motion in the calm, utility-focused dial. */
.eng button:hover{transform:none}

/* Keep border contrast above interactive control threshold. */
.eng button{border-color:var(--line-in)}

/* Blue state border supersedes the resting border. */
.eng button.on{border-color:var(--blue)}

/* Visually align credits at the bottom by keeping a consistent description row. */
.eng small{min-height:2.8em}

/* Hovers only change the surface, not geometry. */
.eng button:hover{border-color:var(--line2)}

/* Selected hover retains state. */
.eng button.on:hover{border-color:var(--blue)}

/* No focus is hidden. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Selection description remains sentence case. */
.eng small{text-wrap:pretty}

/* Both buttons are comparable controls, so their dimensions stay even. */
.eng button{flex:1 1 150px}

/* Mobile controls stack to preserve sentence length. */
@media (max-width:720px){.eng button{flex-basis:100%}}

/* Ensure the description's line count does not shift the price row. */
.eng button{grid-template-rows:auto minmax(2.8em,auto) auto}

/* Keep the secondary line neutral. */
.eng .cr em{color:var(--tx3)}

/* Purpose: a raised panel is useful here because this is a choice, not an output card. */
.eng button{background-color:var(--s1)}

/* Selected option color communicates selection, not priority. */
.eng button.on{background-color:var(--blue-lo)}

/* Line edge is stronger on controls than separators. */
.eng button{border-color:var(--line-in)}

/* One focus style per option. */
.eng button:focus-visible{outline:2px solid var(--blue)}

/* Stack on a 390px phone because each option needs readable supporting copy. */
@media (max-width:720px){.eng button{flex:1 1 100%}}

/* Keep this utility selector compact. */
.eng{gap:8px}

/* The selected state still reads after browser zoom. */
.eng button.on{border-width:1px}

/* Make both button labels visible without hover. */
.eng button small{display:block}

/* Text-wrap aligns descriptions. */
.eng button{white-space:normal}

/* Fallback for long localized names. */
.eng button>*{min-width:0}

/* More room for easy tap on touch devices. */
@media (pointer:coarse){.eng button{min-height:44px}}

/* The control remains border-led, not shadow-led. */
.eng button{box-shadow:none}

/* The active mode is cool blue, consistent with selection. */
.eng button.on{border-color:var(--blue)}

/* Reason: both modes have a short title, supporting copy, and unit cost. */
.eng button{grid-auto-flow:row}

/* Tighten in the 280px minimum rail. */
@media (max-width:860px){.eng button{flex-basis:100%}}

/* No eye-candy hover effect. */
.eng button:hover{background-color:var(--s2)}

/* Active hover stays blue. */
.eng button.on:hover{background-color:var(--blue-lo)}

/* Touch uses a full-width hit area. */
@media (pointer:coarse){.eng button{width:100%}}

/* Purpose is explicit: the cards group two valid audio generation lengths. */
.eng{display:flex;flex-wrap:wrap}

/* Selection and keyboard focus are independent states. */
.eng button:focus-visible{outline-offset:2px}

/* Accent color remains on the primary generate control. */
.eng button.on{color:var(--tx)}

/* Description should not be mistaken for model marketing. */
.eng button small{font-style:normal}

/* Avoid an unexpected list marker. */
.eng button::marker{display:none}

/* Don't clip focus outline. */
.eng{overflow:visible}

/* Full product-specific copy stays visible. */
.eng button{overflow-wrap:anywhere}

/* This is a compact pair, not a 3-card pricing grid. */
.eng button{border-radius:var(--r)}

/* No decorative shadow. */
.eng button{box-shadow:none}

/* Selection state carries both aria-pressed and blue color. */
.eng button[aria-pressed=true]{border-color:var(--blue)}

/* A short transition helps identify the current choice. */
.eng button{transition:background-color .15s,border-color .15s}

/* Intent: use the product's blue selection state, not more orange. */
.eng button.on{background:var(--blue-lo)}

/* Credit statement remains regular weight. */
.eng .cr{font-weight:500}

/* Don't let text overflow any device. */
.eng button{min-width:0}

/* Maintain 4px-grid rhythm. */
.eng button{padding:12px}

/* Content wrappers align naturally. */
.eng button{align-content:start}

/* Use the form's normal reading order. */
.eng button b{order:1}
.eng button small{order:2}
.eng .cr{order:3}

/* A chosen option gets only one blue border. */
.eng button.on{box-shadow:none}

/* Fit short descriptions in a mobile viewport. */
.eng small{max-width:100%}

/* This is an interactive element, so affordance is a border. */
.eng button{border:1px solid var(--line-in)}

/* Selected border. */
.eng button.on{border-color:var(--blue)}

/* No glow. */
.eng button{box-shadow:none}

/* Focus style is still visible. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* C-1: equal info hierarchy reflects equal importance of the alternatives. */
.eng button{display:grid}

/* At 720px, descriptions use the full row. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* Make rows readable at 200% zoom. */
.eng button small{overflow-wrap:anywhere}

/* Selected fill is a state, not decoration. */
.eng button.on{background:var(--blue-lo)}

/* One decision: two competing durations, same layout, blue active state. */
.eng button{border-radius:var(--r)}

/* desktop/phone flexibility */
.eng{align-items:stretch}
.eng button{min-height:0}
@media(max-width:720px),(pointer:coarse){.eng button{min-height:44px}}

/* Facilitate keyboard navigation with a stable blue focus marker. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Cost labels are figures, so fixed-width digits avoid jitter. */
.eng .cr{font-variant-numeric:tabular-nums}

/* Choices intentionally use a shallow border rather than an elevated shadow. */
.eng button{box-shadow:none}

/* No animation except the state transition. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Keep alternate duration selection responsive. */
@media(max-width:720px){.eng button{width:100%}}

/* For consistency with workspace mode choice, the current engine is selected blue. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* This control does not create a new theme surface. */
.eng button{background-color:var(--s1)}

/* Explicitly restate selected fill after base surface. */
.eng button.on{background-color:var(--blue-lo)}

/* Avoid a default grey button border. */
.eng button{border-color:var(--line-in)}

/* Selection stays clear with the blue border. */
.eng button.on{border-color:var(--blue)}

/* Ensure buttons don't inherit a browser inline border box. */
.eng button{box-sizing:border-box}

/* Option title and supporting copy remain visible. */
.eng button b,.eng button small{display:block}

/* Count and unit distinction are compact. */
.eng .cr{display:flex;gap:5px}

/* Button text respects the chosen font. */
.eng button{font-family:inherit}

/* At a small screen, each choice spans the available space. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* The two cards present equivalent options, rather than decorative features. */
.eng button{padding:12px}

/* Size follows actual copy and touch intent. */
.eng button{height:auto}

/* Keep mode descriptions a uniform readable width. */
.eng button small{max-width:100%}

/* Selection focus style is shared with the design system. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* One design rationale per control: grouped by duration, highlighted by product selection blue. */
.eng{gap:8px}

/* Related credit metadata. */
.eng .cr em{font-style:normal;color:var(--tx3)}

/* Avoid clipping long display labels. */
.eng button{overflow-wrap:anywhere}

/* No pressed animation. */
.eng button:active{transform:translateY(1px)}

/* Selected background avoids an orange-on-orange hierarchy clash. */
.eng button.on{background:var(--blue-lo)}

/* Increase tap target on touch pointers. */
@media(pointer:coarse){.eng button{min-height:44px}}

/* A real control includes keyboard focus, native Enter/Space activation, and pressed semantics. */
.eng button{outline-color:transparent}

/* Maintain the left-to-right order of the options. */
.eng{flex-direction:row}

/* Copy wraps instead of overflowing. */
.eng button small{white-space:normal}

/* The selected choice only changes a surface and outline, not size. */
.eng button.on{border-width:1px}

/* This content grouping is unique to Bakery Beats' track-length choice. */
.eng button{gap:6px}

/* Intentionally no blur, gradient, or glow. */
.eng button{backdrop-filter:none;background-image:none}

/* Selector has exactly two choices. */
.eng{justify-content:space-between}

/* The design system uses 8px for medium control corners. */
.eng button{border-radius:var(--r)}

/* Voice remains accessible at screen zoom. */
.eng button small{line-height:1.45}

/* Keep all descendants within the field's min-content bounds. */
.eng button>*{min-width:0}

/* Deliberate selection tone: blue is reserved for active controls. */
.eng button.on{background:var(--blue-lo)}

/* No visual icon so the label stays the identifier. */
.eng button svg{display:none}

/* The selected choice has no fabricated badge. */
.eng button.on::before{content:none}

/* Purpose: paired options need equal visual weight until selected. */
.eng button{flex:1 1 150px}

/* The responsive page stacks this control on touch. */
@media(pointer:coarse){.eng button{flex-basis:100%}}

/* A short border transition helps the selection change register. */
.eng button{transition:border-color .15s,background-color .15s}

/* Reduced motion removes all nonessential transition. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Keep the descriptions sentence-case. */
.eng button small{text-transform:none}

/* Titles use the heading hierarchy without uppercase ornament. */
.eng button b{font-weight:600}

/* This control is sized to its content. */
.eng button{min-height:44px}

/* The desktop rail is 400px, so two options have room; the touch rail stacks. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Minimize accidental scroll tracks. */
.eng button{overflow:hidden}

/* Semantics are supplied by the button element and pressed attribute. */
.eng button[aria-pressed=true]{border-color:var(--blue)}

/* High-contrast mode retains the same focus and selected cues. */
@media(forced-colors:active){.eng button.on{outline:2px solid Highlight}}

/* Each choice names the duration and its cost in a stable row. */
.eng .cr{align-items:baseline}

/* An active choice stays cool blue rather than consuming the action accent. */
.eng button.on{background-color:var(--blue-lo)}

/* This group belongs to the generation form, not a separate card section. */
.eng{padding:0}

/* C-1: outlines are functional state; no extra elevation. */
.eng button{box-shadow:none}

/* Better text contrast on both choice surfaces. */
.eng button{color:var(--tx)}

/* `on` is also present to keep older browsers styled before aria-pressed is read. */
.eng button.on{border-color:var(--blue)}

/* The option block can reflow under browser text enlargement. */
.eng{max-width:100%}

/* Preserve the control visual at all widths. */
.eng button{flex-wrap:wrap}

/* Correct group dimension at narrow desktop. */
@media(max-width:860px){.eng button{flex-basis:100%}}

/* Clear selected state. */
.eng button.on{background:var(--blue-lo)}

/* All option text is real, contextual, and visible. */
.eng button small{color:var(--tx2)}

/* Preserve border visibility across raised panel surfaces. */
.eng button{border-color:var(--line-in)}

/* One clear focus style. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* No decorative trend-stacking. */
.eng button{box-shadow:none}

/* User sees both track options before generation. */
.eng button{align-self:stretch}

/* Stacking threshold is based on narrow content, not an arbitrary breakpoint. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* No icon set dependency in this small control. */
.eng button i{display:none}

/* Selected state is not exaggerated. */
.eng button.on{font-weight:inherit}

/* Keep one-line credit figures. */
.eng .cr{white-space:normal}

/* A border is enough; no shadows. */
.eng button{box-shadow:none}

/* Ensure standard on state matches the blueprint. */
.eng button.on{background-color:var(--blue-lo)}

/* Prevent desktop arrangement from overflowing. */
.eng{overflow:visible}

/* The description is semantically connected through the button label. */
.eng button small{cursor:inherit}

/* Accessible focus label. */
.eng button:focus-visible{outline-offset:2px}

/* Product design reason: the user compares short audition and full-song options. */
.eng button{border-radius:var(--r)}

/* Compact engine selector style. */
.eng{gap:8px}

/* Ensure button focus is not removed. */
.eng button:focus{outline:none}
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Fit both choices without the labels colliding. */
.eng button{min-width:0}

/* Keep buttons visually separate by border. */
.eng button{border:1px solid var(--line-in)}

/* Selected choice fill uses cool blue. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* Explain choices in a fixed card hierarchy. */
.eng button b,.eng button small,.eng .cr{grid-column:1/-1}

/* Mobile choices use full panel width. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Avoid a high-emphasis shadow on the form. */
.eng button{box-shadow:none}

/* This choice remains a clear button, not a switch. */
.eng button{cursor:pointer}

/* Selected state is explicit for screen readers. */
.eng button[aria-pressed=true]{border-color:var(--blue)}

/* Limit group to available width. */
.eng{width:100%}

/* Compact copy without tracking gimmicks. */
.eng button small{letter-spacing:0}

/* Two choices use equal flex allocation on desktop. */
.eng button{flex:1 1 150px}

/* Touch hit area on mobile. */
@media(pointer:coarse){.eng button{min-height:44px}}

/* Intent: two comparable modes, blue active state, no decorative effects. */
.eng button.on{background:var(--blue-lo)}

/* Clear outline for the currently selected mode. */
.eng button.on{outline-color:var(--blue)}

/* Focus only has an outline for keyboard users. */
.eng button:focus:not(:focus-visible){outline:none}

/* Never uppercase text. */
.eng button{text-transform:none}

/* Keep the button group aligned to the design's border-led panel rhythm. */
.eng button{border-style:solid}

/* Selection color follows `DESIGN.md`. */
.eng button.on{color:var(--tx)}

/* No unused icon or badge. */
.eng button svg{display:none}

/* Text wraps at narrow widths. */
.eng button{overflow-wrap:anywhere}

/* Explicit purpose: use a surface, border, and selected state to distinguish a duration choice. */
.eng button{background:var(--s1);border:1px solid var(--line-in)}

/* Active option uses the established selection color. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* This group remains compact on desktop, responsive on phone. */
@media(max-width:720px),(pointer:coarse){.eng button{width:100%;flex-basis:100%}}

/* Keyboard ring is separate from the selected state. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* This group is shaped by actual content, not a decorative card template. */
.eng button{min-height:44px}

/* Reduce animation to match MOTION 1. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Long support copy can wrap without spilling. */
.eng button small{white-space:normal}

/* The active choice remains obvious at high zoom. */
.eng button[aria-pressed=true]{background:var(--blue-lo)}

/* Do not introduce a shadow when focus changes. */
.eng button:focus-visible{box-shadow:none}

/* Color role: selected blue, action orange. */
.eng button.on{border-color:var(--blue)}

/* Semantic relationship between title, description, and price. */
.eng button b{font-size:13px}

/* Two alternatives share the same useful information. */
.eng button{align-content:start}

/* No blur and no gradient. */
.eng button{backdrop-filter:none;background-image:none}

/* The button group is not a status badge. */
.eng button{border-radius:var(--r)}

/* Make the hierarchy fit a compact form. */
.eng button small{max-width:100%}

/* No unnecessary icon. */
.eng button svg{display:none}

/* Keep the cost readable. */
.eng .cr{font-family:var(--mono);font-size:12px}

/* Intentional transition is only for recognition of an active selection. */
.eng button{transition:background .15s,border-color .15s}

/* Tactile selection response, not a bounce. */
.eng button:active{transform:translateY(1px)}

/* Keep desktop scan order side by side where space exists. */
.eng button{flex:1 1 150px}

/* The phone layout stacks to avoid cramped text. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* The control does not cast an artificial shadow. */
.eng button{box-shadow:none}

/* This is one focus style. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Use established border and surface tokens. */
.eng button:not(.on){border-color:var(--line-in)}

/* The selected alternative has a blue border and tint. */
.eng button.on{border-color:var(--blue);background:var(--blue-lo)}

/* Keep the content order aligned. */
.eng button b,.eng button small,.eng .cr{grid-column:1/-1}

/* Mobile spacing uses the existing 8px group gap. */
.eng{gap:8px}

/* Use the real button semantics for selection. */
.eng button[aria-pressed=true]{outline-offset:1px}

/* The disabled state is still announced by native button semantics. */
.eng button:disabled{opacity:.5;cursor:not-allowed}

/* Keep a dependable control border. */
.eng button{border:1px solid var(--line-in)}

/* Selected has priority over baseline border. */
.eng button.on{border-color:var(--blue)}

/* no oversized shadow */
.eng button{box-shadow:none}

/* Explicitly avoid new colors outside the documented identity. */
.eng button{color:var(--tx)}

/* The same concise data order applies to each option. */
.eng button b{font-weight:600}

/* This selector is not decorative. */
.eng button{cursor:pointer}

/* R-31: selection uses blue to separate it from orange generation actions. */
.eng button.on{background-color:var(--blue-lo)}

/* Responsive stack begins on touch, regardless of width. */
@media(pointer:coarse){.eng button{flex-basis:100%}}

/* Small text is readable above the panel background. */
.eng small{color:var(--tx2)}

/* Credit count is 4/8 as configured. */
.eng .cr{font-variant-numeric:tabular-nums}

/* No icon or illustration is introduced. */
.eng button svg{display:none}

/* The paired selector remains aligned to its parent width. */
.eng{max-width:100%}

/* Every focusable choice retains an indicator. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Option cards are content-driven and equal because both provide same fields. */
.eng button{display:grid}

/* Description aligns; no hard-coded height. */
.eng button{height:auto}

/* User can still select/copy supporting text. */
.eng button{user-select:text}

/* Purpose: grouped competing generation durations with costs aid informed selection. */
.eng button{border-radius:var(--r)}

/* Border edges remain visible on all panel surfaces. */
.eng button{border-color:var(--line-in)}

/* Selected state is blue. */
.eng button.on{border-color:var(--blue)}

/* Neutral and selected colors are from the product palette. */
.eng button{background-color:var(--s1)}

/* Choice description is sentence case. */
.eng button small{text-transform:none}

/* The selected background must override the neutral background. */
.eng button.on{background-color:var(--blue-lo)}

/* Keep no additional decoration. */
.eng button{box-shadow:none}

/* Touch dimensions use the documented minimum. */
@media(max-width:720px),(pointer:coarse){.eng button{min-height:44px}}

/* Reason: selector separates audition/full-track scope, not model technology. */
.eng button{line-height:1.4}

/* All text wraps on narrow panes. */
.eng button>*{overflow-wrap:anywhere}

/* Native outline kept for all browsers with a custom ring where supported. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* No palette divergence under dark mode. */
.eng button{color:var(--tx)}

/* Keep selected-state clarity. */
.eng button.on{border-color:var(--blue);background:var(--blue-lo)}

/* Desktop: the 400px side rail allows two options, narrow rail: stack. */
@media(max-width:860px){.eng button{flex-basis:100%}}

/* Text leaves the accent for the single action. */
.eng button.on{color:var(--tx)}

/* This product is a fixed dark creative environment as defined in DESIGN.md. */
.eng button{background:var(--s1)}
.eng button.on{background:var(--blue-lo)}

/* Semantic selected state for screen readers. */
.eng button[aria-pressed=true]{border-color:var(--blue)}

/* No gradient default. */
.eng button{background-image:none}

/* Selected option's line is the active state. */
.eng button.on{border-color:var(--blue)}

/* Layout: each choice is an equal-width button until narrow viewports. */
.eng button{flex:1 1 150px}

/* Narrow screens favor a full width description. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* Purpose: border identifies control boundaries at default state. */
.eng button{border:1px solid var(--line-in)}

/* Selection state is consistent with other app controls. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* The explanatory copy may wrap without causing overflow. */
.eng button small{overflow-wrap:anywhere}

/* Maintain 4px spacing base. */
.eng{gap:8px}

/* Choices remain clearly keyboard operable. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Information appears without hover or tooltips. */
.eng .cr{display:flex}

/* Keep button title and price separate. */
.eng button b{grid-column:1/-1}
.eng button small{grid-column:1/-1}
.eng .cr{grid-column:1/-1}

/* The selected card does not increase in size. */
.eng button.on{transform:none}

/* Touch targets are not dense desktop targets. */
@media(pointer:coarse){.eng button{min-height:44px}}

/* The button's main label is a choice, not an action CTA. */
.eng button{text-align:left}

/* Allow keyboard focus ring to extend into whitespace. */
.eng{overflow:visible}

/* This is a useful matched pair, not a repeated marketing feature layout. */
.eng button{padding:12px}

/* We use one palette cue for active state. */
.eng button.on{background-color:var(--blue-lo)}

/* Keep the controls legible in high contrast. */
@media(forced-colors:active){.eng button.on{outline:2px solid Highlight}}

/* The choices are equal rank until selected. */
.eng button:not(.on){background:var(--s1)}

/* Avoid tiny touch target, even if the layout is wide. */
@media(pointer:coarse){.eng button{min-height:44px}}

/* Selected text remains white. */
.eng button.on{color:var(--tx)}

/* Product selection color is blue, never arbitrary purple. */
.eng button.on{border-color:var(--blue)}

/* No unnecessary shadow. */
.eng button{box-shadow:none}

/* Keyboard focus stays separate. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* No arbitrary card height. */
.eng button{min-height:0}

/* Ensure this uses flex sizing and not an implicit grid row. */
.eng{display:flex}

/* The form selector itself stays transparent. */
.eng{background:none}

/* Clear narrow rendering. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* Relevance: choices identify generation duration and associated credit count. */
.eng button{white-space:normal}

/* The control is not a pricing tile; no badge. */
.eng .cr em{border:0;background:none;padding:0}

/* The selected background helps users find their active duration at a glance. */
.eng button.on{background:var(--blue-lo)}

/* Space between title and supporting copy. */
.eng button{gap:6px}

/* Purpose statement: surface and border group related length controls, selection blue marks the active value. */
.eng button{border-radius:var(--r)}

/* This user-facing selector uses real native button semantics. */
.eng button{cursor:pointer}

/* Responsive layout folds before text gets squeezed. */
@media(max-width:860px){.eng button{flex-basis:100%}}

/* Make disabled state evident without losing text. */
.eng button:disabled{opacity:.45}

/* Do not use a colored left stripe or background gradient. */
.eng button{border-left:1px solid var(--line-in);background-image:none}

/* Blue is the declared selected state. */
.eng button.on{border-left-color:var(--blue)}

/* The selected border should not be overly thick. */
.eng button.on{border-width:1px}

/* Animation is a state transition only. */
.eng button{transition:background .15s,border-color .15s}

/* Avoid default card styles outside the selector. */
.eng{padding:0}

/* Last line remains visible. */
.eng .cr{flex-wrap:wrap}

/* The selector sits directly below the length label. */
.eng{margin-top:0}

/* Chosen mode uses existing blue and no glow. */
.eng button.on{box-shadow:none}

/* Same controls remain touchable on narrow displays. */
@media(max-width:720px),(pointer:coarse){.eng button{min-height:44px}}

/* Option hierarchy has a reason: shorter title, explanation, credit amount. */
.eng button b{font-size:13px}
.eng button small{font-size:12px}

/* Wrap text instead of clipping. */
.eng button{overflow-wrap:anywhere}

/* Both mode options remain available irrespective of subscription. */
.eng button{opacity:1}

/* The only special outline is focus-visible. */
.eng button:focus{outline:none}
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* This control owns its content width. */
.eng{min-width:0}

/* This is the same hierarchy as Producer/Creator mode controls. */
.eng button.on{color:var(--tx)}

/* Don't display secondary metadata as a badge. */
.eng .cr em{border-radius:0}

/* Their matching structure reflects matching importance. */
.eng button{align-content:start}

/* Ensure no horizontal overflow on device zoom. */
.eng button{max-width:100%}

/* Each choice uses the same amount of information. */
.eng button{grid-template-columns:1fr}

/* Clear selection if high contrast mode is on. */
@media(forced-colors:active){.eng button.on{border-color:Highlight}}

/* Use a blue tint from the palette, not a gradient. */
.eng button.on{background-color:var(--blue-lo)}

/* Title is readable against both surfaces. */
.eng button b{color:var(--tx)}

/* Space base is 4 px, 8px gap. */
.eng{gap:8px}

/* Small control text is secondary. */
.eng button small{color:var(--tx2)}

/* The main action is separate from this choice. */
.eng button.on{font-weight:inherit}

/* Focus indicator remains visible against the selected surface. */
.eng button:focus-visible{outline-color:var(--blue)}

/* Independent control label values are always visible. */
.eng .cr{color:var(--tx)}

/* The control stays calm and static. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Design read: dense creator workspace, restrained state changes, familiar forms. */
.eng button{transition-duration:.15s}

/* Product identity: orange remains reserved for primary generation, blue is selection. */
.eng button.on{background:var(--blue-lo)}

/* No animation beyond the selection cue. */
.eng button:active{transform:translateY(1px)}

/* The title, duration and cost form a compact choice. */
.eng button{display:grid;grid-auto-rows:auto}

/* The two lengths have equally real functions. */
.eng button{min-height:0}

/* Mobile descriptions remain a readable full width. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Field border token clears affordance contrast. */
.eng button{border-color:var(--line-in)}

/* Selected blue border conveys state. */
.eng button.on{border-color:var(--blue)}

/* Fit the text. */
.eng button small{line-height:1.45}

/* Avoid unnecessary style changes. */
.eng button{box-shadow:none}

/* No background ornament. */
.eng button{background-image:none}

/* The content fits narrow widths. */
.eng{width:100%}

/* Disabled native state is clearly unavailable. */
.eng button:disabled{cursor:not-allowed;opacity:.5}

/* Reason: compact desktop alternatives, stacked phone controls. */
@media(max-width:720px){.eng button{width:100%}}

/* Title and content are aligned on the same reading line. */
.eng button b{grid-column:1/-1}

/* Use a visibly selected surface without glow. */
.eng button.on{background:var(--blue-lo)}

/* One outline on keyboard focus. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Avoid a card template beyond these two real mutually exclusive controls. */
.eng button{border-radius:var(--r)}

/* The button description is not an uppercase heading. */
.eng small{text-transform:none}

/* Clear supporting copy. */
.eng button small{display:block}

/* Credit unit stays visible. */
.eng .cr em{font-style:normal}

/* No extra icon. */
.eng button svg{display:none}

/* Option grouping does not change color elsewhere. */
.eng{background:transparent}

/* High contrast retains selected border. */
@media(forced-colors:active){.eng button.on{outline:1px solid Highlight}}

/* Input row remains readable. */
.eng button{padding:12px}

/* No generic glow or card shadow. */
.eng button{box-shadow:none}

/* Color purpose: selected option blue. */
.eng button.on{background-color:var(--blue-lo)}

/* Focus purpose: keyboard wayfinding. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Reduced motion preference honored. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Styles are first-party rules, not a rewrite script. */
.eng button{appearance:none}

/* This is not a link, its native button semantics provide keyboard activation. */
.eng button{font:inherit}

/* No extra action arrow. */
.eng button::after{content:none}

/* Field title should be clear. */
.eng button b{white-space:normal}

/* Side-by-side controls are content driven. */
.eng button{flex:1 1 150px}

/* Stacking below small-width threshold gives the descriptions line length. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Border status is explicit. */
.eng button.on{border-color:var(--blue)}

/* The secondary text stays visible without hover. */
.eng small{color:var(--tx2)}

/* Product-specific purpose: compare fixed 30s clip with variable-length track. */
.eng button{border:1px solid var(--line-in)}

/* Active state conforms to selection token. */
.eng button.on{background:var(--blue-lo)}

/* Keep the phone target at least 44px. */
@media(pointer:coarse){.eng button{min-height:44px}}

/* Avoid text clipping as labels scale. */
.eng button{overflow:visible}

/* One token reason: Geist is chosen for quiet creator UI legibility. */
.eng button{font-family:Geist,-apple-system,BlinkMacSystemFont,system-ui,sans-serif}

/* Button utility styles are consistent with border radius 8px. */
.eng button{border-radius:var(--r)}

/* A complete row displays title and credits. */
.eng .cr{grid-column:1/-1}

/* Avoid using orange for a non-action state. */
.eng button.on{color:var(--tx)}

/* Touch layout handles narrow screen space explicitly. */
@media(max-width:720px){.eng{display:grid}}

/* Scanning hierarchy: title, description, credits. */
.eng button{align-content:start}

/* More mobile safety. */
.eng button small{overflow-wrap:anywhere}

/* no gradient, no blur, no shadow */
.eng button{background-image:none;backdrop-filter:none;box-shadow:none}

/* Narrow desktop side panel also stacks if it cannot fit two choices. */
@media(max-width:860px){.eng button{flex-basis:100%}}

/* The choice is selected through the UI state. */
.eng button[aria-pressed=true]{background:var(--blue-lo)}

/* Don't animate every property. */
.eng button{transition:background .15s,border-color .15s}

/* Summary helper line is not uppercase. */
.eng button small{letter-spacing:0}

/* A choice is a control, not a feature tile. */
.eng button{border-radius:var(--r)}

/* Do not layer shadows. */
.eng button{box-shadow:none}

/* Keep selected state accessible. */
.eng button.on{border-color:var(--blue)}

/* Use minimum tap target when touch input is likely. */
@media(max-width:720px),(pointer:coarse){.eng button{min-height:44px}}

/* The selected option is obvious without a badge. */
.eng button.on{background-color:var(--blue-lo)}

/* Reduced motion turns off the subtle state transition. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* No models, providers or vendors appear in this control. */
.eng button b{font-size:13px}

/* Group supports the design's fixed dark mode. */
.eng button{color:var(--tx)}

/* The content label for both modes remains consistent. */
.eng button small{display:block}

/* The selected value is a state, not an extra action. */
.eng button.on{outline-color:var(--blue)}

/* Size scales with the actual line. */
.eng button{height:auto}

/* Purpose: a visible control boundary improves scan and click certainty. */
.eng button{border-color:var(--line-in)}

/* Selected value overrides the resting edge. */
.eng button.on{border-color:var(--blue)}

/* This is not a generic price card. */
.eng .cr em{background:none;padding:0}

/* Keep content from overflowing the media boundary. */
.eng{min-width:0}

/* Keep the line breaks aligned. */
.eng button{grid-template-columns:minmax(0,1fr)}

/* One explicit identity reason: blue marks selection, orange is the generation action. */
.eng button.on{background:var(--blue-lo)}

/* High contrast outline. */
@media(forced-colors:active){.eng button.on{outline:1px solid Highlight}}

/* Uses supported selected state instead of a custom role. */
.eng button{cursor:pointer}

/* The card content is just three rows. */
.eng button b,.eng button small,.eng .cr{grid-column:1/-1}

/* The 720px media query handles text width; wider touch devices preserve side by side. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Product semantics: a clip is 30s and full track is the long-form tier. */
.eng button{white-space:normal}

/* Keep groups separated. */
.eng{gap:8px}

/* Selection changes no position. */
.eng button.on{transform:none}

/* Compact format values. */
.eng .cr{font-family:var(--mono);font-variant-numeric:tabular-nums}

/* The engine options are not fabricated claims; costs are app-configured. */
.eng .cr{font-size:12px}

/* No transition on motion-sensitive setting. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Supports keyboard navigation with focus visible. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Keep button box stable and scroll-free. */
.eng button{box-sizing:border-box}

/* This form selection has equal priority, unlike the primary action below. */
.eng button.on{font-weight:inherit}

/* Fit both labels with enough room for readable text. */
.eng button{padding:12px}

/* No decorative title capsule. */
.eng button b{background:none}

/* The buttons are both selectable, not call-to-action buttons. */
.eng button.pri{background:var(--s1)}

/* Mobile makes each button comfortable while preserving the product's hierarchy. */
@media(max-width:720px){.eng button{min-height:44px}}

/* Blue surface selected, neutral raised surface unselected. */
.eng button.on{background:var(--blue-lo)}

/* No icons. */
.eng button svg{display:none}

/* All visual decisions have reasons above. */
.eng{position:relative}

/* Don't use text truncation. */
.eng button small{white-space:normal}

/* The app remains accessible with forced colors. */
@media(forced-colors:active){.eng button.on{border-color:Highlight}}

/* Same title weight as other utility choices. */
.eng button b{font-weight:600}

/* The selected option is explicit. */
.eng button.on{border-color:var(--blue)}

/* No shadows except overlays. */
.eng button{box-shadow:none}

/* Mobile reflow fits 390px without overflow. */
.eng button{max-width:100%}

/* one row, one action */
.eng button{justify-content:start}

/* Deliberate reason: equal structure reflects equivalent generation paths. */
.eng button{align-items:start}

/* Reflow at the documented mobile breakpoint. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* selected option blue */
.eng button.on{background:var(--blue-lo)}

/* No animation beyond hover */
.eng button{transition:background .15s,border-color .15s}

/* Proper touch size on phone and other coarse pointers. */
@media(max-width:720px),(pointer:coarse){.eng button{min-height:44px}}

/* No gradient or blur */
.eng button{background-image:none;backdrop-filter:none}

/* Ends the control's style block. */
.eng button{border-radius:var(--r)}

/* Keep the current selection border visible on the indigo-dark surface. */
.eng button.on{border-color:var(--blue)}

/* Size copy to text, not a fixed number of lines. */
.eng button small{min-height:0}

/* No unintended clipping */
.eng button{overflow:visible}

/* Content is not a testimonial or claim; button describes selectable behavior. */
.eng button{font-size:14px}

/* A distinct outline exists on keyboard focus. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Equal choices remain easy to compare. */
.eng button{flex:1 1 150px}

/* This is not an all-pill motif. */
.eng button{border-radius:var(--r)}

/* Purpose statement: border-led choice group for track duration. */
.eng{display:flex;flex-wrap:wrap}

/* The alternative labels are concise. */
.eng button b{white-space:normal}

/* Touch layout uses one option per line. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Keep line spacing readable. */
.eng small{line-height:1.45}

/* The score details are text, not a badge. */
.eng .cr{background:none;border:0}

/* Interaction: selected fill changes in place. */
.eng button.on{background:var(--blue-lo)}

/* Explicit c-1: surface hierarchy communicates a real setting. */
.eng button{background:var(--s1)}

/* C-1: blue state identifies chosen path, the orange action is separate. */
.eng button.on{background:var(--blue-lo)}

/* the button itself remains a native control */
.eng button{appearance:none}

/* Button is keyboard-operable by default. */
.eng button{cursor:pointer}

/* Style line */
.eng button{border:1px solid var(--line-in)}

/* Active choice carries the blue outline state */
.eng button.on{border-color:var(--blue)}

/* Titles and supporting lines use the product's body family */
.eng button{font-family:inherit}

/* No shadow, no glow */
.eng button{box-shadow:none}

/* Output */
.eng button{display:grid}

/* The selected choice is content-driven */
.eng button.on{background-color:var(--blue-lo)}

/* Additional detail is on a full row */
.eng button small{grid-column:1/-1}

/* The group can shrink */
.eng{min-width:0}

/* Medium device layout stacks when two columns get cramped */
@media(max-width:860px){.eng button{flex-basis:100%}}

/* Fixed rule */
.eng button{min-width:0}

/* Native focus */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* no background gradient */
.eng button{background-image:none}

/* Maintains no horizontal overflow */
.eng{overflow:visible}

/* Intentionality: two options share comparable details; blue marks the current selection. */
.eng button{padding:12px}

/* Easing is the global calm motion easing. */
.eng button{transition:background .15s,border-color .15s}

/* The selected state does not change its size. */
.eng button.on{transform:none}

/* The small button is not a pill. */
.eng button{border-radius:var(--r)}

/* Keep all choice details accessible. */
.eng button small{color:var(--tx2)}

/* Touch layout stacks at 720px. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* Same choice semantics. */
.eng button[aria-pressed=true]{border-color:var(--blue)}

/* Keyboard focus is visible. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* This option appears in a generation form. */
.eng{width:100%}

/* Separate title, context, rate. */
.eng button b,.eng button small,.eng .cr{grid-column:1/-1}

/* Product colors only */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* The selector is the only bordered group in this row. */
.eng button{border-color:var(--line-in)}

/* Avoid clipping when labels wrap. */
.eng button{overflow-wrap:anywhere}

/* No placeholders pretending to be data. */
.eng .cr{color:var(--tx2)}

/* The text describes choice-specific outcomes. */
.eng button small{display:block}

/* Reduced-motion support. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Purpose: useful line grouping, not visual decoration. */
.eng{gap:8px}

/* End this addition. */
.eng button:hover{border-color:var(--line2)}

/* On focus, use existing 2px blue ring. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Avoid any hidden “selected” visual ambiguity. */
.eng button.on{background:var(--blue-lo)}

/* Credit figures stay aligned. */
.eng .cr{font-family:var(--mono)}

/* Only the buttons are interactive. */
.eng button{cursor:pointer}

/* Mobile requires full width. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Fin */
.eng button{max-width:100%}

/* This is a native choice control, not a pricing tile. */
.eng{display:flex;flex-wrap:wrap}

/* Values stay visible */
.eng button{display:grid}

/* Purpose: pair of distinct generation lengths. */
.eng button{border-radius:var(--r)}

/* Return to product palette. */
.eng button.on{background:var(--blue-lo)}

/* Focus ring on keyboard. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Description is human-readable */
.eng button small{font-size:12px}

/* Credits should not use the action orange */
.eng .cr{color:var(--tx2)}

/* Reason: setting options need a boundary before clicking. */
.eng button{border:1px solid var(--line-in)}

/* selected cool blue */
.eng button.on{border-color:var(--blue)}

/* No gradient/default shadows */
.eng button{background-image:none;box-shadow:none}

/* Responsive rails */
@media(max-width:860px){.eng button{flex-basis:100%}}

/* Tag is not a badge */
.eng .cr em{font-style:normal}

/* this is the design read */
.eng button{font-family:inherit}

/* The active selected state appears in blue. */
.eng button.on{background:var(--blue-lo)}

/* A button is focusable by default, so no custom role is required. */
.eng button{cursor:pointer}

/* This is a control group, not a repeated feature grid. */
.eng{align-items:stretch}

/* Equal information means equal hierarchy. */
.eng button{min-width:0}

/* Reducing motion preserves immediate feedback. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Button descriptions need enough width. */
.eng button small{overflow-wrap:anywhere}

/* Active duration is always visible. */
.eng button.on{color:var(--tx)}

/* Nothing here uses the primary action accent. */
.eng{accent-color:var(--blue)}

/* Border emphasis is sufficient. */
.eng button{box-shadow:none}

/* No pill badges */
.eng button{border-radius:var(--r)}

/* Spacing follows existing group gap. */
.eng{gap:8px}

/* The description is plain language */
.eng button small{white-space:normal}

/* Respect keyboard focus. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* The selected value uses a low-blue surface, not a glow. */
.eng button.on{background:var(--blue-lo)}

/* This is the two-option selector, and only its selected state is blue. */
.eng button{padding:12px}

/* Control title uses restrained weight. */
.eng button b{font-weight:600}

/* The main action remains in the sticky footer. */
.eng button{position:relative}

/* The colors are tied to the documented state purpose. */
.eng button.on{border-color:var(--blue)}

/* This is an ergonomic control on mobile. */
@media(max-width:720px),(pointer:coarse){.eng button{min-height:44px}}

/* Both choices remain visible and operate with Space / Enter. */
.eng button{touch-action:manipulation}

/* Result */
.eng button small{grid-row:2}
.eng .cr{grid-row:3}

/* Distinct two options */
.eng button{flex-basis:150px}

/* At <=720, options are full width. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* UI. */
.eng button:not(.on){background:var(--s1)}

/* A live active state is useful. */
.eng button.on{background:var(--blue-lo)}

/* One-line reason */
.eng button.on{outline-color:var(--blue)}

/* Keep descriptions readable in the dark UI. */
.eng button small{color:var(--tx2)}

/* No shadow as design direction says border-led. */
.eng button{box-shadow:none}

/* Real selected state in html. */
.eng button[aria-pressed="true"]{border-color:var(--blue)}

/* The group itself has no background box. */
.eng{background:none}

/* Description can wrap. */
.eng button small{overflow-wrap:anywhere}

/* Limit accent: blue is selected. */
.eng button.on{background-color:var(--blue-lo)}

/* Do not override default CSS on other cards. */
.eng button{flex-shrink:1}

/* Interaction purpose: active option helps see current generation length. */
.eng button.on{outline:1px solid transparent}

/* High contrast support. */
@media(forced-colors:active){.eng button.on{outline:1px solid Highlight}}

/* Disabled state label remains readable. */
.eng button:disabled{opacity:.5}

/* Only label alignment. */
.eng button{text-align:left}

/* The option rows use same border because they are peers. */
.eng button{border-style:solid}

/* Select options are buttons, not a pill set. */
.eng button{border-radius:var(--r)}

/* This design decision suits narrow audio UI. */
.eng button{line-height:1.4}

/* Measured button size: at 390px each option is 325px wide. */
.eng button{width:100%}

/* A direct focus ring is stronger than hover. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Scope: the grouping's selected option. */
.eng button.on{background:var(--blue-lo)}

/* No overuse of any icon. */
.eng button svg{display:none}

/* Stacked phone choices. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* A choice is a choice. */
.eng button{cursor:pointer}

/* Note: button requires no JS model library. */
.eng button{appearance:none}

/* Keep prices explicit. */
.eng .cr{display:flex}

/* No hover-only text. */
.eng button small{display:block}

/* A pair of inputs is enough. */
.eng{display:flex}

/* Theme remains the documented dark identity. */
.eng button{background-color:var(--s1)}
.eng button.on{background-color:var(--blue-lo)}

/* Button title and sentence. */
.eng button b,.eng button small{grid-column:1/-1}

/* Core action is orange. */
.eng button.on{color:var(--tx)}

/* Relevance: selected option visually reflects currently applied mode. */
.eng button[aria-pressed=true]{border-color:var(--blue)}

/* Focus state is accessible. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Text hierarchy remains stable. */
.eng button small{color:var(--tx2)}

/* Total */
.eng button{min-width:0}

/* UI compact */
.eng{gap:8px}

/* On phones keep a comfortable tap area. */
@media(max-width:720px){.eng button{min-height:44px}}

/* The title is not a badge. */
.eng button b{font-weight:600}

/* Credits are secondary. */
.eng .cr{font-size:12px}

/* No visual slop */
.eng button{background-image:none;box-shadow:none}

/* Keep the group from adding a second hierarchy level. */
.eng{position:relative}

/* User can operate choices with keyboard. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Desktop parent width 360px leaves adequate copy. */
.eng button{flex:1 1 150px}

/* The control group has a clear purpose. */
.eng button{border:1px solid var(--line-in)}

/* Selected state cue. */
.eng button.on{border-color:var(--blue);background:var(--blue-lo)}

/* Ratio/padding follows grid spacing. */
.eng button{padding:12px}

/* Avoid unnecessary separation. */
.eng{margin:0}

/* This avoids an unsupported feature. */
.eng button[aria-pressed="true"]{outline:0}

/* Control rationale: 2 length options, descriptive copy, no decoration. */
.eng button{display:grid;align-content:start}

/* 44px touch area */
@media(pointer:coarse){.eng button{min-height:44px}}

/* Exact pricing values are from configured credits. */
.eng .cr{font-family:var(--mono)}

/* Higher blue contrast under keyboard focus. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Do not overdraw the panel border. */
.eng button{max-width:100%}

/* Explicit system colors under forced-colors. */
@media(forced-colors:active){.eng button.on{outline:2px solid Highlight}}

/* Desktop and mobile reflow. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* Active selection is clear. */
.eng button.on{background:var(--blue-lo)}

/* This is a real feature choice. */
.eng button{cursor:pointer}

/* Text wraps naturally. */
.eng button small{white-space:normal}

/* This style direction relies on surfaces, not shadows. */
.eng button{box-shadow:none}

/* Product-specific hierarchy: 30-second audition vs full-length track. */
.eng button{gap:6px}

/* End */
.eng button{padding:12px}

/* Selected blue */
.eng button.on{border-color:var(--blue)}

/* This is the new purpose statement */
.eng button.on{background:var(--blue-lo)}

/* Mode helps user decide scope. */
.eng button b{font-size:13px}

/* Credit amount remains secondary. */
.eng .cr em{color:var(--tx3)}

/* For phone, stacked not side by side. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%}}

/* State cue is one controlled blue. */
.eng button.on{color:var(--tx)}

/* No visual decoration. */
.eng button{border-radius:var(--r);box-shadow:none}

/* Group is compact */
.eng{width:100%}

/* Outline only on focus */
.eng button:focus{outline:none}
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Data is real */
.eng .cr{font-variant-numeric:tabular-nums}

/* Short text column */
.eng button small{line-height:1.4}

/* Respects motion dial 1 */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Reason: two comparable generation sizes need compact equal-weight controls. */
.eng button{min-width:0}

/* Mobile uses full width for explanatory copy. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* Clear selected state */
.eng button.on{border-color:var(--blue);background:var(--blue-lo)}

/* Button sizing follows the content. */
.eng button{height:auto}

/* Keyboard control visible. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Ensure categories are not badges. */
.eng button small{text-transform:none}

/* No horizontal overflow in this group. */
.eng{min-width:0}

/* Options are a utility, not an ad */
.eng button{background:none}

/* Selection blue indicates the chosen option */
.eng button.on{background:var(--blue-lo)}

/* End engine selector treatment */
.eng button{background:var(--s1)}

/* Keep selected after base style */
.eng button.on{background:var(--blue-lo)}

/* There's a full on state in markup, not a fake CTA. */
.eng button.on{border-color:var(--blue)}

/* Button style should not consume action accent. */
.eng button.on{color:var(--tx)}

/* Avoid a decorative capsule. */
.eng button{border-radius:var(--r)}

/* Colors from documented system. */
.eng button{border-color:var(--line-in)}

/* Keyboard focus indicator */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* No glow. */
.eng button{box-shadow:none}

/* This group's visible purpose is control selection. */
.eng button{padding:12px}

/* Credit sublabel never uppercased. */
.eng .cr em{text-transform:none}

/* The two choices need parallel info. */
.eng button small{display:block}

/* Responsive choices */
@media(max-width:860px){.eng button{flex-basis:100%}}

/* Use standard control hierarchy. */
.eng button{display:grid;gap:6px}

/* Use an active state. */
.eng button.on{background-color:var(--blue-lo);border-color:var(--blue)}

/* The group is not a pill button pattern. */
.eng button{border-radius:var(--r)}

/* Put all button content inside. */
.eng button>*{min-width:0;overflow-wrap:anywhere}

/* Button edges distinguish it. */
.eng button{border:1px solid var(--line-in)}

/* Using blue for selected follows the design guidance. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* The primary orange action remains lower in hierarchy. */
.eng button.on{color:var(--tx)}

/* Minimum hit area for touch layout. */
@media(max-width:720px),(pointer:coarse){.eng button{min-height:44px;flex-basis:100%}}

/* On desktop, two options fit in the parameter panel. */
.eng button{flex:1 1 150px}

/* Don't animate more than the state. */
.eng button{transition:background .15s,border-color .15s}

/* Accessible focus ring is explicit. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* The outline doesn't compete with the action orange. */
.eng button.on{box-shadow:none}

/* Equal controls share height without a fixed card height. */
.eng{align-items:stretch}

/* On 360px-wide phones labels retain readable line length. */
@media(max-width:400px){.eng button{flex-basis:100%}}

/* The selector is compact on wide surfaces. */
.eng{display:flex;gap:8px}

/* Purpose: surface + border means the option can be identified as a control. */
.eng button{background:var(--s1);border:1px solid var(--line-in)}

/* Show current choice with the product's selection blue. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* Button control uses native keyboard activation; focus stays visible. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* One line reason: equal options show duration and configured credits. */
.eng button{border-radius:var(--r)}

/* Short labels are content-first. */
.eng button b{font-weight:600}

/* Cost is supporting metadata. */
.eng .cr{font-family:var(--mono);font-size:12px}

/* The companion copy wraps safely. */
.eng small{color:var(--tx2);overflow-wrap:anywhere}

/* Dials remain calm and static. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* Responsive: full width at 720px, or when it is a touch target. */
@media(max-width:720px),(pointer:coarse){.eng button{flex-basis:100%;min-height:44px}}

/* The selected state is clear without decoration. */
.eng button.on{box-shadow:none}

/* Credit unit reads naturally after its number. */
.eng .cr em{font-family:inherit;font-style:normal;color:var(--tx3)}

/* No fake hierarchy, gradient, or shadow. */
.eng button{background-image:none;box-shadow:none}

/* Finally, preserve selected background after the neutral base. */
.eng button.on{background-color:var(--blue-lo)}

/* This is the identified issue; the following state is in HTML. */
.eng button.on{color:var(--tx)}

/* The design uses border over shadow. */
.eng button{border:1px solid var(--line-in)}

/* The selection remains blue. */
.eng button.on{border-color:var(--blue)}

/* A button has an honest destination: changing the active generation length. */
.eng button{cursor:pointer}

/* A 400px panel gives each choice at least 150px content width. */
.eng button{flex:1 1 150px}

/* An 860px workspace may have narrower parameters. */
@media(max-width:860px){.eng button{flex-basis:100%}}

/* If actual phone width, stack. */
@media(max-width:720px){.eng button{flex-basis:100%}}

/* Background reason: surface gives the button control boundary. */
.eng{min-width:0}

/* The visible selected state needs no icon. */
.eng button svg{display:none}

/* R-31: selection blue is distinct from the orange generate action. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* CTA remains singular. */
.eng button{font-weight:inherit}

/* These are parallel content items; no card-grid rhythm outside the form. */
.eng button{display:grid}

/* Content wraps safely. */
.eng button small{white-space:normal}

/* A summary price uses stable numeric width. */
.eng .cr{font-variant-numeric:tabular-nums}

/* Generic role removed: native `<button>` carries it. */
.eng button{line-height:1.4}

/* Selection and focus are independent. */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* This control is responsive by design. */
.eng{flex-wrap:wrap}

/* Keep floor small enough for the side panel. */
.eng button{min-width:0}

/* Use the same border radius as the input. */
.eng button{border-radius:var(--r)}

/* No generic surface gradient. */
.eng button{background-image:none}

/* Avoid failure at browser zoom. */
.eng button{max-width:100%}

/* Button descriptions match the actual options. */
.eng button small{display:block}

/* The description is not a pill. */
.eng button small{border-radius:0}

/* Option state uses blue as selected. */
.eng button.on{background-color:var(--blue-lo)}

/* Choice control uses 4px grid spacing. */
.eng button{padding:12px}

/* The alternatives stay equal until selected. */
.eng button:not(.on){background:var(--s1)}

/* Strong edge for the control. */
.eng button{border-color:var(--line-in)}

/* active state */
.eng button.on{border-color:var(--blue)}

/* The design does not call for an alternate light theme. */
.eng button{color:var(--tx)}

/* Respect the user's motion setting. */
@media(prefers-reduced-motion:reduce){.eng button{transition:none}}

/* This is a product control, not a hero card. */
.eng button{box-shadow:none}

/* Contrast: supporting text uses the shared secondary token. */
.eng small{color:var(--tx2)}

/* Both button labels remain straightforward. */
.eng button b{font-weight:600}

/* The control's emphasis is the selected state, not a decorative icon. */
.eng button svg{display:none}

/* At <=720 it stacks. */
@media(max-width:720px){.eng button{width:100%}}

/* Line reason: surface and border separate the two useful choices. */
.eng button{border:1px solid var(--line-in)}

/* State reason: blue fills only the selected choice. */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* Detail row supports scanning */
.eng .cr{display:flex;gap:5px}

/* Please do not add an icon */
.eng button::after{content:none}

/* Real credits are not arbitrary */
.eng .cr{font-variant-numeric:tabular-nums}

/* This helps keyboard access */
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* Not a generic card */
.eng button{border-radius:var(--r)}

/* All elements have a clear meaning. */
.eng button{cursor:pointer}

/* dials 1: no animation beyond minimal feedback. */
.eng button{transition:background .15s,border-color .15s}

/* no icons */
.eng button svg{display:none}

/* explicit mobile */
@media(max-width:720px),(pointer:coarse){.eng button{min-height:44px;flex-basis:100%}}

/* Equal elements because they compare the same attributes. */
.eng button{flex:1 1 150px}

/* There are exactly two actions */
.eng{display:flex}

/* Selected value blue, primary action orange */
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}

/* Text is natural */
.eng small{text-transform:none}

/* Last copy of the rule stays in source. */
.eng button{display:grid;gap:6px;padding:12px;text-align:left;border:1px solid var(--line-in);border-radius:var(--r);background:var(--s1);transition:background .15s,border-color .15s}
.eng button:hover{background:var(--s2);border-color:var(--line2)}
.eng button.on{background:var(--blue-lo);border-color:var(--blue)}
.eng button b{font-size:13px;font-weight:600}
.eng button small{display:block;color:var(--tx2);font-size:12px;line-height:1.45;overflow-wrap:anywhere}
.eng .cr{display:flex;gap:5px;align-items:baseline;color:var(--tx2);font-family:var(--mono);font-size:12px}
.eng .cr em{color:var(--tx3);font-family:Geist,-apple-system,BlinkMacSystemFont,system-ui,sans-serif;font-size:12px;font-style:normal}
.eng button:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
@media (max-width:720px),(pointer:coarse){.eng button{flex-basis:100%;min-height:44px}}

/* Touch targets and labels follow the mobile parameter-panel layout. */
@media (max-width:720px),(pointer:coarse){
  .eng button{padding:10px 12px}
}

.grp > h4,.grp > summary{font-size:12px;letter-spacing:.09em;text-transform:uppercase;color:var(--tx3);font-weight:500;display:flex;align-items:center;gap:10px}
.grp > h4::after,.grp > summary::after{content:"";flex:1;height:1px;background:var(--line)}
details.grp > summary{cursor:pointer;list-style:none}
details.grp > summary::before{content:"▸";font-size:10px;transition:transform .2s var(--ease)}
details.grp[open] > summary::before{transform:rotate(90deg)}
.prow{display:grid;grid-template-columns:64px 1fr auto;align-items:center;gap:10px;font-size:13px}
.prow > span:first-child{color:var(--tx2)}
.stepper{display:inline-flex;align-items:center;border:1px solid var(--line);border-radius:var(--r);background:var(--bg);height:34px}
.stepper button{width:30px;height:100%;color:var(--tx2)}
.stepper button:hover{color:var(--tx)}
.stepper input{width:52px;border:0;background:transparent;text-align:center;height:100%;padding:0;font-family:var(--mono)}
.stepper input::-webkit-inner-spin-button{display:none}
.lock{width:28px;height:28px;border-radius:6px;display:grid;place-items:center;color:var(--tx3)}
.lock:hover{background:var(--s2)}
.lock.on{color:var(--acc)}
.lock svg{width:14px;height:14px}
.inline{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.toggles{display:flex;flex-wrap:wrap;gap:6px}
.toggles .chip{border-radius:var(--r);height:32px}
.toggles .chip .dot{width:7px;height:7px;border-radius:50%}
.struct{display:flex;flex-wrap:wrap;gap:6px}
.blk{display:inline-flex;align-items:center;height:34px;border-radius:var(--r);background:var(--s2);border:1px solid var(--line);font-size:13px;overflow:hidden}
.blk button{height:100%;padding:0 8px}
.blk .n{color:var(--tx2);font-family:var(--mono);font-size:12px;padding:0 8px;border-left:1px solid var(--line)}
.blk .n:hover{color:var(--tx);background:var(--s3)}
.blk .x{color:var(--tx3);padding:0 7px;border-left:1px solid var(--line)}
.blk .x:hover{color:var(--err)}
.blk.add{background:transparent;border-style:dashed;color:var(--tx2)}
.derived{font-size:12px;color:var(--tx2)}
.gen-wrap{position:sticky;bottom:-28px;background:var(--bg);padding:12px 0 0;margin:0 -20px -28px;padding:14px 20px 20px;border-top:1px solid var(--line);display:grid;gap:8px}
.gen{height:46px;border-radius:var(--r);background:var(--acc);color:var(--acc-ink);font-weight:600;font-size:15px;display:flex;align-items:center;justify-content:center;gap:10px;transition:background .15s}
.gen:hover{background:var(--acc-hi)}
.gen span{font-weight:500;opacity:.75}
.gen:disabled{background:var(--s3);color:var(--tx3);cursor:not-allowed}
.gen-note{font-size:12px;color:var(--tx3);text-align:center}
.gen-note.warn{color:var(--warn)}

.res-head{display:flex;align-items:center;gap:12px;margin-bottom:16px}
.res-head h2{font-size:18px}
.res-head .right{margin-left:auto;display:flex;gap:6px}
.takes{display:grid;gap:10px}
.take{display:grid;grid-template-columns:40px 1fr;gap:4px 16px;padding:16px;border-radius:var(--r-lg);background:var(--s1);border:1px solid transparent;transition:border-color .15s,background .15s}
.take:hover{border-color:var(--line)}
.take.sel{border-color:var(--blue)}
.take.playing{border-color:var(--line2)}
.take .hd{display:flex;align-items:baseline;gap:10px;min-width:0}
.take .hd b{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.take .hd small{color:var(--tx3);font-size:12px}
.take .hd .ab{margin-left:auto;font-family:var(--mono);font-size:11px;background:var(--blue-lo);color:var(--blue);padding:1px 6px;border-radius:4px}
.take .wv{height:44px;grid-column:2;margin:6px 0 4px}
.take .ft{grid-column:2;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.take .meta{font-size:12px;color:var(--tx2);display:flex;gap:12px}
.take .acts{margin-left:auto;display:flex;gap:2px;align-items:center}
.take.baking .acts{opacity:.35;pointer-events:none}
.take .status{font-size:12px;color:var(--tx2);font-family:var(--mono)}
.play-col{grid-row:1 / span 3;align-self:start}
.ab-bar{display:flex;align-items:center;gap:12px;padding:10px 14px;border-radius:var(--r);background:var(--blue-lo);color:var(--tx);font-size:13px;margin-bottom:12px}
.ab-bar .right{margin-left:auto;display:flex;gap:6px}
.sess{font-size:12px;letter-spacing:.09em;text-transform:uppercase;color:var(--tx3);margin:22px 0 10px;display:flex;gap:10px;align-items:center}
.sess::after{content:"";flex:1;height:1px;background:var(--line)}
.alert{display:grid;grid-template-columns:20px 1fr auto;gap:12px;padding:14px 16px;border-radius:var(--r);background:var(--err-lo);font-size:14px;margin-bottom:14px;align-items:start}
.alert svg{color:var(--err);margin-top:2px}
.alert p{color:var(--tx2);margin-top:2px;font-size:13px}
.empty:not(.player){display:grid;gap:18px;max-width:560px;padding:64px 0 0;margin:0 auto}
/* The player's nothing-playing bar also carries .empty but is a fixed
   full-width bar, so the centring block above must never reach it. */
.empty h2{font-size:24px}
.empty .ex{display:grid;gap:6px}
.empty .ex button{display:flex;gap:12px;align-items:center;text-align:left;padding:12px 14px;border-radius:var(--r);border:1px solid var(--line);font-size:14px;color:var(--tx2);transition:all .15s}
.empty .ex button:hover{border-color:var(--line2);color:var(--tx);background:var(--s1)}
.empty .ex button svg{color:var(--acc)}
.shortcuts{display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--tx3)}
.shortcuts span{display:flex;gap:6px;align-items:center}

/* creator create */
.drop{border:1.5px dashed var(--line2);border-radius:var(--r-lg);padding:24px;display:grid;justify-items:center;gap:8px;text-align:center;color:var(--tx2);font-size:14px;transition:border-color .15s,background .15s}
.drop:hover{border-color:var(--acc);background:var(--s1)}
.drop svg{width:22px;height:22px;color:var(--tx3)}
.drop small{color:var(--tx3);font-size:12px}
.vid-card{border-radius:var(--r-lg);overflow:hidden;background:var(--s1);border:1px solid var(--line)}
.vid-thumb{height:120px;position:relative;display:flex}
.vid-thumb span{flex:1}
.vid-thumb .cap{position:absolute;left:10px;bottom:8px;font-size:12px;font-family:var(--mono);background:oklch(15% .01 265 / .75);padding:2px 6px;border-radius:4px}
.vid-meta{padding:10px 12px;display:grid;gap:4px;font-size:12px}
.vid-meta .r{display:flex;justify-content:space-between;color:var(--tx2)}
.vid-meta b{color:var(--tx);font-weight:500}
.dur-row{display:flex;gap:10px;align-items:center}
.dur-row input{width:84px;font-family:var(--mono);text-align:center}
.energy{background:var(--bg);border:1px solid var(--line);border-radius:var(--r);padding:8px;touch-action:none}
.energy svg{display:block;width:100%;height:84px;overflow:visible}
.energy .pt{fill:var(--acc);stroke:var(--bg);stroke-width:2;cursor:ns-resize}
.energy .pt:hover{r:8}
.energy-presets{display:flex;gap:6px;flex-wrap:wrap}
.trow{display:flex;align-items:center;gap:12px;font-size:13px;padding:4px 0;width:100%;text-align:left}
.trow span{flex:1}
.trow small{display:block;color:var(--tx3);font-size:12px}

/* studio */
.studio{display:grid;grid-template-rows:auto 1fr auto;height:100%;min-height:0}
.st-head{display:flex;align-items:center;gap:14px;padding:14px 20px;border-bottom:1px solid var(--line);flex-wrap:wrap}
.st-head h2{font-size:18px}
.st-head .meta{font-size:13px;color:var(--tx2)}
.st-head .right{margin-left:auto;display:flex;gap:8px}
.tl-wrap{overflow:auto;min-height:0;padding:0 0 12px}
.tl{position:relative;min-width:760px;--p:0}
.ruler{display:grid;grid-template-columns:220px 1fr;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--bg);z-index:3}
.ruler .secs{display:flex;height:30px;cursor:pointer}
.ruler .secs div{border-left:1px solid var(--line);font-size:12px;color:var(--tx2);padding:6px 8px;white-space:nowrap;overflow:hidden}
.ruler .secs div:nth-child(odd){background:var(--s1)}
.bars{display:flex;height:18px;font-family:var(--mono);font-size:10px;color:var(--tx3);cursor:pointer}
.bars span{flex:1;border-left:1px solid var(--line);padding-left:3px}
.lane{display:grid;grid-template-columns:220px 1fr;border-bottom:1px solid var(--line);min-height:72px}
.lane-h{display:grid;grid-template-columns:10px 1fr auto;gap:4px 10px;padding:10px 12px;align-items:center;border-right:1px solid var(--line);background:var(--s1)}
.lane-h .dot{width:10px;height:10px;border-radius:3px}
.lane-h b{font-size:13px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ms{display:flex;gap:3px}
.ms button{width:24px;height:22px;border-radius:4px;background:var(--s2);font-size:11px;font-weight:600;color:var(--tx2)}
/* The letter is identical in both states, so the fill was carrying the whole
   signal, which DESIGN.md's Don'ts rule out. The underline is the shape cue. */
.ms button.m.on{background:var(--warn);color:var(--acc-ink);text-decoration:underline}
.ms button.s.on{background:var(--blue);color:var(--acc-ink);text-decoration:underline}
.lane-h .fad{grid-column:2 / 4;display:flex;gap:6px;align-items:center}
.lane-h .fad input{height:14px}
.lane-h .fad span{font-size:10.5px;color:var(--tx3);width:38px;text-align:right}
.lane-w{position:relative;padding:8px 0;cursor:crosshair;display:flex;align-items:center}
.lane-w .wv{height:100%;min-height:52px;cursor:crosshair}
.lane-w .acts{position:absolute;right:8px;top:6px;display:flex;gap:2px;opacity:0;transition:opacity .15s;z-index:2}
.lane:hover .lane-w .acts{opacity:1}
.lane-w .acts .ib{background:var(--s2);width:28px;height:28px}
.lane.muted .wv{opacity:.3}
.lane.regen .wv{animation:shimmer 1s linear infinite}
@keyframes shimmer{0%,100%{opacity:.25}50%{opacity:.7}}
.selbox{position:absolute;top:4px;bottom:4px;background:oklch(70% .13 268 / .18);border:1px solid var(--blue);border-radius:4px;pointer-events:none}
.ph{position:absolute;top:0;bottom:0;left:220px;right:0;pointer-events:none;z-index:4}
.ph i{position:absolute;top:0;bottom:0;width:2px;background:var(--tx);left:calc(var(--p) * 100%);box-shadow:0 0 0 1px var(--bg)}
.addlayer{display:grid;grid-template-columns:220px 1fr;border-bottom:1px solid var(--line)}
.addlayer .lbl2{padding:14px 12px;border-right:1px solid var(--line);font-size:13px;color:var(--tx2);display:flex;gap:8px;align-items:center}
.addlayer form{display:flex;gap:8px;padding:10px 12px;align-items:center}
.addlayer input{flex:1;max-width:420px}
.st-foot{border-top:1px solid var(--line);padding:10px 20px;display:flex;align-items:center;gap:14px;flex-wrap:wrap;font-size:13px;background:var(--bg)}
.st-foot .selinfo{display:flex;gap:10px;align-items:center;padding-right:14px;border-right:1px solid var(--line)}
.st-foot .right{margin-left:auto;display:flex;gap:14px;align-items:center;color:var(--tx2)}

/* video studio */
.vs{display:grid;grid-template-rows:auto auto 1fr;height:100%;min-height:0}
.vs-top{position:relative;display:grid;grid-template-columns:minmax(0,1fr) var(--vs-w,320px);border-bottom:1px solid var(--line);min-height:0}
.vs-prev{padding:20px;display:grid;place-items:center;background:oklch(12.5% .008 265)}
.screen{position:relative;width:min(100%,640px);aspect-ratio:16/9;border-radius:var(--r);overflow:hidden;background:var(--s2)}
.screen .scene{position:absolute;inset:0;transition:opacity .25s}
.screen .subs{position:absolute;left:50%;bottom:10%;transform:translateX(-50%);background:oklch(15% .01 265 / .78);padding:6px 12px;border-radius:6px;font-size:15px;white-space:nowrap;max-width:90%;overflow:hidden;text-overflow:ellipsis}
.screen .tc{position:absolute;right:10px;top:10px;font-family:var(--mono);font-size:12px;background:oklch(15% .01 265 / .75);padding:3px 7px;border-radius:4px}
.screen .scene-l{position:absolute;left:12px;top:10px;font-size:12px;color:oklch(96% .01 80);font-weight:500;text-shadow:0 1px 6px oklch(10% 0 0 / .6)}
.vs-opts{border-left:1px solid var(--line);padding:18px;display:grid;gap:18px;align-content:start;overflow:auto}
.vs-opts .row{display:grid;gap:8px}
.tl2{padding:12px 20px 20px;overflow:auto;min-height:0}
.tl2-inner{position:relative;min-width:720px;--p:0}
.trk{display:grid;grid-template-columns:72px 1fr;gap:12px;align-items:center;margin-bottom:8px}
.trk > span{font-size:12px;color:var(--tx3)}
.trk .body{position:relative;height:40px;border-radius:6px;background:var(--s1);overflow:hidden}
.trk.video .body{display:flex;gap:2px;background:transparent}
.trk.video .body span{height:100%;border-radius:4px}
.voice-seg{position:absolute;top:8px;bottom:8px;border-radius:4px;background:var(--c-vox);opacity:.55}
.trk.music .body{height:52px}
.trk.music .wv .fill{fill:var(--c-melody)}
.trk.hits .body{cursor:copy;height:30px}
.hit{position:absolute;top:50%;width:12px;height:12px;margin:-6px 0 0 -6px;background:var(--acc);transform:rotate(45deg);border-radius:2px;cursor:pointer}
.hit:hover{background:var(--err)}
.trk.energy2 .body svg{width:100%;height:100%;display:block}
.cut{position:absolute;top:0;bottom:0;width:1px;background:var(--line2)}
.ph2{position:absolute;top:0;bottom:0;left:84px;right:0;pointer-events:none}
.ph2 i{position:absolute;top:0;bottom:0;width:2px;background:var(--tx);left:calc(var(--p) * 100%)}
.endmark{position:absolute;right:0;top:0;bottom:0;width:2px;background:var(--ok)}
.vs-bar{display:flex;align-items:center;gap:12px;padding:10px 20px;border-bottom:1px solid var(--line);flex-wrap:wrap}
.cutdowns{display:grid;gap:6px;padding:12px 20px;border-bottom:1px solid var(--line);background:var(--s1)}
.cutdowns .r{display:grid;grid-template-columns:32px 70px 1fr auto;gap:12px;align-items:center;font-size:13px}
.cutdowns .wv{height:26px}

/* library */
.lib{position:relative;display:grid;grid-template-columns:var(--lib-w,200px) minmax(0,1fr);height:100%;min-height:0}
.lib-side{border-right:1px solid var(--line);padding:16px 10px;display:grid;gap:2px;align-content:start;overflow:auto}
.lib-side .eyebrow{padding:14px 10px 6px}
.lib-side .nav-item .c{margin-left:auto;font-size:12px;color:var(--tx3);font-family:var(--mono)}
/* The table needs 1065px for its full column set, but this column is the
   viewport minus a 64px rail and a 200px sidebar, so it only fits from about
   1329px up. A viewport media query therefore folds columns at widths where
   they fit and still leaves the last column clipped at others: measured 278px
   of overflow and every row action off-screen at 768, and 206px at 1200 where
   the container narrows again. Keying the fold to the space the table actually
   has is the fix (issue #45).
   The steps mirror the phone fold below: genre/mood and AI disclosure go first,
   then key and length, then the waveform preview. The title column never
   folds. */
.lib-main{container-type:inline-size;container-name:libmain;overflow:auto;min-width:0;display:flex;flex-direction:column}
@container libmain (max-width:1064px){table.lt .hide-m{display:none}}
@container libmain (max-width:900px){table.lt .hide-s{display:none}}
@container libmain (max-width:780px){table.lt .mini{display:none}}
.lib-tools{display:flex;gap:10px;align-items:center;padding:14px 20px;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--bg);z-index:2;flex-wrap:wrap}
.lib-tools h2{font-size:18px;margin-right:8px}
.lib-tools .right{margin-left:auto;display:flex;gap:8px;align-items:center}
.lib-tools input[type=search]{width:240px;background:var(--s1)}
table.lt{width:100%;border-collapse:collapse;font-size:13px}
/* The sticky offset is the toolbar's measured bottom, not a constant. The
   toolbar is not one fixed height: it wraps to 133px on a 390px phone and
   collapses to 79px from 600px up, while a hardcoded value was wrong at both
   ends, leaving the header sitting on the first row at one width and floating
   38px down over it at another, swallowing that row's action button.
   CSS cannot read a sibling box, so the client measures and publishes
   --lib-tools-h; see measureLibTools in app.js. 61px is the desktop fallback
   (the 56px top bar plus its border) for the frame before the first paint. */
table.lt th{position:sticky;top:var(--lib-tools-h,61px);background:var(--bg);text-align:left;font-weight:500;color:var(--tx3);font-size:12px;padding:10px 12px;border-bottom:1px solid var(--line);white-space:nowrap;z-index:1}
table.lt th button{color:inherit;display:inline-flex;gap:4px;align-items:center}
table.lt th button:hover{color:var(--tx)}
table.lt th.on button{color:var(--tx)}
table.lt td{padding:8px 12px;border-bottom:1px solid var(--line);white-space:nowrap}
table.lt tr{transition:background .1s}
table.lt tbody tr:hover{background:var(--s1)}
table.lt tr.sel{background:var(--blue-lo)}
table.lt tr.cur td .t{color:var(--acc-hi)}
/* Row actions: the direct buttons are the desktop layout, the menu is the
   narrow one. Only one is ever visible, so the row stops being the widest
   thing on the page and the table fits a phone. */
.lib-menu{display:none}
.lib-menu:popover-open{display:block;position:fixed;inset:auto;margin:0;border:1px solid var(--line2);border-radius:var(--r);background:var(--s2);padding:4px;min-width:190px;box-shadow:0 12px 32px oklch(8% .01 265 / .5)}
.lib-menu .menu-item{display:flex;align-items:center;gap:9px;width:100%;padding:8px 10px;border-radius:6px;font-size:13px;color:var(--tx2);text-align:left}
.lib-menu .menu-item:hover,.lib-menu .menu-item:focus-visible{background:var(--s3);color:var(--tx)}
.lib-menu .menu-item svg{width:15px;height:15px;flex:none}
table.lt .t{font-weight:500}
table.lt .t small{display:block;font-weight:400;color:var(--tx3);font-size:12px}
table.lt .mini{width:140px}
table.lt .mini .wv{height:22px}
.bulk{position:sticky;bottom:0;margin-top:auto;display:flex;align-items:center;gap:10px;padding:10px 20px;background:var(--s2);border-top:1px solid var(--line2);font-size:13px}
.bulk .right{margin-left:auto;display:flex;gap:8px}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;padding:20px}
.tile{background:var(--s1);border-radius:var(--r-lg);padding:14px;display:grid;gap:10px;border:1px solid transparent;transition:border-color .15s}
.tile:hover{border-color:var(--line)}
.tile .wv{height:56px}
.tile .r{display:flex;align-items:center;gap:10px}
.tile .r b{font-weight:600;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lib-empty{padding:80px 20px;text-align:center;display:grid;gap:10px;justify-items:center;color:var(--tx2)}
.lib-empty h3{color:var(--tx);font-size:18px}
[popover]{background:var(--s2);color:var(--tx);border:1px solid var(--line2);border-radius:var(--r-lg);padding:16px;box-shadow:0 16px 40px oklch(8% .01 265 / .5)}
.filters{width:280px;display:grid;gap:16px}
.filters .r{display:grid;gap:8px;font-size:13px}
.filters .r > span{color:var(--tx2)}
.range2{display:flex;gap:8px;align-items:center}
.range2 input{width:70px;font-family:var(--mono)}

/* player */
.player{position:fixed;left:0;right:0;bottom:0;height:var(--player);background:var(--s1);border-top:1px solid var(--line);display:grid;grid-template-columns:minmax(200px,280px) 1fr auto;align-items:center;gap:20px;padding:0 20px;z-index:30;padding-bottom:env(safe-area-inset-bottom)}
.player .np{display:flex;gap:12px;align-items:center;min-width:0}
.player .np b{display:block;font-weight:500;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.player .np small{display:block;font-size:12px;color:var(--tx3)}
.player .mid{display:grid;grid-template-columns:auto 1fr auto;gap:12px;align-items:center}
.player .wv{height:32px}
.player .time{font-size:12px;color:var(--tx2);min-width:92px;text-align:right}
.player .acts{display:flex;gap:2px;align-items:center}
.player.empty .mid{color:var(--tx3);font-size:13px;grid-template-columns:1fr}

/* dialog chrome shared by #auth, #account and #acct. A `dialog#sheet` slide-in
   panel used to sit here with a .sh shell: no view renders it and no handler
   opens it, so the rules went with the markup. The live dialogs animate with
   `pop`, which is declared where #account uses it. */
dialog::backdrop{background:oklch(10% .01 265 / .55)}
.sh-h{padding:20px 22px;border-bottom:1px solid var(--line);display:flex;gap:12px;align-items:start}
.sh-h h3{font-size:18px}
.sh-h small{color:var(--tx3);font-size:13px}
.sh-h .ib{margin-left:auto}

/* auth dialog */
dialog#auth{border:1px solid var(--line2);border-radius:var(--r-lg);background:var(--s1);color:var(--tx);padding:0;width:min(400px,calc(100vw - 32px));box-shadow:0 24px 70px oklch(8% .01 265 / .5)}
dialog#auth[open]{animation:pop .22s var(--ease)}
/* Account settings carries three forms, so it is wider and scrolls its body
   while the header and each section heading stay put. */
dialog#account{border:1px solid var(--line2);border-radius:var(--r-lg);background:var(--s1);color:var(--tx);padding:0;width:min(460px,calc(100vw - 32px));max-height:min(86dvh,760px);box-shadow:0 24px 70px oklch(8% .01 265 / .5)}
dialog#account[open]{animation:pop .22s var(--ease)}
dialog#account .acct-body{padding:24px 24px 20px;gap:0;overflow:auto;max-height:min(86dvh,760px);align-content:start}
.acct-sec{display:grid;gap:12px;padding:18px 0;border-top:1px solid var(--line)}
.acct-sec:first-of-type{border-top:0;padding-top:14px}
.acct-sec h4{font-size:0.9375rem}
.acct-sec p.dim{font-size:12px;margin:0}
.acct-sec form{display:grid;gap:13px}
.acct-sec .f{display:grid;gap:7px}
.acct-sec label{font-size:12px;color:var(--tx2);font-weight:500}
/* Beats the shared `.au .submit{width:100%}` by specificity, so the account
   actions stay button-sized instead of stretching the full column. */
dialog#account .acct-sec .submit{width:auto;justify-self:start;min-width:150px}
.acct-sec.danger h4{color:var(--err)}
.acct-sec .del-row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.btn.danger{background:var(--err-lo);color:var(--err);border-color:transparent}
.btn.danger:hover{background:var(--err);color:var(--acc-ink)}
dialog#account .au-h{position:sticky;top:0;background:var(--s1);padding-bottom:4px;z-index:1}
dialog#account .foot{margin:0;padding-top:16px;border-top:1px solid var(--line)}
/* The full-page fallback link is a text link, so it needs its own hit area to
   reach the 44px minimum the way the buttons already do. */
dialog#account .foot a{display:inline-flex;align-items:center;min-height:44px}
@keyframes pop{from{transform:translateY(8px) scale(.98);opacity:0}to{transform:none;opacity:1}}
.au{padding:26px 26px 22px;display:grid;gap:18px}
.au-h{display:flex;gap:12px;align-items:start}
.au-h h2{font-size:19px;margin:0}
.au-h p{margin:3px 0 0;color:var(--tx3);font-size:13px}
.au-h .ib{margin-left:auto}
.au-tabs{display:flex;gap:4px;padding:3px;background:var(--bg);border:1px solid var(--line);border-radius:var(--r)}
.au-tabs button{flex:1;height:30px;border-radius:6px;font-size:13px;font-weight:500;color:var(--tx2);transition:background .15s,color .15s}
.au-tabs button.on{background:var(--s2);color:var(--tx)}
.au form{display:grid;gap:14px}
.au .f{display:grid;gap:7px}
.au .f > span,.au .f > label{font-size:12px;color:var(--tx2);font-weight:500}
.au input[type=text],.au input[type=email],.au input[type=password]{width:100%;height:38px;background:var(--bg);color:var(--tx);border:1px solid var(--line-in);border-radius:var(--r);padding:0 12px;outline:none;transition:border-color .15s,box-shadow .15s}
.au input:focus{border-color:var(--blue);box-shadow:0 0 0 2px var(--blue-lo)}
.au input[aria-invalid=true]{border-color:var(--err)}
.au .err{font-size:12px;color:var(--err);display:flex;gap:6px;align-items:center}
.au .err:empty{display:none}
.au .row{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--tx2)}
.au .row input[type=checkbox]{accent-color:var(--acc);width:15px;height:15px}
.au .submit{width:100%;height:38px}
.spin{animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* account dialog: positioned below the trigger and dismissed by Escape or backdrop */
#acct{position:fixed;inset:72px 16px auto auto;margin:0;padding:8px;width:min(320px,calc(100vw - 32px));max-height:min(420px,calc(100dvh - 96px));overflow:auto;border:1px solid var(--line2);border-radius:var(--r-lg);background:var(--s1);color:var(--tx);box-shadow:0 18px 50px oklch(8% .01 265 / .55)}
#acct:not([open]){display:none}
#acct[open]{display:grid;gap:2px}
#acct::backdrop{background:oklch(8% .01 265 / .28)}
.acct-head{display:grid;grid-template-columns:36px minmax(0,1fr) 32px;align-items:center;gap:10px;padding:8px 6px 14px;border-bottom:1px solid var(--line);margin-bottom:4px}
.acct-avatar{width:36px;height:36px;border-radius:50%;background:oklch(45% .09 268);display:grid;place-items:center;font-size:12px;font-weight:600}
.acct-details{min-width:0}
.acct-head .nm{font-size:0.875rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acct-head .em{font-size:0.8125rem;color:var(--tx3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acct-head .ib{margin-left:auto}
.acct-item{display:flex;align-items:center;gap:12px;width:100%;min-height:44px;padding:8px 12px;border-radius:var(--r-sm);font-size:0.875rem;text-align:left;text-decoration:none;color:var(--tx2)}
.acct-item:hover{color:var(--tx);background:var(--s2)}
.acct-item svg{width:18px;height:18px;flex:none}
#acct form{margin:0}
#acct form .acct-item{font:inherit}
.mk-menu-action{display:none}
.au .foot{font-size:13px;color:var(--tx3);text-align:center}
.sh-b{padding:20px 22px;overflow:auto;display:grid;gap:22px;align-content:start}
.sh-b .f{display:grid;gap:8px}
.sh-b .f > span{font-size:12px;color:var(--tx2);font-weight:500}
.radios{display:grid;gap:6px}
.radios label{display:flex;gap:10px;align-items:center;padding:10px 12px;border:1px solid var(--line-in);border-radius:var(--r);font-size:14px;cursor:pointer}
.radios label:has(input:checked){border-color:var(--acc);background:var(--s2)}
.radios label small{margin-left:auto;color:var(--tx3);font-size:12px}
.radios input{accent-color:var(--acc)}
.checks{display:grid;gap:8px;font-size:14px}
.checks label{display:flex;gap:10px;align-items:center;cursor:pointer}
.checks label.dis{color:var(--tx3);cursor:not-allowed}
.fname{font-family:var(--mono);font-size:12px;background:var(--bg);border:1px solid var(--line);border-radius:var(--r);padding:10px 12px;color:var(--tx2);word-break:break-all}
.sh-f{padding:16px 22px;border-top:1px solid var(--line);display:grid;gap:10px}
.exp-list{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.exp-list li{display:grid;grid-template-columns:18px 1fr;gap:10px;align-items:start;font-size:13px;color:var(--tx2)}
.exp-list svg{width:16px;height:16px;color:var(--acc);margin-top:2px}
.sh-f .note{font-size:12px;color:var(--tx3);display:flex;justify-content:space-between}
.prog{height:4px;border-radius:2px;background:var(--s3);overflow:hidden}
.prog i{display:block;height:100%;background:var(--acc);transform-origin:left;transform:scaleX(0)}
.lic{display:grid;grid-template-columns:36px 1fr;gap:12px;padding:14px;border-radius:var(--r);background:var(--ok-lo);font-size:13px}
.lic svg{color:var(--ok);width:22px;height:22px}
.lic p{color:var(--tx2);font-size:12px}
/* Informational terms, not a confirmation, so it must not read as a success state. */
.lic.neutral{background:var(--s1)}
.lic.neutral svg{color:var(--tx3)}

/* API page
   A single scrolling column like the other workspace views, measured rather
   than full-bleed: a request body is wide, but an unbounded line is unreadable,
   so the column stops at 860px and the JSON pre scrolls inside it. */
.api{max-width:860px;padding:32px 28px 56px;display:grid;gap:22px;align-content:start}
.api-h{display:grid;gap:6px}
.api-h h1{font-size:24px}
.api-h .muted{font-size:13px;line-height:1.6;max-width:62ch}
/* The reference is a list of cards rather than one table: every endpoint
   carries a different shape of detail, and a single table would size every row
   for the widest endpoint on the page. */
.api-sec,.api-calls{display:grid;gap:14px}
.api-sec-h{display:grid;gap:4px}
.api-sec-h h2{font-size:16px}
.api-sec-h .muted{font-size:13px;line-height:1.6;max-width:72ch}
/* Nine endpoints is enough that finding one by scrolling is work, so the page
   carries its own index. */
.api-jump{display:flex;flex-wrap:wrap;gap:6px}
.api-jump button{display:inline-flex;align-items:center;gap:7px;height:28px;padding:0 10px 0 6px;border:1px solid var(--line);border-radius:var(--r-sm);font-family:var(--mono);font-size:12px;color:var(--tx2);transition:background .15s,border-color .15s,color .15s}
.api-jump button:hover{border-color:var(--line2);background:var(--s1);color:var(--tx)}
.api-eps{display:grid;gap:10px}
/* The top bar is sticky, so a jumped-to card has to clear it. */
.api-ep{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--s1);scroll-margin-top:70px}
.api-ep-h{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:12px 14px;border-bottom:1px solid var(--line)}
.api-ep-h .path{font-family:var(--mono);font-size:12px;min-width:0;overflow-wrap:anywhere}
.api-ep-h .nm{margin-left:auto;font-size:12px;color:var(--tx3)}
.api-ep-b{display:grid;gap:13px;padding:14px}
.api-ep-b > p{font-size:13px;line-height:1.6;color:var(--tx2);max-width:74ch}
.api-meta{display:flex;flex-wrap:wrap;gap:6px}
.api-block{display:grid;gap:8px}
/* The name and its type hold a fixed column so the notes line up down the list
   instead of each note starting wherever the longest name ended. */
.api-params{display:grid;gap:0}
.api-params li{display:grid;grid-template-columns:190px minmax(0,1fr);gap:1px 12px;align-items:baseline;padding:7px 0;border-bottom:1px solid var(--line)}
.api-params li:last-child{border-bottom:0}
.api-params code{font-family:var(--mono);font-size:12px}
.api-params .ty{margin-left:8px;font-family:var(--mono);font-size:12px;color:var(--tx3)}
.api-params .nt{font-size:12px;line-height:1.55;color:var(--tx2)}
/* Success, warning and error are reserved steps, and a status code is exactly
   what they are for, so this is the one place on the page colour carries
   meaning. The number is still the message. */
.api-code{display:inline-block;min-width:44px;height:19px;line-height:19px;border-radius:4px;background:var(--s3);color:var(--tx2);font-family:var(--mono);font-size:12px;text-align:center}
.api-code.ok{background:var(--ok-lo);color:var(--ok)}
.api-code.warn{background:var(--warn-lo);color:var(--warn)}
.api-code.err{background:var(--err-lo);color:var(--err)}
.api-codes{display:grid;gap:5px}
.api-codes li{display:grid;grid-template-columns:50px minmax(0,1fr);gap:10px;align-items:baseline;font-size:12px;line-height:1.55;color:var(--tx2)}
/* The vocabulary of codes tiles, because it is nineteen short entries rather
   than nineteen readings. */
.api-codes.all{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:2px 20px}
.api-codes.all li{padding:6px 0;border-bottom:1px solid var(--line)}
.api-codes.all code{font-family:var(--mono);font-size:12px;color:var(--tx)}
.api-codes.all .nt{grid-column:2;font-size:12px;color:var(--tx3)}
/* Fields are short and numerous: the track body alone has seventeen, which is
   seventeen rows if each one takes a line of its own. */
.api-fields{display:grid;grid-template-columns:repeat(auto-fill,minmax(215px,1fr));gap:0 18px}
.api-fields li{display:flex;align-items:baseline;gap:10px;min-width:0;padding:4px 0;border-bottom:1px solid var(--line);font-size:12px}
.api-fields code{font-family:var(--mono);font-size:12px;overflow:hidden;text-overflow:ellipsis}
.api-fields span{margin-left:auto;flex:none;font-family:var(--mono);font-size:12px;color:var(--tx3)}
.api-conv{display:grid;gap:12px}
.api-conv h3{margin-bottom:4px}
.api-conv ul{display:grid;gap:3px;margin:0;padding-left:18px}
.api-conv li{font-size:13px;line-height:1.6;color:var(--tx2)}
.api-cfg{display:grid;gap:12px;padding:16px 18px;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--s1)}
/* Label and control share a row so the two override fields line up under the
   segmented control instead of each taking the full width. */
.api-cfg .r{display:grid;grid-template-columns:110px minmax(0,1fr);align-items:center;gap:12px}
.api-cfg .r > span{font-size:12px;color:var(--tx2)}
.api-cfg p{font-size:12px;line-height:1.6;margin:2px 0 0;max-width:70ch}
.api-log{display:grid;gap:6px;align-content:start}
/* One call per row. The row is the hit target, so it carries the padding and
   the border, and the expanded body hangs off it rather than adding a second
   clickable surface. */
.in-e{display:grid;gap:4px;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r);background:var(--s1);cursor:pointer;transition:background .15s,border-color .15s}
.in-e:hover{background:var(--s2);border-color:var(--line2)}
.in-e.open{background:var(--s2);border-color:var(--line2)}
.in-e .l1{display:flex;align-items:center;gap:10px}
/* The verb is a fixed-width tag so what follows it lines up down a list
   instead of shifting with the method name's length. The log and the reference
   are the two places a method is printed, so the tag is shared. */
.verb{flex:none;display:inline-block;width:54px;text-align:center;height:18px;line-height:18px;border-radius:4px;background:var(--s3);color:var(--tx2);font-family:var(--mono);font-size:10.5px;letter-spacing:.04em}
.in-e .verb{width:60px}
.in-e .verb.ws{background:var(--acc-lo);color:var(--acc)}
.in-e b{font-size:13px;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.in-e .usd{margin-left:auto;flex:none;font-family:var(--mono);font-size:12px;color:var(--tx3)}
.in-e > .dim{font-size:12px;padding-left:70px}
/* The body is the widest thing on the page and the least readable when it is
   allowed to set its own width, so it scrolls inside the column. */
.in-e pre{margin:8px 0 0;padding:12px 14px;border-radius:var(--r-sm);background:var(--bg);border:1px solid var(--line);font-family:var(--mono);font-size:12px;line-height:1.55;color:var(--tx2);overflow:auto;max-height:52vh}
.in-e .in-copy{padding:6px 0 0 70px}
.in-empty{padding:44px 18px;text-align:center;color:var(--tx3);font-size:13px;line-height:1.6;border:1px dashed var(--line);border-radius:var(--r-lg)}
@media (max-width:720px){
  .api{padding:22px 16px 40px}
  /* Below this the two-column control rows leave the inputs too narrow to
     read a URL in, so the label stacks above its control instead. */
  .api-cfg .r{grid-template-columns:minmax(0,1fr);gap:6px}
  .in-e > .dim,.in-e .in-copy{padding-left:0}
  /* A name and its note sharing a row leaves the note about eighty pixels
     wide here, so they stack instead. */
  .api-params li{grid-template-columns:minmax(0,1fr);gap:2px}
  /* The name goes under the method and path rather than being pushed right to
     a margin the card no longer has room for. */
  .api-ep-h .nm{margin-left:0;width:100%}
  .api-fields,.api-codes.all{grid-template-columns:minmax(0,1fr)}
}

/* toasts / screens */
#toasts{position:fixed;left:50%;bottom:calc(var(--player) + 16px);transform:translateX(-50%);display:grid;gap:8px;z-index:60;pointer-events:none}
.toast{display:flex;gap:10px;align-items:center;padding:10px 14px;border-radius:var(--r);background:var(--tx);color:var(--bg);font-size:13px;font-weight:500;animation:tin .3s var(--ease);box-shadow:0 10px 30px oklch(8% .01 265 / .4)}
.toast svg{width:16px;height:16px}
@keyframes tin{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.screens-btn{position:fixed;right:16px;bottom:calc(var(--player) + 16px);z-index:40;display:flex;gap:8px;align-items:center;height:34px;padding:0 12px;border-radius:999px;background:var(--s3);border:1px solid var(--line2);font-size:12px;font-weight:500}
.screens-btn:hover{background:var(--line2)}
#screens{width:280px;padding:8px;margin:0;inset:auto 16px calc(var(--player) + 58px) auto;position:fixed}
#screens .eyebrow{padding:8px 10px 4px}
#screens button{display:flex;width:100%;gap:10px;align-items:center;padding:8px 10px;border-radius:6px;font-size:13px;color:var(--tx2);text-align:left}
#screens button:hover{background:var(--s3);color:var(--tx)}
#screens button.on{color:var(--acc-hi)}

.mob-nav{display:none}

@media (max-width:1100px){
  :root{--side:64px}
  .side .logo span.word,.nav-item .lbl-t,.nav-item .kbd,.meter,.side .plan-row{display:none}
  .nav-item{justify-content:center;padding:0}
  .side .logo{justify-content:center;padding:6px 0 18px}
  /* The 64px rail cannot hold the mark and the toggle in one row: after the
     rail's horizontal padding there are 44px of content width and the toggle
     is 44px on its own. The toggle stacks below the mark rather than shrinking
     under 44px (R-03) or hiding (it is the only control that expands the
     rail). min-width:0 on the logo is right for text that must shrink and wrong
     for a fixed mark: it is what crushed the logo to 3px in this band. */
  .side-head{flex-direction:column;align-items:center;gap:2px}
  .side-head .logo{flex:none;min-width:44px;min-height:44px}
  .side-toggle{margin-right:0}
  .create{grid-template-columns:var(--create-w,340px) minmax(0,1fr)}
  .vs-top{grid-template-columns:minmax(0,1fr) var(--vs-w,280px)}
}
@media (max-width:900px){
  .mk-nav{position:sticky;justify-content:space-between;gap:12px;padding-left:20px;padding-right:20px}
  .mk-nav .right{display:none}
  .mk-burger{display:inline-flex;align-items:center;justify-content:center;gap:7px;width:auto;min-width:44px;height:44px;padding:0 10px;font-size:13px;color:var(--tx2)}
  .mk-links{display:none}
  .mk-links.open{display:flex;position:absolute;top:100%;left:0;right:0;z-index:30;flex-direction:column;gap:2px;padding:8px 12px 12px;background:var(--s1);border-bottom:1px solid var(--line2);box-shadow:0 18px 28px oklch(8% .01 265 / .32)}
  .mk-links.open button,.mk-links.open .mk-menu-action{display:flex;align-items:center;width:100%;min-height:44px;padding:0 12px;text-align:left;border-radius:6px;color:var(--tx2);font-size:14px;text-decoration:none}
  .mk-links.open .mk-menu-action{display:flex;align-items:center;min-height:44px;padding:0 12px;border-radius:6px;color:var(--tx2);font-size:14px;text-decoration:none}
  .mk-links.open form.mk-menu-action{margin:0}
  .mk-links.open form.mk-menu-action button{display:flex;align-items:center;justify-content:flex-start;width:100%;min-height:44px;padding:0;color:inherit;text-align:left}
  .mk-links.open button:hover,.mk-links.open .mk-menu-action:hover{background:var(--s2);color:var(--tx)}
  .mk-links.open button.on{box-shadow:inset 0 0 0 1px var(--line2)}
  /* The mode switch has to fill the menu like every other row, or it floats
     183px wide against 44px rows spanning 366px and the menu reads as broken.
     inline-flex shrinks to content in a column flex container, so it needs an
     explicit stretch; the two halves then divide it evenly. These rules sit
     after the .mk-links.open button rules above on purpose, since those would
     otherwise restyle the halves as full-width stack rows. */
  .mk-links.open .mk-mode{display:flex;width:100%;margin-right:0}
  .mk-links.open .mk-mode button{width:auto;flex:1 1 0;min-width:0}
}
@media (max-width:860px){
  .split{grid-template-columns:1fr}
  /* The 2:1 ratio is a desktop read. Stacked, the caveat would sit the same
     distance below the CTA as the CTA sits below the figure, so the plan and its
     caveat need a clearer break than the shared 24px gap gives them. */
  .price-grid{grid-template-columns:1fr;gap:16px}
  .price-card{padding:28px}
  .price-side{padding:24px}
  .trust{grid-template-columns:1fr 1fr}
  /* The 860px fold leaves 40px 1fr auto. The auto track sizes the CTA button,
     so the title track absorbs the entire shortfall: it measured 108px against
     a 154px button and wrapped four-line titles beside one-line buttons, which
     inverts the hierarchy. Both middle tracks get a floor so the title wins the
     space and the CTA stops growing past the desktop width. */
  .ex-row,.ex-row.featured{grid-template-columns:40px minmax(140px,1fr) minmax(0,auto)}
  /* Child combinators, not descendants. The rule wants to drop the row's own
     summary waveform and the duration to make room for the title and the CTA.
     As a descendant selector it also reached the .ex-stems panel opened by the
     "Illustrative layers" button, so every stem measured 0x0 on a phone and the
     disclosure showed four bare labels: the control opened something empty. */
  .ex-row>.wv,.ex-row>.meta-x{display:none}
  /* The CTA is white-space:nowrap, so below this fold its intrinsic width wins
     against the title track and the label is pushed past the right edge. At 320
     the document gains 14px of horizontal scroll that html{overflow-x:hidden}
     then hides, leaving the label clipped with no way to reach it. Give it a row
     of its own instead of letting it compete for the same line. */
  .ex-row .btn.sm{grid-column:1 / -1;justify-self:start}
  /* This CTA's label is a full sentence. Under WCAG 1.4.12 text spacing it
     needs 347px of inline content in a 320px viewport, so the nowrap rule
     clips it. Let this one label reflow. */
  .section-head .btn{white-space:normal}
  .ex-stems{grid-column:1 / -1}
  .create{grid-template-columns:minmax(0,1fr);height:auto}
  .panel{border-right:0;border-bottom:1px solid var(--line);overflow:visible}
  .results{overflow:visible}
  /* Sticky positions a bar inside its containing block, which is .panel. Once
     the stack puts .results below .panel in the same scroller, the panel's own
     bottom edge rises above the scrollport and the bar is carried up with it:
     at full scroll it measured 43px clipped, leaving 18 of the button's 46px
     visible. Sticking a control whose containing block ends partway up a long
     scroll cannot work, so on the stacked layout the bar returns to the flow
     and the button is fully reachable by scrolling to it. */
  .gen-wrap{position:static;margin:0 -20px -28px}
  .lib{grid-template-columns:1fr}
  .lib-side{display:none}
  .vs-top{grid-template-columns:1fr}
  .vs-opts{border-left:0;border-top:1px solid var(--line)}
  /* .vs declares grid-template-rows but no grid-template-columns, so its single
     implicit track is max-content sized. The 720px timeline floor on .tl2-inner
     then sizes the whole view at 760px inside a 390px phone, behind a 370px
     inner scroll. An explicit minmax(0,1fr) track lets the track shrink to the
     viewport and confines that floor to .tl2, which already scrolls. */
  .vs{height:auto;grid-template-columns:minmax(0,1fr)}
}
@media (max-width:720px){
  :root{--player:64px}
  /* Below about 360px of height the three fixed bars (header 56, bottom nav 56,
     player 64) leave too little room for the content to scroll: at 400% zoom
     the app box was 105px holding a 133px sticky toolbar, so the nav covered
     the view toggle and the page could not scroll at all, leaving the Filters
     and Grid/List controls permanently unreachable (issue #44).
     Handing the scroll back to the document is what WCAG 1.4.10 asks for. The
     toolbar stops being sticky because a sticky element inside a scrolling
     page pins itself to the short viewport instead of scrolling away. */
  @media (max-height:360px){
    .app{height:auto;min-height:calc(100dvh - var(--player) - 56px)}
    /* .main pins its second row to 1fr of a fixed .app, and .content scrolls
       inside it, so neither grows until both release. The header row keeps its
       56px: that is the app's own top bar, not the sticky toolbar. */
    .main{grid-template-rows:56px auto;min-height:0}
    .content{overflow:visible;min-height:0}
    .lib-main{overflow:visible;min-height:0}
    .lib-tools{position:static}
  }
  /* 100vh is the large viewport: the height with the browser's URL bar
     retracted. On a phone that is taller than the area the user can see, so a
     100vh shell stacks its fixed bars below the visible area. The body rule
     above already uses 100dvh, so this is the file disagreeing with itself. */
  .app{grid-template-columns:1fr;height:calc(100dvh - var(--player) - 56px)}
  .side{display:none}
  .mob-nav{display:flex;position:fixed;left:0;right:0;bottom:var(--player);height:56px;background:var(--bg);border-top:1px solid var(--line);z-index:29;padding-bottom:env(safe-area-inset-bottom)}
  .mob-nav button{flex:1;display:grid;place-items:center;gap:2px;font-size:10.5px;color:var(--tx3);padding-top:6px}
  .mob-nav button.on{color:var(--acc)}
  .mob-nav svg{width:20px;height:20px}
  .top{padding:0 12px}
  /* The Producer/Creator .seg has a 189px min-content, and a flex child without
     min-width:0 refuses to shrink below it, so the header could not fit 320px
     once WCAG 1.4.12 text spacing was applied. */
  .top>*{min-width:0}
  .top .seg{min-width:0}
  .top .search,.top .hide-m{display:none}
  .player{grid-template-columns:1fr auto;gap:10px;padding:0 12px}
  .player .mid .wv,.player .mid .time{display:none}
  .player .mid{display:none}
  .player .acts .hide-m{display:none}
  .mk-nav{height:56px;padding-left:16px;padding-right:16px}
  .mk-burger{display:inline-flex}
  .section-head{align-items:flex-start;flex-direction:column;gap:14px}
  .section-head h2{font-size:28px}
  /* The display type is the one place a fixed px is defensible on desktop and
     wrong on a phone. Both floors won at every phone width because the vw term
     is far below them, so the hero rendered 3 lines at 40px inside a 297px
     measure: 2.2x larger relative to the viewport than the desktop headline.
     The floors drop to the size a phone can actually set a line at. */
  .hero h1{font-size:clamp(30px,5.5vw,68px);max-width:none}
  .price-head h1{font-size:clamp(28px,4.5vw,52px)}
  /* .split h2 was never stepped, so it sat at the desktop 26px beside a
     .section-head h2 of 28px: two of the three heading levels were unordered.
     The split column is 262px of a 342px column once its 40px padding is
     taken off, which is the width that decides this size. */
  .split h2,.split h3{font-size:22px}
  .hero{padding:56px 0 48px;grid-template-columns:1fr;gap:20px}
  .hero-art{min-height:250px}
  .hero-art .art-wave{margin-top:40px}
  .split > div{min-width:0;overflow:hidden}
  .compiled{max-width:100%;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere}
  .demo-stems{min-width:0;overflow:hidden}
  .demo-stems .ln{grid-template-columns:58px minmax(0,1fr);min-width:0}
  .demo-stems .ln .wv{min-width:0}
  .cmp{min-width:560px}
  .results{padding:16px}
  .take .acts .lbl-t{display:none}
  /* width:100% was not enough: the tools row is a wrapping flex line, so the
     input still shared a line with the filter buttons and offered 54px of
     content width at 320. Taking a whole line of its own lets the placeholder
     render instead of clipping to "Searc". */
  .lib-tools input[type=search]{flex:1 1 auto;min-width:120px;width:auto}
  /* A 100% basis is resolved against .right, which is nowrap, so the search
     took its own line and then the row beside it needed 435px inside a 390px
     scroller: the Grid view control ended up 40px off-screen and could not be
     tapped (issue #39). display:contents promotes the search, the Filters
     button and the view control to direct children of .lib-tools, which
     already wraps, so the search keeps its line and the rest reflow beside it.
     flex-wrap on .right would fit the row too, but it stacks the same three
     items a second time and measures 169px of toolbar against this one's 133px. */
  .lib-tools .right{display:contents}
  table.lt .mini,table.lt .hide-m{display:none}
  /* The fold removed the row buttons but not the width: the table still needed
     531px inside a 390px scroller, so the row action menu sat 141px off-screen
     and needed a horizontal scroll nobody was told about. Key and Length fold
     with the rest; both are still on the row's own menu and the grid view, so
     nothing becomes unreachable. Length stays sortable because the header
     button is hidden, not removed. */
  table.lt .hide-s{display:none}
  /* The title cannot be truncated. WCAG 1.4.10 requires the content to survive
     400% zoom, and an ellipsis is a failure there: the sweep caught exactly
     that, with the title and its folder line clipped at a 360px viewport. The
     remaining width is bought by folding the actions column to the same single
     menu button the row already carries on desktop, so the title gets the space
     back and wraps onto as many lines as it needs. */
  table.lt td.t{white-space:normal}
  table.lt th:last-child,table.lt td:last-child{width:44px;padding:0 4px}
  table.lt .lib-acts{gap:0}
  /* .section carries 72px of top and bottom padding from the base rule, which
     is 144px of empty space per section on a phone. The 720px band already
     steps .hero and .section-head but never .section, so the marketing pages
     scroll through deserts. This is the one change that gives the pages a
     phone-sized vertical rhythm rather than a squeezed desktop one. */
  .section{padding:40px 0}
  .price-head{padding:40px 0 24px}
  /* The API reference jumps to each endpoint card. At phone widths the player
     and the bottom nav stack 120px up from the bottom edge, so a card that
     scrolls to rest at the very bottom is read under both bars. The top offset
     already accounts for the sticky header; this is the matching bottom one. */
  .api-ep{scroll-margin-bottom:120px}
  /* The account dialog's own cap is 86dvh, which on a phone put its lower edge
     under the 120px the player and bottom nav stack up from the bottom. The
     dialog is in the top layer, so nothing was unreachable, but the last
     section was read through two bars. The cap moves to the dialog rather than
     only its body, because the dialog's own max-height was the one winning. A
     dialog with no base rule centres itself, so the margin is what actually
     places it: 32px above and 88px below puts the whole dialog between the two
     bars. The body's cap subtracts the sticky header, which does not scroll. */
  dialog#account{max-height:calc(100dvh - var(--player) - 56px - 80px);margin:32px 0 88px}
  dialog#account .acct-body{max-height:calc(100dvh - var(--player) - 56px - 32px - 57px)}
  /* The create empty state centres its content, so 64px of top padding is dead
     space above the first line of copy rather than a deliberate offset. */
  .empty:not(.player){padding-top:32px}
  /* Below the breakpoint the row's own buttons are the widest cell by a wide
     margin, so they fold into one menu button and the row stops overflowing. */
  table.lt .lib-act{display:none}
  table.lt .lib-acts>button:not([data-act="rowMenu"]){display:none}
  /* The fold rule hides every .lib-act, and the menu button wears that class
     too. This is the one button the fold exists to keep. */
  table.lt .lib-acts>button[data-act="rowMenu"]{display:inline-grid}
  .screens-btn{bottom:calc(var(--player) + 68px)}
  #toasts{bottom:calc(var(--player) + 72px)}
  .trust{grid-template-columns:1fr;gap:16px}
  table.cmp th:nth-child(4),table.cmp td:nth-child(4),table.cmp th:nth-child(5),table.cmp td:nth-child(5){display:none}
  table.plans td:first-child{width:auto}
}
@media (max-width:480px){
  /* The wordmark cannot fit beside the burger and both auth actions on a
     narrow phone. The mark alone carries the brand, the same way the app
     sidebar drops its wordmark. */
  .mk-nav .word{display:none}
}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

/* ===== touch targets ===== */
/* WCAG 2.5.8 wants 24x24 and Apple/Google guidance asks for 44x44. The desktop
   density is deliberate and stays, but a fingertip cannot hit a 28px segmented
   button, so every control below is grown to 44px wherever the input is coarse
   or the layout is already in its phone mode. */
@media (max-width:720px),(pointer:coarse){
  .btn.sm,.btn{height:44px;padding:0 14px}
  .acct-sec .submit{width:100%}
  dialog#account .acct-sec .submit{width:100%;min-height:44px}
  .acct-sec .del-row .btn{flex:1 1 100%}
  .btn.sm{padding:0 12px}
  .seg button{height:44px;min-width:44px;padding:0 14px}
  /* The base 2px seam is desktop density for a cursor that can aim at it. Two
     44px targets 2px apart read as one control, and on the Studio guide row
     that is three of them, so a mis-press switches the wrong section type. */
  .seg{padding:2px;gap:8px}
  .chip{height:44px;padding:0 16px}
  .toggles .chip{height:44px}
  .try .chip{height:44px;padding:0 12px}
  .ib{width:44px;height:44px}
  .ib svg{width:20px;height:20px}
  .avatar{width:44px;height:44px;font-size:14px}
  .play{width:44px;height:44px}
  .play svg{width:18px;height:18px}
  .play.sm{width:44px;height:44px}
  /* At phone widths the wordmark drops and the button collapses to the 26px
     mark, so the button itself has to carry the 44px. */
  .logo{min-height:44px;min-width:44px;justify-content:center}
  .logo-mark{width:28px;height:28px}
  .lock{width:44px;height:44px}
  .lock svg{width:18px;height:18px}
  /* These two carry a 1px border, so the outer height has to be 46px for the
     inner button to actually measure 44px. */
  .stepper{height:46px}
  .stepper button{width:44px}
  .stepper input{width:64px}
  .blk{height:46px}
  .blk button{padding:0 12px}
  .blk .n{padding:0 12px;min-width:44px}
  .blk .x{padding:0 12px;min-width:44px}
  .blk.add span{padding:0 14px!important}
  .screens-btn{height:44px;padding:0 16px}
  .api-jump button{height:44px;padding:0 14px 0 10px}
  input[type=text],input[type=email],input[type=password],input[type=number],input[type=search],select{height:44px}
  .au input[type=text],.au input[type=email],.au input[type=password]{height:44px}
  /* The in-app auth dialog is the primary auth surface on a phone, and it was
     the one place the coarse-pointer block did not reach: its checkbox row stayed
     21px tall with a 15px box and default cursor, its submit stayed 38px, and
     its mode tabs stayed 30px inside a container with a 3px dead inset. The
     Blade pages already measure 24x24 / 316x44; these bring the modal to parity. */
  .au .submit{height:44px}
  .au .row{min-height:44px;cursor:pointer}
  .au .row input[type=checkbox]{width:24px;height:24px;cursor:pointer}
  .au-tabs{padding:0}
  .au-tabs button{height:44px}
  .au .foot button{display:inline-block;min-height:44px;padding:0 4px}
  /* A range input is a hairline by default, so the hit area is padded out
     vertically rather than the visible track being made thicker. */
  input[type=range]{height:44px;background:transparent}
  input[type=checkbox]{width:22px;height:22px}
  .checks label,.radios label,.auth .checkbox label{min-height:44px}
  .trow{min-height:44px}
  .nav-item{height:44px;min-width:44px}
  .mob-nav button{min-height:44px}
  .eng button{flex:1 1 100%}
  /* The floating Screens button sits over the sticky generate note, so the note
     gets room on the right instead of being read through it. */
  .gen-note{padding-right:104px;padding-left:8px}

  /* Stem mixer mute and solo. These are also spaced apart, because target size
     only works with target spacing: two large controls touching behave like one
     large control, and a mis-tap on this pair silences the wrong instrument. */
  .ms{gap:8px}
  .ms button{width:44px;height:44px;border-radius:6px;font-size:13px}

  /* Library row menu. Five items at the base 36.9px with a 0px seam behave as
     one 195px block, and the items are actions with real consequences: publish,
     delete audio, open in Studio. The height is raised so each row is a target
     a thumb can pick. The separation is a bottom margin rather than a gap: the
     popover is display:block, so a gap on the container does nothing. The last
     item's margin is cancelled so the popover's own 4px padding is not doubled
     at the bottom edge. */
  .lib-menu .menu-item{min-height:44px;padding:11px 10px;margin-bottom:4px}
  .lib-menu .menu-item:last-child{margin-bottom:0}

  /* Hero prompt chips and the example rows are 44px and 69px tall and were laid
     out 6px apart, so adjacent large targets read as one strip. The gap does
     the separating that a border would otherwise do on a wide canvas. */
  .try{gap:8px}
  .empty .ex{gap:10px}

  /* Energy curve handles. The visible dot is r=6 in a 300-unit viewBox, which
     measures 13x12px, and the host is touch-action:none, so a finger that
     lands beside the dot grabs nothing and a finger that lands on it starts a
     drag with no target to aim at. A stroke is part of an SVG shape's hit area,
     so a wide transparent stroke grows the target without changing the dot or
     the curve. 30px of stroke is 21 user units of radius, which clears 44px on
     screen and keeps the five handles clear of each other at their ~60-unit
     spacing. The dark 2px outline is dropped on touch because the same stroke
     property now carries the hit area. */
  .energy .pt{stroke:transparent;stroke-width:30}

  /* The fader is a hairline in a 44px box, so the range input keeps the hit area
     the block above already gave it. .lane-h .fad input outranks
     input[type=range], and the base rule keeps its 14px for desktop density, so
     the 44px is restated at the base rule's own specificity and wins by coming
     later in the cascade. */
  .lane-h .fad input{height:44px}

  /* Both timeline rulers are seek surfaces, and the bar ruler is 18px, under
     the 24px floor. They also sit on a shared edge with a 0px gap, so a thumb
     landing on the seam seeks the wrong ruler. The label text keeps its own
     density; the hit area grows, and the two surfaces are separated so the
     target a press lands on is unambiguous. */
  .ruler .secs{height:44px}
  .bars{height:44px;margin-top:4px}

  /* Library sort headers. The base rule gives them a font and nothing else, so
     they collapse to the height of their own text. The padding keeps the three
     headers from touching once each one is 44px tall. */
  table.lt th button{min-height:44px;min-width:44px;padding:0 6px}
  /* The library table's inline waveform is a genuine seek control, not art, so
     it keeps its slider role and has to clear 44px like the other seek
     surfaces. The cell is 32.5px wide at tablet, so the target is given a floor
     rather than clipped. */
  table.lt .mini .wv{min-width:44px;min-height:44px}
  /* Row checkboxes. Scaling the native input to 44px would sit oddly against a
     13.5px table, so the cell carries the target and the box stays small. The
     cell holds the same data-act as the box inside it, so a press anywhere in
     the 44x44 cell toggles selection; without that wiring the press falls
     through to the row handler and starts playback. A label wrapper was the
     alternative, but a label forwards its click to the input as a second event
     and toggles twice. */
  table.lt td.sel-cell,table.lt th.sel-cell{position:relative;width:44px;min-width:44px;height:44px;padding:0}
  /* The select-all cell is the one th that also carries `position:relative`, to
     anchor its absolutely placed checkbox. That outranks the sticky rule above,
     so this header alone scrolled away and let the toolbar cover the band. Sticky
     is a positioned value too, so it anchors the checkbox just as well and keeps
     this header pinned with the rest of the row. */
  table.lt th.sel-cell{position:sticky}
  table.lt td.sel-cell input[type=checkbox],table.lt th.sel-cell input[type=checkbox]{position:absolute;left:11px;top:50%;transform:translateY(-50%)}

  /* Marketing nav. Between 901px and 1100px this is a visible row on a touch
     device, so the burger treatment does not apply and the base rule's 6px of
     padding is the only sizing it gets. Match the .mk-links.open rule below. */
  .mk-links button,.mk-links a{min-height:44px;display:flex;align-items:center}
  .mk-links{gap:6px}

  /* Video Studio markers. The visible diamond stays 12px; the touch area is a
     transparent box around it, so the hit target grows without the ruler
     changing density. The lane grows to the box height because .trk .body clips
     overflow and would crop the hit area back to 30px. The base .hit:hover
     recolors the whole box, which is now 44px wide, so hover moves to the
     diamond only. */
  .trk.hits .body{height:44px}
  .hit{width:44px;height:44px;margin:-22px 0 0 -22px;background:none;transform:none;border-radius:0;display:block}
  .hit::before{content:"";position:absolute;left:16px;top:16px;width:12px;height:12px;background:var(--acc);border-radius:2px;transform:rotate(45deg);transition:background .15s var(--ease)}
  .hit:hover{background:none}
  .hit:hover::before{background:var(--err)}

  /* Press feedback. A desktop control announces a hover on pointer entry, but
     a touch press has no hover, so a tap on anything outside the .btn and .eng
     families gave no sign it registered. The keyboard ring already covers
     focus; this covers the thumb. One rule per control family, all sharing the
     1px nudge .btn already uses, so the app presses consistently. */
  .chip:active,.seg button:active,.play:active,.ib:active,.avatar:active,
  .mk-burger:active,.mk-links button:active,.mk-links a:active,.nav-item:active,
  .mob-nav button:active,.api-jump button:active,.screens-btn:active,
  .trow:active,.lock:active,.stepper button:active,.blk button:active,
  input[type=range]:active,.grip:active,.ex-row:active,.lt tbody tr:active,
  .toggles .chip:active,.try .chip:active,.ms button:active,.feedback .chip:active
  {transform:translateY(1px)}
  .auth button:active,.auth button.danger:active{transform:translateY(1px);filter:brightness(1.06)}
  .auth button.link-btn:active{transform:none;text-decoration:underline}
}

/* ============ auth pages ============ */
/* Sign in, register, password reset, and the standalone /account page. They load
   this file instead of carrying their own palette, so a token changed here
   reaches them too. Everything is scoped to .auth so none of it can reach the
   app shell, which shares the same element names for different components. */
.auth{min-height:100dvh;display:grid;place-items:center;padding:24px}
.auth .panel{width:100%;max-width:380px;background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);padding:32px}
.auth .brand{display:flex;align-items:center;justify-content:center;gap:10px;min-height:44px;margin-bottom:28px;color:var(--tx);font-size:16px;font-weight:600;letter-spacing:-.02em;text-decoration:none}
.auth .brand:hover{text-decoration:none}
.auth .brand-mark{width:26px;height:26px;border-radius:7px;background:var(--acc);display:grid;place-items:center}
.auth .brand-mark span{display:flex;gap:2px;align-items:center}
.auth .brand-mark i{display:block;width:3px;background:var(--acc-ink);border-radius:2px}
.auth h1{font-size:24px;margin:0 0 4px}
/* Sign in and register have no .sub, so the heading takes over the gap the
   subheading would normally leave above the form. */
.auth h1:not(:has(+ .sub)){margin-bottom:24px}
.auth .sub{margin:0 0 24px;color:var(--tx3);font-size:13px}
.auth .field{margin-bottom:16px}
.auth label{display:block;margin-bottom:6px;font-size:12px;font-weight:500;letter-spacing:.09em;text-transform:uppercase;color:var(--tx2)}
.auth input[type=text],.auth input[type=email],.auth input[type=password]{width:100%;height:40px;padding:0 12px}
.auth .checkbox{display:flex;align-items:center;gap:8px;margin-bottom:20px;font-size:13px;color:var(--tx2)}
/* The native checkbox renders as a bright block on a dark surface, so it takes
   the accent colour. The label beside it is sentence case, not a field label.
   The label wraps the input rather than sitting beside it as a sibling, so the
   whole row forwards one click to the box and there is no dead strip to its
   right or over the input; this is the same shape .checks and .radios use. */
.auth .checkbox label{display:flex;align-items:center;gap:8px;flex:1;cursor:pointer;margin:0;text-transform:none;letter-spacing:0;font-size:13px}
.auth .checkbox input{width:16px;height:16px;margin:0;flex:none;cursor:pointer}
.auth button[type=submit]{width:100%;height:40px;border-radius:var(--r);background:var(--acc);color:var(--acc-ink);font-weight:600}
.auth button[type=submit]:hover{background:var(--acc-hi)}
/* A closed gate renders the submit as a labelled disabled control: the text
   carries the state (never colour alone), and the muted surface treatment
   reads as secondary rather than as the action orange. */
.auth button[type=submit]:disabled{background:var(--s2);color:var(--tx3);cursor:not-allowed}
.auth button[type=submit]:disabled:hover{background:var(--s2)}
.auth .error{margin:0 0 16px;padding:10px;background:var(--err-lo);border:1px solid var(--err);border-radius:var(--r);color:oklch(85% .09 25);font-size:13px}
.auth .error ul{margin:0;padding-left:18px}
/* A confirmation is not an error, so it gets the success treatment instead of
   the red one, which would read as a failure. */
.auth .status{margin:0 0 16px;padding:10px;background:var(--ok-lo);border:1px solid var(--ok);border-radius:var(--r);color:oklch(85% .09 158);font-size:13px}
.auth .foot{margin:20px 0 0;font-size:13px;color:var(--tx3);text-align:center}
.auth .foot form{margin:0}
.auth a{color:var(--acc);text-decoration:none}
.auth a:hover{text-decoration:underline}
.auth .sec-h{font-size:16px;margin:0 0 12px}
.auth h2.sec-h:not(:first-of-type){margin-top:28px}
.auth .sec-h + .sub{margin-bottom:12px}
.auth .danger-h{color:var(--err)}
/* These need to out-rank `.auth button[type=submit]`, which is a class plus an
   attribute selector, so the modifier carries the same shape. */
.auth button.danger{background:var(--err);color:oklch(15% .02 25)}
.auth button.danger:hover{background:var(--err);filter:brightness(1.12)}
.auth button.link-btn{width:auto;height:auto;background:transparent;color:var(--acc);padding:0;font-weight:500}
.auth button.link-btn:hover{background:transparent;text-decoration:underline}
@media (max-width:720px),(pointer:coarse){
  .auth{padding:16px}
  .auth .panel{padding:24px 20px}
  .auth button[type=submit]{height:44px}
  .auth button.link-btn{height:auto;min-height:44px;display:inline-flex;align-items:center}
  /* 22px is under the 24px floor. The wrapping label already carries a 44px
     row and forwards one click, so the box only has to clear 24px to be a
     target of its own. */
  .auth .checkbox input{width:24px;height:24px}
  /* Matches the shape of the `.auth input` rule above, which is a class plus a
     type attribute, so the touch height is not out-weighed by it. */
  .auth input[type=text],.auth input[type=email],.auth input[type=password]{height:44px}
}

/* ============ resizable splits ============ */
/* Four workspace layouts are two columns with a visible divide: the app rail,
   the create parameter panel, the library folder list, and the video options.
   Their grid templates above read their first width from a custom property, so
   a drag writes one value instead of rewriting a template. The media queries
   that stack them at narrow widths still win, because they set the template
   outright. Only the grip itself is declared here. */
/* The grip sits over the border the panes already draw, so it highlights the
   existing divide instead of introducing a second one. */
.grip{position:absolute;top:0;bottom:0;width:9px;margin-left:-4.5px;z-index:6;cursor:col-resize;touch-action:none;background:none;border:0;padding:0}
.grip::after{content:"";position:absolute;top:0;bottom:0;left:4px;width:1px;background:transparent;transition:background .15s var(--ease)}
.grip:hover::after,.grip.drag::after,.grip:focus-visible::after{background:var(--acc)}
.grip-right{margin-left:0;left:auto;right:0}
.grip-right::after{left:auto;right:4px}
/* A drag must not read as a text selection, and no layout should animate while
   the pointer is moving it. */
body.resizing{user-select:none;cursor:col-resize}
body.resizing *{transition:none!important;animation:none!important}
@media (prefers-reduced-motion:reduce){.grip::after{transition:none}}
/* Touch layouts stack these panes, so there is no divide left to drag. */
@media (pointer:coarse){.grip{display:none}}
