/* ============================================================================
   Houseband — marketing site.

   Ported from the Claude Design canvas `Korda Site.dc.html` (archive filename, predates the rename) to a standalone
   page: no design-system runtime, no React, no <x-import>. Every component
   below is a hand-written equivalent of the canvas component of the same name,
   and the values come from the design system rather than from measurement.

   Design tokens live in `tokens.css` and are loaded first. Two rules from the
   system carry most of the weight here, and both are easy to break by accident:

     1. The accent is CONTENT on neutral glass, or a solid fill. It is never a
        tint ON glass — a tint composited through a blurred layer comes out a
        position-dependent khaki.
     2. A surface underneath glass may be flat and faint, but never glass. Two
        blurs stacked render as flat grey, which is why `.k-section` (the flat
        frame) exists alongside `.k-card` (the frosted one).
   ============================================================================ */

/* ---------------------------------------------------------------- page ---- */

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

body {
  font-family: var(--font-system);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* The shared backdrop, per tokens/effects.css: base colour, two corner glows,
   and a vertical band in the base colour that gives text a quiet ground
   exactly where the two glows would otherwise meet. */
.k-backdrop {
  position: relative;
  min-height: 100%;
  background-color: var(--background);
  background-image: var(--backdrop-band), var(--backdrop-glow-teal), var(--backdrop-glow-rust);
  background-attachment: fixed;
}

/* Vertical rhythm scales with the viewport HEIGHT, not just its width. On a
   13" laptop the usable band between the browser chrome and the dock is around
   700px, and fixed 96px section padding spent a quarter of it on air.
   `svh` is the small-viewport height, so this does not jump as mobile browser
   chrome collapses. */
:root {
  --sec-pad-top:    clamp(28px, 6svh, 96px);
  --sec-pad-bottom: clamp(36px, 9svh, 96px);
}
.k-sec { padding-block: var(--sec-pad-top) var(--sec-pad-bottom); }
.k-sec-tight { padding-block: clamp(20px, 4svh, 40px) clamp(28px, 7svh, 88px); }

/* One measure for the whole page — hero, sections, nav and footer all share it.
   The Sounds section used to run 120px wider on its own, to buy width for its
   three-column layout; the overhang read as a misalignment against every
   section above it, which cost more than the width was worth. */
.k-wrap { max-width: 1140px; margin: 0 auto; padding-inline: 24px; }

/* The nav is sticky, so every anchor target needs to clear it or the section
   heading lands underneath the bar. */
section[id], header[id] { scroll-margin-top: 84px; }

/* ------------------------------------------------------------ typography -- */

.k-eyebrow {
  margin: 0 0 12px;
  font-size: var(--chrome-12);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--accent);
}

.k-micro {
  margin: 0;
  font-size: var(--chrome-11);
  font-weight: 600;
  letter-spacing: var(--tracking-fact);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.k-h1 {
  margin: 0 0 20px;
  font-size: clamp(44px, 5.4vw, 70px);
  line-height: 1.02;
  letter-spacing: -1.6px;
  font-weight: 700;
  text-wrap: balance;
}

.k-h2 {
  margin: 0 0 14px;
  font-size: clamp(30px, 3.6vw, 44px);
  line-height: 1.08;
  letter-spacing: -1.1px;
  font-weight: 700;
  text-wrap: balance;
}

.k-lede {
  margin: 0 0 clamp(18px, 3.2svh, 28px);
  max-width: 34em;
  font-size: var(--chrome-17);
  line-height: 1.55;
  color: var(--fg-secondary);
  text-wrap: pretty;
}

.k-note {
  margin: 20px 0 0;
  font-size: var(--text-footnote-size);
  line-height: 1.5;
  color: var(--fg-muted);
}

/* --------------------------------------------------------------- chrome -- */

.k-nav {
  position: sticky;
  top: 0;
  z-index: 40;
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  background: var(--glass-fill);
  box-shadow: inset 0 -1px 0 var(--panel-stroke);
}
.k-nav-inner {
  max-width: 1140px;
  margin: 0 auto;
  padding: 12px 24px;
  display: flex;
  align-items: center;
  gap: 20px;
}
.k-brand {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.7px;
  color: var(--fg-primary);
}
.k-brand:hover { color: var(--fg-primary); }
.k-nav-links {
  display: flex;
  gap: 22px;
  margin-left: auto;
  font-size: var(--chrome-14);
}
.k-nav-links a { color: var(--fg-secondary); }
.k-nav-links a:hover { color: var(--fg-primary); }

/* Tier 1 selection volume: a solid accent fill with a literal-white top-lit
   rim. The rim is never adaptive — it sits on fixed amber, not on the page. */
.k-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-capsule);
  font-family: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: filter var(--dur-quick) var(--ease-out-quick);
}
.k-btn:hover { filter: brightness(1.06); }
.k-btn-primary {
  background: linear-gradient(var(--accent), var(--accent)) padding-box,
              var(--tier1-rim-strong) border-box;
  color: var(--on-accent);
}
.k-btn-primary:hover { color: var(--on-accent); }
.k-btn-glass {
  background: linear-gradient(var(--glass-fill), var(--glass-fill)) padding-box,
              var(--card-edge) border-box;
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  color: var(--fg-primary);
  font-weight: 500;
}
.k-btn-glass:hover { color: var(--fg-primary); }
.k-btn-sm { height: 34px; padding: 0 16px; font-size: var(--chrome-14); }
.k-btn-lg { height: 52px; padding: 0 24px; font-size: var(--chrome-17); box-shadow: var(--shadow-card); }

