/* ==========================================================================
   ONE DIGITAL MUSIC — Landing page
   --------------------------------------------------------------------------
   The whole marketing page, lifted out of the <style> block that used to sit
   in one-digital-music.html so the markup is readable and the styling is
   cacheable on its own.

   This page keeps its OWN identity — brass and cream on near-black, Fraunces
   for display type — which is deliberately not the app's graphite/violet
   design system. What it does share with the app is the header's structure
   and its responsive behaviour, so the bar behaves identically on both.
   See section 4.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  --ink: #0a0a0e;
  --panel: #141319;
  --panel-2: #1c1a22;
  --line: rgba(245, 241, 232, 0.10);
  --line-strong: rgba(245, 241, 232, 0.22);
  --brass: #c99a3c;
  --brass-soft: rgba(201, 154, 60, 0.15);
  --coral: #ff5a45;
  --paper: #f5f1e8;
  --muted: #a49fae;

  --font-display: 'Fraunces', Georgia, serif;
  --font-body: 'Manrope', 'Segoe UI', system-ui, sans-serif;

  /* Header geometry — the same rules the app's header.css uses, so the two
     bars break at the same widths and gutter the same way. Only the paint
     differs. */
  --header-height: 84px;
  --header-rule: 1px;
  --header-band: calc(var(--header-height) + var(--header-rule));
  --header-gutter: clamp(16px, 3vw, 40px);
  --header-max: 1600px;

  --wrap-max: 1240px;
  --ease: cubic-bezier(0.2, 0.8, 0.3, 1);

  /* Uppercase nav tracking. Deliberately the same value as --nav-tracking in
     the app's public/css/header.css: the two headers are the one component
     a visitor sees on both sides of the login, so they are set identically.
     Change it here and change it there. */
  --nav-tracking: 0.09em;

  color-scheme: dark;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

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

html { scroll-behavior: smooth; scroll-padding-top: var(--header-band); }

body {
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, .serif {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.01em;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

/* The hidden attribute only hides via a UA `display: none`, which ANY author
   display declaration outranks — and several elements here are given
   display:grid/flex. Without this guard the icon fallbacks render on top of
   the icons they were meant to replace. */
[hidden] { display: none !important; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
ul { list-style: none; }

.wrap { max-width: var(--wrap-max); margin: 0 auto; padding: 0 32px; }
::selection { background: var(--brass); color: #0a0a0e; }
:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; border-radius: 4px; }

.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;
}

/* Film grain over everything, so flat panels do not read as flat colour. */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: 9999; pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   3. Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--brass); color: #191305;
  font-weight: 800; font-size: 14.5px;
  padding: 13px 24px; border-radius: 100px;
  border: 1px solid var(--brass);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), background .18s var(--ease);
  white-space: nowrap;
}

.btn:hover { transform: translateY(-2px); box-shadow: 0 10px 24px -8px rgba(201, 154, 60, 0.55); }
.btn-lg { padding: 16px 30px; font-size: 15.5px; }
.btn-outline { background: transparent; color: var(--paper); border: 1px solid var(--line-strong); }
.btn-outline:hover { border-color: var(--brass); background: var(--brass-soft); box-shadow: none; }

/* --------------------------------------------------------------------------
   4. Logo lockup
   --------------------------------------------------------------------------
   Built from live text rather than an image file so it stays crisp at any
   size, inherits colour from its container (white on the header, white on the
   record label), and can be restyled without re-exporting anything.

   Two forms: the default horizontal lockup for the bar and the footer, and
   .odm-logo--stack for the centre of the record, where a wide wordmark would
   not fit inside a circle.
   -------------------------------------------------------------------------- */

.odm-logo {
  display: inline-flex; align-items: center; gap: 12px;
  color: var(--paper);
  line-height: 1;
}

.odm-logo-mark {
  width: 34px; height: 34px; flex-shrink: 0;
  color: var(--brass);
}

.odm-logo-word {
  display: flex; flex-direction: column; gap: 3px;
  min-width: 0;
}

.odm-logo-one {
  font-family: var(--font-display);
  font-size: 19px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* "MUSIC" set solid and flanked by rules, echoing the brand mark. */
.odm-logo-music {
  display: flex; align-items: center; gap: 7px;
  font-size: 10px; font-weight: 800; letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--paper); opacity: 0.92;
  white-space: nowrap;
}

.odm-logo-music::before,
.odm-logo-music::after {
  content: ""; flex: 1; min-width: 10px; height: 1px;
  background: currentColor; opacity: 0.45;
}

/* Stacked form — the record label at the centre of the hero disc. */
.odm-logo--stack {
  flex-direction: column; gap: 6px; text-align: center;
}
.odm-logo--stack .odm-logo-mark { width: 26px; height: 26px; }
.odm-logo--stack .odm-logo-word { align-items: center; }
.odm-logo--stack .odm-logo-one { font-size: 17px; letter-spacing: 0.08em; }
.odm-logo--stack .odm-logo-music { font-size: 8.5px; letter-spacing: 0.28em; }
.odm-logo--stack .odm-logo-music::before,
.odm-logo--stack .odm-logo-music::after { min-width: 12px; }

/* On the record and in the footer the whole lockup is plain white. */
.odm-logo--white, .odm-logo--white .odm-logo-mark { color: #fff; }

/* --- File-backed assets --------------------------------------------------
   When assets/js/asset-map.js declares a real file for a slot, the built-in
   drawing is replaced by an <img>. These rules size those images so a
   dropped-in file lands at the right scale without anyone editing CSS. */

.odm-logo-img { height: 38px; width: auto; max-width: 100%; }
.odm-logo--stack .odm-logo-img { height: 30px; }
@media (max-width: 600px) { .odm-logo-img { height: 32px; } }


/* ==========================================================================
   5. Header
   --------------------------------------------------------------------------
   Structurally the same bar as the app (public/css/header.css): a fluid
   gutter instead of fixed padding, only the brand allowed to shrink, and the
   drawer taking over at 1024px. Those three rules are what keep it from
   overlapping on iPads and small laptops, and they are reproduced here so
   this page behaves exactly like the signed-in site.

   No shadows: every edge is a border.
   ========================================================================== */

.site-header {
  position: sticky; top: 0; z-index: 200;
  border-bottom: var(--header-rule) solid var(--line);
}

/* The frosted pane is a PSEUDO-ELEMENT, not the header itself, and that is
   load-bearing rather than stylistic.

   backdrop-filter makes an element the containing block for every
   position:fixed descendant. With the blur on .site-header, the drawer inside
   it stopped being fixed to the viewport and became fixed to an 84px-tall bar:
   `top: 85px; bottom: 0` then resolved to a panel of zero height — full width,
   correctly placed, and invisible. Moving the blur to ::before keeps the glass
   and hands the drawer the viewport back. */
.site-header::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: rgba(10, 10, 14, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.header-container {
  display: flex; align-items: center; gap: 16px;
  height: var(--header-height);
  width: 100%;
  max-width: var(--header-max);
  margin-inline: auto;
  /* max() so a notched handset in landscape cannot tuck the brand under the
     cutout, exactly as the app header does. */
  padding-left: max(var(--header-gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--header-gutter), env(safe-area-inset-right, 0px));
}

/* The only shrinkable item on the bar. Everything else reserves its true
   width, so a cramped viewport ellipses the wordmark rather than folding the
   nav underneath the buttons. */
.odm-logo-link { display: inline-flex; min-width: 0; }
.header-container > .odm-logo-link {
  flex: 0 1 auto; min-width: 0; overflow: hidden; z-index: 210;
}
.header-container > .odm-logo-link .odm-logo { min-width: 0; }

.header-nav { display: flex; align-items: center; gap: 34px; }

.nav-links { display: flex; align-items: center; gap: 34px; }

/* Set to match the app's header exactly: 11px uppercase on the same 0.09em
   tracking (--nav-tracking there). The two bars are built from different
   design systems — brass and Manrope here, graphite and Inter in the app —
   but a visitor moving from the marketing site to their dashboard crosses
   between them in one click, and the navigation is the one component they
   see on both sides. It reads as one product only if it is set identically.

   Tracking in em rather than the previous flat 0.5px, so the spacing stays
   proportional if the size is ever changed. */
.nav-link {
  position: relative;
  font-size: 11px; color: var(--muted); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--nav-tracking);
  white-space: nowrap;
  transition: color .2s var(--ease);
}
.nav-link:hover, .nav-link.active { color: var(--paper); }

/* --- Menu underline ------------------------------------------------------
   The rule is a pseudo-element pinned BELOW the text box rather than a
   border or a bottom padding: either of those would change the link's height
   and shift every item in the bar by a few pixels the moment one became
   active. This way the geometry of the header is identical whether a rule is
   showing or not.

   It wipes in from the left and out to the right — the origin flips on the
   way out — which reads as the rule travelling with the cursor instead of
   collapsing back the way it came. The active page keeps it drawn. */
.nav-link::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -7px;
  height: 2px; border-radius: 2px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform .34s var(--ease);
}
.nav-link:hover::after,
.nav-link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left center;
}
.nav-link.active::after { transform: scaleX(1); }

.header-actions { display: flex; align-items: center; gap: 22px; }
/* .btn-ghost is a filled gradient button; its rule lives in section 14c,
   below, with the gradient it shares with the headings. Nothing to set here. */

/* Drawer-only chrome; the drawer tier reveals it. */
.drawer-head, .drawer-foot { display: none; }

.burger {
  display: none;
  width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid var(--line-strong); background: transparent;
  position: relative; z-index: 210; flex-shrink: 0; margin-left: auto;
}
.burger span {
  position: absolute; left: 11px; width: 18px; height: 2px;
  background: var(--paper); border-radius: 2px;
  transition: transform .25s var(--ease), opacity .18s var(--ease);
}
.burger span:nth-child(1) { top: 15px; }
.burger span:nth-child(2) { top: 20px; }
.burger span:nth-child(3) { top: 25px; }
.burger.is-open span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.burger.is-open span:nth-child(2) { opacity: 0; }
.burger.is-open span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* --- Horizontal nav: 1025px and up -------------------------------------- */

@media (min-width: 1025px) {
  /* The wrapper dissolves so the links and the buttons become direct flex
     children of the bar; the auto margin makes them one right-hand group. */
  .header-nav { display: contents; }
  .nav-links { margin-left: auto; flex-wrap: nowrap; flex-shrink: 0; }
  /* Matches the 34px rhythm between the nav links themselves — without it the
     container's 16px gap makes "Log in" look stuck to the last link. */
  .header-actions { flex-shrink: 0; padding-left: 18px; }
  .burger { display: none; }
}

/* Compact desktop: small laptops and large tablets in landscape. */
@media (min-width: 1025px) and (max-width: 1279px) {
  .header-container { gap: 10px; }
  .nav-links { gap: 20px; }
  /* Size holds at 11px; the tracking eases back instead, because on a
     capitalised label the spacing is what actually costs the width. */
  .nav-link { letter-spacing: 0.06em; }
  .header-actions { gap: 14px; }
  .btn { padding: 11px 18px; font-size: 13.5px; }
  .odm-logo-one { font-size: 17px; }
}

/* --- Drawer: 1024px and down --------------------------------------------- */

@media (max-width: 1024px) {
  .burger { display: block; }

  /* Fixed to the viewport — which only holds because the header's blur lives
     on a pseudo-element. See the note on .site-header::before before adding
     any filter, transform or will-change to an ancestor of this panel. */
  /* Full width, at every size in this tier.
     It used to be min(340px, 88vw). The 88vw is what made the panel a
     different width on every screen — 282px on a 320px phone, 317px at 360px,
     340px above that — and on a narrow viewport it left a strip of the page
     showing down the side, so the menu read as half-open rather than as a
     screen of its own.

     100% removes both problems at once: nothing is left showing, and the
     panel is the same thing on a phone and on an iPad instead of a sliver
     that grows with the display. The header stays above it (z-index 200 over
     195), so the close button is still there to tap. */
  .header-nav {
    position: fixed;
    top: var(--header-band); right: 0; bottom: 0; left: 0;
    width: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: 0;
    background: var(--panel);
    overflow-y: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    z-index: 195;
    transform: translateX(100%); visibility: hidden;
    transition: transform .28s var(--ease), visibility .28s;
  }
  .header-nav.is-open { transform: translateX(0); visibility: visible; }

  /* The panel is full width now, but the menu inside it is not: capped and
     left-aligned so a row is roughly the same size on a phone as on an iPad.
     Without the cap a menu item would be a 1000px-wide target on a tablet,
     with its label stranded at the far left of an empty bar. */
  .nav-links {
    flex-direction: column; align-items: stretch; gap: 2px;
    width: 100%; max-width: 460px; padding: 18px 14px;
  }
  /* Drawer rows, not bar items: read at arm's length on a phone, so they take
     the display face at a readable size. The caps and the tracking carry over
     so it is recognisably the same navigation, just not shrunk to 11px where
     nobody could read it. */
  .nav-link {
    display: block; width: 100%;
    padding: 14px 16px; border-radius: 12px;
    font-family: var(--font-display); font-size: 15px; font-weight: 700;
    letter-spacing: var(--nav-tracking);
    color: var(--paper);
  }
  .nav-link:hover { background: rgba(245, 241, 232, 0.05); }

  /* In the drawer each link is a full-width block, so the travelling rule
     would stretch the whole panel and read as a divider rather than as an
     underline. The current page is marked in brass instead. */
  .nav-link::after { display: none; }
  .nav-link.active { color: var(--brass); }

  /* Log in sits with the menu, directly under the last link.
     It used to be pushed to the far bottom with `margin-top: auto`. On a tall
     phone that merely looked detached, but the drawer's bottom edge is set
     from the viewport — and on a device whose browser chrome overlays the
     bottom of the viewport, the button lands underneath it and cannot be
     seen or tapped at all. Reported as "the login button is missing", and it
     effectively was. Anchored to the content instead, it is visible on every
     screen height, on every page. */
  .header-actions {
    margin-top: 4px;
    flex-direction: column; align-items: stretch; gap: 12px;
    /* Same cap as .nav-links above, so the button lines up with the menu
       rather than running the full width of the panel beneath it. */
    width: 100%; max-width: 460px;
    padding: 14px 14px calc(18px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--line);
  }
  .header-actions .btn { width: 100%; padding: 15px; font-size: 15px; }

  /* The same gradient button as the bar, widened to the panel and squared off
     to match the links above it. Only the box changes here — the fill, the
     ink and the animation all come from the base rule in section 14c, so the
     button cannot drift out of step with the desktop one. */
  .header-nav .btn-ghost {
    display: flex; width: 100%; justify-content: center;
    padding: 15px 16px; border-radius: 12px;
    font-size: 13px;
  }
  .header-nav .btn-ghost:hover { transform: none; box-shadow: none; }
}

