/* ---------------------------------------------------------------------------
   Music Soundboard — marketing site
   Single hand-written stylesheet. No framework, no build step, no CDN.
   Phone mockups are the app UI drawn in HTML, authored in a 430x932pt space
   (iPhone 15 Pro Max points) and scaled with a single --s variable.
   --------------------------------------------------------------------------- */

/* Archivo, self-hosted so the page makes no third-party requests. Variable
   font: one file per subset covers weights 400-900. */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url(assets/archivo-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url(assets/archivo-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Surfaces */
  --bg: #08080a;
  --surface: #111114;
  --surface-2: #0c0c0f;
  --hairline: rgba(255, 255, 255, .07);

  /* Text */
  --fg: #fff;
  --fg-2: #9b9ba4;
  /* The dimmest text on the site: fineprint, footer, release dates. Sized
     against the *lightest* place it ever sits, which is not --bg: the hero
     fineprint crosses the red glow, and at 430px that background peaks at
     rgb(14,27,43). This clears 4.5:1 there (4.75:1) and reaches 5.48:1 on
     plain --bg. The handoff's #6f6f78 was 4.02:1, and #7c7c86 still measured
     4.20:1 over the glow. Don't darken it. */
  --fg-3: #85858f;
  --fg-list: #c9c9cf;

  /* The app's six sound colours, borrowed as section accents */
  --gray: #79838f;
  --purple: #b18cf5;
  --yellow: #fdc02f;
  --green: #22dd7e;
  --red: #f4536b;
  --blue: #2f8ef4;
  --stop-red: #ff5a5f;

  /* In-app surfaces, for the phone mockups */
  --bezel: #1b1b1f;
  --app-bg: #000;
  --app-card: #1c1c1e;
  --app-chrome: #2c2c2e;
  --app-transport: #1e1e20;
  --app-fg-2: #98989e;

  --sans: 'Archivo', system-ui, -apple-system, sans-serif;
  --ios: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--red); text-decoration: none; transition: color 140ms ease; }
a:hover { color: #ff8496; }

h1, h2, h3, p, ul, dl, dd { margin: 0; }
img, svg { display: block; }

:focus-visible { outline: 2px solid var(--fg); outline-offset: 3px; border-radius: 4px; }

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 20;
  padding: 10px 18px; border-radius: 20px;
  background: var(--fg); color: var(--bg);
  font: 700 15px/1 var(--sans);
  transition: top 140ms ease;
}
.skip-link:focus { top: 12px; color: var(--bg); }

/* --- Shared layout ------------------------------------------------------- */

.wrap { max-width: 1160px; margin: 0 auto; }

.band { border-top: 1px solid var(--hairline); padding: 92px 40px; }
.band--split { padding: 96px 40px; }

.split {
  display: flex; flex-wrap: wrap;
  gap: 72px; align-items: center; justify-content: space-between;
}
.split--reverse { flex-wrap: wrap-reverse; }
.split__copy { flex: 1 1 420px; max-width: 520px; }

.eyebrow {
  font: 800 13px/1 var(--sans);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--red);
}
.eyebrow--blue { color: var(--blue); }
.eyebrow--green { color: var(--green); }
.eyebrow--purple { color: var(--purple); }

h1 {
  margin-top: 22px;
  font: 900 clamp(42px, 8vw, 76px)/1.02 var(--sans);
  letter-spacing: -.03em;
  text-wrap: balance;
}

h2 {
  font: 900 clamp(34px, 5vw, 52px)/1.08 var(--sans);
  letter-spacing: -.028em;
  text-wrap: balance;
}
.band > .wrap > h2 { max-width: 680px; }
.eyebrow + h2 { margin-top: 20px; }

.lede { margin-top: 22px; color: var(--fg-2); font: 400 19px/1.6 var(--sans); }

.ticks { margin-top: 30px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 14px; }
.ticks li { display: flex; gap: 12px; align-items: flex-start; color: var(--fg-list); font: 500 17px/1.5 var(--sans); }
.ticks li::before { content: '—'; color: var(--accent, var(--blue)); }

/* --- Buttons ------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 56px; padding: 0 30px; border-radius: 28px;
  font: 700 17px/1 var(--sans);
  transition: background 140ms ease, color 140ms ease;
}
.btn--primary { background: var(--fg); color: var(--bg); }
.btn--primary:hover { background: #e9e9ec; color: var(--bg); }
.btn--ghost { background: rgba(255, 255, 255, .07); color: var(--fg); font-weight: 600; }
.btn--ghost:hover { background: rgba(255, 255, 255, .12); color: var(--fg); }

/* Apple's badge artwork, shipped unmodified. Apple's guidelines set a 40px
   minimum height and clear space of 10% of the badge height on every side. */
.badge { display: inline-block; transition: opacity 140ms ease; }
.badge img { height: 56px; width: auto; }
.badge:hover { opacity: .85; }
.badge--lg img { height: 58px; }

.buttons { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 38px; }

.fineprint { margin-top: 26px; color: var(--fg-3); font: 500 15px/1.5 var(--sans); }

/* --- Header -------------------------------------------------------------- */