/* A CTA with nowhere to point yet is inert rather than silently dead. Kept
   close to full strength — dropped far enough to read as "not yet" and no
   further, since a washed-out hero button reads as a rendering fault. */
.k-btn[aria-disabled="true"] { opacity: 0.78; cursor: not-allowed; filter: none; }

/* ------------------------------------------------------------- surfaces -- */

/* §6.1 glassCard. The edge is a top-lit hairline drawn as a border-box
   gradient, so the card has a light direction rather than a flat border. */
.k-card {
  position: relative;
  border: 1px solid transparent;
  border-radius: var(--radius-card);
  background: linear-gradient(var(--glass-fill), var(--glass-fill)) padding-box,
              var(--card-edge) border-box;
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

/* §6.2 pageSection — the FLAT frame you are allowed to put glass on. No blur. */
.k-section-frame {
  position: relative;
  padding: var(--pad-section);
  border: 1px solid transparent;
  border-radius: var(--radius-card);
  background: linear-gradient(var(--panel-fill), var(--panel-fill)) padding-box,
              var(--card-edge) border-box;
}

/* §9.2 PRO badge — an outline, not a fill. */
.k-pro {
  display: inline-block;
  flex: 0 0 auto;
  padding: 2px 6px;
  border-radius: var(--radius-capsule);
  background: var(--pro-badge-fill);
  box-shadow: inset 0 0 0 var(--stroke-pro-badge) var(--pro-badge-stroke);
  font: 700 var(--chrome-9) / 1 var(--font-system);
  letter-spacing: var(--tracking-pro-badge);
  color: var(--accent);
  vertical-align: 2px;
}

/* Base rules for the elements that used to carry these inline. */
.k-pull {
  margin: 0;
  font-size: clamp(24px, 3vw, 38px);
  line-height: 1.25;
  letter-spacing: -0.8px;
  font-weight: 600;
  text-wrap: pretty;
  max-width: 26em;
}
.k-footer-brand {
  margin: 0 0 4px;
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.7px;
}
/* Width is capped by viewport HEIGHT as well as width: a 1290x2796 frame is
   2.17x its own width, so width alone cannot keep it inside a short viewport. */
.k-phone-lg { width: min(clamp(230px, 26vw, 310px), 38svh); }

/* ----------------------------------------------------------- the phone --- */

.k-phone {
  position: relative;
  border-radius: 46px;
  max-width: 100%;
  padding: 9px;
  background: linear-gradient(160deg, #3a3a3e, #17171a 42%, #2c2c30);
  box-shadow: 0 30px 60px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.k-phone-screen {
  position: relative;
  overflow: hidden;
  border-radius: 38px;
  background: #000;
  aspect-ratio: 1290 / 2796;
}
.k-phone-screen img,
.k-phone-screen video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The Dynamic Island, drawn rather than relied on from the screenshot. */
.k-phone-island {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  width: 32%;
  height: 22px;
  border-radius: var(--radius-capsule);
  background: #000;
}

/* Floating fact chips beside the hero phone. */
.k-chip-float {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-chip);
  background: linear-gradient(var(--glass-fill), var(--glass-fill)) padding-box,
              var(--card-edge) border-box;
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  box-shadow: var(--shadow-card);
  white-space: nowrap;
}
.k-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }

/* ------------------------------------------------------- hero background -- */

/* One composited banner loop behind the headline, full-bleed: it breaks out of
   the 1140px column to the viewport edges.

   This used to be three still crops of the app, each tilted in 3D and panned
   by keyframes to fake a camera move. All of that is gone — the move, the
   depth of field and the grade are baked into the file now, so the element
   does nothing but cover its box. No blur and no `filter` either: a composited
   video layer under a filter is re-rasterized every frame, and the treatment
   is already in the pixels. Legibility is the scrim's job alone.

   `object-fit: cover` crops rather than letterboxes, so the 16:9 source fills
   a hero of any aspect. On a tall/narrow viewport that crops the sides hard —
   which is why the mobile block below drops the video and the poster takes
   over. */

.k-hero-bg {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100vw;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.k-hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The poster is the same frame graded the same way, so the swap from still
     to first decoded frame is invisible. */
  background: var(--background);
}

/* The plates sit behind everything in the hero. */
#top > *:not(.k-hero-bg) { position: relative; z-index: 1; }

/* Two jobs: darken the left half so the headline has a ground, and stop the
   plates before they reach the section below. */
.k-hero-scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to right,
      var(--background) 0%,
      color-mix(in srgb, var(--background) 82%, transparent) 34%,
      color-mix(in srgb, var(--background) 30%, transparent) 62%,
      transparent 100%),
    linear-gradient(to bottom,
      color-mix(in srgb, var(--background) 70%, transparent) 0%,
      transparent 18%,
      transparent 62%,
      var(--background) 100%);
}

.k-hero-stage { display: flex; align-items: center; justify-content: center; }

/* ----------------------------------------------------------- hero motif -- */
/* Retained for reference. The hero no longer renders the motif markup — see
   the comment in index.html — but this is what it was. */

