/**
 * Section 03 — Discography + player (§7) — THE HERO.
 *
 * Layout (desktop, ≥1024px):
 *   ┌─────────────────────────────────────────────┐
 *   │ cassette rack (spines, horizontal)            │  ← top row
 *   ├───────────────────────┬─────────────────────┤
 *   │ tracklist column      │  tape deck (sticky)   │  ← two columns
 *   └───────────────────────┴─────────────────────┘
 *
 * Phase 2 additions:
 *   1. Rack click → cassette flips spine→front IN PLACE and a description
 *      slides out to its right, pushing later cassettes further along.
 *   2. Every cassette is a 6-faced CSS cube (shared with the deck).
 *   3. The deck is sticky while the tracklist scrolls.
 *   4. The deck cassette auto-rotates on Y, is drag-to-inspect, and snaps
 *      back to the nearest face on release (controller in main.js).
 */

/* ══ Shared cube system ═══════════════════════════════════════════════════
   One cube, reused in the rack and the deck. Faces are placeholders now;
   each --front/--back/--spine face is a drop-in point for Illustrator art. */
.cube {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--cass-w);
  height: var(--cass-h);
  margin-left: calc(var(--cass-w) / -2);
  margin-top: calc(var(--cass-h) / -2);
  transform-style: preserve-3d;
  /* --cube-rot drives the resting/flipped orientation in the rack. */
  transform: rotateY(var(--cube-rot, 90deg));
}

.cube__face {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--accent-mid);
  backface-visibility: hidden;
  /* Faint texture so placeholder faces read as distinct planes. */
  box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.6);
}

/* Wide artwork faces (front / back). */
.cube__face--front,
.cube__face--back {
  width: var(--cass-w);
  height: var(--cass-h);
  font-size: var(--fs-micro);
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* PNG cover art layer. Fills the face; sits above the placeholder label.
   Removed by onerror when the file is missing (see cubeFacesHTML).
   pointer-events/user-drag/user-select off so dragging to rotate the deck
   cassette never grabs or ghost-drags the image. */
.cube__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 2;
  backface-visibility: hidden;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  -webkit-user-select: none;
}
.cube__face--front {
  transform: translate(-50%, -50%) rotateY(0deg)
    translateZ(calc(var(--cass-d) / 2));
}
.cube__face--back {
  transform: translate(-50%, -50%) rotateY(180deg)
    translateZ(calc(var(--cass-d) / 2));
  background: var(--shadow);
}

/* Thin spine faces (left / right) — title printed sideways. */
.cube__face--spine-l,
.cube__face--spine-r {
  width: var(--cass-d);
  height: var(--cass-h);
}
.cube__face--spine-r {
  transform: translate(-50%, -50%) rotateY(90deg)
    translateZ(calc(var(--cass-w) / 2));
}
.cube__face--spine-l {
  transform: translate(-50%, -50%) rotateY(-90deg)
    translateZ(calc(var(--cass-w) / 2));
}

/* Top / bottom caps. */
.cube__face--top,
.cube__face--bottom {
  width: var(--cass-w);
  height: var(--cass-d);
  background: var(--shadow);
}
.cube__face--top {
  transform: translate(-50%, -50%) rotateX(90deg)
    translateZ(calc(var(--cass-h) / 2));
}
.cube__face--bottom {
  transform: translate(-50%, -50%) rotateX(-90deg)
    translateZ(calc(var(--cass-h) / 2));
}

/* Sideways-printed spine title + type badge. */
.cube__spine-title {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-height: calc(var(--cass-h) - 26px);
}
.cube__spine-type {
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--accent);
}

.discography__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-lg);
}

/* ══ Top row: the rack ════════════════════════════════════════════════════ */
.rack {
  position: relative;
  border: 1px solid var(--hairline);
  background: linear-gradient(180deg, var(--shadow), var(--bg));
  padding: var(--space-md) var(--space-md) var(--space-sm);
}

/* Illustrator rack-background art drops in here (behind the cassettes). */
.rack__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}

.rack__shelf {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: flex-end;
  gap: 6px;
  overflow-x: auto;
  /* Headroom so a flipped front face isn't clipped at the top. */
  padding: 40px var(--space-sm) var(--space-sm);
  /* Cassettes stand on a shelf baseline. */
  border-bottom: 3px solid var(--accent-mid);
}

/* Cluster grouping — spacing + dashed divider, no labels (§7). */
.rack__cluster {
  display: flex;
  align-items: flex-end;
  gap: 6px;
}
.rack__cluster + .rack__cluster {
  margin-left: var(--space-md);
  padding-left: var(--space-md);
  border-left: 1px dashed var(--hairline);
}

/* A rack cassette = flippable cube scene + slide-out description, side by
   side. Growing either child reflows the shelf and pushes siblings right. */
.cassette {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: flex-end;
  flex: 0 0 auto;
  transition: margin var(--flip-dur) var(--ease);
}