.site-header {
  position: relative; z-index: 5;
  max-width: 1240px; margin: 0 auto; padding: 28px 40px;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 20px;
}
.brand { display: flex; align-items: center; gap: 12px; color: var(--fg); }
.brand:hover { color: var(--fg); }
.brand img { width: 34px; height: 34px; border-radius: 9px; }
.brand span { font: 800 18px/1 var(--sans); letter-spacing: -.01em; white-space: nowrap; }

.nav { display: flex; align-items: center; gap: 32px; }
.nav a { color: var(--fg-2); font: 500 15px/1 var(--sans); }
.nav a:hover { color: var(--fg); }
.nav .nav__cta {
  display: flex; align-items: center; height: 40px; padding: 0 20px;
  border-radius: 20px; background: var(--fg); color: var(--bg);
  font: 700 15px/1 var(--sans);
  transition: background 140ms ease;
}
.nav .nav__cta:hover { background: #e9e9ec; color: var(--bg); }

/* --- Hero ---------------------------------------------------------------- */

.hero { position: relative; overflow: hidden; padding: 60px 40px 110px; }
.hero::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(70% 55% at 62% 12%, rgba(244, 83, 107, .22), rgba(8, 8, 10, 0) 62%),
    radial-gradient(50% 40% at 12% 40%, rgba(47, 142, 244, .14), rgba(8, 8, 10, 0) 70%);
}
.hero .wrap {
  position: relative;
  display: flex; flex-wrap: wrap; gap: 60px;
  align-items: center; justify-content: space-between;
}
.hero__copy { flex: 1 1 480px; max-width: 620px; }
.hero__lede { margin-top: 26px; color: var(--fg-2); font: 400 21px/1.55 var(--sans); max-width: 540px; text-wrap: pretty; }

/* --- Prose pages (privacy policy) ---------------------------------------- */

/* Deliberately not built on .hero — that is a flex row with a 60px gap, which
   would space every paragraph apart. */
.prose { position: relative; overflow: hidden; padding: 60px 40px 110px; }
.prose::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60% 45% at 60% 0%, rgba(244, 83, 107, .16), rgba(8, 8, 10, 0) 65%);
}
.prose .wrap { position: relative; max-width: 720px; }
.prose h1 { font-size: clamp(40px, 6vw, 60px); }
.prose__lede { margin-top: 26px; color: var(--fg-2); font: 400 21px/1.55 var(--sans); text-wrap: pretty; }
.prose__body { margin-top: 56px; }
.prose__body h2 {
  font: 800 24px/1.25 var(--sans);
  letter-spacing: -.01em;
  padding-top: 34px;
  margin-top: 34px;
  border-top: 1px solid var(--hairline);
}
.prose__body h2:first-child { padding-top: 0; margin-top: 0; border-top: 0; }
.prose__body p { margin-top: 14px; color: var(--fg-2); font: 400 17px/1.65 var(--sans); }
/* A link inside a paragraph can't be told apart by colour alone: --red on
   --fg-2 body text is 1.21:1, well under the 3:1 WCAG needs. Underline them. */
.prose p a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(244, 83, 107, .55);
  text-underline-offset: 3px;
}
.prose p a:hover { text-decoration-color: currentColor; }
.prose__body .prose__meta { margin-top: 48px; color: var(--fg-3); font: 500 15px/1.6 var(--sans); }

/* --- What's new (release notes) ------------------------------------------ */

/* The entries are generated from CHANGELOG.md by scripts/build-whats-new.py.
   Wider than the 720px prose measure because each release runs two columns:
   the version stays beside its notes rather than above them. */
.prose .wrap--releases { max-width: 880px; }

.releases { margin-top: 60px; }
.release {
  display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 44px;
  border-top: 1px solid var(--hairline); margin-top: 44px; padding-top: 44px;
}
.release:first-child { border-top: 0; margin-top: 0; padding-top: 0; }

/* The version follows its own notes down the page — with entries this long the
   number would otherwise scroll away from the list it labels. */
.release__head { position: sticky; top: 28px; align-self: start; }
.release__version { font: 900 36px/1 var(--sans); letter-spacing: -.025em; }
.release__version span {
  display: block; margin-bottom: 12px; color: var(--fg-3);
  font: 800 12px/1 var(--sans); letter-spacing: .18em; text-transform: uppercase;
}
.release__date { margin-top: 14px; color: var(--fg-3); font: 500 15px/1.5 var(--sans); }
.release__tag {
  display: inline-flex; align-items: center; height: 26px; margin-top: 14px;
  padding: 0 12px; border-radius: 13px;
  background: rgba(244, 83, 107, .14); color: var(--red);
  font: 800 12px/1 var(--sans); letter-spacing: .06em; text-transform: uppercase;
}

.release__body > * + * { margin-top: 18px; }
.release__body .release__lede { color: var(--fg); font: 700 21px/1.45 var(--sans); text-wrap: pretty; }
.release__body p { color: var(--fg-2); font: 400 17px/1.65 var(--sans); }
/* An editorial note standing in for a version the store published no copy for.
   Dimmer than the notes themselves so it doesn't read as the app's own voice. */
.release__body .release__none { color: var(--fg-3); font-size: 16px; }
.release__body h3 {
  margin-top: 34px; color: var(--fg);
  font: 800 13px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase;
}
.release__body ul { padding: 0; list-style: none; display: flex; flex-direction: column; gap: 13px; }
.release__body li { display: flex; gap: 14px; color: var(--fg-list); font: 400 17px/1.55 var(--sans); }
/* A pad, not a dash: the notes are full of em dashes of their own. */
.release__body li::before {
  content: ''; flex: none; width: 7px; height: 7px; margin-top: 9px;
  border-radius: 2px; background: var(--accent, var(--red));
}