/* A drifting bar grid with teal note blocks and a sweeping amber playhead —
   the timeline, abstracted. Masked away from the headline so it never
   competes with type. */
.k-motif {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  opacity: 0.55;
  mask-image: linear-gradient(to bottom, transparent, black 22%, black 74%, transparent);
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 22%, black 74%, transparent);
}
.k-motif-inner {
  position: absolute;
  inset: 0;
  mask-image: linear-gradient(to right, transparent 0%, transparent 44%, black 66%, black 100%);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, transparent 44%, black 66%, black 100%);
}
.k-motif-grid {
  position: absolute;
  inset: 0;
  width: 200%;
  animation: k-drift 46s linear infinite;
  background-image:
    repeating-linear-gradient(to right, rgba(255, 255, 255, 0.10) 0 1px, transparent 1px 8.333%),
    repeating-linear-gradient(to right, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px 2.083%);
}
.k-motif-half { position: absolute; top: 0; bottom: 0; width: 50%; }
.k-motif-note {
  position: absolute;
  height: 10px;
  border-radius: 3px;
  background: var(--note-fill);
  opacity: 0.5;
}
.k-motif-head {
  position: absolute;
  top: 14%;
  bottom: 14%;
  width: 2px;
  background: var(--accent);
  box-shadow: 0 0 18px rgba(232, 163, 61, 0.75);
  animation: k-sweep 19s linear infinite;
}

@keyframes k-drift { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes k-sweep { from { left: -2%; } to { left: 102%; } }
@keyframes k-pip {
  0%, 8%   { opacity: 1;    transform: scale(1.34); }
  60%,100% { opacity: 0.28; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  [data-motion] { animation: none !important; }

  /* The hero loop is motion the media query is asking us not to play. Hiding
     the <video> falls through to the poster on .k-hero-bg, so the hero keeps
     its background instead of going flat. JS also pauses it, belt and braces. */
  .k-hero-video { display: none; }
  .k-hero-bg {
    background: url("assets/hero/banner.jpg") center / cover no-repeat;
  }
}

/* --------------------------------------------------------- record cards -- */

.k-feature-list { display: grid; gap: clamp(9px, 1.4svh, 14px); }
.k-feature {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  padding: clamp(11px, 1.9svh, 16px) 16px;
}
.k-feature h3 { margin: 0 0 3px; font-size: var(--chrome-16); font-weight: 600; }
.k-feature p  { margin: 0; font-size: var(--chrome-14); line-height: 1.45; color: var(--fg-secondary); }
.k-feature-glyph {
  display: flex;
  align-items: center;
  height: 20px;
  padding-top: 2px;
  font-size: var(--chrome-15);
  font-weight: 600;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* The record screen's four beat pips, walking the bar. */
.k-pips { display: flex; gap: 3px; align-items: flex-end; height: 20px; padding-top: 2px; }
.k-pips i {
  display: block;
  width: 5px;
  height: 8px;
  border-radius: var(--radius-capsule);
  background: var(--accent);
  animation: k-pip 0.6s linear infinite;
}
.k-pips i:nth-child(2) { animation-delay: 0.15s; }
.k-pips i:nth-child(3) { animation-delay: 0.30s; }
.k-pips i:nth-child(4) { animation-delay: 0.45s; }

/* ------------------------------------------------------- waveform glyph -- */

.k-wave { display: inline-flex; align-items: center; justify-content: center; gap: 3px; flex: 0 0 auto; }
.k-wave i { display: block; width: 3px; border-radius: 1.5px; background: rgba(var(--primary-rgb), 0.40); }
.k-wave i:nth-child(odd)  { height: 12px; }
.k-wave i:nth-child(even) { height: 8px; }
.k-wave[data-picked="1"] i { background: var(--accent); }
.k-wave[data-picked="1"] i:nth-child(odd)  { height: 16px; }
.k-wave[data-picked="1"] i:nth-child(even) { height: 10px; }

/* The Recent row's five-bar teal glyph — the app's own take marker. */
.k-wave-recent { display: inline-flex; align-items: center; gap: 2.2px; width: 20px; height: 20px; flex: none; }
.k-wave-recent i { display: block; width: 2.2px; border-radius: 1.1px; background: rgba(0, 201, 214, 0.9); }

/* ------------------------------------------------------------- controls -- */

/* Tier 2 selection volume: an accent RING on neutral glass, never a tint. */
.k-seg {
  display: flex;
  gap: var(--gap-segments);
  padding: var(--segmented-inset);
  border-radius: var(--radius-capsule);
  background: var(--panel-fill);
  box-shadow: inset 0 0 0 var(--hairline) var(--panel-stroke);
}
.k-seg button {
  flex: 1 1 0;
  min-width: 0;
  height: var(--segmented-height);
  padding: 0 6px;
  border: 1px solid transparent;
  border-radius: var(--radius-capsule);
  font: 500 var(--text-footnote-size) / 1 var(--font-system);
  color: var(--fg-segment-unpicked);
  background: transparent;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.k-seg button[aria-selected="true"] {
  font-weight: 600;
  color: var(--on-accent);
  background: linear-gradient(var(--accent), var(--accent)) padding-box,
              var(--tier1-rim) border-box;
}

.k-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  height: var(--chip-rail-height);
  padding: 0 13px;
  border: none;
  border-radius: var(--radius-capsule);
  background: var(--glass-fill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  box-shadow: inset 0 0 0 var(--hairline) rgba(var(--primary-rgb), 0.08);
  color: var(--fg-row-label);
  font: 500 var(--chrome-14) / 1 var(--font-system);
  white-space: nowrap;
  flex: 0 0 auto;
}
.k-chip[aria-pressed="true"] {
  box-shadow: inset 0 0 0 var(--stroke-ring) var(--selection-ring);
  color: var(--fg-primary);
  font-weight: 600;
}
.k-chip .k-chip-sub { font: 400 var(--chrome-12) / 1 var(--font-system); color: var(--fg-muted); }
.k-rail { display: flex; flex-wrap: wrap; gap: var(--gap-chips); }

/* Tier 3 selection volume: a neutral wash plus a 3pt accent bar on the
   leading edge. The wash is NOT hued — a picked row must not shout as loudly
   as a picked segment. */
.k-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-12);
  width: 100%;
  min-height: 46px;
  padding: var(--pad-row-v) var(--pad-row-h);
  border: none;
  background: transparent;
  color: var(--fg-primary);
  text-align: left;
  font-family: inherit;
}
.k-row[aria-pressed="true"] { background: var(--row-wash); }
.k-row[aria-pressed="true"]::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: var(--stroke-selection-bar);
  background: var(--selection-bar);
}
.k-row-main { display: flex; align-items: center; gap: var(--space-12); flex: 1 1 0; min-width: 0; }
.k-row-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.k-row-label {
  font: 500 var(--chrome-16) / 1.3 var(--font-system);
  color: var(--fg-row-label);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.k-row[aria-pressed="true"] .k-row-label { font-weight: 600; color: var(--fg-primary); }
/* Rust = a fact about the user's own choice. Teal = the app's opinion.
   These two must never swap colours. */
.k-row-fact {
  font: 400 var(--chrome-11) / 1.2 var(--font-system);
  letter-spacing: var(--tracking-fact);
  text-transform: uppercase;
  color: var(--text-fact);
  white-space: nowrap;
}
.k-row-suggestion {
  font: 600 var(--chrome-10) / 1.2 var(--font-system);
  letter-spacing: var(--tracking-suggestion);
  color: var(--text-suggestion);
  white-space: nowrap;
}
.k-tick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--accent);
}

