/* ── Google Fonts ────────────────────────────────────────────────────────── */
/* Webfonts are loaded from base.html, not imported here.
   A CSS @import can only start after this file has been fetched and parsed, so
   it serialises two render-blocking requests: the page cannot paint until
   Google Fonts answers. Measured at 12.9s to DOMContentLoaded with that host
   unreachable, on every page of the site. The <link> in base.html uses the
   media="print" swap so a slow or blocked font host costs a font, not a
   blank page. */

/* ── Design tokens ───────────────────────────────────────────────────────── */
:root {
  /* Every value below is an alias of a token in static/css/tokens.css (redo 0,
     2026-10-13). The names stay because templates, scripts and tests read
     them; the values moved to the new palette. Violet and cyan are gone from
     the UI: their names now resolve to ink or to neutral tints, and pink
     resolves to the one accent. Pairs and ratios: docs/design/COLOR-AUDIT.md. */

  /* Backgrounds */
  --bg-base:            var(--bg);
  --bg-surface:         var(--surface-1);
  --bg-elevated:        var(--surface-2);
  --bg-overlay:         var(--surface-3);

  /* The old brand gradient. A fill that used it is now the accent (primary
     buttons, the play button, progress); the soft and subtle tints are
     neutral. Text that was clipped to it is plain ink. The gradient itself
     lives on as --gradient-logo (logo and one landing hero moment). */
  --gradient-brand:        var(--accent);
  --gradient-brand-subtle: rgb(var(--ink-rgb) / .04);
  --gradient-brand-soft:   rgb(var(--ink-rgb) / .08);
  --gradient-brand-text:   linear-gradient(var(--ink), var(--ink));

  /* Accent names. Fills, borders and outlines read the accent; the -light and
     -xlight names were text colours and are now ink. */
  --accent-primary:         var(--accent);
  --accent-primary-hover:   var(--accent-hover);
  --accent-primary-light:   var(--ink);
  --accent-pink:            var(--accent);
  --accent-pink-hover:      var(--accent-hover);
  --accent-pink-light:      var(--accent);
  --accent-secondary:       var(--ink);
  --accent-secondary-hover: var(--muted);
  --accent-secondary-light: var(--ink);
  --accent-glow:            transparent;
  --accent-glow-pink:       transparent;

  /* Former violet, pink and cyan tints: neutral ink tints now. */
  --accent-a08: rgb(var(--ink-rgb) / .04);
  --accent-a12: rgb(var(--ink-rgb) / .06);
  --accent-a15: rgb(var(--ink-rgb) / .07);
  --accent-a20: rgb(var(--ink-rgb) / .10);
  --accent-a30: rgb(var(--ink-rgb) / .14);
  --accent-a40: rgb(var(--ink-rgb) / .18);
  --pink-a10: rgb(var(--ink-rgb) / .05);
  --pink-a15: rgb(var(--ink-rgb) / .07);
  --pink-a20: rgb(var(--ink-rgb) / .10);
  --pink-a30: rgb(var(--ink-rgb) / .14);
  --cyan-a12: rgb(var(--ink-rgb) / .06);
  --cyan-a15: rgb(var(--ink-rgb) / .07);
  --cyan-a20: rgb(var(--ink-rgb) / .10);

  /* Text */
  --text-primary:   var(--ink);
  --text-secondary: var(--muted);
  --text-muted:     var(--muted);
  --text-on-accent: var(--accent-ink);

  /* Pale text tiers (were tinted text on soft fills) */
  --accent-primary-xlight:   var(--ink);
  --accent-secondary-xlight: var(--ink);
  --success-xlight:          var(--success);
  --warning-xlight:          var(--warning);
  --danger-xlight:           var(--error);

  /* Borders */
  --border-subtle:  var(--line-soft);
  --border-default: var(--line);
  --border-strong:  rgb(var(--ink-rgb) / .2);

  /* Semantic (--success and --warning are tokens.css names) */
  --success-light: var(--success);
  --warning-light: var(--warning);
  --danger:        var(--error);
  --danger-light:  var(--error);

  /* Semantic "tints" were chip fills; a status chip is now a neutral surface
     with a semantic dot or word. */
  --success-a15: var(--surface-2);
  --warning-a15: var(--surface-2);
  --danger-a15:  var(--surface-2);

  /* --accent-hot was the focus/hover pink */
  --accent-hot: var(--focus-ring);

  /* Shadows: offset and soft; the glow is retired. */
  --shadow-sm:   0 1px 3px rgb(var(--shade-rgb) / .4);
  --shadow-md:   0 4px 16px rgb(var(--shade-rgb) / .5);
  --shadow-lg:   var(--shadow-float);
  --shadow-glow: 0 0 0 transparent;

  /* Radii */
  --radius-sm: 8px;
  --radius-md: var(--radius-control);
  --radius-lg: var(--radius-card);
  --radius-xl: 20px;

  /* Spacing (8px grid) */
  --sp-8:  8px;
  --sp-16: 16px;
  --sp-24: 24px;
  --sp-32: 32px;
  --sp-40: 40px;
  --sp-48: 48px;
  --sp-64: 64px;
  --sp-80: 80px;
  --sp-96: 96px;

  /* Breakpoints (mobile-first reference values — CSS can't use vars in @media,
     so these are for documentation/JS only. Use them consistently:
       --bp-xs: 480  phone portrait
       --bp-sm: 640  phone landscape / small tablet portrait
       --bp-md: 768  tablet portrait
       --bp-lg: 900  tablet landscape (custom breakpoint for marketplace)
       --bp-xl: 1024 desktop                                                */
  --bp-xs: 480px;
  --bp-sm: 640px;
  --bp-md: 768px;
  --bp-lg: 900px;
  --bp-xl: 1024px;

  /* Typography */
  /* --font-display and --font-body are defined in static/css/tokens.css. */

  /* Transitions */
  --transition-fast:   all var(--dur-hover) var(--ease);
  --transition-base:   all var(--dur-ui) var(--ease);
  --transition-slow:   all var(--dur-fade) var(--ease);

  /* Z-index scale */
  --z-base:    1;
  --z-raised:  10;
  --z-nav:     100;
  --z-modal:   200;
  --z-widget:  300;
  --z-tooltip: 400;

  /* Legacy aliases — keep existing JS from breaking */
  /* --bg, --muted, --accent and --success/--warning are tokens.css names. */
  --surface:  var(--surface-1);
  --surface2: var(--surface-2);
  --border:   var(--line);
  --accent2:  var(--ink);
  --text:     var(--ink);
  --radius:   var(--radius-card);
}

/* ── Reset & base ────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; font-size: 16px; }

body {
  background: var(--bg-base);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 400;
  line-height: 1.6;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, video { display: block; max-width: 100%; }

button, input, textarea, select {
  font-family: var(--font-body);
  font-size: inherit;
  color: inherit;
}

a { color: inherit; text-decoration: none; transition: var(--transition-fast); }

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  color: var(--text-primary);
  line-height: 1.15;
}

p { color: var(--text-secondary); line-height: 1.65; }

/* ── Typography scale ────────────────────────────────────────────────────── */

/* Display — 64px / 800 */
.text-display {
  font-family: var(--font-display);
  font-size: 64px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
  color: var(--text-primary);
}

/* H1 — 48px / 700 */
.text-h1, h1 {
  font-family: var(--font-display);
  font-size: 48px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

/* H2 — 36px / 600 */
.text-h2, h2 {
  font-family: var(--font-display);
  font-size: 36px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

/* H3 — 24px / 600 */
.text-h3, h3 {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
  line-height: 1.3;
}

/* H4 — 18px / 600 */
.text-h4, h4 {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  line-height: 1.4;
}

/* Body — 15px / 400 */
.text-body { font-family: var(--font-body); font-size: 15px; font-weight: 400; line-height: 1.6; }

/* Body large — 16px */
.text-body-lg { font-family: var(--font-body); font-size: 16px; font-weight: 400; line-height: 1.7; color: var(--text-secondary); }

/* Small — 13px */
.text-sm { font-family: var(--font-body); font-size: 13px; font-weight: 400; color: var(--text-muted); }

/* Label / overline — 12px / 500 uppercase */
.text-label {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Gradient text utility — dark surfaces only */
.text-gradient {
  color: var(--ink);
}

/* Muted utility */
.text-muted  { color: var(--text-muted) !important; }
.text-secondary-color { color: var(--text-secondary); }

/* Code */
code, pre {
  font-family: 'JetBrains Mono', 'Fira Code', monospace;
  font-size: 13px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
}
code { padding: 2px 6px; }
pre  { padding: 16px; overflow-x: auto; }

/* ── Layout shell ────────────────────────────────────────────────────────── */

/* App shell — no top-nav offset; sidenav handles layout */
.app-shell {
  min-height: 100vh;
  padding-top: 0;
}

/* Page container — standard horizontal padding */
.page-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 32px 32px 96px;
}
.page-container--narrow {
  max-width: 800px;
  margin: 0 auto;
  padding: 32px 32px 96px;
}
.page-container--wide {
  max-width: 1440px;
  margin: 0 auto;
  padding: 32px 32px 96px;
}

/* Section wrapper */
.section { padding: 96px 96px; }
.section--sm { padding: 64px 96px; }

/* Content widths */
.content-xs  { max-width: 480px; }
.content-sm  { max-width: 640px; }
.content-md  { max-width: 800px; }
.content-lg  { max-width: 1024px; }
.content-xl  { max-width: 1200px; }
.content-full { max-width: 100%; }
.mx-auto { margin-left: auto; margin-right: auto; }

/* Flex primitives */
.flex        { display: flex; }
.flex-col    { display: flex; flex-direction: column; }
.flex-center { display: flex; align-items: center; justify-content: center; }
.flex-between{ display: flex; align-items: center; justify-content: space-between; }
.flex-wrap   { flex-wrap: wrap; }
.items-center{ align-items: center; }
.items-start { align-items: flex-start; }
.flex-1      { flex: 1; }

/* Gap scale (8px grid) */
.gap-8  { gap: 8px; }
.gap-16 { gap: 16px; }
.gap-24 { gap: 24px; }
.gap-32 { gap: 32px; }
.gap-48 { gap: 48px; }
.gap-64 { gap: 64px; }

/* Grid primitives */
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; }

/* Two-panel layouts */
.panel-60-40 { display: flex; gap: 64px; align-items: center; }
.panel-60-40 > :first-child { flex: 0 0 60%; }
.panel-60-40 > :last-child  { flex: 0 0 40%; }

.panel-50-50 { display: flex; gap: 32px; }
.panel-50-50 > * { flex: 1; }

.panel-40-60 { display: flex; gap: 32px; }
.panel-40-60 > :first-child { flex: 0 0 40%; }
.panel-40-60 > :last-child  { flex: 1; }

.sidebar-layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 0;
  min-height: calc(100vh - 64px);
}

/* Legacy layout aliases */
.studio-layout, .form-page        { max-width: 800px;  margin: 0 auto; padding: 32px 32px 96px; display: flex; flex-direction: column; gap: 32px; }
.dashboard-layout                  { max-width: 1200px; margin: 0 auto; padding: 32px 32px 96px; display: flex; flex-direction: column; gap: 24px; }
/* min-height dropped along with the 64px top-nav assumption: forcing a full
   viewport height here padded the page out even when the content was short. */
.marketplace-layout                { display: grid; grid-template-columns: 256px 1fr; gap: 24px; align-items: start; }
.release-layout, .analytics-layout { max-width: 800px;  margin: 0 auto; padding: 32px 32px 96px; display: flex; flex-direction: column; gap: 32px; }

/* Divider */
.divider { width: 100%; height: 1px; background: var(--border-subtle); margin: 32px 0; }

/* ── Top nav ─────────────────────────────────────────────────────────────── */
.topnav {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: 64px;
  padding: 0 32px;
  border-bottom: 1px solid var(--border-subtle);
  background: rgb(var(--shade-rgb) / .85);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-nav);
}

/* Logo */
.nav-logo {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
  background: var(--gradient-logo);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  text-decoration: none;
  justify-self: start;
}

/* Centre link group — always perfectly centered */
.nav-links {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-self: center;
}

.nav-link {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  color: var(--text-secondary);
  text-decoration: none;
  padding: 8px 12px;
  border-radius: var(--radius-md);
  transition: var(--transition-fast);
  white-space: nowrap;
}
.nav-link:hover  { color: var(--text-primary); }
.nav-link.active { color: var(--text-primary); background: rgb(var(--ink-rgb) / .06); }
.nav-link:focus-visible {
  outline: none;
  box-shadow: none;
}

/* Right action group */
.nav-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-self: end;
}

/* Mobile hamburger (hidden on desktop) */
.nav-hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 8px;
  background: none;
  border: none;
  cursor: pointer;
  border-radius: var(--radius-md);
  transition: var(--transition-fast);
}
.nav-hamburger span {
  display: block;
  height: 2px;
  background: var(--text-secondary);
  border-radius: 2px;
  transition: var(--transition-fast);
}
.nav-hamburger:hover span { background: var(--text-primary); }

/* Mobile full-screen overlay nav */
.nav-mobile-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-nav) + 1);
  background: var(--bg-base);
  flex-direction: column;
  padding: 24px 32px;
}
.nav-mobile-overlay.is-open { display: flex; }
.nav-mobile-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 40px;
}
.nav-mobile-close {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 18px;
  transition: var(--transition-fast);
}
.nav-mobile-close:hover { color: var(--text-primary); border-color: var(--border-default); }
.nav-mobile-links {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
}
.nav-mobile-link {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
  color: var(--text-secondary);
  text-decoration: none;
  padding: 16px 0;
  border-bottom: 1px solid var(--border-subtle);
  transition: var(--transition-fast);
}
.nav-mobile-link:hover { color: var(--text-primary); }
.nav-mobile-actions {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-top: 32px;
}

/* ── Grain overlay ───────────────────────────────────────────────────────── */
.grain-overlay { position: relative; overflow: hidden; }
.grain-overlay::before {
  content: '';
  position: absolute;
  inset: -200%;
  width: 400%;
  height: 400%;
  opacity: 0.035;
  pointer-events: none;
  z-index: 0;
  filter: url(#grain);
  background: var(--ink);
  animation: grain 8s steps(10) infinite;
}

@keyframes grain {
  0%,100% { transform: translate(0,0); }
  10%      { transform: translate(-5%,-10%); }
  20%      { transform: translate(-15%,5%); }
  30%      { transform: translate(7%,-25%); }
  40%      { transform: translate(-5%,25%); }
  50%      { transform: translate(-15%,10%); }
  60%      { transform: translate(15%,0%); }
  70%      { transform: translate(0%,15%); }
  80%      { transform: translate(3%,35%); }
  90%      { transform: translate(-10%,10%); }
}

/* Ensure grain-overlay children sit above the pseudo-element */
.grain-overlay > * { position: relative; z-index: 1; }

/* ── Global animations ───────────────────────────────────────────────────── */
@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

@keyframes pulse-ring {
  0%   { transform: scale(1);   opacity: 0.6; }
  100% { transform: scale(1.6); opacity: 0; }
}

@keyframes pulse-dot {
  0%,100% { opacity: 1; }
  50%     { opacity: 0.4; }
}

/* Page entrance */
.page-enter { animation: fadeInUp 0.3s ease; }

/* Staggered card entrance via --i CSS var */
.stagger { animation: fadeInUp 0.3s ease both; animation-delay: calc(var(--i, 0) * 0.05s); }
.stagger-0 { --i: 0; }
.stagger-1 { --i: 1; }
.stagger-2 { --i: 2; }
.stagger-3 { --i: 3; }
.stagger-4 { --i: 4; }
.stagger-5 { --i: 5; }

/* ── Landing — hero ──────────────────────────────────────────────────────── */
.hero {
  min-height: 100vh;
  display: flex;
  align-items: center;
  padding: 0 96px;
  background:
     var(--bg-base);
}

.hero-inner {
  display: flex;
  align-items: center;
  gap: 64px;
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

.hero-copy { flex: 0 0 55%; }

.hero-eyebrow {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-primary-light);
  background: rgb(var(--ink-rgb) / .05);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 4px 12px;
}

.hero-headline {
  font-family: var(--font-display);
  font-size: 64px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin-top: 16px;
}
.hero-headline .line-gradient {
  color: var(--ink);
}

.hero-sub {
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--text-secondary);
  line-height: 1.7;
  max-width: 520px;
  margin-top: 24px;
}

.hero-cta-group {
  margin-top: 32px;
  max-width: 320px;
}

.hero-cta-note {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-muted);
  text-align: center;
  margin-top: 8px;
}

.hero-trust-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.trust-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-secondary);
  background: rgb(var(--ink-rgb) / .04);
  border: 1px solid var(--border-subtle);
  border-radius: 20px;
  padding: 6px 12px;
}
.trust-chip svg { color: var(--success); flex-shrink: 0; }

/* Hero mockup card */
.hero-mockup {
  flex: 1;
  display: flex;
  justify-content: center;
  overflow: visible;
}

.hero-mockup-card {
  width: 340px;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 24px;
  box-shadow: none;
  transform: rotate(-2deg);
  transition: var(--transition-base);
}
.hero-mockup-card:hover { transform: rotate(-1deg) translateY(-4px); }

.hero-mockup-header {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 16px;
}

.mockup-track-row {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 56px;
  border-bottom: 1px solid var(--border-subtle);
}
.mockup-track-row:last-of-type { border-bottom: none; }

.mockup-cover {
  width: 40px;
  height: 40px;
  border-radius: 8px;
  flex-shrink: 0;
}
.mockup-cover--violet { background: var(--surface-3); }
.mockup-cover--orange { background: linear-gradient(var(--surface-2), var(--surface-2)); }

.mockup-title {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 500;
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mockup-footer { margin-top: 16px; }

/* ── Landing — marquee strip ─────────────────────────────────────────────── */
.marquee-strip {
  height: 48px;
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-surface);
  overflow: hidden;
  display: flex;
  align-items: center;
}

.marquee-inner {
  display: flex;
  width: max-content;
  animation: marquee 20s linear infinite;
  white-space: nowrap;
}

.marquee-inner span {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-muted);
  padding: 0 24px;
}
.marquee-inner .marquee-arrow { color: var(--ink); }

/* ── Landing — how it works ──────────────────────────────────────────────── */
.how-it-works { padding: 80px 96px 96px; background: var(--bg); }
.how-it-works-heading {
  font-family: var(--font-display);
  font-size: 36px;
  font-weight: 600;
  text-align: center;
  margin-bottom: 64px;
}

.steps-row { display: flex; gap: 32px; position: relative; }

.step-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 32px;
  flex: 1;
  transition: var(--transition-base);
}
.step-card:hover {
  border-color: var(--border-default);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.step-number {
  font-family: var(--font-display);
  font-size: 48px;
  font-weight: 800;




  line-height: 1;
  color: var(--ink);
}

.step-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  margin-top: 16px;
}

.step-desc {
  font-family: var(--font-body);
  font-size: 15px;
  color: var(--text-secondary);
  margin-top: 8px;
  line-height: 1.6;
}

/* ── Landing — stats row ─────────────────────────────────────────────────── */
.stats-row {
  display: flex;
  gap: 24px;
  padding: 0 96px;
}

.stat-card-landing {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 32px;
  flex: 1;
  text-align: center;
}

.stat-card-landing .stat-value {
  font-family: var(--font-display);
  font-size: 48px;
  font-weight: 700;




  line-height: 1;
  color: var(--ink);
}

.stat-card-landing .stat-label {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-secondary);
  margin-top: 8px;
}

/* ── Landing — pricing ───────────────────────────────────────────────────── */
.pricing-section { padding: 96px; }
.pricing-heading {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 700;
  text-align: center;
}
.pricing-sub {
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--text-secondary);
  text-align: center;
  margin-top: 16px;
  margin-bottom: 48px;
}

.pricing-grid { display: flex; gap: 24px; align-items: stretch; }

.pricing-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 32px;
  flex: 1;
  display: flex;
  flex-direction: column;
}
.pricing-card--featured {
  border: 1px solid var(--line);
  box-shadow: none;
}

.pricing-tier {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
}

.pricing-price {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 800;




  margin-top: 16px;
  line-height: 1;
  color: var(--ink);
}
.pricing-period {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-muted);
  -webkit-text-fill-color: var(--text-muted);
}

.pricing-features {
  list-style: none;
  margin: 24px 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.pricing-features li {
  font-family: var(--font-body);
  font-size: 15px;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 8px;
}
.pricing-features li::before {
  content: '';
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--line);
  flex-shrink: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2322c55e'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E");
  background-size: contain;
}

/* ── Landing — footer CTA ────────────────────────────────────────────────── */
.footer-cta {
  padding: 96px;
  text-align: center;
  background: var(--bg-surface);
  border-top: 1px solid var(--border-subtle);
}
.footer-cta-heading {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 700;
}

/* ── Flash messages ─────────────────────────────────────────────────────── */
.flash-container { max-width: 820px; margin: 0.75rem auto 0; padding: 0 1.5rem; }
.flash { padding: 0.65rem 1rem; border-radius: var(--radius-sm); margin-bottom: 0.5rem; font-size: 0.875rem; }
.flash-success { background: var(--surface-2); border: 1px solid var(--line); color: var(--success); }
.flash-error   { background: var(--surface-2); border: 1px solid var(--line); color: var(--danger); }

/* ── Page header ────────────────────────────────────────────────────────── */
.page-header { text-align: center; padding: 2.5rem 1rem 1.2rem; }
.page-header h1 { font-size: 2rem; letter-spacing: -0.03em; }
.page-sub { color: var(--muted); font-size: 0.88rem; margin-top: 0.3rem; }
.header-actions { display: flex; gap: 0.5rem; justify-content: center; margin-top: 0.75rem; }

/* ── Layout helpers ─────────────────────────────────────────────────────── */
/* All page-level wrappers share the same 32px/96px vertical rhythm so every
   page opens at the same visual depth. Dashboard is the reference. */
.studio-layout, .form-page { max-width: 820px; margin: 0 auto; padding: 32px 32px 96px; display: flex; flex-direction: column; gap: 1.75rem; }
/* One source of vertical rhythm.
   This is a flex column with a `gap`, so any margin-bottom on a direct child
   ADDS to that gap rather than replacing it. Measured on a near-empty
   dashboard: a 32px gap plus .dash-attention's 24px and .growth-row's 22px
   produced 56px and 54px gutters, and 230px of a 1175px page — a fifth of it —
   was empty space between sections. The gap owns the spacing; the reset below
   makes sure nothing quietly adds to it again. */
.dashboard-layout { max-width: 960px; margin: 0 auto; padding: 28px 32px 72px; display: flex; flex-direction: column; gap: 20px; }
.dashboard-layout > * { margin-bottom: 0; }
.marketplace-layout { max-width: 1100px; margin: 0 auto; padding: 32px 32px 96px; display: grid; grid-template-columns: 220px 1fr; gap: 2rem; }
.release-layout, .analytics-layout { max-width: 820px; margin: 0 auto; padding: 32px 32px 96px; display: flex; flex-direction: column; gap: 1.75rem; }

footer { text-align: center; padding: 1.5rem; color: var(--muted); font-size: 0.8rem; border-top: 1px solid var(--border); margin-top: 2rem; }

/* ── Cards ───────────────────────────────────────────────────────────────── */
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  transition: var(--transition-base);
}
.card:hover {
  border-color: var(--border-default);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.card--flat:hover { transform: none; box-shadow: none; }
.card--elevated { background: var(--bg-elevated); }
.card--overlay  { background: var(--bg-overlay); }

.card h2 {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Step number badge (studio cards) */
.num {
  background: var(--surface-3);
  color: var(--ink);
  text-shadow: 0 1px 2px rgb(var(--shade-rgb) / .35);
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 4px;
  letter-spacing: 0.05em;
  flex-shrink: 0;
}

.hint {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.55;
}

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 14px;
  border: none;
  cursor: pointer;
  text-decoration: none;
  border-radius: var(--radius-md);
  transition: var(--transition-fast);
  white-space: nowrap;
  -webkit-user-select: none;
  user-select: none;
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.btn:focus-visible { outline: none; box-shadow: none; }
.btn:active:not(:disabled) { transform: scale(0.98); }

/* Primary */
.btn-primary {
  background: var(--accent-primary);
  color: var(--accent-ink);
  padding: 10px 20px;
  width: 100%;
}
.btn-primary:hover:not(:disabled) {
  background: var(--accent-primary-hover);
  box-shadow: var(--shadow-glow);
  transform: scale(1.01);
}

/* Gradient CTA */
.btn-gradient {
  background: var(--gradient-brand);
  color: var(--accent-ink);
  text-shadow: 0 1px 2px rgb(var(--shade-rgb) / .25);
  padding: 12px 24px;
  width: 100%;
}
.btn-gradient:hover:not(:disabled) {
  opacity: 0.88;
  box-shadow: none;
  transform: scale(1.01);
}

/* Secondary */
.btn-secondary {
  background: transparent;
  border: 1px solid var(--border-default);
  color: var(--text-primary);
  padding: 10px 20px;
}
.btn-secondary:hover:not(:disabled) {
  border-color: var(--line-control);
  color: var(--ink);
}

/* Ghost / muted */
.btn-ghost {
  background: transparent;
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  padding: 10px 20px;
}
.btn-ghost:hover:not(:disabled) {
  border-color: var(--border-default);
  color: var(--text-primary);
}

/* Danger */
.btn-danger {
  background: var(--danger);
  color: var(--ink);
  padding: 10px 20px;
}
.btn-danger:hover:not(:disabled) { opacity: 0.88; }

/* Approve / reject inline action variants */
.btn-approve {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--success-light);
  padding: 6px 16px;
  border-radius: var(--radius-sm);
}
.btn-approve:hover:not(:disabled) { background: var(--surface-2); }

.btn-reject {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--danger-light);
  padding: 6px 16px;
  border-radius: var(--radius-sm);
}
.btn-reject:hover:not(:disabled) { background: var(--surface-2); }

/* Sizes */
.btn-sm { padding: 6px 16px; font-size: 13px; width: auto; }
.btn-lg { padding: 16px 32px; font-size: 16px; }
.btn-auto { width: auto; }
.btn-full { width: 100%; }
.btn-icon {
  width: 40px;
  height: 40px;
  padding: 0;
  width: auto;
  border-radius: var(--radius-md);
}

/* ── Form elements ───────────────────────────────────────────────────────── */
label {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  color: var(--text-secondary);
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
input[type="date"],
input[type="search"],
textarea,
select {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 14px;
  padding: 10px 14px;
  outline: none;
  transition: var(--transition-fast);
  width: 100%;
}
input:focus,
textarea:focus,
select:focus {
  border-color: var(--accent-primary);
  box-shadow: none;
}
input::placeholder,
textarea::placeholder { color: var(--text-muted); }
textarea { resize: vertical; min-height: 80px; }
select option { background: var(--bg-elevated); }

.optional-tag {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 400;
}

.field-group { display: flex; flex-direction: column; gap: 8px; }
.field-row   { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

/* Toggle switch */
.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.toggle-switch {
  position: relative;
  width: 44px;
  height: 24px;
  flex-shrink: 0;
}
.toggle-switch input { opacity: 0; width: 0; height: 0; }
.toggle-slider {
  position: absolute;
  inset: 0;
  background: var(--bg-overlay);
  border: 1px solid var(--border-default);
  border-radius: 24px;
  cursor: pointer;
  transition: var(--transition-fast);
}
.toggle-slider::before {
  content: '';
  position: absolute;
  left: 3px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  background: var(--text-muted);
  border-radius: 50%;
  transition: var(--transition-fast);
}
.toggle-switch input:checked + .toggle-slider {
  background: var(--ink);
  border-color: transparent;
}
.toggle-switch input:checked + .toggle-slider::before {
  left: calc(100% - 19px);
  background: var(--ink);
}

/* ── Status pills ────────────────────────────────────────────────────────── */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  border-radius: 20px;
  padding: 4px 10px;
  white-space: nowrap;
}

.pill--waiting {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--warning-light);
}
.pill--ready {
  background: rgb(var(--ink-rgb) / .06);
  border: 1px solid var(--line);
  color: var(--accent-secondary-light);
}
.pill--released {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--success-light);
}
.pill--pending {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--warning-light);
}
.pill--error {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--danger-light);
}

/* ── Badges ──────────────────────────────────────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  border-radius: 20px;
  padding: 3px 10px;
  white-space: nowrap;
}
.badge-genre, .badge-mood {
  background: rgb(var(--ink-rgb) / .05);
  border: 1px solid var(--line);
  color: var(--accent-primary-light);
}
.badge-role {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--success-light);
}
.badge-pro {
  background: var(--surface-3);
  color: var(--ink);
  text-shadow: none;
  font-size: 11px;
}
.badge-yours {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  color: var(--text-muted);
}
/* AI detection badges */
.badge-ai-low    { background: var(--surface-2);  border: 1px solid var(--line);  color: var(--success-light); }
.badge-ai-medium { background: var(--surface-2); border: 1px solid var(--line); color: var(--warning-light); }
.badge-ai-high   { background: var(--surface-2);  border: 1px solid var(--line);  color: var(--danger-light); }

/* ── Chips (selectable pills) ────────────────────────────────────────────── */
.chip-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  padding: 10px 16px;
  border-radius: 24px;
  border: 1px solid var(--border-default);
  background: var(--bg-elevated);
  color: var(--text-secondary);
  cursor: pointer;
  transition: var(--transition-fast);
  user-select: none;
}
.chip:hover       { border-color: var(--line-control); color: var(--text-primary); }
.chip.is-selected { background: var(--ink); color: var(--bg); text-shadow: none; border-color: transparent; }

/* ── Upload zones ────────────────────────────────────────────────────────── */
.upload-row  { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.upload-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 2px dashed var(--border-default);
  border-radius: var(--radius-lg);
  padding: 40px 24px;
  cursor: pointer;
  transition: var(--transition-base);
  text-align: center;
}
.upload-zone:hover,
.upload-zone.drag-over {
  border-color: var(--line-control);
  background: rgb(var(--ink-rgb) / .03);
}
.upload-zone.has-file {
  border-color: var(--success);
  background: var(--surface-2);
  border-style: solid;
}
.upload-icon  { font-size: 40px; color: var(--text-muted); line-height: 1; }
.upload-icon svg { width: 34px; height: 34px; stroke-width: 1.5;
                   margin-left: auto; margin-right: auto; }
.upload-label {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  color: var(--text-primary);
  margin-top: 8px;
}
.upload-sub   { font-family: var(--font-body); font-size: 14px; color: var(--text-muted); }
.upload-cta   { font-family: var(--font-body); font-size: 14px; color: var(--ink); cursor: pointer; }
.file-names   { display: flex; gap: 8px; flex-wrap: wrap; }
.file-name-tag {
  background: rgb(var(--ink-rgb) / .06);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 3px 10px;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--accent-primary-light);
}