/* Lift the hovered/active cassette above its neighbours so its 3D faces are
   never clipped by, or ambiguously touching, the next spine. */
.cassette:hover,
.cassette.is-active {
  z-index: 3;
}

.cassette__scene {
  position: relative;
  width: var(--cass-d); /* spine footprint; animates to --cass-w on flip */
  height: var(--cass-h);
  flex: 0 0 auto;
  perspective: 900px;
  padding: 0;
  background: none;
  border: none;
  transition: width var(--flip-dur) var(--ease), transform 0.28s var(--ease);
  cursor: pointer;
}

/* The rack cube rests showing a spine; flip animates to the front face.
   Not drag-rotatable in the rack (that's a deck-only interaction). */
.cassette .cube {
  transition: transform var(--flip-dur) var(--ease);
}

/* Hover affordance: a straight vertical lift — NOT a rotateY swing — so the
   wide face can never rotate out and overlap the neighbouring spine (fix 1). */
.cassette:not(.is-active) .cassette__scene:hover,
.cassette:not(.is-active) .cassette__scene:focus-visible {
  transform: translateY(-14px);
}
.cassette__scene:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 4px;
}

/* Active (selected) cassette: flip to front + reveal description, and hold a
   clear gap on BOTH sides so it never touches its neighbours as it opens
   (fix 2). Still clickable — clicking it again flips it back (fix 3). */
.cassette.is-active {
  margin: 0 var(--space-md);
}
.cassette.is-active .cassette__scene {
  width: var(--cass-w);
  transform: none;
}
.cassette.is-active .cube {
  --cube-rot: 0deg; /* front face to camera */
}
.cassette.is-active .cube__face--front {
  border-color: var(--accent);
  box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.6), 0 0 24px -8px var(--accent);
}

/* Slide-out description to the RIGHT of the cassette, inside the rack. */
.cassette__desc {
  align-self: stretch;
  width: 0;
  overflow: hidden;
  opacity: 0;
  white-space: nowrap;
  transition: width var(--flip-dur) var(--ease), opacity 0.4s var(--ease);
}
.cassette.is-active .cassette__desc {
  width: var(--desc-w);
  opacity: 1;
}

.cassette__desc-inner {
  width: var(--desc-w);
  height: 100%;
  margin-left: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  border-left: 1px solid var(--hairline);
  white-space: normal;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-xs);
}
.cassette__desc-title {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-h3);
  text-transform: uppercase;
  color: var(--text);
}
.cassette__desc-meta {
  font-size: var(--fs-micro);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}
.cassette__desc-body {
  font-size: var(--fs-small);
  line-height: 1.7;
  color: var(--text-dim);
}

/* ══ Two columns: tracklist + deck ════════════════════════════════════════ */
.console {
  display: grid;
  grid-template-columns: minmax(280px, 1fr) minmax(340px, 1.15fr);
  gap: var(--space-lg);
  align-items: start;
}

/* ── Tracklist column ─────────────────────────────────────────────────── */
.tracklist__head {
  border-bottom: 1px solid var(--hairline);
  padding-bottom: var(--space-sm);
  margin-bottom: var(--space-sm);
}
.tracklist__release {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-h3);
  text-transform: uppercase;
  color: var(--text);
}
.tracklist__count {
  font-size: var(--fs-small);
  color: var(--text-dim);
  letter-spacing: 0.1em;
}

/* No internal max-height cap: the column grows with its tracks so the page
   scrolls and the sticky deck (below) stays in view. */
.track {
  display: grid;
  grid-template-columns: 2rem 1fr auto;
  gap: var(--space-sm);
  align-items: center;
  padding: 0.6rem var(--space-sm) 0.6rem 0.75rem;
  border-left: 3px solid transparent;
  font-size: var(--fs-small);
  transition: background 0.2s var(--ease);
  cursor: pointer;
}
.track:hover {
  background: var(--surface);
}
/* Rows without a usable preview can't be played. */
.track[data-preview="none"] {
  cursor: not-allowed;
  color: var(--text-dim);
}
/* The current track's number takes the accent colour. */
.track[aria-current="true"] .track__n {
  color: var(--accent);
}
.track[aria-current="true"] {
  border-left-color: var(--accent);
  background: var(--shadow);
  color: var(--text);
}
.track__n {
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.track__title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.track__dur {
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.track[data-preview="none"] .track__dur {
  color: var(--text-faint);
}
.track[data-preview="none"] .track__title::after {
  content: " · no preview";
  color: var(--text-faint);
  font-size: var(--fs-micro);
}
.tracklist__empty {
  padding: var(--space-md) 0;
  color: var(--text-dim);
  font-size: var(--fs-small);
}

/* ── Tape deck column (§7) — sticky while the tracklist scrolls ────────── */
.deck {
  position: sticky;
  top: var(--space-md);
  align-self: start;
  overflow: hidden; /* clip the future bg art to the panel */
  border: 1px solid var(--accent-mid);
  background: linear-gradient(160deg, var(--surface), var(--shadow));
  padding: var(--space-md);
}

/* Illustrator deck-body art drops in here (behind the deck contents). */
.deck__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}
.deck > *:not(.deck__bg) {
  position: relative;
  z-index: 1;
}

.deck__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-md);
}
.deck__brand {
  font-family: var(--font-display);
  font-style: italic;
  letter-spacing: 0.05em;
  color: var(--text);
}
.deck__led {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  font-size: var(--fs-micro);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.deck__led::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px -1px var(--accent);
}