.k-fader { display: flex; flex-direction: column; gap: var(--space-6); }
.k-fader-head { display: flex; align-items: baseline; gap: var(--space-8); }
.k-fader-label { font: 400 var(--text-caption2-size) / 1.2 var(--font-system); color: var(--fg-primary); white-space: nowrap; }
.k-fader-read  { margin-left: auto; font-variant-numeric: tabular-nums; font-size: var(--text-caption2-size); color: var(--fg-secondary); }
.k-fader-body  { position: relative; height: var(--fader-thumb); }
/* A groove cut INTO the surface, never glass. */
.k-fader-track { position: absolute; top: 9px; left: 0; right: 0; height: var(--fader-track-height); border-radius: var(--radius-capsule); background: var(--fader-track); }
.k-fader-fill  { position: absolute; top: 9px; left: 0; height: var(--fader-track-height); border-radius: var(--radius-capsule); background: var(--fader-fill); }
.k-fader-thumb {
  position: absolute; top: 0;
  width: var(--fader-thumb); height: var(--fader-thumb);
  border-radius: 50%;
  background: var(--glass-fill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  box-shadow: inset 0 0 0 var(--hairline) rgba(var(--primary-rgb), 0.14);
}

/* ------------------------------------------------------------ recording -- */

/* The column ratio and gap are the hero's, deliberately — the phone is centred
   in its column, so a wider column here (it was 1fr/1fr, 56px) pushed the same
   310px frame ~70px left of the hero's on a large display. Matching the grid is
   what keeps the two phones on one axis at every width; sharing .k-phone-lg only
   ever guaranteed they were the same SIZE. */
#record .k-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: 48px;
  align-items: center;
}

/* ---- the crossfaded screen loop ---- */

/* Both videos are stacked over the poster; script.js fades between them across
   the loop seam. Opacity is the only thing that moves, so the compositor can
   carry the transition on its own. */
.k-loop-video {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--loop-fade, 700ms) linear;
}
.k-loop-video[data-on] { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .k-loop-video { display: none; }
}

/* --------------------------------------------------------------- sounds -- */

.k-player {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
}
.k-play-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 44px;
  height: 44px;
  border: 1px solid transparent;
  border-radius: 50%;
  background: linear-gradient(var(--accent), var(--accent)) padding-box,
              var(--tier1-rim) border-box;
  color: var(--on-accent);
  font-size: var(--chrome-15);
  font-weight: 700;
  cursor: pointer;
}
.k-play-btn[disabled] { opacity: 0.45; cursor: not-allowed; }
.k-player-meta { min-width: 220px; }
.k-player-meta p { margin: 0; }
.k-player-title { font-size: var(--chrome-15); font-weight: 600; margin-bottom: 2px !important; }
.k-player-sub   { font-size: var(--text-footnote-size); color: var(--fg-secondary); }
.k-player-ab    { margin-left: auto; width: 280px; max-width: 100%; }

