/* ============================================================================
   Traven Luc: site layer.
   The scroll engine (scrollcraft.css) is the floor. This file themes it with
   brand tokens and draws the page's own shapes. Never restyle the engine's
   devices; style the markup here instead.
   ========================================================================== */

:root {
  /* --- the six brand roles ------------------------------------------------- */
  --sc-canvas:      #0A0305;   /* near-black, warm crimson ground        */
  --sc-surface:     #180A0E;   /* raised panels                          */
  --sc-ink:         #F6EDE9;   /* warm bone                              */
  --sc-ink-soft:    #BE9AA0;   /* rose-tinted secondary text             */
  --sc-accent:      #FFC5BC;   /* pale rose, the one accent              */
  --sc-accent-ink:  #2B0008;   /* text that sits on the accent           */

  /* --- type: two loaded families, mono reserved for labels --------------- */
  --sc-font-display: "Archivo", "Archivo Black", system-ui, sans-serif;
  --sc-font-text:    "Instrument Sans", system-ui, sans-serif;
  --sc-font-mono:    "JetBrains Mono", ui-monospace, monospace;

  /* --- brand extras ------------------------------------------------------- */
  --brand-crimson: #9D0034;
  --brand-deep:    #610017;
  --brand-shade:   #3A0012;
  --shadow:        220 60% 2%;

  --sc-maxw: 84rem;
}

::selection { background: var(--sc-accent); color: var(--sc-accent-ink); }

/* The ground carries a fixed crimson atmosphere so the dark never reads flat. */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(120% 85% at 15% 0%, color-mix(in oklab, var(--brand-crimson) 34%, transparent) 0%, transparent 55%),
    radial-gradient(90% 70% at 100% 100%, color-mix(in oklab, var(--brand-deep) 52%, transparent) 0%, transparent 60%);
}

/* One light for the page, not one per section. The engine's spotlight paints
   inside a single section's box, so it is cut off dead at the boundary and that
   straight cut reads as a seam between two sections. This layer is fixed to the
   viewport instead, so the same light crosses every boundary whole. It sits
   under main in the stacking order, so no text loses contrast to it. Fine
   pointers only, so a touch device paints nothing at all. */
@media (hover: hover) and (pointer: fine) {
  body::after {
    content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
    background: radial-gradient(32rem 30rem at calc(var(--mx, 0.5) * 100%) calc(var(--my, 0.5) * 100%),
      color-mix(in oklab, var(--sc-accent) 22%, transparent) 0%,
      color-mix(in oklab, var(--sc-accent) 9%, transparent) 40%,
      transparent 70%);
  }
}

main, .site-nav, .site-foot, .player { position: relative; z-index: 1; }

/* ------------------------------------------------------------------- chrome */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 120;
  background: var(--sc-accent); color: var(--sc-accent-ink);
  padding: var(--sc-3) var(--sc-5); border-radius: var(--sc-r-sm); font-weight: 600;
}
/* the bar no longer hugs the top edge, so the skip link parks just under it
   rather than landing on top of the wordmark */
.skip:focus { left: var(--sc-4); top: calc(var(--sc-4) + 3.5rem); }

/* A floating pill, not a banner. It sits inside the viewport on all four sides,
   wears no border, and is mostly the page showing through: a light blur over a
   thin wash of the canvas at rest, firming to smoked glass once the page has
   moved. The bottom hairline is gone, so nothing slices the artwork. */
.site-nav {
  position: fixed; inset: var(--sc-4) 0 auto; z-index: 50;
  width: min(calc(100% - var(--sc-gutter) * 2), var(--sc-maxw));
  margin-inline: auto;
  display: flex; align-items: center; gap: var(--sc-5);
  padding: var(--sc-2) var(--sc-2) var(--sc-2) var(--sc-6);
  border-radius: var(--sc-r-pill);
  background: color-mix(in oklab, var(--sc-canvas) 28%, transparent);
  backdrop-filter: blur(12px) saturate(140%);
  transition: background 320ms var(--sc-ease-out), box-shadow 320ms var(--sc-ease-out);
}
.site-nav[data-solid="true"] {
  background: color-mix(in oklab, var(--sc-canvas) 68%, transparent);
  backdrop-filter: blur(20px) saturate(150%);
  box-shadow: 0 14px 34px -16px hsl(var(--shadow) / 0.62);
}
.site-nav__brand {
  font-family: var(--sc-font-display); font-weight: 800;
  font-size: var(--sc-t-sm); letter-spacing: var(--sc-track-wide);
  text-transform: uppercase; text-decoration: none; white-space: nowrap;
}
.site-nav__brand span { color: var(--sc-accent); }
.site-nav__links { display: flex; gap: var(--sc-5); margin-inline-start: auto; align-items: center; }
.site-nav__link {
  font-size: var(--sc-t-sm); text-decoration: none; color: var(--sc-ink);
  transition: color 160ms var(--sc-ease-out); white-space: nowrap;
}
.site-nav__link:hover, .site-nav__link[aria-current="page"] { color: var(--sc-accent); }
/* the bar rides over the artwork now, so the type carries its own shadow: bone
   on mid-purple is about 2.6:1 without one */
