/* ============================================================
   DRUMKIT — by NIGHTSHAPE
   Pro-audio landing page
   ============================================================ */

/* ---------- Fonts ---------- */
@font-face {
  font-family: "Nightshape";
  src: url("../fonts/Nightshape-Bold.ttf") format("truetype");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Adam";
  src: url("../fonts/Adam-Medium.ttf") format("truetype");
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: "Adam";
  src: url("../fonts/Adam-Light.ttf") format("truetype");
  font-weight: 300;
  font-display: swap;
}
@font-face {
  font-family: "Adam";
  src: url("../fonts/Adam-Bold.ttf") format("truetype");
  font-weight: 700;
  font-display: swap;
}

/* ---------- Design tokens ---------- */
:root {
  /* Canonical NIGHTSHAPE palette (from NightshapeTheme.swift) */
  --bg:            #0C0C0E;
  --bg-deep:       #09090C;
  --panel:         #0F0F13;
  --graphite:      #141418;
  --border:        rgba(255, 255, 255, 0.10);
  --border-strong: rgba(255, 255, 255, 0.18);

  --text:          #EEEEFF;
  --text-2:        #B6B8C6;
  --text-dim:      #888899;

  --teal:          #33CCCC;
  --indigo:        #6666FF;
  --purple:        #9933FF;
  --hot-teal:      #00E5D4;
  --hot-purple:    #A855F7;
  --lavender:      #BBA6FD;

  --grad: linear-gradient(100deg, var(--teal) 0%, var(--indigo) 48%, var(--purple) 100%);
  --grad-soft: linear-gradient(100deg, rgba(51,204,204,.16), rgba(102,102,255,.16) 50%, rgba(153,51,255,.16));

  --maxw: 1200px;
  --ease: cubic-bezier(.22, 1, .36, 1);

  /* SF first: used where the app calls .system(...) directly, so the
     weight scale is the real one (Thin = 100) rather than Inter's. */
  --display: -apple-system, BlinkMacSystemFont, "SF Pro Display", system-ui, var(--sans);
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: "Adam", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;
}

/* ---------- Reset / base ---------- */
* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  letter-spacing: 0.005em;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Fixed ambient background layers */
.bg-fx {
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  overflow: hidden;
}
.bg-fx .glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  opacity: .5;
  will-change: transform;
}
.glow.g1 { width: 46vw; height: 46vw; top: -12vh; left: -8vw;  background: radial-gradient(circle, rgba(51,204,204,.55), transparent 65%); }
.glow.g2 { width: 52vw; height: 52vw; top: 22vh;  right: -14vw; background: radial-gradient(circle, rgba(153,51,255,.50), transparent 65%); }
.glow.g3 { width: 40vw; height: 40vw; bottom: -10vh; left: 24vw; background: radial-gradient(circle, rgba(102,102,255,.42), transparent 65%); }

/* Fine grid + noise overlay for pro-audio texture */
.bg-grid {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.022) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, #000 30%, transparent 85%);
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, #000 30%, transparent 85%);
}

/* ---------- Layout helpers ---------- */
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }

.eyebrow {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--teal);
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.eyebrow::before {
  content: "";
  width: 26px; height: 1px;
  background: var(--grad);
}

.grad-text {
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.section { position: relative; padding: 120px 0; }
.section-head { max-width: 720px; margin-bottom: 64px; }
.section-head h2 {
  font-size: clamp(30px, 5vw, 52px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  font-weight: 800;
  margin: 18px 0 20px;
}
.section-head p { color: var(--text-2); font-size: clamp(16px, 2vw, 19px); max-width: 620px; }

/* ---------- Nav ---------- */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 28px;
  transform: translateZ(0);
}

/* The blur lives on a PSEUDO-ELEMENT behind the bar, not on the bar itself.
   backdrop-filter re-samples a backdrop that moves every scroll frame, and it
   re-rasterises the filtered element's CHILDREN along with it — which is why
   the wordmark kept shimmering and drifting no matter how its own box was
   pinned. Promoting the bar to a layer was not enough because the mark was
   still inside the filtered element. As a sibling layer behind the content it
   blurs the page underneath exactly as before, while the brand and links sit
   on top of it, untouched. */
.nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-bottom: 1px solid transparent;
  transition: background .4s var(--ease), backdrop-filter .4s var(--ease), border-color .4s var(--ease);
}
.nav.scrolled::before {
  background: rgba(9, 9, 12, 0.72);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-bottom: 1px solid var(--border);
}
.nav-brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
/* Explicit INTEGER width. aspect-ratio 5096/1126 at 26px high gives a 117.66px
   box, and paintOneWordmark sizes its background from the rounded offsetWidth,
   so mask and image disagreed by a sub-pixel. That alone was not what made the
   mark wobble — see .nav::before, where the blur was moved off the parent so
   the mark is no longer a child of a filtered element — but an integer box and
   its own layer keep the two in exact agreement regardless. */
.nav-brand .nav-mark { height: 26px; width: 118px; display: block;
  transform: translateZ(0); backface-visibility: hidden; }
.nav-brand .by {
  font-family: "Nightshape", var(--sans);
  font-size: 13px;
  letter-spacing: 0.18em;
  color: var(--text-2);
  padding-left: 12px;
  border-left: 1px solid var(--border);
}
.nav-links { display: flex; align-items: center; gap: 34px; }
.nav-links a {
  color: var(--text-2);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: color .25s var(--ease);
}
.nav-links a:hover { color: var(--text); }
.nav-links .nav-cta {
  color: var(--text);
  padding: 9px 18px;
  border: 1px solid var(--border-strong);
  border-radius: 0;
  background: var(--grad-soft);
  transition: border-color .25s var(--ease), transform .25s var(--ease);
}
.nav-links .nav-cta:hover { border-color: var(--teal); transform: translateY(-1px); }
.nav-toggle { display: none; background: none; border: 0; cursor: pointer; padding: 6px; }
.nav-toggle span { display: block; width: 24px; height: 2px; background: var(--text); margin: 5px 0; transition: .3s var(--ease); border-radius: 2px; }

/* ---------- Hero ---------- */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  /* The bottom padding reserves room for .scroll-hint, which is absolutely
     positioned 26px off the bottom and stands ~56px tall (label + gap + line).
     At 80px the trust bar landed flush against the top of it. */
  padding: 140px 24px 132px;
  overflow: hidden;
}
.hero canvas.wave {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  width: 100%;
  height: 42vh;
  opacity: .55;
  z-index: 0;
  pointer-events: none;
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.hero-inner { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; }

.hero-badge {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 0;
  background: rgba(255,255,255,.03);
  backdrop-filter: blur(8px);
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-2);
  margin-bottom: 40px;
}
.hero-badge .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--hot-teal); box-shadow: 0 0 12px var(--hot-teal); animation: pulse 2.2s infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }

.hero-logo {
  width: min(760px, 88vw);
  /* A span has no intrinsic size, so the PNG's own 5096x1126 ratio is stated
     here to reproduce what height:auto gave the <img>. */
  aspect-ratio: 5096 / 1126;
  height: auto;
  display: block;
  background-color: #6666FF;
  -webkit-mask-image: url(../img/drumkit-logo.png); mask-image: url(../img/drumkit-logo.png);
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  margin-bottom: 30px;
  filter: drop-shadow(0 12px 60px rgba(102,102,255,.28));
  will-change: transform;
}
.hero h1 {
  font-size: clamp(26px, 4.4vw, 46px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  font-weight: 800;
  /* Every break is authored in the markup — one phrase per line — so the
     headline must not be re-wrapped by a width cap. Only the narrowest
     handsets fall back to natural wrapping on the longest line. */
  max-width: none;
  text-wrap: balance;
  margin-bottom: 22px;
}
.hero p.sub {
  color: var(--text-2);
  font-size: clamp(16px, 2.2vw, 20px);
  max-width: 56ch;
  margin-bottom: 42px;
}

/* CTA row */
.cta-row { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; justify-content: center; }

/* App Store badge */
.appstore-badge {
  display: inline-block;
  border-radius: 12px;
  transition: transform .3s var(--ease), filter .3s var(--ease);
  outline: none;
}
.appstore-badge svg { display: block; height: 56px; width: auto; }
.appstore-badge:hover { transform: translateY(-2px); filter: drop-shadow(0 8px 24px rgba(0,0,0,.5)); }
.appstore-badge.pending { position: relative; cursor: default; margin-bottom: 30px; }
/* Under the badge, and deliberately WITHOUT a box. The App Store badge is
   Apple artwork with its own rounded rect; putting a square bordered chip
   directly beneath it stacked two competing container shapes and the tag read
   as an orphan floating under the button. It is a caption, so it is set as one
   — quiet letterspaced caps, centred on the badge, close enough to belong to
   it. */
.appstore-badge.pending::after {
  content: "Coming soon";
  position: absolute;
  left: 0; right: 0; bottom: -22px;
  text-align: center;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: .3em;
  text-indent: .3em;          /* balance the trailing letterspace so it centres */
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-dim);
  font-weight: 500;
}

/* Launch pricing */
.price-note { margin-top: 20px; font-size: 14px; color: var(--text-2); letter-spacing: .01em; }
.price-note strong { color: var(--text); font-weight: 700; }

.price-block {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: 16px;
  /* 34px of clear space sits above this block. The 30px here plus the 16px
     top margin on .price-anchor made 46px below it, so the block read as
     hanging off the note above rather than sitting between the two. 18 + 16
     matches the gap above exactly. */
  margin: 0 auto 18px;
  padding: 14px 22px;
  border: 1px solid var(--border);
  border-radius: 0;
  background: rgba(255,255,255,.03);
  backdrop-filter: blur(6px);
}
/* One flat colour, matching the LAUNCH PRICE outline beside it so the block
   reads as a single accent. No bloom — cyan is already the loudest colour in
   the palette and does not need lifting. */
.price-block .pb-amt {
  font-size: clamp(34px, 6vw, 46px); font-weight: 800; letter-spacing: -0.02em; line-height: 1;
  color: var(--teal);
}
.price-block .pb-meta { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; text-align: left; }
/* Accent as a thin rule and lit type, never a filled block. */
.price-block .pb-tag {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .26em; text-transform: uppercase;
  color: var(--teal); background: transparent;
  border: 1px solid rgba(51,204,204,.34);
  /* Not 4px top and bottom. The label is all caps, so it has an ascent but no
     descender, and symmetric padding centres the LINE BOX while leaving the
     glyphs sitting 1.46px high in the outline (measured). Splitting that
     difference across the two paddings centres the ink itself and keeps the
     box the same height. */
  padding: 4.7px 10px 3.3px; font-weight: 500;
}
.price-block .pb-reg { font-size: 12.5px; color: var(--text-dim); }

.ghost-link {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--text-2);
  text-decoration: none;
  font-size: 15px;
  font-weight: 500;
  transition: color .25s var(--ease), gap .25s var(--ease);
}
.ghost-link:hover { color: var(--text); gap: 12px; }
.ghost-link svg { width: 16px; height: 16px; }

/* Trust strip */
.trust {
  margin-top: 64px;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 14px 30px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.trust span { display: inline-flex; align-items: center; gap: 9px; }
.trust span::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--indigo); }

/* Scroll hint */
.scroll-hint {
  position: absolute; bottom: 26px; left: 50%; transform: translateX(-50%);
  z-index: 2;
  font-family: var(--mono); font-size: 10px; letter-spacing: .3em; text-transform: uppercase;
  color: var(--text-dim);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.scroll-hint .line { width: 1px; height: 34px; background: linear-gradient(var(--teal), transparent); animation: drop 1.8s infinite; }
@keyframes drop { 0% { transform: scaleY(0); transform-origin: top; } 50% { transform: scaleY(1); transform-origin: top; } 51% { transform-origin: bottom; } 100% { transform: scaleY(0); transform-origin: bottom; } }

/* ---------- Logo marquee ---------- */
.marquee {
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 22px 0;
  overflow: hidden;
  background: rgba(255,255,255,.012);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee-track { display: flex; gap: 56px; width: max-content; animation: scroll-x 32s linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-track span {
  font-family: var(--mono);
  font-size: 14px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-dim);
  white-space: nowrap;
  display: inline-flex; align-items: center; gap: 56px;
}
.marquee-track span::after { content: "◆"; color: var(--indigo); font-size: 8px; }
@keyframes scroll-x { to { transform: translateX(-50%); } }

/* ---------- Feature grid ---------- */
.features { display: grid; grid-template-columns: repeat(12, 1fr); gap: 22px; }
.card {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 0;
  background:
    linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,.008));
  padding: 34px 32px;
  overflow: hidden;
  transition: border-color .4s var(--ease), transform .4s var(--ease);
  will-change: transform;
}
.card::before {
  /* animated top hairline */
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: var(--grad);
  opacity: 0; transition: opacity .4s var(--ease);
}
.card:hover { border-color: var(--border-strong); transform: translateY(-4px); }
.card:hover::before { opacity: 1; }
.card .icon {
  width: 46px; height: 46px; border-radius: 0;
  display: grid; place-items: center;
  background: var(--grad-soft);
  border: 1px solid var(--border);
  margin-bottom: 22px;
}
.card .icon svg { width: 24px; height: 24px; stroke: var(--teal); }
.card h3 { font-size: 20px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 10px; }
.card p { color: var(--text-2); font-size: 15.5px; }
.card .tag {
  position: absolute; top: 26px; right: 28px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--text-dim);
}
.card.span-6 { grid-column: span 6; }
.card.span-4 { grid-column: span 4; }
.card.span-8 { grid-column: span 8; }

/* Feature card wide: the "engine" highlight */
.card.feature-lg { grid-column: span 8; display: flex; flex-direction: column; justify-content: space-between; min-height: 260px; }
.card.feature-lg .fx-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
.fx-chip {
  font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  padding: 6px 12px; border-radius: 0;
  border: 1px solid var(--border);
  color: var(--text-2);
  background: rgba(255,255,255,.02);
}
/* No `.hot` variant. It filled one chip with the full accent gradient, which
   broke two house rules at once — gradients belong to the wordmark, and the UI
   language is flat accent outlines, not bright solid fills — and it singled out
   one of seven peer modules for no reason the page ever explains. */

/* ---------- Showcase / parallax split ---------- */
.showcase { position: relative; overflow: hidden; }
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 72px; align-items: center; }
.split.reverse { direction: rtl; }
.split.reverse > * { direction: ltr; }
.split .copy h2 { font-size: clamp(28px, 4vw, 44px); line-height: 1.08; letter-spacing: -0.02em; font-weight: 800; margin: 16px 0 18px; }
.split .copy p { color: var(--text-2); font-size: 17px; margin-bottom: 16px; }
.split .copy ul { list-style: none; margin-top: 24px; display: grid; gap: 14px; }
.split .copy li { display: flex; gap: 13px; align-items: flex-start; color: var(--text-2); font-size: 15.5px; }
.split .copy li svg { width: 18px; height: 18px; stroke: var(--teal); flex: none; margin-top: 3px; }