/* Fixed columns, not flex. Under flex the takes column was sized by its widest
   row, and every take's subtitle is a different length ("2h ago · G · 72 BPM ·
   6/8" vs "2 weeks ago · Bb · 68 BPM · 4/4") — plus the selected row gains a
   tick. Measured, that swung the column 316 -> 340px and dragged the panel with
   it as you clicked down the list. A track that cannot resize cannot propagate.

   Two rows, and the heading occupies only the first cell of the left column.
   That is what aligns the player with the top of the takes list instead of the
   top of the section — a hard-coded offset would drift the moment the heading
   rewrapped. */
.k-sounds-layout {
  display: grid;
  grid-template-columns: var(--recent-col-w) minmax(0, 1fr);
  grid-template-areas:
    "head ."
    "list panel";
  column-gap: 24px;
  row-gap: 4px;
  align-items: start;
}
.k-sounds-head { grid-area: head; min-width: 0; }
.k-recent-col  { grid-area: list;  min-width: 0; }
.k-cells-col   { grid-area: panel; min-width: 0; display: grid; gap: 14px; align-content: start; }
/* The column heading is part of the grid flow, so it takes the row gap too;
   pull it back to the 10px the left column uses. */
.k-cells-col > .k-col-head { margin-bottom: -4px; }

:root { --recent-col-w: 400px; }

/* The heading is set against 400px here, not the full width, so it needs its
   own scale. */
.k-h2-col { font-size: clamp(27px, 2.3vw, 33px); letter-spacing: -0.8px; }
.k-lede-col { font-size: var(--chrome-16); max-width: none; margin-bottom: 22px; }

.k-col-head {
  margin: 0 0 10px;
  font-size: var(--chrome-17);
  font-weight: 600;
  letter-spacing: -0.2px;
  color: var(--fg-primary);
}

/* The takes list, framed like the cells beside it. */
.k-recent-frame {
  position: relative;
  padding-bottom: 18px;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: var(--radius-list-card);
  background: linear-gradient(var(--glass-fill), var(--glass-fill)) padding-box,
              var(--card-edge) border-box;
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  box-shadow: var(--shadow-card);
}
/* The same bottom fade the cells carry. It sits mostly over the padding rather
   than over the last row: the list is not scrollable, so every take has to stay
   readable and clickable — the fade implies more, it must not hide any. */
.k-recent-frame::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 42px;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--background));
}

.k-recent-list { display: grid; min-width: 0; }
.k-recent-item { position: relative; display: flex; align-items: center; min-width: 0; }
.k-recent-item[aria-current="true"] { background: var(--row-wash); }
.k-recent-item[aria-current="true"]::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: var(--stroke-selection-bar);
  background: var(--selection-bar);
}
.k-recent-btn {
  display: flex; align-items: center; gap: 13px;
  flex: 1; min-width: 0;
  height: var(--recent-row-height);
  padding: 13px 15px;
  border: none; background: transparent;
  text-align: left; cursor: pointer; font-family: inherit;
}
.k-recent-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.k-recent-name {
  font: 500 var(--chrome-16) / 1.2 var(--font-system);
  color: rgba(var(--primary-rgb), 0.95);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.k-recent-sub {
  font: 400 var(--chrome-12) / 1.2 var(--font-system);
  color: rgba(var(--primary-rgb), 0.45);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.k-recent-tick { flex: none; margin-right: 15px; }

/* ---- The two setting cells ------------------------------------------ */

.k-cells { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.k-cell { margin: 0; }

/* The page titles are cropped out of the screenshots, so this row is the only
   thing naming which page a cell is and what it has selected. At ~0.30 scale
   nobody is reading the screenshot for that — the caption carries it. */
.k-cell-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0 2px 7px;
  height: 22px;
}
.k-cell-name {
  font-size: var(--chrome-11);
  font-weight: 600;
  letter-spacing: var(--tracking-fact);
  text-transform: uppercase;
  color: var(--fg-secondary);
  white-space: nowrap;
}
/* Rust: a fact about the user's own choice, the role the accent plays on
   "DEFAULT FOR NYLON" inside the app. */
.k-cell-pick {
  margin-left: auto;
  font-size: var(--text-footnote-size);
  font-weight: 600;
  color: var(--accent);
  text-align: right;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Real captures, not CSS replicas. The four pages were rebuilt by hand in an
   earlier pass and were wrong in ways invisible until the screenshots landed
   beside them — a missing strum-rate control, no PRO badges, no locked-row
   dimming, a drum list that did not match the app. */
.k-cell-frame {
  position: relative;
  aspect-ratio: 1320 / 1162;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: var(--radius-card);
  background: linear-gradient(var(--glass-fill), var(--glass-fill)) padding-box,
              var(--card-edge) border-box;
  box-shadow: var(--shadow-card);
}
/* Both of a slot's pages stay in the DOM and cross-fade, so switching pairs
   never waits on the network or flashes an empty frame. */
.k-cell-frame img {
  position: absolute; inset: 0;
  display: block; width: 100%; height: 100%;
  opacity: 0;
  transition: opacity var(--dur-standard) var(--ease-out-quick);
}
.k-cell-frame img[data-active] { opacity: 1; }
/* The crop stops mid-page on purpose: the bottom edge says "this continues"
   rather than pretending the page ended. */
.k-cell-frame::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 52px;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--background));
}

/* ---- The tab bar ----------------------------------------------------- */

/* Modelled on Houseband's bottom navigation — glyph over label, active tab in a
   pill — but built as a WEB control: it has hover and focus states an iOS tab
   bar does not, because here it has to read as clickable to someone who has
   never seen the app. */