/* Scrim behind the open drawer. */
.nav-scrim {
  position: fixed; inset: var(--header-band) 0 0 0;
  z-index: 190;
  background: rgba(10, 10, 14, 0.62);
  opacity: 0; transition: opacity .26s var(--ease);
}
.nav-scrim.is-open { opacity: 1; }
.nav-scrim[hidden] { display: none; }

@media (min-width: 1025px) { .nav-scrim { display: none !important; } }

body.nav-open { overflow: hidden; }

/* Coarse pointers get finger-sized targets. */
@media (pointer: coarse), (max-width: 768px) {
  .burger { width: 46px; height: 46px; }
  .burger span { left: 13px; }
}

/* --------------------------------------------------------------------------
   6. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  padding: 130px 0 110px;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
}

.hero::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(58% 52% at 78% 34%, rgba(201, 154, 60, 0.10), transparent 62%);
}

.hero-grid {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 1.18fr 0.82fr; gap: 64px; align-items: center;
}

.eyebrow {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--brass); margin-bottom: 26px;
}
.eyebrow::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--coral); box-shadow: 0 0 0 4px rgba(255, 90, 69, 0.18);
}

/* Sized so "Upload your music." holds ONE line in the text column at every
   desktop width — the cap is set from the narrowest column this grid ever
   produces, not from taste. Below 940px the layout stacks and the line is
   allowed to wrap rather than shrink to nothing. */
h1.hero-title {
  font-size: clamp(34px, 4.4vw, 60px); line-height: 1.02; font-weight: 600;
  margin-bottom: 26px;
}
h1.hero-title em { font-style: italic; color: var(--brass); font-weight: 500; }

@media (min-width: 941px) {
  .hero-line { white-space: nowrap; }
}

.hero-lead {
  font-size: 18.5px; line-height: 1.66; color: var(--muted);
  max-width: 520px; margin-bottom: 38px;
}

.hero-actions { display: flex; align-items: center; gap: 18px; margin-bottom: 44px; flex-wrap: wrap; }

.hero-stats { display: flex; gap: 46px; flex-wrap: wrap; }
.stat b { display: block; font-family: var(--font-display); font-size: 30px; font-weight: 600; }
.stat span { font-size: 13.5px; color: var(--muted); }


/* --- The record ---------------------------------------------------------- */

.hero-visual {
  position: relative; height: 500px;
  display: flex; align-items: center; justify-content: center;
}

/* Nudged outboard of its column so the record sits nearer the right edge and
   away from the headline. Only where there are two columns to sit between. */
@media (min-width: 941px) {
  .hero-visual { transform: translateX(46px); }
}

.disc {
  position: relative; width: 380px; height: 380px; border-radius: 50%;
  background:
    repeating-radial-gradient(circle at center, rgba(245, 241, 232, 0.05) 0 1px, transparent 1px 6px),
    radial-gradient(circle at 32% 28%, #2a2732, #0e0d12 70%);
  border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  animation: spin 22s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* The label carries the brand mark and turns WITH the record.

   It used to counter-rotate so the wordmark stayed upright. That is the safer
   choice for legibility, but it also means the centre of the record is the one
   part of it visibly not spinning, which reads as a sticker laid on top rather
   than a label printed on the disc. Turning with it is what makes the object
   read as one thing. The record is a slow 22s turn, so the mark is legible for
   most of every revolution anyway. */
.disc-label {
  width: 168px; height: 168px; border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, #2b2833, #121118 78%);
  border: 1px solid rgba(245, 241, 232, 0.14);
  display: flex; align-items: center; justify-content: center;
}

/* No spindle hole is drawn: the label centre is where the logo goes, and the
   two would sit on top of each other. */

.tonearm {
  position: absolute; top: 20px; right: 26px; width: 14px; height: 170px;
  transform-origin: top center; transform: rotate(24deg);
}
.tonearm::before {
  content: ""; position: absolute; top: 0; left: 5px; width: 4px; height: 100%;
  background: linear-gradient(var(--muted), var(--brass)); border-radius: 4px;
}
.tonearm::after {
  content: ""; position: absolute; top: -6px; left: -4px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--panel-2); border: 1px solid var(--line);
}

.waveform {
  position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  display: flex; align-items: flex-end; gap: 5px; height: 70px; opacity: 0.9;
}
.waveform span { width: 5px; background: var(--brass); border-radius: 3px; animation: bounce 1.2s ease-in-out infinite; }
.waveform span:nth-child(odd) { background: var(--coral); }
@keyframes bounce { 0%, 100% { height: 10px; } 50% { height: 52px; } }

/* ==========================================================================
   7. Platform slider
   --------------------------------------------------------------------------
   All that remains of the old "Where your music lands" band. Kept as a thin
   strip directly under the hero so the section beneath it — Sell your music —
   starts as close to the top of the page as a headline allows.
   ========================================================================== */

.slider-band {
  position: relative;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  padding: 30px 0;
  overflow: hidden;

  /* The width of the mask ramp below, named once so the ramp and the hover
     shields that depend on it cannot drift apart. */
  --marquee-fade: 7%;
  /* The widest tile in the strip — the wordmark pills ("Hungama") run to
     132px where an icon tile is 70px. The shields are sized from the widest
     because they have to hold back the pointer far enough that NO tile can be
     reached while any part of it is still inside the ramp. */
  --marquee-tile-max: 132px;
}

/* The soft edges. Written from --marquee-fade so the shields below stay in
   step with the ramp automatically. */
.marquee-track {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--marquee-fade),
                                      #000 calc(100% - var(--marquee-fade)), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 var(--marquee-fade),
                              #000 calc(100% - var(--marquee-fade)), transparent);
}

/* Hover shields over the two faded ends.

   The ramp is 7% — about 83px on a desktop — which is WIDER than a 70px tile,
   so at any moment there is a tile sitting inside it, drawn at part alpha. At
   rest that is the whole point and nobody notices: the tiles are dim grey and
   the fade reads as the strip running off the edge of the page.

   Hovering one of those tiles is what breaks it. The hover lights the tile up
   — a brass ring, a brass-tinted fill, the icon at full opacity — and the ramp
   then erases half of that bright ring, so the circle looks sliced down the
   middle. Nothing is actually broken; the highlight is simply landing where
   the strip is already half transparent.

   These two blocks sit over the ramp and take the pointer instead. They are
   invisible — no background, nothing to see — and exist only to be hit first,
   so a tile can only be hovered once it is clear of the fade and will light up
   whole. Width is the ramp plus the widest tile, because the pointer may be
   anywhere on a tile including its trailing edge, and it is the tile's FAR
   edge that has to be past the ramp.

   z-index is what makes it work: .marquee carries will-change: transform, so
   it paints in the positioned layer, and without a z-index here these would
   sit underneath it and shield nothing. */
.slider-band::before,
.slider-band::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: calc(var(--marquee-fade) + var(--marquee-tile-max));
  z-index: 2;
}

.slider-band::before { left: 0; }
.slider-band::after { right: 0; }

/* Nothing to shield where there is no pointer to shield from, and on a phone
   these would eat most of a narrow strip. */
@media (hover: none) {
  .slider-band::before,
  .slider-band::after { display: none; }
}
/* The strip holds the platform list TWICE, and scrolls by exactly one copy so
   the second copy arrives where the first began and the loop is invisible.
   Getting that distance right is the whole trick:

     one copy          C = S + (N-1)·gap        S = total tile widths
     whole track       W = 2S + (2N-1)·gap
     half the track  W/2 = S + (N - 0.5)·gap
     seamless        C+g = S + N·gap

   so a plain translateX(-50%) stops HALF A GAP short of the loop point and
   the strip snaps back by that much every cycle — measured at exactly 8px on
   a 16px gap. That snap is the stutter; it is not dropped frames, and no
   amount of easing or duration hides it.

   The distance is therefore written as `-50% - half a gap`, and the gap is a
   variable so the narrow-screen override below cannot change one without the
   other. translate3d rather than translateX to keep the strip on its own
   compositor layer — a 4000px-wide element repainted per frame is its own
   source of judder. */
.marquee {
  --marquee-gap: 16px;
  display: flex; width: max-content;
  gap: var(--marquee-gap);
  align-items: center;
  animation: scroll 40s linear infinite;
  will-change: transform;
}
.marquee:hover { animation-play-state: paused; }

@keyframes scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-50% - var(--marquee-gap) / 2), 0, 0); }
}

.tile {
  display: inline-flex; align-items: center; justify-content: center;
  width: 70px; height: 70px; flex-shrink: 0;
  border-radius: 50%; border: 1px solid var(--line);
  background: rgba(245, 241, 232, 0.025);
  transition: border-color .25s var(--ease), background .25s var(--ease), transform .25s var(--ease);
}
.tile:hover { border-color: var(--brass); background: var(--brass-soft); transform: translateY(-3px); }
/* Monochrome, and it STAYS monochrome — see the note above .store-logo img.
   The hover used to be `filter: none`, which handed the logo its brand colour
   back the moment the pointer touched it. It now keeps the grayscale and only
   lifts the brightness and the opacity, so the row reads the same whether or
   not anything is being hovered. */
.tile .picon {
  width: 30px; height: 30px;
  /* 1.9 before. Lowered for the same reason as the stores row: a local icon
     that is a solid tile with the mark reversed out of it loses the mark
     entirely when both are driven to near-white. The opacity below carries
     the resting dimness instead, so nothing looks brighter than it did. */
  filter: brightness(0) invert(1);
  opacity: .55;
  transition: filter .25s, opacity .25s;
}
.tile:hover .picon { 
  /* Keeps it white, but brings it to full opacity on hover */
  filter: brightness(0) invert(1); 
  opacity: 1; 
}
.tile.noicon { width: auto; height: 52px; border-radius: 100px; padding: 0 22px; }
.tile.noicon .picon { display: none; }
.tile.noicon .wordmark {
  display: block; font-family: var(--font-display); font-size: 18px; font-weight: 600;
  color: var(--muted); white-space: nowrap; transition: color .25s;
}
.tile.noicon:hover .wordmark { color: var(--paper); }
.wordmark { display: none; }

/* --------------------------------------------------------------------------
   8. Shared section furniture
   -------------------------------------------------------------------------- */

section { padding: 120px 0; border-bottom: 1px solid var(--line); }
.section-head { max-width: 700px; margin-bottom: 64px; }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head h2 { font-size: clamp(32px, 4.2vw, 52px); line-height: 1.06; margin-bottom: 20px; }
.section-head p { color: var(--muted); font-size: 18px; line-height: 1.65; }
.section-head--center p { margin-inline: auto; }

.feature-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-radius: 22px; overflow: hidden;
}
.feature { background: var(--panel); padding: 48px 38px; transition: background .25s var(--ease); }
.feature:hover { background: var(--panel-2); }
.feature h3 { font-size: 23px; margin-bottom: 14px; font-weight: 600; }
.feature p { color: var(--muted); font-size: 15.5px; line-height: 1.65; }

.inline-link { color: var(--brass); font-weight: 600; }
.inline-link:hover { color: var(--paper); }

/* --------------------------------------------------------------------------
   8b. How to sell your music — three steps
   -------------------------------------------------------------------------- */

.how { background: var(--panel); }
.section-head h2 em { font-style: normal; color: var(--brass); }

.steps {
  max-width: 760px; margin: 0 auto;
  display: flex; flex-direction: column; gap: 4px;
}
.step {
  display: grid; grid-template-columns: 92px 1fr; gap: 8px; align-items: start;
  padding: 26px 0; border-top: 1px solid var(--line);
}
.step:first-child { border-top: none; }
.step-num {
  font-family: var(--font-display); font-size: 54px; font-weight: 700;
  line-height: 0.9; color: var(--brass); opacity: 0.85;
}
.step h3 { font-size: 21px; margin-bottom: 10px; }
.step p { color: var(--muted); font-size: 15.5px; line-height: 1.7; }