/* Device / visual panel */
.panel-visual {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 0;
  background: linear-gradient(160deg, var(--panel), var(--bg-deep));
  padding: 30px;
  overflow: hidden;
  will-change: transform;
  box-shadow: 0 40px 100px rgba(0,0,0,.5);
}
.panel-visual::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(ellipse 60% 40% at 50% -10%, rgba(102,102,255,.18), transparent 70%);
  pointer-events: none;
}

/* Sequencer mock */
.seq { display: grid; gap: 10px; position: relative; z-index: 1; }
.seq-row { display: grid; grid-template-columns: 62px 1fr; gap: 12px; align-items: center; }
.seq-row .label { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-2); }
.seq-steps { display: grid; grid-template-columns: repeat(8, 1fr); gap: 7px; }
.step { aspect-ratio: 1; border-radius: 0; border: 1px solid var(--border); background: rgba(255,255,255,.03); transition: background .2s, box-shadow .2s; }
.step.on { border-color: transparent; }
.step.on.teal   { background: var(--teal);   box-shadow: 0 0 14px rgba(51,204,204,.6); }
.step.on.indigo { background: var(--indigo); box-shadow: 0 0 14px rgba(102,102,255,.6); }
.step.on.purple { background: var(--purple); box-shadow: 0 0 14px rgba(153,51,255,.6); }
.step.play { outline: 2px solid rgba(255,255,255,.8); outline-offset: 1px; }

/* EQ mock */
.eq-visual { position: relative; z-index: 1; height: 220px; display: flex; align-items: flex-end; gap: 8px; }
.eq-bar { flex: 1; border-radius: 0; background: var(--grad); opacity: .85; transition: height .3s var(--ease); will-change: height; }

/* Waveform strip mock */
.wf-strip { position: relative; z-index: 1; height: 120px; display: flex; align-items: center; gap: 3px; }
.wf-strip i { flex: 1; background: var(--grad); border-radius: 0; opacity: .8; will-change: transform; display: block; }

/* ---------- Stats ---------- */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; }
.stat {
  border: 1px solid var(--border); border-radius: 0; padding: 30px 26px;
  background: linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,.006));
  text-align: center;
}
.stat .num { font-size: clamp(34px, 5vw, 52px); font-weight: 800; letter-spacing: -0.03em; line-height: 1; }
.stat .lbl { font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--text-dim); margin-top: 12px; }

/* ---------- Big CTA ---------- */
.cta-final {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 84px 40px;
  text-align: center;
  overflow: hidden;
  background: linear-gradient(160deg, var(--panel), var(--bg-deep));
}
.cta-final::before {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 50% 60% at 20% 10%, rgba(51,204,204,.22), transparent 60%),
    radial-gradient(ellipse 50% 60% at 85% 90%, rgba(153,51,255,.22), transparent 60%);
  pointer-events: none;
}
.cta-final img.icon-float {
  width: 108px; height: 108px; border-radius: 24px;
  margin-bottom: 30px;
  box-shadow: 0 20px 60px rgba(0,0,0,.6), 0 0 0 1px var(--border);
  position: relative; z-index: 1;
  will-change: transform;
}
.cta-final h2 { position: relative; z-index: 1; font-size: clamp(32px, 5.5vw, 60px); line-height: 1.03; letter-spacing: -0.03em; font-weight: 800; margin-bottom: 18px; }
.cta-final .cta-lede { position: relative; z-index: 1; color: var(--text-2); font-size: 18px; max-width: 52ch; margin: 0 auto 40px; }
/* The price block butted straight into the signup note. Spacing the whole CTA
   stack deliberately now: statement, action, then the reasoning under it. */
.cta-final .price-block { margin-top: 34px; }
.cta-final .cta-row { position: relative; z-index: 1; margin-top: 38px; }

/* ---------- Footer ---------- */
.footer { border-top: 1px solid var(--border); padding: 60px 0 40px; }
.footer-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 40px; flex-wrap: wrap; }
.footer-brand .footer-mark { height: 26px; margin-bottom: 16px; }
.footer-brand .by { font-family: "Nightshape", var(--sans); font-size: 13px; letter-spacing: 0.16em; color: var(--text-2); }
.footer-brand p { color: var(--text-dim); font-size: 14px; margin-top: 12px; max-width: 34ch; }
.footer-cols { display: flex; gap: 64px; flex-wrap: wrap; }
.footer-col h4 { font-family: var(--mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 16px; }
.footer-col a { display: block; color: var(--text-2); text-decoration: none; font-size: 14.5px; margin-bottom: 11px; transition: color .2s var(--ease); }
.footer-col a:hover { color: var(--text); }
.footer-bottom {
  margin-top: 54px; padding-top: 26px; border-top: 1px solid var(--border);
  display: flex; justify-content: space-between; align-items: center; gap: 20px; flex-wrap: wrap;
  color: var(--text-dim); font-size: 13px;
}
.footer-bottom .legal { display: flex; gap: 24px; flex-wrap: wrap; }
.footer-bottom a { color: var(--text-dim); text-decoration: none; }
.footer-bottom a:hover { color: var(--text-2); }

/* ---------- Reveal animation ---------- */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity .8s var(--ease), transform .8s var(--ease); }
.reveal.in { opacity: 1; transform: none; }
.reveal.d1 { transition-delay: .08s; }
.reveal.d2 { transition-delay: .16s; }
.reveal.d3 { transition-delay: .24s; }
.reveal.d4 { transition-delay: .32s; }

/* ============================================================
   DEVICE SHOWCASE — life-size iPhone 17 Pro Max running the app
   Recreated faithfully from the SwiftUI workstation layout.
   ============================================================ */
@font-face {
  font-family: "NightshapeOutline";
  src: url("../fonts/NIGHTSHAPE-Outline.ttf") format("truetype");
  font-weight: 700;
  font-display: swap;
}

:root {
  --nsbg: #0C0C0E;
  --dk-teal: #33CCCC;   --dk-hotteal: #00E5D4;
  --dk-indigo: #6666FF; --dk-purple: #9933FF; --dk-hotpurple: #A855F7;
  --dk-lav: #BBA6FD;    --dk-cool: #E6ECF5;
}

.device-section { position: relative; }
.device-section .intro { text-align: center; max-width: 720px; margin: 0 auto; padding: 110px 24px 0; }
.device-section .intro h2 { font-size: clamp(30px, 5vw, 52px); line-height: 1.05; letter-spacing: -0.02em; font-weight: 800; margin: 18px 0 18px; }
.device-section .intro p { color: var(--text-2); font-size: clamp(16px, 2vw, 19px); }

/* Tall wrapper provides the scroll distance; the phone stays pinned inside it */
.device-scroll { position: relative; height: 300vh; }
.device-sticky { position: sticky; top: 0; height: 100svh; display: flex; align-items: center; overflow: hidden; }
.device-stage {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 40px;
  width: 100%;
}
.device-stage .callouts { justify-self: end; max-width: 340px; }
.device-stage .stage-spacer { }

/* Scroll-synced callouts */
/* .24s, not .5s. This is a scroll-driven state, so the fade IS the response
   to the reader's own movement — half a second reads as the page being slow
   to notice them rather than as a graceful fade. */
.callout { opacity: .35; transform: translateX(-6px); transition: opacity .24s var(--ease), transform .24s var(--ease); margin-bottom: 30px; padding-left: 18px; border-left: 2px solid var(--border); }
.callout.active { opacity: 1; transform: none; border-left-color: var(--dk-teal); }
.callout .k { font-family: var(--mono); font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--teal); }
.callout h3 { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin: 8px 0 8px; }
.callout p { color: var(--text-2); font-size: 15px; }