.k-tabbar {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  width: 100%;
  max-width: 460px;
  margin: 2px auto 0;
  gap: 4px;
  padding: 6px;
  border-radius: var(--radius-capsule);
  background: var(--glass-fill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  box-shadow: inset 0 0 0 var(--hairline) var(--panel-stroke);
}
.k-tabbar button {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 8px 4px 7px;
  border: none;
  /* Capsule, not --radius-chip: the bar itself is a capsule, so a 14px-radius
     highlight inside it read as a rounded rectangle floating in a pill. */
  border-radius: var(--radius-capsule);
  background: transparent;
  color: var(--fg-secondary);
  font-family: inherit;
  font-size: var(--chrome-12);
  font-weight: 500;
  cursor: pointer;
  transition: background var(--dur-quick) var(--ease-out-quick),
              color var(--dur-quick) var(--ease-out-quick);
}
.k-tabbar button:hover { color: var(--fg-primary); background: rgba(var(--primary-rgb), 0.05); }
.k-tabbar button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The pill is a NEUTRAL wash and the accent is the content on top of it —
   tinting the glass itself with the accent is the system's one hard rule. */
.k-tabbar button[aria-selected="true"] {
  background: var(--row-wash);
  color: var(--accent);
  font-weight: 600;
}
.k-tab-icon { display: flex; gap: 5px; height: 18px; }

/* ----------------------------------------------------------------- demo -- */

.k-demo-grid { display: grid; grid-template-columns: minmax(0, 1fr) 290px; gap: 32px; align-items: start; }
.k-demo-stage { display: flex; justify-content: center; }
.k-demo-stage .k-phone { width: 100%; max-width: min(430px, 30svh); border-radius: 52px; padding: 10px; }
.k-demo-stage .k-phone-screen { border-radius: 44px; }

.k-chapters { display: grid; gap: 2px; }
.k-chapter {
  display: grid;
  grid-template-columns: 3px 42px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  min-height: clamp(42px, 6svh, 52px);
  padding: clamp(6px, 1svh, 10px) 12px;
  border: none;
  border-radius: var(--radius-chip);
  background: transparent;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
.k-chapter[aria-current="true"] { background: var(--row-wash); }
.k-chapter-bar { width: 3px; height: 24px; border-radius: var(--radius-capsule); background: transparent; }
.k-chapter[aria-current="true"] .k-chapter-bar { background: var(--accent); }
.k-chapter-time { font-size: var(--text-footnote-size); color: var(--fg-muted); font-variant-numeric: tabular-nums; }
.k-chapter-title { font-size: var(--chrome-15); font-weight: 600; color: var(--fg-primary); }
.k-chapter[aria-current="true"] .k-chapter-title { color: var(--accent); }
.k-chapter-now { margin-bottom: 18px; }
.k-chapter-now p { margin: 0; }
.k-chapter-now p:first-child { font-size: var(--chrome-16); font-weight: 600; margin-bottom: 2px; }
.k-chapter-now p:last-child  { font-size: var(--chrome-14); line-height: 1.4; color: var(--fg-secondary); }

/* ---------------------------------------------------------------- tiers -- */

.k-tiers { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; align-items: stretch; }
.k-tier {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 22px;
  /* Minimum separation between the feature list and the CTA. `margin-top: auto`
     on the button collapses to 0 when the card has no spare height — which is
     exactly what happens on a phone — so the gap is what guarantees the CTA is
     never touching the last line. */
  gap: 22px;
}
.k-tier-name { margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -0.5px; }
.k-tier-list { display: grid; gap: 10px; font-size: var(--chrome-15); line-height: 1.4; color: var(--fg-row-label); }
.k-tier-list p { margin: 0; }
.k-tier-list .k-dim { color: var(--fg-muted); }
.k-tier .k-btn { margin-top: auto; height: 48px; font-size: var(--chrome-16); }
.k-tier-head { display: flex; align-items: center; gap: 8px; margin-bottom: -14px; }

/* ------------------------------------------------------------ questions -- */

.k-faq { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 8px 44px; }
.k-faq-item { display: grid; gap: 4px; padding: clamp(12px, 2.2svh, 20px) 0; box-shadow: inset 0 -1px 0 var(--divider); }
.k-faq-item h3 { margin: 0; font-size: var(--chrome-16); font-weight: 600; letter-spacing: -0.2px; }
.k-faq-item p  { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--fg-secondary); text-wrap: pretty; }

/* --------------------------------------------------------------- footer -- */

.k-footer {
  max-width: 1140px;
  margin: 0 auto;
  padding: 48px 24px 40px;
  box-shadow: inset 0 1px 0 var(--divider);
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  align-items: flex-end;
  justify-content: space-between;
}
.k-footer-links { display: flex; flex-wrap: wrap; gap: 18px; font-size: var(--chrome-14); }
.k-footer-links a { color: var(--fg-secondary); }
.k-footer-links a:hover { color: var(--fg-primary); }
.k-footer-legal { margin: 0; width: 100%; font-size: var(--chrome-12); color: var(--fg-tertiary); }

/* ------------------------------------------------------------ responsive -- */

@media (max-width: 1080px) {
  .k-demo-grid { grid-template-columns: 1fr; }
  .k-demo-stage .k-phone { max-width: 340px; }
}

@media (max-width: 900px) {
  #record .k-grid { grid-template-columns: 1fr; gap: 40px; }
  #top { grid-template-columns: 1fr !important; gap: 40px !important; padding-top: 56px !important; }
  .k-tiers { grid-template-columns: 1fr; }
  .k-nav-links { display: none; }
  /* Single-column hero: the banner loses the right-hand half it was composed
     for, so the scrim goes vertical instead of horizontal — and harder, since
     the text now runs the full width over it rather than sitting in a darkened
     left column. */
  .k-hero-scrim {
    background:
      linear-gradient(to bottom,
        color-mix(in srgb, var(--background) 86%, transparent) 0%,
        color-mix(in srgb, var(--background) 78%, transparent) 45%,
        color-mix(in srgb, var(--background) 88%, transparent) 88%,
        var(--background) 100%);
  }
  /* The video never loads here — script.js only attaches the source above this
     breakpoint, so a phone on cellular pays for the 35KB poster, not 3.7MB of
     H.264 that a 16:9 loop would crop to ribbons in a portrait hero anyway. */
  .k-hero-bg {
    background: url("assets/hero/banner.jpg") center / cover no-repeat;
  }
  /* The element still carries the poster, which would draw that same still a
     second time on top of the background. Nothing to add, so show nothing. */
  .k-hero-video { display: none; }
  /* The two-column track is fixed-width by design, so it has to be dismissed
     explicitly here — left to itself it kept the 340px column and pushed the
     page into horizontal scroll. */
  /* The two-column track is fixed-width by design, so it has to be dismissed
     explicitly here — left to itself it kept the 400px column and pushed the
     page into horizontal scroll. */
  /* The two-column track is fixed-width by design, so it has to be dismissed
     explicitly here — left to itself it kept the 400px column and pushed the
     page into horizontal scroll. */
  .k-sounds-layout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "head" "list" "panel";
    row-gap: 28px;
  }
  .k-recent-col { max-width: none; }
  .k-h2-col { font-size: clamp(30px, 3.6vw, 44px); }
  .k-lede-col { font-size: var(--chrome-17); }
  .k-tab-label { font-size: var(--chrome-11); }
}