/* ── Status / result areas ───────────────────────────────────────────────── */
.status {
  padding: 12px 16px;
  border-radius: var(--radius-md);
  font-family: var(--font-body);
  font-size: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.status.loading     { background: rgb(var(--ink-rgb) / .06); border: 1px solid var(--line); color: var(--accent-primary-light); }
.status.error       { background: var(--surface-2);  border: 1px solid var(--line);  color: var(--danger-light); }
.status.success-msg { background: var(--surface-2);  border: 1px solid var(--line);  color: var(--success-light); }

.result-box {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.result-box p    { font-size: 14px; color: var(--text-muted); }
.result-actions  { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.two-col         { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.edit-summary    { font-size: 14px; color: var(--accent-primary-light) !important; font-style: italic; }
audio            { width: 100%; accent-color: var(--ink); border-radius: var(--radius-md); }
.file-picker-row { display: flex; gap: 8px; align-items: center; }
.file-picker-row select { flex: 1; }

/* ── Pipeline bar ────────────────────────────────────────────────────────── */
.pipeline-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--text-muted);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 16px 24px;
}
.pipe-step {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: 20px;
  border: 1px solid var(--border-subtle);
  background: var(--bg-surface);
  transition: var(--transition-base);
  font-family: var(--font-body);
  font-size: 13px;
}
.pipe-step.active { border-color: var(--line-control); color: var(--accent-primary-light); background: rgb(var(--ink-rgb) / .06); }
.pipe-step.done   { border-color: var(--success); color: var(--success-light); background: var(--surface-2); }
.pipe-arrow       { color: var(--border-subtle); font-size: 14px; }
.pipeline-step    { display: flex; flex-direction: column; gap: 16px; border-top: 1px solid var(--border-subtle); padding-top: 24px; margin-top: 8px; }
.pipeline-step h3 { font-family: var(--font-display); font-size: 16px; font-weight: 600; }

/* ── Modals ──────────────────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  background: rgb(var(--shade-rgb) / .7);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.modal-box {
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xl);
  padding: 32px;
  width: 100%;
  max-width: 480px;
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.modal-box--sm { max-width: 420px; }
.modal-box h3 {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
}
.modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 8px; }
.modal-box--md     { max-width: 560px; }
.modal-header-row  { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.modal-field       { display: flex; flex-direction: column; gap: 6px; }
.modal-field-label { font-size: 13px; color: var(--text-secondary); }
.modal-input {
  width: 100%; box-sizing: border-box;
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: 10px 14px;
  color: var(--text-primary);
  font-size: 14px;
}
.modal-input--textarea { resize: vertical; }
.modal-status-error   { color: var(--danger);  font-size: 13px; }
.modal-status-success { color: var(--success); font-size: 13px; }

/* ── Spotify / fans card ───────────────────────────────────────────────────── */
.sp-card {
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg); padding: 20px;
}
.sp-artist-avatar {
  width: 48px; height: 48px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
}
.sp-artist-avatar--fallback {
  width: 48px; height: 48px; border-radius: 50%; background: var(--surface-3);
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; font-weight: 700; color: var(--ink); flex-shrink: 0;
}
.sp-stats-row { display: flex; gap: 24px; flex-wrap: wrap; }
.sp-stat { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.sp-tracks-label {
  font-size: 11px; font-weight: 700; color: var(--text-muted);
  letter-spacing: .08em; text-transform: uppercase; margin: 0;
}
.sp-track-list { display: flex; flex-direction: column; gap: 0; }
.sp-track-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid var(--border-subtle);
}
.sp-track-num { font-size: 11px; color: var(--text-muted); width: 16px; text-align: center; flex-shrink: 0; }
.sp-track-thumb { width: 32px; height: 32px; border-radius: 4px; object-fit: cover; flex-shrink: 0; }
.sp-track-name { font-size: 13px; font-weight: 500; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-track-link { font-size: 11px; color: var(--text-muted); flex-shrink: 0; text-decoration: none; }
.sp-track-link:hover { color: var(--text-primary); }

/* ── Profile page ──────────────────────────────────────────────────────────── */
.profile-follow-stats {
  display: flex; gap: 20px; margin-top: 8px;
  font-family: var(--font-body); font-size: 13px; color: var(--text-muted);
}
.follow-stat-link { color: inherit; text-decoration: none; }
.follow-stat-link strong { color: var(--text-primary); }
.follow-stat-link:hover strong { text-decoration: underline; }
.profile-avatar-wrap { position: relative; flex-shrink: 0; }
.profile-avatar-img { width: 72px; height: 72px; border-radius: 50%; object-fit: cover; border: 2px solid var(--border-subtle); }
.avatar-edit-btn {
  position: absolute; bottom: 0; right: 0;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-secondary);
  transition: color .15s, border-color .15s;
}
.avatar-edit-btn:hover { color: var(--text-primary); border-color: var(--line-control); }
.verified-badge { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.verified-badge svg { display: block; }

/* ── Voxen verified badge (scalloped gradient with check) ─────────────────
   em-sized so it scales with the text beside it. Add filter-glow on hover
   for a subtle interactive feel. */
.vx-verified {
  display: inline-flex; align-items: center; justify-content: center;
  vertical-align: -0.14em;
  width: 0.78em; height: 0.78em;
  margin-left: 6px;
  flex-shrink: 0;
  filter: drop-shadow(0 1px 2px rgb(var(--shade-rgb) / .4))
          drop-shadow(0 0 10px transparent);
  transition: filter .2s ease, transform .2s ease;
}
.vx-verified svg { width: 100%; height: 100%; display: block; }
.vx-verified:hover {
  filter: drop-shadow(0 1px 2px rgb(var(--shade-rgb) / .4))
          drop-shadow(0 0 16px transparent);
  transform: scale(1.08);
}
@media (prefers-reduced-motion: reduce) {
  .vx-verified { transition: none; }
  .vx-verified:hover { transform: none; }
}
.profile-beats { margin-top: 32px; }
.profile-beats h2 { font-size: 16px; font-weight: 600; margin-bottom: 12px; }
.beats-list { display: flex; flex-direction: column; gap: 10px; }
.beat-row {
  display: flex; align-items: center; gap: 16px;
  background: var(--bg-elevated); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md); padding: 12px 16px;
}
.beat-info { flex: 1; min-width: 0; }
.beat-title { font-weight: 600; font-size: 14px; display: block; margin-bottom: 4px; }
.beat-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.beat-bpm { font-size: 12px; color: var(--text-muted); }

/* Collab status card avatar */
.collab-avatar {
  width: 44px; height: 44px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
}
.collab-avatar-fallback {
  width: 44px; height: 44px; border-radius: 50%; background: var(--surface-3);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-size: 18px; font-weight: 700;
  color: var(--ink); flex-shrink: 0;
}
.collab-link { color: var(--text-primary); text-decoration: none; }
.collab-link:hover { color: var(--ink); }
.btn-sm-pad { padding: 8px 14px; font-size: 13px; }
.claim-status-card { border-left: 3px solid var(--line); }

/* Split-sheet banners */
.split-sheet-banner {
  padding: 10px 14px; border-radius: var(--radius-md);
  background: rgb(var(--ink-rgb) / .04); border: 1px solid var(--line);
}
.split-sheet-banner--warn {
  background: var(--surface-2); border-color: var(--line);
}
.split-sheet-banner--ok {
  background: var(--surface-2); border-color: var(--line);
}

/* Tooltip trigger */
.vx-tooltip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  color: var(--text-muted); font-size: 10px; font-weight: 600;
  cursor: help; vertical-align: middle; margin-left: 4px;
  font-family: var(--font-body); position: relative;
}
/* `display: none` when hidden, not `opacity: 0`.
   An absolutely-positioned descendant still contributes to the document's
   scrollable overflow even at zero opacity, so a 220px bubble anchored to a
   15px dot near the right edge widened the whole page — the release page
   carried a permanent 2px horizontal scrollbar because of one help tooltip.
   The fade is kept with a keyframe, which does run on a display change. */
.vx-tooltip::after {
  content: attr(data-tip);
  display: none;
  position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  background: var(--bg-overlay); color: var(--text-primary);
  font-size: 12px; font-weight: 400; line-height: 1.5;
  padding: 8px 12px; border-radius: var(--radius-md);
  border: 1px solid var(--border-default);
  width: max-content; max-width: min(220px, calc(100vw - 32px));
  white-space: normal; text-align: left;
  box-shadow: var(--shadow-md); pointer-events: none;
  z-index: var(--z-tooltip);
}
.vx-tooltip:hover::after, .vx-tooltip:focus::after {
  display: block;
  animation: vx-tip-in 0.15s ease-out;
}
@keyframes vx-tip-in { from { opacity: 0 } to { opacity: 1 } }
@media (prefers-reduced-motion: reduce) {
  .vx-tooltip:hover::after, .vx-tooltip:focus::after { animation: none; }
}

/* ── Spinner ─────────────────────────────────────────────────────────────── */
@keyframes spin { to { transform: rotate(360deg); } }
.spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 2px solid var(--line);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  flex-shrink: 0;
}

/* ── Auth pages ──────────────────────────────────────────────────────────── */
.auth-page {
  min-height: 100vh;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 80px;
  padding-bottom: 96px;
  background:
     var(--bg-base);
}

/* legacy compat */
.auth-wrap {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 80px 16px 96px;
}

.auth-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  padding: 48px;
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.wide-card { max-width: 560px; }

.auth-logo {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  background: var(--gradient-logo);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  text-decoration: none;
  text-align: center;
  display: block;
  margin-bottom: 32px;
}

.auth-title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 24px;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.auth-divider {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 24px 0;
}
.auth-divider::before,
.auth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border-subtle);
}
.auth-divider span {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-muted);
}

.auth-switch {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-muted);
  text-align: center;
  margin-top: 24px;
}
.auth-switch a { color: var(--ink); }
.auth-switch a:hover { color: var(--ink); }

/* The heading and the line of explanation on the sign-in page and /welcome. */
.auth-heading {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 600;
  color: var(--text-primary);
  text-align: center;
  margin: 0 0 12px;
}

.auth-intro {
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-secondary);
  text-align: center;
  margin: 0 0 24px;
}

/* Username at sign-up (docs/adr/0016): the hint under the field, and the line
   saying which profile action brought the visitor here. */
.auth-optional { font-weight: 400; color: var(--text-muted); }
.auth-hint { font-family: var(--font-body); font-size: 12px; color: var(--text-muted); margin: -6px 0 4px; }
.auth-username-status { font-family: var(--font-body); font-size: 13px; margin: -2px 0 4px; }
.auth-username-status.is-ok { color: var(--success); }
.auth-username-status.is-bad { color: var(--danger); }
.auth-username-status.is-wait { color: var(--text-muted); }
.auth-username-suggest {
  background: none; border: 1px solid var(--border-default); border-radius: 999px;
  color: var(--text-primary); font: inherit; font-size: 12px; padding: 2px 10px; cursor: pointer;
}
.auth-pending {
  font-family: var(--font-body);
  font-size: 14px;
  margin: 0 0 16px;
  padding: 10px 12px;
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  background: var(--bg-elevated);
}

/* The consent line under Create account. Smaller than .auth-switch — it is a
   disclosure, not a call to action, and must not compete with the button
   directly above it. Kept at --text-secondary rather than --text-muted: a
   consent notice the reader cannot comfortably read is not consent. */
.auth-legal {
  font-family: var(--font-body);
  font-size: 12px;
  line-height: 1.6;
  color: var(--text-secondary);
  text-align: center;
  margin: 14px 0 0;
}
/* nowrap so "Privacy Policy" cannot break across two lines — a document name
   split mid-phrase reads as two separate links. */
.auth-legal a { color: var(--text-primary); text-decoration: underline;
                text-underline-offset: 2px; white-space: nowrap; }
.auth-legal a:hover { color: var(--accent-primary-light); }

/* Role picker */
.role-picker { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 8px; }
/* The radio stays rendered and focusable, only out of sight (the clip
   pattern, WebAIM): `display: none` took it out of the tab order, so the
   role could not be chosen from the keyboard at all. Tab reaches the
   group, the arrow keys move the choice (native radio behaviour), and the
   card beside the focused radio carries the focus ring. */
.role-option { position: relative; }
.role-option input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  opacity: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.role-option input:focus-visible + .role-card {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
.role-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  padding: 24px 16px;
  border: 2px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: var(--transition-fast);
  text-align: center;
}
.role-card:hover { border-color: var(--border-default); }
.role-option input:checked + .role-card {
  border-color: var(--accent-primary);
  background: rgb(var(--ink-rgb) / .04);
}
.role-icon { font-size: 32px; line-height: 1; }
/* These slots held an emoji glyph and were sized with font-size. An SVG is a
   box, so it needs explicit dimensions or it collapses to the 16px default. */
.role-icon svg { width: 30px; height: 30px; stroke-width: 1.5; }
.role-card strong { font-family: var(--font-display); font-size: 15px; font-weight: 600; }
.role-card small  { font-family: var(--font-body); font-size: 13px; color: var(--text-muted); }

/* ── /login and /register: one screen, no scroll ─────────────────────────────
   Create account used to be a 1,228px card under 80px of padding with the
   footer below it: two screens on a laptop. The card now centres in the space
   the footer leaves (.main-wrap is already a min-height:100vh flex column with
   the footer pushed to the bottom), the logo is a small lockup in the card's
   top-left, and the sign-up fields pair up two to a row. Measured at
   1280x720: the whole page fits with no scrollbar. */
.auth-page-body .app-shell { display: flex; flex-direction: column; }
.auth-page-body .auth-wrap { flex: 1; align-items: center; padding: 16px; }
.auth-page-body footer { margin-top: 0; padding: 10px 24px; display: flex; flex-wrap: wrap;
                         justify-content: center; column-gap: 16px; }
.auth-page-body footer p { margin: 0; }

/* The landing's lockup (mark + wordmark), top left inside the card. */
.auth-brand { display: block; align-self: flex-start; margin-bottom: 10px; }
.auth-brand-img { display: block; height: 30px; width: auto; }

/* The card holds the form only, so it needs less padding than a page card. */
.auth-page-body .auth-card { padding: 20px 32px 22px; }
.auth-page-body .auth-card--register { max-width: 560px; }
.auth-page-body .auth-form { gap: 12px; }
.auth-page-body .auth-form label { gap: 6px; }
.auth-page-body .launch-offer { font-size: 13px; line-height: 1.4; padding: 8px 12px; margin-bottom: 12px; }
.auth-page-body .auth-legal { margin-top: 4px; }

/* Two fields to a row on sign-up; one under the other on a phone. */
.auth-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.auth-field { display: flex; flex-direction: column; gap: 6px; }


/* The three roles in one row of short cards instead of a 2+1 grid of tall
   ones: same three choices and descriptions, a third of the height. */
.role-picker--compact { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-top: 4px; }
.role-picker--compact .role-card { padding: 8px; gap: 4px; border-width: 1.5px; border-radius: var(--radius-md); }
.role-picker--compact .role-icon svg { width: 20px; height: 20px; }
.role-picker--compact .role-card strong { font-size: 14px; }
.role-picker--compact .role-card small { font-size: 12px; line-height: 1.35; }

@media (max-width: 560px) {
  .auth-brand-img { height: 26px; }
  .auth-page-body .auth-wrap { padding: 12px; align-items: flex-start; }
  .auth-page-body .auth-card { padding: 20px 16px; }
  .auth-row { grid-template-columns: minmax(0, 1fr); }
  .auth-row--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  /* The global ≤768px rule stacks .role-picker one per row; these cards are
     short enough to stay three across. */
  .role-picker.role-picker--compact { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
}
/* .main-wrap pads 64px for the signed-in mobile menu button; a signed-out
   visitor has no such button, so on these pages that band was empty. */
@media (max-width: 768px) {
  .auth-page-body .main-wrap--no-nav { padding-top: 0; }
}

/* Perks row */
.perks-row { display: grid; grid-template-columns: repeat(3,1fr); gap: 16px; }
.perk {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  text-align: center;
  padding: 24px 8px;
  background: var(--bg-elevated);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-subtle);
}
.perk-icon { font-size: 28px; line-height: 1; }
.perk-icon svg { width: 26px; height: 26px; stroke-width: 1.5; }
.perk strong { font-family: var(--font-display); font-size: 13px; font-weight: 600; }
.perk small  { font-family: var(--font-body); font-size: 12px; color: var(--text-muted); }

/* Connect card pair */
.connect-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.connect-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.connect-card-name {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
}
.connect-card-benefit {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-secondary);
}

/* ── Form containers and utilities ───────────────────────────────────────── */
.form-stack  { display: flex; flex-direction: column; gap: 16px; }
.form-row    { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.form-group  { display: flex; flex-direction: column; gap: 8px; }

/* Input with inline action (e.g. search + button) */
.input-action-row {
  display: flex;
  gap: 8px;
  align-items: flex-end;
}
.input-action-row input  { flex: 1; }
.input-action-row .btn   { width: auto; flex-shrink: 0; }

/* Checkbox */
.checkbox-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-primary);
  cursor: pointer;
}
.checkbox-label input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--ink);
  flex-shrink: 0;
}

/* Filter bar */
.filter-bar {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  padding: 24px 32px;
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-surface);
}
.filter-select {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 8px 12px;
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 14px;
  width: auto;
}

/* Legacy text-input shim */
.text-input {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 10px 14px;
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 14px;
  outline: none;
  width: 100%;
  transition: var(--transition-fast);
}
.text-input:focus { border-color: var(--accent-primary); box-shadow: none; }
.date-input { background: var(--bg-elevated); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: 8px 12px; color: var(--text-primary); font-family: var(--font-body); font-size: 14px; }

/* ── Marketplace ─────────────────────────────────────────────────────────── */

/* Sidebar filters */
.filters-sidebar {
  background: var(--bg-surface);
  border-right: 1px solid var(--border-subtle);
  padding: 20px;
  position: sticky;
  top: 16px;
  /* Sizes to its content and only scrolls if it genuinely exceeds the
     viewport. The previous `top: 64px; height: calc(100vh - 64px)` assumed a
     fixed 64px top nav that this layout no longer has — it uses a left
     sidebar — so the panel was locked to a fixed box that its own content
     overflowed. That gave it a permanent inner scrollbar and cut off the
     search field at the top. */
  max-height: calc(100vh - 32px);
  overflow-y: auto;
}
.filters-heading {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 24px;
}
.filters-section { margin-bottom: 24px; }
/* Two short controls on one row. The sticky panel's height is the binding
   constraint (see marketplace.html), so a filter that fits beside another one
   is a filter that does not push the panel below the fold. minmax(0,1fr) not
   1fr: a bare 1fr track resolves to its min-content, which for a <select> is
   its longest option. */
.filters-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
                gap: 10px; align-items: end; }
.filters-label {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 8px;
  display: block;
}
.filters-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.filter-reset {
  display: block;
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--ink);
  margin-top: 24px;
  cursor: pointer;
}
.filter-reset:hover { color: var(--ink); }

/* BPM range */
.bpm-range { display: flex; align-items: center; gap: 8px; }
.bpm-range input[type="number"] { width: 72px; text-align: center; }

/* Custom range slider */
input[type="range"] {
  -webkit-appearance: none;
  width: 100%;
  height: 4px;
  border-radius: 2px;
  background: var(--bg-overlay);
  accent-color: var(--ink);
  outline: none;
  padding: 0;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--ink);
  cursor: pointer;
  box-shadow: none;
}

/* Sort row */
.sort-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
}
.sort-count {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-muted);
}
.sort-select {
  width: auto;
  padding: 8px 12px;
  font-size: 13px;
}

/* Beat/track card grid */
.beat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.track-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: var(--transition-base);
}
.track-card:hover {
  border-color: var(--border-default);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

/* Cover art area — genre colour maps */
.track-cover {
  position: relative;
  padding-bottom: 56.25%; /* 16:9 */
  overflow: hidden;
}
.track-cover-inner {
  position: absolute;
  inset: 0;
}
.track-cover--edm     { background: linear-gradient(var(--surface-2), var(--surface-2)); }
.track-cover--hiphop  { background: linear-gradient(var(--surface-2), var(--surface-2)); }
.track-cover--pop     { background: linear-gradient(var(--surface-2), var(--surface-2)); }
.track-cover--rnb     { background: linear-gradient(var(--surface-2), var(--surface-2)); }
.track-cover--indie   { background: linear-gradient(var(--surface-2), var(--surface-2)); }
.track-cover--acoustic{ background: linear-gradient(var(--surface-2), var(--surface-2)); }
.track-cover--default { background: var(--surface-3); }

.track-play-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgb(var(--shade-rgb) / .6);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  transition: var(--transition-fast);
}
.track-play-btn:hover { background: rgb(var(--shade-rgb) / .8); transform: translate(-50%,-50%) scale(1.08); }

.track-card-body { padding: 16px; flex: 1; display: flex; flex-direction: column; gap: 8px; }
.track-title {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.track-producer {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-muted);
}
.track-meta { display: flex; gap: 8px; flex-wrap: wrap; }
.track-royalty {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;




  margin-top: 4px;
  color: var(--ink);
}
.track-date { font-family: var(--font-body); font-size: 13px; color: var(--text-muted); }
.track-preview { width: 100%; margin-top: 8px; }
.track-actions  { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.btn-claim { width: auto; }

/* Old track-card-top compat */
.track-card-top { display: flex; justify-content: space-between; align-items: flex-start; }
.royalty-badge  { display: flex; flex-direction: column; align-items: flex-end; }
.royalty-pct    { font-size: 22px; font-weight: 700; color: var(--success); line-height: 1; }
.royalty-label  { font-size: 11px; color: var(--text-muted); }

/* Royalty terms box (claim modal) */
.royalty-terms {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--success);
}
.claim-actions     { display: flex; gap: 8px; }
.claim-actions .btn { width: auto; flex: 1; }

/* ── Catalog / tables ────────────────────────────────────────────────────── */
.catalog-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: 24px; }

/* Table wrapper */
.table-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.table-header-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 24px;
  background: var(--bg-elevated);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border-subtle);
}
.table-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 24px;
  border-bottom: 1px solid var(--border-subtle);
  transition: var(--transition-fast);
}
.table-row:last-child { border-bottom: none; }
.table-row:hover { background: var(--bg-elevated); }

.table-thumb {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  flex-shrink: 0;
  object-fit: cover;
}
.table-title {
  flex: 1;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.table-cell {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-secondary);
  white-space: nowrap;
}
.table-cell--earnings { color: var(--success); }
.table-cell--muted    { color: var(--text-muted); font-size: 13px; }

/* Generic data table (revenue, analytics) */
.table-wrap { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-family: var(--font-body); font-size: 14px; }
.data-table th {
  text-align: left;
  padding: 12px 16px;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border-subtle);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  background: var(--bg-elevated);
}
.data-table td { padding: 12px 16px; border-bottom: 1px solid var(--border-subtle); vertical-align: middle; color: var(--text-secondary); }
.data-table tbody tr:hover { background: var(--bg-elevated); }
.data-table tbody tr:last-child td { border-bottom: none; }

/* Track stat rows (analytics top tracks) */
.track-stat-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border-subtle);
}
.track-stat-row:last-child { border-bottom: none; }
.track-rank  { font-family: var(--font-body); font-size: 13px; color: var(--text-muted); width: 24px; text-align: center; flex-shrink: 0; }
.track-thumb { width: 40px; height: 40px; border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; background: var(--bg-elevated); }
.track-stat-info { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.track-stat-info strong { font-family: var(--font-display); font-size: 14px; font-weight: 500; }
.track-stat-info span   { font-family: var(--font-body); font-size: 13px; color: var(--text-muted); }
.popularity-bar-wrap  { display: flex; align-items: center; gap: 8px; width: 96px; }
.popularity-bar       { height: 4px; background: var(--ink); border-radius: 2px; }
.popularity-val       { font-family: var(--font-body); font-size: 12px; color: var(--text-muted); width: 24px; }

/* Shared link utility */
.link { color: var(--accent-secondary); text-decoration: none; font-family: var(--font-body); font-size: 14px; }
.link:hover { text-decoration: underline; }

/* Legacy modal compat (keep for marketplace claim flow) */
.modal-close { position: absolute; top: 16px; right: 16px; background: none; border: none; color: var(--text-muted); font-size: 22px; cursor: pointer; line-height: 1; }
.modal-close svg { width: 18px; height: 18px; }
.modal-close:hover { color: var(--text-primary); }

/* ── Dashboard ───────────────────────────────────────────────────────────── */

/* Top bar */
.dash-topbar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.dash-greeting-block { display: flex; flex-direction: column; gap: 2px; }
.dash-greeting-sub {
  font-size: 12px; font-weight: 600; letter-spacing: .12em;
  /* Was --accent-primary at 0.7 opacity: 2.81:1. The light violet at full
     opacity is 7.31:1. */
  text-transform: uppercase; color: var(--accent-primary-light);
}
.dash-greeting-name {
  position: relative;
  display: inline-block;
  font-family: var(--font-display);
  font-size: clamp(26px, 3vw, 38px);
  font-weight: 800; letter-spacing: -.03em;
  margin: 0; line-height: 1.1;
  /* Multi-stop brand gradient that continuously sweeps across the text */

  background-size: 250% 100%;


  animation: greeting-shine 6s linear infinite;
  color: var(--ink);
}
@keyframes greeting-shine {
  0%   { background-position: 100% 50%; }
  100% { background-position: -150% 50%; }
}

/* Animated gradient underline: draws in on load, then flows continuously */
.dash-greeting-cursor {
  position: absolute;
  left: 0; right: 0;
  bottom: -8px;
  height: 3px; border-radius: 3px;
  background: linear-gradient(var(--surface-2), var(--surface-2));
  background-size: 300% 100%;
  transform-origin: left center;
  box-shadow: none;
  animation:
    underline-draw .9s cubic-bezier(.2, .8, .2, 1) .2s both,
    underline-flow 5s linear 1.1s infinite;
}
@keyframes underline-draw {
  from { transform: scaleX(0); opacity: 0; }
  to   { transform: scaleX(1); opacity: 1; }
}
@keyframes underline-flow {
  0%   { background-position:   0% 50%; }
  100% { background-position: 300% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .dash-greeting-name,
  .dash-greeting-cursor { animation: none; transform: scaleX(1); opacity: 1; }
}
/* Bento stat cards row */
.dash-stats {
  display: flex;
  gap: 24px;
}
.stat-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 24px;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: var(--transition-base);
}
.stat-card:hover { border-color: var(--border-default); }
.stat-card-label {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.stat-card-value {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}
.stat-card-value--empty {
  background: none;
  -webkit-text-fill-color: var(--text-muted);
  color: var(--text-muted);
}
.stat-card-trend {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-body);
  font-size: 13px;
}
.stat-card-trend--up   { color: var(--success); }
.stat-card-trend--down { color: var(--danger); }
.stat-card-link {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
}
.stat-card-link:hover { color: var(--ink); }

/* Bento second row */
.dash-bento {
  display: flex;
  gap: 24px;
}
.dash-main-panel {
  flex: 0 0 65%;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 24px;
}
.dash-side-panel {
  flex: 1;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 24px;
}
.dash-panel-heading {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  margin-bottom: 16px;
}

/* Project rows */
.instr-list, .claims-list { display: flex; flex-direction: column; }

.instr-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 72px;
  border-bottom: 1px solid var(--border-subtle);
  transition: var(--transition-fast);
  flex-wrap: wrap;
  padding: 8px 0;
}
.instr-row:last-child { border-bottom: none; }
.instr-row:hover { background: rgb(var(--ink-rgb) / .02); margin: 0 -24px; padding: 8px 24px; }

/* Vocalist submissions panel */
.submissions-panel {
  border-top: 1px solid var(--border-subtle);
  padding: 12px 0 4px;
  margin-bottom: 4px;
  display: flex; flex-direction: column; gap: 10px;
}
.submission-row {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; padding: 8px 12px;
  background: rgb(var(--ink-rgb) / .03); border-radius: 10px;
  border: 1px solid var(--border-subtle);
}
.sub-user {
  display: flex; align-items: center; gap: 7px;
  text-decoration: none; min-width: 140px;
  transition: opacity .15s;
}
.sub-user:hover { opacity: .8; }
.sub-avatar {
  width: 28px; height: 28px; border-radius: 50%; object-fit: cover;
  border: 1px solid var(--border-subtle); flex-shrink: 0;
}
.sub-avatar--initial {
  background: var(--surface-3); display: flex; align-items: center;
  justify-content: center; font-size: 11px; font-weight: 700; color: var(--ink);
  text-shadow: 0 1px 2px rgb(var(--shade-rgb) / .35);
}
.sub-name { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.sub-verified { font-size: 11px; color: var(--ink); }

.instr-cover {
  width: 40px;
  height: 40px;
  border-radius: 8px;
  flex-shrink: 0;
  background: var(--surface-3);
}
.instr-cover--orange { background: linear-gradient(var(--surface-2), var(--surface-2)); }
.instr-cover--green  { background: linear-gradient(var(--surface-2), var(--surface-2)); }
.instr-cover--pink   { background: linear-gradient(var(--surface-2), var(--surface-2)); }

.instr-row-info { flex: 1; min-width: 160px; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
.instr-row-info strong {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.instr-row-meta {
  display: flex;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-muted);
}

.instr-status-label { font-size: 12px; color: var(--text-muted); }
.muted-text         { color: var(--text-muted); font-size: 13px; }
.date-label         { font-family: var(--font-body); font-size: 13px; color: var(--text-muted); }
.vocalist-tag       { font-family: var(--font-body); font-size: 13px; color: var(--accent-secondary); }

/* Status dots */
.status-dot              { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.status-dot-open         { background: var(--success); }
.status-dot-claimed      { background: var(--warning); }
.status-dot-mixing       { background: var(--muted); }
.status-dot-complete     { background: var(--success); }
.status-dot-vocal_uploaded { background: var(--accent-secondary); }

/* Claim rows (vocalist dashboard) */
.claim-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 0;
  border-bottom: 1px solid var(--border-subtle);
  /* The row did not wrap and .claim-info had no min-width, so a flex item
     cannot shrink below its content: at 390px the actions were laid out past
     the right edge and every vocalist dashboard scrolled 7px sideways. */
  flex-wrap: wrap;
}
.claim-row:last-child { border-bottom: none; }
.claim-info  { flex: 1 1 200px; min-width: 0; display: flex; flex-direction: column; gap: 4px; font-family: var(--font-body); font-size: 14px; }
.claim-meta  { display: flex; gap: 16px; font-family: var(--font-body); font-size: 13px; color: var(--text-muted); }
.claim-actions-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mini-player { width: 240px; max-width: 100%; }

/* Activity timeline */
.activity-timeline { display: flex; flex-direction: column; gap: 16px; }
.activity-item     { display: flex; gap: 12px; }
.activity-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ink);
  flex-shrink: 0;
  margin-top: 6px;
}
.activity-body { display: flex; flex-direction: column; gap: 2px; }
.activity-desc {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-primary);
}
.activity-time {
  font-family: var(--font-body);
  font-size: 12px;
  color: var(--text-muted);
}