.site-nav__brand, .site-nav__link {
  text-shadow: 0 1px 8px color-mix(in oklab, var(--sc-canvas) 62%, transparent);
}

/* ------------------------------------------------------------------ language */
/* The switch is a native <details> disclosure riding in the same pill as the
   links. Its summary wears only the globe and the locale's two-letter code, so
   eleven languages cost the bar about as much width as one word; the list drops
   below it on the canvas, which keeps the resting bar as narrow as it was. */
.lang { position: relative; }
.lang__btn {
  display: inline-flex; align-items: center; gap: var(--sc-2);
  min-height: 36px; padding: var(--sc-2) var(--sc-3);
  border-radius: var(--sc-r-pill); cursor: pointer; list-style: none;
  font-family: var(--sc-font-mono); font-size: var(--sc-t-xs);
  letter-spacing: var(--sc-track-wide); color: var(--sc-ink);
  transition: color 160ms var(--sc-ease-out);
}
.lang__btn::-webkit-details-marker { display: none; }
.lang__btn:hover, .lang[open] .lang__btn { color: var(--sc-accent); }
.lang__btn svg { opacity: .75; }
.lang__code { line-height: 1; }
.lang__menu {
  position: absolute; inset-block-start: calc(100% + var(--sc-3)); inset-inline-end: 0;
  z-index: 1; min-width: 13rem; max-height: min(70vh, 26rem); overflow-y: auto;
  padding: var(--sc-3);
  border: 1px solid var(--sc-hairline-strong); border-radius: var(--sc-r-md);
  background: color-mix(in oklab, var(--sc-surface) 94%, var(--sc-canvas));
  backdrop-filter: blur(20px) saturate(150%);
  box-shadow: 0 22px 46px -24px hsl(var(--shadow) / .85);
}
.lang__title {
  margin: 0 0 var(--sc-2); padding-inline: var(--sc-2);
  font-family: var(--sc-font-mono); font-size: var(--sc-t-xs);
  letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink-soft);
}
.lang__list { display: grid; gap: 2px; list-style: none; margin: 0; padding: 0; }
.lang__item {
  display: block; padding: var(--sc-2) var(--sc-3);
  border-radius: var(--sc-r-sm); text-decoration: none; white-space: nowrap;
  font-size: var(--sc-t-sm); color: var(--sc-ink);
  transition: background 160ms var(--sc-ease-out), color 160ms var(--sc-ease-out);
}
.lang__item:hover { background: color-mix(in oklab, var(--sc-accent) 14%, transparent); color: var(--sc-accent); }
.lang__item.is-current {
  background: color-mix(in oklab, var(--sc-accent) 11%, transparent);
  color: var(--sc-accent); font-weight: 600;
}

/* ------------------------------------------------------------- melody rail */
/* A comb of tines riding the page edge: one tine per section marked data-note,
   positioned at the scroll point where its section crosses the read line
   (mid-viewport). Striking a tine glows it and drops a drifting note — visual
   only, by decision: sound on scroll would fight the preview player. The rail
   is also a mini-TOC (each tine is a button that jumps to its section), and it
   hides itself on pages with fewer than two sections. It sits at z-index 4,
   under the nav and the player, over nothing but page padding. */
.melody-rail {
  position: fixed; left: var(--sc-3); top: 15vh; height: 70vh; width: 190px;
  z-index: 4;
  /* The strip is wider than the comb so hover labels have room, which once
     made it an invisible 190px click-shield over the content column on narrow
     windows. The container therefore never intercepts anything: clicks pass
     through the strip, and only the keys themselves are re-armed below. */
  pointer-events: none;
}
.melody-rail[hidden] { display: none; }
.melody-rail .rail-line {
  position: absolute; left: 3px; top: 0; bottom: 0; width: 2px; border-radius: 2px;
  background: linear-gradient(rgba(246,237,233,.04), rgba(246,237,233,.16), rgba(246,237,233,.04));
}
/* each tine is a real button; the visual bar rides its ::after, so the hit
   area stays comfortable even though the bar itself is 3px tall */