/* LED pulses while audio plays. */
.deck.is-playing .deck__led {
  color: var(--accent);
}
.deck.is-playing .deck__led::before {
  animation: led-pulse 1.1s ease-in-out infinite;
}
@keyframes led-pulse {
  0%,
  100% {
    opacity: 1;
    box-shadow: 0 0 12px 0 var(--accent);
  }
  50% {
    opacity: 0.35;
    box-shadow: 0 0 4px -1px var(--accent);
  }
}

/* ── Cassette bay: the rotating / draggable deck cassette ──────────────── */
.deck__bay {
  margin-bottom: var(--space-md);
  border: 1px solid var(--hairline);
  background: var(--bg);
}
.deck__stage {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 280px;
  perspective: 1000px;
}

/* Illustrator backdrop behind the rotating cassette drops in here. */
.deck__stage-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* The deck cube: continuously rotated by JS; grab to inspect. */
.deck__cube {
  position: relative;
  width: var(--cass-w);
  height: var(--cass-h);
  transform-style: preserve-3d;
  transform: rotateX(0deg) rotateY(0deg);
  cursor: grab;
  touch-action: none; /* let drag rotate instead of scrolling the page */
  will-change: transform;
  user-select: none;
  -webkit-user-select: none;
}
.deck__cube.is-dragging {
  cursor: grabbing;
}
/* Reuse the shared .cube__face rules; the deck cube is not absolutely
   centred like .cube (it fills the stage cell), so its faces still centre
   on the cube's own middle via top/left 50%. */
.deck__cube.is-empty {
  display: none;
}

.deck__hint {
  position: absolute;
  font-size: var(--fs-small);
  color: var(--text-dim);
  letter-spacing: 0.1em;
}
.deck__stage.is-loaded .deck__hint {
  display: none;
}

/* Reels — two hubs that spin while audio plays (placeholder for deck art). */
.deck__reels {
  position: absolute;
  bottom: 14px;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  gap: 90px;
  pointer-events: none;
}
.reel {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid var(--accent-mid);
  background: radial-gradient(circle, var(--surface) 30%, transparent 32%),
    conic-gradient(
      var(--accent-mid) 0 20deg,
      transparent 20deg 90deg,
      var(--accent-mid) 90deg 110deg,
      transparent 110deg 180deg,
      var(--accent-mid) 180deg 200deg,
      transparent 200deg 270deg,
      var(--accent-mid) 270deg 290deg,
      transparent 290deg 360deg
    );
  opacity: 0.5;
  transition: opacity 0.3s var(--ease);
}
.deck.is-playing .reel {
  opacity: 0.9;
  animation: reel-spin 1.8s linear infinite;
}
@keyframes reel-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Play/pause icon swap driven by player.js. */
.deck__btn-icon {
  line-height: 1;
  font-size: 1.1rem;
}
.deck__btn--play {
  color: var(--accent);
}
.deck.is-playing .deck__btn--play {
  background: var(--accent);
  color: var(--bg);
}

/* ── Now-playing readout ──────────────────────────────────────────────── */
.deck__readout {
  font-family: var(--font-mono);
  display: flex;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm);
  background: var(--bg);
  border: 1px solid var(--hairline);
  margin-bottom: var(--space-md);
  color: var(--text);
  font-size: var(--fs-small);
}
.deck__readout .time {
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* ── Transport controls (inert until Phase 4; SVG buttons later) ──────── */
.deck__transport {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
}
.deck__btn {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--accent-mid);
  border-radius: 50%;
  color: var(--text);
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}
.deck__btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.deck__btn--play {
  width: 60px;
  height: 60px;
  border-color: var(--accent);
}

/* ── Description of the loaded release ─────────────────────────────────── */
.deck__desc {
  font-size: var(--fs-small);
  line-height: 1.8;
  color: var(--text-dim);
  border-top: 1px solid var(--hairline);
  padding-top: var(--space-sm);
}

.deck__desc code {
  color: var(--text);
  font-size: 0.95em;
}

/* ── Reduced motion: stop the idle spinning bits (deck auto-rotate is also
   disabled in JS). Transitions on flips/reveals stay — they're user-driven. */
@media (prefers-reduced-motion: reduce) {
  .deck.is-playing .reel {
    animation: none;
  }
  .deck.is-playing .deck__led::before {
    animation: none;
  }
}