/* Empty state (dashboard) */
.dash-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  text-align: center;
  gap: 16px;
}
.dash-empty-icon {
  width: 64px;
  height: 64px;
  position: relative;
}
/* Abstract CSS wave shape for empty state */
.dash-empty-icon::before,
.dash-empty-icon::after,
.dash-empty-icon span {
  content: '';
  position: absolute;
  border-radius: 50%;
  border: 2px solid var(--border-default);
}
.dash-empty-icon::before { inset: 0; }
.dash-empty-icon::after  { inset: 8px; border-color: var(--border-subtle); }
.dash-empty-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  color: var(--text-primary);
}
.dash-empty-sub {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-muted);
  max-width: 320px;
}

/* Generic empty state (used across pages) */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 64px 24px;
  text-align: center;
  gap: 16px;
  color: var(--text-muted);
}
.empty-state-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  color: var(--text-primary);
  margin-top: 8px;
}
.empty-state-sub {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--text-muted);
  max-width: 360px;
}

/* Mobile bottom nav (hidden on desktop) */
.mobile-bottom-nav {
  display: none;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 64px;
  background: var(--bg-surface);
  border-top: 1px solid var(--border-subtle);
  z-index: var(--z-nav);
}
.mobile-bottom-nav-inner {
  display: flex;
  align-items: stretch;
  height: 100%;
}
.mobile-nav-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  text-decoration: none;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 11px;
  transition: var(--transition-fast);
  min-height: 44px;
}
.mobile-nav-item svg { width: 22px; height: 22px; }
.mobile-nav-item.active { color: var(--accent-primary-light); }
@media (hover: hover) and (pointer: fine) {
  .mobile-nav-item:hover { color: var(--accent-primary-light); }
}

/* ── Profile ────────────────────────────────────────────────────────────── */
/* Profile and Settings are two tabs of one account page, so they share one
   column: the shared page container below, at one measure. Before, the profile
   centred itself in the main area while Settings sat on the shared left edge,
   and switching tabs moved the tab bar sideways by ~130px at 1440. */
.profile-page { padding-bottom: 96px; }
.profile-page, .settings-page { --page-measure: 720px; }
/* Logged out there is no sidebar to line up with: the public profile centres. */
.main-wrap--no-nav .app-shell > .profile-page { margin-left: auto; margin-right: auto; }
.profile-header { display: flex; align-items: flex-start; gap: 1.25rem; margin-bottom: 1.5rem; flex-wrap: wrap; }
.profile-avatar { width: 72px; height: 72px; border-radius: 50%; background: var(--surface-3); display: flex; align-items: center; justify-content: center; font-size: 1.8rem; font-weight: 700; color: var(--ink); flex-shrink: 0; }
.profile-meta { flex: 1; display: flex; flex-direction: column; gap: 0.4rem; }
.profile-meta h1 { font-size: 1.6rem; }
.profile-style { font-size: 0.85rem; color: var(--muted); }
.profile-bio { font-size: 0.9rem; color: var(--muted); line-height: 1.6; margin-bottom: 1.5rem; }
.profile-samples { margin-top: 1rem; }
.profile-samples h2 { font-size: 1rem; margin-bottom: 0.75rem; }
.samples-list { display: flex; flex-direction: column; gap: 0.6rem; }
.sample-row { display: flex; align-items: center; gap: 0.75rem; background: var(--surface2); border-radius: var(--radius-sm); padding: 0.6rem 0.9rem; border: 1px solid var(--border); flex-wrap: wrap; }
.sample-upload-row { display: flex; gap: 0.75rem; align-items: flex-end; flex-wrap: wrap; }
.sample-upload-row input[type="text"] { flex: 1; min-width: 180px; }

/* ── Admin ──────────────────────────────────────────────────────────────── */
.tab-row { display: flex; gap: 0.5rem; border-bottom: 1px solid var(--border); margin-bottom: 1.5rem; padding: 0 1.5rem; max-width: 960px; margin-left: auto; margin-right: auto; }
.tab { padding: 0.55rem 1rem; font-size: 0.88rem; color: var(--muted); text-decoration: none; border-bottom: 2px solid transparent; transition: all 0.15s; }
.tab:hover, .tab.active { color: var(--text); border-bottom-color: var(--accent); }
.admin-list { max-width: 960px; margin: 0 auto 4rem; padding: 0 1.5rem; display: flex; flex-direction: column; gap: 0.75rem; }
.admin-row { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 1rem 1.25rem; display: flex; flex-direction: column; gap: 0.7rem; }
.admin-row-info { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; font-size: 0.88rem; }
.admin-row-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* ── Release page ───────────────────────────────────────────────────────── */
.cover-preview { display: flex; gap: 1rem; flex-wrap: wrap; align-items: flex-start; }
.cover-img { width: 180px; height: 180px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border); }
.canvas-preview { width: 101px; height: 180px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border); }
.cover-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.cover-actions .btn { width: auto; }
.generate-cover-form { border-top: 1px solid var(--border); padding-top: 1rem; margin-top: 0.5rem; display: flex; flex-direction: column; gap: 0.9rem; }

.promo-section { display: flex; flex-direction: column; gap: 0.6rem; border-top: 1px solid var(--border); padding-top: 1rem; }
.promo-section h3 { font-size: 0.9rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
.copy-block { background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.75rem 0.9rem; display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.87rem; line-height: 1.5; }
.copy-block .btn { width: auto; align-self: flex-end; }
.reddit-post .reddit-sub { font-size: 0.78rem; color: var(--accent2); font-weight: 600; }
.reddit-post .reddit-title { font-size: 0.9rem; font-weight: 600; }

/* ── Analytics ──────────────────────────────────────────────────────────── */
.connect-card { text-align: center; }
.artist-search-row { display: flex; gap: 0.75rem; }
.artist-search-row input { flex: 1; }
.artist-search-row .btn { width: auto; }
.stats-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 1rem; }
.stat-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 1.25rem; text-align: center; display: flex; flex-direction: column; gap: 0.3rem; }
.stat-value { font-size: 2rem; font-weight: 700; color: var(--accent2); line-height: 1; }
.stat-label { font-size: 0.8rem; color: var(--muted); }
.tracks-table { display: flex; flex-direction: column; gap: 0.5rem; }
.track-stat-row { display: flex; align-items: center; gap: 0.75rem; background: var(--surface2); border-radius: var(--radius-sm); padding: 0.6rem 0.9rem; border: 1px solid var(--border); }
.track-rank { font-size: 0.8rem; color: var(--muted); width: 1.5rem; text-align: center; flex-shrink: 0; }
.track-thumb { width: 36px; height: 36px; border-radius: 4px; object-fit: cover; flex-shrink: 0; }
.track-stat-info { flex: 1; display: flex; flex-direction: column; gap: 0.1rem; font-size: 0.88rem; }
.popularity-bar-wrap { display: flex; align-items: center; gap: 0.5rem; width: 100px; }
.popularity-bar { height: 4px; background: var(--ink); border-radius: 2px; }
.popularity-val { font-size: 0.75rem; color: var(--muted); width: 2rem; }
.link { color: var(--accent2); text-decoration: none; }
.link:hover { text-decoration: underline; }

/* ── Utility ────────────────────────────────────────────────────────────── */
.hidden { display: none !important; }
.hint-inline { font-size: 0.8rem; color: var(--muted); }
.page-wrap { max-width: 1100px; margin: 0 auto; padding: 2rem 1.5rem; }
.section-title { font-size: 1.1rem; font-weight: 600; color: var(--text); }

/* ── Badge extras ───────────────────────────────────────────────────────── */
.badge-red    { background: var(--surface-2); color: var(--danger-light); border-color: var(--line); }
.badge-blue   { background: rgb(var(--ink-rgb) / .07);  color: var(--ink); border-color: var(--line); }
.badge-purple { background: rgb(var(--ink-rgb) / .07); color: var(--accent-primary-light); border-color: var(--line); }
.badge-grey   { background: rgb(var(--shade-rgb) / .12); color: var(--muted); border-color: var(--line); }
.badge-btn    { cursor: pointer; border: 1px solid; border-radius: 999px; padding: 0.2rem 0.7rem; font-size: 0.75rem; background: none; }
.badge-btn:hover { opacity: 0.85; }

/* ── Quick nav strip (producer dashboard) ───────────────────────────────── */
.quick-nav { display: flex; gap: 0.75rem; padding: 1rem 2rem; overflow-x: auto; }
.quick-nav-item { display: flex; flex-direction: column; align-items: center; gap: 0.2rem; padding: 0.75rem 1.25rem; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); text-decoration: none; color: var(--text); font-size: 0.82rem; min-width: 72px; transition: border-color 0.15s; }
.quick-nav-item:hover { border-color: var(--line-control); }
.qn-icon { font-size: 1.4rem; }
.qn-label { color: var(--muted); font-size: 0.78rem; }

/* ── Dashboard highlight section ────────────────────────────────────────── */
.dash-section-highlight { border: 1px solid var(--line); background: rgb(var(--ink-rgb) / .03); border-radius: var(--radius); padding: 1.25rem; margin-bottom: 1.5rem; }

/* ── Stars ───────────────────────────────────────────────────────────────── */
.star { color: var(--muted); font-size: 0.95rem; }
.star-on { color: var(--warning-light); }
.star-row { display: flex; align-items: center; gap: 2px; margin: 0.3rem 0; }
.star-label { font-size: 0.78rem; color: var(--muted); margin-left: 4px; }
.inline-stars { display: inline-flex; align-items: center; gap: 1px; margin-left: 4px; font-size: 0.8rem; }
.verified-badge { color: var(--accent2); font-size: 0.85rem; margin-left: 4px; cursor: help; }

/* ── Catalog grid ────────────────────────────────────────────────────────── */
.catalog-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: 1.25rem; }
.catalog-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; display: flex; flex-direction: column; }
.catalog-card.card-released { border-color: var(--line); }
.catalog-cover { height: 160px; background-size: cover; background-position: center; background-color: var(--surface2); display: flex; align-items: center; justify-content: center; }
.catalog-cover-placeholder { background: linear-gradient(135deg, var(--surface2), var(--surface-2)); }
.catalog-cover-placeholder span { font-size: 2.5rem; color: var(--muted); }
.catalog-info { padding: 1rem; display: flex; flex-direction: column; gap: 0.4rem; flex: 1; }
.catalog-title { font-weight: 600; font-size: 1rem; }
.catalog-meta { font-size: 0.82rem; color: var(--muted); }
.catalog-badges { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.25rem; }
.catalog-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: auto; padding-top: 0.75rem; border-top: 1px solid var(--border); }

/* ── Revenue page ────────────────────────────────────────────────────────── */
.rev-summary { display: flex; gap: 1rem; margin-bottom: 1.5rem; flex-wrap: wrap; }
.rev-stat { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.25rem 1.75rem; flex: 1; min-width: 140px; }
.rev-stat-value { font-size: 1.75rem; font-weight: 700; color: var(--accent2); }
.rev-stat-label { font-size: 0.8rem; color: var(--muted); margin-top: 0.25rem; }
.chart-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; margin-bottom: 1.5rem; }
.chart-title { font-size: 0.95rem; font-weight: 600; margin-bottom: 1rem; color: var(--muted); }
.table-wrap { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.data-table th { text-align: left; padding: 0.6rem 0.75rem; color: var(--muted); border-bottom: 1px solid var(--border); font-weight: 500; white-space: nowrap; }
.data-table td { padding: 0.6rem 0.75rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
.data-table tbody tr:hover { background: var(--surface2); }

/* ── Forms ───────────────────────────────────────────────────────────────── */
.form-stack { display: flex; flex-direction: column; gap: 0.85rem; }
.form-stack label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.88rem; color: var(--muted); }
.form-stack input, .form-stack select, .form-stack textarea { background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.55rem 0.75rem; color: var(--text); font-size: 0.9rem; outline: none; }
.form-stack input:focus, .form-stack select:focus, .form-stack textarea:focus { border-color: var(--accent); }
.text-input { background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.55rem 0.75rem; color: var(--text); font-size: 0.9rem; outline: none; width: 100%; }
.text-input:focus { border-color: var(--accent); }
.date-input { background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.3rem 0.5rem; color: var(--text); font-size: 0.85rem; }
.filter-bar { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; margin-bottom: 1.5rem; }
.filter-select { background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.45rem 0.75rem; color: var(--text); font-size: 0.88rem; }
.form-msg { font-size: 0.82rem; color: var(--danger); }
.checkbox-label { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; color: var(--text); cursor: pointer; }
.checkbox-label input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--ink); }

/* ── Calendar ────────────────────────────────────────────────────────────── */
.cal-controls { display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem;
                flex-wrap: wrap; }
/* Prev | month | Next belong on one line. Wrapping put "Next" alone on a
   second row, which reads as a stray button rather than as navigation. A
   three-column grid keeps them together and centres the month between them. */
@media (max-width: 560px) {
  .cal-controls {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 8px;
  }
  .cal-controls .cal-month-label { text-align: center; }
  .cal-controls .btn { padding: 8px 12px; min-width: 0; }
}
/* At 320px the two labelled buttons plus the month do not fit on one line, so
   the arrows carry it alone — the month name between them says which way each
   one goes. */
@media (max-width: 380px) {
  .cal-controls .btn { padding: 8px; }
  .cal-controls .btn span:not(.vx-icon) { display: none; }
  .cal-controls #cal-prev, .cal-controls #cal-next { font-size: 0; }
  .cal-controls #cal-prev svg, .cal-controls #cal-next svg { font-size: 1rem; }
}
.cal-month-label { font-weight: 600; font-size: 1rem; min-width: 160px; text-align: center; }
/* minmax(0,…) not 1fr: a bare 1fr track floors at MIN-CONTENT, so seven
   day cells could not shrink below their widest label and the month pushed
   the page sideways on a phone. The same fault, and the same fix, as the
   admin stat grids. */
.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.cal-day-hdr { text-align: center; font-size: 0.75rem; color: var(--muted); padding: 0.3rem 0; }
.cal-cell { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); min-height: 72px; padding: 0.4rem; font-size: 0.78rem; position: relative; }
.cal-cell-empty { background: transparent; border-color: transparent; }
.cal-today { border-color: var(--line-control); }
.cal-day-num { display: block; color: var(--muted); font-size: 0.8rem; margin-bottom: 2px; }
.cal-event { background: rgb(var(--ink-rgb) / .08); color: var(--accent2); border-radius: 3px; padding: 1px 4px; font-size: 0.7rem; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ai-rec-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; margin-bottom: 1.75rem; }
.ai-rec-form { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.75rem; }
.ai-rec-form input, .ai-rec-form select { flex: 1; min-width: 160px; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.55rem 0.75rem; color: var(--text); font-size: 0.9rem; }
.ai-rec-result { background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 1rem 1.25rem; margin-top: 1rem; font-size: 0.9rem; line-height: 1.7; white-space: pre-wrap; }

/* ── Sync catalog ────────────────────────────────────────────────────────── */
.sync-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: 1.25rem; }
.sync-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.sync-cover { height: 180px; background-size: cover; background-position: center; background-color: var(--surface2); display: flex; align-items: center; justify-content: center; position: relative; cursor: pointer; }
.sync-cover-placeholder { background: linear-gradient(135deg,var(--surface-2),var(--bg)); }
.sync-play-overlay { font-size: 2rem; color: var(--ink); }
.sync-info { padding: 1rem; }
.sync-title { font-weight: 600; }
.sync-artist { font-size: 0.85rem; color: var(--muted); margin-bottom: 0.5rem; }
.sync-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 0.75rem; }
.tag { background: var(--surface2); border: 1px solid var(--border); border-radius: 999px; padding: 0.15rem 0.6rem; font-size: 0.75rem; color: var(--muted); }
.tag-mood { border-color: var(--line); color: var(--accent2); }
.sync-card-actions { margin-top: 0.5rem; }

/* ── Smart link / pre-save page ─────────────────────────────────────────── */
.smart-link-page { background: linear-gradient(160deg, var(--bg) 0%, var(--surface-1) 100%); }
.smart-link-wrap { max-width: 480px; margin: 0 auto; padding: 3rem 1.5rem; text-align: center; }
.sl-cover-wrap { margin-bottom: 1.5rem; }
.sl-cover { width: 280px; height: 280px; border-radius: var(--radius); object-fit: cover; box-shadow: 0 24px 48px rgb(var(--shade-rgb) / .6); }
.sl-cover-placeholder { background: linear-gradient(135deg, var(--surface2), var(--surface-2)); display: inline-flex; align-items: center; justify-content: center; font-size: 4rem; color: var(--muted); }
.sl-info { margin-bottom: 1.75rem; }
.sl-title { font-size: 1.75rem; font-weight: 700; margin-bottom: 0.25rem; }
.sl-artist { font-size: 1rem; color: var(--muted); }
.sl-artist-link { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.sl-genre { font-size: 0.85rem; color: var(--muted); margin-top: 0.25rem; }
/* Hear it. Sits between the title and the platform buttons because that is the
   order a fan wants: what is this, what does it sound like, where do I get it. */
.sl-preview { margin-bottom: 1.5rem; }
.sl-links { margin-bottom: 2rem; display: flex; flex-direction: column; gap: 0.75rem; }
.sl-platform-btn { display: flex; align-items: center; justify-content: center; gap: 0.5rem; padding: 0.85rem 1.5rem; border-radius: var(--radius); text-decoration: none; font-weight: 600; font-size: 0.95rem; transition: opacity 0.15s; }
.sl-platform-btn:hover { opacity: 0.88; }
.sl-spotify { background: var(--success); color: var(--accent-ink); }
.sl-coming-soon { padding: 0.75rem; }
.sl-presave-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; }
.sl-presave-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.3rem; }
.sl-presave-sub { font-size: 0.88rem; color: var(--muted); margin-bottom: 1rem; }
.sl-presave-form { display: flex; gap: 0.5rem; }
.sl-presave-form input { flex: 1; }
.sl-presave-msg { padding: 0.75rem; border-radius: var(--radius-sm); font-size: 0.9rem; }
.sl-success { background: var(--surface-2); color: var(--success); border: 1px solid var(--line); }
.sl-error   { background: var(--surface-2); color: var(--danger); border: 1px solid var(--line); }
.sl-fan-count { font-size: 0.82rem; color: var(--muted); margin-top: 0.75rem; }

/* ── Fans page ───────────────────────────────────────────────────────────── */
.fans-header { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }
.fans-title { font-size: 1.2rem; font-weight: 600; }
.fans-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* ── Empty states ────────────────────────────────────────────────────────── */
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--muted); }
.empty-icon { font-size: 3rem; margin-bottom: 0.75rem; }
/* These slots were sized for an emoji glyph; an SVG has to be sized as a
   box, not a font. Kept to the same optical weight as the glyph it replaced. */
.empty-icon svg { width: 44px; height: 44px; stroke-width: 1.5; opacity: 0.55;
                  margin-left: auto; margin-right: auto; }
.empty-state h2 { font-size: 1.1rem; margin-bottom: 0.5rem; color: var(--text); }
.empty-state p { font-size: 0.9rem; max-width: 380px; margin: 0 auto 1rem; }

/* ── AI detection result ─────────────────────────────────────────────────── */
.detection-result { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 1rem; border-radius: var(--radius-sm); margin-bottom: 0.5rem; }
.detect-green  { background: var(--surface-2);  border: 1px solid var(--line); }
.detect-yellow { background: var(--surface-2);  border: 1px solid var(--line); }
.detect-red    { background: var(--surface-2); border: 1px solid var(--line); }
.detect-score  { font-size: 1.75rem; font-weight: 700; }
.detect-green  .detect-score { color: var(--success); }
.detect-yellow .detect-score { color: var(--warn); }
.detect-red    .detect-score { color: var(--danger); }
.detect-label  { font-size: 0.88rem; color: var(--muted); }

/* ── Mood chips ──────────────────────────────────────────────────────────── */
.mood-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.4rem; }
.mood-chip { background: var(--surface2); border: 1px solid var(--border); border-radius: 999px; padding: 0.25rem 0.75rem; font-size: 0.82rem; color: var(--muted); cursor: pointer; transition: all 0.15s; }
.mood-chip:hover { border-color: var(--line-control); color: var(--text); }
.mood-chip-on { background: rgb(var(--ink-rgb) / .08); border-color: var(--line-control); color: var(--accent2); }

/* ── Release badges strip ────────────────────────────────────────────────── */
.release-badges { display: flex; flex-wrap: wrap; gap: 0.4rem; }

/* ── PRO / generic modal ─────────────────────────────────────────────────── */
.modal-backdrop { position: fixed; inset: 0; background: rgb(var(--shade-rgb) / .7); z-index: 200; display: flex; align-items: center; justify-content: center; padding: 1rem; overflow-y: auto; }
.modal-backdrop > .modal-box { position: relative; max-height: calc(100vh - 2rem); overflow-y: auto; overscroll-behavior: contain; }
.modal-box { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 2rem; max-width: 520px; width: 100%; }
.modal-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 0.75rem; }
.modal-body  { font-size: 0.9rem; color: var(--muted); line-height: 1.7; }
.modal-list  { list-style: none; display: flex; flex-direction: column; gap: 0.4rem; margin-top: 0.75rem; font-size: 0.9rem; }
.modal-list a { color: var(--accent2); text-decoration: none; }
.modal-list a:hover { text-decoration: underline; }
.modal-actions { display: flex; gap: 0.75rem; margin-top: 1.25rem; flex-wrap: wrap; }

/* ── Signal AI chat widget ───────────────────────────────────────────────── */
.signal-widget { position: fixed; bottom: 1.5rem; right: 1.5rem; z-index: 500; display: flex; flex-direction: column; align-items: flex-end; gap: 0.5rem; }
.signal-toggle { display: flex; align-items: center; gap: 0.5rem; background: linear-gradient(135deg, var(--surface-3), var(--accent2)); color: var(--ink); border: none; border-radius: 999px; padding: 0.65rem 1.1rem; font-size: 0.88rem; font-weight: 600; cursor: pointer; box-shadow: none; transition: transform 0.15s; }
.signal-toggle:hover { transform: scale(1.04); }
.signal-icon { font-size: 1.1rem; }
.signal-panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 8px 32px rgb(var(--shade-rgb) / .5); width: 340px; max-height: 500px; flex-direction: column; overflow: hidden; }
.signal-header { display: flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); background: var(--surface2); }
.signal-header-name { font-weight: 700; font-size: 0.92rem; flex: 1; }
.signal-header-sub  { font-size: 0.75rem; color: var(--muted); }
.signal-close { background: none; border: none; color: var(--muted); cursor: pointer; font-size: 0.95rem; padding: 0.1rem 0.3rem; }
.signal-close svg { width: 14px; height: 14px; }
.signal-close:hover { color: var(--text); }
.signal-messages { flex: 1; overflow-y: auto; padding: 0.75rem; display: flex; flex-direction: column; gap: 0.5rem; min-height: 200px; }
.signal-msg { max-width: 88%; padding: 0.55rem 0.8rem; border-radius: var(--radius-sm); font-size: 0.85rem; line-height: 1.55; }
.signal-msg-user { background: rgb(var(--ink-rgb) / .08); align-self: flex-end; color: var(--text); }
.signal-msg-bot  { background: var(--surface2); align-self: flex-start; color: var(--text); border: 1px solid var(--border); }
.signal-input-row { display: flex; gap: 0.4rem; padding: 0.6rem 0.75rem; border-top: 1px solid var(--border); }
.signal-input { flex: 1; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.45rem 0.65rem; color: var(--text); font-size: 0.85rem; outline: none; }
.signal-input:focus { border-color: var(--accent); }

/* ── AI job row ──────────────────────────────────────────────────────────── */
.ai-job-row { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; padding: 0.75rem 0; border-bottom: 1px solid var(--border); }
.ai-job-info { flex: 1; }
.ai-job-info strong { display: block; }

/* ── card-title / card-sub helpers ──────────────────────────────────────── */
.card-title { font-size: 1rem; font-weight: 600; margin-bottom: 0.25rem; }
.card-sub { font-size: 0.85rem; color: var(--muted); margin-bottom: 0.75rem; }

/* ── btn-block ───────────────────────────────────────────────────────────── */
.btn-block { display: block; width: 100%; text-align: center; }

/* ── link-subtle ─────────────────────────────────────────────────────────── */
.link-subtle { color: inherit; text-decoration: none; }
.link-subtle:hover { color: var(--accent2); }

/* ── Validation and field states ─────────────────────────────────────────── */

/* Error field */
input.is-error, textarea.is-error, select.is-error {
  border-color: var(--danger) !important;
  box-shadow: none;
}
/* Success field */
input.is-success, textarea.is-success, select.is-success {
  border-color: var(--success) !important;
  box-shadow: none;
}
/* Disabled field */
input:disabled, textarea:disabled, select:disabled, .btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Help / hint text below inputs */
.field-help {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-muted);
  margin-top: 4px;
}
.field-error {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--danger);
  margin-top: 4px;
}
.field-success {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--success);
  margin-top: 4px;
}

/* Flash / toast messages */
.flash-container { max-width: 800px; margin: 16px auto 0; padding: 0 32px; }
.flash {
  padding: 12px 16px;
  border-radius: var(--radius-md);
  margin-bottom: 8px;
  font-family: var(--font-body);
  font-size: 14px;
}
.flash-success { background: var(--surface-2);  border: 1px solid var(--line);  color: var(--success-light); }
.flash-error   { background: var(--surface-2);  border: 1px solid var(--line);  color: var(--danger-light); }

/* Form-level message */
.form-msg { font-family: var(--font-body); font-size: 13px; color: var(--danger); margin-top: 4px; }

/* AI detection result card */
.detection-result {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px;
  border-radius: var(--radius-lg);
  border-width: 2px;
  border-style: solid;
  margin-bottom: 8px;
}
.detect-green  { background: var(--surface-2);  border-color: var(--line); }
.detect-yellow { background: var(--surface-2); border-color: var(--line); }
.detect-red    { background: var(--surface-2);  border-color: var(--line); }
.detect-score  { font-family: var(--font-display); font-size: 28px; font-weight: 700; line-height: 1; }
.detect-green  .detect-score { color: var(--success-light); }
.detect-yellow .detect-score { color: var(--warning-light); }
.detect-red    .detect-score { color: var(--danger-light); }
.detect-label  { font-family: var(--font-body); font-size: 14px; color: var(--text-secondary); }

/* ── Utility carry-forwards ──────────────────────────────────────────────── */
.hidden       { display: none !important; }
.hint-inline  { font-family: var(--font-body); font-size: 13px; color: var(--text-muted); }
.page-wrap    { max-width: 1100px; margin: 0 auto; padding: 32px 32px 96px; }
.section-title { font-family: var(--font-display); font-size: 18px; font-weight: 600; color: var(--text-primary); }
.btn-block    { display: block; width: 100%; text-align: center; }
.link-subtle  { color: inherit; text-decoration: none; }
.link-subtle:hover { color: var(--accent-secondary); }

/* Badge colour extras */
.badge-red    { background: var(--surface-2);   border: 1px solid var(--line);   color: var(--danger-light); }
.badge-blue   { background: rgb(var(--ink-rgb) / .06);  border: 1px solid var(--line);  color: var(--ink); }
.badge-purple { background: rgb(var(--ink-rgb) / .06); border: 1px solid var(--line); color: var(--accent-primary-light); }
.badge-grey   { background: rgb(var(--shade-rgb) / .1); border: 1px solid var(--line);  color: var(--muted); }
.badge-btn    { cursor: pointer; border: 1px solid; border-radius: 999px; padding: 3px 10px; font-size: 12px; background: none; }
.badge-btn:hover { opacity: 0.85; }

/* Stars */
.star    { color: var(--text-muted); }
.star-on { color: var(--warning-light); }
.star-row   { display: flex; align-items: center; gap: 2px; }
.star-label { font-family: var(--font-body); font-size: 13px; color: var(--text-muted); margin-left: 4px; }
.inline-stars   { display: inline-flex; align-items: center; gap: 1px; margin-left: 4px; }
.verified-badge { color: var(--accent-secondary); margin-left: 4px; cursor: help; }

/* Footer */
footer {
  text-align: center;
  padding: 18px 32px;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 13px;
  border-top: 1px solid var(--border-subtle);
  /* 64px of margin on top of 24px of padding put 134px of nothing at the
     bottom of every page, which was enough on its own to push three pages
     (marketplace, revenue, fans) over the fold by under 50px each. */
  margin-top: 24px;
}

/* Page header — no top pad; outer wrapper (.page-wrap / .dashboard-layout /
   .app-shell first-child rule) provides the 32px top rhythm so all pages line
   up at the same vertical depth. */
/* Every page opens with this block, so its padding is multiplied across the
   whole product. 32px above plus 24px below a two-line header put 56px of
   nothing at the top of every screen; 20/16 keeps the same rhythm and buys
   back the last few pixels that pushed revenue and fans over the fold. */
.page-header        { text-align: center; padding: 0 16px 16px; }
.page-header h1     { font-family: var(--font-display); font-size: 32px; font-weight: 700; letter-spacing: -0.02em; }
.page-sub           { color: var(--text-muted); font-family: var(--font-body); font-size: 14px; margin-top: 8px; }
.header-actions     { display: flex; gap: 8px; justify-content: center; margin-top: 16px; }

/* ── Responsive — tablet (≤ 1024px) ─────────────────────────────────────── */
@media (max-width: 1024px) {
  .hero               { padding: 0 48px; }
  .hero-headline      { font-size: 48px; }
  .section            { padding: 64px 48px; }
  .section--sm        { padding: 48px 48px; }
  .stats-row          { padding: 0 48px; }
  .pricing-section    { padding: 64px 48px; }
  .how-it-works       { padding: 64px 48px; }
  .footer-cta         { padding: 64px 48px; }
  .beat-grid          { grid-template-columns: repeat(2,1fr); }
  .dash-bento         { flex-direction: column; }
  .dash-main-panel,
  .dash-side-panel    { flex: none; width: 100%; }
  .panel-60-40        { gap: 40px; }
}