.melody-rail .tine {
  position: absolute; left: 0; width: 26px; height: 22px; margin-top: -11px;
  background: none; border: 0; padding: 0; cursor: pointer;
  pointer-events: auto;
}
.melody-rail .tine::after {
  content: ""; position: absolute; left: 3px; top: 50%; margin-top: -1.5px;
  width: 18px; height: 3px; border-radius: 2px;
  background: rgba(246,237,233,.14); transform-origin: left center;
  transition: background 260ms var(--sc-ease-out), transform 260ms var(--sc-ease-out), box-shadow 260ms var(--sc-ease-out);
}
.melody-rail .tine:hover::after { background: rgba(255,197,188,.55); }
.melody-rail .tine:focus-visible {
  outline: 1px solid rgba(255,197,188,.55); outline-offset: 2px; border-radius: 4px;
}
.melody-rail .tine.is-passed::after { background: rgba(255,197,188,.34); }
.melody-rail .tine.is-current::after {
  background: var(--sc-accent); transform: scaleX(1.5);
  box-shadow: 0 0 10px rgba(255,197,188,.55);
}
.melody-rail .tine.is-pluck::after { animation: melody-pluck 480ms cubic-bezier(.2,.9,.3,1.35); }
@keyframes melody-pluck {
  0% { transform: scaleX(1.5); }
  30% { transform: scaleX(2.6) translateY(-2px); }
  55% { transform: scaleX(1.15) translateY(1px); }
  100% { transform: scaleX(1.5); }
}
.melody-rail .note {
  position: absolute; left: 30px; font: 400 13px/1 var(--sc-font-mono);
  color: var(--sc-accent); opacity: 0; pointer-events: none;
  animation: melody-note .9s var(--sc-ease-out) forwards;
}
@keyframes melody-note {
  0% { opacity: 0; transform: translate(2px,4px) rotate(-8deg); }
  18% { opacity: 1; }
  100% { opacity: 0; transform: translate(12px,-26px) rotate(10deg); }
}
@media (prefers-reduced-motion: reduce) {
  .melody-rail .tine.is-pluck::after { animation: none; }
  .melody-rail .note { display: none; }
  .melody-rail .tine::after { transition: none; }
}

/* ----------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; gap: var(--sc-2);
  min-height: 44px; padding: var(--sc-3) var(--sc-5);
  border: 1px solid transparent; border-radius: var(--sc-r-pill);
  font-size: var(--sc-t-sm); font-weight: 600; text-decoration: none;
  white-space: nowrap;
  cursor: pointer; transition: transform 140ms var(--sc-ease-out), background 180ms var(--sc-ease-out), border-color 180ms var(--sc-ease-out);
}
.btn:active { transform: translateY(1px) scale(0.99); }
.btn--solid { background: var(--sc-accent); color: var(--sc-accent-ink); }
.btn--solid:hover { background: color-mix(in oklab, var(--sc-accent) 86%, white); }
.btn--ghost { border-color: var(--sc-hairline-strong); color: var(--sc-ink); }
.btn--ghost:hover { border-color: var(--sc-accent); color: var(--sc-accent); }
.btn--sm { min-height: 36px; padding: var(--sc-2) var(--sc-4); font-size: var(--sc-t-xs); }
/* the one action in the floating bar: a bone pill with dark text, so the accent
   stays scarce and the hero's accent pill keeps its weight */
.btn--lite { background: var(--sc-ink); color: var(--sc-canvas); }
.btn--lite:hover { background: var(--sc-accent); color: var(--sc-accent-ink); }
/* the nav CTA's Spotify glyph stays hidden until the narrow layout calls for
   the icon-only form (see the 620px query below) */
.btn__icon { display: none; }

/* ------------------------------------------------------------------- hero */
.hero__bed, .hero__veil {
  position: absolute; inset: 0; z-index: 0; overflow: hidden;
  will-change: transform;
}
/* The engine's parallax writes translate3d(0, rate * (p - 0.5) * 100px, 0), so
   the travel is centred on the middle of the act: at the top of the page a
   negative rate has already pushed the bed down by half its own travel and the
   frame's own near-black ground shows above it. A parallax layer therefore has
   to carry slack equal to half its travel, or it bares the page behind it. The
   rate is -0.4, so the travel is 20px either way; 22px covers it with a margin.
   Kept deliberately small so the image barely has to overscale to pay for it. */
.hero__bed { inset: -22px 0; }
/* The veil drifts the other way, and at the top of the page it too is riding
   17.5px off its frame, which would bare an un-veiled strip of the artwork
   along the bottom edge. Same contract, same slack, with a little margin so a
   subpixel round can never open a hairline at either end. */
.hero__veil { inset: -20px 0; }
/* The hero is one flat raster, and the cat's lenses are opaque, so nothing can
   literally look at the cursor. What can move is the plane. Three layers drift
   at three rates off one pointer, and the separation is what reads as depth:
   the bed follows the cursor a little, the code-cut stars answer it and travel
   the other way, the bloom barely moves at all. Both new layers sit under the
   veil, so text contrast is exactly as it was before.
   The drift lives inside a fine-pointer query, so a touch device never pays for
   a composited layer or an overscale it cannot use. */