.steps-cta { text-align: center; margin-top: 46px; }

/* ==========================================================================
   9. Sell your music
   --------------------------------------------------------------------------
   Replaces the old plan/sign-up button pair. The visual is composed here in
   CSS rather than shipped as a bitmap: it stays sharp on any display, weighs
   nothing, and the platform badges reuse the same icon pipeline (and the same
   fallbacks) as the marquee, so nothing renders as a broken image.
   ========================================================================== */

.sell {
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, #101015, var(--ink) 70%);
}

/* --- The flowing wave backdrop -------------------------------------------
   Six sine curves drifting left behind the copy.

   Each path is drawn across twice the viewBox and every period divides 1440,
   so translating by exactly 1440 user units lands on an identical shape and
   the loop is invisible. (On an SVG element a CSS transform length is in the
   local user coordinate system, not CSS pixels — which is what makes a plain
   1440px translate the right figure here regardless of how wide the section
   is rendered.)

   Masked to fade out at both ends so the curves emerge and dissolve rather
   than being cut off by the section edge, and pinned behind the content with
   z-index: 0 against the grid's 1. */

.wave-field {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0.5;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
}

.wave-field svg { width: 100%; height: 100%; display: block; }

.wave-field path {
  fill: none;
  /* Keeps the line 1.2px however hard preserveAspectRatio="none" stretches
     the viewBox — without it the strokes thicken on a wide screen and thin
     to nothing on a narrow one. */
  stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
  animation: waveDrift 34s linear infinite;
}

/* Staggered durations so the curves separate and recombine instead of moving
   as one rigid sheet. Each is a whole-number ratio of the others only by
   accident — that is the point, they should not re-sync on a short cycle. */