@media (max-width: 620px) {
  .k-cells { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 560px) {
  .k-wrap { padding-inline: 18px; }
  .k-player-ab { margin-left: 0; width: 100%; }
  .k-chip-float { display: none; }
}

/* ==========================================================================
   Large-display scaling
   ==========================================================================
   The page was responsive but not fluid: containers capped at 1140/1260 and
   every body size fixed, so on a 2005px viewport 43% of the screen was empty
   margin around 17px type.

   This scales the page up between 1440px and 1920px and then STOPS. Linear
   scaling to a 4K viewport would give 34px body text, which is a billboard —
   you sit no closer to a 27" display than to a 14" one. Everything below caps
   at roughly 1.2x, which is what Apple, Stripe and Linear all do in one form
   or another: fill more of a big screen, then hold.

   Every value is `clamp(current, ramp, ceiling)` where the ramp equals the
   current value at exactly 1440px — so this is continuous at the breakpoint,
   and the media query guarantees nothing below 1440 is touched at all.

   The ramp for A at 1440 -> B at 1920 is:  A-3(B-A) + ((B-A)/4.8)vw

   These are overrides, not edits to tokens.css. That file is the iOS app's
   type scale, extracted from shipping source; the decision to scale type for a
   large *browser window* is a website decision and belongs here. */
@media (min-width: 1441px) {
  :root {
    --chrome-9:  clamp(9px,  3px + 0.417vw, 11px);
    --chrome-10: clamp(10px, 4px + 0.417vw, 12px);
    --chrome-11: clamp(11px, 5px + 0.417vw, 13px);
    --chrome-12: clamp(12px, 6px + 0.417vw, 14px);
    --chrome-13: clamp(13px, 4px + 0.625vw, 16px);
    --chrome-14: clamp(14px, 5px + 0.625vw, 17px);
    --chrome-15: clamp(15px, 6px + 0.625vw, 18px);
    --chrome-16: clamp(16px, 7px + 0.625vw, 19px);
    --chrome-17: clamp(17px, 8px + 0.625vw, 20px);
    --chrome-18: clamp(18px, 6px + 0.833vw, 22px);
    --text-footnote-size:    clamp(13px, 4px + 0.625vw, 16px);
    --text-caption-size:     clamp(12px, 6px + 0.417vw, 14px);
    --text-caption2-size:    clamp(11px, 5px + 0.417vw, 13px);
    --text-subheadline-size: clamp(15px, 6px + 0.625vw, 18px);
    --text-body-size:        clamp(17px, 8px + 0.625vw, 20px);

    /* Rows grow with the type they hold, or the list looks cramped. */
    --recent-row-height: clamp(56px, 23px + 2.292vw, 67px);
    --recent-col-w:      clamp(400px, 160px + 16.667vw, 480px);
  }

  .k-wrap      { max-width: clamp(1140px, 360px + 54.167vw, 1400px); }
  .k-nav-inner,
  .k-footer    { max-width: clamp(1140px, 360px + 54.167vw, 1400px); }

  /* Headings already ramp with vw but top out by ~1300px; lift their ceilings. */
  .k-h1        { font-size: clamp(70px, 28px + 2.917vw, 84px); }
  .k-h2        { font-size: clamp(44px, 17px + 1.875vw, 53px); }
  .k-h2-col    { font-size: clamp(33px, 12px + 1.458vw, 40px); }
  .k-pull      { font-size: clamp(38px, 14px + 1.667vw, 46px); }
  .k-tier-name { font-size: clamp(24px, 9px + 1.042vw, 29px); }
  .k-brand,
  .k-footer-brand { font-size: clamp(21px, 9px + 0.833vw, 25px); }
  .k-faq-item p   { font-size: clamp(14.5px, 5.5px + 0.625vw, 17.5px); }

  /* The captures are 1320px wide, so there is headroom to grow them — the
     screenshots get sharper on a large display, not softer. */
  /* Deliberately NOT grown further. Widening the phone to fill its column was
     tried and reverted: at 2.17x taller than wide, going 372 -> 418px bought
     23px of horizontal slack and cost 100px of hero height. A portrait frame in
     a landscape column cannot be filled sideways — narrow the column instead,
     which is what the grid ratio below does. */
  .k-phone-lg  { width: min(clamp(310px, 124px + 12.917vw, 372px), 38svh); }

  /* More of the width to the headline, less to the phone's column, so the phone
     sits in a column closer to its own size without the section growing. */
  #top { grid-template-columns: minmax(0, 1.24fr) minmax(0, 0.76fr) !important; }
  #record .k-grid { grid-template-columns: minmax(0, 1.24fr) minmax(0, 0.76fr); }
  .k-tabbar    { max-width: clamp(460px, 190px + 18.75vw, 550px); }
}

/* ============================================================== doc pages ===
   privacy.html and support.html — long-form text rather than a landing page.
   One narrow measure, the site's own type ramp, and nothing new invented: the
   pages reuse .k-nav, .k-footer and .k-card from above so the chrome matches
   index.html exactly and there is only ever one place to change it.

   The measure is capped in ch, not px, so it stays at a readable line length
   through the >1441px type ramp instead of growing with the viewport. */

.k-doc { max-width: 68ch; margin: 0 auto; }

.k-doc-head { margin-bottom: clamp(28px, 5svh, 44px); }

.k-doc h1 {
  margin: 0 0 12px;
  font-size: clamp(34px, 3.2vw, 46px);
  font-weight: 700;
  letter-spacing: -1.2px;
  line-height: 1.08;
  text-wrap: balance;
}

.k-doc h2 {
  margin: clamp(30px, 5svh, 46px) 0 10px;
  font-size: var(--chrome-18);
  font-weight: 600;
  letter-spacing: -0.3px;
  color: var(--fg-primary);
}

.k-doc h3 {
  margin: 24px 0 6px;
  font-size: var(--chrome-16);
  font-weight: 600;
  letter-spacing: -0.2px;
}

.k-doc p,
.k-doc li {
  margin: 0 0 12px;
  font-size: var(--chrome-16);
  line-height: 1.62;
  color: var(--fg-secondary);
  text-wrap: pretty;
}

.k-doc ul { margin: 0 0 12px; padding-left: 20px; }
.k-doc li { margin-bottom: 7px; }
.k-doc li::marker { color: var(--fg-tertiary); }

.k-doc strong { color: var(--fg-primary); font-weight: 600; }

/* Inline links only. A .k-btn inside the doc column keeps its own colours —
   without the :not(), the accent below repaints the label of a primary button
   in the accent it is already sitting on, and the button renders blank. */
.k-doc a:not(.k-btn) { color: var(--accent); text-decoration: none; }
.k-doc a:not(.k-btn):hover { text-decoration: underline; }

/* The dateline under the title, and the closing legal line. */
.k-doc-meta {
  margin: 0;
  font-size: var(--chrome-14);
  color: var(--fg-tertiary);
}

/* The claim the whole privacy page rests on, stated once at the top so nobody
   has to read the rest to get the answer. */
.k-doc-summary {
  margin: clamp(20px, 3svh, 30px) 0 clamp(26px, 4svh, 38px);
  padding: clamp(18px, 2.6svh, 24px);
}

.k-doc-summary p:last-child { margin-bottom: 0; }

.k-doc-summary .k-doc-lede {
  font-size: var(--chrome-17);
  color: var(--fg-primary);
  line-height: 1.5;
}

/* Support: a question and its answer, divided like the FAQ on the home page. */
.k-doc-qa {
  padding: clamp(14px, 2.4svh, 20px) 0;
  box-shadow: inset 0 -1px 0 var(--divider);
}
.k-doc-qa:last-child { box-shadow: none; }
.k-doc-qa h3 { margin-top: 0; }
.k-doc-qa p:last-child { margin-bottom: 0; }

/* The contact block — the one thing a support page exists to deliver, so it
   gets the card treatment and sits above the questions rather than under them. */
.k-doc-contact {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 20px;
  padding: clamp(18px, 2.6svh, 24px);
  margin: clamp(20px, 3svh, 30px) 0 clamp(26px, 4svh, 38px);
}

.k-doc-contact-text { flex: 1 1 240px; }
.k-doc-contact-text p { margin: 0; }
.k-doc-contact-text .k-doc-lede { font-size: var(--chrome-17); color: var(--fg-primary); }

@media (max-width: 620px) {
  .k-doc h1 { font-size: clamp(28px, 8vw, 34px); }
}