.hero__depth { position: absolute; inset: 0; }
.hero__img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 46% 50%; }
.hero__sparks { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
/* a star that only drifts reads as a sticker, so each one pulses on its own
   offset and the field never breathes in unison */
.hero__spark { position: absolute; fill: var(--sc-ink); opacity: .5; animation: hero-twinkle 4.6s ease-in-out infinite; }
@keyframes hero-twinkle {
  0%, 100% { opacity: .14; transform: scale(.8); }
  45%      { opacity: .8;  transform: scale(1); }
}
.hero__glow {
  position: absolute; inset: -8%; z-index: 1; pointer-events: none;
  background: radial-gradient(40% 46% at calc(56% + var(--px, 0) * 4%) calc(44% + var(--py, 0) * 4%),
    color-mix(in oklab, var(--sc-accent) 18%, transparent) 0%, transparent 72%);
  animation: hero-breathe 7.5s ease-in-out infinite;
  will-change: opacity;
}
@keyframes hero-breathe { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
@media (hover: hover) and (pointer: fine) {
  /* the nearer plane answers a little quicker than the farther one, which is how
     depth actually behaves and reads as depth here too */
  .hero__depth {
    will-change: transform;
    transform: translate3d(calc(var(--px, 0) * 11px), calc(var(--py, 0) * 8px), 0);
    transition: transform 440ms cubic-bezier(0.4, 0, 0.2, 1);
  }
  .hero__sparks {
    will-change: transform;
    transform: translate3d(calc(var(--px, 0) * -18px), calc(var(--py, 0) * -13px), 0);
    transition: transform 320ms cubic-bezier(0.4, 0, 0.2, 1);
  }
  /* a 6% overscale is what pays for the drift: without it the plane would peel
     away from the viewport edge every time the cursor reached the far side */
  .hero__img { transform: scale(1.06); }
}
.hero__veil {
  z-index: 2;
  background:
    linear-gradient(to top, var(--sc-canvas) 3%, color-mix(in oklab, var(--brand-deep) 82%, transparent) 36%, transparent 74%),
    linear-gradient(to right, color-mix(in oklab, var(--sc-canvas) 95%, transparent) 0%, color-mix(in oklab, var(--sc-canvas) 72%, transparent) 36%, transparent 68%);
}
.hero__copy { max-width: min(40rem, 60vw); }
.hero__title { font-size: var(--sc-t-4xl); font-weight: 800; text-transform: none; }
.hero__title-sub {
  display: block; margin-top: var(--sc-3);
  font-size: var(--sc-t-lg); font-weight: 600;
  letter-spacing: var(--sc-track-snug); color: var(--sc-accent);
}
.hero__lede { margin-top: var(--sc-4); }
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--sc-3); margin-top: var(--sc-5); }
.hero__meta {
  margin-top: var(--sc-5); padding-top: var(--sc-3);
  border-top: 1px solid var(--sc-hairline);
  font-family: var(--sc-font-mono); font-size: var(--sc-t-xs);
  letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink-soft);
}

/* ------------------------------------------------------------------- rails */
.rail { gap: var(--sc-5); align-items: center; height: 100%; padding-inline: var(--sc-gutter); }
.rail__item { width: clamp(15rem, 24vw, 21rem); flex: 0 0 auto; }
.rail__cover {
  position: relative; border-radius: var(--sc-r-md); overflow: hidden;
  box-shadow: var(--sc-e2); background: var(--sc-surface);
}
.rail__cover img { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; transition: transform 420ms var(--sc-ease-out); }
.rail__cover a:focus-visible { outline-offset: -3px; }
.rail__item:hover .rail__cover img { transform: scale(1.04); }
.rail__badge {
  position: absolute; inset-block-start: var(--sc-3); inset-inline-start: var(--sc-3);
  font-family: var(--sc-font-mono); font-size: 0.66rem; letter-spacing: var(--sc-track-wide);
  text-transform: uppercase; padding: 2px var(--sc-2); border-radius: var(--sc-r-sm);
  background: color-mix(in oklab, var(--sc-canvas) 78%, transparent); color: var(--sc-accent);
}
.rail__cover a { display: block; }
.rail__title { margin-top: var(--sc-3); font-weight: 600; font-size: var(--sc-t-base); letter-spacing: var(--sc-track-snug); }
.rail__title a { color: var(--sc-ink); text-decoration: none; }
.rail__title a:hover { color: var(--sc-accent); }
.rail__meta { font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); color: var(--sc-ink-soft); letter-spacing: var(--sc-track-wide); text-transform: uppercase; }
.rail__lead { width: clamp(16rem, 30vw, 26rem); flex: 0 0 auto; align-self: center; }
.rail__lead h2 { font-size: var(--sc-t-2xl); }
.rail__lead p { margin-top: var(--sc-4); }

/* ------------------------------------------------------------------ numbers */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--sc-6); }
.stat__num {
  display: block; font-family: var(--sc-font-display); font-weight: 800;
  font-size: var(--sc-t-3xl); line-height: var(--sc-leading-none); color: var(--sc-ink);
}
.stat__label { display: block; margin-top: var(--sc-2); font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink-soft); }
.stat--accent .stat__num { color: var(--sc-accent); }