/* ── Responsive — mobile (≤ 768px) ──────────────────────────────────────── */
@media (max-width: 768px) {
  /* Nav */
  .nav-links          { display: none; }
  .nav-actions        { display: none; }
  .nav-hamburger      { display: flex; }
  .topnav             { padding: 0 16px; }

  /* Mobile bottom nav appears */
  .mobile-bottom-nav  { display: flex; }
  .app-shell          { padding-bottom: 64px; }

  /* Hero */
  .hero               { padding: 80px 16px 64px; min-height: auto; padding-top: 96px; }
  .hero-inner         { flex-direction: column; gap: 48px; }
  .hero-headline      { font-size: 40px; }
  .hero-sub           { font-size: 15px; }
  .hero-cta-group     { max-width: 100%; }
  .hero-mockup        { width: 100%; }
  .hero-mockup-card   { width: 100%; transform: none; }

  /* Sections */
  .section            { padding: 64px 16px; }
  .section--sm        { padding: 48px 16px; }
  .how-it-works       { padding: 64px 16px; }
  .stats-row          { padding: 0 16px; flex-direction: column; }
  .pricing-section    { padding: 64px 16px; }
  .pricing-grid       { flex-direction: column; }
  .footer-cta         { padding: 64px 16px; }
  .footer-cta-heading { font-size: 28px; }
  .steps-row          { flex-direction: column; }

  /* Layout */
  .page-container,
  .page-container--narrow,
  .page-container--wide { padding: 16px 16px 80px; }
  .panel-60-40,
  .panel-50-50,
  .panel-40-60        { flex-direction: column; gap: 24px; }
  .sidebar-layout     { grid-template-columns: 1fr; }
  .marketplace-layout { grid-template-columns: 1fr; }
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .beat-grid          { grid-template-columns: 1fr; }
  .connect-cards      { grid-template-columns: 1fr; }
  .field-row, .form-row { grid-template-columns: 1fr; }
  .upload-row         { grid-template-columns: 1fr; }
  .dash-bento         { flex-direction: column; }

  /* Cards */
  .card               { padding: 16px; }
  .auth-card          { padding: 24px; border-radius: var(--radius-lg); }

  /* Tables */
  .table-header-row   { display: none; }

  /* Typography scale-down */
  .text-display,
  .hero-headline      { font-size: 40px; }
  h1, .text-h1        { font-size: 32px; }
  h2, .text-h2        { font-size: 28px; }

  /* All CTA buttons full width */
  .btn-gradient,
  .btn-primary        { width: 100%; }
  .btn-auto           { width: auto; }

  /* Filters sidebar becomes bottom sheet trigger */
  .filters-sidebar    { display: none; }

  /* Signal widget */
  .signal-panel       { width: calc(100vw - 32px); right: 16px; }

  /* Misc */
  .perks-row          { grid-template-columns: 1fr; }
  .role-picker        { grid-template-columns: 1fr; }
  .catalog-grid,
  .sync-grid          { grid-template-columns: 1fr; }
  .sl-presave-form    { flex-direction: column; }
  .cal-grid           { font-size: 11px; }
  .stats-grid         { grid-template-columns: 1fr 1fr; }
  .quick-nav          { gap: 8px; padding: 16px; }
}

/* ── Responsive — small mobile (≤ 480px) ────────────────────────────────── */
@media (max-width: 480px) {
  .hero-headline    { font-size: 32px; }
  .hero-trust-chips { flex-direction: column; align-items: flex-start; }
  .auth-card        { padding: 24px 16px; }
  .pricing-card     { padding: 24px; }
  .step-card        { padding: 24px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SIDE NAVIGATION
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --sn-w:  220px;
  --sn-cw:  64px;
  /* add missing alias used in templates */
  --bg-panel: var(--surface-1);
  --bg-panel-elevated: var(--surface-2);
}

/* Sidenav container */
.sidenav {
  position: fixed; left: 0; top: 0;
  width: var(--sn-w); height: 100vh;
  background: var(--bg-surface);
  border-right: 1px solid var(--border-subtle);
  z-index: 150;
  display: flex; flex-direction: column;
  overflow: hidden;
  transition: width .25s ease;
}
.sidenav.sn-c { width: var(--sn-cw); }

/* Header */
.sn-top {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 14px;
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0; min-height: 72px;
}
.sidenav.sn-c .sn-top { justify-content: center; padding: 16px 0; }

.sn-logo {
  text-decoration: none; white-space: nowrap;
  display: flex; align-items: center;
  opacity: 1; transition: opacity .15s;
}
.sn-logo svg { display: block; }
.sn-logo-img { height: 44px; width: auto; display: block; }
.sidenav.sn-c .sn-logo { opacity: 0; width: 0; overflow: hidden; pointer-events: none; }

.sn-toggle {
  width: 26px; height: 26px;
  border: 1px solid var(--border-subtle); border-radius: 6px;
  background: none; cursor: pointer;
  color: var(--text-muted);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; transition: color .15s, border-color .15s;
}
@media (hover: hover) and (pointer: fine) {
  .sn-toggle:hover { color: var(--text-primary); border-color: var(--border-default); }
}
.sn-toggle svg { transition: transform .25s ease; }
.sidenav.sn-c .sn-toggle svg { transform: rotate(180deg); }

/* Nav scroll area */
.sn-nav {
  flex: 1; overflow-y: auto; overflow-x: hidden;
  padding: 8px 0; scrollbar-width: none;
}
.sn-nav::-webkit-scrollbar { display: none; }

/* Nav items */
.sn-item {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 12px; margin: 2px 8px;
  border-radius: 8px;
  color: var(--text-secondary); text-decoration: none;
  font-size: 13px; font-weight: 500; white-space: nowrap;
  transition: color .15s, background .15s;
  width: calc(100% - 16px);
}
@media (hover: hover) and (pointer: fine) {
  .sn-item:hover { color: var(--text-primary); background: rgb(var(--ink-rgb) / .05); }
}
/* --accent-primary-light, not --accent-primary: #8b5cf6 on the tinted active
   background measures 4.2:1, under AA for 13-21px text; #a78bfa is 6.4:1. */
.sn-item.active { color: var(--accent-primary-light); background: rgb(var(--ink-rgb) / .06); }
.sn-item svg { width: 16px; height: 16px; flex-shrink: 0; }
.sn-item-accent { color: var(--accent-primary-light); }
@media (hover: hover) and (pointer: fine) {
  .sn-item-accent:hover { background: rgb(var(--ink-rgb) / .06); }
}

.sn-lbl { overflow: hidden; opacity: 1; transition: opacity .15s; font-size: 13px; }
.sidenav.sn-c .sn-lbl { opacity: 0; width: 0; }
.sidenav.sn-c .sn-item { justify-content: center; padding: 8px; margin: 2px 4px; width: calc(100% - 8px); gap: 0; }

/* Unread badge on messages item */
.sn-badge {
  margin-left: auto; background: var(--ink); color: var(--ink);
  border-radius: 10px; font-size: 10px; font-weight: 700;
  padding: 1px 6px; min-width: 18px; text-align: center;
}
.sidenav.sn-c .sn-badge { display: none !important; }

/* Section divider (legacy) */
.sn-div { height: 1px; background: var(--border-subtle); margin: 6px 12px; }
.sidenav.sn-c .sn-div { margin: 6px 6px; }

/* Section label */
.sn-sec {
  display: flex; align-items: center; gap: 8px;
  padding: 14px 14px 4px;
  font-size: 10px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-muted);
  overflow: hidden; white-space: nowrap;
}
.sn-sec::after {
  content: ''; flex: 1; height: 1px;
  background: var(--border-subtle); min-width: 0;
}
.sidenav.sn-c .sn-sec { padding: 10px 0 2px; justify-content: center; }
.sidenav.sn-c .sn-sec::after { display: none; }
.sidenav.sn-c .sn-sec .sn-lbl { display: none; }

/* Footer */
.sn-footer { flex-shrink: 0; border-top: 1px solid var(--border-subtle); padding: 6px 0; }

/* ── Main content wrapper ──────────────────────────────────────────────────── */
.main-wrap {
  margin-left: var(--sn-w);
  min-height: 100vh;
  display: flex; flex-direction: column;
  transition: margin-left .25s ease;
}
body.sn-collapsed .main-wrap { margin-left: var(--sn-cw); }
.main-wrap--no-nav { margin-left: 0 !important; }
/* min-height:100vh on the shell fights the sticky-footer layout it sits in:
   .main-wrap is already min-height:100vh and a flex column, so a shell that
   insists on a full viewport plus a 70px footer guarantees a 70px scrollbar
   with nothing in it on every short page. `flex: 1` already grows the shell to
   fill whatever the footer leaves. */
.main-wrap .app-shell { padding-top: 0 !important; flex: 1; min-height: 0; }
.main-wrap footer { margin-top: auto; }

/* Messages is the one full-height page, so it has to subtract the section tab
   bar explicitly or its bottom runs off the screen. The value is measured and
   published by script in base.html; this is the no-JS fallback. */
:root { --sec-tabs-h: 80px; --app-footer-h: 70px; }
.msg-layout {
  height: calc(100vh - var(--sec-tabs-h) - var(--app-footer-h)) !important;
}
/* Below 640px the page stacks the conversation list above the thread and sizes
   itself, so a fixed viewport height must not apply — the `!important` above
   was overriding that `height: auto` and collapsing the list out of view,
   leaving a phone with only the empty right-hand pane. */
@media (max-width: 640px) {
  .msg-layout { height: auto !important; }
}

/* ── Auth pages — account for sidenav left offset ─────────────────────────── */
.auth-page { padding-top: 40px; }

/* ── Flash messages spacing ──────────────────────────────────────────────── */
.flash-container { padding-top: 16px; }

/* ── Mobile: hide sidenav ─────────────────────────────────────────────────── */
@media (max-width: 768px) {
  .sidenav { display: none; }
  .main-wrap { margin-left: 0 !important; }
}

/* ── Social links on profile ─────────────────────────────────────────────── */
.profile-socials {
  display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 1.5rem;
}
.social-link {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  text-decoration: none;
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary); background: var(--bg-elevated);
  transition: border-color .15s, color .15s, background .15s;
}
.social-link svg { width: 18px; height: 18px; flex-shrink: 0; }
.social-link:hover { background: var(--bg-surface); }
.social-spotify:hover   { color: var(--success); border-color: var(--line); }
.social-instagram:hover { color: var(--ink); border-color: var(--line); }
.social-tiktok:hover    { color: var(--ink); border-color: var(--line); }
.social-twitter:hover   { color: var(--ink); border-color: var(--line); }
.social-youtube:hover   { color: var(--error); border-color: var(--line); }
.social-soundcloud:hover{ color: var(--warning); border-color: var(--line); }

/* ── Custom Audio Player ─────────────────────────────────────────────────── */
.vx-player {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  min-width: 0;
  max-width: 420px;
  font-family: var(--font-body);
  width: 100%;
}
.vx-player-play {
  width: 36px; height: 36px; min-width: 36px;
  border-radius: 50%;
  background: var(--gradient-brand);
  border: none; color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: transform 0.15s ease;
  padding-left: 2px;
  text-shadow: 0 1px 2px rgb(var(--shade-rgb) / .25);
}
.vx-player-play:hover { transform: scale(1.05); }
.vx-player-play:active { transform: scale(0.95); }
.vx-player-play.playing { padding-left: 0; }
.vx-player-play:focus-visible { outline: 2px solid var(--accent-hot); outline-offset: 2px; }
.vx-player-waveform {
  flex: 1; height: 32px;
  position: relative; cursor: pointer;
  border-radius: 4px; overflow: hidden; min-width: 0;
}
.vx-player-waveform:focus-visible { outline: 2px solid var(--accent-hot); outline-offset: 2px; }
.vx-player-canvas { width: 100%; height: 100%; display: block; }
.vx-player-progress {
  position: absolute; top: 0; left: 0; height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--accent-a20) 0%, var(--pink-a20) 50%, var(--cyan-a20) 100%);
  pointer-events: none;
  transition: width 0.1s linear;
}
.vx-player-loading {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--pink-a20), transparent);
  background-size: 200% 100%;
  animation: vx-shimmer 1.2s infinite;
}
@keyframes vx-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.vx-player-error {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; color: var(--danger);
  background: var(--surface-2);
}
.vx-player-time {
  font-size: 12px; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  display: flex; gap: 3px; white-space: nowrap; min-width: 68px;
}
.vx-player-divider { opacity: 0.45; }
@media (max-width: 640px) {
  .vx-player { padding: 8px 10px; gap: 8px; }
  .vx-player-time { min-width: 58px; font-size: 11px; }
}

/* ── Toast notifications ─────────────────────────────────────────────────── */
#vx-toast-container {
  position: fixed; top: 20px; right: 20px; z-index: 2000;
  display: flex; flex-direction: column; gap: 8px;
  pointer-events: none; max-width: calc(100% - 40px);
}
.vx-toast {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 14px 18px;
  box-shadow: 0 12px 32px rgb(var(--shade-rgb) / .4);
  font-family: var(--font-body); font-size: 14px; color: var(--text-primary);
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: 10px;
  min-width: 260px; max-width: 420px;
  animation: vx-toast-in 0.25s ease;
}
@keyframes vx-toast-in  { from { transform: translateX(20px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes vx-toast-out { from { transform: translateX(0); opacity: 1; } to { transform: translateX(20px); opacity: 0; } }
.vx-toast.success { border-left: 3px solid var(--success); }
.vx-toast.error   { border-left: 3px solid var(--danger); }
.vx-toast.info    { border-left: 3px solid var(--line); }
.vx-toast-close {
  background: transparent; border: none; color: var(--text-muted);
  cursor: pointer; font-size: 16px; line-height: 1; margin-left: auto; padding: 0;
}
.vx-toast-close svg { width: 14px; height: 14px; }
@media (hover: hover) and (pointer: fine) {
  .vx-toast-close:hover { color: var(--text-primary); }
}

/* ── Loading overlay ─────────────────────────────────────────────────────── */
.vx-overlay {
  position: fixed; inset: 0;
  background: rgb(var(--shade-rgb) / .82);
  backdrop-filter: blur(4px);
  z-index: 1500;
  display: flex; align-items: center; justify-content: center;
  flex-direction: column; gap: 20px;
  color: var(--text-primary); font-family: var(--font-body);
}
.vx-overlay-spinner {
  width: 48px; height: 48px; border-radius: 50%;
  background: conic-gradient(from 0deg, transparent, var(--ink), transparent);
  animation: vx-spin 1.2s linear infinite;
  -webkit-mask: radial-gradient(circle at center, transparent 16px, black 18px);
  mask: radial-gradient(circle at center, transparent 16px, black 18px);
}
@keyframes vx-spin { to { transform: rotate(360deg); } }
.vx-overlay-text  { font-size: 16px; color: var(--text-secondary); text-align: center; max-width: 320px; }
.vx-overlay-step  { font-size: 13px; color: var(--text-muted); }

@media (max-width: 640px) {
  #vx-toast-container { top: 12px; right: 12px; left: 12px; max-width: none; }
  .vx-toast { min-width: 0; max-width: 100%; }
}

/* ── Skip-to-main + accessibility ────────────────────────────────────────── */
.skip-to-main {
  position: absolute; top: -48px; left: 16px;
  background: var(--bg-surface); color: var(--text-primary);
  padding: 8px 16px; border-radius: var(--radius-sm);
  z-index: 3000; text-decoration: none; font-family: var(--font-body);
  border: 1px solid var(--border-default);
  transition: top 0.15s;
}
.skip-to-main:focus { top: 16px; }

/* Global focus rings */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent-hot); outline-offset: 2px;
}
/* Minimum 40px tap targets */
button, .btn, a.btn { min-height: 40px; }

/* Reduced motion — respects OS-level "reduce motion" preference.
   Kills decorative animations (grain, marquee, eq-scan, pulses),
   speeds transitions to instant, and disables smooth scrolling. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
  html { scroll-behavior: auto; }
  .grain-overlay { animation: none !important; opacity: 0 !important; }
  .eq-scan-line,
  .gen-greeting-shimmer,
  [class*="marquee"] { animation: none !important; }
}

/* ── Mobile hamburger + sidebar drawer ───────────────────────────────────── */
.mobile-nav-toggle {
  display: none;
  position: fixed; top: 14px; left: 14px; z-index: 1001;
  width: 44px; height: 44px;
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  color: var(--text-primary);
  align-items: center; justify-content: center;
  cursor: pointer;
}
.mobile-nav-backdrop {
  display: none; position: fixed; inset: 0;
  background: rgb(var(--shade-rgb) / .6); z-index: 999; opacity: 0;
  transition: opacity 0.2s;
}
.mobile-nav-backdrop.open { opacity: 1; }
@media (max-width: 900px) {
  .mobile-nav-toggle { display: flex; }
  .sidenav {
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    z-index: 1000 !important;
    box-shadow: 4px 0 24px rgb(var(--shade-rgb) / .4);
  }
  .sidenav.open { transform: translateX(0); }
  .mobile-nav-backdrop.open { display: block; }
  .main-wrap { margin-left: 0 !important; padding-top: 64px; }
}

/* ── Dashboard hero + stats ──────────────────────────────────────────────── */
.dash-hero-card {
  padding: 48px 40px;
  border-radius: var(--radius-xl);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  position: relative; overflow: hidden;
}
.dash-hero-card::before {
  content: ''; position: absolute; top: -40%; right: -20%;
  width: 500px; height: 500px;
  background: radial-gradient(circle, var(--pink-a10), transparent 70%);
  pointer-events: none;
}
.dash-hero-eyebrow {
  font-family: var(--font-body); font-size: 12px; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 16px; position: relative;
}
.dash-hero-title {
  font-family: var(--font-display); font-size: 44px; font-weight: 700;
  line-height: 1.1; margin: 0 0 16px 0; position: relative;
  color: var(--ink);
}
.dash-hero-sub {
  font-family: var(--font-body); font-size: 17px;
  color: var(--text-secondary); line-height: 1.5;
  max-width: 540px; margin: 0 0 32px 0; position: relative;
}
.dash-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; position: relative; }

.btn-gradient-lg {
  display: inline-flex; align-items: center;
  padding: 14px 28px; border-radius: var(--radius-md);
  background: var(--gradient-brand); color: var(--accent-ink);
  font-family: var(--font-body); font-weight: 500; font-size: 16px;
  text-decoration: none;
  transition: transform 0.15s, box-shadow 0.15s;
  box-shadow: 0 8px 24px var(--accent-glow-pink);
  text-shadow: 0 1px 2px rgb(var(--shade-rgb) / .2);
  min-height: 44px; border: none; cursor: pointer;
}
.btn-gradient-lg:hover { transform: translateY(-1px); box-shadow: 0 12px 32px var(--accent-glow-pink); }
.btn-gradient-lg:focus-visible { outline: 2px solid var(--accent-hot); outline-offset: 3px; }

.btn-ghost-lg {
  display: inline-flex; align-items: center;
  padding: 14px 28px; border-radius: var(--radius-md);
  background: transparent; color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  font-family: var(--font-body); font-weight: 500; font-size: 16px;
  text-decoration: none;
  transition: background 0.15s, border-color 0.15s;
  min-height: 44px; cursor: pointer;
}
.btn-ghost-lg:hover { background: var(--bg-elevated); border-color: var(--pink-a30); }
.btn-ghost-lg:focus-visible { outline: 2px solid var(--accent-hot); outline-offset: 3px; }

.btn-ghost-sm {
  display: inline-flex; align-items: center;
  padding: 8px 14px; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
  font-family: var(--font-body); font-size: 13px;
  text-decoration: none; transition: background 0.15s;
  min-height: 36px; cursor: pointer;
}
.btn-ghost-sm:hover { background: var(--bg-elevated); }

.dash-stats {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
}
.dash-stat {
  padding: 20px; background: var(--bg-surface);
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  text-decoration: none;
  transition: border-color 0.15s, transform 0.15s;
}
.dash-stat:hover { border-color: var(--pink-a30); transform: translateY(-1px); }
.dash-stat:focus-visible { outline: 2px solid var(--accent-hot); outline-offset: 2px; }
.dash-stat-label {
  font-family: var(--font-body); font-size: 11px; font-weight: 500;
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 8px;
}
.dash-stat-value {
  font-family: var(--font-display); font-size: 28px; font-weight: 700;
  color: var(--text-primary);
}
.dash-connect-strip {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 18px; background: var(--bg-surface);
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  font-family: var(--font-body); color: var(--text-secondary);
  gap: 12px; flex-wrap: wrap; font-size: 14px;
}

/* Page headlines */
.page-headline {
  font-family: var(--font-display); font-weight: 700;
  font-size: 38px; line-height: 1.1; margin: 0 0 16px 0; max-width: 720px;
}
/* 720px caps the line length; inside a centred .page-header the box has to be
   centred too, or the text centres within a box pinned to the left edge. */
.page-header .page-headline { margin-left: auto; margin-right: auto; }
.headline-accent {
  color: var(--ink);
}
.page-subtitle {
  font-family: var(--font-body); font-size: 16px;
  color: var(--text-secondary); margin: 0 0 32px 0; max-width: 640px;
}

/* Empty state CTAs */
.empty-state-cta {
  text-align: center; padding: 52px 24px; max-width: 480px; margin: 0 auto;
}
/* When the empty state is the WHOLE page there is nothing to crowd, so it can
   breathe. When it is one section among others — the versions list under a
   beat's header and stats — 160px of vertical padding for one sentence is the
   single largest block on the page. */
.empty-state-cta--inline { padding: 28px 20px; }
.empty-state-cta--inline .empty-state-icon { margin-bottom: 10px; }
.empty-state-cta--inline .empty-state-icon svg { width: 34px; height: 34px; }
.empty-state-cta--inline h2 { font-size: 19px; margin-bottom: 6px; }
.empty-state-cta--inline p { font-size: 14px; margin-bottom: 16px; }
.empty-state-icon { font-size: 56px; margin-bottom: 20px; opacity: 0.6; }
/* svg is display:block here, so text-align on the parent cannot centre it. */
.empty-state-icon svg { width: 52px; height: 52px; stroke-width: 1.5;
                        margin-left: auto; margin-right: auto; }
.empty-state-cta h2 {
  font-family: var(--font-display); font-weight: 700; font-size: 26px; margin: 0 0 12px 0;
}
.empty-state-cta p {
  font-family: var(--font-body); color: var(--text-secondary);
  font-size: 16px; line-height: 1.5; margin: 0 0 28px 0;
}

/* btn-subtitle — stacks under main button label */
.btn-subtitle { display: block; font-size: 11px; font-weight: 400; opacity: 0.8; margin-top: 2px; }
.btn:has(.btn-subtitle) {
  flex-direction: column;
  white-space: normal;
  line-height: 1.35;
  padding-top: 10px;
  padding-bottom: 10px;
}

@media (max-width: 768px) {
  .dash-stats { grid-template-columns: repeat(2, 1fr); }
  .dash-hero-title { font-size: 30px; }
  .dash-hero-card { padding: 28px 20px; }
  .dash-hero-sub { font-size: 15px; }
  .btn-gradient-lg, .btn-ghost-lg { padding: 12px 20px; font-size: 15px; }
  .page-headline { font-size: 26px; margin-bottom: 12px; }
  .empty-state-cta { padding: 48px 16px; }
  .empty-state-icon { font-size: 44px; }
  .empty-state-icon svg { width: 40px; height: 40px; }
  .empty-state-cta h2 { font-size: 20px; }
}

/* ── Signal AI FAB (labelled pill trigger) ───────────────────────────────── */
.signal-fab.signal-toggle {
  display: inline-flex !important;
  align-items: center; gap: 8px;
  padding: 10px 16px 10px 12px !important;
  border-radius: 999px !important;
  background: var(--surface-3) !important;
  color: var(--ink) !important;
  box-shadow: 0 10px 28px var(--pink-a30);
  font-family: var(--font-body); font-weight: 500; font-size: 14px;
  text-shadow: 0 1px 2px rgb(var(--shade-rgb) / .2);
  min-height: 44px; min-width: auto;
  transition: transform 0.15s, box-shadow 0.15s;
}
.signal-fab.signal-toggle:hover { transform: translateY(-2px); box-shadow: none; }
.signal-fab-label { white-space: nowrap; }
@media (max-width: 640px) {
  /* Icon only on a phone. The labelled pill is ~140px wide and floats over
     whatever is beneath it — it was sitting squarely on the "No thanks" button
     of an agent suggestion, so a control the user needed could not be tapped.
     A 48px circle still reads as the assistant and covers a quarter as much. */
  .signal-fab.signal-toggle {
    padding: 0 !important;
    width: 48px; height: 48px;
    justify-content: center;
    gap: 0;
  }
  .signal-fab .signal-fab-label { display: none; }
}

/* ── Calendar section headers ────────────────────────────────────────────── */
.calendar-section-header { margin: 28px 0 14px 0; }
.calendar-section-header h2 {
  font-family: var(--font-display); font-weight: 600; font-size: 20px; margin: 0 0 4px 0;
}
.calendar-section-header p {
  font-family: var(--font-body); color: var(--text-muted); font-size: 14px; margin: 0;
}

/* ── Cover placeholder ───────────────────────────────────────────────────── */
.cover-placeholder {
  position: relative; background: var(--surface-3);
  border-radius: var(--radius-md); overflow: hidden;
  display: flex; align-items: center; justify-content: center; flex-direction: column;
}
.cover-placeholder-grain {
  position: absolute; inset: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.85'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.12'/%3E%3C/svg%3E");
  mix-blend-mode: overlay;
}
.cover-placeholder-text {
  font-family: var(--font-display); font-weight: 700;
  color: var(--ink); letter-spacing: -0.02em;
  z-index: 1; position: relative;
  text-shadow: 0 1px 3px rgb(var(--shade-rgb) / .3);
}
.cover-placeholder-genre {
  font-family: var(--font-body); text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--ink); position: absolute; bottom: 8px;
  z-index: 1; font-size: 9px; text-shadow: 0 1px 2px rgb(var(--shade-rgb) / .3);
}
.cover-sm  { width: 40px; height: 40px; }
.cover-sm  .cover-placeholder-text { font-size: 16px; }
.cover-md  { width: 80px; height: 80px; }
.cover-md  .cover-placeholder-text { font-size: 28px; }
.cover-md  .cover-placeholder-genre { font-size: 8px; }
.cover-lg  { width: 100%; aspect-ratio: 1; }
.cover-lg  .cover-placeholder-text { font-size: 40px; }
.cover-lg  .cover-placeholder-genre { font-size: 10px; }

/* ── Generate page preset pills ─────────────────────────────────────────── */
.gen-presets { margin-bottom: 20px; }
.gen-presets-label {
  display: block; font-family: var(--font-body); font-size: 13px;
  color: var(--text-muted); margin-bottom: 10px;
}
.gen-presets-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.gen-preset {
  padding: 8px 14px; border-radius: 999px;
  background: var(--bg-elevated); border: 1px solid var(--border-subtle);
  color: var(--text-primary); font-family: var(--font-body); font-size: 13px;
  cursor: pointer; transition: border-color 0.15s, background 0.15s;
  min-height: 36px;
}
.gen-preset:hover { border-color: var(--line); }
.gen-preset.active {
  background: linear-gradient(var(--surface-2), var(--surface-2));
  border-color: var(--line-control);
}
.gen-preset:focus-visible { outline: 2px solid var(--accent-hot); outline-offset: 2px; }

/* ── Beat card ───────────────────────────────────────────────────────────── */
.beat-card {
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg); overflow: hidden;
  display: flex; flex-direction: column;
  transition: border-color 0.15s, transform 0.15s;
  /* Containing block for the stretched title link below. */
  position: relative;
}
.beat-card:hover { border-color: var(--pink-a30); transform: translateY(-2px); }

/* ── The whole card opens the beat ───────────────────────────────────────────
   The "stretched link" pattern: the title is a real <a>, and its ::after is
   blown up to cover the card, so every part of the card that is not itself
   interactive is inside that link's hit area. Clicking only the title was too
   small a target on a card this size.

   A click handler on the <article> would have been simpler and worse: no
   middle-click, no ctrl-click, no keyboard, and a screen reader announcing a
   clickable region with no name. This way there is exactly one link and it is
   named after the beat.

   Everything genuinely interactive is raised above the overlay so it keeps its
   own behaviour — the producer's name still goes to their profile, the player
   still plays, the button still claims. */
.beat-card-link::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  border-radius: inherit;
}
.beat-card { cursor: pointer; }
.beat-card-producer a,
.beat-card .vx-player,
.beat-card-actions,
.beat-card-badges { position: relative; z-index: 2; }
/* The player and the buttons are their own targets, not part of the card link. */
.beat-card .vx-player, .beat-card-actions { cursor: auto; }
.beat-card-actions .btn-ghost-lg, .beat-card-actions .btn-gradient-lg,
.beat-card-producer a { cursor: pointer; }
/* 16:10 rather than a 1:1 square. On a ~380px column the square cover alone
   was 380px tall and pushed the whole card to 657px, so a single beat filled
   most of the viewport and the grid always needed scrolling. */
/* Capped as well as proportional. aspect-ratio alone means the cover grows
   with the column, so on a wide screen a 500px-wide card got a 310px cover and
   the card ran past 700px — the "too spread out" complaint. The cap holds it
   at a sensible band height whatever the column does. */
.beat-card-cover { position: relative; aspect-ratio: 16 / 10; max-height: 180px;
                   overflow: hidden; }