/* .prose__meta is scoped to .prose__body, which this page doesn't use — without
   this the closing note butts straight into the last release. */
.wrap--releases .prose__meta {
  margin-top: 44px; padding-top: 44px; border-top: 1px solid var(--hairline);
  color: var(--fg-3); font: 500 15px/1.6 var(--sans);
}

@media (max-width: 720px) {
  .release { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .release__head { position: static; }
  .release__version { font-size: 30px; }
  .release__date, .release__tag { margin-top: 10px; }
}

/* --- Feature cards ------------------------------------------------------- */

.cards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 20px; margin-top: 48px;
}
.card {
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 20px; padding: 32px;
  transition: border-color 140ms ease;
}
.card:hover { border-color: rgba(255, 255, 255, .14); }
.card__icons { display: flex; gap: 12px; }
.card__icon {
  width: 64px; height: 64px; border-radius: 32px;
  background: rgba(255, 255, 255, .06);
  display: flex; align-items: center; justify-content: center;
  color: var(--fg);
}
.card__icon .stop-glyph { display: block; width: 24px; height: 24px; border-radius: 5px; background: var(--fg); }
.card h3 { margin-top: 24px; font: 800 26px/1.15 var(--sans); }

/* second row of the features band: four narrower cards */
.cards--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: 28px; }
@media (max-width: 1040px) { .cards--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px)  { .cards--4 { grid-template-columns: minmax(0, 1fr); } }
.card--sm { padding: 26px; }
.card--sm .card__icon { width: 54px; height: 54px; border-radius: 27px; }
.card--sm h3 { margin-top: 20px; font-size: 22px; }
.card--sm p { font-size: 16px; }

.subhead {
  margin-top: 84px;
  font: 900 clamp(26px, 3.2vw, 36px)/1.15 var(--sans);
  letter-spacing: -.022em;
  max-width: 620px;
  text-wrap: balance;
}
.card p { margin-top: 12px; color: var(--fg-2); font: 400 17px/1.55 var(--sans); }

/* --- Hairline grid ------------------------------------------------------- */

/* 320px rather than the handoff's 260px: at the 1160px container that lands on
   3 columns, and 6 cells divide evenly into 3 / 2 / 1. A 260px track gives 4
   columns, which leaves two empty holes in what should read as a solid table. */
.hairgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 1px; margin-top: 48px;
  background: var(--hairline);
  border: 1px solid var(--hairline); border-radius: 20px; overflow: hidden;
}
.hairgrid > div { background: var(--surface-2); padding: 30px; }
.hairgrid h3 { font: 700 20px/1.2 var(--sans); }
.hairgrid p { margin-top: 10px; color: var(--fg-2); font: 400 16px/1.55 var(--sans); }

/* --- Who it's for -------------------------------------------------------- */

.who { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: 28px; margin-top: 36px; }
.who h3 { font: 800 30px/1.1 var(--sans); }
.who p { margin-top: 12px; color: var(--fg-2); font: 400 17px/1.55 var(--sans); }

/* --- Section glows ------------------------------------------------------- */

.glow-blue  { background: radial-gradient(60% 50% at 20% 40%, rgba(47, 142, 244, .12), rgba(8, 8, 10, 0) 70%); }
.glow-green { background: radial-gradient(60% 50% at 80% 40%, rgba(34, 221, 126, .12), rgba(8, 8, 10, 0) 70%); }
.glow-red   { background: radial-gradient(60% 70% at 50% 0%,  rgba(244, 83, 107, .18), rgba(8, 8, 10, 0) 65%); }

/* --- Closing CTA + footer ------------------------------------------------ */

.cta { padding: 110px 40px; text-align: center; }
.cta .wrap { max-width: 820px; }
/* overrides the 680px cap on `.band > .wrap > h2`, which has no auto margins
   and so parks a centred headline to the left of its own section */
.cta .wrap > h2 { max-width: 720px; margin-inline: auto; }
.cta h2 { font-size: clamp(38px, 6vw, 62px); line-height: 1.04; letter-spacing: -.03em; }
.cta p { margin: 22px auto 0; max-width: 560px; color: var(--fg-2); font: 400 20px/1.55 var(--sans); }
.cta .buttons { justify-content: center; margin-top: 36px; }

.site-footer { border-top: 1px solid var(--hairline); padding: 38px 40px; }
.site-footer .wrap { display: flex; flex-wrap: wrap; gap: 20px; align-items: center; justify-content: space-between; }
.site-footer p { color: var(--fg-3); font: 500 15px/1 var(--sans); }
.site-footer nav { display: flex; flex-wrap: wrap; gap: 26px; }
.site-footer a { color: var(--fg-2); font: 500 15px/1 var(--sans); }
.site-footer a:hover { color: var(--fg); }

/* ===========================================================================
   Phone mockups — the app UI, drawn in HTML.
   Everything inside .screen is positioned in 430x932pt iPhone points and
   scaled by --s, so the whole device resizes from one number.
   =========================================================================== */