/* --------------------------------------------------------------- track rows */
.tracks { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--sc-hairline); }
.track {
  display: grid; grid-template-columns: auto 1fr auto auto; gap: var(--sc-4);
  align-items: center; padding: var(--sc-4) 0; border-bottom: 1px solid var(--sc-hairline);
}
.track__play {
  width: 44px; height: 44px; border-radius: var(--sc-r-pill);
  display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--sc-hairline-strong); background: transparent; color: var(--sc-ink);
  transition: background 180ms var(--sc-ease-out), border-color 180ms var(--sc-ease-out), transform 140ms var(--sc-ease-out);
}
.track__play:hover { border-color: var(--sc-accent); color: var(--sc-accent); }
.track__play:active { transform: scale(0.96); }
.track__play[data-state="playing"] { background: var(--sc-accent); border-color: var(--sc-accent); color: var(--sc-accent-ink); }
.track__play svg { width: 16px; height: 16px; }
.track__play[disabled] { opacity: 0.35; cursor: not-allowed; }
.track__name { font-weight: 600; letter-spacing: var(--sc-track-snug); }
.track__from { display: block; font-size: var(--sc-t-xs); color: var(--sc-ink-soft); font-family: var(--sc-font-mono); letter-spacing: var(--sc-track-wide); text-transform: uppercase; }
.track__dur { font-family: var(--sc-font-mono); font-size: var(--sc-t-sm); color: var(--sc-ink-soft); font-variant-numeric: tabular-nums; }
.track__tag { font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); color: var(--sc-accent); letter-spacing: var(--sc-track-wide); text-transform: uppercase; }

.tag {
  font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide);
  text-transform: uppercase; color: var(--sc-ink-soft);
  border: 1px solid var(--sc-hairline); border-radius: var(--sc-r-pill); padding: 3px var(--sc-3);
}

/* ----------------------------------------------------------- catalogue index */
.cat-index { columns: 3; column-gap: var(--sc-7); column-rule: 1px solid var(--sc-hairline); }
.cat-col { break-inside: avoid; }
.cat-index h3 { break-after: avoid; margin: 0 0 var(--sc-4); font-size: var(--sc-t-lg); }
.cat-index h3 a { color: var(--sc-ink); text-decoration: none; }
.cat-index h3 a:hover { color: var(--sc-accent); }
.cat-index ul { list-style: none; margin: 0 0 var(--sc-7); padding: 0; break-inside: avoid; }
.cat-index li { margin-bottom: var(--sc-2); break-inside: avoid; font-size: var(--sc-t-sm); }
.cat-index a { color: var(--sc-ink-soft); text-decoration: none; }
.cat-index a:hover { color: var(--sc-accent); text-decoration: underline; }
.cat-index time { font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); color: color-mix(in oklab, var(--sc-ink-soft) 60%, transparent); }

/* ------------------------------------------------------------------- faq */
.faq { display: grid; gap: var(--sc-6); }
.faq__q { font-size: var(--sc-t-lg); font-weight: 600; letter-spacing: var(--sc-track-snug); margin: 0; }
.faq__body { max-width: var(--sc-measure); color: var(--sc-ink-soft); text-wrap: pretty; }
.faq__a { margin-top: var(--sc-3); }
.faq__item { padding-bottom: var(--sc-6); border-bottom: 1px solid var(--sc-hairline); }

/* ------------------------------------------------------------------- close */
.close { text-align: left; }
.close__title { font-size: var(--sc-t-3xl); font-weight: 800; }
.close__cta { display: flex; flex-wrap: wrap; gap: var(--sc-3); margin-top: var(--sc-6); }
.close__links { margin-top: var(--sc-6); display: flex; flex-wrap: wrap; gap: var(--sc-3) var(--sc-6); }
.close__social { margin-top: var(--sc-5); display: flex; flex-wrap: wrap; gap: var(--sc-3); }
.sc-nav-link { color: var(--sc-ink-soft); font-size: var(--sc-t-sm); }
.sc-nav-link:hover { color: var(--sc-accent); }

/* --------------------------------------------------------------- facts list */
.facts {
  margin: var(--sc-6) 0 0; display: grid; gap: var(--sc-4);
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
.facts > div { padding-top: var(--sc-3); border-top: 1px solid var(--sc-hairline); }
.facts dt {
  font-family: var(--sc-font-mono); font-size: var(--sc-t-xs);
  letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink-soft);
}
.facts dd { margin: var(--sc-2) 0 0; color: var(--sc-ink); letter-spacing: var(--sc-track-snug); text-wrap: pretty; }
.facts__link { color: var(--sc-accent); text-decoration: none; }
.facts__link:hover { text-decoration: underline; }
.facts__link + .facts__link::before { content: ', '; color: var(--sc-ink-soft); }

/* ------------------------------------------------------------------ footer */
.site-foot {
  border-top: 1px solid var(--sc-hairline); padding: var(--sc-7) var(--sc-gutter) var(--sc-10);
  color: var(--sc-ink-soft); font-size: var(--sc-t-sm);
}
.site-foot__grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: var(--sc-6); max-width: var(--sc-maxw); margin-inline: auto; }
.site-foot h4 { margin: 0 0 var(--sc-3); font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink); }
.site-foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sc-2); }
.site-foot a { text-decoration: none; }
.site-foot a:hover { color: var(--sc-accent); }
.site-foot__note { max-width: var(--sc-maxw); margin: var(--sc-7) auto 0; padding-top: var(--sc-5); border-top: 1px solid var(--sc-hairline); font-size: var(--sc-t-xs); }