.beat-card-cover img, .beat-card-cover .cover-placeholder { width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.beat-card-badges { position: absolute; top: 10px; left: 10px; display: flex; gap: 6px; }
.beat-badge {
  padding: 4px 10px; border-radius: 999px;
  font-family: var(--font-body); font-size: 11px; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase; backdrop-filter: blur(8px);
}
.beat-badge-open     { background: var(--surface-2);  color: var(--success-xlight); border: 1px solid var(--line); }
.beat-badge-claimed  { background: var(--surface-2); color: var(--warning); border: 1px solid var(--line); }
.beat-badge-complete { background: rgb(var(--ink-rgb) / .08); color: var(--accent-primary-xlight); border: 1px solid var(--line); }
/* How the beat may be worked on, not where it is in its lifecycle. Both licence
   badges sit on the near-opaque dark base the challenge badge uses, and for the
   same reason: a translucent tint disappears against a brand-gradient cover
   placeholder, and these two are the badges an artist most needs to read before
   deciding whether they can record on this beat at all. */
.beat-badge-exclusive { background: rgb(var(--shade-rgb) / .82); color: var(--accent-primary-xlight);
                        border: 1px solid var(--line); }
.beat-badge-invite    { background: rgb(var(--shade-rgb) / .82); color: var(--accent-secondary-xlight);
                        border: 1px solid var(--line); }
/* Pink, so a live challenge reads as distinct from the status badge beside it
   rather than as a second opinion about the same thing.
   Unlike its neighbours this one sits on a near-opaque dark base rather than a
   20%-alpha tint: cover placeholders are drawn from the brand gradient, which
   is itself pink in the middle, so a translucent pink badge disappeared on
   roughly a third of the cards. */
.beat-badge-challenge { background: rgb(var(--shade-rgb) / .82); color: var(--ink);
                        border: 1px solid var(--line); }

.beat-card-body { padding: 14px; display: flex; flex-direction: column; gap: 9px; }
/* Producer and their credibility on one line — they are the same thought, and
   as separate rows they cost 36px of the card for two short strings. */
.beat-card-byline { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; }
.beat-card-title {
  font-family: var(--font-display); font-weight: 600; font-size: 17px; margin: 0;
  color: var(--text-primary); line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.beat-card-producer { font-family: var(--font-body); font-size: 13px; color: var(--text-muted); }
.beat-card-producer a { color: var(--text-secondary); text-decoration: none; }
.beat-card-producer a:hover { color: var(--ink); }
.beat-card-meta { display: flex; flex-wrap: wrap; gap: 6px; }
.beat-chip {
  padding: 4px 10px;
  background: linear-gradient(var(--surface-2), var(--surface-2));
  border: 1px solid var(--line); border-radius: 999px;
  font-family: var(--font-body); font-size: 11px; font-weight: 500; color: var(--text-primary);
}
.beat-chip-plain {
  padding: 4px 10px; background: var(--bg-elevated);
  border: 1px solid var(--border-subtle); border-radius: 999px;
  font-family: var(--font-body); font-size: 11px; color: var(--text-muted);
}
/* The royalty split reads as a fact about the beat, so it is a chip in the
   fact row rather than a bordered footer of its own. Tinted green because it
   is the one number in that row the artist is being offered. */
.beat-chip-split {
  padding: 4px 10px; border-radius: 999px;
  background: var(--success-a15); border: 1px solid var(--line);
  font-family: var(--font-body); font-size: 11px; font-weight: 600;
  color: var(--success-xlight); cursor: help;
}
.beat-card-actions { margin-top: 2px; }

/* ── Vocalist card ───────────────────────────────────────────────────────── */
.voc-card {
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg); padding: 18px;
  display: flex; flex-direction: column; gap: 12px;
  transition: border-color 0.15s, transform 0.15s;
}
.voc-card:hover { border-color: var(--pink-a30); transform: translateY(-2px); }
.voc-card-header { display: flex; gap: 12px; align-items: center; }
.voc-avatar { position: relative; width: 52px; height: 52px; flex-shrink: 0; }
.voc-avatar img, .voc-avatar-fallback { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
.voc-avatar-fallback {
  background: var(--surface-3); display: flex; align-items: center;
  justify-content: center; color: var(--ink); font-family: var(--font-display);
  font-weight: 700; font-size: 20px; text-shadow: 0 1px 2px rgb(var(--shade-rgb) / .2);
}
.voc-verified {
  position: absolute; bottom: -2px; right: -2px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--ink); color: var(--bg);
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; border: 2px solid var(--bg-surface);
}
.voc-card-name { font-family: var(--font-display); font-weight: 600; font-size: 16px; margin: 0; }
.voc-card-name a { color: var(--text-primary); text-decoration: none; }
.voc-card-name a:hover { color: var(--ink); }
.voc-card-username { font-family: var(--font-body); font-size: 12px; color: var(--text-muted); }
.voc-card-stats {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px;
  padding: 10px; background: var(--bg-elevated); border-radius: var(--radius-md); text-align: center;
}
.voc-stat { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.voc-stat-value {
  font-family: var(--font-display); font-weight: 700; font-size: 16px;
  color: var(--ink);
}
.voc-stat-label { font-family: var(--font-body); font-size: 10px; color: var(--text-muted); margin-top: 2px; }
.voc-card-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.voc-card-bio { font-family: var(--font-body); font-size: 13px; color: var(--text-secondary); margin: 0; line-height: 1.5; }
.voc-card-sample { display: flex; flex-direction: column; gap: 6px; }
.voc-card-sample-label {
  font-family: var(--font-body); font-size: 11px; font-weight: 500;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted);
}
.voc-card-actions { display: flex; gap: 8px; margin-top: auto; }

/* ── Claim card ──────────────────────────────────────────────────────────── */
.claim-card {
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg); overflow: hidden; display: flex;
  flex-direction: column; max-width: 560px; transition: border-color .15s;
}
.claim-card:hover { border-color: var(--line); }

/* Horizontal header: thumbnail left + info right */
.claim-card-inner { display: flex; gap: 14px; padding: 16px 16px 12px; }
.claim-card-thumb {
  flex-shrink: 0; width: 72px; height: 72px;
  border-radius: 8px; overflow: hidden;
}
.claim-card-thumb img,
.claim-card-thumb .cover-placeholder { width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.claim-card-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.claim-card-head { display: flex; flex-direction: column; gap: 2px; }
.claim-card-title { font-family: var(--font-display); font-size: 14px; font-weight: 600; color: var(--text-primary); margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.claim-card-split-row { display: flex; align-items: center; gap: 10px; }

/* Timeline (now inside the body, compact) */
.claim-timeline { display: flex; align-items: center; gap: 3px; padding: 6px 0 0; }
.claim-step { display: flex; flex-direction: column; align-items: center; gap: 4px; flex-shrink: 0; }
.claim-step-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--bg-elevated); border: 2px solid var(--border-subtle);
}
.claim-step.done .claim-step-dot {
  background: var(--ink); border-color: transparent;
  box-shadow: none;
}
.claim-step-label { font-size: 9px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); text-align: center; white-space: nowrap; }
.claim-step.done .claim-step-label { color: var(--text-primary); }
.claim-step-line { flex: 1; height: 2px; background: var(--border-subtle); margin-bottom: 13px; min-width: 12px; }
.claim-step-line.done { background: var(--ink); }

.claim-deadline { font-family: var(--font-body); font-size: 12px; color: var(--text-muted); }
.claim-deadline.urgent { color: var(--danger); font-weight: 500; }

/* Audio preview strip */
.claim-card-preview { display: flex; align-items: center; gap: 8px; padding: 0 16px 10px; }
.claim-card-preview-label { font-size: 11px; color: var(--text-muted); white-space: nowrap; flex-shrink: 0; }

/* Action row */
.claim-card-actions { padding: 0 16px 16px; }
.claim-waiting {
  text-align: center; padding: 10px; background: var(--bg-elevated);
  border-radius: var(--radius-md); font-family: var(--font-body); font-size: 13px; color: var(--text-muted);
}

/* Claims use a narrower grid so cards don't stretch to full viewport width */
.claims-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 540px)); gap: 20px; }

/* Inline vocal upload inside claim card */
.claim-upload-form { display: flex; flex-direction: column; gap: 8px; position: relative; border-radius: var(--radius-md); transition: outline-color .15s ease, background .15s ease; }
.claim-upload-form .upload-trigger { display: block; text-align: center; cursor: pointer; }
.claim-upload-form .upload-name-row { display: flex; flex-direction: column; gap: 8px; }
.claim-upload-form .upload-name {
  font-size: 12px; color: var(--text-muted); text-align: center;
  padding: 8px 12px; background: var(--bg-elevated); border-radius: var(--radius-sm);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.claim-upload-form.drag-over { outline: 2px dashed var(--accent); outline-offset: 4px; background: rgb(var(--ink-rgb) / .03); }

/* ── Marketplace grid ── */
.mkt-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(300px, 100%),1fr)); gap:20px; }
.mkt-grid-section { flex:1; min-width:0; }
.mkt-full-width { grid-column: 1 / -1; }

/* ══════════════════════════════════════════════════════════════════════════
   UTILITIES — use these instead of inline styles.
   Layout, spacing, typography and sizing helpers on an 8px / type-scale grid.
   ══════════════════════════════════════════════════════════════════════════ */

/* Flex & layout */
.u-stack        { display: flex; flex-direction: column; }
.u-stack-4      { display: flex; flex-direction: column; gap: 4px; }
.u-stack-6      { display: flex; flex-direction: column; gap: 6px; }
.u-stack-8      { display: flex; flex-direction: column; gap: 8px; }
.u-stack-12     { display: flex; flex-direction: column; gap: 12px; }
.u-stack-16     { display: flex; flex-direction: column; gap: 16px; }
.u-stack-24     { display: flex; flex-direction: column; gap: 24px; }
.u-row          { display: flex; flex-direction: row; align-items: center; }
.u-row-6        { display: flex; flex-direction: row; align-items: center; gap: 6px; }
.u-row-8        { display: flex; flex-direction: row; align-items: center; gap: 8px; }
.u-row-12       { display: flex; flex-direction: row; align-items: center; gap: 12px; }
.u-row-16       { display: flex; flex-direction: row; align-items: center; gap: 16px; }
/* A flex item will not shrink below its own content unless told it may, so a
   long title in one of these rows pushed the release page 2px past the
   viewport. Allowing the children to shrink costs nothing at any width. */
.u-row-16 > *   { min-width: 0; }
@media (max-width: 720px) { .u-row-16 { flex-wrap: wrap; } }
.u-row-wrap     { display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
.u-row-between  { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; }
.u-row-between-wrap { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.u-row-end      { display: flex; flex-direction: row; align-items: center; justify-content: flex-end; gap: 8px; }
.u-row-center   { display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 8px; }
.u-flex-1       { flex: 1; min-width: 0; }
.u-flex-none    { flex: none; }
.u-grid-auto    { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%),1fr)); gap: 16px; }

/* Spacing — margin (top-heavy + sides) */
.u-mt-4  { margin-top: 4px; }
.u-mt-8  { margin-top: 8px; }
.u-mt-12 { margin-top: 12px; }
.u-mt-16 { margin-top: 16px; }
.u-mt-24 { margin-top: 24px; }
.u-mt-32 { margin-top: 32px; }
.u-mt-40 { margin-top: 40px; }
.u-mb-4  { margin-bottom: 4px; }
.u-mb-8  { margin-bottom: 8px; }
.u-mb-12 { margin-bottom: 12px; }
.u-mb-16 { margin-bottom: 16px; }
.u-mb-24 { margin-bottom: 24px; }
.u-mb-32 { margin-bottom: 32px; }
.u-m-0   { margin: 0; }
.u-ml-auto { margin-left: auto; }

/* Spacing — padding */
.u-p-8   { padding: 8px; }
.u-p-12  { padding: 12px; }
.u-p-16  { padding: 16px; }
.u-p-24  { padding: 24px; }
.u-px-12 { padding-left: 12px; padding-right: 12px; }
.u-px-16 { padding-left: 16px; padding-right: 16px; }
.u-py-8  { padding-top: 8px;  padding-bottom: 8px; }
.u-py-12 { padding-top: 12px; padding-bottom: 12px; }
.u-py-16 { padding-top: 16px; padding-bottom: 16px; }

/* Gap only (for existing flex/grid parents) */
.u-gap-4  { gap: 4px; }
.u-gap-6  { gap: 6px; }
.u-gap-8  { gap: 8px; }
.u-gap-12 { gap: 12px; }
.u-gap-16 { gap: 16px; }
.u-gap-24 { gap: 24px; }

/* Typography scale */
.u-text-11  { font-size: 11px; line-height: 1.4; }
.u-text-12  { font-size: 12px; line-height: 1.45; }
.u-text-13  { font-size: 13px; line-height: 1.5; }
.u-text-14  { font-size: 14px; line-height: 1.55; }
.u-text-15  { font-size: 15px; line-height: 1.6; }
.u-text-16  { font-size: 16px; line-height: 1.6; }
.u-text-18  { font-size: 18px; line-height: 1.5; }
.u-text-22  { font-size: 22px; line-height: 1.3; }
.u-text-28  { font-size: 28px; line-height: 1.2; }
.u-weight-400 { font-weight: 400; }
.u-weight-500 { font-weight: 500; }
.u-weight-600 { font-weight: 600; }
.u-weight-700 { font-weight: 700; }
.u-display  { font-family: var(--font-display); }
.u-body     { font-family: var(--font-body); }

/* Colors */
.u-text-primary   { color: var(--text-primary); }
.u-text-secondary { color: var(--text-secondary); }
.u-text-muted     { color: var(--text-muted); }
.u-text-danger    { color: var(--danger); }
.u-text-success   { color: var(--success); }
.u-text-warning   { color: var(--warning); }
.u-text-gradient  {
  color: var(--ink);
}

/* Sizing */
.u-w-full     { width: 100%; }
.u-w-auto     { width: auto; }
.u-max-w-260  { max-width: 260px; }
.u-max-w-320  { max-width: 320px; }
.u-max-w-480  { max-width: 480px; }
.u-max-w-640  { max-width: 640px; }

/* Text alignment */
.u-text-center { text-align: center; }
.u-text-left   { text-align: left; }
.u-text-right  { text-align: right; }

/* Surfaces */
.u-surface {
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md); padding: 16px;
}
.u-surface-elevated {
  background: var(--bg-elevated); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md); padding: 16px;
}
.u-divider-top    { border-top: 1px solid var(--border-subtle); padding-top: 16px; }
.u-divider-bottom { border-bottom: 1px solid var(--border-subtle); padding-bottom: 16px; }

/* Visibility */
.u-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;
}
.u-hidden { display: none !important; }

/* Opacity utilities */
.u-opacity-40 { opacity: 0.4; }
.u-opacity-50 { opacity: 0.5; }
.u-opacity-60 { opacity: 0.6; }

/* Small fixed-dimension utilities */
.u-w-120          { width: 120px; }
.u-h-16           { height: 16px; }
.u-ml-4           { margin-left: 4px; }
.u-mt-6           { margin-top: 6px; }
.u-nowrap         { white-space: nowrap; }
.u-overflow-hidden{ overflow: hidden; }
.u-align-start    { align-items: flex-start; }
.u-display-block  { display: block; }
.u-display-inline-flex { display: inline-flex; align-items: center; gap: 8px; }
.u-text-accent    { color: var(--accent-light); }
.u-mb-16-only     { margin-bottom: 16px; }
.u-mt-12-rem      { margin-top: 0.75rem; }
.btn-inline-icon  { display: inline-flex; align-items: center; gap: 8px; }
.u-display-inline { display: inline; }
.u-ml-0           { margin-left: 0 !important; }
.u-text-right     { text-align: right; }
.u-position-relative { position: relative; }
.u-chart-220      { position: relative; height: 220px; }
.u-chart-240      { position: relative; height: 240px; }
.u-mx-auto        { margin-left: auto; margin-right: auto; }
.u-max-w-520      { max-width: 520px; }
.u-mb-2rem        { margin-bottom: 2rem; }
.u-mt-2rem        { margin-top: 2rem; }
.form-flash       { margin-bottom: 12px; border-radius: 8px; }
.follow-back-link { font-size: 13px; color: var(--text-muted); text-decoration: none; }
.follow-header    { margin-bottom: 6px; }
.follow-h1        { margin-top: 6px; }
.follow-empty     { color: var(--text-muted); font-size: 14px; padding: 16px 0; }
.search-heading   {
  font-family: var(--font-display); font-size: 26px;
  font-weight: 700; margin-bottom: 20px;
}
.search-chevron   { color: var(--text-muted); flex-shrink: 0; }
.revenue-amount-cell {
  text-align: right; font-weight: 700;
  color: var(--ink);
}
.conn-badge-count {
  font-size: 13px; font-weight: 400;
  color: var(--text-muted);
}

/* Focus — apply to interactive elements that lack a focus ring */
.u-focus-ring:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* Icon sizing — <svg class="vx-icon"> or <svg class="vx-icon vx-icon-lg"> */
.vx-icon      { width: 16px; height: 16px; flex-shrink: 0; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.vx-icon-sm   { width: 14px; height: 14px; }
.vx-icon-lg   { width: 20px; height: 20px; }
.vx-icon-xl   { width: 28px; height: 28px; }
.vx-icon-inline { display: inline-block; vertical-align: -3px; }
/* Reuses trending-up for a downward delta rather than shipping a second
   path that is the same shape mirrored. */
.vx-icon-flip { transform: scaleY(-1); }

/* Status pill (semantic) — replaces mixed badge/pill usage */
.vx-pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px; border-radius: 999px;
  font-family: var(--font-body); font-size: 11px; font-weight: 500;
  letter-spacing: 0.02em; text-transform: none;
  background: var(--bg-elevated); color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
}
.vx-pill--success { background: var(--surface-2); color: var(--success-xlight); border-color: var(--line); }
.vx-pill--warn    { background: var(--surface-2); color: var(--warning-xlight); border-color: var(--line); }
.vx-pill--danger  { background: var(--surface-2);  color: var(--danger-xlight); border-color: var(--line); }
.vx-pill--info    { background: rgb(var(--ink-rgb) / .05);  color: var(--accent-secondary-xlight); border-color: var(--line); }
.vx-pill--brand   {
  background: var(--gradient-brand-subtle); color: var(--accent-primary-xlight);
  border-color: var(--line);
}

/* ── Landing page (index.html) overrides ─────────────────────────────────── */
.pricing-grid--2col {
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  max-width: 900px;
  margin: 0 auto;
}
.footer-cta-row {
  display: flex; gap: 12px; justify-content: center;
  flex-wrap: wrap; margin-top: 32px;
}
.footer-cta-btn { padding: 16px 36px; font-size: 16px; }
.u-text-success-bright { color: var(--success); }

/* ── Settings page ───────────────────────────────────────────────────────── */
.settings-header        { margin-bottom: 28px; }
.settings-header h1     { font-size: 26px; font-weight: 700; }
.settings-header p      { font-size: 14px; color: var(--text-muted); margin-top: 4px; }
.settings-eyebrow {
  font-size: 14px; font-weight: 600; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .06em;
  margin-bottom: 12px;
}
.int-card-desc   { font-size: 13px; color: var(--text-muted); margin-bottom: 12px; }
.int-card-text   { font-size: 13px; color: var(--text-muted); }
.sp-tracks-spaced { margin-top: 18px; }
.sp-tracks-label  { font-size: 12px; font-weight: 600; color: var(--text-muted); margin-bottom: 8px; }
.sp-change-block  {
  margin-top: 16px; padding-top: 16px;
  border-top: 1px solid var(--border-subtle);
}
.sp-change-label  { font-size: 12px; color: var(--text-muted); margin-bottom: 8px; }
.int-help-code {
  font-size: 10px;
  background: rgb(var(--ink-rgb) / .06);
  padding: 1px 5px; border-radius: 4px;
}

/* ── Form fieldsets (shared — profile_edit, settings, etc.) ─────────────── */
.form-fieldset {
  border: none; padding: 0; margin: 16px 0 0;
}
.form-fieldset--spaced { margin-top: 20px; }
.form-fieldset--tight  { margin: 0; }
.form-legend--body     {
  font-family: var(--font-body);
  font-size: 14px; font-weight: 500;
  color: var(--text-secondary);
  margin-bottom: 8px;
}
.form-legend {
  font-size: 14px; font-weight: 500;
  color: var(--text-secondary);
  margin-bottom: 10px;
}
.form-stack {
  display: flex; flex-direction: column; gap: 10px;
}
.form-label-sm {
  font-size: 13px;
  color: var(--text-secondary);
}
/* Three role cards. minmax(0,…) so the tracks can shrink, and stacked below
   640px because three ~110px columns are narrower than the words on them. */
.role-picker-3col { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 640px) {
  .role-picker-3col { grid-template-columns: minmax(0, 1fr); }
}

.radio-stacked {
  display: flex; align-items: flex-start; gap: 12px;
  cursor: pointer;
}
.radio-stacked input[type="radio"] {
  margin-top: 3px; flex-shrink: 0;
}
.radio-stacked-title { font-size: 14px; }
.radio-stacked-desc {
  font-size: 12px; color: var(--text-muted);
  margin: 2px 0 0;
}
.form-submit-spaced { margin-top: 20px; }

/* ── Generate page (beat generator) ─────────────────────────────────────── */
.gen-hero-title {
  font-family: var(--font-display);
  font-size: 32px; font-weight: 700;
  letter-spacing: -0.02em;
  margin-top: 8px; line-height: 1.2;
}
.gen-label-spaced { margin-top: 16px; display: block; }
.gen-btn-primary { margin-top: 24px; align-self: flex-start; }

.eq-wrap          { margin-top: 24px; }
.eq-card {
  position: relative;
  background: var(--bg-overlay);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px 20px 14px;
  overflow: hidden;
}
.eq-scan-line {
  position: absolute; top: 0; left: -100%;
  width: 40%; height: 100%;
  background: linear-gradient(var(--surface-2), var(--surface-2));
  animation: eq-scan 2.4s linear infinite;
  pointer-events: none;
}
.eq-canvas { display: block; width: 100%; height: 80px; border-radius: 6px; }
.eq-meta {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 12px;
}
.eq-phase-label {
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-muted);
}
.eq-dot-row { display: flex; gap: 5px; align-items: center; }
.eq-dot {
  width: 6px; height: 6px; border-radius: 50%;
  animation: eq-pulse 1.2s ease-in-out infinite;
}
.eq-dot--1 { background: var(--muted); }
.eq-dot--2 { background: var(--muted); animation-delay: 0.4s; }
.eq-dot--3 { background: var(--accent-secondary); animation-delay: 0.8s; }
@keyframes eq-scan  { from { left: -40%; } to { left: 110%; } }
@keyframes eq-pulse { 0%,100% { opacity: .3; transform: scale(.85); } 50% { opacity: 1; transform: scale(1); } }

.gen-waveform-canvas {
  width: 100%;
  border-radius: var(--radius-md);
  background: var(--bg-overlay);
}
.gen-result-heading { margin-bottom: 0; }
.gen-post-status    { margin-top: 16px; }
.gen-submit-btn     { margin-top: 16px; }
.gen-panel-hint     { margin-bottom: 16px; }
.hint-inline-below  { margin-top: 4px; display: block; }

/* ── form/display inline & tight util classes ─────────────────────────────── */
.u-inline-form         { display: inline; }
.u-file-hidden         { display: none; }
.u-mb-16               { margin-bottom: 16px; }
.u-hint-block          { display: block; }
.sp-brand-icon         { margin-right: 4px; vertical-align: -1px; }

/* ── marketplace cards buttons ────────────────────────────────────────────── */
.mkt-card-btn {
  padding: 10px 18px;
  font-size: 14px;
  width: 100%;
}
.mkt-card-btn--flex1   { padding: 10px 18px; font-size: 14px; flex: 1; }
.mkt-card-btn--auto    { padding: 10px 18px; font-size: 14px; }

/* Vocalist vocal-submit form: drop zone + selected-file summary */
.form-submit-vocal              {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px;
  border-radius: 8px;
  border: 2px dashed transparent;
  transition: border-color .15s, background .15s;
}
.form-submit-vocal.is-dragover  {
  border-color: var(--accent-primary, var(--line));
  background: rgb(var(--ink-rgb) / .04);
}
.form-submit-vocal .upload-trigger {
  display: inline-flex; flex-direction: column; align-items: center;
  line-height: 1.15;
}
.form-submit-vocal .upload-trigger-hint {
  font-size: 10px; font-weight: 500; opacity: 0.85; letter-spacing: 0.02em;
}
.form-submit-vocal .upload-summary {
  /* Wraps so the vocal-chain picker can take its own row on narrow layouts
     instead of squeezing the filename and the buttons onto one line. */
  display: inline-flex; align-items: center; gap: 8px; max-width: 100%;
  flex-wrap: wrap;
}
.form-submit-vocal .upload-name {
  display: inline-block;
  max-width: 180px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--font-body); font-size: 13px;
  color: var(--text-muted);
}

/* Vocal chain picker (acapella upload) */
.preset-picker {
  display: flex; flex-direction: column; gap: 3px;
  flex: 1 1 100%; min-width: 0;
}
.preset-picker-label {
  font-family: var(--font-body); font-size: 11px; font-weight: 600;
  letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--text-muted);
}
.preset-picker-select {
  width: 100%; max-width: 320px;
  padding: 6px 8px;
  font-family: var(--font-body); font-size: 13px;
  color: var(--text-primary);
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 6px;
}
.preset-picker-select:focus-visible {
  outline: 2px solid var(--accent-secondary-xlight);
  outline-offset: 1px;
}
.preset-picker-hint {
  margin: 0; max-width: 320px;
  font-family: var(--font-body); font-size: 12px; line-height: 1.35;
  color: var(--text-muted);
}
.preset-picker-hint:empty { display: none; }

/* Settings → dual-role toggle */
.role-toggle-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
}
/* A native checkbox on a dark card paints as a stark white square — the one
   unstyled control on the page. This is the same input, restyled as a switch:
   `appearance: none` removes the platform box, the ::after is the knob. The
   input keeps its name, checked state and form semantics, so the
   `dual_role_form` marker field and the onchange submit are unaffected. */
.role-toggle-row input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  flex: 0 0 auto;
  width: 38px;
  height: 22px;
  margin: 0;
  border-radius: 999px;
  border: 1px solid var(--border-default, var(--line));
  background: var(--bg-elevated, var(--surface-2));
  cursor: pointer;
  transition: background .18s, border-color .18s;
}
.role-toggle-row input[type="checkbox"]::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 3px;
  width: 16px;
  height: 16px;
  transform: translateY(-50%);
  border-radius: 50%;
  background: var(--text-secondary, var(--muted));
  transition: transform .18s, background .18s;
}
.role-toggle-row input[type="checkbox"]:checked {
  background: var(--ink);
  border-color: transparent;
}
.role-toggle-row input[type="checkbox"]:checked::after {
  transform: translateY(-50%) translateX(15px);
  background: var(--ink);
}
.role-toggle-row input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent-primary, var(--focus-ring));
  outline-offset: 2px;
}

/* ══════════════════════════════════════════════════════════════════════════
   MOBILE NAVIGATION — consolidated

   Two earlier media queries fought each other and left mobile with no
   working navigation at all:

     @media (max-width: 768px) { .sidenav { display: none } }   (line ~3358)
     @media (max-width: 900px) { .sidenav { transform: ... } }  (line ~3609)

   The drawer rules came later and won on transform, but nothing overrode
   `display: none`, so at 768px and below the drawer was simply not rendered.
   Tapping the hamburger added .open to an element that could never paint —
   which is why the menu appeared to do nothing and no page was reachable.

   Separately, .mobile-bottom-nav is `display: flex`, which made
   .mobile-bottom-nav-inner a flex *item*. With `flex: 0 1 auto` it sized to
   its content (171px of a 402px bar), so the five tabs bunched into the left
   corner with their labels overlapping.

   Everything mobile-nav now lives in this one block so the two cannot drift
   apart again.
   ═══════════════════════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  .mobile-nav-toggle { display: flex; }

  /* Off-canvas drawer. `display` is forced because the older rule above
     still sets `display: none` at <=768px. */
  .sidenav {
    display: flex !important;
    flex-direction: column;
    position: fixed;
    top: 0; left: 0; bottom: 0;
    width: min(300px, 84vw);
    max-width: 300px;
    transform: translateX(-100%);
    transition: transform .26s cubic-bezier(.4,0,.2,1);
    z-index: 1000;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    box-shadow: 4px 0 28px rgb(var(--shade-rgb) / .5);
  }
  .sidenav.open { transform: translateX(0); }
  .mobile-nav-backdrop.open { display: block; }

  /* The collapse chevron is a desktop affordance — in a drawer it would
     shrink the panel the user just opened. */
  .sidenav .sn-toggle { display: none; }
  /* A drawer is never in collapsed mode, whatever the desktop preference. */
  .sidenav.sn-c { width: min(300px, 84vw); }
  .sidenav.sn-c .sn-lbl { opacity: 1; width: auto; }
  .sidenav.sn-c .sn-item { justify-content: flex-start; padding: 10px 12px;
                           margin: 2px 8px; width: calc(100% - 16px); gap: 12px; }
  .sidenav.sn-c .sn-sec { justify-content: flex-start; padding: 14px 16px 4px; }
  .sidenav.sn-c .sn-sec .sn-lbl { display: block; }
  .sidenav.sn-c .sn-logo { opacity: 1; width: auto; }

  .main-wrap, .app-shell { margin-left: 0 !important; }
}