.wave-field .w1 { stroke: var(--brass); opacity: .55; animation-duration: 34s; }
.wave-field .w2 { stroke: var(--coral); opacity: .34; animation-duration: 46s; }
.wave-field .w3 { stroke: #8f83f8;      opacity: .30; animation-duration: 58s; }
.wave-field .w4 { stroke: var(--brass); opacity: .26; animation-duration: 40s; }
.wave-field .w5 { stroke: #f2e05a;      opacity: .22; animation-duration: 52s; }
.wave-field .w6 { stroke: var(--paper); opacity: .12; animation-duration: 64s; }

@keyframes waveDrift {
  from { transform: translateX(0); }
  to   { transform: translateX(-1440px); }
}

.sell-grid {
  position: relative;
  z-index: 1;
  display: grid; grid-template-columns: 1fr 1fr; gap: 76px; align-items: center;
}

.sell h2 { font-size: clamp(34px, 4.6vw, 58px); line-height: 1.04; margin-bottom: 22px; }
.sell h2 em { font-style: normal; color: var(--brass); }
.sell-lead { font-size: 18px; line-height: 1.7; color: var(--muted); margin-bottom: 34px; max-width: 520px; }

.sell-points { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 26px; margin-bottom: 40px; }
.sell-point { display: flex; align-items: flex-start; gap: 11px; font-size: 15px; color: #e7e2d8; font-weight: 600; }
.sell-point svg { width: 18px; height: 18px; color: var(--brass); flex-shrink: 0; margin-top: 1px; }

.sell-actions { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
.sell-note { font-size: 13.5px; color: var(--muted); margin-top: 18px; }

/* --- Global Music Orbit ---------------------------------------------------
   The release card with the platforms circling it. Replaces the phone mockup.

   HOW A PLATFORM MOVES. Three elements, each with one job, because trying to
   do them on one element means two animations fighting over `transform`:

     .orbit-item   rides the ellipse            (animates transform: translate)
     .orbit-depth  near/far size and blur       (animates transform: scale)
     .orbit-face   the glass badge; hover only  (no animation, so :hover works)

   Both animations share `--dur` and `--delay`, which is what phase-locks them:
   the badge is at its largest exactly when it reaches the near side of the
   path. Change one duration without the other and a badge grows on the far
   side, which reads as broken depth.

   The negative --delay starts each icon partway round its lap. It also means
   prefers-reduced-motion can simply PAUSE everything and the icons hold their
   spread-out positions — `animation: none` would drop all six onto the centre
   point instead.
   -------------------------------------------------------------------------- */

.orbit-stage {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  max-width: 560px;
  margin-inline: auto;
  display: grid;
  place-items: center;
  /* Perspective for the card's hover tilt. Set here, on the parent, because a
     perspective declared on the element being rotated has no effect. */
  perspective: 1100px;

  /* Ring radii and badge size in one place: the rings, the paths and the
     responsive steps below all read these, so they cannot disagree.

     THE INNER RING MUST CLEAR THE CARD. Every ring needs either
     rx > cardHalfWidth + badge/2, or ry > cardHalfHeight + badge/2 — otherwise
     its icons are inside the card's footprint for the entire lap and are never
     seen at all. The first version had r1 at 118x66 against a card 272 wide,
     which hid two of the six platforms permanently on every desktop size. */
  --r1x: 150px; --r1y: 104px;
  --r2x: 190px; --r2y: 122px;
  --r3x: 232px; --r3y: 148px;
  --badge: 54px;
}

/* Ambient lighting — violet, pink and gold pools well under the surface. */
.orbit-lighting {
  position: absolute; inset: -8%;
  border-radius: 50%;
  pointer-events: none;
  background:
    radial-gradient(46% 40% at 30% 28%, rgba(158, 122, 240, 0.16), transparent 70%),
    radial-gradient(44% 38% at 74% 68%, rgba(221, 96, 148, 0.13), transparent 70%),
    radial-gradient(54% 46% at 52% 50%, rgba(201, 154, 60, 0.13), transparent 72%);
  filter: blur(22px);
}

/* --- Rings and the light that sweeps along them --------------------------- */

.orbit-rings { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; }

.orbit-ring {
  position: absolute;
  border-radius: 50%;
  border: 1px solid rgba(245, 241, 232, 0.065);
}
.orbit-ring-1 { width: calc(var(--r1x) * 2); height: calc(var(--r1y) * 2); }
.orbit-ring-2 { width: calc(var(--r2x) * 2); height: calc(var(--r2y) * 2); }
.orbit-ring-3 { width: calc(var(--r3x) * 2); height: calc(var(--r3y) * 2); }

/* Two soft beams turning slowly out from the card — the "connection lines".
   Heavily blurred and low-alpha on purpose: a crisp rotating line reads as a
   radar sweep, which is the games-UI look this is meant to avoid. */
.orbit-rings::before,
.orbit-rings::after {
  content: "";
  position: absolute; left: 50%; top: 50%;
  width: var(--r3x); height: 2px;
  transform-origin: 0 50%;
  filter: blur(5px);
  background: linear-gradient(90deg, rgba(201, 154, 60, 0.34), rgba(201, 154, 60, 0) 76%);
  animation: orbitSweep 28s linear infinite;
}
.orbit-rings::after {
  background: linear-gradient(90deg, rgba(158, 122, 240, 0.30), rgba(158, 122, 240, 0) 76%);
  animation-duration: 37s;
  animation-delay: -18s;
}

@keyframes orbitSweep { to { transform: rotate(360deg); } }

/* --- Drifting motes ------------------------------------------------------- */

.orbit-dust { position: absolute; inset: 0; pointer-events: none; }
.orbit-dust i {
  position: absolute; left: var(--x); top: var(--y);
  width: 3px; height: 3px; border-radius: 50%;
  background: rgba(245, 241, 232, 0.55);
  opacity: 0;
  animation: dustFloat var(--dur) ease-in-out infinite;
  animation-delay: var(--d);
}
@keyframes dustFloat {
  0%, 100% { opacity: 0; transform: translateY(7px) scale(.5); }
  50%      { opacity: .5; transform: translateY(-9px) scale(1); }
}

/* --- The release card ----------------------------------------------------- */

.release-card {
  position: relative;
  z-index: 4;
  width: min(230px, 52%);
  padding: 17px 17px 15px;
  border-radius: 22px;
  overflow: hidden;
  background: linear-gradient(158deg, rgba(41, 38, 50, 0.88), rgba(19, 18, 24, 0.94));
  border: 1px solid rgba(245, 241, 232, 0.15);
  backdrop-filter: blur(16px) saturate(125%);
  -webkit-backdrop-filter: blur(16px) saturate(125%);
  box-shadow:
    0 30px 60px -34px rgba(0, 0, 0, 0.92),
    0 1px 0 rgba(255, 255, 255, 0.05) inset;
  /* The float animates `translate` and the hover tilt sets `rotate` — two
     separate properties, so neither overwrites the other. Doing both through
     `transform` would mean the animation always won and the tilt never
     appeared. */
  animation: cardFloat 9s ease-in-out infinite;
  transition: rotate .55s var(--ease), box-shadow .55s var(--ease);
}

@keyframes cardFloat {
  0%, 100% { translate: 0 -6px; }
  50%      { translate: 0 6px; }
}

.release-card:hover {
  rotate: 1 -1.7 0 7deg;
  box-shadow:
    0 40px 70px -34px rgba(0, 0, 0, 0.95),
    0 1px 0 rgba(255, 255, 255, 0.08) inset;
}

/* A highlight that crosses the card occasionally rather than constantly: it
   sits still for the first ~72% of the cycle and only then sweeps. */
.release-sheen {
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, 0.09) 48%, transparent 58%);
  animation: releaseSheen 12s ease-in-out infinite;
}
@keyframes releaseSheen {
  0%, 72%   { transform: translateX(-130%); }
  90%, 100% { transform: translateX(130%); }
}

.release-top { display: flex; align-items: center; gap: 12px; }

.release-art {
  width: 46px; height: 46px; flex-shrink: 0;
  border-radius: 12px;
  display: grid; place-items: center;
  background:
    radial-gradient(circle at 30% 26%, rgba(255, 255, 255, 0.30), transparent 48%),
    linear-gradient(150deg, var(--coral), #a03bd6 52%, var(--brass));
}
.release-art svg { width: 21px; height: 21px; color: rgba(255, 255, 255, 0.94); }

.release-meta { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.release-meta b { font-size: 14px; font-weight: 700; }
.release-meta em { font-style: normal; font-size: 11.5px; color: var(--brass); font-weight: 600; }

/* space-between plus a capped bar width, rather than letting each bar take an
   equal share of the row: nine bars across a 240px card gives each about 24px,
   and a 24px-wide bar 8px tall reads as a dash, not a waveform. Capping the
   width and distributing the slack keeps them upright. */
.release-wave {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 3px;
  height: 26px; margin: 15px 0 13px;
}
.release-wave i {
  flex: 1 1 auto; max-width: 5px; border-radius: 2px; height: 30%;
  background: linear-gradient(180deg, var(--brass), var(--coral));
  opacity: .85;
  animation: releaseBar 1.15s ease-in-out infinite alternate;
  animation-delay: var(--d);
}
@keyframes releaseBar { from { height: 20%; } to { height: 100%; } }

.release-status {
  display: flex; align-items: center; gap: 8px;
  font-size: 11.5px; color: var(--muted);
}
.release-pulse {
  width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
  background: #6bc192;
  animation: releasePulse 2.4s ease-out infinite;
}
@keyframes releasePulse {
  0%        { box-shadow: 0 0 0 0 rgba(107, 193, 146, 0.45); }
  70%, 100% { box-shadow: 0 0 0 9px rgba(107, 193, 146, 0); }
}

.release-progress {
  margin-top: 12px; height: 3px; border-radius: 3px;
  background: rgba(245, 241, 232, 0.10);
  overflow: hidden;
}
.release-progress i {
  display: block; height: 100%; border-radius: 3px;
  background: linear-gradient(90deg, var(--brass), var(--coral));
  animation: releaseProgress 8s ease-in-out infinite;
}
@keyframes releaseProgress {
  0%   { width: 10%; }
  60%  { width: 76%; }
  100% { width: 94%; }
}

/* --- The orbiting platforms ----------------------------------------------- */

.orbit-item {
  position: absolute; top: 50%; left: 50%;
  width: 0; height: 0;
  animation: orbitPath var(--dur) linear infinite;
  animation-delay: var(--delay);
}

/* Offset by half a badge so the badge's CENTRE sits on the path, and sized
   here rather than on .orbit-face so scale() pivots on that same centre. */
.orbit-depth {
  position: absolute;
  width: var(--badge); height: var(--badge);
  margin-left: calc(var(--badge) / -2);
  margin-top: calc(var(--badge) / -2);
  animation: orbitDepth var(--dur) linear infinite;
  animation-delay: var(--delay);
}

/* Phase-locked to orbitPath: 25% is the near side of the ellipse, 75% the far
   side. z-index steps below the card's 4 on the far side, so a badge really
   passes BEHIND the card rather than sliding over it. */
@keyframes orbitDepth {
  0%   { transform: scale(.94); opacity: .92; filter: blur(0);     z-index: 3; }
  25%  { transform: scale(1.08); opacity: 1;  filter: blur(0);     z-index: 6; }
  50%  { transform: scale(.94); opacity: .92; filter: blur(0);     z-index: 3; }
  75%  { transform: scale(.76); opacity: .58; filter: blur(1.5px); z-index: 1; }
  100% { transform: scale(.94); opacity: .92; filter: blur(0);     z-index: 3; }
}

.orbit-face {
  position: relative;
  width: 100%; height: 100%;
  border-radius: 17px;
  display: grid; place-items: center;
  background: linear-gradient(155deg, rgba(255, 255, 255, 0.11), rgba(255, 255, 255, 0.028));
  border: 1px solid rgba(245, 241, 232, 0.16);
  backdrop-filter: blur(10px) saturate(130%);
  -webkit-backdrop-filter: blur(10px) saturate(130%);
  box-shadow:
    0 10px 26px -14px rgba(0, 0, 0, 0.85),
    0 0 18px -6px rgba(var(--glow), 0.30);
  transition: transform .32s var(--ease), box-shadow .32s var(--ease), border-color .32s;
}

/* The platform's own colour, behind its badge. z-index: -1 puts it under the
   badge's own background, so only the halo that spills past the edge shows. */
.orbit-face::before {
  content: "";
  position: absolute; inset: -24%;
  border-radius: 50%;
  z-index: -1;
  background: radial-gradient(circle, rgba(var(--glow), 0.34), transparent 68%);
  filter: blur(11px);
}

.orbit-icon { display: grid; place-items: center; width: 56%; height: 56%; }
.orbit-icon img { width: 100%; height: 100%; object-fit: contain; }
.orbit-icon b {
  font-family: var(--font-display); font-size: 10px; font-weight: 700;
  color: var(--paper); text-align: center; line-height: 1.05;
}

.orbit-face::after {
  content: attr(data-name);
  position: absolute; bottom: calc(100% + 11px); left: 50%;
  transform: translateX(-50%) translateY(5px);
  padding: 5px 11px; border-radius: 9px;
  background: rgba(14, 13, 18, 0.97);
  border: 1px solid var(--line-strong);
  font-size: 10px; font-weight: 800;
  letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--paper); white-space: nowrap;
  opacity: 0; visibility: hidden;
  pointer-events: none;
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility .22s;
}

/* Hover. :hover matches ancestors of the hovered element, so pointing at the
   badge pauses the zero-sized .orbit-item that carries it round. */
.orbit-item:hover { animation-play-state: paused; }
.orbit-item:hover .orbit-depth {
  animation-play-state: paused;
  /* !important because a running animation outranks a normal declaration, and
     the far-side blur is set BY that animation. Without it, hovering a badge
     on the back of the orbit shows a blurred badge and a blurred tooltip. */
  filter: none !important;
}
.orbit-item:hover .orbit-face {
  transform: scale(1.16);
  border-color: rgba(var(--glow), 0.5);
  box-shadow:
    0 16px 32px -12px rgba(0, 0, 0, 0.9),
    0 0 30px -4px rgba(var(--glow), 0.55);
}
.orbit-item:hover .orbit-face::after {
  opacity: 1; visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* The ellipse. Generated — see build-orbit-css.js. */
@keyframes orbitPath {
  0% { transform: translate(calc(var(--rx) * 1), calc(var(--ry) * 0)); }
  2.7778% { transform: translate(calc(var(--rx) * 0.9848), calc(var(--ry) * 0.1736)); }
  5.5556% { transform: translate(calc(var(--rx) * 0.9397), calc(var(--ry) * 0.342)); }
  8.3333% { transform: translate(calc(var(--rx) * 0.866), calc(var(--ry) * 0.5)); }
  11.1111% { transform: translate(calc(var(--rx) * 0.766), calc(var(--ry) * 0.6428)); }
  13.8889% { transform: translate(calc(var(--rx) * 0.6428), calc(var(--ry) * 0.766)); }
  16.6667% { transform: translate(calc(var(--rx) * 0.5), calc(var(--ry) * 0.866)); }
  19.4444% { transform: translate(calc(var(--rx) * 0.342), calc(var(--ry) * 0.9397)); }
  22.2222% { transform: translate(calc(var(--rx) * 0.1736), calc(var(--ry) * 0.9848)); }
  25% { transform: translate(calc(var(--rx) * 0), calc(var(--ry) * 1)); }
  27.7778% { transform: translate(calc(var(--rx) * -0.1736), calc(var(--ry) * 0.9848)); }
  30.5556% { transform: translate(calc(var(--rx) * -0.342), calc(var(--ry) * 0.9397)); }
  33.3333% { transform: translate(calc(var(--rx) * -0.5), calc(var(--ry) * 0.866)); }
  36.1111% { transform: translate(calc(var(--rx) * -0.6428), calc(var(--ry) * 0.766)); }
  38.8889% { transform: translate(calc(var(--rx) * -0.766), calc(var(--ry) * 0.6428)); }
  41.6667% { transform: translate(calc(var(--rx) * -0.866), calc(var(--ry) * 0.5)); }
  44.4444% { transform: translate(calc(var(--rx) * -0.9397), calc(var(--ry) * 0.342)); }
  47.2222% { transform: translate(calc(var(--rx) * -0.9848), calc(var(--ry) * 0.1736)); }
  50% { transform: translate(calc(var(--rx) * -1), calc(var(--ry) * 0)); }
  52.7778% { transform: translate(calc(var(--rx) * -0.9848), calc(var(--ry) * -0.1736)); }
  55.5556% { transform: translate(calc(var(--rx) * -0.9397), calc(var(--ry) * -0.342)); }
  58.3333% { transform: translate(calc(var(--rx) * -0.866), calc(var(--ry) * -0.5)); }
  61.1111% { transform: translate(calc(var(--rx) * -0.766), calc(var(--ry) * -0.6428)); }
  63.8889% { transform: translate(calc(var(--rx) * -0.6428), calc(var(--ry) * -0.766)); }
  66.6667% { transform: translate(calc(var(--rx) * -0.5), calc(var(--ry) * -0.866)); }
  69.4444% { transform: translate(calc(var(--rx) * -0.342), calc(var(--ry) * -0.9397)); }
  72.2222% { transform: translate(calc(var(--rx) * -0.1736), calc(var(--ry) * -0.9848)); }
  75% { transform: translate(calc(var(--rx) * -0), calc(var(--ry) * -1)); }
  77.7778% { transform: translate(calc(var(--rx) * 0.1736), calc(var(--ry) * -0.9848)); }
  80.5556% { transform: translate(calc(var(--rx) * 0.342), calc(var(--ry) * -0.9397)); }
  83.3333% { transform: translate(calc(var(--rx) * 0.5), calc(var(--ry) * -0.866)); }
  86.1111% { transform: translate(calc(var(--rx) * 0.6428), calc(var(--ry) * -0.766)); }
  88.8889% { transform: translate(calc(var(--rx) * 0.766), calc(var(--ry) * -0.6428)); }
  91.6667% { transform: translate(calc(var(--rx) * 0.866), calc(var(--ry) * -0.5)); }
  94.4444% { transform: translate(calc(var(--rx) * 0.9397), calc(var(--ry) * -0.342)); }
  97.2222% { transform: translate(calc(var(--rx) * 0.9848), calc(var(--ry) * -0.1736)); }
  100% { transform: translate(calc(var(--rx) * 1), calc(var(--ry) * -0)); }
}

/* ==========================================================================
   10. World map
   --------------------------------------------------------------------------
   Real country geometry (assets/world-map.js). Every country is a hit target:
   click one and it is marked and its delivery detail opens.
   ========================================================================== */

.map-shell {
  position: relative;
  border: 1px solid var(--line); border-radius: 26px;
  background:
    radial-gradient(130% 105% at 50% -12%, rgba(201, 154, 60, 0.11), transparent 58%),
    linear-gradient(180deg, #17161d, #0f0e14);
  padding: 30px 26px 22px;
}

.map-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 18px;
}
.map-title { font-family: var(--font-display); font-size: 19px; font-weight: 600; }
.map-hint { font-size: 13px; color: var(--muted); }

.map-canvas { position: relative; }
#worldMap { width: 100%; height: auto; display: block; overflow: visible; }

.country {
  fill: #26242c;
  stroke: #0f0e14; stroke-width: 0.55;
  transition: fill .18s var(--ease);
  cursor: pointer;
  outline: none;
}
/* Markets we carry detail for read a step brighter, so the map advertises
   what is clickable before anyone clicks. */
.country.is-key { fill: #3a3742; }
.country:hover { fill: #6d6478; }
.country.is-selected { fill: var(--brass); }
.country:focus-visible { stroke: var(--paper); stroke-width: 1.4; }

/* The pin dropped on the selected country. */
.map-pin { pointer-events: none; opacity: 0; transition: opacity .2s var(--ease); }
.map-pin.show { opacity: 1; }
.map-pin .pin-halo { fill: var(--coral); opacity: .22; animation: pulse 3s ease-out infinite; transform-box: fill-box; transform-origin: center; }
.map-pin .pin-ring { fill: var(--ink); stroke: var(--coral); stroke-width: 1.6; }
.map-pin .pin-core { fill: var(--coral); }
@keyframes pulse {
  0% { transform: scale(.5); opacity: .35; }
  70%, 100% { transform: scale(2.4); opacity: 0; }
}

/* Detail popup, anchored to the country on desktop. */
.pop {
  position: absolute; z-index: 20; width: 268px;
  transform: translate(-50%, calc(-100% - 20px));
  background: rgba(18, 17, 23, 0.97);
  border: 1px solid var(--brass);
  border-radius: 16px; padding: 20px 20px 18px;
  box-shadow: 0 28px 64px -26px rgba(0, 0, 0, 0.95);
  opacity: 0; visibility: hidden;
  transition: opacity .22s var(--ease), visibility .22s;
}
.pop.show { opacity: 1; visibility: visible; }
.pop.below { transform: translate(-50%, 20px); }
.pop::after {
  content: ""; position: absolute; left: calc(50% + var(--arrow-shift, 0px)); bottom: -7px;
  width: 12px; height: 12px; transform: translateX(-50%) rotate(45deg);
  background: rgba(18, 17, 23, 0.97);
  border-right: 1px solid var(--brass); border-bottom: 1px solid var(--brass);
}
.pop.below::after {
  bottom: auto; top: -7px;
  border-right: none; border-bottom: none;
  border-left: 1px solid var(--brass); border-top: 1px solid var(--brass);
}
.pop-close { position: absolute; top: 12px; right: 14px; color: var(--muted); font-size: 16px; line-height: 1; }
.pop-close:hover { color: var(--paper); }
.pop-region { font-size: 10.5px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brass); margin-bottom: 8px; }
.pop h4 { font-family: var(--font-display); font-size: 20px; font-weight: 600; margin-bottom: 6px; padding-right: 20px; }
.pop-meta { font-size: 12.5px; color: var(--muted); margin-bottom: 15px; }
.pop ul { display: flex; flex-wrap: wrap; gap: 7px; }
.pop li {
  font-size: 12.5px; font-weight: 600; color: #e7e2d8;
  border: 1px solid var(--line); border-radius: 100px; padding: 5px 11px;
  background: rgba(245, 241, 232, 0.03);
}

.map-legend { display: flex; flex-wrap: wrap; gap: 9px; justify-content: center; margin-top: 22px; }
.leg {
  font-size: 13px; font-weight: 600; color: var(--muted);
  border: 1px solid var(--line); border-radius: 100px; padding: 9px 17px;
  transition: color .2s, border-color .2s, background .2s;
}
.leg:hover { color: var(--paper); border-color: var(--line-strong); }
.leg.active { color: #191305; background: var(--brass); border-color: var(--brass); }

/* ==========================================================================
   11. Inner pages — shared furniture
   ========================================================================== */

.page-hero { padding: 96px 0 72px; text-align: center; border-bottom: 1px solid var(--line); }
.page-hero h1 { font-size: clamp(34px, 5vw, 62px); line-height: 1.04; margin-bottom: 20px; }
.page-hero h1 em { font-style: normal; color: var(--brass); }
.page-hero p { color: var(--muted); font-size: 17.5px; line-height: 1.7; max-width: 640px; margin: 0 auto; }

/* --- Dotted starfield ----------------------------------------------------
   A drifting dot grid behind the title. Two layers at different sizes and
   speeds so the movement reads as depth rather than as one sliding sheet,
   and both are masked to fade out well before the section edge — a grid that
   runs to a hard border looks like a mistake.

   The dots are pseudo-elements, so they add nothing to the DOM and cannot be
   caught by the overflow walk; the section clips them itself. */

.page-hero--dots { position: relative; overflow: hidden; }
.page-hero--dots > .wrap { position: relative; z-index: 2; }

.page-hero--dots::before,
.page-hero--dots::after {
  content: ""; position: absolute; inset: -120px; pointer-events: none; z-index: 1;
  -webkit-mask-image: radial-gradient(72% 68% at 50% 42%, #000 12%, transparent 76%);
  mask-image: radial-gradient(72% 68% at 50% 42%, #000 12%, transparent 76%);
}

/* Far layer: small, dim, slow. */
.page-hero--dots::before {
  background-image: radial-gradient(rgba(245, 241, 232, 0.30) 1px, transparent 1px);
  background-size: 30px 30px;
  animation: dotDriftFar 34s linear infinite;
}

/* Near layer: fewer, brighter, brass, drifting the other way and breathing. */
.page-hero--dots::after {
  background-image: radial-gradient(rgba(201, 154, 60, 0.42) 1.4px, transparent 1.4px);
  background-size: 78px 78px;
  animation: dotDriftNear 26s linear infinite, dotGlow 7s ease-in-out infinite;
}

/* Each drift is exactly ONE tile in each axis. Any other distance leaves the
   grid mid-tile when the animation loops and the whole field visibly jumps. */
@keyframes dotDriftFar  { to { transform: translate(30px, 30px); } }
@keyframes dotDriftNear { to { transform: translate(-78px, 78px); } }
@keyframes dotGlow      { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
.page-meta { font-size: 13.5px; color: var(--muted); }

/* --- Legal pages ---------------------------------------------------------
   Centred title over a hairline, then a single measured column. Long-form
   terms are read, not skimmed, so the page gives them one narrow column and
   a lot of air rather than the full 1240 the marketing sections use. */

.legal-hero {
  text-align: center;
  padding: 104px 0 46px;
  border-bottom: 1px solid var(--line);
  background:
    radial-gradient(90% 130% at 50% -20%, rgba(201, 154, 60, 0.12), transparent 62%),
    var(--ink);
}
.legal-hero h1 {
  font-size: clamp(34px, 5.4vw, 66px);
  line-height: 1.04;
  margin-bottom: 18px;
}
.legal-date {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 14.5px; color: var(--brass);
  letter-spacing: 0.04em;
  border: 1px solid var(--brass-soft);
  background: var(--brass-soft);
  border-radius: 100px;
  padding: 8px 20px;
}

/* Measure is capped in ch so the line length stays readable however wide the
   window gets, and the column is centred rather than left-hugging. */
.prose-section { border-bottom: none; padding: 84px 0 110px; }
.prose { max-width: 74ch; margin-inline: auto; }
.prose-lead { font-size: 18px; line-height: 1.7; color: #e7e2d8; margin-bottom: 40px; }

.prose h2 {
  font-size: 21px; margin: 46px 0 16px;
  padding-top: 26px; border-top: 1px solid var(--line);
  color: var(--paper);
}
.prose h2:first-of-type { margin-top: 0; padding-top: 0; border-top: none; }

.prose p { color: var(--muted); font-size: 15.8px; line-height: 1.78; margin-bottom: 14px; }
.prose ul { margin: 4px 0 20px; display: flex; flex-direction: column; gap: 11px; }
.prose li {
  color: var(--muted); font-size: 15.8px; line-height: 1.72;
  padding-left: 22px; position: relative;
}
.prose li::before {
  content: "\25C6"; position: absolute; left: 0; top: 8px;
  color: var(--brass); font-size: 8px;
}
.prose b { color: var(--paper); font-weight: 700; }

.legal-foot {
  margin-top: 52px; padding: 24px 26px;
  border: 1px solid var(--line); border-radius: 16px;
  background: var(--panel);
}
.legal-foot p { margin: 0; }

/* Accordion FAQ — <details>, so it works with no script at all. */
.faq-list { max-width: 780px; margin-inline: auto; display: flex; flex-direction: column; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 18px; overflow: hidden; }
.faq-list details { background: var(--panel); }
.faq-list summary {
  cursor: pointer; list-style: none;
  padding: 20px 24px; font-size: 16px; font-weight: 700;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary::after {
  content: "+"; color: var(--brass); font-size: 20px; font-weight: 400; line-height: 1; flex-shrink: 0;
}
.faq-list details[open] summary::after { content: "\2212"; }
.faq-list summary:hover { background: var(--panel-2); }
.faq-list p { padding: 0 24px 22px; color: var(--muted); font-size: 15.5px; line-height: 1.7; }

/* --------------------------------------------------------------------------
   11b. Pricing plans
   -------------------------------------------------------------------------- */

.plans { border-bottom: 1px solid var(--line); }
.plan-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 22px; }
.plan {
  background: var(--panel); padding: 46px 34px 40px;
  display: flex; flex-direction: column; position: relative; text-align: center;
}
.plan:first-child { border-radius: 22px 0 0 22px; }
.plan:last-child { border-radius: 0 22px 22px 0; }
.plan-featured { background: linear-gradient(180deg, rgba(201, 154, 60, 0.10), var(--panel) 46%); }

.plan-flag {
  position: absolute; top: -15px; left: 50%; transform: translateX(-50%);
  background: var(--brass); color: #191305;
  font-size: 11.5px; font-weight: 800; padding: 7px 18px; border-radius: 100px;
  white-space: nowrap;
}

.plan-name {
  font-size: 13px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase;
  margin-bottom: 14px;
}
.plan-name-1 { color: #6ea8ff; }
.plan-name-2 { color: var(--coral); }
.plan-name-3 { color: var(--brass); }

.plan-price { font-family: var(--font-display); font-size: 42px; font-weight: 600; margin-bottom: 18px; }
.plan-price sup { font-size: 18px; }
.plan-price span { font-family: var(--font-body); font-size: 15px; color: var(--muted); font-weight: 600; }

.plan-desc { color: var(--muted); font-size: 14.5px; line-height: 1.65; margin-bottom: 26px; }
.plan-desc b { color: var(--paper); font-weight: 700; }

.plan-list { margin-bottom: 32px; flex: 1; text-align: left; }
.plan-list li { font-size: 14.5px; padding: 10px 0; border-top: 1px solid var(--line); display: flex; gap: 10px; color: #e7e2d8; }
.plan-list li:first-child { border-top: none; }
.plan-list li::before { content: "\25C6"; color: var(--brass); font-size: 8px; margin-top: 7px; }

/* A row the plan does NOT include.
   It stays in the list rather than being dropped, so the three columns line up
   row for row and can be read across — an omitted row reads as an oversight,
   a struck one states the difference. Dimmed AND marked with a cross, because
   colour alone is not a difference everyone can see. */
.plan-list li.plan-no { color: var(--text-muted, #8A82A0); opacity: 0.72; }
.plan-list li.plan-no::before {
  content: "\00D7";
  color: var(--coral);
  font-size: 14px;
  line-height: 1;
  margin-top: 3px;
}

.plan .btn { justify-content: center; }

/* --------------------------------------------------------------------------
   11c. Let's make Music Work
   --------------------------------------------------------------------------
   Four words on one shared keyframe, offset by a quarter of the cycle each,
   so exactly one word is at each point of the palette at any moment. Driving
   them off one animation rather than four keeps them permanently in step —
   four separate animations drift apart over a long session.
   -------------------------------------------------------------------------- */

.mmw {
  text-align: center;
  padding: 120px 0;
  background: var(--ink);
  border-bottom: 1px solid var(--line);
}

.mmw-title {
  font-size: clamp(42px, 8vw, 104px);
  line-height: 1.02;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 34px;
}

.mmw-word {
  display: inline-block;
  animation: mmwCycle 8s linear infinite;
}
.mmw-word:nth-child(1) { animation-delay: 0s; }
.mmw-word:nth-child(2) { animation-delay: -2s; }
.mmw-word:nth-child(4) { animation-delay: -4s; }
.mmw-word:nth-child(5) { animation-delay: -6s; }

@keyframes mmwCycle {
  0%, 100% { color: var(--paper); }
  25%      { color: var(--brass); }
  50%      { color: var(--coral); }
  75%      { color: #f2e05a; }
}

.mmw-sub {
  color: var(--muted); font-size: 17.5px; line-height: 1.7;
  max-width: 480px; margin: 0 auto 38px;
}

.mmw-btn { min-width: 190px; }

/* A cycling colour is decoration; hold it still and keep the contrast. */
@media (prefers-reduced-motion: reduce) {
  .mmw-word { animation: none; }
  .mmw-word:nth-child(2) { color: var(--brass); }
  .mmw-word:nth-child(5) { color: var(--coral); }
}

.plan-foot { text-align: center; margin-top: 44px; }
.pill {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 13px 26px; border-radius: 100px; border: 1px solid var(--line-strong);
  font-size: 13px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--paper); transition: border-color .2s, background .2s;
}
.pill:hover { border-color: var(--brass); background: var(--brass-soft); }
.plan-note { margin-top: 22px; font-size: 13px; color: var(--muted); }

/* --------------------------------------------------------------------------
   11d. Artist services — release tracker, splits, YouTube, promotion
   -------------------------------------------------------------------------- */

.tracker-grid {
  display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 76px; align-items: center;
}
.tracker-copy h2 { font-size: clamp(32px, 4vw, 46px); line-height: 1.08; margin-bottom: 22px; }
.tracker-copy h2 em { font-style: normal; color: var(--brass); }
.tracker-copy p { color: var(--muted); font-size: 17px; line-height: 1.7; max-width: 480px; margin-bottom: 18px; }
.tracker-copy .btn { margin-top: 10px; }

/* --- Release journey ------------------------------------------------------
   The dashboard that replaced the phone mockup: one release moving from
   Uploaded to Live, with the stores it reaches drifting around it.

   LAYERS, back to front:
     .rj-glow    amber light pooled behind everything
     .rj-grid    a faint ruled grid plus noise, for texture rather than detail
     .rj-motes   a few drifting specks
     .rj-plat    the six store badges (and the signals travelling to them)
     .rj-card    the dashboard itself, above all of it

   The card sits at z-index 3 and the badges at 2, so a badge drifting behind
   the card really passes behind it.
   -------------------------------------------------------------------------- */

/* The section clips, because the glow and the outermost badges are placed a
   little beyond the stage on purpose — the glow at inset -6% was reaching past
   the page edge and widening the document at tablet widths. Clipping here lets
   those keep their generous placement without any of it escaping. */
.tracker { position: relative; overflow: hidden; }

.rj-stage {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  min-height: 520px;
  /* Perspective for the card's hover tilt and the artwork's own. Declared on
     the ancestor, since a perspective set on the element being rotated does
     nothing. */
  perspective: 1200px;
}

/* --- Backdrop layers ------------------------------------------------------ */

.rj-glow {
  position: absolute; inset: 4% -6%;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle,
    rgba(243, 199, 84, 0.20),
    rgba(224, 166, 58, 0.10) 44%,
    transparent 72%);
  /* Reuses the tracker glow cycle the phone used, so the section keeps the
     same slowly-breathing amber light it had before. */
  animation: trackerGlow 17s ease-in-out infinite alternate;
}

/* Ruled grid and a fine noise wash. Both very low contrast — they are there to
   stop the panel reading as flat black, not to be looked at. */
.rj-grid {
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: .5;
  background-image:
    linear-gradient(rgba(245, 241, 232, 0.028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(245, 241, 232, 0.028) 1px, transparent 1px);
  background-size: 46px 46px, 46px 46px;
  -webkit-mask-image: radial-gradient(68% 62% at 50% 48%, #000 20%, transparent 78%);
  mask-image: radial-gradient(68% 62% at 50% 48%, #000 20%, transparent 78%);
}

.rj-motes { position: absolute; inset: 0; pointer-events: none; }
.rj-motes i {
  position: absolute; left: var(--x); top: var(--y);
  width: 3px; height: 3px; border-radius: 50%;
  background: rgba(245, 241, 232, 0.5);
  opacity: 0;
  animation: rjMote 13s ease-in-out infinite;
  animation-delay: var(--d);
}
@keyframes rjMote {
  0%, 100% { opacity: 0; transform: translateY(8px) scale(.5); }
  50%      { opacity: .45; transform: translateY(-10px) scale(1); }
}

/* --- The dashboard card --------------------------------------------------- */

.rj-card {
  position: relative;
  z-index: 3;
  width: min(300px, 82%);
  padding: 20px 20px 18px;
  border-radius: 24px;
  overflow: hidden;
  border: 1px solid rgba(245, 241, 232, 0.14);
  backdrop-filter: blur(18px) saturate(125%);
  -webkit-backdrop-filter: blur(18px) saturate(125%);
  box-shadow:
    0 36px 70px -34px rgba(0, 0, 0, 0.94),
    0 1px 0 rgba(255, 255, 255, 0.05) inset;
  animation: rjFloat 10s ease-in-out infinite;
  transition: rotate .55s var(--ease), box-shadow .55s var(--ease);
}

@keyframes rjFloat {
  0%, 100% { translate: 0 -7px; }
  50%      { translate: 0 7px; }
}

.rj-card:hover {
  rotate: 1 -1.6 0 6deg;
  box-shadow:
    0 46px 84px -34px rgba(0, 0, 0, 0.96),
    0 1px 0 rgba(255, 255, 255, 0.09) inset;
}

/* Reflection crossing the glass — still for most of the cycle, then a sweep. */
.rj-sheen {
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, 0.075) 48%, transparent 58%);
  animation: rjSheen 14s ease-in-out infinite;
}
@keyframes rjSheen {
  0%, 74%   { transform: translateX(-130%); }
  92%, 100% { transform: translateX(130%); }
}

/* --- Head: artwork, track, artist, date, LIVE ----------------------------- */

.rj-head { display: flex; align-items: flex-start; gap: 13px; }

.rj-art {
  width: 54px; height: 54px; flex-shrink: 0;
  border-radius: 14px;
  display: grid; place-items: center;
  background:
    radial-gradient(circle at 30% 26%, rgba(255, 255, 255, 0.32), transparent 48%),
    linear-gradient(150deg, var(--coral), #a03bd6 52%, var(--brass));
  box-shadow: 0 10px 22px -12px rgba(0, 0, 0, 0.9);
  /* Its own slow tilt, independent of the card's. Kept small — this is a
     highlight catching a turning surface, not a spin. */
  animation: rjArtTilt 12s ease-in-out infinite;
}
@keyframes rjArtTilt {
  0%, 100% { transform: perspective(420px) rotateY(-7deg) rotateX(3deg); }
  50%      { transform: perspective(420px) rotateY(7deg) rotateX(-3deg); }
}
.rj-art svg { width: 24px; height: 24px; color: rgba(255, 255, 255, 0.94); }

.rj-meta { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.rj-meta b { font-size: 15px; font-weight: 700; line-height: 1.2; }
.rj-meta em { font-style: normal; font-size: 12px; color: var(--brass); font-weight: 600; }
.rj-date { font-size: 10.5px; color: var(--muted); margin-top: 2px; }

.rj-live {
  flex-shrink: 0;
  font-size: 9.5px; font-weight: 800;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: #7de0a6;
  padding: 4px 9px; border-radius: 100px;
  background: rgba(107, 193, 146, 0.14);
  border: 1px solid rgba(107, 193, 146, 0.34);
  animation: rjLive 2.6s ease-out infinite;
}
@keyframes rjLive {
  0%        { box-shadow: 0 0 0 0 rgba(107, 193, 146, 0.4); }
  70%, 100% { box-shadow: 0 0 0 9px rgba(107, 193, 146, 0); }
}

/* --- Progress -------------------------------------------------------------
   The waveform that used to sit above this was removed; the head now runs
   straight into the progress row. The home page's orbit card keeps its own
   waveform (.release-wave) — different component, untouched. */

.rj-progress {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 7px 10px;
  /* The waveform used to sit between this and the head, and its margin was
     doing the separating. With it gone the release date ran straight into
     "Release progress", so the gap is now this row's own. */
  margin: 18px 0 16px;
}
.rj-progress-label { font-size: 11px; color: var(--muted); }
.rj-progress-value {
  font-family: var(--font-display); font-size: 13px; font-weight: 700;
  color: var(--brass);
  animation: rjPulse 3.4s ease-in-out infinite;
}
@keyframes rjPulse { 0%, 100% { opacity: .72; } 50% { opacity: 1; } }

.rj-progress-track {
  grid-column: 1 / -1;
  height: 4px; border-radius: 4px;
  background: rgba(245, 241, 232, 0.10);
  overflow: hidden;
}
.rj-progress-track i {
  display: block; height: 100%; width: 100%; border-radius: 4px;
  background: linear-gradient(90deg, var(--brass), var(--coral) 70%, #7de0a6);
  transform-origin: left center;
  animation: rjFill 9s ease-in-out infinite;
}
@keyframes rjFill {
  0%   { transform: scaleX(.08); }
  55%  { transform: scaleX(.82); }
  100% { transform: scaleX(1); }
}

/* --- The journey ---------------------------------------------------------- */

.rj-steps {
  position: relative;
  display: flex; flex-direction: column; gap: 2px;
  padding-top: 2px;
}

/* One line behind every dot, and a second that fills along it. Both are
   pseudo-elements on the list, so the line is continuous rather than being
   stitched together from a border on each row. */
.rj-steps::before,
.rj-steps::after {
  content: "";
  position: absolute; left: 5px; top: 13px; bottom: 13px;
  width: 2px; border-radius: 2px;
}
.rj-steps::before { background: rgba(245, 241, 232, 0.10); }
.rj-steps::after {
  background: linear-gradient(180deg, var(--brass), var(--coral) 62%, #7de0a6);
  transform-origin: top center;
  animation: rjLine 9s ease-in-out infinite;
}
@keyframes rjLine {
  0%   { transform: scaleY(.06); }
  55%  { transform: scaleY(.78); }
  100% { transform: scaleY(1); }
}

.rj-step {
  position: relative;
  display: grid;
  grid-template-columns: 12px 1fr;
  align-items: center;
  gap: 11px;
  padding: 6px 8px 6px 0;
  border-radius: 9px;
  transition: background .25s var(--ease);
}

.rj-step-dot {
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--panel-2);
  border: 2px solid rgba(245, 241, 232, 0.22);
  z-index: 1;
  transition: border-color .25s var(--ease), background .25s var(--ease);
}
.rj-step.is-done .rj-step-dot { background: var(--brass); border-color: var(--brass); }
.rj-step.is-live .rj-step-dot {
  background: #7de0a6; border-color: #7de0a6;
  animation: rjLive 2.6s ease-out infinite;
}

.rj-step-name { font-size: 12.5px; font-weight: 600; color: #e7e2d8; }
.rj-step.is-live .rj-step-name { color: #7de0a6; }

/* The per-stage description. Laid over the row on hover rather than expanding
   it: growing the row would push every stage below it down and make the
   connector line jump. */
.rj-step-note {
  position: absolute; left: 23px; right: 6px;
  font-size: 10.5px; color: var(--muted);
  opacity: 0; visibility: hidden;
  transform: translateY(3px);
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility .22s;
  pointer-events: none;
}
.rj-step:hover { background: rgba(245, 241, 232, 0.055); }
.rj-step:hover .rj-step-name { opacity: 0; }
.rj-step:hover .rj-step-note { opacity: 1; visibility: visible; transform: translateY(0); }

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

.rj-delivery {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 15px; padding-top: 13px;
  border-top: 1px solid var(--line);
  font-size: 11px;
}
.rj-delivery-label { color: var(--muted); }
.rj-delivery-value { color: #7de0a6; font-weight: 700; }

/* --- Store badges --------------------------------------------------------- */

.rj-plat {
  position: absolute;
  z-index: 2;
  width: 50px; height: 50px;
  margin-left: -25px; margin-top: -25px;
  animation: rjDrift 9s ease-in-out infinite;
  animation-delay: var(--sig);
}
@keyframes rjDrift {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(0, -9px); }
}

.rj-plat-face {
  position: relative;
  width: 100%; height: 100%;
  border-radius: 16px;
  display: grid; place-items: center;
  background: linear-gradient(155deg, rgba(255, 255, 255, 0.11), rgba(255, 255, 255, 0.03));
  border: 1px solid rgba(245, 241, 232, 0.16);
  backdrop-filter: blur(10px) saturate(130%);
  -webkit-backdrop-filter: blur(10px) saturate(130%);
  box-shadow:
    0 10px 24px -14px rgba(0, 0, 0, 0.85),
    0 0 16px -6px rgba(var(--glow), 0.28);
  transition: transform .3s var(--ease), box-shadow .3s var(--ease), border-color .3s;
}
.rj-plat-face::before {
  content: "";
  position: absolute; inset: -22%;
  border-radius: 50%;
  z-index: -1;
  background: radial-gradient(circle, rgba(var(--glow), 0.30), transparent 68%);
  filter: blur(10px);
}

.rj-plat-icon { display: grid; place-items: center; width: 54%; height: 54%; }
.rj-plat-icon img { width: 100%; height: 100%; object-fit: contain; }
.rj-plat-icon b {
  font-family: var(--font-display); font-size: 8.5px; font-weight: 700;
  color: var(--paper); text-align: center; line-height: 1.05;
}

.rj-plat-face::after {
  content: attr(data-name);
  position: absolute; bottom: calc(100% + 10px); left: 50%;
  transform: translateX(-50%) translateY(5px);
  padding: 5px 10px; border-radius: 9px;
  background: rgba(14, 13, 18, 0.97);
  border: 1px solid var(--line-strong);
  font-size: 9.5px; font-weight: 800;
  letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--paper); white-space: nowrap;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility .22s;
}

.rj-plat:hover { animation-play-state: paused; }
.rj-plat:hover .rj-plat-face {
  transform: scale(1.14);
  border-color: rgba(var(--glow), 0.5);
  box-shadow:
    0 16px 30px -12px rgba(0, 0, 0, 0.9),
    0 0 26px -4px rgba(var(--glow), 0.5);
}
.rj-plat:hover .rj-plat-face::after {
  opacity: 1; visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* The signal: a mote that leaves the card and arrives under its badge, once
   per cycle, staggered per store so the six read as a sequence of deliveries
   rather than one simultaneous flash.

   It travels from the CARD's centre, which is the stage centre — so the start
   offset is simply the badge's own position mirrored, expressed here in the
   same percentages the badge is placed with. */
.rj-signal {
  position: absolute;
  z-index: 2;
  width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: rgba(var(--glow), 0.95);
  box-shadow: 0 0 10px 2px rgba(var(--glow), 0.55);
  opacity: 0;
  pointer-events: none;
  animation: rjSignal 5.4s ease-in-out infinite;
  animation-delay: var(--sig);
}

/* left/top rather than a transform, deliberately.
   The dot has to finish exactly under its badge, and the badge is placed in
   PERCENTAGES of the stage. A percentage transform resolves against the dot's
   own 5px box, not the stage, so there is no transform that means "travel to
   where the badge is" at every screen size — but animating the same left/top
   values the badge is positioned with lands on it exactly, at any width.

   It costs layout per frame, which is why it is six 5px dots and not sixty. */
@keyframes rjSignal {
  0%        { left: 50%; top: 50%; opacity: 0; transform: scale(.4); }
  10%       { opacity: 1; transform: scale(1); }
  68%       { left: var(--tx); top: var(--ty); opacity: 1; transform: scale(1); }
  82%, 100% { left: var(--tx); top: var(--ty); opacity: 0; transform: scale(1.7); }
}

/* --- Right-hand copy ------------------------------------------------------ */

.tracker-title { display: flex; flex-direction: column; gap: 10px; margin-bottom: 34px; }

/* The lead-in is deliberately quiet: small, tracked, muted. It sets up the
   product name rather than competing with it. */
.tracker-kicker {
  font-family: var(--font-body);
  font-size: 12.5px; font-weight: 700;
  letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--muted);
}

.tracker-brandline {
  font-size: clamp(30px, 3.6vw, 46px);
  line-height: 1.06;
  letter-spacing: -0.015em;
}

/* Body text is held narrower than the column it sits in — a measure of about
   58 characters, which is easier to read than the full width. */
.tracker-copy p {
  color: var(--muted);
  font-size: 16.5px; line-height: 1.75;
  max-width: 44ch;
  margin-bottom: 18px;
}

/* Kept from the phone block: the Splits card further down the page shares this
   glow, and it is the half of that rule that must survive. */
.split-card::before {
  content: "";
  position: absolute; inset: -13% -16%;
  z-index: -1; pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(201, 154, 60, 0.30),
    rgba(201, 154, 60, 0.10) 46%,
    transparent 70%);
  filter: blur(22px);
}

@keyframes trackerGlow {
  0%   { filter: blur(30px) hue-rotate(-26deg) saturate(1.25) brightness(0.94); }
  50%  { filter: blur(36px) hue-rotate(-4deg)  saturate(1.30) brightness(1.10); }
  100% { filter: blur(32px) hue-rotate(16deg)  saturate(1.10) brightness(1.02); }
}

/* --- Splits card ---------------------------------------------------------- */

.collab { background: var(--panel); }
.collab-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 76px; align-items: center; }
.collab-copy h2 { font-size: clamp(32px, 4.2vw, 48px); line-height: 1.08; margin-bottom: 8px; }
.collab-copy h2 em { font-style: normal; color: var(--brass); }
.collab-lead { font-family: var(--font-display); font-size: 18px; color: var(--brass); margin-bottom: 20px; }
.collab-copy p { color: var(--muted); font-size: 16.5px; line-height: 1.7; max-width: 460px; margin-bottom: 14px; }

.collab-visual { display: grid; place-items: center; }

.split-card {
  position: relative;
  width: min(400px, 100%);
  background: linear-gradient(180deg, #1d1b24, #131219);
  border: 1px solid var(--line-strong); border-radius: 24px;
  padding: 30px 28px 26px;
  box-shadow: 0 46px 90px -38px rgba(0, 0, 0, 0.92);
}
.split-head { text-align: center; margin-bottom: 22px; }
.split-eyebrow {
  display: block; font-size: 11px; font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.16em; color: var(--brass); margin-bottom: 7px;
}
.split-head h4 { font-family: var(--font-display); font-size: 22px; font-weight: 600; }

/* The ring states the division at a glance. The hole is punched with a mask
   rather than covered by an opaque disc, so the card's gradient shows through
   it and the logo can sit in the gap without a colour seam behind it. */
.split-chart { position: relative; display: grid; place-items: center; margin-bottom: 24px; }
.split-ring {
  width: 168px; height: 168px; border-radius: 50%;
  background: conic-gradient(
    var(--brass)  0     40%,
    var(--coral)  40%   75%,
    #6ea8ff       75%  100%);
  -webkit-mask: radial-gradient(circle, transparent 0 57px, #000 58px);
  mask: radial-gradient(circle, transparent 0 57px, #000 58px);
}
.split-core {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  display: grid; place-items: center;
}
.odm-logo--micro .odm-logo-mark { width: 19px; height: 19px; }
.odm-logo--micro .odm-logo-one { font-size: 11.5px; letter-spacing: 0.05em; }
.odm-logo--micro .odm-logo-music { font-size: 6px; letter-spacing: 0.18em; }

/* Left for the same reason as .rt-body — the stacked grid centres everything
   above it, and a name/role pair reads as a list only when it is aligned. */
.split-list { display: flex; flex-direction: column; text-align: left; }
.split-list li {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 0; border-top: 1px solid var(--line);
}
.split-list li:first-child { border-top: none; }
.split-swatch { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
.split-swatch-1 { background: var(--brass); }
.split-swatch-2 { background: var(--coral); }
.split-swatch-3 { background: #6ea8ff; }
.split-who { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.split-who b { font-size: 14px; font-weight: 700; }
.split-who em { font-style: normal; font-size: 11.5px; color: var(--muted); }
.split-pc { font-family: var(--font-display); font-size: 17px; font-weight: 600; }

.split-foot {
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
  text-align: center; font-size: 12px; color: var(--muted);
}

.yt-promo { background: linear-gradient(180deg, #101015, var(--ink) 70%); }
.yt-card {
  max-width: 380px; margin: 0 auto; text-align: center;
  background: var(--panel); border: 1px solid var(--line); border-radius: 22px;
  padding: 40px 34px;
}
.yt-icon {
  display: inline-grid; place-items: center;
  width: 56px; height: 56px; margin-bottom: 20px;
}
.yt-icon img { width: 48px; height: 48px; }
.yt-card h3 { font-size: 22px; margin-bottom: 10px; }
.yt-card p { color: var(--muted); font-size: 15px; line-height: 1.6; }

.feature-icon { width: 36px; height: 36px; color: var(--brass); margin-bottom: 18px; }

/* --------------------------------------------------------------------------
   12. Artist stories
   -------------------------------------------------------------------------- */

.quote-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; }
.quote-card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 20px;
  padding: 32px 28px; display: flex; flex-direction: column;
}
.quote-stars { display: flex; gap: 3px; margin-bottom: 18px; }
.quote-stars i { width: 15px; height: 15px; background: var(--brass); display: block; border-radius: 3px; position: relative; }
.quote-stars i::after {
  content: "\2605"; position: absolute; inset: 0;
  font-size: 10px; line-height: 15px; text-align: center; color: #191305; font-style: normal;
}
.quote-card p {
  font-size: 15.5px; line-height: 1.62; color: #e7e2d8; margin-bottom: 22px;
  font-style: italic; font-family: var(--font-display); font-weight: 450; flex: 1;
}
.quote-who { display: flex; align-items: center; gap: 12px; padding-top: 18px; border-top: 1px solid var(--line); }
.avatar {
  width: 40px; height: 40px; border-radius: 50%;
  background: conic-gradient(from 90deg, var(--brass), var(--coral));
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 13px; color: #191305; flex-shrink: 0;
}
.quote-who b { font-size: 14.5px; display: block; }
/* Country only — never a city. A landing page that names towns reads as a
   local service; the catalogue goes worldwide. */
.quote-who span { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; }

/* --------------------------------------------------------------------------
   13. 150+ digital stores
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   13. 150+ digital stores — six logos, monochrome
   --------------------------------------------------------------------------
   One row, no captions, everything white. The icons are REQUESTED in white
   from the CDN rather than filtered to white in CSS: a grayscale filter
   cannot lift a black logo (TikTok, Tidal) off a black page, it just leaves
   it black. Brands with no icon in the set fall back to a white wordmark,
   which sits in the row perfectly happily.
   -------------------------------------------------------------------------- */

.stores { text-align: center; background: var(--panel); }
.stores h2 { font-size: clamp(30px, 4vw, 48px); line-height: 1.08; margin-bottom: 20px; }
.stores h2 em { font-style: normal; color: var(--brass); }
.stores-lead { color: var(--muted); font-size: 17.5px; line-height: 1.7; max-width: 720px; margin: 0 auto 60px; }

.stores-row {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 30px 60px; margin-bottom: 56px;
}
.store-logo {
  display: inline-grid; place-items: center;
  height: 48px; min-width: 48px;
  opacity: .8; transition: opacity .22s var(--ease);
}
.store-logo:hover { opacity: 1; }
/* Marks run larger than the wordmarks so the row reads as one weight: a
   glyph has to be bigger than lettering to carry the same presence. */
/* Forced monochrome IN CSS, not just by asking the CDN for a white copy.
   The registry lets a real file be dropped in for any slug, and landing.js
   prefers that file over the CDN — which quietly defeats the mono request,
   because a local brand SVG arrives in full colour. That is how a teal
   JioSaavn tile ended up in a row that is meant to be black and white.
   Filtering here catches every source: CDN, local file, colour or not.

   The brightness lift is deliberately SMALL. A local icon is often a solid
   tile with the mark reversed out of it — the JioSaavn png is a coloured
   square with a white leaf — and a strong lift drives the tile and the mark
   to the same near-white, erasing the detail and leaving a plain grey blob.
   Anything arriving from the CDN here is already requested in paper white
   (data-tone="mono" in the markup), so it needs no lift at all; this is only
   enough to keep a mid-tone off the background. */
.store-logo img {
  width: 46px; height: 46px;
  filter: brightness(0) invert(1);
}

.store-logo b {
  font-family: var(--font-display); font-size: 23px; font-weight: 700;
  color: var(--paper); white-space: nowrap; letter-spacing: -0.01em;
}

/* --------------------------------------------------------------------------
   14. Footer
   -------------------------------------------------------------------------- */

footer { padding: 90px 0 34px; }
.footer-top { display: grid; grid-template-columns: 1.5fr repeat(3, 1fr); gap: 44px; margin-bottom: 72px; }
.footer-brand p { color: var(--muted); font-size: 14.5px; line-height: 1.65; margin: 22px 0 26px; max-width: 300px; }
.socials { display: flex; gap: 12px; }
.socials a {
  width: 38px; height: 38px; border: 1px solid var(--line); border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 800; color: var(--muted); transition: .2s;
}
.socials a:hover { border-color: var(--brass); background: var(--brass-soft); color: var(--brass); }
.fcol h4 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); margin-bottom: 22px; font-weight: 700; }
.fcol a { display: block; font-size: 14.5px; color: #d9d4c8; margin-bottom: 14px; transition: .2s; width: fit-content; }
.fcol a:hover { color: var(--brass); }
.footer-bottom {
  display: flex; justify-content: space-between; align-items: center;
  padding-top: 32px; border-top: 1px solid var(--line);
  font-size: 13px; color: var(--muted); flex-wrap: wrap; gap: 14px;
}
.footer-bottom a { color: var(--muted); margin-left: 20px; }
.footer-bottom a:hover { color: var(--paper); }

/* --------------------------------------------------------------------------
   14b. Scroll reveal
   --------------------------------------------------------------------------
   Headings, paragraphs and cards start a little below their resting place
   and invisible, then settle into position once landing.js marks them
   visible. Staggered per parent (see landing.js) so a row of cards steps in
   left-to-right instead of arriving as one flat block.
   -------------------------------------------------------------------------- */

.reveal { opacity: 0; transform: translateY(22px); transition: opacity .65s var(--ease), transform .65s var(--ease); }
.reveal.is-visible { opacity: 1; transform: translateY(0); }

/* --------------------------------------------------------------------------
   14c. Animated gradient text
   --------------------------------------------------------------------------
   Every highlighted word that used to be flat brass now runs a gradient that
   drifts through gold, coral and yellow.

   MUST STAY BELOW the rules it replaces. Each selector here is the same
   specificity as the `color: var(--brass)` declaration it overrides, so it
   wins on source order alone — moving this block higher up the file silently
   hands those words their flat colour back.

   The pan uses `alternate` rather than looping in one direction. A one-way
   loop has to arrive back at the colour it started on or it visibly jumps at
   the restart; alternating reverses instead, so the movement is seamless by
   construction whatever colours are in the ramp.

   Deliberately NOT display: inline-block. That would make each highlight an
   unbreakable box — "sell your music" is three words, and on a 320px phone an
   unbreakable three-word box runs off the side of the screen. Left inline, it
   wraps and each line takes its own slice of the gradient.
   -------------------------------------------------------------------------- */

h1.hero-title em,
.section-head h2 em,
.sell h2 em,
.page-hero h1 em,
.tracker-copy h2 em,
.collab-copy h2 em,
.stores h2 em {
  background-image: linear-gradient(
    90deg,
    var(--brass) 0%,
    #e8703f 28%,
    var(--coral) 46%,
    #f2e05a 72%,
    var(--brass) 100%);
  background-size: 200% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* Safari paints the text fill before honouring `color: transparent`, so
     without this the gradient is hidden behind solid glyphs. */
  -webkit-text-fill-color: transparent;
  animation: gradientText 7s ease-in-out infinite alternate;
}

/* Drives both the clipped-to-text headings above and the filled Log in button
   below — in each case it is the background that travels, so one keyframe
   serves both and they stay in step with each other. */
@keyframes gradientText {
  from { background-position: 0% center; }
  to   { background-position: 100% center; }
}

/* --- Log in: a real button --------------------------------------------
   It was a bordered label with gradient TEXT, which read as a link that
   happened to be coloured. Now the gradient fills the button itself and the
   label sits on top in ink, so it is unmistakably a control.

   The ink is the same near-black used on .btn — dark type on a light gold is
   what keeps it legible through the whole colour cycle, where white would
   drop to roughly 2:1 as the ramp passes through yellow. */
.btn-ghost {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 10px 20px;
  border-radius: 100px;
  border: 1px solid transparent;
  background-image: linear-gradient(
    90deg,
    var(--brass) 0%,
    #e8703f 28%,
    var(--coral) 46%,
    #f2e05a 72%,
    var(--brass) 100%);
  background-size: 200% auto;
  animation: gradientText 7s ease-in-out infinite alternate;
  color: #191305;
  font-size: 11px; font-weight: 800;
  text-transform: uppercase; letter-spacing: var(--nav-tracking);
  white-space: nowrap;
  transition: transform .18s var(--ease), box-shadow .18s var(--ease);
}

.btn-ghost:hover {
  transform: translateY(-1px);
  box-shadow: 0 10px 24px -10px rgba(201, 154, 60, 0.6);
}

/* --------------------------------------------------------------------------
   14d. Capitalised section headings
   --------------------------------------------------------------------------
   Set in CSS rather than by retyping the markup, so the underlying text stays
   readable in the source, in search results and to a screen reader, which
   announces the sentence-case original rather than spelling out capitals.
   -------------------------------------------------------------------------- */

#sell h2,
#how h2,
.stores h2,
#youtube-promo h2,
#promote h2 {
  text-transform: uppercase;
  /* Capitals set tighter than lowercase at the same tracking, and these run
     to three or four words, so they get a touch of air to stay readable. */
  letter-spacing: 0.01em;
}

/* --------------------------------------------------------------------------
   15. Motion preferences
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .disc, .disc-label { animation: none; }
  .waveform span { animation: none; height: 26px; }
  .marquee { animation: none; flex-wrap: wrap; justify-content: center; width: 100%; }
  .marquee-track { -webkit-mask-image: none; mask-image: none; }
  .marquee .dupe { display: none; }
  .tile:hover { transform: none; }
  .sell-badge { animation: none; }
  .map-pin .pin-halo { animation: none; opacity: .18; }
  .btn:hover { transform: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  /* The dot field holds still, but stays — it is texture, not motion. */
  .page-hero--dots::before, .page-hero--dots::after { animation: none; }
  /* The release journey holds still. The card, progress, signals and
     drifting badges all stop; the LIVE pulse and the stage glow stop too. The
     progress bar and connector line are pinned FULL rather than left at the
     8% their animations start from — a tracker frozen at "just began" would
     misreport a release that is finished. */
  .rj-glow, .rj-card, .rj-sheen, .rj-motes i, .rj-art,
  .rj-progress-value, .rj-live,
  .rj-plat, .rj-signal, .rj-step.is-live .rj-step-dot { animation: none; }
  .rj-progress-track i, .rj-steps::after { animation: none; transform: none; }
  /* Signals are motion by definition — with nothing travelling they are just
     six dots parked on the card. */
  .rj-signal { display: none; }
  /* The waves hold their position. Kept visible for the same reason as the
     dot field: they are texture, and removing them would change the design
     rather than just calming it. */
  .wave-field path { animation: none; }

  /* The orbit is PAUSED, never switched off.
     Each icon's position comes from its negative animation-delay, so a paused
     animation holds it where it had got to — the six stay spread around the
     rings. `animation: none` would reset every transform and stack all six on
     the centre point, on top of the card. The card, waveform, progress, sheen
     and pulse stop outright, since those add nothing when still. */
  .orbit-item,
  .orbit-depth { animation-play-state: paused; }
  .release-card,
  .release-sheen,
  .release-wave i,
  .release-progress i,
  .release-pulse,
  .orbit-dust i,
  .orbit-rings::before,
  .orbit-rings::after { animation: none; }
  /* Held at a readable width rather than the 10% the animation starts from. */
  .release-progress i { width: 68%; }
  .release-wave i { height: 55%; }
  /* Gradient headings keep the gradient and stop travelling. Reverting them
     to flat brass would lose the colour entirely, which is more change than
     reduced-motion asks for — it asks for stillness, not plainness. */
  h1.hero-title em,
  .section-head h2 em,
  .sell h2 em,
  .page-hero h1 em,
  .tracker-copy h2 em,
  .collab-copy h2 em,
  .stores h2 em,
  .header-nav .btn-ghost { animation: none; }
}

/* ==========================================================================
   16. Responsive
   --------------------------------------------------------------------------
   The header has its own tiers up in section 5 — it breaks at 1024px, in step
   with the app. What follows is page content only.
   ========================================================================== */

@media (max-width: 1100px) {
  .quote-strip { grid-template-columns: repeat(2, 1fr); }
  .sell-grid { gap: 48px; }
  .stores-row { gap: 26px 44px; }
}

/* Laptops and small desktops: still TWO columns (they stack at 940), but the
   wrap is no longer at its 1240 cap, so the stage column is narrower than the
   550px the desktop radii are sized for. At 1024 that put the outer ring 33px
   outside the stage — invisible as overflow, because #sell clips, so it simply
   sliced the badges as they came round. The rings come in to fit the column
   that actually exists between these two widths. */
@media (min-width: 941px) and (max-width: 1239px) {
  .orbit-stage {
    --r1x: 134px; --r1y: 96px;
    --r2x: 152px; --r2y: 114px;
    --r3x: 170px; --r3y: 130px;
    --badge: 46px;
  }
  .release-card { width: min(206px, 50%); }
}

@media (max-width: 940px) {
  section { padding: 84px 0; }

  /* The hero is deliberately compact once it stacks: the record goes on top,
     and every pixel it spends pushes "Sell your music" — the section this page
     is actually for — further off the first screen. */
  .hero { padding: 56px 0 52px; }
  .hero-grid { grid-template-columns: 1fr; gap: 34px; text-align: center; }
  .hero-title { margin-bottom: 20px; }
  .hero-lead { margin-left: auto; margin-right: auto; margin-bottom: 28px; }
  .hero-actions { justify-content: center; margin-bottom: 30px; }
  .hero-stats { justify-content: center; gap: 30px; }
  .hero-visual { height: 250px; order: -1; }
  .disc { width: 210px; height: 210px; }
  .disc-label { width: 108px; height: 108px; }
  .tonearm { height: 120px; top: 6px; right: 14px; }
  .waveform { height: 44px; }
  .slider-band { padding: 20px 0; }

  .mmw { padding: 84px 0; }
  .step { grid-template-columns: 64px 1fr; }
  .step-num { font-size: 40px; }

  .sell-grid { grid-template-columns: 1fr; gap: 56px; }
  .sell-visual { order: -1; max-width: 460px; margin-inline: auto; width: 100%; }
  .sell-points { max-width: 520px; }

  /* Stacked: the stage is narrower, so the rings come in rather than the whole
     thing being scaled down — a scaled-down stage would take the badge type
     and the card's text with it. */
  .orbit-stage {
    --r1x: 136px; --r1y: 104px;
    --r2x: 164px; --r2y: 124px;
    --r3x: 190px; --r3y: 144px;
    --badge: 48px;
  }
  /* Narrower here than on desktop so the inner ring has room to clear it. */
  .release-card { width: min(200px, 48%); }

  .tracker-grid { grid-template-columns: 1fr; gap: 44px; text-align: center; }
  .tracker-copy p { margin-left: auto; margin-right: auto; }

  /* Heading first once the columns stack. The visual leads in the DOM because
     that is the order the two-column layout wants; on a phone the words have
     to arrive before the dashboard or the section opens on a picture with no
     explanation. */
  .tracker-copy { order: -1; }
  .tracker-title { align-items: center; }

  /* The stage stops reserving desktop height and sizes to the card, and the
     badges pull in so they still frame it rather than hugging the edges. */
  .rj-stage { min-height: 0; padding: 26px 0 10px; }
  .rj-card { width: min(330px, 92%); }
  .rj-plat { width: 44px; height: 44px; margin-left: -22px; margin-top: -22px; }
  .rj-steps { text-align: left; }
  .rj-delivery, .rj-progress, .rj-head { text-align: left; }

  .collab-grid { grid-template-columns: 1fr; gap: 44px; text-align: center; }
  .collab-copy p { margin-left: auto; margin-right: auto; }
  /* The splits card leads once the columns stack; the copy reads better
     underneath it. (The phone is already first in its own section.) */
  .collab-visual { order: -1; }

  .feature-grid { grid-template-columns: 1fr; }
  .section-head { text-align: center; margin-left: auto; margin-right: auto; }
  .footer-top { grid-template-columns: repeat(2, 1fr); }
  .map-shell { padding: 22px 16px 18px; }
  .map-toolbar { justify-content: center; text-align: center; }

  .page-hero { padding: 72px 0 56px; }
}

/* --------------------------------------------------------------------------
   Pricing stacks at 1150px, not at 940 like everything else.

   The three plans are read ACROSS — row four of one column against row four of
   the next — so every feature has to sit on one line or the column it is in
   slides a line out of step with its neighbours. Below about 1150px each card
   is roughly 224px of text, which is not enough for "Customer support in 5
   business days" on one line, and the comparison quietly stops lining up.

   So they stop being columns before that happens. Stacked there is nothing to
   align, and each plan gets the full measure to itself.
   -------------------------------------------------------------------------- */
@media (max-width: 1150px) {
  .plan-grid { grid-template-columns: 1fr; max-width: 440px; margin-inline: auto; }
  /* Stacked, so the rounded corners belong to the ends of the column rather
     than the ends of a row that no longer exists. */
  .plan:first-child { border-radius: 22px 22px 0 0; }
  .plan:last-child { border-radius: 0 0 22px 22px; }
  .plan-featured { margin-top: 14px; }
}

@media (max-width: 700px) {
  .quote-strip { grid-template-columns: 1fr; }
  .sell-points { grid-template-columns: 1fr; }
  .stores-row { gap: 24px 34px; }
  .store-logo { height: 34px; }
  .store-logo img { width: 32px; height: 32px; }
  .store-logo b { font-size: 20px; }
}

/* Smallest handsets. The record shrinks again rather than the type: the
   headline has to stay readable, and the record is decoration. */
@media (max-width: 400px) {
  .hero { padding: 44px 0 40px; }
  .hero-grid { gap: 26px; }
  .hero-visual { height: 200px; }
  .disc { width: 172px; height: 172px; }
  .disc-label { width: 90px; height: 90px; }
  .tonearm { height: 96px; }
  .waveform { height: 34px; }
  .hero-stats { gap: 22px; }
}

/* Phones: fewer effects running at once, not just a smaller picture.
   The dust, the sweeping beams and the backdrop blurs are the parts that cost
   most per frame and read least at this size, so they go; the orbit, the card
   and the depth cycle — the things the section is actually about — stay. */
/* Phones: the release journey keeps its card and drops the surrounding
   traffic. Six badges around a 300px card on a 390px screen would have to sit
   on top of it; four in the corners still say "delivered everywhere" without
   crowding the thing they are delivering to. */
@media (max-width: 700px) {
  .rj-plat { width: 40px; height: 40px; margin-left: -20px; margin-top: -20px; }
  /* The two flank stores go by name. :nth-of-type would count divs and spans
     rather than badges, and hid the wrong one. */
  .rj-minor { display: none; }
  .rj-grid, .rj-motes { display: none; }
  .rj-card {
    width: min(300px, 94%);
    padding: 17px 17px 15px;
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .rj-plat-face { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .rj-art { width: 46px; height: 46px; }
}

@media (max-width: 420px) {
  .rj-card { width: min(268px, 96%); border-radius: 20px; padding: 15px 15px 13px; }
  .rj-plat { width: 36px; height: 36px; margin-left: -18px; margin-top: -18px; }
  .rj-art { width: 40px; height: 40px; }
  .rj-meta b { font-size: 13.5px; }
  .rj-step-name, .rj-step-note { font-size: 11px; }
}

@media (max-width: 700px) {
  /* Rounder as well as smaller. The desktop ellipses are flat (ry is about
     0.56 of rx) because there is width to spare there; on a phone that same
     flatness put the inner rings INSIDE the card's own footprint, so two of
     the six icons were behind it for the whole lap and simply never appeared.
     Opening the vertical radius lets them clear the card top and bottom, and
     they still pass behind it at the sides — which is the depth effect, not a
     bug. */
  .orbit-stage {
    --r1x: 112px; --r1y: 110px;
    --r2x: 132px; --r2y: 128px;
    --r3x: 152px; --r3y: 144px;
    --badge: 38px;
  }
  .orbit-dust,
  .orbit-rings::before,
  .orbit-rings::after { display: none; }
  .release-card {
    width: min(196px, 66%);
    padding: 13px 13px 12px;
    /* Dropped with the rest of the per-frame cost on phones: a backdrop blur
       under six moving badges is the most expensive thing in this section. */
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .release-art { width: 38px; height: 38px; }
  .release-meta b { font-size: 12.5px; }
  .release-meta em { font-size: 10.5px; }
  .release-status { font-size: 10.5px; }
  .orbit-face { backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* Smallest handsets. The outer ring is pulled in further than the arithmetic
   strictly needs: at 320px the previous figures cleared the stage edge by two
   tenths of a pixel, which is not a margin, it is a coincidence waiting for a
   slightly wider scrollbar or a rounding difference to turn into a clipped
   badge. */
@media (max-width: 420px) {
  .orbit-stage {
    --r2x: 96px;  --r2y: 90px;
    --r3x: 116px; --r3y: 108px;
    --badge: 34px;
  }
  /* Four platforms instead of six on the smallest handsets.
     There is not room for a third ring that both clears a readable card and
     stays inside the stage — the two would have to overlap, and icons stuck
     permanently behind the card are worse than icons that are not there. The
     brief allows reducing the number of simultaneous effects on mobile rather
     than shrinking everything; this is that. */
  .orbit-r1 { display: none; }
  .release-card { width: min(164px, 62%); border-radius: 18px; padding: 11px 11px 10px; }
  .release-wave { height: 18px; margin: 11px 0 9px; }
  .release-art { width: 32px; height: 32px; border-radius: 10px; }
  .release-art svg { width: 16px; height: 16px; }
  .release-top { gap: 9px; }
  .release-meta b { font-size: 11.5px; }
}

@media (max-width: 600px) {
  .wrap { padding: 0 20px; }
  /* --header-height deliberately NOT reduced here.
     It used to drop to 70px below 600px, which shortened --header-band and
     moved the drawer's top edge with it: the panel began at 71px on a phone
     and 85px on an iPad, so the whole sidebar — and everything in it — sat
     14px higher on one than the other. That is the "one is taller, another
     shorter" difference. One height at every width means one drawer at every
     width, which is worth more than 14px of reclaimed phone chrome. */
  .feature { padding: 36px 26px; }
  .price-card { padding: 34px 24px; }
  /* .btn is nowrap by design, which a long label turns into an element wider
     than a 320px phone. Large buttons are always the standalone call to
     action here, so on a phone they take the full width and are allowed to
     run onto a second line. */
  .btn-lg {
    width: 100%;
    white-space: normal;
    text-align: center;
    padding-inline: 18px;
  }
  .footer-top { grid-template-columns: 1fr; gap: 40px; }
  .legal-hero { padding: 66px 0 34px; }
  .prose-section { padding: 56px 0 76px; }
  .prose h2 { font-size: 18.5px; margin-top: 34px; padding-top: 22px; }
  .legal-foot { padding: 20px; }
  .step { grid-template-columns: 1fr; gap: 6px; }
  .step-num { font-size: 34px; }
  .faq-list summary { padding: 17px 18px; font-size: 15px; }
  .faq-list p { padding: 0 18px 18px; }
  .plan { padding: 38px 24px 34px; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
  .footer-bottom a { margin-left: 0; margin-right: 18px; }
  /* Sets the variable, not `gap` directly: the keyframe derives its travel
     distance from this, so changing the raw gap here would put the loop half
     a gap out again on phones only. */
  .marquee { --marquee-gap: 12px; }
  .tile { width: 56px; height: 56px; }
  .tile .picon { width: 24px; height: 24px; }
  .stores-grid { grid-template-columns: repeat(2, 1fr); }
  .stores-tally { gap: 28px; }
  .hero-stats { gap: 28px; }
  .stat b { font-size: 24px; }
  .phone { width: 200px; }
  .sell-badge { width: 48px; height: 48px; border-radius: 14px; }
  .sell-badge img { width: 21px; height: 21px; }

  /* The popup stops trying to float over a 360px-wide map and becomes a card
     underneath it, where there is room to read it. */
  .pop, .pop.below {
    position: static; width: 100%; transform: none;
    margin-top: 20px; opacity: 1; visibility: visible; display: none;
  }
  .pop.show { display: block; }
  .pop::after { display: none; }
}
/* ==========================================
   FOOTER SOCIAL ICONS
   ========================================== */

.socials {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 22px;
}

.socials a {
  width: 42px;
  height: 42px;

  display: flex;
  align-items: center;
  justify-content: center;

  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 50%;

  color: #fff;
  text-decoration: none;

  background: rgba(255, 255, 255, 0.06);

  transition:
    transform 0.3s ease,
    background 0.3s ease,
    border-color 0.3s ease,
    box-shadow 0.3s ease;
}

.socials a svg {
  width: 19px;
  height: 19px;
  display: block;
}

.socials a:hover {
  transform: translateY(-4px) scale(1.08);

  background: rgba(255, 255, 255, 0.13);
  border-color: rgba(255, 255, 255, 0.4);

  box-shadow:
    0 8px 24px rgba(0, 0, 0, 0.22),
    0 0 20px rgba(255, 255, 255, 0.06);
}

.socials a:active {
  transform: translateY(-1px) scale(0.96);
}