/* ------------------------------------------------------------ discography */
.disc-head { padding-block: clamp(7rem, 16vh, 11rem) var(--sc-7); }
.crumbs {
  display: flex; flex-wrap: wrap; gap: var(--sc-2); align-items: center;
  font-family: var(--sc-font-mono); font-size: var(--sc-t-xs);
  letter-spacing: var(--sc-track-wide); text-transform: uppercase;
  color: var(--sc-ink-soft); margin-bottom: var(--sc-5);
}
.crumbs a { color: var(--sc-ink-soft); text-decoration: none; }
.crumbs a:hover { color: var(--sc-accent); }
.crumbs [aria-current="page"] { color: var(--sc-ink); }
.disc-jump { display: flex; flex-wrap: wrap; gap: var(--sc-3); margin-top: var(--sc-5); }
.disc-group { padding-block: var(--sc-7) var(--sc-6); border-top: 1px solid var(--sc-hairline); }
.disc-group__head { display: flex; align-items: baseline; gap: var(--sc-4); flex-wrap: wrap; margin-bottom: var(--sc-6); }
.disc-group__count { font-family: var(--sc-font-mono); font-size: var(--sc-t-sm); color: var(--sc-accent); }
/* The hub is a record bin, not a card wall: covers carry the grid and each cell
   is separated by a hairline, so nothing is boxed and nothing nests. */
.cards { display: grid; gap: var(--sc-7) var(--sc-5); grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); }
.card { min-width: 0; padding-top: var(--sc-4); border-top: 1px solid var(--sc-hairline); }
.card__cover { display: block; border-radius: var(--sc-r-md); overflow: hidden; background: var(--sc-surface); box-shadow: var(--sc-e1); }
.card__img { display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; transition: transform 420ms var(--sc-ease-out); }
@media (hover: hover) and (pointer: fine) { .card:hover .card__img { transform: scale(1.04); } }
.card__title { margin: var(--sc-3) 0 0; font-size: var(--sc-t-base); font-weight: 600; letter-spacing: var(--sc-track-snug); }
.card__title a { color: var(--sc-ink); text-decoration: none; }
.card__title a:hover { color: var(--sc-accent); }
.card__meta { margin: var(--sc-2) 0 0; font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink-soft); }
.card__tracks { margin: var(--sc-3) 0 0; font-size: var(--sc-t-sm); line-height: 1.55; color: color-mix(in oklab, var(--sc-ink-soft) 90%, transparent); }
.card__more { margin: var(--sc-3) 0 0; font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide); }
.card__more a { color: var(--sc-accent); text-decoration: none; }
.card__more a:hover { text-decoration: underline; }