@media (max-width: 768px) {
  .mobile-bottom-nav { display: flex; }
  /* The bar is a flex container, so the inner row must be told to fill it —
     otherwise it collapses to content width and the tabs bunch left. */
  .mobile-bottom-nav-inner { flex: 1 1 auto; width: 100%; min-width: 0; }
  .mobile-nav-item { min-width: 0; padding: 0 2px; }
  .mobile-nav-item span { max-width: 100%; overflow: hidden;
                          text-overflow: ellipsis; white-space: nowrap; }

  /* Clear the fixed bottom bar, plus the iOS home indicator. */
  .app-shell { padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }
  .mobile-bottom-nav {
    height: calc(64px + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  /* The Signal button sat on top of the bottom bar and covered a tab. */
  .signal-widget { bottom: calc(80px + env(safe-area-inset-bottom, 0px)) !important; }
  .signal-panel  { width: min(340px, calc(100vw - 32px)); }

  /* Content starts below the fixed hamburger. */
  .app-shell { padding-top: 64px; }
}

/* Six slots on the narrowest phones: at 320px a slot is 53px, and "Challenges"
   and "Dashboard" at 11px measured 55-56px, so they were cut. Without the side
   padding and at 10px every label fits (measured over CDP at 320px). */
@media (max-width: 359px) {
  .mobile-nav-item { padding: 0; }
  .mobile-nav-item span { font-size: 10px; }
}

@media (max-width: 900px) {
  /* The fixed hamburger sits at x=14 and overlaps the drawer's logo when the
     drawer is open. Indent the drawer header past it. */
  .sidenav .sn-top { padding-left: 68px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   CREDIBILITY — rating / reviews / plays
   Shown on marketplace cards and profile headers so people can judge who to
   work with before committing. Uses the brand amber for stars (the only
   non-brand hue on the page, because a purple star does not read as a star)
   and the existing muted greys for counts.
   ═══════════════════════════════════════════════════════════════════════ */
.cred-stars { display: inline-flex; align-items: center; gap: 1px; vertical-align: -2px; }
.cred-star { width: 14px; height: 14px; }
.cred-stars-sm .cred-star { width: 12px; height: 12px; }
.cred-star.is-full  { fill: var(--warning); color: var(--warning); }
.cred-star.is-half  { color: var(--warning); stroke: var(--line); stroke-width: 1.5; }
.cred-star.is-empty { fill: none; stroke: var(--line); stroke-width: 1.5; }

.cred-inline { display: inline-flex; align-items: center; gap: 5px;
               font-size: 12px; color: var(--text-muted); }
.cred-score  { color: var(--text-primary); font-weight: 600; }
.cred-count  { color: var(--text-muted); }
.cred-dot    { color: var(--text-muted); opacity: .6; }
.cred-new    { font-size: 11px; font-weight: 600; letter-spacing: .04em;
               text-transform: uppercase; color: var(--accent-secondary);
               background: rgb(var(--ink-rgb) / .06); border: 1px solid var(--line);
               border-radius: 999px; padding: 2px 8px; }

.cred-stats { display: flex; gap: 26px; flex-wrap: wrap; margin: 14px 0 10px; }
.cred-stat { display: flex; flex-direction: column; gap: 3px; }
.cred-stat-value { font-family: var(--font-display); font-size: 20px;
                   font-weight: 700; line-height: 1; color: var(--text-primary); }
.cred-stat-label { font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
                   color: var(--text-muted); display: flex; align-items: center; gap: 4px; }

/* ── Account tabs (Profile / Settings merged into one nav entry) ─────────── */
.acct-tabs { display: flex; gap: 4px; margin-bottom: 22px;
             border-bottom: 1px solid var(--border-subtle); padding-bottom: 12px; }
.acct-tab { display: inline-flex; align-items: center; gap: 7px; padding: 8px 16px;
            border-radius: 8px; font-size: 13px; font-weight: 500;
            color: var(--text-secondary); text-decoration: none;
            border: 1px solid transparent; transition: all .15s; }
.acct-tab:hover  { background: rgb(var(--ink-rgb) / .04); color: var(--text-primary); }
.acct-tab.active { background: rgb(var(--ink-rgb) / .07); border-color: var(--line);
                   color: var(--ink); }

/* ── Section tabs (Create / Studio / Social grouped into one nav entry each) ─
   Same visual language as .acct-tabs deliberately: four areas of the app that
   all behave the same way should not each look different. Scrolls sideways on a
   phone rather than wrapping to two rows, which would push the page content
   below the fold. */
/* One container for the bar on every page. Its width is deliberately fixed
   here and not inherited from the page wrapper — see the note in base.html.
   1100/24px matches .page-wrap, which most tabbed pages already used. */
.sec-tabs-wrap {
  max-width: 1100px;
  margin: 0 auto;
  padding: 28px 24px 0;
}
.sec-tabs {
  display: flex;
  gap: 4px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-subtle);
  overflow-x: auto;
  scrollbar-width: none;
}
/* ── One page container ──────────────────────────────────────────────────────
   Every app page's wrapper starts its first block at the same place: the left
   edge of the 1100px column the tab bar uses, 28px below the top (the bar's own
   top padding, so an untabbed page's header sits where a tabbed page's bar does).
   Measured before this rule, the header block started anywhere from x=42 to
   x=302 and y=21 to y=69 depending on which wrapper the page used.

   A page that wants a narrower reading column sets --page-measure on its own
   wrapper. The column is then that wide and left-aligned on the shared edge,
   the same treatment `.sec-tabs-wrap + .studio-layout > *` gives a tabbed form.
   Bottom padding is each page's own business and is not set here. */
.app-shell > :is(.page-wrap, .dashboard-layout, .studio-layout, .search-page,
                 .form-page, .explore-page, .marketplace-wrap, .settings-page,
                 .profile-page, .journey-page) {
  width: 100%;
  max-width: calc(var(--page-measure, 1052px) + 2 * var(--page-gutter));
  margin-left: max(0px, (100% - 1100px) / 2);
  margin-right: auto;
  padding-top: var(--page-top);
  padding-left: var(--page-gutter);
  padding-right: var(--page-gutter);
}
:root { --page-top: 28px; --page-gutter: 24px; }
/* A page whose first block is a bare centred header rather than a wrapper. */
.app-shell > .page-header:first-child { padding-top: var(--page-top); }
/* An artist's studio bar renders no tabs and is hidden (base.css); the page
   under it is then untabbed and keeps the full top gap. */
.sec-tabs-wrap:has(.sec-tab) + .page-header { padding-top: 8px; }

/* A tabbed page shares the bar's container exactly, so the tabs and the content
   below them line up on one left edge. Without this the wrappers kept their own
   widths — 800 for .studio-layout, 680 for .search-page, 1200 for
   .dashboard-layout — and the bar floated up to 190px left of the content it
   belonged to. The bar supplies the gap above the heading, so the page's own top
   padding is dropped rather than stacked. */
.sec-tabs-wrap:has(.sec-tab) + .page-wrap,
.sec-tabs-wrap:has(.sec-tab) + .studio-layout,
.sec-tabs-wrap:has(.sec-tab) + .dashboard-layout,
.sec-tabs-wrap:has(.sec-tab) + .search-page,
.sec-tabs-wrap:has(.sec-tab) + .form-page {
  max-width: 1100px;
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--page-gutter);
  padding-right: var(--page-gutter);
  padding-top: 8px;
}
/* Widening the container must not turn a form into a 1050px-wide line length.
   The column keeps a readable width and left-aligns under the first tab. */
.sec-tabs-wrap + .studio-layout > *,
.sec-tabs-wrap + .form-page > *   { max-width: 820px; width: 100%; }
.sec-tabs-wrap + .search-page > * { max-width: 680px; width: 100%; }
.sec-tabs::-webkit-scrollbar { display: none; }
.sec-tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: 0 0 auto;
  padding: 8px 16px;
  border-radius: 8px;
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  text-decoration: none;
  border: 1px solid transparent;
  transition: all .15s;
  white-space: nowrap;
}
.sec-tab:hover  { background: rgb(var(--ink-rgb) / .04); color: var(--text-primary); }
.sec-tab.active { background: rgb(var(--ink-rgb) / .07); border-color: var(--line);
                  color: var(--ink); }
.sec-tab svg    { flex-shrink: 0; }
@media (max-width: 900px) {
  .sec-tabs-wrap { padding: 16px 16px 0; }
  /* The bar is 16px from the edge here, so the page is too. */
  :root { --sec-tabs-h: 62px; --page-top: 16px; --page-gutter: 16px; }
}
@media (max-width: 640px) {
  .sec-tabs { gap: 2px; padding-bottom: 10px; }
  .sec-tab  { padding: 7px 12px; font-size: 12.5px; }
}
/* `has-more` is set by script only while there is unscrolled content to the
   right, so the last tab is never left faded once you reach the end. */
.sec-tabs.has-more {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
          mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
}

/* ── Review prompt + star picker ─────────────────────────────────────────── */
.review-prompt { background: var(--bg-surface); border: 1px solid var(--border-subtle);
                 border-radius: 14px; padding: 18px 20px; margin-bottom: 22px; }
.review-prompt-head { font-family: var(--font-display); font-size: 15px;
                      font-weight: 600; margin-bottom: 4px; }
.review-prompt-sub  { font-size: 13px; color: var(--text-muted); margin-bottom: 14px; }
.review-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
              padding: 10px 0; border-top: 1px solid var(--border-subtle); }
.review-row-who { flex: 1; min-width: 150px; font-size: 13px; }
.review-row-who strong { color: var(--text-primary); }
.review-row-track { color: var(--text-muted); font-size: 12px; }
.star-picker { display: inline-flex; gap: 2px; }
.star-picker button { background: none; border: none; padding: 2px; cursor: pointer;
                      line-height: 0; color: var(--muted); transition: color .12s; }
.star-picker button svg { width: 20px; height: 20px; fill: currentColor; }
.star-picker button:hover, .star-picker button.on { color: var(--warning); }
.review-done { font-size: 12px; color: var(--accent-secondary); }

@media (max-width: 640px) {
  .cred-stats { gap: 18px; }
  .cred-stat-value { font-size: 17px; }
}
.beat-card-cred { margin-top: 4px; }
.voc-card-cred  { padding: 0 16px 10px; }

/* ── Recommendations panel ───────────────────────────────────────────────── */
.reco-panel { background: var(--bg-surface); border: 1px solid var(--border-subtle);
              border-radius: 14px; padding: 18px 20px; margin-bottom: 22px; }
.reco-head { margin-bottom: 12px; }
.reco-title { display: block; font-family: var(--font-display); font-size: 15px;
              font-weight: 600; color: var(--text-primary); }
.reco-sub   { display: block; font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.reco-list  { display: flex; flex-direction: column; }
.reco-row   { display: flex; align-items: center; gap: 12px; padding: 10px 0;
              border-top: 1px solid var(--border-subtle); text-decoration: none;
              color: inherit; transition: opacity .15s; }
.reco-row:hover { opacity: .82; }
.reco-avatar { width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
               background: var(--surface-3); display: flex; align-items: center;
               justify-content: center; font-family: var(--font-display);
               font-weight: 700; color: var(--ink); overflow: hidden; }
.reco-avatar img { width: 100%; height: 100%; object-fit: cover; }
.reco-meta { flex: 1; min-width: 0; }
.reco-name { font-size: 14px; font-weight: 600; color: var(--text-primary);
             display: flex; align-items: center; gap: 5px; }
.reco-verified { color: var(--accent-secondary); font-size: 12px; }
.reco-reason { font-size: 12px; color: var(--text-secondary); margin-top: 1px; }
.reco-cred { margin-top: 3px; }
.reco-arrow { width: 16px; height: 16px; color: var(--text-muted); flex-shrink: 0; }

/* ── Browser vocal recorder ─────────────────────────────────────────────── */
.vox-disclosure { margin-top: 10px; width: 100%; }
.vox-disclosure > summary {
  cursor: pointer; list-style: none;
  font-family: var(--font-body); font-size: 12px; font-weight: 600;
  color: var(--accent-secondary-xlight);
  padding: 4px 0;
}
.vox-disclosure > summary::-webkit-details-marker { display: none; }
.vox-disclosure > summary::before { content: "▸ "; }
.vox-disclosure[open] > summary::before { content: "▾ "; }

.vox-recorder {
  margin-top: 10px; padding: 14px;
  border: 1px solid var(--border-default); border-radius: 10px;
  background: var(--bg-elevated);
  display: flex; flex-direction: column; gap: 10px;
  max-width: 420px;
}
.vox-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.vox-title {
  font-family: var(--font-display); font-size: 14px; font-weight: 700;
}
.vox-headphones {
  font-family: var(--font-body); font-size: 10px; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px;
  color: var(--ink); background: rgb(var(--ink-rgb) / .06);
  border: 1px solid var(--line);
}
.vox-hint {
  margin: 0; font-family: var(--font-body); font-size: 12px; line-height: 1.45;
  color: var(--text-muted);
}
.vox-beat { display: none; }

.vox-meter {
  height: 6px; border-radius: 3px; overflow: hidden;
  background: rgb(var(--ink-rgb) / .07);
}
.vox-meter-fill {
  height: 100%; width: 0;
  background: linear-gradient(var(--ink), var(--ink));
  transition: width .05s linear;
}

.vox-controls { display: flex; gap: 8px; flex-wrap: wrap; }
.vox-status {
  margin: 0; min-height: 1.2em;
  font-family: var(--font-body); font-size: 12px; line-height: 1.45;
  color: var(--text-secondary);
}
.vox-review { display: flex; flex-direction: column; gap: 8px; }
.vox-playback { width: 100%; }
/* Timing nudge. Shared by the dashboard recorder panel (.vox-) and the beat
   page's own recorder (.rec-) — two surfaces with different data contracts,
   one control. Defined once so the two cannot drift the way the recorder
   engines themselves did. */
.vox-nudge-row,
.rec-nudge-row { display: flex; align-items: center; gap: 8px; }
.vox-nudge-label,
.rec-nudge-label {
  font-family: var(--font-body); font-size: 11px; font-weight: 600;
  letter-spacing: .03em; text-transform: uppercase; color: var(--text-muted);
  white-space: nowrap;
}
.vox-nudge,
.rec-nudge { flex: 1 1 auto; min-width: 0; }
.vox-nudge-value,
.rec-nudge-value {
  font-family: var(--font-body); font-size: 12px; color: var(--text-primary);
  min-width: 52px; text-align: right;
}
.rec-with-beat { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 10px 0 4px; }
.rec-with-beat-hint {
  flex: 1 1 220px; margin: 0;
  font-family: var(--font-body); font-size: 12px; line-height: 1.45; color: var(--text-muted);
}
.rec-nudge-hint {
  font-family: var(--font-body); font-size: 12px; line-height: 1.45;
  color: var(--text-muted); margin: 0;
}
/* The beat page's nudge is a disclosure; its summary carries the value. */
.rec-nudge-more > .rec-nudge-row { margin-top: 8px; }
.rec-nudge-more > .rec-nudge-hint { margin-top: 6px; }
.rec-nudge-summary {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  min-height: 32px; cursor: pointer;
  font-family: var(--font-body); font-size: 13px; color: var(--text-primary);
}
.rec-nudge-summary .rec-nudge-value { min-width: 0; text-align: left; }

/* Stated-tempo field on the acapella upload form */
.bpm-field { display: flex; flex-direction: column; gap: 3px; flex: 1 1 100%; min-width: 0; }
.bpm-label {
  font-family: var(--font-body); font-size: 11px; font-weight: 600;
  letter-spacing: .03em; text-transform: uppercase; color: var(--text-muted);
}
.bpm-row { display: flex; align-items: center; gap: 6px; }
.bpm-input {
  width: 110px; padding: 6px 8px;
  font-family: var(--font-body); font-size: 13px;
  color: var(--text-primary); background: var(--bg-elevated);
  border: 1px solid var(--border-default); border-radius: 6px;
}
.bpm-input:focus-visible {
  outline: 2px solid var(--accent-secondary-xlight); outline-offset: 1px;
}
.bpm-suffix {
  font-family: var(--font-body); font-size: 12px; color: var(--text-muted);
}
.bpm-hint {
  margin: 0; max-width: 320px;
  font-family: var(--font-body); font-size: 12px; line-height: 1.35;
  color: var(--text-muted);
}

/* "I recorded this over this beat" — the answer that decides whether the
   tempo and key estimators run at all. */
.rec-origin-row {
  display: flex; align-items: flex-start; gap: 8px;
  flex: 1 1 100%; min-width: 0; cursor: pointer;
}
.rec-origin-check {
  flex: 0 0 auto; margin: 2px 0 0; width: 16px; height: 16px;
  accent-color: var(--brand-pink, var(--ink));
}
.rec-origin-text {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
  font-family: var(--font-body); font-size: 13px; color: var(--text-primary);
}
.rec-origin-hint {
  font-size: 12px; line-height: 1.35; color: var(--text-muted);
  max-width: 340px;
}

/* ── Badge colours used outside the admin dashboard ──────────────────────────
   badge-green and badge-amber were defined only inside admin_dashboard.html's
   inline <style>, so release.html, catalog.html and calendar.html rendered
   "Released" / "Live on streaming" as an unstyled grey pill. Defined here so
   every template gets the same colour. */
.badge-green { background: var(--surface-2);  border: 1px solid var(--line);  color: var(--success-light); }
.badge-amber { background: var(--surface-2); border: 1px solid var(--line); color: var(--warning-light); }

/* ── Beat page ───────────────────────────────────────────────────────────────
   One beat, every version on it. Shares the page-wrap container and the badge,
   chip, player and credibility vocabulary already used on marketplace cards —
   nothing here introduces a new visual language. */
.beat-back {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--text-muted); text-decoration: none;
  margin-bottom: 20px;
}
.beat-back:hover { color: var(--text-primary); }
.beat-back svg { width: 14px; height: 14px; }

.beat-head { display: flex; gap: 28px; margin-bottom: 22px; }
/* An explicit width, because the artwork inside is `width: 100%` — and 100% of
   a flex item with no basis resolves to its CONTENT width, which measured
   38px. The placeholder's initials are 64px tall, so they overflowed a 38px
   box and the beat page showed two letters colliding where the cover should
   be. The mobile rule below always set a width, which is why this only ever
   looked wrong on a desktop. */
.beat-head-cover { flex-shrink: 0; width: 148px; }
.beat-head-cover .cover-placeholder { width: 148px; height: 148px; }
.beat-head-main  { flex: 1; min-width: 0; }
.beat-head-badges { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.beat-head-title {
  font-family: var(--font-display);
  font-size: 34px; font-weight: 700; line-height: 1.1;
  color: var(--text-primary); margin: 0 0 6px;
}
.beat-head-by { font-size: 14px; color: var(--text-secondary); margin-bottom: 14px; }
.beat-head-by a { color: var(--text-primary); text-decoration: none; }
.beat-head-by a:hover { color: var(--accent-secondary); }
.beat-head-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
/* The rule in a sentence: what an artist may actually do on this beat. Sits
   between the facts and the button, because it is the thing that decides
   whether pressing the button is even possible. Muted rather than an alert —
   this is the normal state of every beat, not a warning. */
.beat-head-rule {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 0 16px; padding: 9px 12px;
  background: var(--surface-2); border: 1px solid var(--border-subtle);
  border-radius: 10px;
  color: var(--text-secondary); font-size: 13px; line-height: 1.5;
}
.beat-head-rule svg { flex: 0 0 auto; width: 15px; height: 15px; margin-top: 2px; }
.beat-head-actions { margin-top: 16px; }

/* Activity. Wraps rather than scrolling — these are seven short numbers, and a
   horizontal scroller would hide the ones on the right on a phone. */
.beat-stats {
  display: flex; flex-wrap: wrap; gap: 12px;
  padding: 14px 18px; margin-bottom: 22px;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}
.beat-stat { flex: 1 1 90px; min-width: 84px; }
.beat-stat-value {
  font-family: var(--font-display);
  font-size: 24px; font-weight: 700; line-height: 1.1;
  color: var(--text-primary);
}
.beat-stat-label {
  font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-muted); margin-top: 3px;
}

.beat-versions-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 14px;
}
.beat-versions-hint { font-size: 13px; color: var(--warning-light); }

/* Invite an artist. Producer-only, and built from the same card and row
   vocabulary as the versions list below it so the two read as one page rather
   than as a panel bolted on. */
.beat-invite { margin-bottom: 32px; }
.beat-invite-list { list-style: none; margin: 0; padding: 0;
                    display: flex; flex-direction: column; gap: 8px; }
.beat-invite-row {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 10px 14px;
}
/* min-width:0 so a long reason can shrink instead of forcing the row wider than
   the page — the fault that gave the vocalist dashboard 7px of sideways scroll
   at 390px. */
.beat-invite-who { display: flex; flex-direction: column; gap: 2px;
                   min-width: 0; text-decoration: none; }
.beat-invite-name { color: var(--text-primary); font-weight: 600; font-size: 14px; }
.beat-invite-why  { color: var(--text-muted); font-size: 12px; }
.beat-invite-row.is-invited { opacity: 0.6; }
.beat-invite-status { margin-top: 10px; }
@media (max-width: 480px) {
  .beat-invite-row { align-items: stretch; }
  .beat-invite-row .btn { width: 100%; }
}

.beat-versions { list-style: none; margin: 0; padding: 0;
                 display: flex; flex-direction: column; gap: 14px; }
.beat-version {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
}
/* A revision is a child of the take above it, so it is indented rather than
   given its own card — the original still exists and the relationship is the
   point. */
.beat-version.is-revision { margin-left: 24px; border-left: 2px solid var(--line); }

.beat-version-top {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 10px; margin-bottom: 12px;
}
.beat-version-artist {
  display: flex; align-items: center; gap: 10px;
  text-decoration: none; color: inherit; min-width: 0;
}
.beat-version-artist:hover .beat-version-name { color: var(--accent-secondary); }
.beat-version-name { font-weight: 600; font-size: 15px; color: var(--text-primary); }
.beat-version-tags { display: flex; flex-wrap: wrap; gap: 6px; }

.beat-version-audio { margin-bottom: 10px; }
.beat-version-pending {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; color: var(--text-muted); margin-bottom: 10px;
}
.beat-version-pending svg { width: 14px; height: 14px; flex-shrink: 0; }

.beat-version-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  font-size: 12px; color: var(--text-muted);
}
.beat-version-meta a {
  display: inline-flex; align-items: center; gap: 5px;
  color: var(--accent-secondary); text-decoration: none;
}
.beat-version-meta a svg { width: 12px; height: 12px; }
.beat-version-date { margin-left: auto; }

.beat-version-note {
  margin-top: 12px; padding: 10px 12px;
  background: var(--bg-elevated, rgb(var(--ink-rgb) / .03));
  border-left: 2px solid var(--border-default);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 13px; color: var(--text-secondary);
}
.beat-version-note-label {
  display: block; font-size: 11px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-muted); margin-bottom: 3px;
}

/* Note and buttons on one row. Both containers used to wrap, so the actions
   box took the full remaining width and Accept stretched across the card with
   the other two dropping beneath it. */
.beat-review {
  margin-top: 14px; padding-top: 14px;
  border-top: 1px solid var(--border-subtle);
  display: flex; gap: 10px; align-items: center;
}
.beat-review-note {
  flex: 1 1 auto; min-width: 0;
  padding: 9px 12px; font-size: 13px;
  background: var(--bg-base); color: var(--text-primary);
  border: 1px solid var(--border-subtle); border-radius: var(--radius);
}
.beat-review-note:focus { outline: none; border-color: var(--accent-primary); }
.beat-review-actions { flex: 0 0 auto; display: flex; gap: 8px; }
/* Normalised inside this row for two reasons: .btn-gradient carries
   `width: 100%`, which made Accept stretch across the whole card, and it pads
   12px against .btn-ghost's 10px, so the three buttons came out 45px and 40px
   tall side by side. */
.beat-review-actions .btn-gradient,
.beat-review-actions .btn-ghost {
  white-space: nowrap;
  width: auto;
  padding: 11px 18px;
}
.beat-review-pass { color: var(--danger-light); }

.beat-version-own {
  margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--border-subtle);
  display: flex; flex-wrap: wrap; gap: 8px;
}

@media (max-width: 720px) {
  /* The cover stays beside the title rather than stacking above it. Full
     width it was a 360px square — half a phone screen — before the beat's
     name, its producer, the BPM or the player. It is artwork, not
     information. */
  .beat-head { flex-direction: row; align-items: flex-start; gap: 14px; }
  .beat-head-cover { width: 96px; flex-shrink: 0; }
  .beat-head-cover .cover-placeholder { width: 96px; height: 96px; }
  .beat-head-cover .cover-placeholder-text { font-size: 26px; }
  .beat-head-cover .cover-placeholder-genre { display: none; }
  .beat-head-title { font-size: 22px; }
  .beat-head-badges { margin-bottom: 6px; }
  .beat-stat { flex: 1 1 calc(33.333% - 8px); }
  /* The indent costs more than the relationship is worth at this width. */
  .beat-version.is-revision { margin-left: 10px; }
  .beat-version-date { margin-left: 0; }
  .beat-review { flex-wrap: wrap; }
  .beat-review-note { flex: 1 1 100%; }
  /* Grid rather than a wrapping flex row: the three labels are different
     lengths, so flex gave two rows of unequal cells. Accept and Request
     revision share row one, Pass spans row two, and grid stretch keeps every
     cell the same height. */
  .beat-review-actions {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
  }
  .beat-review-actions .beat-review-pass { grid-column: 1 / -1; }
  .beat-review-actions .btn-gradient,
  .beat-review-actions .btn-ghost { white-space: normal; padding: 11px 10px; }
}

/* ── Notifications panel ─────────────────────────────────────────────────────
   The read side of emit_event()'s fan-out. Matches .review-prompt exactly —
   same card, same rhythm — because they sit next to each other at the top of
   the dashboard and a second visual language there would read as two products. */
.notif-panel { background: var(--bg-surface); border: 1px solid var(--border-subtle);
               border-radius: 14px; padding: 18px 20px; margin-bottom: 22px; }
.notif-head { display: flex; align-items: baseline; justify-content: space-between;
              gap: 12px; margin-bottom: 10px; }
.notif-title { font-family: var(--font-display); font-size: 15px; font-weight: 600;
               color: var(--text-primary); }
.notif-clear { background: none; border: none; padding: 0; cursor: pointer;
               font-size: 12px; color: var(--text-muted); }
.notif-clear:hover:not(:disabled) { color: var(--text-primary); }
.notif-clear:disabled { opacity: .5; cursor: default; }

.notif-list { list-style: none; margin: 0; padding: 0; }
.notif-row { display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
             padding: 10px 0; border-top: 1px solid var(--border-subtle);
             font-size: 13px; color: var(--text-secondary); }
.notif-icon { flex-shrink: 0; color: var(--text-muted); line-height: 0; padding-top: 2px; }
.notif-icon svg { width: 14px; height: 14px; }
/* Unread is marked by weight and the accent icon, not by a filled row: a block
   of highlighted rows is louder than the information in them. */
.notif-row.is-unread .notif-icon { color: var(--accent-secondary); }
.notif-row.is-unread .notif-body { color: var(--text-primary); }
.notif-body { flex: 1; min-width: 160px; }
.notif-note { display: block; color: var(--text-muted); font-size: 12px; margin-top: 2px; }
.notif-link { flex-shrink: 0; font-size: 12px; color: var(--accent-secondary);
              text-decoration: none; }
.notif-link:hover { text-decoration: underline; }

/* ── In-browser recorder (beat page) ─────────────────────────────────────────
   Same card as .beat-version and .notif-panel. The recorder is a step in the
   same flow, not a separate tool, so it does not get its own look. */
.rec-panel {
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg); padding: 18px 20px; margin-bottom: 28px;
}
.rec-head { display: flex; flex-wrap: wrap; align-items: baseline;
            justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.rec-hint { display: inline-flex; align-items: center; gap: 6px;
            font-size: 12px; color: var(--text-muted); }
.rec-hint svg { width: 14px; height: 14px; flex-shrink: 0; }
.rec-unsupported { font-size: 13px; color: var(--text-secondary); }

/* Peak meter. Green through most of the range, amber approaching full scale,
   red at the top — the reading that matters is "about to clip". */
.rec-meter {
  height: 6px; border-radius: 3px; overflow: hidden; margin-bottom: 14px;
  background: rgb(var(--ink-rgb) / .06);
}
.rec-meter-fill {
  height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--success) 0%, var(--success) 70%,
                              var(--warning) 88%, var(--danger) 100%);
  transition: width 60ms linear;
}
.rec-meter-fill.is-hot { background: var(--danger); }

.rec-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
/* .btn supplies inline-flex, the 8px gap and the radius; -gradient/-ghost are
   modifiers over it. Omitting .btn leaves the icon stacked above the label. */
.rec-btn { width: auto; padding: 11px 18px; white-space: nowrap; }
.rec-btn svg { width: 14px; height: 14px; }
.rec-time { font-family: var(--font-display); font-size: 18px; font-weight: 600;
            font-variant-numeric: tabular-nums; color: var(--text-primary); }
.rec-status { font-size: 13px; color: var(--text-muted); }
.rec-status--error { color: var(--danger-light); }
.rec-status--ok    { color: var(--success-light); }
/* A live indicator has to be unmistakable — someone stepping away from the mic
   must be able to tell at a glance that it is still running. */
.rec-status--live  { color: var(--danger-light); font-weight: 600; }
.rec-status--live::before {
  content: ''; display: inline-block; width: 8px; height: 8px; margin-right: 6px;
  border-radius: 50%; background: var(--danger);
  animation: rec-pulse 1.2s ease-in-out infinite;
}
@keyframes rec-pulse { 0%, 100% { opacity: 1 } 50% { opacity: 0.25 } }

.rec-review { margin-top: 16px; padding-top: 16px;
              border-top: 1px solid var(--border-subtle); }
.rec-playback { margin-bottom: 12px; }
/* The take check, in the recorder's review panel. Same component as the
   dashboard upload form's — one verdict vocabulary — with a margin so it does
   not sit flush against the Send row and read as part of it. */
.rec-take-check { margin: 14px 0 16px; }
.rec-review-actions { display: flex; flex-wrap: wrap; gap: 8px; }

/* ── Sent ──────────────────────────────────────────────────────────────────
   The state that replaced window.location.reload(). It has to answer three
   things an artist has just earned the right to ask: did it arrive, who has
   it, and what happens now. */
.rec-sent { text-align: center; padding: 28px 20px; }
.rec-sent-icon { color: var(--success); margin-bottom: 10px; }
.rec-sent-icon svg { width: 40px; height: 40px; }
.rec-sent-title { margin: 0 0 6px; font-size: 20px; color: var(--text-primary); }
.rec-sent-sub   { margin: 0 0 18px; color: var(--text-secondary); }
/* Numbered, left-aligned inside a centred block: these are three steps in
   order, and centring a list makes the sequence harder to read than it is. */
.rec-sent-next {
  list-style: decimal; text-align: left;
  max-width: 420px; margin: 0 auto 22px; padding-left: 22px;
  color: var(--text-secondary); font-size: 14px; line-height: 1.7;
}
.rec-sent-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }

/* ── Guided setup: allow → pick → check → headphones ─────────────────────────
   The whole list disappears once it is satisfied (.is-complete), because a
   completed checklist above the controls is clutter with no remaining use.
   Steps ahead of the current one are dimmed rather than hidden: seeing what
   is coming is what stops the sequence feeling like an interrogation. */
.rec-setup { margin-bottom: 4px; }
.rec-setup.is-complete { display: none; }

.rec-steps {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
  counter-reset: rec-step;
}
.rec-step {
  counter-increment: rec-step;
  display: grid; grid-template-columns: 22px 1fr; gap: 12px;
  padding: 12px 2px;
  opacity: 0.45;
  transition: opacity 160ms ease;
}
.rec-step + .rec-step { border-top: 1px solid var(--border-subtle); }
.rec-step.is-current, .rec-step.is-done { opacity: 1; }

/* The dot is the step number until the step is done, then a tick. Numbers
   come from the list counter rather than the markup, so inserting a step is
   one <li> and not a renumbering pass. */
.rec-step-dot {
  width: 22px; height: 22px; margin-top: 1px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--border-subtle);
  background: var(--bg-elevated);
  font-family: var(--font-display); font-size: 11px; font-weight: 600;
  color: var(--text-muted);
}
.rec-step-dot::before { content: counter(rec-step); }
.rec-step.is-current .rec-step-dot {
  border-color: var(--line-control);
  color: var(--accent-primary-light);
}
.rec-step.is-done .rec-step-dot {
  border-color: var(--success);
  background: var(--surface-2);
  color: var(--success-light);
}
.rec-step.is-done .rec-step-dot::before { content: '\2713'; font-size: 12px; }

.rec-step-title {
  margin: 0 0 4px; font-family: var(--font-display);
  font-size: 14px; font-weight: 600; color: var(--text-primary);
}
.rec-step-body {
  margin: 0 0 10px; font-size: 13px; line-height: 1.55;
  color: var(--text-secondary); max-width: 62ch;
}
.rec-step .rec-btn { margin-bottom: 0; }
/* .status supplies the colour, border and padding; these only place it. */
.rec-step-error, .rec-step-verdict { margin: 10px 0 0; font-size: 13px; }

.rec-device { max-width: 320px; margin-bottom: 10px; }

/* Taller than the live meter, because this one is being read deliberately
   rather than glanced at, and it carries a target band. The band spans the
   range between "the engine would refuse this" and "this is clipping" —
   0.02 and 0.98 peak in the check, which the fill maps to 2.8% and 100%. */
.rec-meter--check { position: relative; height: 12px; border-radius: var(--radius-sm); }
.rec-meter-zone {
  position: absolute; top: 0; bottom: 0; left: 30%; right: 10%;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  background: rgb(var(--ink-rgb) / .05);
  pointer-events: none;
}

.rec-phones-row {
  display: flex; align-items: center; gap: 10px;
  font-size: 13px; color: var(--text-secondary); cursor: pointer;
}
/* Same reasoning as the Settings switch: the native control on a dark card is
   a stark white square and the one unstyled thing on the page. */