.phone {
  --s: .8372;
  --r: 64px;
  flex: 0 0 auto;
  position: relative;
  width: calc(430px * var(--s) + 12px);
  height: calc(932px * var(--s) + 12px);
  border-radius: var(--r);
  background: var(--bezel);
  box-shadow: 0 50px 110px rgba(0, 0, 0, .7), inset 0 0 0 2px rgba(255, 255, 255, .1);
}
.phone--sm { --s: .7163; --r: 56px; }

.phone__screen {
  position: absolute; top: 6px; left: 6px;
  width: calc(430px * var(--s));
  height: calc(932px * var(--s));
  border-radius: calc(var(--r) - 6px);
  overflow: hidden;
  background: var(--app-bg);
}

.app {
  position: relative;
  width: 430px; height: 932px;
  transform: scale(var(--s));
  transform-origin: top left;
  background: var(--app-bg);
  font-family: var(--ios);
}

/* Status bar */
.app__island { position: absolute; top: 12px; left: 50%; transform: translateX(-50%); width: 123px; height: 34px; border-radius: 17px; background: #000; }
.app__time { position: absolute; top: 18px; left: 58px; font: 600 17px/1 var(--ios); }
.app__status { position: absolute; top: 19px; right: 24px; display: flex; align-items: center; gap: 6px; color: #fff; }

/* Board tabs + header buttons */
/* right, not width-by-content: Import is pinned to the trailing edge exactly as
   it is in the app, and the tab capsule takes whatever is left. */
.app__chrome { position: absolute; top: 72px; left: 17px; right: 17px; display: flex; align-items: center; gap: 15px; }
/* The strip scrolls in the app rather than squeezing its tabs, so the last one
   clips at the capsule edge instead of wrapping. */
.tabs { display: flex; align-items: center; flex: 1; min-width: 0; height: 37px; padding: 2px; border-radius: 19px; background: var(--app-chrome); overflow: hidden; }
.tab { flex: none; display: flex; align-items: center; justify-content: center; padding: 0 13px; white-space: nowrap; color: var(--app-fg-2); font: 500 15px/1 var(--ios); }
.tab.is-on { height: 33px; border-radius: 17px; padding: 0 8px 0 13px; background: var(--tab, var(--red)); color: #fff; font-weight: 600; }
.circle-btn { width: 37px; height: 37px; border-radius: 19px; background: var(--app-chrome); display: flex; align-items: center; justify-content: center; }
/* Import is the accent-filled primary in the app now — it is the only action a
   user with an empty board can usefully take — so the mockup wears it too. */
.pill-btn { display: flex; align-items: center; gap: 6px; height: 37px; padding: 0 15px; border-radius: 19px; background: var(--green); color: #06130c; font: 600 15px/1 var(--ios); white-space: nowrap; }
.pill-btn svg { color: #06130c; }
/* The ⋯ inside the active tab: in the app it opens the board menu on tap, not
   only on long press. Three dots painted with a gradient, so it needs no sprite. */
.tab__more { width: 13px; height: 3px; margin-left: 6px; flex: none; background:
  radial-gradient(circle at 1.5px 50%, #fff 1.4px, transparent 1.5px) 0 0/5px 3px repeat-x; opacity: .8; }

/* Pad grid */
.pads { position: absolute; top: 123px; left: 17px; right: 17px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 21px 18px; }

/* Pad fill is the pad colour multiplied to 42% over black, matching the app's
   .opacity(playersPower) on the tile background. Precomputed, not color-mix,
   so it renders identically everywhere. */
.pad { position: relative; height: 188px; border-radius: 24px; background: var(--pad-fill); box-shadow: inset 0 0 0 .5px rgba(255, 255, 255, .08); }
.pad--gray   { --pad: #79838f; --pad-fill: #33373c; --pad-glow: rgb(67, 72, 79); }
.pad--purple { --pad: #b18cf5; --pad-fill: #4a3b67; --pad-glow: rgb(97, 77, 135); }
.pad--yellow { --pad: #fdc02f; --pad-fill: #6a5114; --pad-glow: rgb(139, 106, 26); }
.pad--green  { --pad: #22dd7e; --pad-fill: #0e5d35; --pad-glow: rgb(19, 122, 69); }
.pad--red    { --pad: #f4536b; --pad-fill: #66232d; --pad-glow: rgb(134, 46, 59); }
.pad--blue   { --pad: #2f8ef4; --pad-fill: #143c66; --pad-glow: rgb(26, 78, 134); }

.pad.is-playing { box-shadow: 0 0 34px var(--pad-glow); }
.pad.is-playing::after {
  content: ''; position: absolute; inset: 0;
  border-radius: 24px; border: 2.5px solid var(--pad);
}

.pad__badges { position: absolute; top: 11px; left: 11px; display: flex; gap: 8px; }
.pad__badge { width: 29px; height: 29px; border-radius: 15px; background: rgba(0, 0, 0, .3); display: flex; align-items: center; justify-content: center; }
.pad__stop { position: absolute; top: 11px; right: 11px; z-index: 1; width: 33px; height: 33px; border-radius: 17px; background: rgba(0, 0, 0, .32); display: flex; align-items: center; justify-content: center; }
.pad__stop i { width: 13px; height: 13px; border-radius: 3px; background: #fff; }
.pad__label { position: absolute; left: 12px; right: 12px; top: 80px; text-align: center; font: 700 22px/1.2 var(--ios); }
/* .72, not the .6 this started at: at .6 the duration reads 3.85:1 on the
   yellow pad and 3.96:1 on the green, under the 4.5:1 AA floor. .72 clears
   every pad colour (yellow, the worst, lands at 4.78:1). */
.pad__dur { position: absolute; right: 14px; bottom: 12px; color: rgba(255, 255, 255, .72); font: 500 15px/1 var(--ios); }
.pad.is-playing .pad__dur { bottom: 22px; }
.pad__progress { position: absolute; left: 12px; right: 12px; bottom: 10px; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, .12); overflow: hidden; }
.pad__progress i { display: block; height: 100%; border-radius: 2px; background: var(--pad); }

/* Transport card */
.transport {
  position: absolute; left: 13px; right: 13px; bottom: 24px;
  height: 109px; padding: 0 18px; border-radius: 28px;
  background: var(--app-transport);
  display: flex; align-items: center; gap: 12px;
}
/* The idle transport label and its stop square, lifted from #7a7a80/#5a5a5e:
   the label measured 3.54:1 on the pill. Still clearly quieter than the armed
   (#ff8a8e) and live (#e4e4e8) states, so the three still read apart. */
.pill { width: 76px; height: 52px; border-radius: 26px; background: #262628; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08); display: flex; align-items: center; justify-content: center; gap: 6px; font: 700 13px/1 var(--ios); letter-spacing: .8px; color: #909097; }
.pill--stop i { width: 14px; height: 14px; border-radius: 3px; background: #6b6b70; }
.pill.is-armed { background: #2a1a1c; box-shadow: inset 0 0 0 1px rgba(255, 90, 95, .55); color: #ff8a8e; }
.pill.is-armed i { background: var(--stop-red); }
.pill--fade.is-live { color: #e4e4e8; }

.fader { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.fader__row { display: flex; align-items: center; gap: 8px; width: 100%; }
.fader__track { flex: 1; position: relative; height: 6px; border-radius: 3px; background: rgba(255, 255, 255, .22); }
.fader__fill { position: absolute; inset: 0 auto 0 0; width: 74%; border-radius: 3px; background: #fff; }
.fader__knob { position: absolute; left: 74%; top: 50%; transform: translate(-50%, -50%); width: 26px; height: 26px; border-radius: 13px; background: #fff; }
/* #888a92, up from #6b6f7b — 11px at 3.32:1 was the worst contrast on the page. */
.fader__label { width: 100%; padding-left: 20px; color: #888a92; font: 500 11px/1 var(--ios); }
.airplay { --icon-knockout: #262628; width: 40px; height: 40px; border-radius: 20px; background: #262628; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08); display: flex; align-items: center; justify-content: center; }

.home-bar { position: absolute; left: 50%; transform: translateX(-50%); bottom: 9px; width: 145px; height: 5px; border-radius: 3px; background: rgba(255, 255, 255, .9); }

/* Track Settings sheet */
.sheet { position: absolute; top: 59px; left: 0; right: 0; bottom: 0; background: #0a0a0c; border-radius: 14px 14px 0 0; }
.sheet__grabber { position: absolute; top: 9px; left: 50%; transform: translateX(-50%); width: 40px; height: 5px; border-radius: 3px; background: #4a4a50; }
.sheet__title { position: relative; height: 70px; display: flex; align-items: center; justify-content: center; font: 700 22px/1 var(--ios); }
.sheet__done { position: absolute; right: 14px; top: 20px; width: 75px; height: 36px; border-radius: 18px; background: var(--app-chrome); display: flex; align-items: center; justify-content: center; font: 700 19px/1 var(--ios); }
.sheet__rule { height: 1px; margin: 0 14px; background: rgba(255, 255, 255, .1); }
.sheet__card { margin: 16px 14px 0; padding: 16px; border-radius: 16px; background: var(--app-card); }
.sheet__card--swatches { margin-top: 14px; padding: 14px 16px; display: flex; align-items: center; justify-content: space-between; }
.sheet__label { color: #9a9aa0; font: 600 13px/1 var(--ios); letter-spacing: .09em; }

.swatch { width: 44px; height: 44px; border-radius: 22px; display: flex; align-items: center; justify-content: center; }
.swatch.is-on { box-shadow: 0 0 0 3px #fff; }

.wave { position: relative; height: 140px; margin-top: 14px; border-radius: 6px; background: #151517; overflow: hidden; }
/* direct child only — the handle icons are svgs inside .wave too */
.wave > svg { position: absolute; inset: 0; width: 100%; height: 140px; }
.wave__region { position: absolute; top: 0; bottom: 0; left: 22%; right: 52%; background: rgba(255, 255, 255, .5); }
.wave__edge { position: absolute; top: 0; bottom: 0; width: 5px; }
.wave__handle { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 40px; height: 40px; border-radius: 20px; display: flex; align-items: center; justify-content: center; }
.wave__edge--start, .wave__handle--start { background: var(--green); }
.wave__edge--end, .wave__handle--end { background: var(--stop-red); }

.trim-row { display: flex; justify-content: space-between; align-items: baseline; margin-top: 16px; font: 500 20px/1 var(--ios); }
.trim-row + .trim-row { margin-top: 14px; }
.trim-row dt { font-weight: 700; }
.trim-row dd { margin: 0; }

.preview-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  height: 56px; margin-top: 16px; border-radius: 28px;
  background: rgba(255, 255, 255, .08);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08);
  color: #f2f2f4; font: 600 19px/1 var(--ios);
}

.vol-row { display: flex; align-items: center; gap: 12px; margin-top: 16px; }
.vol-row dt { font: 700 20px/1 var(--ios); }
.vol-row dd { margin: 0; }
/* Two <dd>s to one <dt>: the track and its readout. They were a <dd> and a
   loose <span>, and a <span> is not something a <dl> may directly contain. */
.vol-row .vol-track { flex: 1; position: relative; height: 6px; border-radius: 3px; background: rgba(255, 255, 255, .22); }
.vol-row .vol-track i { position: absolute; inset: 0; border-radius: 3px; background: #fff; }
.vol-row .vol-track b { position: absolute; right: 0; top: 50%; transform: translate(50%, -50%); width: 30px; height: 30px; border-radius: 15px; background: #fff; }
.vol-row .pct { font: 500 20px/1 var(--ios); margin-left: 18px; }
.card-rule { height: 1px; margin: 16px 0 0; background: rgba(255, 255, 255, .1); }

.trim-clear { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; margin-left: 10px; border-radius: 13px; background: var(--app-chrome); vertical-align: middle; }

.toggles { display: flex; align-items: center; justify-content: space-between; margin-top: 16px; }
.toggles__item { display: flex; align-items: center; gap: 10px; font: 700 20px/1 var(--ios); }
.switch { width: 59px; height: 34px; border-radius: 17px; background: #38383c; position: relative; }
.switch i { position: absolute; top: 2px; left: 2px; width: 30px; height: 30px; border-radius: 15px; background: #fff; }
.switch.is-on { background: var(--green); }
.switch.is-on i { left: auto; right: 2px; }

.segmented { display: flex; align-items: center; height: 44px; padding: 3px; margin-top: 14px; border-radius: 22px; background: var(--app-chrome); }
.segmented span { flex: 1; display: flex; align-items: center; justify-content: center; color: #e8e8ec; font: 500 19px/1 var(--ios); }
.segmented span.is-on { height: 38px; border-radius: 19px; background: #4a4a50; color: #fff; font-weight: 600; }

/* The finger that fires a cue: a fingertip ring that presses onto the pad and
   a ripple that spreads from the contact point. Sits in the app's 430x932pt
   space, so it scales with the phone. Both parts start invisible, which is
   also how they stay if motion is not welcome. */
.tapper { position: absolute; width: 116px; height: 116px; margin: -58px 0 0 -58px; pointer-events: none; }
.tapper--a { left: 111.5px; top: 217px; }
.tapper--b { left: 318.5px; top: 217px; }
.tapper i { position: absolute; border-radius: 50%; opacity: 0; }
.tapper__tip {
  inset: 30px;
  background: rgba(255, 255, 255, .16);
  box-shadow: inset 0 0 0 3.5px rgba(255, 255, 255, .92), 0 0 26px rgba(255, 255, 255, .4);
}
.tapper__ripple { inset: 0; box-shadow: 0 0 0 3px rgba(255, 255, 255, .5); }

/* Notes thrown out of the phone. .fx overlays the screen exactly but does not
   clip, so a note can carry on past the bezel. Travel and size are authored in
   app points and scaled by --s, so the arcs shrink with the phone. */
.fx {
  position: absolute; left: 6px; top: 6px;
  width: calc(430px * var(--s)); height: calc(932px * var(--s));
  pointer-events: none;
}
.note {
  position: absolute;
  width: calc(var(--sz) * var(--s)); height: calc(var(--sz) * var(--s));
  margin: calc(var(--sz) * var(--s) * -.5) 0 0 calc(var(--sz) * var(--s) * -.5);
  opacity: 0;
}
/* The two pad centres, a little above the middle so a note clears the label,
   with --ox/--oy scattering the birth points across the pad */
.note--a { left: calc((111.5px + var(--ox, 0px)) * var(--s)); top: calc((178px + var(--oy, 0px)) * var(--s)); }
.note--b { left: calc((318.5px + var(--ox, 0px)) * var(--s)); top: calc((178px + var(--oy, 0px)) * var(--s)); }
/* Lifted from the pad colours: the pad fills are dark, notes have to carry
   over the page background */
.note--a svg { color: #ff8090; }
.note--b svg { color: #74b6ff; }
.note svg { width: 100%; height: 100%; filter: drop-shadow(0 0 12px currentColor); }

/* Air Horn is idle in the still, so its bar only exists while its cue runs */
.pad--fires .pad__progress { opacity: 0; }

/* The transport's now-playing waveform, in the gap between the pad grid and
   the transport card. One waveform drawn twice — dim for the whole track,
   bright and clipped to what has played — with the play head at the seam. */
.wavebar {
  position: absolute; left: 13px; top: 738px; width: 404px; height: 48px;
  border-radius: 16px; background: var(--app-transport);
  transform-origin: center bottom;
  overflow: hidden;
}
.wavebar__wave { position: absolute; left: 0; top: 0; width: 404px; height: 48px; color: rgba(255, 255, 255, .22); }
.wavebar__played { position: absolute; left: 0; top: 0; width: 38%; height: 48px; overflow: hidden; }
.wavebar__played .wavebar__wave { color: var(--red); }
.wavebar__head {
  position: absolute; top: 5px; bottom: 5px; left: 38%; width: 2px; margin-left: -1px;
  border-radius: 1px; background: #fff; box-shadow: 0 0 10px rgba(255, 255, 255, .75);
}

/* --- Hero mockup animation ----------------------------------------------- */
/* One shared 9s timeline, phrased so the whole loop reads as a cue being
   fired: a finger presses the pad, the pad and the phone thump on the hit,
   notes fly up off the glass, and the sound runs its progress bar. Applause is
   tapped at 0.72s and Air Horn layers a stab over it at 3.96s — both use the
   same keyframes, offset with animation-delay, so each phrase is written once.
   Only the hero phone moves, and only when motion is welcome. */
@media (prefers-reduced-motion: no-preference) {
  .hero .phone { animation: phone-thump 9s ease-out infinite; }

  /* Every animation here is delayed to its own hit, and every one fills
     backwards: through that first delay the element holds the 0% frame — cue
     off — which is exactly where the loop leaves it. Without that, the first
     0.72s would show the static playing state and then snap. */

  /* Applause — tapped at 0.72s, holds for most of the loop */
  .hero .pad.is-playing {
    animation: pad-hit 9s .72s ease-out infinite backwards,
               pad-glow 9s .72s ease-in-out infinite backwards;
  }
  .hero .pad.is-playing::after           { opacity: 0; animation: cue-fade 9s .72s ease-out infinite backwards; }
  .hero .pad.is-playing .pad__progress   { opacity: 0; animation: cue-fade 9s .72s ease-out infinite backwards; }
  .hero .pad.is-playing .pad__progress i { animation: pad-progress 9s .72s linear infinite backwards; }

  /* Applause's waveform, scrubbing in step with its pad bar */
  .hero .wavebar         { opacity: 0; animation: wave-pop 9s .72s cubic-bezier(.2, 1.4, .4, 1) infinite backwards; }
  .hero .wavebar__played { animation: wave-scrub 9s .72s linear infinite backwards; }
  .hero .wavebar__head   { animation: wave-head 9s .72s linear infinite backwards; }

  /* Air Horn — tapped at 3.96s, a two-second stab over the top */
  .hero .pad--fires {
    animation: pad-hit 9s 3.96s ease-out infinite backwards,
               horn-glow 9s 3.96s ease-in-out infinite backwards;
  }
  .hero .pad--fires::after {
    content: ''; position: absolute; inset: 0;
    border-radius: 24px; border: 2.5px solid var(--pad);
    opacity: 0; animation: horn-cue 9s 3.96s ease-out infinite backwards;
  }
  .hero .pad--fires .pad__progress   { animation: horn-cue 9s 3.96s ease-out infinite backwards; }
  .hero .pad--fires .pad__progress i { animation: horn-progress 9s 3.96s linear infinite backwards; }
  /* the bar takes the space the duration label sits in, as it does on a
     playing pad — the app's own `.pad.is-playing .pad__dur` shift */
  .hero .pad--fires .pad__dur        { animation: horn-dur 9s 3.96s ease-out infinite backwards; }

  /* The finger starts its approach 0.45s before the hit it lands */
  .tapper--a { --tap-d: .27s; }
  .tapper--b { --tap-d: 3.51s; }
  .hero .tapper__tip    { animation: tap-tip 9s var(--tap-d) cubic-bezier(.3, .9, .3, 1) infinite backwards; }
  .hero .tapper__ripple { animation: tap-ripple 9s var(--tap-d) ease-out infinite backwards; }

  /* Rise eases out and drift eases in, so the pair traces an arc */
  .hero .note     { animation: note-rise 9s var(--d) cubic-bezier(.2, .62, .4, 1) infinite backwards; }
  .hero .note svg { animation: note-drift 9s var(--d) cubic-bezier(.3, .35, .5, 1) infinite backwards; }
}

/* Each bar runs its pad's real length: 00:06 is 6s, 66.7% of the loop, and
   00:02 is 2s, 22.2%. The cue's ring, glow and bar then go out together. */
@keyframes pad-progress {
  0%          { width: 0; }
  66.7%, 100% { width: 100%; }
}
/* Flash on the hit, settle, breathe, then go out with the cue */
@keyframes pad-glow {
  0%        { box-shadow: 0 0 0 var(--pad-glow); }
  2%        { box-shadow: 0 0 52px var(--pad-glow); }
  14%       { box-shadow: 0 0 26px var(--pad-glow); }
  40%       { box-shadow: 0 0 42px var(--pad-glow); }
  67%       { box-shadow: 0 0 26px var(--pad-glow); }
  74%, 100% { box-shadow: 0 0 0 var(--pad-glow); }
}
/* Shared by the playing ring and the progress bar, which arrive and leave together */
@keyframes cue-fade {
  0%        { opacity: 0; }
  2%, 67%   { opacity: 1; }
  74%, 100% { opacity: 0; }
}
@keyframes horn-progress {
  0%          { width: 0; }
  22.2%, 100% { width: 100%; }
}
@keyframes horn-glow {
  0%        { box-shadow: 0 0 0 var(--pad-glow); }
  2%        { box-shadow: 0 0 48px var(--pad-glow); }
  12%, 23%  { box-shadow: 0 0 28px var(--pad-glow); }
  29%, 100% { box-shadow: 0 0 0 var(--pad-glow); }
}
@keyframes horn-cue {
  0%        { opacity: 0; }
  2%, 23%   { opacity: 1; }
  29%, 100% { opacity: 0; }
}
@keyframes horn-dur {
  0%        { transform: translateY(0); }
  2%, 23%   { transform: translateY(-10px); }
  29%, 100% { transform: translateY(0); }
}

/* The waveform pops up on the hit and the head scrubs it over the same 6s */
@keyframes wave-pop {
  0%        { opacity: 0; transform: translateY(8px) scaleY(.5); }
  4%, 67%   { opacity: 1; transform: translateY(0) scaleY(1); }
  74%, 100% { opacity: 0; transform: translateY(8px) scaleY(.5); }
}
@keyframes wave-scrub {
  0%          { width: 0; }
  66.7%, 100% { width: 100%; }
}
@keyframes wave-head {
  0%          { left: 0; }
  66.7%, 100% { left: 100%; }
}

/* The bass hit: the pad kicks and wobbles itself still over about 0.6s */
@keyframes pad-hit {
  0%       { transform: scale(1); }
  1.4%     { transform: scale(1.055) rotate(-.7deg); }
  3%       { transform: scale(.982) rotate(.55deg); }
  4.4%     { transform: scale(1.022) rotate(-.32deg); }
  5.6%     { transform: scale(.995) rotate(.14deg); }
  7%, 100% { transform: scale(1); }
}
/* ...and the whole phone takes the knock. Both hits are in one set of
   keyframes: two delayed copies of one animation would fight over transform. */
@keyframes phone-thump {
  0%, 7%      { transform: translate3d(0, 0, 0); }
  8.2%        { transform: translate3d(0, 3px, 0); }
  9.6%        { transform: translate3d(0, -2px, 0); }
  11%         { transform: translate3d(0, 1px, 0); }
  12.4%, 43%  { transform: translate3d(0, 0, 0); }
  44.2%       { transform: translate3d(0, 2.5px, 0); }
  45.6%       { transform: translate3d(0, -1.6px, 0); }
  47%         { transform: translate3d(0, .8px, 0); }
  48.4%, 100% { transform: translate3d(0, 0, 0); }
}

/* Contact is at 5% — 0.45s in, which is where each --tap-d puts the hit */
@keyframes tap-tip {
  0%        { opacity: 0; transform: scale(1.8); }
  1.6%      { opacity: 1; }
  5%        { opacity: 1; transform: scale(.86); }
  6.6%      { transform: scale(1); }
  11%       { opacity: 1; }
  14%, 100% { opacity: 0; transform: scale(1); }
}
@keyframes tap-ripple {
  0%, 5%    { opacity: 0; transform: scale(.34); }
  5.2%      { opacity: .85; }
  16%, 100% { opacity: 0; transform: scale(1.5); }
}

/* A note is alive for the first 28% of the loop after its delay — 2.52s */
@keyframes note-rise {
  0%        { opacity: 0; transform: translateY(0); }
  2%        { opacity: 1; }
  18%       { opacity: .95; }
  28%, 100% { opacity: 0; transform: translateY(calc(var(--y) * var(--s))); }
}
@keyframes note-drift {
  0%        { transform: translateX(0) rotate(0deg) scale(.3); }
  3.5%      { transform: translateX(calc(var(--x) * var(--s) * .08)) rotate(calc(var(--rot) * .12)) scale(1.1); }
  28%, 100% { transform: translateX(calc(var(--x) * var(--s))) rotate(var(--rot)) scale(1); }
}

/* --- Responsive ---------------------------------------------------------- */

/* Once a row wraps, space-between leaves the lone phone hard against the left
   edge with all the slack on its right. Centre the lines instead. */
@media (max-width: 980px) {
  .hero .wrap, .split { justify-content: center; }
  .phone { margin-inline: auto; }
}

@media (max-width: 900px) {
  .band, .band--split, .hero, .cta { padding-left: 24px; padding-right: 24px; }
  .site-header, .site-footer { padding-left: 24px; padding-right: 24px; }
  /* Four links plus the Download pill: tightened so the header stays on one
     line further down. Below ~740px it wraps the nav under the brand, which is
     what it has always done once the row runs out of room. */
  .nav { gap: 24px; }
  .split { gap: 56px; }
  /* .split--reverse keeps wrap-reverse deliberately: once the row wraps, the
     second line (the copy) is placed above the first (the phone). */
}

@media (max-width: 560px) {
  .band, .band--split { padding-top: 72px; padding-bottom: 72px; }
  .hero { padding-bottom: 80px; }
  .cta { padding-top: 88px; padding-bottom: 88px; }
  .site-header { padding-top: 20px; }
  .nav { gap: 20px; }
  .nav a:not(.nav__cta) { display: none; }
  .brand span { font-size: 16px; }
  .nav .nav__cta { padding: 0 16px; }
  .phone { --s: .66; }
  .phone--sm { --s: .58; }
}

@media (max-width: 380px) {
  .phone { --s: .56; }
  .phone--sm { --s: .52; }
}

@media (prefers-reduced-motion: reduce) {
  /* animation-duration:0 would jump a loop to its final frame; drop them */
  * { transition-duration: 0ms !important; animation: none !important; }
}

@media print {
  body { background: #fff; color: #000; }
  .phone { box-shadow: none; }
}