/* --- Device frame (titanium) --- */
.dk-device { --scale: 1; transform: scale(var(--scale)); transform-origin: center center; justify-self: center; }
.dk-frame {
  position: relative;
  /* iPhone 16 Pro Max: 440x956pt screen + 14px bezel all round. */
  width: 468px; height: 984px;
  border-radius: 68px;
  padding: 14px;
  background: linear-gradient(150deg, #3a3d44 0%, #17181c 22%, #232529 50%, #101114 78%, #34363c 100%);
  box-shadow:
    0 2px 2px rgba(255,255,255,.18) inset,
    0 -2px 3px rgba(0,0,0,.6) inset,
    0 60px 120px -30px rgba(0,0,0,.85),
    0 0 0 1px rgba(0,0,0,.6),
    0 0 70px -10px rgba(102,102,255,.22);
}
/* side buttons */
.dk-frame::before, .dk-frame::after {
  content: ""; position: absolute; background: linear-gradient(90deg,#2a2c31,#3d4046); border-radius: 3px;
}
.dk-frame::before { left: -3px; top: 190px; width: 3px; height: 62px; box-shadow: 0 92px 0 #2a2c31, 0 176px 0 0 #2a2c31; }
.dk-frame::after  { right: -3px; top: 240px; width: 3px; height: 104px; }
.dk-screen {
  position: relative;
  width: 440px; height: 956px;
  border-radius: 55px;
  overflow: hidden;
  background: var(--nsbg);
  color: var(--text);
  font-family: var(--sans);
}
.dk-island {
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  width: 126px; height: 36px; border-radius: 20px; background: #000;
  z-index: 40;
}

/* status bar */
.dk-statusbar {
  height: 62px; display: flex; align-items: center; justify-content: space-between;
  padding: 14px 34px 0; font-family: var(--sans); font-weight: 600; font-size: 16px; color: var(--text);
}
.dk-statusbar .r { display: flex; align-items: center; gap: 7px; }
.dk-statusbar svg { display: block; }

/* Frozen wave ground, behind the whole workstation (see #dkWave in main.js).
   The screen colour stays underneath it, exactly as in the app. */
.dk-wave { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 0; pointer-events: none; }
/* Everything above the ground. The island already carries its own z-index. */
.dk-statusbar, .dk-body { position: relative; z-index: 1; }

/* content column padding (contentLeft = 8pt scaled to this 428 screen) */
.dk-body { padding: 0 9px 38px; height: calc(100% - 62px); display: flex; flex-direction: column; }

/* Home indicator. The app's content stops above it — 34pt of bottom safe area
   plus the chrome's own 4pt bottom padding — which the mock had not reserved,
   so the step grid ran all the way to the screen edge. */
.dk-home { position: absolute; left: 50%; transform: translateX(-50%); bottom: 8px;
  width: 139px; height: 5px; border-radius: 3px; background: rgba(255,255,255,.28); z-index: 40; }

/* Brand header: full-width DRUMKIT lockup (fixed 78px height) + byline */
/* Brand block spacing, from WorkstationLayout and DrumkitBrandHeader:
   logoTop = y(8) ~= 9px on a Pro Max; the VStack puts the byline 4pt under the
   mark; and the panel below sits "the byline-to-logo gap, plus 4pt of breathing
   room" beneath it — 8pt. The mock had 5 / 4 / 4, so the panel crowded the
   byline. */
.dk-brand { display: block; padding: 9px 4px 8px; position: relative; }
/* HELP over HOME, from topRightChromeButtons: a VStack(spacing: 6) of 34pt
   square buttons, right-aligned to the content column. Each glyph renders at
   size * 0.42 = 14.28pt in controlChrome at 0.86 — the same cool grey as the
   command rail. The mock had 21-22px glyphs 18px apart in #6a6a78, the near-
   black byline grey the app deliberately moved away from for being barely
   legible against the wave. HELP carries a 5pt raise; HOME does not. */
/* topNavTop is -12 against a 24pt top inset, so the stack starts 12pt below
   the safe-area top — not hard against it. */
.dk-nav { position: absolute; top: 12px; right: 0; display: flex; flex-direction: column;
  align-items: center; gap: 6px; color: rgba(228,231,240,.86); }
.dk-nav .btn { width: 34px; height: 34px; display: grid; place-items: center; }
.dk-nav .q { font-size: 20px; font-weight: 400; line-height: 1; font-family: var(--sans);
  position: relative; top: -5px; }
.dk-nav svg { width: 14.3px; height: 14.3px; display: block; }
/* The app does not use the PNG's baked gradient: DrumkitLogoMark masks the
   NIGHTSHAPE tie-dye through the logo's own alpha, so only the letters carry
   colour. Same indigo base, same five spot centres and colours, same teal
   shadow. The asset is untouched — it serves only as the mask. Spot radius is
   0.6 x max(w, h), measured from the element itself in main.js. */
/* DrumkitLogoMark(width:, height: 70.2) — "Logo reduced 10% (78 -> 70.2)" to
   free vertical space. The mark is height-constrained and left-aligned, so its
   ink is 70.2 * 4.5258 = 317.7pt wide, not the full content column. */
.dk-brand .dk-logo {
  /* mask-size is 100% 100%, so the BOX has to carry the artwork's ratio or the
     letters stretch to whatever width the box happens to be. This was
     calc(100% - 10px) — the full content column — which pulled the wordmark
     edge to edge and distorted it. The mark is height-constrained: 70.2px at
     the PNG's real 5096x1126 gives 70.2 x 4.525755 = 317.71px, which is the
     317.7pt the comment above already specifies. */
  display: block; height: 70.2px; width: 317.71px;
  /* Indigo base is the ZStack floor and the fallback if the canvas paint has
     not run; the five spots are drawn in main.js (paintWordmark). */
  background-color: #6666FF;
  -webkit-mask-image: url(../img/drumkit-logo.png); mask-image: url(../img/drumkit-logo.png);
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-position: left center; mask-position: left center;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  filter: drop-shadow(0 0 10px rgba(51,204,204,.08)); /* SwiftUI shadow(radius:5) ~= 10px CSS blur */
}
/* DrumkitBrandHeader: Adam Medium 12.2pt, tracking 12.8pt, accentPurple, 6pt
   leading inset, 4pt below the mark. The mock had it at 11px with a 0.7em
   approximation for tracking (7.7px, well short of 12.8) in #4C4C5A — a dead
   grey the app does not use here at all. */
.dk-byline {
  font-family: "Adam", var(--mono); font-weight: 500; font-size: 12.2px;
  letter-spacing: 12.8px; color: #9933FF; padding-left: 6px; margin-top: 4px;
  white-space: nowrap;
}

/* display / visualizer panel */
.dk-display {
  position: relative; height: 160px; background: #08090B;
  border: 1.5px solid var(--dk-teal); overflow: hidden; flex: none;
}
.dk-matrix { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.dk-numeral {
  position: absolute; top: 50%; left: 25%; transform: translate(-50%, -46%);
  font-family: "NightshapeOutline", var(--sans); font-size: 116px; line-height: 1;
  background: linear-gradient(var(--dk-hotteal), var(--dk-hotpurple));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  opacity: .22; pointer-events: none; z-index: 3;
  filter: drop-shadow(0 0 12px rgba(51,204,204,.3));
  transition: left .3s var(--ease);
}

/* header row: title/mode + bpm, floating transport (meter moved to controls) */
/* Header band, measured off a 3x device crop against the panel's bottom edge.
   The whole stack below the panel was sitting high — title 4pt low, mode 5pt
   high, the BPM block 16-18pt high, and everything from the identity row down
   about 9pt high. */
.dk-head { position: relative; padding: 6px 4px 0; min-height: 93px; }
.dk-title { background: none; border: 0; padding: 0; cursor: default; display: inline-flex; align-items: center; gap: 6px;
  font-family: "Nightshape", var(--sans); font-size: 12.8px; letter-spacing: 1.8px; color: var(--dk-hotteal); }
.dk-title svg { width: 7.5px; height: 7.5px; }
/* HStack(alignment: .center, spacing: -6) — the words are CENTRE-aligned to
   each other, not sitting on a common baseline. */
.dk-mode { display: flex; align-items: center; gap: 0; margin-top: 13px; line-height: .9; }
.dk-word { font-family: "Nightshape", var(--sans); letter-spacing: 1.2px; }
/* nightshapeBold(34) active / (26) inactive. The active word carries an opaque
   matte so it clips the edge of the word behind it — but the app's matte is a
   WaveMatte that redraws the SAME screen-aligned wave, so it occludes without
   showing as a block. A flat fill would be a visible rectangle now that the
   screen has a wave ground; main.js paints this element with its own region of
   that ground. */
.dk-word.pattern { font-size: 34px; color: var(--dk-hotpurple); z-index: 2; background-color: var(--nsbg); position: relative; }
.dk-word.song { font-size: 26px; color: #3A3A48; margin-left: -6px; }

.dk-bpm { position: absolute; top: 24px; right: 6px; text-align: right; }
/* metaFont(weight: .heavy, size: 15), tracking 4.6, accentHotPurple at 0.98,
   and padding(.trailing, -4.6) — letter-spacing leaves a trailing gap after the
   final M, and the app cancels it so the M lands flush with the 0 below. */
.dk-bpm .lbl { font-family: "Adam", var(--mono); font-weight: 700; font-size: 15px;
  letter-spacing: 4.6px; margin-right: -4.6px; color: var(--dk-hotpurple); opacity: .98; }
/* Meter picker — its own control beside the tempo label, teal like the app. */
.dk-bpm .meter { font-family: "Adam", var(--mono); font-weight: 500; font-size: 10px;
  letter-spacing: .08em; color: var(--dk-teal); margin-right: 7px; display: inline-flex;
  align-items: center; gap: 2px; vertical-align: 3px; }
.dk-bpm .meter svg { width: 7px; height: 7px; display: block; }
/* bpmValue(size: 60) in accentLavender, VStack(spacing: -11) under the label,
   offset(x: 3) so the digit's side bearing lines up with the grid edge. */
.dk-bpm .val { font-family: var(--display); font-weight: 100; font-size: 60px; line-height: 1;
  color: var(--dk-lav); margin-top: -13.7px; transform: translateX(3px); }
.dk-out { display: flex; align-items: center; gap: 6px; flex: none;
  font-family: "Adam", var(--mono); font-size: 9.5px; letter-spacing: 1.05px; white-space: nowrap; }
.dk-out .o { color: var(--text-dim); }
/* frame(width: 58, alignment: .trailing) — a fixed box so the readout
   does not shuffle the CLIP lamp as digits change. */
.dk-out .db { color: rgba(230,236,245,.78); width: 58px; text-align: right; font-variant-numeric: tabular-nums; }
.dk-out .clip { display: inline-flex; align-items: center; gap: 3px; color: var(--dk-hotpurple); }
.dk-out .clip i { width: 5px; height: 5px; border-radius: 50%; background: #3A3A48; }
.dk-out .clip.on i { background: var(--dk-hotpurple); box-shadow: 0 0 4px rgba(168,85,247,.55); }
.dk-out .clip.on { color: var(--dk-hotpurple); }
.dk-out .clip.off { color: #3A3A48; }
.dk-out .clip.off i { background: #3A3A48; box-shadow: none; }

.dk-transport { position: absolute; top: 33px; left: 60%; background: none; border: 0; cursor: default; color: var(--dk-teal); }
.dk-transport svg { width: 30px; height: 30px; display: block; }

/* Control band line 1 — pattern identity */
/* identityBandHeight 24, identityBandGap 6 down to the command row. */
/* No horizontal padding. The display panel and the track grid both run to the
   body's own 9px edge, so 4px here inset this row alone — which is why the
   meter could never sit flush with everything above and below it. */
.dk-identity { display: flex; align-items: center; gap: 8px; padding: 12px 0 6px; }
/* Fixed, not auto: letting it size to content overflows the identity row,
   which collapses the auto margin and pushes the meter past the grid's right
   edge instead of flush with it. 121px is the cluster's real drawn width,
   measured off a native 3x capture of the app — OUT's ink starts at 309.7pt
   and CLIP ends at 430.7pt on a 440pt screen. The old 125 was 4px of reserve
   that the row could not afford, and it was one of the reasons the whole row
   overflowed. */
.dk-identity .dk-out { width: 121px; flex: none; margin-left: auto; justify-content: flex-end; align-self: flex-end; position: relative; top: 2px; }
/* The one item in this row allowed to give. Everything else is a fixed chip or
   the meter, so without a shrinkable child any overflow gets pushed out of the
   right edge and the meter stops being flush with the grid. This plays the
   part scaleDownToFitWidth() plays in the app: the row absorbs its own
   overflow instead of exporting it. */
.dk-identity .dk-pat { min-width: 0; overflow: hidden; flex: 0 1 auto; }
.dk-pat { background: none; border: 0; padding: 0; cursor: default; display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  font-family: "Nightshape", var(--sans); font-size: 16px; letter-spacing: .05em; color: var(--dk-lav); flex: none; }
.dk-pat svg { width: 10px; height: 10px; }
.dk-save { position: relative; width: 29px; height: 29px; flex: none; display: grid; place-items: center; border: 1.5px solid rgba(51,204,204,.42); border-radius: 3px; }
.dk-save svg { width: 13px; height: 13px; stroke: rgba(51,204,204,.84); }
/* UNDO / REDO / CLEAR share the identity row with PATTERN. Chrome-grey like
   the app's command chips; undo/redo sit disabled-dim on an empty pattern. */
.dk-mini { position: relative; width: 29px; height: 29px; flex: none; display: grid; place-items: center;
  border: 1.5px solid rgba(228,231,240,.12); border-radius: 3px; color: rgba(228,231,240,.30); }
.dk-mini svg { width: 13px; height: 13px; display: block; }
.dk-clear { position: relative; height: 29px; flex: none; display: inline-flex; align-items: center; gap: 5px;
  padding: 0 8px; border: 1.5px solid rgba(228,231,240,.34); border-radius: 3px;
  color: rgba(228,231,240,.86); font-family: "Nightshape", var(--sans);
  font-size: 10.5px; letter-spacing: .14em; white-space: nowrap; }
.dk-clear svg { width: 11px; height: 11px; display: block; }
/* The Nightshape face is all-caps but still reserves descender space, so its
   ink sits above the frame centre. The app corrects this with an optical drop
   of 0.061 × font size (nightshapeOpticalDrop); same correction, text only —
   the icon is already centred on its own box. */
.dk-clear i { font-style: normal; display: block; transform: translateY(0.061em); }

/* Control band line 2 — action buttons (left) + output meter (right) */
/* tracksTop = controlsTop + max(y(38), 39): 42.2pt from the command row's TOP
   on a Pro Max, less its own 29pt height, leaves 13.2pt of air before the first
   track. The mock was running 17. */
/* No horizontal padding, for the same reason as .dk-identity: controlsRow is
   framed at layout.contentWidth in the app, so the command rail shares one
   right edge with the display panel and the track grid. Measured off a native
   3x capture, all three land on 430.7pt — the 4px here was inseting the rail
   alone. */
.dk-controls { display: flex; align-items: center; gap: 8px; padding: 0 0 10px; overflow: hidden; }
.dk-ctl-buttons { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; width: 100%; min-width: 0; }
/* One chrome for the whole command rail. The app drives MUTE, SOLO, FX, KITS,
   PERFORM, the pager, UNDO, REDO and CLEAR from a single pair — controlChrome
   #E4E7F0 at 0.34 border / 0.86 text — precisely so they "read as one set of
   controls, not four unrelated greys" (DrumkitRootView). The mock had drifted
   to four different values, which is why CLEAR looked brighter than its
   neighbours: CLEAR was the only one already carrying the real numbers. */
.dk-chip { position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 29px; padding: 0 6px; flex: none; white-space: nowrap; border-radius: 3px;
  border: 1.5px solid rgba(228,231,240,.34); color: rgba(228,231,240,.86);
  /* Every command label is nightshapeUIBold — PERFORM, KITS, FX and the pager
     at 10.5/1.45, MUTE and SOLO at 10/1.15. The mock had them in Adam at 9px,
     which is why CLEAR (correctly 10.5 Nightshape) towered over the row. */
  font-family: "Nightshape", var(--sans); font-size: 10.5px; letter-spacing: 1.45px; }
.dk-chip i { font-style: normal; display: block; transform: translateY(0.061em); }
.dk-ctl-buttons > *:nth-child(1), .dk-ctl-buttons > *:nth-child(2) { font-size: 10px; letter-spacing: 1.15px; }
.dk-chip svg { width: 11px; height: 11px; }
/* FX differs in type only — never in colour. */

/* Widths are set in main.js (fitSelector) so they scale as a group to
   the row while the 8pt gap stays fixed. */

/* sequencer grid */
.dk-grid { flex: 1; display: flex; flex-direction: column; gap: 8px; padding: 0 4px 0; min-height: 0; }
.dk-row { display: grid; grid-template-columns: 60px 1fr; gap: 8px; flex: 1; min-height: 0; }
.dk-thead { display: flex; flex-direction: column; align-items: center; justify-content: center;
  background-color: #0C0C0E; position: relative; border-radius: 3px; overflow: hidden; }
/* glassEdge: the reflected rim every glass button carries, a 1px stroke running
   white .26 -> .05 top-left to bottom-right, inside the accent stroke. */
.dk-thead::after, .dk-cell::after, .dk-chip::after, .dk-save::after, .dk-mini::after, .dk-clear::after {
  /* inset -1.5px so the rim lands ON the accent stroke rather than inside it.
     In the app both are strokeBorder calls on the same glassShape, so the
     white edge overlaps and mutes the stroke — without that overlap the
     on-beat tint read far louder here than it does on device. */
  content: ""; position: absolute; inset: -1.5px; border-radius: 3px; padding: 1.5px;
  background: linear-gradient(135deg, rgba(255,255,255,.26), rgba(255,255,255,.05));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude; pointer-events: none;
}
/* Two lines, as the app draws them (SequencerGridView.trackLabel): the sound's
   name at 8.85pt bold rounded, then its drum category beneath at 8.5pt. Idle
   rows carry the track accent at 0.42 on the name and 0.34 on the type — the
   mock was showing one line at 11.5px in full-strength accent. */
/* line-height must be reset: the page body sets 1.6, which inflated a 34px
   tile's two labels to ~31px of line boxes and left them looking crammed. The
   app stacks them in a VStack(spacing: 3) at the font's own metrics. Tracking
   is absolute (0.55pt / 1.2pt) exactly as trackLabel states it, not an em
   approximation. */
.dk-thead .nm { font-family: "Adam", var(--mono); font-weight: 700; font-size: 8.85px; line-height: 1.16; letter-spacing: .55px; padding: 0 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.dk-thead .bar { position: absolute; left: 0; right: 0; bottom: 0; height: 1px; }
.dk-thead .ty { font-family: "Adam", var(--mono); font-weight: 500; font-size: 8.5px; line-height: 1.16; letter-spacing: 1.2px; margin-top: 3px; padding: 0 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.dk-steps { display: grid; grid-template-columns: repeat(8, 1fr); gap: 8px; }
/* Step buttons are the app's glassSurface: an opaque dark base carrying its own
   region of one screen-sized blurred copy of the frozen wave, painted in from
   main.js. Lit steps take an opaque accent fill inline from the transport loop,
   so the glass reads on the unlit ones — as it does in the app. */
.dk-cell { position: relative; background-color: #0C0C0E; border: 1.5px solid #2A2A30; border-radius: 3px; transition: background .1s, border-color .1s; }
.dk-cell.on { }



@media (max-width: 1080px) {
  .device-scroll { height: auto; }
  .device-sticky { position: static; height: auto; padding: 24px 0 56px; }
  .device-stage { grid-template-columns: 1fr; justify-items: center; gap: 20px; }
  .device-stage .callouts { display: none; }
  .device-stage .stage-spacer { display: none; }
  .device-section .intro { padding-bottom: 8px; }
}

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .nav-links { display: none; }
  .nav-links.open {
    display: flex; flex-direction: column; align-items: stretch; gap: 8px;
    position: absolute; top: 100%; left: 0; right: 0;
    background: rgba(9,9,12,.96); backdrop-filter: blur(20px);
    padding: 18px 28px 26px; border-bottom: 1px solid var(--border);
  }
  .nav-links.open a { padding: 12px 4px; font-size: 16px; border-bottom: 1px solid var(--border); }
  .nav-links.open .nav-cta { text-align: center; border-bottom: 0; margin-top: 6px; }
  .nav-toggle { display: block; }
  .nav.menu-open .nav-toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav.menu-open .nav-toggle span:nth-child(2) { opacity: 0; }
  .nav.menu-open .nav-toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  /* Hint is gone here, so the space reserved for it goes back. */
  .scroll-hint { display: none; }
  .hero { padding-bottom: 80px; }
  .section { padding: 84px 0; }
  .split { grid-template-columns: 1fr; gap: 42px; }
  .split.reverse { direction: ltr; }
  .features { gap: 16px; }
  .card.span-4, .card.span-6, .card.span-8, .card.feature-lg { grid-column: span 12; }
  .stats { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
  body { font-size: 16px; }
  .wrap { padding: 0 18px; }
  .nav { padding: 14px 18px; }
  .hero { padding: 120px 18px 70px; }
  .hero-logo { margin-bottom: 24px; }
  .hero .trust { gap: 10px 18px; }
  .cta-row { flex-direction: column; gap: 16px; width: 100%; }
  .appstore-badge { width: 100%; display: flex; justify-content: center; }
  .stats { grid-template-columns: 1fr 1fr; gap: 12px; }
  .cta-final { padding: 56px 24px; border-radius: 0; }
  .seq-row { grid-template-columns: 44px 1fr; }
  .seq-steps { gap: 5px; }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
  .reveal { opacity: 1; transform: none; }
}

/* ---------- Drum Synth specs ----------
   Deliberately plain: the numbers are the argument, so the styling stays out of
   their way. Flat accent outlines and hairline rules only — no gradient fills,
   which belong to the wordmark and the page's own headline treatment. */
.spec-lead {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
  margin-bottom: 18px;
}
.spec-hero {
  border: 1px solid var(--border); border-radius: 0;
  padding: 26px 26px 24px;
  background: rgba(255,255,255,.012);
}
/* Claims, not counters. The earlier version led with three big numerals, which
   is the spec-sheet pattern the audit told us to retire — and parameter and
   preset counts are the two figures a producer discounts fastest. The number
   now sits inside a sentence that says what it buys you. */
.spec-hero h3 {
  font-size: 19px; line-height: 1.3; font-weight: 700;
  letter-spacing: -.01em; color: var(--text);
}
.spec-hero p { margin-top: 12px; color: var(--text-2); font-size: 14.5px; line-height: 1.6; }

.spec-note {
  margin: 18px 0; padding-left: 16px;
  border-left: 1px solid rgba(51,204,204,.35);
  color: var(--text-dim); font-size: 14px; line-height: 1.65; max-width: 780px;
}

.spec-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.spec {
  border: 1px solid var(--border); border-radius: 0;
  padding: 26px 26px 22px;
  background: rgba(255,255,255,.012);
}
.spec h3 {
  font-family: var(--mono); font-size: 10px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--teal);
  padding-bottom: 14px; margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.spec dl > div {
  display: grid; grid-template-columns: 116px 1fr; gap: 14px;
  padding: 11px 0; border-bottom: 1px solid rgba(255,255,255,.05);
}
.spec dl > div:last-child { border-bottom: 0; }
.spec dt {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-dim); padding-top: 2px;
}
.spec dd { color: var(--text); font-size: 14.5px; line-height: 1.55; }
.spec dd code { font-family: var(--mono); font-size: 1em; color: var(--lavender); }

@media (max-width: 1080px) {
  .spec-lead, .spec-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
  .spec-lead, .spec-grid { grid-template-columns: 1fr; }
  .spec dl > div { grid-template-columns: 1fr; gap: 3px; }
}

/* Inline link inside a feature card — accent underline, no fill. */
.card p a { color: var(--teal); text-decoration: none; border-bottom: 1px solid rgba(51,204,204,.4); transition: border-color .25s var(--ease); }
.card p a:hover { border-bottom-color: var(--teal); }


/* Every DRUMKIT lockup on the page carries the app's tie-dye, masked through
   the logo's own alpha. The field is generated in main.js (paintWordmark); the
   indigo base doubles as the fallback before that runs. The PNG is untouched —
   it is only ever a mask. 5096x1126 is its intrinsic ratio, needed because a
   span has no intrinsic size. */
.dk-mark {
  display: block;
  aspect-ratio: 5096 / 1126;
  width: auto;
  background-color: #6666FF;
  -webkit-mask-image: url(../img/drumkit-logo.png); mask-image: url(../img/drumkit-logo.png);
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-position: left center; mask-position: left center;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}

/* ---------- Scene 02 — turn any source into a kit ----------
   Same pinned-scroll mechanism as the device showcase. Flat accent outlines
   throughout; no gradient fills, no invented app chrome. */
.extract-section { position: relative; }
.extract-section .intro { text-align: center; max-width: 720px; margin: 0 auto; padding: 110px 24px 0; }
.extract-section .intro h2 { font-size: clamp(30px, 5vw, 52px); line-height: 1.05; letter-spacing: -.02em; font-weight: 800; margin: 18px 0 18px; }
.extract-section .intro p { color: var(--text-2); font-size: clamp(16px, 2vw, 19px); }

.extract-scroll { position: relative; height: 320vh; }
.extract-sticky { position: sticky; top: 0; height: 100svh; display: flex; align-items: center; overflow: hidden; }
.extract-stage {
  width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px;
  display: grid; grid-template-columns: 1fr 300px; gap: 40px; align-items: start;
}

.ex-lane { border: 1px solid var(--border); border-radius: 0; padding: 26px 24px 24px; background: rgba(255,255,255,.012); }
.ex-lane-head { margin-bottom: 18px; }
.ex-lane-head .k { font-family: var(--mono); font-size: 10px; letter-spacing: .22em; text-transform: uppercase; color: var(--teal); }

/* Beat 1-2: the source waveform and its transient markers. */
.ex-wavewrap { position: relative; height: 96px; }
.ex-wave { width: 100%; height: 96px; display: block; }
.ex-markers { position: absolute; inset: 0; pointer-events: none; }
.ex-markers i { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--hot-teal); opacity: 0; transform: scaleY(.3); transform-origin: center; transition: opacity .18s var(--ease), transform .18s var(--ease); }
.ex-markers i.on { opacity: .85; transform: scaleY(1); }

/* Beat 3: the waveform separates into discrete slice cards. */
.ex-cards { display: flex; gap: 8px; margin-top: 18px; min-height: 54px; }
.ex-card {
  flex: 1; border: 1px solid var(--border); border-radius: 0; padding: 8px 6px;
  display: flex; flex-direction: column; gap: 5px; align-items: center;
  opacity: 0; transform: translateY(10px);
  transition: opacity .22s var(--ease), transform .22s var(--ease), border-color .22s var(--ease);
}
.ex-card.on { opacity: 1; transform: none; }
.ex-card .nm { font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; color: var(--text-2); }
.ex-card .bar { width: 100%; height: 16px; border-radius: 0; background: rgba(255,255,255,.06); }

/* Beat 4: cards settle into their category columns. */
.ex-cols { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; margin-top: 14px; min-height: 26px; }
.ex-col { text-align: center; font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em; color: var(--text-dim);
  border-top: 1px solid var(--border); padding-top: 8px; opacity: 0; transition: opacity .25s var(--ease), color .25s var(--ease); }
.ex-col.on { opacity: 1; }

/* Beat 5: curation — the producer overrules the analysis. */
.ex-curate { margin-top: 18px; min-height: 20px; opacity: 0; transition: opacity .3s var(--ease); }
.ex-curate.on { opacity: 1; }
.ex-hint { font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); }
.ex-card .tick { position: absolute; top: 6px; right: 6px; width: 12px; height: 12px; border-radius: 0; border: 1px solid var(--border-strong); opacity: 0; transition: opacity .2s var(--ease), background .2s var(--ease), border-color .2s var(--ease); }
.ex-card { position: relative; }
.ex-card.keep .tick { opacity: 1; background: var(--teal); border-color: var(--teal); }
.ex-card.drop { opacity: .28; }
.ex-card.fixed { border-color: var(--teal); }
.ex-card.fixed .nm { color: var(--teal); }

/* The one-shot lane. Shorter by design, and finished before the main lane is. */
.ex-short { align-self: start; }
.ex-file, .ex-libentry, .ex-assign {
  border: 1px solid var(--border); border-radius: 0; padding: 10px 12px;
  display: flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: 11px; letter-spacing: .06em; color: var(--text-2);
  opacity: 0; transform: translateY(8px); transition: opacity .28s var(--ease), transform .28s var(--ease);
}
.ex-file svg { width: 15px; height: 15px; flex: none; color: var(--text-dim); }
.ex-libentry { justify-content: space-between; }
.ex-libentry .tag { font-size: 9px; letter-spacing: .16em; text-transform: uppercase; color: var(--teal); }
.ex-assign { color: var(--text); border-color: rgba(51,204,204,.42); }
.ex-file.on, .ex-libentry.on, .ex-assign.on { opacity: 1; transform: none; }
.ex-arrow { height: 26px; display: grid; place-items: center; }
.ex-arrow span { display: block; width: 1px; height: 0; background: var(--border-strong); transition: height .28s var(--ease); }
.ex-arrow.on span { height: 26px; }
.ex-note { margin-top: 16px; font-size: 13px; line-height: 1.6; color: var(--text-dim); opacity: 0; transition: opacity .3s var(--ease); }
.ex-note.on { opacity: 1; }

@media (max-width: 1080px) {
  .extract-scroll { height: auto; }
  .extract-sticky { position: static; height: auto; padding: 24px 0 56px; }
  .extract-stage { grid-template-columns: 1fr; gap: 20px; }
}

/* ---------- Scene 05 — the Piano Roll ----------
   Every value below is read out of SignalCorruptionVisualizerView. Key height
   42, black keys 0.68 wide x 0.60 tall centred on the white-key divider,
   column gap 4, pad border 1.5. Nothing here is estimated. */
.pr { border: 1px solid var(--border); border-radius: 0; background: #07080C; overflow: hidden; }

/* Header: "<track> · PIANO ROLL · <mode>" with the AVG summary trailing,
   nightshapeBold 14 / tracking 2.2 / white .76. */
.pr-head { display: flex; align-items: center; gap: 8px; padding: 13px 16px;
  font-family: "Nightshape", var(--sans); font-size: 14px; letter-spacing: 2.2px;
  border-bottom: 1px solid var(--border); }
.pr-track { color: rgba(255,255,255,.76); }
.pr-dot { color: var(--text-dim); }
.pr-title { color: rgba(255,255,255,.76); }
.pr-title b { font-weight: 400; color: rgba(168,85,247,.92); }
.pr-summary { margin-left: auto; color: var(--text-2); }

/* Eight step columns. Each is a complete keyboard on #07080C, bordered in
   accentIndigo — accentTeal at 1.55 when it is the playing step. */
.pr-roll { position: relative; display: grid; grid-template-columns: repeat(8, 1fr); gap: 4px; height: 336px; }
.pr-col { position: relative; background: #07080C; overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(102,102,255,.82); transition: box-shadow .2s var(--ease); }
.pr-col.playing { box-shadow: inset 0 0 0 1.55px rgba(51,204,204,1); }
.pr-col .keys { position: absolute; inset: 0; }

/* White key: full column width, 42pt tall as pianoWhiteKeyHeight fixes it —
   NOT a fraction of the viewport. The stack deliberately overflows and the roll
   clips it, which is why the app scrolls the keys. */
.pr-key { position: absolute; left: 0; right: 0; box-sizing: border-box; height: 42px;
  background: #E4E7F0; border-bottom: 1.2px solid rgba(21,23,33,.92);
  transition: background .28s var(--ease); }
.pr-key.sel { background: rgba(153,51,255,.82); border-bottom-color: rgba(21,23,33,.70); }
.pr-key .lead { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: rgba(51,204,204,.94); transition: width .18s var(--ease); }
.pr-key.sel .lead { width: 2.25px; }
.pr-key .root { position: absolute; left: 0; top: 0; bottom: 0; width: 1.5px; background: rgba(153,51,255,.48); }
.pr-key .oct { position: absolute; right: 1px; top: 0; bottom: 0; display: flex; align-items: center;
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-family: "Nightshape", var(--sans); font-size: 11px; letter-spacing: .15px;
  color: rgba(7,8,12,.86); pointer-events: none; }
.pr-key.sel .oct { color: rgba(7,8,12,.98); }

/* Black key: 68% of the column, 60% of a key's height, centred on the divider,
   with its own 1pt border. */
.pr-blk { position: absolute; left: 0; width: 68%; box-sizing: border-box; height: 25.2px;
  background: #11131B; border: 1px solid rgba(5,6,10,.95); z-index: 2;
  transition: background .28s var(--ease), border-color .28s var(--ease); }
.pr-blk.sel { background: rgba(153,51,255,.96); border-color: rgba(153,51,255,.98); }
.pr-blk .lead { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: rgba(51,204,204,.94); transition: width .18s var(--ease); }
.pr-blk.sel .lead { width: 2.25px; }

/* Step number over note name, at the top of every column. */
.pr-colhead { position: absolute; top: 4px; left: 0; right: 0; z-index: 3; text-align: center; pointer-events: none; }
.pr-colhead .n { display: block; font-family: "Adam", var(--mono); font-weight: 500; font-size: 7.3px; letter-spacing: .75px; color: rgba(255,255,255,.74); }
.pr-colhead .nm { display: block; margin-top: 1px; font-family: "Nightshape", var(--sans); font-size: 8.4px; letter-spacing: .5px; color: rgba(153,51,255,.94); }
.pr-colhead .nm.off { color: rgba(153,51,255,.38); }

/* Painted stroke. Two layers, because pitch is painted on the keys and values
   are painted in the pads below. */
.pr-stroke { position: absolute; inset: 0; pointer-events: none; z-index: 4; opacity: 0; transition: opacity .25s var(--ease); }
.pr-stroke.on { opacity: 1; }
.pr-stroke svg { width: 100%; height: 100%; display: block; overflow: visible; }
.pr-stroke path { fill: none; stroke: var(--hot-teal); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 0 7px rgba(0,229,212,.55)); }
.pr-stroke .tip { position: absolute; width: 18px; height: 18px; margin: -9px 0 0 -9px; border-radius: 50%;
  background: rgba(0,229,212,.18); border: 1px solid rgba(0,229,212,.75); }

/* Parameter lane — parameterPad. Values are painted HERE, not on the keys. */
.pr-ctl { position: relative; display: grid; grid-template-columns: repeat(8, 1fr); gap: 4px; height: 92px; margin-top: 8px; }
.pr-ctl .c { position: relative; background: #090A0D; overflow: hidden;
  box-shadow: inset 0 0 0 1.5px rgba(102,102,255,.78); transition: box-shadow .2s var(--ease); }
.pr-ctl .c.playing { box-shadow: inset 0 0 0 1.5px rgba(102,102,255,1); }
.pr-ctl .c i { position: absolute; left: 0; right: 0; bottom: 0; background: var(--indigo); opacity: .30; transition: height .3s var(--ease); }
.pr-ctl .c .no { position: absolute; top: 5px; left: 5px; font-family: "Adam", var(--mono); font-weight: 500; font-size: 7.8px; letter-spacing: .7px; color: rgba(255,255,255,.72); }
.pr-ctl .c .nt { position: absolute; top: 5px; right: 5px; font-family: "Nightshape", var(--sans); font-size: 9px; letter-spacing: .5px; color: rgba(153,51,255,.90); }
.pr-ctl .c .vv { position: absolute; left: 0; right: 0; bottom: 17px; text-align: center; font-family: "Nightshape", var(--sans); font-size: 17px; letter-spacing: .5px; color: rgba(255,255,255,.92); }
.pr-ctl .c .un { position: absolute; left: 0; right: 0; bottom: 5px; text-align: center; font-family: "Adam", var(--mono); font-size: 7.2px; letter-spacing: 1.1px; color: rgba(255,255,255,.42); }

.pr-foot { display: flex; align-items: center; gap: 8px; padding: 10px 16px;
  font-family: "Nightshape", var(--sans); font-size: 11px; letter-spacing: 2.2px; border-top: 1px solid var(--border); margin-top: 8px; }
.pr-foot .lo { color: rgba(102,102,255,.82); }
.pr-foot .hi { margin-left: auto; color: rgba(255,255,255,.66); }

.pr-caption { display: flex; gap: 14px; align-items: flex-start; padding: 16px 20px; border-top: 1px solid var(--border); }
.pr-caption .n { font-family: var(--mono); font-size: 10px; letter-spacing: .2em; color: var(--teal); padding-top: 2px; }
.pr-caption p { color: var(--text-2); font-size: 14.5px; line-height: 1.6; margin: 0; }
.pr-note { margin-top: 18px; padding-left: 16px; border-left: 1px solid rgba(51,204,204,.35);
  color: var(--text-dim); font-size: 14px; line-height: 1.65; max-width: 780px; }

@media (max-width: 760px) {
  .pr-roll { height: 250px; }
  .pr-head, .pr-foot { font-size: 10px; letter-spacing: 1.4px; }
  .pr-ctl { height: 76px; }
}

/* The piano roll lives inside the same device chrome as the sequencer, so it
   inherits .dk-frame / .dk-screen. Only the parts that differ are set here. */
/* Two columns: the gestures read as scroll-synced callouts beside the device,
   the same shape the sequencer showcase uses, instead of leaving the phone
   alone in the middle of the column. */
.pr-stage { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 48px; padding: 8px 0 24px; }
.pr-callouts { max-width: 380px; justify-self: end; }
.pr-callout { margin-bottom: 26px; }
.pr-callout:last-child { margin-bottom: 0; }
@media (max-width: 1000px) {
  .pr-stage { grid-template-columns: 1fr; justify-items: center; gap: 8px; }
  .pr-callouts { max-width: 620px; justify-self: center; order: 2; }
}
/* Scale and the negative margin that compensates for it are both set in JS
   (scalePianoDevice), the same way scaleDevice sizes the sequencer showcase —
   a fixed scale either overflowed short viewports or wasted a tall one. */
/* The slot is sized to the RENDERED dimensions in JS; the device scales inside
   it from its top-left. Compensating with a negative margin instead left the
   phone hanging past its own grid row — align-items centres the unscaled 984px
   box while the transform scales from its top, so the two disagree. */
.pr-device-slot { position: relative; }
.pr-device-slot .dk-device { position: absolute; top: 0; left: 0; transform: scale(var(--scale, 1)); transform-origin: top left; }
.dk-pr { flex: 1; display: flex; flex-direction: column; min-height: 0; padding: 0 4px; }
.dk-pr .pr-head { padding: 6px 2px; border-bottom: 0; font-size: 11px; letter-spacing: 1.6px; }
.dk-pr .pr-roll { flex: 1; height: auto; min-height: 0; overflow: hidden; }
.dk-pr .pr-ctl { height: 74px; margin-top: 4px; }
.dk-pr .pr-foot { padding: 6px 2px 0; border-top: 0; margin-top: 4px; font-size: 9.5px; letter-spacing: 1.4px; }
/* Mode rail: the active mode reads as lit accent type on the same glass face,
   with the border carrying the weight — never a solid fill. */
.pr-rail .dk-chip.pr-on { border-color: rgba(168,85,247,.9); color: rgba(168,85,247,.98); }
.pr-rail .dk-chip.pr-exit svg { width: 10px; height: 10px; }

/* ---------- Scene 06 — PERFORM ----------
   Values from PerformanceCaptureView. PERFORM is its own surface: no display
   panel, no identity row. segGroup is a sharp-cornered hardware shell over a
   barely-lit fill; selected reads as accent type, a 0.12 wash and a solid 2pt
   underbar. Both groups use accentTeal — the metronome is violet precisely so
   it does not read as a third selectable option in that row. */
.dk-pf { flex: 1; display: flex; flex-direction: column; min-height: 0; padding: 14px 20px 0; }
.pf-controls { display: flex; align-items: center; justify-content: center; gap: 10px; padding-top: 10px; }
.pf-seg { display: inline-flex; background: rgba(255,255,255,.022); box-shadow: inset 0 0 0 1px var(--border); }
.pf-div { width: 1px; align-self: stretch; background: var(--border); }
.pf-tab { display: inline-flex; align-items: center; gap: 6px; padding: 7px 13px; position: relative;
  color: var(--text-dim); font-family: "Nightshape", var(--sans); font-size: 12px; letter-spacing: 2px; }
.pf-tab i { font-style: normal; transform: translateY(0.061em); }
.pf-tab svg { width: 11px; height: 11px; }
.pf-tab.on { color: var(--dk-teal); background: rgba(51,204,204,.12); }
.pf-tab.on::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--dk-teal); }
/* Violet, and it SNAPS — the arm flips per beat with no animation, so it reads
   as a tick that has already happened rather than a motion in progress. */
.pf-met { width: 34px; height: 34px; display: grid; place-items: center; color: rgba(153,51,255,.95);
  background: rgba(255,255,255,.028); box-shadow: inset 0 0 0 1px rgba(153,51,255,.50); }
/* The REAL SF Symbol, rendered from the system font by tools/render-sf-symbol.swift
   at the app's own pointSize 15 / weight .semibold, and used as a mask so the
   exact glyph still takes the violet tint and the mirror. */
.pf-met .glyph { display: block; width: 17px; height: 15px; background: currentColor;
  -webkit-mask: url(../img/sf/metronome.png) no-repeat center / contain;
  mask: url(../img/sf/metronome.png) no-repeat center / contain; }
/* Mirror on the beat. The app snaps — animation(nil) — so the arm reads as a
   tick that has already happened, never a motion in progress. */
.pf-met .glyph { transition: none; }
.pf-met.flip .glyph { transform: scaleX(-1); }

.pf-status { text-align: center; margin-top: 14px; font-family: "Nightshape", var(--sans);
  font-size: 21px; letter-spacing: 2.4px; color: rgba(255,255,255,.92); }
.pf-sub { text-align: center; margin-top: 5px; font-family: "Adam", var(--mono); font-size: 8.5px;
  letter-spacing: 1.4px; color: var(--text-dim); }

/* PERFORM's own header. The app does NOT show the workstation wordmark here:
   NIGHTSHAPE-Bold 20 white title, a teal 10pt state line under it, then the
   lavender tempo readout and the kit / help / close controls in teal. */
/* The chrome carries the app's own background so the capture field is occluded
   by it rather than bleeding through. In the app the toggles are only a 2.2%
   white face over a full-bleed ripple field — which works there because hits
   land in the open area and never wash up into the controls. The downbeat
   crash sits just under them here, so the chrome needs real ground. */
.pf-header, .dk-pf .pf-controls, .pf-transport { position: relative; background: #0C0C0E; }
.dk-pf .pf-controls { padding-bottom: 10px; }

.pf-header { display: flex; align-items: center; gap: 6px; padding: 10px 0 2px; }
.pf-hl { flex: 1; min-width: 0; }
.pf-h1 { font-family: "Nightshape", var(--sans); font-size: 20px; letter-spacing: .6px; color: #fff; }
.pf-h2 { margin-top: 2px; font-family: "Adam", var(--mono); font-weight: 500; font-size: 10px;
  letter-spacing: 1.5px; color: rgba(51,204,204,.9); white-space: nowrap; }
/* metaFont(.thin, 27) over metaFont(.heavy, 8), spacing -3, both lavender. */
.pf-bpm { display: flex; flex-direction: column; align-items: center; min-width: 48px; padding: 2px 6px; }
.pf-bpm .v { font-family: "Adam", var(--mono); font-weight: 300; font-size: 27px; line-height: 1; color: var(--lavender); }
.pf-bpm .u { margin-top: -3px; font-family: "Adam", var(--mono); font-weight: 700; font-size: 8px;
  letter-spacing: 2.2px; color: var(--lavender); }
.pf-ic { width: 26px; height: 26px; display: grid; place-items: center; color: rgba(51,204,204,.95); }
.pf-ic svg { width: 18px; height: 18px; }
.pf-ic .q { font-family: "Adam", var(--mono); font-weight: 700; font-size: 15px; }
.pf-x svg { width: 22px; height: 22px; }

/* countInOverlay. Sits over EVERYTHING including the chrome, as the app's does
   — it is the last child of the capture ZStack, above the control VStack. */
.pf-countin { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px; background: rgba(0,0,0,.35);
  opacity: 0; pointer-events: none; transition: opacity .25s var(--ease); }
.pf-countin.on { opacity: 1; }
.ci-k { font-family: "Nightshape", var(--sans); font-size: 13px; letter-spacing: 4px; color: var(--lavender); }
/* metaFont(.thin, 120), teal, monospaced, shadow(teal .6, radius 18). */
.ci-n { font-family: "Adam", var(--mono); font-weight: 300; font-size: 120px; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--teal); text-shadow: 0 0 18px rgba(51,204,204,.6); }
.ci-s { font-family: "Adam", var(--mono); font-weight: 600; font-size: 9.5px; letter-spacing: 3px;
  color: rgba(152,152,168,.55); }

/* Transport: two rows — transport, then the edit row (UNDO / CLEAR / DONE). */
.pf-transport { flex-direction: column; gap: 10px; }
.pf-trow { display: flex; gap: 10px; }
.pf-edit .pf-btn { height: 38px; font-size: 11px; }
.pf-edit .pf-btn svg { left: 12px; width: 12px; height: 12px; }
.pf-btn.dim { opacity: .4; }
.pf-btn.dim svg { color: var(--text-dim); }
.pf-btn.pf-clear { box-shadow: inset 0 0 0 1px rgba(153,51,255,.42); }
.pf-btn.pf-clear svg { color: var(--purple); }
/* Recording: RECORD becomes STOP and takes the teal transport tint. */
.pf-btn.pf-rec.rec-on { box-shadow: inset 0 0 0 1px rgba(51,204,204,.42); }
.pf-btn.pf-rec.rec-on svg { color: var(--dk-teal); }

/* PERFORM is an opaque surface over the workstation — NightshapeTheme.background,
   no wave showing through, in either surface. */
.pf-screen { background: #0C0C0E; }

/* The GROOVE capture surface is full-bleed behind the entire screen — the app
   stacks it under the header and controls, not inside the content column. The
   canvas paints the graticule, the indigo radial and the ripples together. */
.pf-groove { position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  opacity: 0; transition: opacity .45s var(--ease); pointer-events: none; z-index: 0; }
.pf-groove.on { opacity: 1; }
/* On GROOVE the pads are gone entirely and the status becomes the big centred
   readout on the surface: NIGHTSHAPE-Bold 18 / tracking 3, subtitle 9.5 / 3. */
.pf-body.groove .pf-pads { display: none; }
/* The centre status is gated on `phase != .countIn` in the app — the overlay
   carries the screen on its own while the count runs. */
.pf-body.counting .pf-status, .pf-body.counting .pf-sub { visibility: hidden; }
.pf-body.groove .pf-status { font-size: 18px; letter-spacing: 3px; color: var(--lavender); }
.pf-body.groove .pf-status.ready { color: var(--teal); }
.pf-body.groove .pf-sub { margin-top: 9px; font-weight: 600; font-size: 9.5px; letter-spacing: 3px;
  color: rgba(152,152,168,.5); }

/* 4 columns, 16 pads (maxTracks). padCell: #141519 at radius 3, a 1pt black
   stroke, an accent CAP across the top, and the label sitting at the BOTTOM of
   the cell with 8pt beneath it — not centred. Lit adds a 1.5pt accent stroke, a
   14pt shadow, and a BLURRED BLOOM over the top cap. There is no bottom bar. */
/* padCell is a VStack(spacing: 5): the cell, then its category beneath. */
.pf-pads { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px 10px; margin-top: 14px; }
.pf-padwrap { display: flex; flex-direction: column; gap: 5px; }
.pf-cat { text-align: center; font-family: "Nightshape", var(--sans); font-size: 7.5px; letter-spacing: 1.6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pf-pad { position: relative; height: 66px; border-radius: 3px; background: #141519; overflow: visible;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.55); transition: box-shadow .42s var(--ease); }
.pf-pad .cap { position: absolute; top: 0; left: 0; right: 0; height: 7px; border-radius: 3px 3px 0 0;
  transition: opacity .42s var(--ease); }
/* The bloom is the same 7pt bar blurred over the cap, at .85 when lit. */
.pf-pad .bloom { position: absolute; top: 0; left: 0; right: 0; height: 7px; filter: blur(6px);
  opacity: 0; pointer-events: none; transition: opacity .42s var(--ease); }
.pf-pad .nm { position: absolute; left: 0; right: 0; bottom: 8px; text-align: center;
  font-family: "Nightshape", var(--sans); font-size: 9.5px; letter-spacing: .6px; color: #8B93A3;
  padding: 0 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pf-pad.empty .nm { color: #565C6B; }
/* shadow(color: accent.opacity(0.6), radius: 14) — at full strength the
   glow read far hotter than the app. */
.pf-pad.lit { box-shadow: inset 0 0 0 1.5px currentColor, 0 0 14px var(--acc60); transition: box-shadow .04s var(--ease); }
.pf-pad.lit .cap, .pf-pad.lit .bloom { transition: opacity .04s var(--ease); }
.pf-pad.lit .bloom { opacity: .85; }

/* padStatus + padGrid sit between Spacers, so the block centres in the space
   left under the control row. */
.pf-body { flex: 1; display: flex; flex-direction: column; justify-content: center; min-height: 0; }

.pf-transport { display: flex; gap: 10px; margin-top: auto; padding: 13px 0 16px; }
.pf-btn { position: relative; flex: 1; height: 46px; display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.028); box-shadow: inset 0 0 0 1px rgba(51,204,204,.42);
  font-family: "Nightshape", var(--sans); font-size: 12.5px; letter-spacing: 1.8px; color: rgba(255,255,255,.92); }
.pf-btn svg { position: absolute; left: 16px; width: 13px; height: 13px; color: var(--dk-teal); }
.pf-btn.pf-rec { box-shadow: inset 0 0 0 1px rgba(168,85,247,.42); }
.pf-btn.pf-rec svg { color: var(--dk-hotpurple); }

/* ============================================================================
   SHAPE — Sonic Decimator floating editor.
   Metrics from SonicDecimatorPrototypeView.swift: editor VStack(spacing:10)
   padding 14; module header 28pt; axis strip 42pt; the pad is a perfect square
   with a 1.5pt #00C8B8 @.72 frame and four 10x10 corner marks at @.92.
   ========================================================================== */
.dc-stage { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; gap: 48px; padding: 8px 0 24px; }
.dc-callouts { max-width: 380px; justify-self: end; }
.dc-callout { margin-bottom: 26px; }
.dc-callout:last-child { margin-bottom: 0; }
@media (max-width: 1000px) {
  .dc-stage { grid-template-columns: 1fr; justify-items: center; gap: 8px; }
  .dc-callouts { max-width: 620px; justify-self: center; order: 2; }
}
.dc-device-slot { position: relative; }
.dc-device-slot .dk-device { position: absolute; top: 0; left: 0; transform: scale(var(--scale,1)); transform-origin: top left; }

/* The editor sits over the workstation, so the screen is the app background. */
.dc-screen { background: #0C0C0E; }
.dc-body { position: relative; z-index: 2; padding: 0; height: calc(100% - 62px);
  display: flex; flex-direction: column; align-items: center; justify-content: center; }
/* The workstation, visible around the floating panel and darkened by the scrim. */
/* Starts BELOW the status bar, where .dk-body actually begins — at inset 0 the
   cloned workstation slid up under the clock and the wordmark collided with it. */
.dc-backdrop { position: absolute; top: 62px; left: 0; right: 0; bottom: 0;
  z-index: 0; overflow: hidden; pointer-events: none; }
.dc-backdrop .dk-body { height: 100%; }
.dc-scrim { position: absolute; inset: 0; z-index: 1; background: rgba(0,0,0,.62); pointer-events: none; }
/* nightshapePremiumPanelChrome: panel fill, 1px white .10 edge, drop shadow.
   Fixed 380x660 as the app sizes it, so the module is squeezed when MOTION
   opens rather than the panel growing. */
.dc-panel { width: 380px; height: 660px; flex: none;
  display: flex; flex-direction: column; gap: 10px; padding: 14px;
  background: #0F0F13; box-shadow: inset 0 0 0 1px rgba(255,255,255,.10), 0 2px 24px rgba(0,0,0,.55); }
.dc-module { display: flex; flex-direction: column; flex: 1; min-height: 0; }

.dc-head { display: flex; align-items: center; height: 34px; }
.dc-title { font-family: "Nightshape", var(--sans); font-size: 16px; letter-spacing: 2px; color: rgba(255,255,255,.94); }
.dc-sub { margin-top: 3px; font-family: "Nightshape", var(--sans); font-size: 8.2px; letter-spacing: 1.8px; color: rgba(168,85,247,.82); }
.dc-live { margin-left: auto; display: flex; align-items: center; gap: 5px; }
.dc-live i { width: 8px; height: 5px; background: var(--dk-teal); display: block; }
.dc-live i.off { background: rgba(255,255,255,.22); }
.dc-live span { font-family: "Nightshape", var(--sans); font-size: 8px; letter-spacing: 1.4px; color: #888899; }

.dc-mhead { display: flex; align-items: center; height: 28px; padding: 0 4px; }
.dc-mbar { width: 3px; height: 12px; background: rgba(168,85,247,.84); margin-right: 6px; }
.dc-mname { font-family: "Nightshape", var(--sans); font-size: 12px; letter-spacing: 2.4px; color: rgba(255,255,255,.86); }
.dc-mstate { margin-left: auto; font-family: "Adam", var(--mono); font-weight: 500; font-size: 8.4px; letter-spacing: 1.8px; color: rgba(255,255,255,.82); }
.dc-mstate.byp { color: rgba(255,255,255,.34); }

/* The teal sits ONLY on the panel frame; the ferrofluid surface stays void. */
.dc-pad { position: relative; margin: 0 auto; background: #040406;
  box-shadow: inset 0 0 0 1.5px rgba(0,200,184,.72); }
.dc-pad canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.dc-pad .cm { position: absolute; width: 10px; height: 10px; box-shadow: inset 0 0 0 1px rgba(0,200,184,.92); }
.dc-pad .cm.tl { top: 4px; left: 4px; } .dc-pad .cm.tr { top: 4px; right: 4px; }
.dc-pad .cm.bl { bottom: 4px; left: 4px; } .dc-pad .cm.br { bottom: 4px; right: 4px; }

.dc-axis { height: 42px; display: flex; flex-direction: column; justify-content: flex-end; gap: 4px; padding: 0 9px 0; }
.dc-axis > div { display: flex; justify-content: space-between; font-family: "Adam", var(--mono); font-weight: 500;
  font-size: 7.8px; letter-spacing: 1.5px; color: #888899; }
.dc-axis .ax.x { color: var(--dk-hotpurple); }
.dc-axis .ax.y { color: var(--dk-teal); }

/* axisReadout: 32pt tall, #101115, 1px accent @.55 border. */
.dc-readouts { display: flex; gap: 8px; }
.dc-ro { flex: 1; display: flex; align-items: center; justify-content: space-between; height: 32px; padding: 0 9px;
  background: #101115; box-shadow: inset 0 0 0 1px rgba(168,85,247,.55); }
.dc-ro.y { box-shadow: inset 0 0 0 1px rgba(51,204,204,.55); }
.dc-ro span { font-family: "Nightshape", var(--sans); font-size: 9.6px; letter-spacing: 1.4px; color: var(--dk-hotpurple); }
.dc-ro.y span { color: var(--dk-teal); }
.dc-ro b { font-family: "Nightshape", var(--sans); font-weight: 400; font-size: 15px; letter-spacing: 1px;
  color: #EEEEFF; font-variant-numeric: tabular-nums; }

/* MOTION — 9pt padding on #0A0A0E, plus the short accent tick top-left. */
.dc-motion { position: relative; padding: 9px; background: #0A0A0E;
  box-shadow: inset 0 0 0 1px rgba(51,51,66,.55); }
.dc-motion::before { content: ""; position: absolute; top: 1px; left: 1px; width: 30px; height: 1px;
  background: rgba(182,184,198,.34); transition: width .3s var(--ease), background .3s var(--ease); }
.dc-motion.on { box-shadow: inset 0 0 0 1px rgba(51,204,204,.72); }
.dc-motion.on::before { width: 58px; background: rgba(51,204,204,.88); }
.dc-mtop { display: flex; align-items: center; gap: 8px; }
.dc-mlabel { font-family: "Nightshape", var(--sans); font-size: 9.8px; letter-spacing: 2.2px; color: #3A3A48; }
.dc-motion.on .dc-mlabel { color: var(--dk-teal); }
.dc-mdiv { width: 1px; height: 15px; background: rgba(255,255,255,.10); }
.dc-motion.on .dc-mdiv { background: rgba(255,255,255,.22); }
.dc-mseq { font-family: "Nightshape", var(--sans); font-size: 8px; letter-spacing: 1.4px; color: #3A3A48; }
.dc-motion.on .dc-mseq { color: #888899; }
.dc-mtoggle { margin-left: auto; width: 52px; height: 26px; display: grid; place-items: center;
  font-family: "Nightshape", var(--sans); font-size: 9.4px; letter-spacing: 1.8px;
  background: #101115; color: #B6B8C6; box-shadow: inset 0 0 0 1px rgba(51,204,204,.6); }
.dc-motion.on .dc-mtoggle { background: var(--dk-teal); color: #0A0A0E; }

.dc-mbody { display: none; flex-direction: column; gap: 7px; margin-top: 8px; padding: 7px;
  background: #050508; box-shadow: inset 0 0 0 1px rgba(255,255,255,.08); }
.dc-motion.on .dc-mbody { display: flex; }

/* Step strip: 32pt cells, 3pt gaps. ON = purple, playing = teal + 2pt top bar,
   selected = white border + 1pt bottom rule. */
.dc-strip { display: flex; gap: 3px; height: 32px; }
.dc-cell { flex: 1; position: relative; background: rgba(255,255,255,.05); box-shadow: inset 0 0 0 1px rgba(255,255,255,.12); }
.dc-cell.on { background: rgba(168,85,247,.55); box-shadow: inset 0 0 0 1px rgba(255,255,255,.18); }
.dc-cell.playing { background: var(--dk-teal); }
.dc-cell.playing::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: rgba(51,204,204,.95); }
.dc-cell.sel { box-shadow: inset 0 0 0 1.6px rgba(255,255,255,.9); }
.dc-cell.sel::after { content: ""; position: absolute; bottom: 0; left: 0; right: 0; height: 1px; background: rgba(255,255,255,.72); }

.dc-selrow { display: flex; align-items: center; gap: 8px; }
.dc-step { width: 66px; font-family: "Nightshape", var(--sans); font-size: 9.4px; letter-spacing: 1.2px; color: #B6B8C6; }
.dc-mini { flex: 1; height: 30px; display: grid; place-items: center; background: #101115;
  font-family: "Nightshape", var(--sans); font-size: 9.8px; letter-spacing: 1.2px; color: rgba(255,255,255,.9);
  box-shadow: inset 0 0 0 1px rgba(168,85,247,.7); }

.dc-rate { display: flex; align-items: center; gap: 5px; }
.dc-rlabel { width: 40px; font-family: "Nightshape", var(--sans); font-size: 8.8px; letter-spacing: 1.3px; color: #888899; }
.dc-rcell { flex: 1; height: 30px; display: grid; place-items: center; background: #101115;
  font-family: "Nightshape", var(--sans); font-size: 9.8px; letter-spacing: .6px; color: rgba(255,255,255,.32);
  box-shadow: inset 0 0 0 1px rgba(51,204,204,.18); }
.dc-rcell.on { background: var(--dk-teal); color: #0A0A0E; box-shadow: inset 0 0 0 1px rgba(51,204,204,.8); }

.dc-lenrow { display: flex; gap: 8px; }
.dc-len { flex: 1; display: flex; box-shadow: inset 0 0 0 1px rgba(255,255,255,.16); }
.dc-len .s { width: 32px; height: 30px; display: grid; place-items: center; background: #101115;
  font-family: "Nightshape", var(--sans); font-size: 16px; color: rgba(255,255,255,.85); }
.dc-len .v { flex: 1; height: 30px; display: grid; place-items: center; background: #101115;
  font-family: "Nightshape", var(--sans); font-size: 9.8px; letter-spacing: 1px; color: rgba(255,255,255,.9); }
.dc-off { flex: 1; display: flex; box-shadow: inset 0 0 0 1px rgba(168,85,247,.4); }
.dc-off span { flex: 1; height: 30px; display: grid; place-items: center; background: #101115;
  font-family: "Nightshape", var(--sans); font-size: 9.8px; letter-spacing: 1.2px; color: rgba(255,255,255,.32); }
.dc-off span.on { background: rgba(168,85,247,.9); color: #0A0A0E; }

.dc-gliderow { display: flex; align-items: center; gap: 10px; height: 28px; }
.dc-glide { position: relative; flex: 1; height: 10px; background: #050509; box-shadow: inset 0 0 0 1px rgba(51,204,204,.32); }
.dc-glide i { position: absolute; left: 0; top: 0; bottom: 0;
  background: linear-gradient(to right, rgba(102,102,255,.58), rgba(51,204,204,.74)); }
.dc-glide b { position: absolute; top: 50%; width: 4px; height: 19px; margin-top: -9.5px;
  background: rgba(51,204,204,.88); box-shadow: inset 0 0 0 .5px rgba(0,0,0,.45); }
.dc-gval { width: 32px; text-align: right; font-family: "Nightshape", var(--sans); font-size: 13px;
  color: #EEEEFF; font-variant-numeric: tabular-nums; }

/* utilityButton: 40pt, #101115, 1px accent @.70. */
.dc-utils { display: flex; gap: 8px; }
.dc-util { flex: 1; height: 40px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  background: #101115; box-shadow: inset 0 0 0 1px rgba(168,85,247,.7); }
.dc-util:nth-child(2) { box-shadow: inset 0 0 0 1px rgba(51,204,204,.7); }
.dc-util.dim { box-shadow: inset 0 0 0 1px rgba(182,184,198,.7); }
.dc-util svg { width: 11px; height: 11px; color: var(--dk-hotpurple); }
.dc-util:nth-child(2) svg { color: var(--dk-teal); }
.dc-util.dim svg { color: #B6B8C6; }
.dc-util i { font-family: "Nightshape", var(--sans); font-style: normal; font-size: 9.6px; letter-spacing: 1.2px; color: rgba(255,255,255,.92); }

/* actionButton: 42pt; APPLY is teal-filled with a top sheen and a soft glow. */
.dc-actions { display: flex; gap: 9px; }
.dc-act { flex: 1; height: 42px; display: grid; place-items: center; background: #101115;
  font-family: "Nightshape", var(--sans); font-size: 11px; letter-spacing: 2.2px; color: rgba(255,255,255,.9);
  box-shadow: inset 0 0 0 1.1px rgba(182,184,198,.6); }
.dc-act.fill { position: relative; color: #050607; background: linear-gradient(to bottom, var(--dk-teal), rgba(51,204,204,.78));
  box-shadow: inset 0 0 0 1.1px rgba(51,204,204,.95), 0 2px 12px rgba(51,204,204,.45); }
/* actionButton's sheen is a 14pt frame whose gradient reaches clear at the
   frame's CENTRE — so the visible fade is ~7pt, not the full 14. Fading over
   the whole 14 made it read as a white band across the top of APPLY. */
.dc-act.fill::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 7px;
  background: linear-gradient(to bottom, rgba(255,255,255,.26), transparent); }

/* FXInspectorChainRail — panel presentation. Matches the app after this
   session's changes: nodes on black at .82, colour means ENGAGED only, and
   bypassed goes fully greyscale so the signal path reads from colour alone.
   Inset to the panel's own 14pt padding, not its outer edge. */
.dc-rail { position: relative; z-index: 2; width: 352px; height: 29px; margin-top: 10px; overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 93%, transparent 100%);
          mask-image: linear-gradient(to right, #000 0, #000 93%, transparent 100%); }
.dc-rail-track { display: flex; gap: 5px; height: 29px; align-items: stretch; padding-right: 12px; }
.dc-node { position: relative; display: flex; align-items: center; gap: 6px; height: 27px; padding: 0 7px;
  background: rgba(0,0,0,.82); flex: none; }
.dc-node .bar { width: 3px; height: 15px; flex: none; }
.dc-node .tx { display: flex; flex-direction: column; gap: 1px; }
.dc-node .nm { font-family: "Nightshape", var(--sans); font-size: 9px; letter-spacing: .7px; white-space: nowrap; }
.dc-node .st { font-family: "Adam", var(--mono); font-weight: 500; font-size: 6.5px; letter-spacing: 1px; white-space: nowrap; }
/* Engaged: full accent, whether or not it is the one open for editing.
   Only the 3px status RAIL takes an accent fill — giving the status TEXT a
   background too painted a solid block over the word. */
.dc-node.on .nm { color: var(--acc); }
.dc-node.on .bar { background: var(--acc); }
.dc-node.on .st { color: var(--acc); }
.dc-node.on { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--acc) 62%, transparent); }
.dc-node.on.sel { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--acc) 95%, transparent); }
/* The tint wash sits BEHIND the label, not over it. */
.dc-node.on::after { content: ""; position: absolute; inset: 0; z-index: 0;
  background: var(--acc); opacity: .045; }
.dc-node.on.sel::after { opacity: .12; }
.dc-node .bar, .dc-node .tx { position: relative; z-index: 1; }
/* Bypassed: greyscale, never a dimmed hue. */
.dc-node.off .nm { color: rgba(255,255,255,.46); }
.dc-node.off .bar { background: rgba(255,255,255,.34); }
.dc-node.off .st { color: rgba(255,255,255,.34); }
.dc-node.off { box-shadow: inset 0 0 0 1px rgba(255,255,255,.24); }

/* ---------- Legal pages ---------- */
.legal-page { padding: 140px 0 100px; }
.legal-page .wrap { max-width: 760px; }
.legal-page h1 { font-size: clamp(38px, 6vw, 58px); font-weight: 800; letter-spacing: -0.02em;
  margin: 10px 0 22px; color: var(--text); }
.legal-lede { font-size: 19px; line-height: 1.62; color: var(--text); margin-bottom: 14px; }
.legal-updated { font-family: var(--mono); font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-dim); margin-bottom: 46px; }
.legal-page section { margin-bottom: 38px; }
.legal-page h2 { font-size: 21px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 12px; color: var(--text); }
.legal-page p { color: var(--text-2); font-size: 16px; line-height: 1.72; margin-bottom: 13px; }
.legal-page p:last-child { margin-bottom: 0; }
.legal-page strong { color: var(--text); font-weight: 600; }
.legal-page code { font-family: var(--mono); font-size: 1em; color: var(--lavender); }
.legal-page a { color: var(--teal); text-decoration: none; border-bottom: 1px solid rgba(51,204,204,.35); }
.legal-page a:hover { border-bottom-color: var(--teal); }
.footer-bottom .legal a { color: var(--text-dim); text-decoration: none; margin-left: 18px; }
.footer-bottom .legal a:hover { color: var(--text-2); }

/* ---------- Extraction lane on narrow screens ----------
   Two problems made the whole document scroll sideways on a phone, which is
   what cut this section off on the right in Safari.

   1. .extract-stage is `1fr 300px`. At 375px the fixed 300px column alone
      exceeds the space left after page and lane padding, so the grid pushed
      past the viewport. Below 900px the one-shot lane stacks underneath.

   2. The slice row is eight cards whose mono labels ("KICK_01") have a
      min-content width the flex row cannot compress below. Rather than shrink
      the type until it is unreadable, or wrap the cards out of alignment with
      the category columns beneath them, the lane scrolls horizontally as ONE
      unit — waveform, markers, cards and columns stay locked together, and the
      page itself never scrolls. */
@media (max-width: 900px) {
  .extract-stage { grid-template-columns: 1fr; gap: 24px; }
  .ex-short { margin-top: 0; }
}
@media (max-width: 760px) {
  .extract-stage { padding: 0 16px; }
  .ex-lane { padding: 20px 16px 18px; overflow-x: auto; overflow-y: hidden;
    -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
  /* One shared min-width keeps the four stacked rows in register. */
  .ex-lane-head, .ex-wavewrap, .ex-cards, .ex-cols, .ex-curate { min-width: 420px; }
  .ex-cards { gap: 6px; }
  .ex-card { padding: 8px 4px; }
  .ex-card .nm { font-size: 8.5px; letter-spacing: .06em; }
  .ex-col { font-size: 8.5px; letter-spacing: .1em; }
}

/* Export breakdown — replaces a ~100-word single paragraph. */
.ex-out { list-style: none; margin: 34px auto 0; max-width: 780px;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 34px; }
.ex-out li { color: var(--text-2); font-size: 15px; line-height: 1.62;
  border-top: 1px solid var(--border); padding-top: 14px; }
.ex-out .k { display: block; margin-bottom: 6px; font-family: var(--mono); font-size: 10px;
  letter-spacing: .2em; text-transform: uppercase; color: var(--teal); }
.ex-out code { font-family: var(--mono); font-size: 1em; color: var(--lavender); }
@media (max-width: 760px) { .ex-out { grid-template-columns: 1fr; gap: 18px; } }

/* The signature claim, directly under the hero. Deliberately quiet chrome — it
   should read as an aside a knowledgeable person leans in for, not a banner. */
.signature { display: block; max-width: 780px; margin: 96px auto 40px; padding: 34px 38px;
  border: 1px solid var(--border); background: rgba(255,255,255,.014);
  text-decoration: none; transition: border-color .3s var(--ease), background .3s var(--ease); }
.signature:hover { border-color: rgba(51,204,204,.42); background: rgba(255,255,255,.03); }
.sig-k { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--teal); margin-bottom: 12px; }
.signature p { color: var(--text); font-size: 17px; line-height: 1.62; margin: 0; }
.signature em { font-style: normal; color: var(--lavender); }
.sig-more { display: inline-block; margin-top: 14px; font-family: var(--mono); font-size: 11px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim);
  transition: color .3s var(--ease); }
.signature:hover .sig-more { color: var(--teal); }
@media (max-width: 760px) { .signature { padding: 24px 20px; margin: 56px 16px 28px; } .signature p { font-size: 15.5px; } }

/* ============================================================================
   SAMPLE — the app's real extraction flow. Values from ExtractionResultsView:
   AnalyzingPanel's three-tier readout, and the 64pt sample rows.
   ========================================================================== */
.sx-stage { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; gap: 48px; padding: 8px 0 24px; }
.sx-callouts { max-width: 380px; justify-self: end; }
.sx-callout { margin-bottom: 26px; }
.sx-callout:last-child { margin-bottom: 0; }
@media (max-width: 1000px) {
  .sx-stage { grid-template-columns: 1fr; justify-items: center; gap: 8px; }
  .sx-callouts { max-width: 620px; justify-self: center; order: 2; }
}
.sx-device-slot { position: relative; }
.sx-device-slot .dk-device { position: absolute; top: 0; left: 0; transform: scale(var(--scale,1)); transform-origin: top left; }
.sx-screen { background: #0C0C0E; }
.sx-body { display: flex; flex-direction: column; }

/* --- AnalyzingPanel --- */
.sx-analyze { flex: 1; display: none; flex-direction: column; align-items: center; justify-content: center; gap: 24px; }
.sx-analyze.on { display: flex; }
#sxHarvest { width: 360px; height: 178px; display: block; background: #060608;
  box-shadow: inset 0 0 0 1.2px rgba(153,51,255,.8); }
.sx-read { display: flex; flex-direction: column; align-items: center; gap: 9px; text-align: center; }
.sx-read .r1 { font-family: "Nightshape", var(--sans); font-size: 18px; letter-spacing: 2.4px; color: #B6B8C6; }
.sx-read .r2 { font-family: "Nightshape", var(--sans); font-size: 11px; letter-spacing: 2.2px; color: rgba(187,166,253,.78); }
.sx-read .r3 { font-family: "Adam", var(--mono); font-weight: 600; font-size: 10.5px; letter-spacing: 1.6px; color: #A8ACBE; white-space: nowrap; }
.sx-prog { position: relative; width: 320px; height: 3px; background: #050507; }
.sx-prog i { position: absolute; left: 0; top: 0; bottom: 0; background: #50505C; }
.sx-prog i::after { content: ""; position: absolute; right: 0; top: 0; bottom: 0; width: 2px; background: #606070; }
.sx-job { font-family: var(--mono); font-weight: 600; font-size: 9.5px; letter-spacing: 1.3px; color: #8B93A3; }

/* --- EXTRACTION RESULTS --- */
.sx-results { flex: 1; display: none; flex-direction: column; min-height: 0; padding: 0 4px; }
.sx-results.on { display: flex; }
.sx-head { padding: 22px 18px 12px; }
.sx-head .t { font-family: "Nightshape", var(--sans); font-size: 24px; letter-spacing: 2px; color: #B6B8C6; }
.sx-head .s { margin-top: 4px; font-family: "Nightshape", var(--sans); font-size: 8px; letter-spacing: 1.6px; color: rgba(187,166,253,.72); }
.sx-rows { display: flex; flex-direction: column; gap: 7px; padding: 0 14px; }
/* sampleRow: 64pt tall, 11pt horizontal padding, bordered in the category accent. */
.sx-row { display: flex; align-items: center; gap: 12px; height: 64px; padding: 0 11px;
  background: #0A0A0E; box-shadow: inset 0 0 0 1px var(--acc45); }
.sx-tick { width: 22px; height: 22px; flex: none; display: grid; place-items: center;
  background: var(--acc90); box-shadow: inset 0 0 0 1.2px var(--acc); }
.sx-tick svg { width: 11px; height: 11px; color: rgba(0,0,0,.85); }
.sx-play { width: 34px; height: 34px; flex: none; display: grid; place-items: center;
  box-shadow: inset 0 0 0 1.2px var(--dk-teal); }
.sx-play svg { width: 11px; height: 11px; color: var(--dk-teal); }
.sx-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sx-meta .nm { font-family: "Nightshape", var(--sans); font-size: 13.5px; letter-spacing: 1.8px; color: #F2F4FA; white-space: nowrap; }
.sx-meta .m1 { font-family: var(--mono); font-weight: 500; font-size: 9px; letter-spacing: .6px; color: #AEAEBE; white-space: nowrap; }
.sx-meta .m2 { font-family: var(--mono); font-weight: 500; font-size: 8px; letter-spacing: .4px; color: #82828F; white-space: nowrap; }
.sx-pen { width: 28px; height: 34px; flex: none; display: grid; place-items: center;
  box-shadow: inset 0 0 0 1px rgba(102,102,255,.34); }
.sx-pen svg { width: 11px; height: 11px; color: rgba(102,102,255,.9); }
.sx-cat { width: 52px; height: 34px; flex: none; display: flex; align-items: center; justify-content: center; gap: 3px;
  font-family: var(--mono); font-weight: 700; font-size: 12px; letter-spacing: 1px; color: var(--acc);
  box-shadow: inset 0 0 0 1px var(--acc34); }
.sx-cat svg { width: 7px; height: 7px; }
.sx-exp { width: 30px; height: 34px; flex: none; display: grid; place-items: center;
  box-shadow: inset 0 0 0 1px rgba(187,166,253,.32); }
.sx-exp svg { width: 13px; height: 13px; color: rgba(187,166,253,.7); }

.sx-foot { margin-top: auto; padding: 14px 18px 16px; display: flex; flex-direction: column; gap: 10px; }
.sx-foot .hint { font-family: "Nightshape", var(--sans); font-size: 8px; letter-spacing: 1.5px;
  color: rgba(187,166,253,.6); line-height: 1.5; }
.sx-sec { display: flex; gap: 10px; justify-content: center; }
.sx-btn { display: flex; align-items: center; justify-content: center; gap: 8px; height: 42px; padding: 0 18px;
  background: #101115; font-family: "Nightshape", var(--sans); font-size: 12px; letter-spacing: 1.8px;
  color: rgba(255,255,255,.9); box-shadow: inset 0 0 0 1px rgba(182,184,198,.5); }
.sx-btn svg { width: 14px; height: 14px; }
/* The primary action carries the app's same-colour bloom — brighter without
   shifting the hex. */
.sx-primary { box-shadow: inset 0 0 0 1.4px rgba(102,102,255,.95), 0 0 10px rgba(102,102,255,.22); color: #fff; }
.sx-build { box-shadow: inset 0 0 0 1px rgba(182,184,198,.5); }

/* The Drum Synth card used an invented blob nobody could read. This is the
   app's own symbol — SF Symbols `waveform`, which DRUMKIT uses everywhere it
   means "a sound" — extracted to a PNG and used as a mask so tint stays ours. */
.sf { display: block; background: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain; }
.card .icon .sf { width: 22px; height: 22px; }
.sf-waveform { -webkit-mask-image: url(../img/sf/waveform.png); mask-image: url(../img/sf/waveform.png); }

/* Launch notification. Square, outlined, in the app's control language. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.notify { display: flex; gap: 10px; justify-content: center; margin: 26px auto 0; max-width: 480px; }
.notify .hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.notify input[type="email"] { flex: 1; min-width: 0; height: 48px; padding: 0 14px;
  background: rgba(255,255,255,.028); border: 1px solid var(--border); border-radius: 0;
  color: var(--text); font-family: var(--sans); font-size: 15px; }
.notify input[type="email"]::placeholder { color: var(--text-dim); }
.notify input[type="email"]:focus { outline: none; border-color: rgba(51,204,204,.6); }
.notify button { height: 48px; padding: 0 22px; flex: none; cursor: pointer;
  background: transparent; border: 1px solid rgba(51,204,204,.55); border-radius: 0;
  color: var(--teal); font-family: var(--mono); font-size: 11px; letter-spacing: .2em;
  text-transform: uppercase; transition: background .25s var(--ease), border-color .25s var(--ease); }
.notify button:hover { background: rgba(51,204,204,.08); border-color: var(--teal); }
.notify button[disabled] { opacity: .5; cursor: default; }
.notify-note { margin: 16px auto 0; font-family: var(--mono);
  font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
.notify-note.ok { color: var(--teal); }
.notify-note.err { color: var(--hot-purple); }
@media (max-width: 560px) { .notify { flex-direction: column; } .notify button { width: 100%; } }

/* Sample Pack tree. Mono, outlined, square — the app's file language. */
.pack { max-width: 620px; margin: 54px auto 0; border: 1px solid var(--border); background: rgba(255,255,255,.012); }
/* Stem folders and filenames are long, unbroken, letter-spaced mono strings —
   NEW-SONG-EXAMPLE_120BPM_STEMS.zip and 03_CLOSED-HAT_MATTE-TICK.wav — with no
   spaces to wrap at. Without this they push the panel past a narrow phone's
   viewport instead of running onto a second line. */
.pack-head { padding: 14px 18px; border-bottom: 1px solid var(--border);
  font-family: var(--mono); font-size: 11px; letter-spacing: .16em; color: var(--teal);
  overflow-wrap: anywhere; }
.pack-tree { list-style: none; margin: 0; padding: 14px 18px; }
.pack-tree li { position: relative; padding: 5px 0 5px 26px; font-family: var(--mono);
  font-size: 12px; letter-spacing: .06em; color: var(--text); overflow-wrap: anywhere; }
.pack-tree li::before { position: absolute; left: 0; color: var(--text-dim); }
.pack-tree li.d::before { content: "▸"; }
.pack-tree li.s { padding-left: 46px; color: var(--text-2); }
.pack-tree li.s::before { content: "└"; left: 24px; }
.pack-tree li.f::before { content: "·"; }
/* Uppercase, like every other label in the app and on this page. The sub-
   labels under a tree row were the one place running lowercase. */
.pack-tree .n { display: block; margin-top: 3px; font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-dim); }
.pack-foot { padding: 12px 18px; border-top: 1px solid var(--border);
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); }
@media (max-width: 560px) { .pack { margin: 34px 16px 0; } .pack-tree li.s { padding-left: 38px; } }

/* Explanatory line under the stems tree. NOT .ex-note — that one is opacity 0
   until JS adds .on, so borrowing it would have shipped an invisible
   paragraph. */
.stems-note {
  max-width: 620px; margin: 18px auto 0; padding-left: 16px;
  border-left: 1px solid rgba(51,204,204,.35);
  color: var(--text-dim); font-size: 14px; line-height: 1.65;
}
@media (max-width: 560px) { .stems-note { margin: 18px 16px 0; } }

/* Route into the full-spec section. */
.spec-link { display: inline-flex; align-items: center; gap: 9px; margin-top: 26px;
  font-family: var(--mono); font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--text-dim); text-decoration: none; border-bottom: 1px solid var(--border);
  padding-bottom: 6px; transition: color .3s var(--ease), border-color .3s var(--ease); }
.spec-link:hover { color: var(--teal); border-bottom-color: rgba(51,204,204,.5); }

/* ---------- Stacked device scenes: pin the phone ----------
   Below 1000px every scene stacks with the callouts under the device. Scrolling
   to the callout that changes the screen therefore pushed the screen off the
   top — you read "here is the file list" with the phone no longer in view. The
   device is sticky now, so it stays put and visibly changes as each callout
   comes up. */
@media (max-width: 1000px) {
  .pr-device-slot, .pf-device-slot, .dc-device-slot, .sx-device-slot {
    position: sticky; top: 74px; z-index: 2; align-self: start;
  }
  /* Room to scroll the callouts under the pinned device. */
  .pr-callouts, .pf-callouts, .dc-callouts, .sx-callouts { padding-top: 12px; }
  .pr-callout, .pf-callout, .dc-callout, .sx-callout { margin-bottom: 40px; }
  .pr-stage, .pf-stage, .dc-stage, .sx-stage { align-items: start; }
}

/* Who it's for — one line, under the hero, before the argument starts. */
/* Sits between the marquee strip and the signature callout. The 96px top
   mirrors the margin .signature already carries below it, so the line is
   spaced off the marquee's border rather than hanging from it. */
.audience { max-width: 720px; margin: 96px auto 0; padding: 0 24px; text-align: center;
  font-size: 16px; line-height: 1.65; color: var(--text-2); }
@media (max-width: 760px) { .audience { font-size: 15px; margin-top: 56px; } }

/* FAQ — square, two columns, no accordion. Nothing here should need a click
   to read: every one of these is a purchase blocker. */
.faq { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 26px 40px; max-width: 900px; margin: 0 auto; }
.faq .q { border-top: 1px solid var(--border); padding-top: 16px; }
.faq h3 { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 8px; color: var(--text); }
.faq p { color: var(--text-2); font-size: 14.5px; line-height: 1.68; }
.faq a { color: var(--teal); text-decoration: none; border-bottom: 1px solid rgba(51,204,204,.35); }
@media (max-width: 760px) { .faq { grid-template-columns: 1fr; gap: 20px; } }

/* Price anchor + value stack + risk reversal, at the decision point. */
.price-anchor { max-width: 560px; margin: 16px auto 0; font-size: 14px; line-height: 1.6; color: var(--text-2); }
.value-stack { list-style: none; max-width: 560px; margin: 30px auto 0; text-align: left; }
.value-stack li { position: relative; padding: 11px 0 11px 26px; border-top: 1px solid var(--border);
  color: var(--text-2); font-size: 14.5px; line-height: 1.6; }
.value-stack li::before { content: ""; position: absolute; left: 0; top: 18px; width: 8px; height: 8px;
  background: var(--teal); }
.value-stack b { color: var(--text); font-weight: 600; }
.value-stack code { font-family: var(--mono); font-size: 1em; color: var(--lavender); }
.risk-reversal { max-width: 560px; margin: 20px auto 0; font-family: var(--mono); font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); line-height: 1.7; }

/* Audio proof. preload="none" — it costs nothing until someone presses play. */
.player { max-width: 640px; margin: 0 auto; border: 1px solid var(--border);
  background: rgba(255,255,255,.014); padding: 26px 28px; }
.pl-meta { display: flex; flex-direction: column; gap: 4px; margin-bottom: 22px; }
.pl-artist { font-family: var(--mono); font-size: 11px; letter-spacing: .24em; text-transform: uppercase; color: var(--teal); }
.pl-title { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; color: var(--text); }
.pl-note { font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; color: var(--text-dim); }
.pl-note em { font-style: normal; color: var(--text-2); }
.pl-transport { display: flex; align-items: center; gap: 16px; }
.pl-play { display: inline-flex; align-items: center; gap: 9px; height: 44px; padding: 0 20px; flex: none;
  cursor: pointer; background: transparent; border: 1px solid rgba(51,204,204,.55); border-radius: 0;
  color: var(--teal); font-family: var(--mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  transition: background .25s var(--ease), border-color .25s var(--ease); }
.pl-play:hover { background: rgba(51,204,204,.08); border-color: var(--teal); }
.pl-play svg { width: 13px; height: 13px; }
.pl-play i { font-style: normal; }
.pl-bar { position: relative; flex: 1; height: 3px; background: rgba(255,255,255,.08); cursor: pointer; }
.pl-bar i { position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  background: linear-gradient(90deg, var(--teal), var(--indigo)); }
.pl-time { font-family: var(--mono); font-size: 11px; color: var(--text-dim); width: 38px; text-align: right; }
.pl-credits { list-style: none; margin: 24px 0 0; display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 14px; }
.pl-credits li { border-top: 1px solid var(--border); padding-top: 11px;
  font-size: 13px; line-height: 1.55; color: var(--text-2); }
.pl-credits .k { display: block; margin-bottom: 4px; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: .2em; text-transform: uppercase; color: var(--text-dim); }
@media (max-width: 620px) {
  .player { padding: 20px 18px; margin: 0 16px; }
  .pl-credits { grid-template-columns: 1fr; gap: 10px; }
  .pl-transport { flex-wrap: wrap; }
  .pl-bar { order: 3; width: 100%; flex: 1 0 100%; }
}

/* Deliberately understated — this verifies the record, it does not compete
   with the CTA a screen below it. */
.pl-verify { display: inline-block; margin-top: 18px; font-family: var(--mono); font-size: 10.5px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); text-decoration: none;
  border-bottom: 1px solid transparent; padding-bottom: 3px; transition: color .25s var(--ease), border-color .25s var(--ease); }
.pl-verify em { font-style: normal; color: var(--text-2); }
.pl-verify:hover { color: var(--teal); border-bottom-color: rgba(51,204,204,.4); }
.pl-verify:hover em { color: var(--teal); }

/* ============================================================================
   SYNTH — Drum Synth browser. Values from DrumSynthBrowserView: header rules
   at #141418, editor header 44pt on #0A0A0C, 36pt rows, 4-column knob grid.
   ========================================================================== */
.sy-stage { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; gap: 48px; padding: 64px 0 8px; }
.sy-callouts { max-width: 380px; justify-self: end; }
.sy-callout { margin-bottom: 26px; }
.sy-callout:last-child { margin-bottom: 0; }
/* Base position for the slot — the device inside is absolutely positioned
   against it. This MUST stay above the stacked media query. It used to sit
   below, and at equal specificity the later rule won at every width, so the
   sticky below was dead: measured on a 375px handset the synth phone scrolled
   232px off the top of the screen while its last callout was still being read.
   Every other section pinned correctly; only this one was overridden. */
.sy-device-slot { position: relative; }
.sy-device-slot .dk-device { position: absolute; top: 0; left: 0; transform: scale(var(--scale,1)); transform-origin: top left; }
@media (max-width: 1000px) {
  .sy-stage { grid-template-columns: 1fr; justify-items: center; gap: 8px; align-items: start; }
  .sy-callouts { max-width: 620px; justify-self: center; order: 2; padding-top: 12px; }
  .sy-callout { margin-bottom: 40px; }
  .sy-device-slot { position: sticky; top: 74px; z-index: 2; align-self: start; }
}
.sy-screen { background: #0C0C0E; }
.sy-body { display: flex; flex-direction: column; }

.sy-head { display: flex; align-items: center; gap: 8px; padding: 0 10px 8px;
  background: #0C0C0E; border-bottom: 1px solid #141418; }
.sy-btn { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 12px;
  font-family: "Nightshape", var(--sans); font-size: 10px; letter-spacing: 1.4px; }
.sy-btn svg { width: 12px; height: 12px; }
.sy-btn.sec { color: #888899; box-shadow: inset 0 0 0 1px #24242C; }
.sy-btn.pri { color: var(--dk-teal); box-shadow: inset 0 0 0 1px rgba(51,204,204,.55); }
.sy-btn.sm { height: 26px; padding: 0 10px; font-size: 9px; margin-left: auto; }

.sy-main { flex: 1; display: flex; min-height: 0; }
/* The drawer is off-canvas until PRESETS is tapped, as in the app. */
.sy-side { width: 220px; flex: none; margin-left: -220px; border-right: 1px solid #141418;
  transition: margin-left .42s var(--ease); overflow: hidden; }
.sy-side.open { margin-left: 0; }
.sy-side-t { height: 44px; display: flex; align-items: center; padding: 0 10px;
  font-family: "Nightshape", var(--sans); font-size: 10px; letter-spacing: 1.6px; color: #888899;
  border-bottom: 1px solid #141418; }
.sy-cat-row, .sy-preset-row { display: flex; align-items: center; gap: 8px; height: 36px; padding-right: 8px; }
.sy-cat-row i, .sy-preset-row i { width: 2px; height: 100%; flex: none; background: transparent; }
.sy-cat-row span { font-family: var(--mono); font-weight: 500; font-size: 10px; letter-spacing: 1.2px; color: #3A3A48; }
.sy-cat-row b { margin-left: auto; font-family: var(--mono); font-weight: 500; font-size: 10px; color: #3A3A48; }
.sy-cat-row.on { background: #111115; }
.sy-cat-row.on i { background: var(--acc); }
.sy-cat-row.on span, .sy-cat-row.on b { color: var(--acc); }
.sy-presets { border-top: 1px solid #141418; }
.sy-preset-row span { font-family: var(--mono); font-weight: 500; font-size: 11px; letter-spacing: .5px; color: #888899; white-space: nowrap; }
.sy-preset-row.on { background: #13131A; }
.sy-preset-row.on i { background: var(--acc); }
.sy-preset-row.on span { color: #EEEEFF; }

.sy-editor { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.sy-ehead { display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 10px;
  background: #0A0A0C; border-bottom: 1px solid #141418; }
.sy-cat { display: flex; flex-direction: column; gap: 2px; }
.sy-cat b { font-family: var(--mono); font-weight: 600; font-size: 11px; letter-spacing: 1.6px; color: var(--acc); }
.sy-cat i { font-family: var(--mono); font-weight: 500; font-style: normal; font-size: 7px; letter-spacing: 1.4px; color: #3A3A48; }
.sy-read { font-family: var(--mono); font-size: 10px; letter-spacing: 1px; color: #888899; margin-left: 10px; white-space: nowrap; }
.sy-icon { width: 26px; height: 26px; display: grid; place-items: center; flex: none;
  font-family: var(--mono); font-size: 12px; color: #888899; box-shadow: inset 0 0 0 1px #24242C; }
.sy-icon.sm { width: auto; padding: 0 8px; font-size: 8.5px; letter-spacing: 1px; }
.sy-erow { display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 10px;
  border-bottom: 1px solid #141418; font-family: var(--mono); font-size: 8.5px; letter-spacing: 1.2px; color: #555566; }
.sy-envwrap { margin: 12px 10px 0; }
.sy-envwrap .sy-sec-t { margin: 0 0 8px; }
.sy-envwrap .sy-sec-t em { background: var(--acc); opacity: .5; }
/* The trace sits on its own panel, not on the editor ground. */
.sy-env { height: 64px; background: #080809; border-radius: 2px; overflow: hidden; }
.sy-env canvas { width: 100%; height: 64px; display: block; }

.sy-params { padding: 10px 10px 12px; overflow: hidden; }
.sy-sec-t { display: flex; align-items: center; gap: 8px; margin: 10px 0 8px; }
.sy-sec-t em { width: 16px; height: 1px; background: var(--acc); display: block; }
.sy-sec-t span { font-family: var(--mono); font-weight: 500; font-size: 9px; letter-spacing: 1.4px; color: #2A2A35; }
.sy-grid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 12px; }
.sy-knob { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.sy-knob svg { width: 40px; height: 40px; display: block; }
.sy-knob .v { font-family: var(--mono); font-weight: 500; font-size: 9px; color: #555566; }
.sy-knob .l { font-family: var(--mono); font-weight: 500; font-size: 8px; color: #444455; white-space: nowrap; }


/* Hero pitch lines. The two clearest statements of what DRUMKIT is were buried:
   the audience line sat below the marquee, and "one app, start to finish" was the
   tail clause of the sub paragraph. Both now sit in the hero, in reading order:
   what it does (h1) -> who it is for (.audience) -> how (.sub) -> the claim (.hero-key). */
.hero .audience {
  margin: 0 0 18px;
  padding: 0;
  max-width: 62ch;
  font-size: clamp(14px, 1.8vw, 16px);
  color: var(--text-2);
}
.hero p.sub { margin-bottom: 26px; }
.hero-key {
  margin: 0 0 38px;
  font-size: clamp(18px, 2.6vw, 24px);
  line-height: 1.32;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
}
@media (max-width: 760px) {
  .hero .audience { margin-bottom: 12px; font-size: 14px; line-height: 1.55; }
  .hero p.sub { margin-bottom: 18px; }
  .hero-key { margin-bottom: 24px; font-size: 18px; line-height: 1.28; }
}

/* Short viewports (iPhone SE and similar). The two pitch lines added ~145px to
   the hero, which pushed the App Store badge under the fold on 667px-tall
   screens. Reclaim it from padding and leading rather than by cutting copy. */
@media (max-height: 700px) {
  .hero { padding-top: 72px; padding-bottom: 52px; }
  .hero-logo { margin-bottom: 12px; }
  .hero .audience { margin-bottom: 10px; }
  .hero p.sub { margin-bottom: 14px; }
  .hero-key { margin-bottom: 18px; }
  .hero .trust { margin-top: 40px; }
}