.rec-phones-check {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; flex: none; margin: 0;
  border: 1px solid var(--border-subtle); border-radius: var(--radius-sm);
  background: var(--bg-elevated); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.rec-phones-check:checked {
  border-color: var(--success);
  background: var(--surface-2);
}
.rec-phones-check:checked::after {
  content: '\2713'; font-size: 12px; line-height: 1; color: var(--success-light);
}
.rec-phones-check:focus-visible {
  outline: 2px solid var(--accent-primary); outline-offset: 2px;
}

@media (max-width: 720px) {
  .rec-row { gap: 10px; }
  .rec-review-actions .rec-btn { flex: 1 1 auto; }
  .rec-step { grid-template-columns: 20px 1fr; gap: 10px; }
  .rec-step-dot { width: 20px; height: 20px; }
  .rec-device { max-width: 100%; }
  .rec-step .rec-btn { width: 100%; justify-content: center; }
}

/* Reduced motion: the pulsing dot is decoration, the colour carries the state. */
@media (prefers-reduced-motion: reduce) {
  .rec-status--live::before { animation: none; }
}

/* ── Daily briefing ──────────────────────────────────────────────────────────
   Sits at the top of the dashboard, above the suggestions it implies. Same
   card as .review-prompt and .notif-panel — this is a step in the same flow,
   not a separate product. */
.brief-panel {
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-radius: 14px; padding: 20px; margin-bottom: 22px;
  position: relative; overflow: hidden;
}
/* A single accent edge rather than a filled card: the briefing is read every
   day, and a permanently loud panel stops being read within a week. */
.brief-panel::before {
  content: ''; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--line);
}
.brief-panel.is-clear::before { background: var(--border-default); }

.brief-head { display: flex; align-items: baseline; justify-content: space-between;
              gap: 12px; margin-bottom: 8px; }
.brief-eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent-secondary);
}
.brief-eyebrow svg { width: 13px; height: 13px; }
.brief-count { font-size: 12px; color: var(--text-muted); }

.brief-headline {
  font-family: var(--font-display); font-size: 18px; font-weight: 600;
  line-height: 1.35; color: var(--text-primary); margin: 0 0 4px;
}
.brief-body { font-size: 14px; line-height: 1.5; color: var(--text-secondary); margin: 0; }

.brief-items { display: flex; flex-direction: column; gap: 2px; margin-top: 14px; }
.brief-item {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 10px; margin: 0 -10px; border-radius: 10px;
  text-decoration: none; color: var(--text-secondary); font-size: 13px;
  transition: background .12s, color .12s;
}
.brief-item:hover { background: rgb(var(--ink-rgb) / .04); color: var(--text-primary); }
.brief-item-count {
  flex-shrink: 0; min-width: 26px; height: 26px; padding: 0 7px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px; font-size: 12px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  background: var(--accent-a12, rgb(var(--ink-rgb) / .06));
  border: 1px solid var(--accent-a30, var(--line));
  color: var(--accent-primary-light);
}
.brief-item-text { flex: 1; min-width: 0; }
.brief-item-arrow { flex-shrink: 0; color: var(--text-muted); line-height: 0; }
.brief-item-arrow svg { width: 14px; height: 14px; }
.brief-item:hover .brief-item-arrow { color: var(--accent-secondary); }

/* ── Agent suggestions ───────────────────────────────────────────────────── */
.sugg-panel {
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-radius: 14px; padding: 18px 20px; margin-bottom: 22px;
}
.sugg-head { display: flex; align-items: baseline; justify-content: space-between;
             gap: 12px; margin-bottom: 6px; flex-wrap: wrap; }
.sugg-title { font-family: var(--font-display); font-size: 15px; font-weight: 600;
              color: var(--text-primary); }
.sugg-settings { font-size: 12px; color: var(--text-muted); text-decoration: none; }
.sugg-settings:hover { color: var(--accent-secondary); }

.sugg-list { list-style: none; margin: 0; padding: 0; }
.sugg-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 0; border-top: 1px solid var(--border-subtle);
  transition: opacity .2s, transform .2s;
}
.sugg-row.is-resolved { opacity: 0; transform: translateX(8px); }
.sugg-icon { flex-shrink: 0; color: var(--accent-secondary); line-height: 0; }
.sugg-icon svg { width: 15px; height: 15px; }
.sugg-body { flex: 1 1 220px; min-width: 0; }
.sugg-what { display: block; font-size: 14px; color: var(--text-primary); }
.sugg-what strong { font-weight: 600; }
/* The reason travels with the suggestion. Accepting one costs somebody else
   their evening, so "why" is not optional decoration. */
.sugg-why { display: block; font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.sugg-actions { flex-shrink: 0; display: flex; gap: 8px; }
.sugg-actions .btn { width: auto; white-space: nowrap; }

@media (max-width: 720px) {
  .sugg-actions { width: 100%; }
  .sugg-actions .btn { flex: 1; }
  .brief-headline { font-size: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .sugg-row, .brief-item { transition: none; }
}

/* ── Agent autonomy controls (Settings) ──────────────────────────────────── */
.agent-card { margin-bottom: 14px; }
.agent-levels {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 14px;
}
.agent-level {
  display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  padding: 10px 12px; cursor: pointer; text-align: left;
  background: var(--bg-base); color: var(--text-secondary);
  border: 1px solid var(--border-subtle); border-radius: var(--radius);
  font-family: var(--font-body); transition: border-color .12s, color .12s, background .12s;
}
.agent-level:hover { border-color: var(--border-default); color: var(--text-primary); }
.agent-level:focus-visible { outline: none; box-shadow: none; }
.agent-level.is-on {
  border-color: var(--line-control); color: var(--text-primary);
  background: var(--accent-a12, rgb(var(--ink-rgb) / .06));
}
.agent-level-name { font-size: 13px; font-weight: 600; }
.agent-level-hint { font-size: 11px; color: var(--text-muted); }
.agent-level.is-on .agent-level-hint { color: var(--accent-primary-light); }

@media (max-width: 560px) {
  .agent-levels { grid-template-columns: 1fr; }
  .agent-level { flex-direction: row; align-items: baseline; gap: 8px; }
}
@media (prefers-reduced-motion: reduce) { .agent-level { transition: none; } }

/* The briefing headline doubles as the link to its most urgent item. */
.brief-headline-link {
  display: flex; align-items: center; gap: 8px;
  text-decoration: none; color: var(--text-primary);
}
.brief-headline-link:hover { color: var(--accent-secondary); }
.brief-headline-link .brief-item-arrow { color: currentColor; }

/* ── Narrow phones (320px: iPhone SE, older Android) ─────────────────────────
   Everything below is one failure mode with several faces: a flex item will
   not shrink below its own content unless told it may, so a horizontal strip
   of tabs, a wide button label or an unbreakable code string pushes the whole
   page sideways. Measured at 320px before these rules: 13-61px of horizontal
   scroll on explore, marketplace, calendar, settings, release and both admin
   pages. */

/* Tab strips scroll sideways rather than widening the page — the same
   behaviour `.sec-tabs` already has, so a second interaction is not invented. */
.tab-row,
.explore-tabs {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  flex-wrap: nowrap;
}
.tab-row::-webkit-scrollbar,
.explore-tabs::-webkit-scrollbar { display: none; }
.tab-row > *,
.explore-tabs > * { flex-shrink: 0; }

/* A canvas has an intrinsic width and ignores its container without this. */
canvas { max-width: 100%; }

@media (max-width: 400px) {
  /* An inline code sample (the Spotify artist-ID example) is one long
     unbreakable token. */
  .int-help-code,
  .int-help code,
  code { overflow-wrap: anywhere; word-break: break-word; }

  /* Buttons keep their label but stop forcing the row wider than the screen. */
  .btn { white-space: normal; }
  .u-row-between-wrap,
  .u-row-16,
  .admin-row-actions,
  .instr-actions { flex-wrap: wrap; }
  .u-row-between-wrap > *,
  .admin-row-actions > * { min-width: 0; }

  /* Card and layout wrappers give back their padding rather than their width. */
  .tab-row { padding-left: 14px; padding-right: 14px; }
}

/* ── Dashboard: the "what needs you" band ────────────────────────────────────
   Briefing, agent suggestions, notifications, the rating prompt and
   recommendations are all the same idea — things waiting on you — so they
   share one grid instead of four full-width cards stacked down the page.
   Stacked they measured 1076px on a 1200px layout, which spent the entire
   first screen before any of the producer's own work appeared.

   `align-items: start` so a short card does not stretch to match a tall one,
   and each child keeps its own bottom margin at 0 since the grid gap owns the
   spacing now. */
.dash-attention {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr));
  gap: 18px;
  /* stretch, not start: with `start` a shorter card leaves a visible hole
     beside its taller neighbour, which reads as a layout fault rather than as
     breathing room. Equal-height cards in a row look deliberate. */
  align-items: stretch;
}
.dash-attention > * { margin-bottom: 0 !important; }
.dash-attention:empty { display: none; margin-bottom: 0; }

/* ── Mobile: give back padding, not information ──────────────────────────────
   Every card on the dashboard carried desktop padding on a 390px screen, which
   spent about a fifth of the width and a lot of height on empty space. The
   content is unchanged; the frame around it is tighter. */
@media (max-width: 560px) {
  .brief-panel, .sugg-panel, .notif-panel, .reco-panel, .review-prompt {
    padding: 16px;
  }
  .dash-attention { gap: 14px; }
  .brief-headline { font-size: 16px; line-height: 1.3; }
  .brief-items { margin-top: 10px; }
  .brief-item { padding: 8px 8px; margin: 0 -8px; }
  .sugg-row { padding: 10px 0; }
  .notif-row { padding: 8px 0; }
  .dash-stat { padding: 14px; }
  .dash-section-highlight, .dash-main-panel { padding: 16px; }
}

/* A dead rule: .dash-stats is a grid (see below), so flex-direction does
   nothing. The 768px rule that switches it to two columns is the live one. */

/* ═══════════════════════════════════════════════════════════════════════════
   GROWTH — share links, challenges, "Made on Voxen"
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Copy-a-link ───────────────────────────────────────────────────────────
   One control everywhere something is shareable. `.btn` is included in the
   markup alongside `.btn-ghost` so it inherits the base inline-flex — a
   modifier alone computes to display:block and stacks the icon above its
   label. */
.share-link       { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.share-link-wide  { display: flex; width: 100%; }
.share-link-url {
  flex: 1 1 200px;
  /* min-width:0 so the field can shrink below its content inside the flex row.
     Without it a long absolute URL forces the row wider than its container and
     the whole panel scrolls sideways. */
  min-width: 0;
  padding: 8px 10px;
  font-size: 12px;
  font-family: var(--font-mono, monospace);
  color: var(--text-secondary);
  background: var(--bg-base);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
}
.share-link-btn   { flex: 0 0 auto; }
.share-link-btn.is-copied { color: var(--success-light); border-color: var(--success-a15); }
.share-link-hint  { flex-basis: 100%; margin: 4px 0 0; font-size: 12px; color: var(--text-muted); }

/* ── Invite panel (dashboard) ─────────────────────────────────────────────── */
.invite-panel {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: 14px;
  padding: 18px 20px;
  margin-bottom: 22px;
}
.invite-title { font-family: var(--font-display); font-size: 15px; font-weight: 600;
                color: var(--text-primary); margin: 0; }
.invite-sub   { font-size: 12px; color: var(--text-muted); margin: 2px 0 0; }
.invite-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
                gap: 8px; margin: 14px 0 12px; }
.invite-stat  { text-align: center; padding: 10px 4px; background: var(--bg-base);
                border-radius: var(--radius-sm); }
.invite-stat-value { display: block; font-family: var(--font-display); font-size: 20px;
                     font-weight: 700; color: var(--text-primary); line-height: 1.1; }
.invite-stat-label { display: block; font-size: 11px; color: var(--text-muted); margin-top: 2px; }

/* ── First-run checklist ──────────────────────────────────────────────────────
   Same card as .invite-panel and .brief-panel: this is a step in the same
   flow, not a separate product. Full width above the attention grid, because
   on a new account every panel in that grid is legitimately empty. */
.fr-panel {
  background: var(--bg-surface);
  border: 1px solid var(--accent-a20);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  margin-bottom: 22px;
}
.fr-head { padding-right: 34px; }
.fr-title { font-family: var(--font-display); font-size: 15px; font-weight: 600;
            color: var(--text-primary); margin: 0; }
.fr-sub   { font-size: 12px; color: var(--text-muted); margin: 2px 0 0; }

/* The bar is decoration over the "N of M done" line above it, which is the
   statement. It carries no text of its own and is aria-hidden. */
.fr-bar {
  height: 4px; border-radius: 2px; overflow: hidden;
  background: rgb(var(--ink-rgb) / .07); margin: 12px 0 14px;
}
.fr-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--ink), var(--accent-secondary));
  transition: width 240ms ease;
}

.fr-steps { list-style: none; margin: 0; padding: 0;
            display: flex; flex-direction: column; gap: 2px; }
.fr-step  { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 12px;
            padding: 10px 0; }
.fr-step + .fr-step { border-top: 1px solid var(--border-subtle); }
.fr-step-mark {
  width: 22px; height: 22px; margin-top: 1px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-subtle); border-radius: 50%;
  background: var(--bg-elevated); color: var(--text-muted);
}
.fr-step-mark svg { width: 12px; height: 12px; }
.fr-step.is-done .fr-step-mark {
  border-color: var(--success); background: var(--surface-2);
  color: var(--success-light);
}
.fr-step-title { margin: 0; font-size: 14px; font-weight: 600;
                 color: var(--text-primary); }
/* A completed step keeps its title and loses everything else — the row is
   evidence that it is done, not a thing to read again. */
.fr-step.is-done .fr-step-title { color: var(--text-muted); font-weight: 500; }
.fr-step-why { margin: 4px 0 10px; font-size: 13px; line-height: 1.55;
               color: var(--text-secondary); max-width: 62ch; }
.fr-step-cta { width: auto; }
/* The one step to do now: its mark carries the accent so the eye lands on it
   before reading. Later steps stay plain titles — the path is visible without
   every row asking for attention. */
.fr-step.is-next .fr-step-mark { border-color: var(--line-control); color: var(--ink); }
/* Waiting on somebody else: a statement, not a prompt, so no button and no
   bottom margin reserved for one. */
.fr-step-waiting { margin-bottom: 0; color: var(--text-muted); }

@media (max-width: 640px) {
  .fr-panel { padding: 16px; }
  .fr-step-cta { width: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .fr-bar-fill { transition: none; }
}

/* ── Challenge panel (beat page) ──────────────────────────────────────────── */
.comp-panel {
  background: var(--bg-surface);
  border: 1px solid var(--accent-a20);
  border-radius: 14px;
  padding: 18px 20px;
  margin-bottom: 22px;
}
.comp-panel-closed { border-color: var(--border-subtle); }
.comp-head { display: flex; align-items: flex-start; justify-content: space-between;
             gap: 16px; flex-wrap: wrap; }
.comp-head-main { flex: 1 1 260px; min-width: 0; }
.comp-badges { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
               margin-bottom: 6px; }
.comp-prize { display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
              font-weight: 600; color: var(--warning-xlight); }
.comp-title { font-family: var(--font-display); font-size: 19px; font-weight: 700;
              color: var(--text-primary); margin: 0; line-height: 1.25; }
.comp-deadline { display: flex; align-items: center; gap: 6px; margin: 4px 0 0;
                 font-size: 12px; color: var(--text-secondary); }
.comp-head-counts { display: flex; gap: 18px; flex: 0 0 auto; }
.comp-count { text-align: right; }
.comp-count-value { display: block; font-family: var(--font-display); font-size: 20px;
                    font-weight: 700; color: var(--text-primary); line-height: 1.1; }
.comp-count-label { display: block; font-size: 11px; color: var(--text-muted); }

.comp-board-head { display: flex; align-items: baseline; justify-content: space-between;
                   gap: 10px; flex-wrap: wrap; margin: 16px 0 6px; }
.comp-board-title { font-size: 13px; font-weight: 600; color: var(--text-primary);
                    margin: 0; text-transform: uppercase; letter-spacing: .04em; }
.comp-board-rule  { font-size: 11px; color: var(--text-muted); }

.comp-board { list-style: none; margin: 0; padding: 0; }
.comp-entry {
  display: grid;
  /* Named proportions rather than `auto` everywhere: the rank badge and the
     vote button are fixed, the artist takes the slack, and minmax(0,·) stops
     a long display name resolving the track to its min-content width and
     pushing the row past the card. */
  grid-template-columns: 32px minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--border-subtle);
}
.comp-entry-won { background: var(--accent-a08); border-radius: var(--radius-sm);
                  padding-left: 8px; padding-right: 8px; }
.comp-entry-rank { display: flex; align-items: center; justify-content: center;
                   width: 28px; height: 28px; border-radius: 50%;
                   background: var(--bg-elevated); color: var(--text-secondary);
                   font-family: var(--font-display); font-size: 13px; font-weight: 700; }
.comp-entry-won .comp-entry-rank { background: var(--ink); color: var(--ink); }
.comp-entry-who  { min-width: 0; }
.comp-entry-name { display: block; font-size: 14px; font-weight: 600;
                   color: var(--text-primary); text-decoration: none;
                   overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.comp-entry-name:hover { color: var(--accent-primary-light); }
.comp-entry-cred { font-size: 12px; }
.comp-entry-pending { font-size: 12px; color: var(--text-muted); }
.comp-entry-votes { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.comp-vote.is-voted { color: var(--ink); border-color: var(--pink-a30); }
.comp-entry-listens { font-size: 11px; color: var(--text-muted); }

.comp-empty { text-align: center; padding: 22px 12px 6px; }
.comp-empty-title { font-size: 14px; font-weight: 600; color: var(--text-primary); margin: 0; }
.comp-empty-sub   { font-size: 12px; color: var(--text-muted); margin: 4px 0 0; }
.comp-winner-note { margin: 14px 0 0; padding: 10px 12px; font-size: 13px;
                    color: var(--text-secondary); background: var(--bg-base);
                    border-radius: var(--radius-sm); }
.comp-judging-nudge { margin: 14px 0 0; padding: 10px 12px; font-size: 13px;
                      color: var(--warning-xlight); background: var(--warning-a15);
                      border-radius: var(--radius-sm); }

/* ── Challenge board page ─────────────────────────────────────────────────── */
/* `.btn-gradient` carries `width: 100%` by design, which made this CTA span the
   full 1024px content width. Overridden here rather than on the base class —
   full-width is correct where the modifier is used inside forms. */
.comp-open-cta { flex: 0 0 auto; width: auto; }
.comp-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
  gap: 10px;
  margin-bottom: 20px;
}
.comp-summary-stat { padding: 12px 14px; background: var(--bg-surface);
                     border: 1px solid var(--border-subtle); border-radius: var(--radius-md); }
.comp-summary-value { display: block; font-family: var(--font-display); font-size: 22px;
                      font-weight: 700; color: var(--text-primary); line-height: 1.1; }
.comp-summary-label { display: block; font-size: 12px; color: var(--text-muted); margin-top: 2px; }

.comp-section-title { font-family: var(--font-display); font-size: 15px; font-weight: 600;
                      color: var(--text-primary); margin: 0 0 10px; }
.comp-reco { margin-bottom: 20px; }
.comp-reco-row { display: grid;
                 grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
                 gap: 10px; }
.comp-reco-card { display: flex; flex-direction: column; gap: 2px; padding: 12px 14px;
                  background: var(--bg-surface); border: 1px solid var(--accent-a20);
                  border-radius: var(--radius-md); text-decoration: none; color: inherit; }
.comp-reco-card:hover { border-color: var(--accent-a40); }
.comp-reco-reason { font-size: 11px; font-weight: 600; color: var(--accent-primary-xlight);
                    text-transform: uppercase; letter-spacing: .04em; }
.comp-reco-title  { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.comp-reco-meta   { font-size: 12px; color: var(--text-muted); }

.comp-filter-bar { display: flex; gap: 6px; margin-bottom: 16px; overflow-x: auto; }
.comp-filter { flex: 0 0 auto; padding: 6px 14px; font-size: 13px; font-weight: 500;
               color: var(--text-secondary); background: var(--bg-surface);
               border: 1px solid var(--border-subtle); border-radius: 999px;
               text-decoration: none; }
.comp-filter.active { color: var(--text-primary); border-color: var(--accent-a40);
                      background: var(--accent-a12); }

.comp-grid { display: grid;
             grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
             gap: 14px; }
.comp-card { display: flex; gap: 12px; padding: 12px; background: var(--bg-surface);
             border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
             text-decoration: none; color: inherit; transition: border-color .15s; }
.comp-card:hover { border-color: var(--accent-a30); }
.comp-card-cover { flex: 0 0 auto; }
.comp-card-body  { min-width: 0; flex: 1; }
.comp-card-badges { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 5px; }
.comp-card-title { font-size: 14px; font-weight: 600; color: var(--text-primary);
                   margin: 0; line-height: 1.3; }
.comp-card-by    { font-size: 12px; color: var(--text-muted); margin: 2px 0 6px; }
.comp-card-meta  { display: flex; gap: 10px; flex-wrap: wrap; font-size: 12px;
                   color: var(--text-secondary); }
.comp-card-stat strong { color: var(--text-primary); }
.comp-card-prize, .comp-card-deadline { display: inline-flex; align-items: center; gap: 4px; }
.comp-card-prize { color: var(--warning-xlight); }
.comp-share-foot { margin-top: 24px; }

/* ── The two growth panels, side by side ──────────────────────────────────────
   Challenges gets the wider track: it holds up to three columns of rows, while
   the invite panel is three numbers and a field. minmax(0, ·) on both so a long
   challenge title cannot resolve its track to min-content and push the row
   past the layout. Collapses to one column below 900px, where two 460px
   columns would each be too narrow to read. */
/* auto-fit rather than a fixed 1.4fr/1fr pair, which is the same pattern
   .dash-attention already uses. With both panels present this is two columns;
   with only one — no challenges yet, or the invite panel dismissed — the fixed
   pair left the single panel in the 1.4fr track with a dead 40% hole beside it,
   which reads as a broken layout rather than as spacing. */
.growth-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
  gap: 18px;
  align-items: stretch;
}
.growth-row > * { margin-bottom: 0; }
.growth-row:empty { display: none; margin-bottom: 0; }
@media (max-width: 900px) {
  .growth-row { gap: 14px; }
}

/* ── Challenge strip (dashboard) ──────────────────────────────────────────── */
.compstrip { background: var(--bg-surface); border: 1px solid var(--border-subtle);
             border-radius: 14px; padding: 16px 20px; margin-bottom: 22px; }
.compstrip-head { display: flex; align-items: baseline; justify-content: space-between;
                  gap: 10px; margin-bottom: 10px; }
.compstrip-title { display: flex; align-items: center; gap: 6px;
                   font-family: var(--font-display); font-size: 15px; font-weight: 600;
                   color: var(--text-primary); margin: 0; }
.compstrip-all { font-size: 12px; color: var(--accent-primary-light); text-decoration: none; }
.compstrip-body { display: grid;
                  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
                  gap: 16px; }
.compstrip-col { min-width: 0; }
.compstrip-sub { font-size: 11px; font-weight: 600; color: var(--text-muted);
                 text-transform: uppercase; letter-spacing: .04em; margin: 0 0 4px; }
.compstrip-row { display: flex; align-items: center; justify-content: space-between;
                 gap: 10px; padding: 8px 0; border-top: 1px solid var(--border-subtle);
                 text-decoration: none; color: inherit; }
.compstrip-row:hover { opacity: .82; }
.compstrip-row-main  { min-width: 0; }
.compstrip-row-title { display: block; font-size: 13px; font-weight: 600;
                       color: var(--text-primary); overflow: hidden;
                       text-overflow: ellipsis; white-space: nowrap; }
.compstrip-row-meta  { display: block; font-size: 12px; color: var(--text-muted); }
.compstrip-prize { flex: 0 0 auto; font-size: 12px; color: var(--warning-xlight); }

/* ── "Made on Voxen" ──────────────────────────────────────────────────────── */
.made-on-voxen { display: inline-flex; align-items: center; gap: 6px; margin: 24px auto 0;
                 padding: 6px 12px; font-size: 12px; color: var(--text-muted);
                 background: var(--bg-surface); border: 1px solid var(--border-subtle);
                 border-radius: 999px; text-decoration: none; }
.made-on-voxen:hover { color: var(--text-secondary); border-color: var(--border-default); }
.made-on-voxen strong { color: var(--text-secondary); font-weight: 600; }
.mov-mark { width: 13px; height: 13px; flex: 0 0 auto; }
.smart-link-wrap .made-on-voxen { display: flex; width: fit-content; }

/* ── Narrow screens ───────────────────────────────────────────────────────────
   The entry row's five-column grid does not survive 560px: the artist name and
   the vote button end up sharing about 90px each. Below that it becomes two
   rows — identity on top, controls underneath — which keeps every control at a
   full tap target instead of shrinking them all. */
@media (max-width: 560px) {
  .comp-panel, .compstrip, .invite-panel { padding: 16px; }
  .comp-entry {
    grid-template-columns: 32px minmax(0, 1fr) auto;
    grid-template-areas: "rank who votes" ".  audio pick";
    row-gap: 8px;
  }
  .comp-entry-rank  { grid-area: rank; }
  .comp-entry-who   { grid-area: who; }
  .comp-entry-votes { grid-area: votes; }
  .comp-entry-audio { grid-area: audio; }
  .comp-pick        { grid-area: pick; }
  .comp-head-counts { gap: 14px; }
  .comp-count-value, .comp-summary-value, .invite-stat-value { font-size: 18px; }
  .comp-title { font-size: 17px; }
}

/* ── Arriving at an in-page anchor ───────────────────────────────────────────
   A briefing item that points at a section of this page needs the arrival to
   be visible; a scroll alone is indistinguishable from a link that did
   nothing. Outline rather than a background change so it reads on both the
   surface and highlight card variants, and it fades on its own. */
@keyframes vx-anchor-flash {
  0%   { box-shadow: 0 0 0 2px rgb(var(--ink-rgb) / .35), 0 0 22px var(--accent-glow); }
  70%  { box-shadow: 0 0 0 2px rgb(var(--ink-rgb) / .35), 0 0 22px var(--accent-glow); }
  100% { box-shadow: none; }
}
.vx-anchor-flash { animation: vx-anchor-flash 1.6s ease-out 1; border-radius: 14px; }
@media (prefers-reduced-motion: reduce) {
  .vx-anchor-flash { animation: none; box-shadow: 0 0 0 2px rgb(var(--ink-rgb) / .35); }
}

/* Dismiss control on the invite panel. Positioned rather than in the flow so
   it does not shift the heading, and sized to a real tap target on a phone
   even though it renders as a small glyph. */
.invite-panel, .fr-panel { position: relative; }
.invite-close {
  position: absolute; top: 10px; right: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  background: none; border: none; border-radius: 8px; cursor: pointer;
  color: var(--text-muted);
}
.invite-close:hover { color: var(--text-primary); background: var(--bg-elevated); }
.invite-close:disabled { opacity: .5; cursor: default; }
/* Keep the heading clear of the button. */
.invite-head { padding-right: 34px; }

/* A button that reads as a link — used where an action sits inside a sentence. */
.link-button {
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; color: var(--accent-primary-light); text-decoration: underline;
}
.link-button:hover { color: var(--accent-primary-xlight); }
.link-button:disabled { opacity: .5; cursor: default; }

/* Legal links in the site footer. Muted by default — they are a legal
   requirement rather than a destination — and readable on hover. */
.footer-legal { margin-top: 6px; font-size: 12px; }
.footer-legal a { color: var(--text-muted); text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  .footer-legal a:hover { color: var(--text-secondary); text-decoration: underline; }
}
.footer-legal span { color: var(--text-muted); margin: 0 6px; opacity: .6; }

/* ── Legal pages (Terms, Privacy) ────────────────────────────────────────────
   Shared by both, and previously duplicated as an inline <style> in each. One
   long column of prose: a measured line length, generous leading, and headings
   that are scannable without shouting. */
.legal-page { max-width: 760px; margin: 0 auto; padding: 44px 24px 80px; }
.legal-back { font-size: 13px; color: var(--text-muted); text-decoration: none;
              display: inline-flex; align-items: center; gap: 6px; margin-bottom: 22px; }
.legal-back:hover { color: var(--text-primary); }
.legal-header h1 { font-family: var(--font-display); font-size: 32px; font-weight: 700;
                   letter-spacing: -.02em; margin: 0 0 8px; }
.legal-date { font-size: 13px; color: var(--text-muted); margin: 0 0 12px; }
.legal-intro { font-size: 15px; line-height: 1.7; color: var(--text-secondary);
               margin: 0 0 28px; padding-bottom: 24px;
               border-bottom: 1px solid var(--border-subtle); }
.legal-body section { margin-bottom: 30px; scroll-margin-top: 90px; }
.legal-body h2 { font-family: var(--font-display); font-size: 17px; font-weight: 600;
                 margin: 0 0 10px; color: var(--text-primary); }
.legal-body h3 { font-size: 14px; font-weight: 600; margin: 16px 0 6px;
                 color: var(--text-primary); }
.legal-body p  { font-size: 14px; line-height: 1.75; color: var(--text-secondary);
                 margin: 0 0 10px; }
.legal-body ul { padding-left: 20px; margin: 0 0 10px; }
.legal-body li { font-size: 14px; line-height: 1.75; color: var(--text-secondary);
                 margin-bottom: 5px; }
.legal-body a  { color: var(--accent-primary-light); }
.legal-body strong { color: var(--text-primary); font-weight: 600; }

/* A callout for the handful of points people most need to actually read —
   what we never do with their music, and where a right has a limit. */
.legal-note {
  margin: 14px 0; padding: 12px 14px;
  background: var(--bg-surface); border: 1px solid var(--border-subtle);
  border-left: 3px solid var(--line); border-radius: var(--radius-sm);
  font-size: 13px; line-height: 1.7; color: var(--text-secondary);
}
.legal-note strong { color: var(--text-primary); }

/* Contents list at the top of each policy. */
.legal-toc { margin: 0 0 34px; padding: 16px 18px; background: var(--bg-surface);
             border: 1px solid var(--border-subtle); border-radius: var(--radius-md); }
.legal-toc-title { font-size: 11px; font-weight: 700; letter-spacing: .1em;
                   text-transform: uppercase; color: var(--text-muted); margin: 0 0 10px; }
.legal-toc ol { margin: 0; padding-left: 20px; columns: 2; column-gap: 28px; }
.legal-toc li { font-size: 13px; line-height: 1.9; margin: 0; }
.legal-toc a { color: var(--text-secondary); text-decoration: none; }
.legal-toc a:hover { color: var(--accent-primary-light); }
@media (max-width: 560px) {
  .legal-toc ol { columns: 1; }
  .legal-page { padding: 32px 18px 60px; }
  .legal-header h1 { font-size: 26px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   VERSION PAGE
   One version, and everything that happened to it.

   Every value below is a token. The page reads as part of the product because
   it reuses .page-wrap, .badge, .btn, .status, the audio player and the
   cover placeholder — the only genuinely new shapes here are the timeline
   and the conversation thread, and both are structure rather than decoration:
   the timeline's dot states encode done / in progress / not started, which is
   information the reader needs and not a flourish.
   ═══════════════════════════════════════════════════════════════════════════ */

.vx-version { padding-bottom: 80px; }

/* ── Header ───────────────────────────────────────────────────────────────── */
.vx-ver-head {
  display: flex;
  gap: 24px;
  align-items: flex-start;
  margin: 8px 0 28px;
}
.vx-ver-cover { flex: 0 0 148px; width: 148px; }
.vx-ver-main  { min-width: 0; flex: 1; }

.vx-ver-badges {
  display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px;
}
.vx-ver-badges a.badge { text-decoration: none; }

.vx-ver-title {
  font-family: var(--font-display);
  font-size: clamp(28px, 4vw, 40px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.08;
  color: var(--text-primary);
  margin: 0 0 10px;
}
.vx-ver-people {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  color: var(--text-secondary); font-size: 15px; margin: 0 0 8px;
}
.vx-ver-people a { color: var(--text-primary); font-weight: 600; text-decoration: none; }
.vx-ver-people a:hover { color: var(--accent-primary-light); }
.vx-ver-sep { color: var(--text-muted); }

.vx-ver-meta {
  display: flex; flex-wrap: wrap; gap: 14px;
  color: var(--text-muted); font-size: 13.5px; margin: 0;
}

/* ── "What happens next" — the most important block on the page ───────────── */
.vx-next {
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  padding: 22px 24px;
  margin-bottom: 28px;
}
/* The one action the viewer is here to take gets the brand wash. Only one
   .vx-next ever renders, so this cannot compete with itself. */
.vx-next--act {
  background: var(--gradient-brand-subtle);
  border-color: var(--accent-a30);
}
.vx-next--warn { border-color: var(--warning); background: var(--warning-a15); }

.vx-next-title {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display);
  font-size: 18px; font-weight: 700; color: var(--text-primary);
  margin: 0 0 8px;
}
.vx-next-title svg { flex: none; }
.vx-next-sub { color: var(--text-secondary); font-size: 14.5px; margin: 0 0 16px; max-width: 62ch; }

.vx-decide { display: flex; flex-direction: column; gap: 14px; }
.vx-decide-note {
  display: flex; flex-direction: column; gap: 6px;
  font-size: 13px; color: var(--text-secondary);
}
.vx-decide-note textarea {
  width: 100%; resize: vertical;
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-body); font-size: 14px;
  padding: 10px 12px;
}
.vx-decide-note textarea:focus-visible {
  outline: 2px solid var(--accent-primary); outline-offset: 1px;
}
/* A 2-column grid on narrow screens so no row mixes a 45px gradient button
   with a 40px ghost one — the height mismatch already fixed on beat.html. */
.vx-decide-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.vx-decide-actions .btn { width: auto; }
.vx-decide-status { margin: 0; }

/* "How does this mix sound?" — the version page's mix verdict. */
.vx-mix-verdict {
  display: flex; flex-direction: column; gap: 10px;
  margin-top: 16px; padding-top: 16px;
  border-top: 1px solid var(--border-default);
}
.vx-mix-verdict-q { margin: 0; font-weight: 600; color: var(--text-primary); }
.vx-mix-verdict-note-label { font-size: 13px; color: var(--text-secondary); }
.vx-mix-verdict textarea {
  width: 100%; resize: vertical;
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-body); font-size: 14px;
  padding: 10px 12px;
}
.vx-mix-verdict textarea:focus-visible {
  outline: 2px solid var(--accent-primary); outline-offset: 1px;
}

.vx-note {
  margin: 0 0 14px;
  padding: 10px 14px;
  border-left: 3px solid var(--line);
  background: var(--bg-base);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--text-primary);
  font-size: 14.5px;
  font-style: normal;
}