/* ------------------------------------------------------------ release page */
.release { display: grid; grid-template-columns: clamp(12rem, 26vw, 19rem) minmax(0, 1fr); gap: var(--sc-7) var(--sc-8); align-items: start; }
.release__cover { border-radius: var(--sc-r-lg); overflow: hidden; box-shadow: var(--sc-e2); }
.release__img { display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; }
.release__title { margin: 0; }
.release__meta { margin: var(--sc-3) 0 0; font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink-soft); }
.release__lede { margin-top: var(--sc-4); }
.release-tracks { padding-block: var(--sc-7) var(--sc-8); border-top: 1px solid var(--sc-hairline); }
.release-tracks h2 { margin-bottom: var(--sc-5); }
.release__note { margin-top: var(--sc-6); max-width: var(--sc-measure); font-size: var(--sc-t-xs); line-height: 1.65; color: var(--sc-ink-soft); }
.release-nav { padding-block: var(--sc-6) var(--sc-9); border-top: 1px solid var(--sc-hairline); }
.release-nav__grid { display: grid; gap: var(--sc-5) var(--sc-7); grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
.release-nav__link { display: grid; gap: var(--sc-2); text-decoration: none; }
.release-nav__dir { font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: var(--sc-track-wide); text-transform: uppercase; color: var(--sc-ink-soft); }
.release-nav__name { font-weight: 600; letter-spacing: var(--sc-track-snug); color: var(--sc-ink); transition: color 140ms var(--sc-ease-out); }
.release-nav__link:hover .release-nav__name { color: var(--sc-accent); }

/* track rows: shared by the home list and every release page */
.rel__links { display: flex; flex-wrap: wrap; gap: var(--sc-2); margin-top: var(--sc-4); }
.rel__tracks { list-style: none; margin: var(--sc-5) 0 0; padding: 0; border-top: 1px solid var(--sc-hairline); }
.rel__track { display: grid; grid-template-columns: 2.9rem minmax(0, 1fr) auto; gap: var(--sc-4); align-items: center; padding: var(--sc-3) 0; border-bottom: 1px solid var(--sc-hairline); }
.rel__no { font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); color: var(--sc-ink-soft); font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- now playing */
.player {
  position: fixed; inset: auto 0 0 0; z-index: 70;
  display: grid; grid-template-columns: auto minmax(0, 1fr) minmax(0, 12rem) auto;
  gap: var(--sc-4); align-items: center;
  padding: var(--sc-3) var(--sc-gutter);
  background: color-mix(in oklab, var(--sc-surface) 92%, transparent);
  backdrop-filter: blur(18px) saturate(140%);
  border-top: 1px solid var(--sc-hairline-strong);
  box-shadow: 0 -18px 40px -24px hsl(var(--shadow) / 0.6);
  transform: translate3d(0, 105%, 0);
  transition: transform 420ms var(--sc-ease-out);
}
.player[data-open="true"] { transform: none; }
/* the trailing controls travel as one group, so dropping the comb on a narrow
   screen leaves no empty grid track behind it */
.player__actions { display: flex; align-items: center; gap: var(--sc-4); }
/* the second way out of the player: the preview is the audition, this is the
   door into the full song on the store the listener already uses */
.player__shop {
  display: inline-flex; align-items: center; gap: var(--sc-2);
  height: 40px; padding-inline: var(--sc-4);
  border: 1px solid var(--sc-hairline); border-radius: var(--sc-r-pill);
  color: var(--sc-ink); font-size: var(--sc-t-xs); font-weight: 600;
  text-decoration: none; white-space: nowrap;
  transition: color 160ms var(--sc-ease-out), border-color 160ms var(--sc-ease-out), background 160ms var(--sc-ease-out);
}
/* the element is hidden until a song is playing, and the display above would
   otherwise beat the browser's own [hidden] rule */
.player__shop[hidden] { display: none; }
.player__shop:hover { color: var(--sc-accent); border-color: var(--sc-hairline-strong); }
.player__cover { width: 48px; height: 48px; border-radius: var(--sc-r-sm); overflow: hidden; box-shadow: var(--sc-e1); }
.player__cover img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 1; }
.player__cover img { transition: transform 600ms var(--sc-ease-out); }
body[data-playing="true"] .player__cover img { transform: scale(1.08); }
.player__text { min-width: 0; }
.player__title { font-weight: 600; font-size: var(--sc-t-sm); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.player__sub { font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); color: var(--sc-ink-soft); text-transform: uppercase; letter-spacing: var(--sc-track-wide); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.player__viz { width: 100%; height: 40px; }
.player__time { font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); color: var(--sc-ink-soft); font-variant-numeric: tabular-nums; }
.player__close {
  width: 40px; height: 40px; border-radius: var(--sc-r-pill); display: grid; place-items: center;
  background: transparent; border: 1px solid var(--sc-hairline); color: var(--sc-ink-soft); cursor: pointer;
}
.player__close:hover { color: var(--sc-ink); border-color: var(--sc-hairline-strong); }
.player__bar { position: absolute; inset: 0 0 auto 0; height: 2px; background: var(--sc-accent); transform-origin: 0 50%; transform: scaleX(0); }

/* the flying artwork: a fixed ghost img sized to the player's slot, whose
   transform starts at the key that struck it and eases to identity. The real
   slot sits hidden underneath until the clone lands (site.js drives
   visibility), so there is never a double sleeve. Sits above the player. */
.cover-clone {
  position: fixed; z-index: 80; margin: 0;
  object-fit: cover; aspect-ratio: 1; border-radius: var(--sc-r-sm);
  box-shadow: var(--sc-e1); transform-origin: top left;
  transition: transform 480ms var(--sc-ease-out);
  will-change: transform; pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .cover-clone { display: none; }
}

/* ------------------------------------------------------------ back to top */
.totop {
  position: fixed; z-index: 60; right: var(--sc-gutter);
  bottom: calc(var(--sc-gutter) + env(safe-area-inset-bottom, 0px));
  width: 44px; height: 44px; display: grid; place-items: center;
  border-radius: var(--sc-r-pill); border: 1px solid var(--sc-hairline-strong);
  background: color-mix(in oklab, var(--sc-surface) 88%, transparent);
  backdrop-filter: blur(14px) saturate(140%);
  color: var(--sc-ink); cursor: pointer;
  opacity: 0; visibility: hidden; transform: translate3d(0, 10px, 0);
  transition: opacity 300ms var(--sc-ease-out), transform 300ms var(--sc-ease-out), visibility 300ms;
}
.totop[data-shown] { opacity: 1; visibility: visible; transform: none; }
.totop:hover { color: var(--sc-accent); border-color: var(--sc-accent); }
/* lift clear of the preview player once it is open, above the bar either way */
body:has(.player[data-open="true"]) .totop { bottom: calc(var(--sc-gutter) + 5.5rem + env(safe-area-inset-bottom, 0px)); }