/* Indeterminate, because the mixer reports no percentage and inventing one
   would be a fabricated number on a page whose whole premise is measured fact. */
.vx-progress {
  height: 4px; border-radius: 2px; overflow: hidden;
  background: var(--bg-overlay);
}
.vx-progress span {
  display: block; height: 100%; width: 38%;
  background: var(--ink);
  animation: vx-progress-slide 1.6s ease-in-out infinite;
}
.vx-mix-elapsed { margin: 10px 0 0; font-size: 13px; color: var(--text-secondary); }
.vx-mix-stages-title {
  margin: 14px 0 6px; font-size: 12px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-secondary);
}
.vx-mix-stages {
  margin: 0; padding-left: 20px; display: grid; gap: 4px;
  font-size: 14px; line-height: 1.45; color: var(--text-primary);
}
@keyframes vx-progress-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(320%); }
}
@media (prefers-reduced-motion: reduce) {
  .vx-progress span { animation: none; width: 100%; opacity: .5; }
}

/* ── Two columns ──────────────────────────────────────────────────────────── */
.vx-ver-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}
.vx-ver-col, .vx-ver-side { display: flex; flex-direction: column; gap: 20px; min-width: 0; }

.vx-panel {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 20px 22px;
}
.vx-panel-title {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-display);
  font-size: 13px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-secondary);
  margin: 0 0 16px;
}
.vx-count {
  font-size: 11px; padding: 1px 7px; border-radius: 999px;
  background: var(--bg-overlay); color: var(--text-secondary); letter-spacing: 0;
}

.vx-audio-row { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.vx-audio-row:last-child { margin-bottom: 0; }
.vx-audio-label {
  display: flex; align-items: center; gap: 7px;
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-muted);
}

.vx-empty-inline { color: var(--text-muted); font-size: 14px; margin: 0; }

/* ── Conversation thread ──────────────────────────────────────────────────── */
.vx-thread { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.vx-thread-row { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; }
.vx-thread-icon {
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--bg-overlay); color: var(--text-secondary);
}
.vx-thread--accept .vx-thread-icon { background: var(--success-a15); color: var(--success-light); }
.vx-thread--reject .vx-thread-icon { background: var(--danger-a15);  color: var(--danger-light); }
.vx-thread--request_revision .vx-thread-icon { background: var(--warning-a15); color: var(--warning-light); }
.vx-thread-body { min-width: 0; }
.vx-thread-what { margin: 0 0 6px; font-size: 14px; color: var(--text-primary); font-weight: 600; }
.vx-thread-when { color: var(--text-muted); font-weight: 400; font-size: 12.5px; margin-left: 8px; }
.vx-thread-body .vx-note { margin: 0; }

.vx-comment { display: flex; gap: 10px; align-items: flex-start; }
.vx-comment textarea {
  flex: 1; min-width: 0; resize: vertical;
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-body); font-size: 14px;
  padding: 10px 12px;
}
.vx-comment .btn { width: auto; flex: none; }

.vx-revisions { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.vx-revisions li { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.vx-revisions a { color: var(--text-primary); text-decoration: none; font-weight: 600; font-size: 14px; }
.vx-revisions a:hover { color: var(--accent-primary-light); }

/* ── Timeline ─────────────────────────────────────────────────────────────── */
.vx-timeline { list-style: none; margin: 0; padding: 0; }
.vx-tl {
  position: relative;
  display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 12px;
  padding-bottom: 18px;
}
.vx-tl:last-child { padding-bottom: 0; }
/* The connecting rail. Drawn on the item rather than the list so the last
   one can drop it without a :last-child override fighting a border. */
.vx-tl::before {
  content: ""; position: absolute;
  left: 10px; top: 18px; bottom: 0; width: 1px;
  background: var(--border-default);
}
.vx-tl:last-child::before { display: none; }

.vx-tl-dot {
  width: 11px; height: 11px; margin: 4px 0 0 5px;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  background: var(--bg-surface);
  position: relative; z-index: 1;
}
.vx-tl--done .vx-tl-dot    { background: var(--success); border-color: var(--success); }
.vx-tl--current .vx-tl-dot { background: var(--ink); border-color: var(--line-control); }

.vx-tl-body { min-width: 0; }
.vx-tl-label { margin: 0; font-size: 14px; font-weight: 600; color: var(--text-muted); }
.vx-tl--done .vx-tl-label    { color: var(--text-primary); }
.vx-tl--current .vx-tl-label { color: var(--accent-primary-light); }
.vx-tl-detail { margin: 3px 0 0; font-size: 13px; color: var(--text-secondary); line-height: 1.5; }
.vx-tl-when   { margin: 3px 0 0; font-size: 12px; color: var(--text-muted); }

.vx-split-line { margin: 0 0 8px; font-size: 15px; color: var(--text-primary); font-weight: 600; }

@media (max-width: 900px) {
  .vx-ver-grid { grid-template-columns: minmax(0, 1fr); }
  .vx-ver-head { gap: 16px; }
  .vx-ver-cover { flex-basis: 96px; width: 96px; }
}
@media (max-width: 560px) {
  .vx-ver-head { flex-direction: column; }
  .vx-ver-cover { width: 120px; flex-basis: auto; }
  /* Equal cells, so no row pairs a 45px gradient button with a 40px ghost. */
  .vx-decide-actions { display: grid; grid-template-columns: 1fr 1fr; }
  .vx-decide-actions .btn { width: 100%; }
  .vx-comment { flex-direction: column; }
  .vx-comment .btn { width: 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   TAKE CHECK — the artist's pre-flight on their own recording

   Deliberately quiet. This is advice, not a verdict: the submit button is
   never disabled by a result, so the panel must not look like a blocker. A
   failing row is amber rather than red for the same reason — the take is
   still sendable and red would say otherwise.
   ═══════════════════════════════════════════════════════════════════════════ */

.take-check { display: flex; flex-direction: column; gap: 10px; }

.take-check-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.take-check-row {
  display: flex; flex-direction: column; gap: 3px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  background: var(--bg-base);
  border-left: 3px solid var(--border-strong);
  font-size: 13px;
  color: var(--text-secondary);
}
.take-check-row.is-ok  { border-left-color: var(--success); }
.take-check-row.is-bad { border-left-color: var(--warning); }
.take-check-what { color: var(--text-primary); }
.take-check-fix  { color: var(--text-secondary); }

/* ── Beat artwork upload ──────────────────────────────────────────────────
   Sits under the cover on the beat page, producer only. Quiet by design:
   the placeholder beneath it is a real design, so this is an offer rather
   than a prompt to fix something.
   ────────────────────────────────────────────────────────────────────────── */
.cover-art {
  display: block; width: 100%; height: auto;
  aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
}
.cover-art.cover-lg { max-height: 180px; }
.cover-art.cover-md { max-height: 132px; }
.cover-art.cover-sm { max-height: 64px; }

.beat-art-upload { margin-top: 10px; }
.beat-art-btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 11px; border-radius: var(--radius-sm);
  border: 1px solid var(--border-default);
  background: var(--bg-elevated);
  color: var(--text-secondary);
  font-size: 12.5px; cursor: pointer;
}
.beat-art-btn:hover { color: var(--text-primary); border-color: var(--border-strong); }
.beat-art-btn:focus-within { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
.beat-art-status { margin: 8px 0 0; font-size: 12.5px; }

/* ═══════════════════════════════════════════════════════════════════════════
   REVIEW WORKSPACE
   Every version waiting on this producer, oldest first.

   The row is the unit of work: artist, take, note, decision. Nothing on it
   navigates away, because the whole point is that a producer never has to
   download a file or open another tool to answer somebody.
   ═══════════════════════════════════════════════════════════════════════════ */

.vx-review { padding-bottom: 80px; }

.vx-rev-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin: 0 0 24px;
}
.vx-rev-title {
  font-family: var(--font-display);
  font-size: clamp(26px, 3.6vw, 34px); font-weight: 800;
  letter-spacing: -0.03em; color: var(--text-primary); margin: 0 0 6px;
}
.vx-rev-sub { color: var(--text-secondary); font-size: 15px; margin: 0; }
.vx-rev-head .btn { width: auto; }

/* Empty is the state a healthy producer is in most of the time, so it reads
   as "you're on top of it" rather than as a page that failed to load. */
.vx-rev-empty {
  text-align: center; padding: 56px 24px;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}
.vx-rev-empty-icon { color: var(--success); margin-bottom: 12px; }
.vx-rev-empty h2 {
  font-family: var(--font-display); font-size: 20px; font-weight: 700;
  color: var(--text-primary); margin: 0 0 8px;
}
.vx-rev-empty p {
  color: var(--text-secondary); font-size: 14.5px;
  max-width: 46ch; margin: 0 auto 18px;
}
.vx-rev-empty .btn { width: auto; }

.vx-rev-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 16px; }

.vx-rev-item {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  display: flex; flex-direction: column; gap: 14px;
  transition: opacity .25s ease, transform .25s ease;
}
.vx-rev-item.is-decided { opacity: .45; transform: scale(.995); }
@media (prefers-reduced-motion: reduce) {
  .vx-rev-item { transition: none; }
}

.vx-rev-top { display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap; }
.vx-rev-cover { flex: 0 0 56px; width: 56px; display: block; }
.vx-rev-who { flex: 1; min-width: 0; }
.vx-rev-artist {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 4px; font-size: 15px;
}
.vx-rev-artist a { color: var(--text-primary); font-weight: 650; text-decoration: none; }
.vx-rev-artist a:hover { color: var(--accent-primary-light); }
.vx-rev-on {
  display: flex; flex-wrap: wrap; gap: 12px;
  margin: 0; font-size: 13px; color: var(--text-muted);
}
.vx-rev-on a { color: var(--text-secondary); text-decoration: none; }
.vx-rev-on a:hover { color: var(--text-primary); }

.vx-rev-tags { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.vx-rev-open {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; color: var(--text-secondary); text-decoration: none;
}
.vx-rev-open:hover { color: var(--accent-primary-light); }

.vx-rev-note { margin: 0; font-size: 14px; }

.vx-rev-actions { display: flex; gap: 10px; align-items: flex-start; flex-wrap: wrap; }
.vx-rev-input {
  flex: 1; min-width: 220px; resize: none; overflow: hidden;
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-body); font-size: 14px;
  padding: 9px 12px; line-height: 1.5;
}
.vx-rev-input:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 1px; }
.vx-rev-buttons { display: flex; gap: 8px; flex-wrap: wrap; }
.vx-rev-buttons .btn { width: auto; }
.vx-rev-status { margin: 0; font-size: 13px; }
.vx-rev-done { margin: 0; font-size: 13.5px; color: var(--success-light); }

@media (max-width: 640px) {
  .vx-rev-actions { flex-direction: column; align-items: stretch; }
  .vx-rev-input { min-width: 0; width: 100%; }
  /* Equal cells so no row pairs a 45px gradient button with a 40px ghost. */
  .vx-rev-buttons { display: grid; grid-template-columns: 1fr 1fr 1fr; }
  .vx-rev-buttons .btn { width: 100%; }
  .vx-rev-tags { width: 100%; }
}

/* The awaiting-review stat is a link for the producer and a number for
   everyone else, so it needs to look interactive only in the first case. */
.beat-stat--link { text-decoration: none; color: inherit; display: block; }
.beat-stat--link:hover .beat-stat-value { color: var(--accent-primary-light); }
.beat-stat--link:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 3px; border-radius: var(--radius-sm); }

/* A missing preset list is a wiring fault, not a user state. Muted rather
   than alarming — the vocalist is not at fault and their take still works. */
.preset-picker-missing {
  margin: 0; font-size: 13px; color: var(--text-muted);
  max-width: 52ch; line-height: 1.5;
}

/* A profile section that VANISHES when empty makes a new member and a broken
   page look identical. Shown with a line instead — and the line differs for
   the owner, because "you haven't posted a beat" is a prompt and
   "they haven't posted a beat" is a fact. */
.profile-empty {
  margin: 0; padding: 14px 0;
  color: var(--text-muted); font-size: 14px; line-height: 1.55; max-width: 56ch;
}

/* An empty admin table body reads as a broken query. The row says which. */
.admin-empty { color: var(--text-muted); font-size: 13px; padding: 18px 14px; text-align: center; }

/* Per-item icons in the briefing. The icon carries the KIND of work so the
   list can be sorted by eye before it is read; the arrow already says it is a
   link, so the icon does not have to. */
.brief-headline-icon, .brief-item-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; flex: none;
  color: var(--accent-primary-light);
}
.brief-item-icon { color: var(--text-secondary); }
.brief-headline-link { display: flex; align-items: center; gap: 10px; }

/* ── Marketplace filter selects ───────────────────────────────────────────
   The rule used to live inside marketplace.html's inline <style>, with
   hardcoded hex fallbacks rather than tokens. That is the badge-green /
   badge-amber shape: a class one page defines privately is a class every
   other page renders as the browser's default control — light chrome on a
   dark page, the fault already recorded for the Settings checkbox and for ten
   native audio players. The beat page's device picker uses it now, so it has
   one definition, here, in tokens.

   appearance:none removes the platform widget; the chevron is a background
   SVG rather than a pseudo-element, because a <select> cannot host one.
   ────────────────────────────────────────────────────────────────────────── */
.mkt-select {
  width: 100%;
  appearance: none; -webkit-appearance: none;
  background-color: var(--bg-base);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a1a1aa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 15px 15px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-body); font-size: 14px;
  padding: 9px 34px 9px 12px;
  cursor: pointer;
}
.mkt-select:hover { border-color: var(--border-strong); }
.mkt-select:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 1px; }
/* The option list is drawn by the OS, so it inherits nothing above — set the
   colours explicitly or a dark-theme page gets black text on a black list in
   some browsers. */
.mkt-select option { background: var(--bg-elevated); color: var(--text-primary); }

.filters-label label { cursor: pointer; }

/* "What got in the way?" — the beat page's abandonment question (ADR 0009). */
.why-prompt {
  margin: 0 0 20px; padding: 16px 18px;
  border: 1px solid var(--border-default); border-radius: var(--radius-md);
  background: var(--bg-elevated, var(--bg-base));
  display: flex; flex-direction: column; gap: 10px;
}
.why-title { margin: 0; font-size: 16px; font-weight: 600; color: var(--text-primary); }
.why-sub { margin: 0; font-size: 13px; color: var(--text-secondary); }
.why-options { display: flex; flex-wrap: wrap; gap: 8px; }
.why-options .btn { width: auto; }
.why-note-label { font-size: 13px; color: var(--text-secondary); }
.why-note {
  width: 100%; background: var(--bg-base); color: var(--text-primary);
  border: 1px solid var(--border-default); border-radius: var(--radius-sm);
  padding: 8px 10px; font-family: var(--font-body); font-size: 14px;
}
.why-note:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 1px; }
.why-foot { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.why-foot .btn { width: auto; }
.why-status { margin: 0; }

/* Admin journey inspector (ADR 0009). */
.journey-page { --page-measure: 1000px; padding-bottom: 48px; }
.journey-back { display: inline-flex; gap: 6px; align-items: center; color: var(--text-secondary); text-decoration: none; margin-bottom: 16px; }
.journey-search { margin: 0 0 20px; }
.journey-search-label { display: block; font-size: 13px; color: var(--text-secondary); margin-bottom: 6px; }
.journey-search-row { display: flex; gap: 8px; flex-wrap: wrap; }
.journey-search-row input {
  flex: 1 1 240px; min-width: 0; background: var(--bg-base); color: var(--text-primary);
  border: 1px solid var(--border-default); border-radius: var(--radius-sm); padding: 8px 10px;
}
.journey-search-row .btn { width: auto; }
.journey-title { font-size: 22px; margin: 0 0 4px; color: var(--text-primary); }
.journey-meta { font-size: 13px; font-weight: 400; color: var(--text-muted); }
.journey-sub { margin: 0 0 20px; color: var(--text-secondary); font-size: 14px; }
.journey-empty { color: var(--text-secondary); }
.journey-results { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.journey-visit { margin: 0 0 18px; border: 1px solid var(--border-default); border-radius: var(--radius-md); overflow: hidden; }
.journey-visit-head { margin: 0; padding: 10px 14px; font-size: 13px; font-weight: 600; color: var(--text-secondary); background: var(--bg-elevated); }
.journey-steps { list-style: none; margin: 0; padding: 0; }
.journey-step {
  display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; gap: 10px; align-items: baseline;
  padding: 8px 14px; border-top: 1px solid var(--border-subtle, var(--border-default)); font-size: 14px;
}
.journey-when { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.journey-what { color: var(--text-primary); overflow-wrap: anywhere; }
.journey-detail { display: block; color: var(--text-secondary); font-size: 12px; }
.journey-src { color: var(--text-muted); font-size: 11px; font-family: var(--font-mono, monospace); }
@media (max-width: 560px) {
  .journey-step { grid-template-columns: minmax(0, 1fr); gap: 2px; }
}
.funnel-worst td { background: var(--surface-2); }

/* Voxen Brain and experiments (admin_brain.html, admin_experiments.html) */
.brain-refresh { margin: 0 0 20px; }
.brain-h2 { font-size: 17px; margin: 24px 0 10px; color: var(--text-primary); }
.brain-h3 { font-size: 14px; margin: 16px 0 6px; color: var(--text-secondary); }
.brain-card {
  border: 1px solid var(--border-default); border-left-width: 4px; border-radius: var(--radius-md);
  padding: 12px 16px; margin: 0 0 12px; background: var(--bg-elevated);
}
.brain-alert { border-left-color: var(--warning); }
.brain-improved { border-left-color: var(--success); }
.brain-card-title { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: 15px; margin: 0 0 8px; color: var(--text-primary); }
.brain-line { margin: 4px 0; font-size: 14px; color: var(--text-primary); overflow-wrap: anywhere; }
.brain-k { display: inline-block; min-width: 110px; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); }
.brain-evidence { margin: 2px 0 6px 18px; padding: 0; font-size: 13px; color: var(--text-secondary); }
.brain-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start; margin-top: 8px; }
.brain-actions .btn { width: auto; }
.brain-affected summary { cursor: pointer; font-size: 13px; color: var(--accent-primary-light); }
.brain-affected ul { margin: 6px 0 0 18px; padding: 0; font-size: 13px; }
.exp-form { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; max-width: 560px; }
.exp-form label { font-size: 13px; color: var(--text-secondary); margin-top: 6px; }
.exp-form input, .exp-form select {
  background: var(--bg-base); color: var(--text-primary); border: 1px solid var(--border-default);
  border-radius: var(--radius-sm); padding: 8px 10px; min-width: 0;
}
.exp-form .btn { width: auto; justify-self: start; margin-top: 8px; }
.rec-preview { margin: 0 0 12px; font-size: 14px; color: var(--text-secondary); }
.beat-similar { margin-top: 28px; }
.beat-similar-list { list-style: none; padding: 0; margin: 8px 0 0; display: flex; flex-direction: column; gap: 8px; }
.beat-similar-meta { display: block; font-size: 12px; color: var(--text-muted); }
/* The admin dashboard's table styles live in its own <style>; the standalone
   admin pages (brain, experiments) use the same classes, scoped here. */
.journey-page .admin-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.journey-page .admin-table th {
  text-align: left; padding: 10px 12px; font-size: 12px; font-weight: 500; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-muted); border-bottom: 1px solid var(--border-subtle); white-space: nowrap;
}
.journey-page .admin-table td { padding: 10px 12px; border-bottom: 1px solid var(--border-subtle); color: var(--text-secondary); }
.journey-page .admin-table-wrap {
  background: var(--bg-surface); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
  overflow-x: auto; -webkit-overflow-scrolling: touch;
}
/* Before/after compare and the plain-English editor on the version page */
.vx-compare, .vx-edit { margin-top: 14px; }
.vx-compare-steps { margin: 8px 0 0 18px; padding: 0; font-size: 13px; color: var(--text-secondary); }
.vx-edit input { flex: 1 1 220px; min-width: 0; background: var(--bg-base); color: var(--text-primary);
  border: 1px solid var(--border-default); border-radius: var(--radius-sm); padding: 8px 10px; }

/* Pricing: unlock sheet, Pro upsell, authorship record, billing (docs/adr/0011) */
.unlock-sheet { margin-top: 16px; }
.unlock-sheet[hidden] { display: none; }  /* .card sets display:flex, which beats the attribute */
.unlock-title { margin: 0 0 4px; }
.unlock-sub, .pro-sub { color: var(--text-secondary); font-size: 14px; margin: 0 0 12px; }
.unlock-cols, .pricing-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
.unlock-h { font-size: 13px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-secondary); margin: 12px 0 6px; }
.unlock-list { margin: 0 0 8px 18px; padding: 0; font-size: 14px; line-height: 1.5; }
.unlock-list li { overflow-wrap: anywhere; }
.unlock-options, .pro-actions, .billing-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.unlock-status { min-height: 1.2em; }
.unlock-done { color: var(--accent-secondary); font-weight: 600; }
.pro-card { max-width: 640px; }
.pro-price { font-size: 20px; font-weight: 700; margin: 4px 0 8px; }
.pro-what { margin: 8px 0; }
.pro-inline { padding: 12px 14px; border: 1px solid var(--accent-a30); border-radius: var(--radius-sm); background: var(--accent-a08); }
.decl-fieldset { border: 1px solid var(--border-default); border-radius: var(--radius-sm); padding: 10px 12px; margin: 12px 0; min-width: 0; }
.decl-legend { font-size: 13px; color: var(--text-secondary); padding: 0 4px; }
.decl-role { display: inline-flex; align-items: center; gap: 6px; margin: 4px 12px 4px 0; font-size: 14px; }
.decl-attest { display: flex; gap: 8px; align-items: flex-start; font-size: 14px; margin-top: 8px; }
.authorship-list { margin: 0; padding-left: 18px; font-size: 14px; line-height: 1.6; }
.authorship-list li { overflow-wrap: anywhere; }
.vx-song-files { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.launch-offer { padding: 12px 14px; margin: 0 0 16px; border: 1px solid var(--accent-a30); border-radius: var(--radius-sm);
  background: var(--accent-a08); font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
.launch-offer-left { color: var(--text-secondary); white-space: nowrap; }

/* Pricing insights (admin; pricing_analytics, docs/adr/0011) */
.pi-section { margin-top: 20px; }
.pi-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; }
.pi-card { border: 1px solid var(--border-default); border-radius: var(--radius-sm); padding: 12px 14px; min-width: 0; }
.pi-card h3 { margin: 0; font-size: 14px; color: var(--text-secondary); }
.pi-big { font-size: 26px; font-weight: 700; margin: 4px 0 0; }
.pi-sub { margin: 0 0 8px; font-size: 12px; color: var(--text-secondary); }
.pi-dl { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; margin: 0; font-size: 13px; }
.pi-dl dt { color: var(--text-secondary); }
.pi-dl dd { margin: 0; text-align: right; }
.pi-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 16px 0 8px; }
.pi-check { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; }
.pi-rate { display: inline-block; padding: 1px 6px; border-radius: 4px; font-weight: 600; }
.pi-heat-0 { background: var(--accent-a08); }
.pi-heat-1 { background: var(--accent-a12); }
.pi-heat-2 { background: var(--accent-a20); }
.pi-heat-3 { background: var(--accent-a30); }
.pi-heat-4, .pi-heat-5 { background: var(--accent-a40); }
.pi-ci { display: block; font-size: 11px; color: var(--text-secondary); white-space: nowrap; }
.pi-na { color: var(--text-secondary); }
.pi-neg { color: var(--error); }
.pi-flag td { background: var(--surface-2); }
.pi-all td { font-weight: 600; }
.pi-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.pi-tab { padding: 6px 12px; border: 1px solid var(--border-default); border-radius: 999px; font-size: 13px; }
.pi-tab.is-active { background: var(--accent-a20); border-color: var(--accent-a40); }

/* ── Collaboration status and final approval (version page; collab.py) ── */
.vx-collab-stage { margin: 0; font-weight: 700; font-size: 15px; color: var(--text-primary); }
.vx-collab-stage.is-late { color: var(--warning); }
.vx-collab-stage.is-hold { color: var(--danger); }
.vx-collab-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.vx-collab-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 8px 0 0; }
.vx-collab-form input[type="text"], .vx-collab-form textarea {
  flex: 1 1 180px; min-width: 0; width: 100%;
  background: var(--bg-base); border: 1px solid var(--border-default);
  border-radius: var(--radius-md); padding: 8px 10px; color: var(--text-primary); font: inherit; font-size: 13px;
}
.vx-collab-form label:not(.u-sr-only):not(.checkbox-label) { flex-basis: 100%; font-size: 13px; color: var(--text-secondary); }
.vx-collab-details > summary { list-style: none; cursor: pointer; display: inline-flex; }
.vx-collab-details > summary::-webkit-details-marker { display: none; }
.vx-collab-details[open] > summary { margin-bottom: 4px; }
.vx-pending-sub { margin: 12px 0 6px; font-size: 13px; font-weight: 700; color: var(--text-secondary); }
.vx-pending-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.vx-pending-row {
  display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1.6fr) minmax(0, 0.8fr);
  gap: 10px; align-items: baseline; padding: 8px 10px;
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md); font-size: 13px;
}
.vx-pending-row a { font-weight: 700; color: var(--text-primary); overflow-wrap: anywhere; }
.vx-pending-stage, .vx-pending-when { color: var(--text-secondary); }
.vx-pending-row.is-late .vx-pending-when { color: var(--warning); }
@media (max-width: 640px) { .vx-pending-row { grid-template-columns: minmax(0, 1fr); gap: 2px; } }

/* ── Admin tables that do not fit (static/js/admin_tables.js) ───────────────
   No admin table scrolls sideways. The script marks every admin table
   `vx-fit` (headers may wrap) and, when the table is still wider than its box,
   `vx-stacked`: one card per row, each value under its column's name
   (data-label, copied from the header). A sortable table keeps its headers as
   a row of sort buttons above the cards. */
table.vx-fit th { white-space: normal; }
table.vx-stacked, table.vx-stacked tbody, table.vx-stacked tfoot { display: block; width: 100%; }
table.vx-stacked thead { display: none; }
table.vx-stacked.vx-sortable thead { display: block; }
table.vx-stacked.vx-sortable thead tr { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 12px; border-bottom: 1px solid var(--border-subtle); }
table.vx-stacked.vx-sortable thead th {
  display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border: 1px solid var(--border-subtle);
  border-radius: 99px; font-size: 11px; white-space: normal;
}
table.vx-stacked tr {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px 16px;
  padding: 14px 16px; border-bottom: 1px solid var(--border-subtle);
}
table.vx-stacked td, table.vx-stacked tbody th {
  display: block; min-width: 0; padding: 0; border: 0; white-space: normal; overflow-wrap: anywhere; text-align: left;
}
table.vx-stacked td[colspan] { grid-column: 1 / -1; }
table.vx-stacked td[data-label]::before {
  content: attr(data-label); display: block; margin-bottom: 2px; font-size: 11px; font-weight: 500;
  letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted);
}
/* A stacked row highlights as one card, not cell by cell. */
@media (hover: hover) and (pointer: fine) {
  table.vx-stacked tr:hover td { background: transparent; }
  table.vx-stacked tbody tr:hover { background: var(--bg-elevated); }
}