/* ------------------------------------------------------------------ helpers */
.section--pad-first { padding-block-start: clamp(2rem, 5vh, 4rem); }
.center { text-align: center; }
.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; }

/* ------------------------------------------------------------------ mobile */
@media (max-width: 900px) {
  .hero__img { object-position: 64% 44%; }
  .hero__copy { max-width: none; }
  /* the copy spans the full width down here, so the bed needs a deeper veil:
     measured 3.9:1 against the raw artwork before this, 4.5:1 is the floor */
  .hero__veil {
    background:
      linear-gradient(to top, var(--sc-canvas) 14%, color-mix(in oklab, var(--brand-deep) 88%, transparent) 54%, color-mix(in oklab, var(--sc-canvas) 34%, transparent) 100%),
      linear-gradient(to right, color-mix(in oklab, var(--sc-canvas) 88%, transparent) 0%, transparent 74%);
  }
  .cat-index { columns: 1; column-rule: 0; }
  .site-foot__grid { grid-template-columns: 1fr; gap: var(--sc-6); }
  .cards { grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr)); gap: var(--sc-6) var(--sc-4); }
  .release { grid-template-columns: 1fr; gap: var(--sc-6); }
  .release__cover { max-width: 15rem; }
  .player { grid-template-columns: auto minmax(0, 1fr) auto; }
  .player__viz { display: none; }
  .track { grid-template-columns: auto 1fr auto; }
  .track__tag { display: none; }
  .site-nav__links { gap: var(--sc-4); }
  .site-nav__links .site-nav__link--optional { display: none; }
}
@media (max-width: 620px) {
  .hero__title { font-size: var(--sc-t-2xl); }
  /* brand + Discography + the one action is all that fits; the rest of the
     navigation is repeated in the footer */
  .site-nav__links { gap: var(--sc-3); }
  .site-nav__links .site-nav__link:not(.site-nav__link--keep) { display: none; }
  .site-nav { padding-inline-start: var(--sc-4); }
  .site-nav__brand { font-size: var(--sc-t-sm); }
  .site-nav .btn { min-height: 32px; padding: var(--sc-1) var(--sc-3); font-size: var(--sc-t-xs); }
  /* the language switch keeps the globe and drops the code, so the row still
     fits the brand, Discography and the one action */
  .lang__code { display: none; }
  .lang__btn { padding-inline: var(--sc-2); }
  .lang__menu { min-width: 11rem; }
  /* the pill keeps its shape and drops its label: at this width the title and
     the transport have first claim on the row */
  .player__shop { padding-inline: var(--sc-3); }
  .player__shop-text { display: none; }
  /* the melody rail is a desktop affordance: on a phone the thumb does the
     navigation and a fixed strip only competes with the content edge */
  .melody-rail { display: none; }
  /* the nav CTA drops its label and wears only the Spotify glyph: one icon
     fits every locale, and the row keeps brand + Discography + action + globe */
  .site-nav .btn--lite { min-height: 32px; width: 32px; padding: 0; justify-content: center; }
  .site-nav .btn--lite .btn__icon { display: block; }
  .site-nav .btn--lite .btn__label { display: none; }
}

/* ------------------------------------------------------------------ routing */
/* The router replaces <main> and nothing else, so the shell, the player and the
   audio element carrying the preview all survive a page change. Two pieces of
   feedback belong to that move: a hairline that says a fetch is in flight, and
   a fade on the content itself. Both read an attribute the script only writes
   when it can route at all, so with scripting off neither ever takes effect and
   the page behaves exactly as it did before. */
.route-bar {
  position: fixed; inset: 0 0 auto; z-index: 60;
  height: 2px; pointer-events: none; opacity: 0;
  transform-origin: 0 50%; transform: scaleX(0);
  background: linear-gradient(90deg, var(--brand-crimson), var(--sc-accent));
  transition: opacity 200ms var(--sc-ease-out), transform 200ms var(--sc-ease-out);
}
html[data-route="load"] .route-bar { opacity: 1; transform: scaleX(0.85); }

/* The fade sits on the content box alone. Opacity leaves layout untouched, so
   every measurement the engine takes at mount is the same one it would have
   taken with the fade turned off. */
main { transition: opacity 200ms var(--sc-ease-out); }
html[data-route="out"] main { opacity: 0; }

/* --------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  .hero__bed { filter: brightness(0.72) saturate(104%); }
  /* the depth rig is motion, and only motion: with it off the hero is the same
     still frame it was before, so nothing about the layout depends on it */
  .hero__depth, .hero__sparks, .hero__glow, .hero__img { transform: none; transition: none; animation: none; }
  .hero__spark { opacity: .32; }
  .hero__glow { opacity: .6; }
  .player { transition-duration: 1ms; }
  .player__cover img { transition: none; }
  /* the ambient light is pointer motion and nothing else, so it goes entirely */
  body::after { display: none; }
  /* the router skips the fade under this flag, so the rule is here only to make
     sure a page change can never animate on a machine that asked for none */
  main, .route-bar { transition: none; }
}
