/* ═══════════════════════════════════════════════════════════════
   djinn — 1210-style turntable player
   Two decks, alternating crossfade, real vinyl spin + tonearm drop.
   ═══════════════════════════════════════════════════════════════ */

.booth {
  display: grid;
  /* Decks get the room, the mixer is capped: a real 1210 is close to square,
     and with an 'auto' mixer column it was eating 461px and leaving the decks
     as tall oblongs. */
  /* 380 is what the mixer's own contents need without squashing (channels row
     measures ~376). Smaller than the 461 it used to take, so the decks still
     get the room to look like 1210s. */
  grid-template-columns: 1fr minmax(300px, 380px) 1fr;
  gap: clamp(.9rem, 2vw, 1.6rem); align-items: start; perspective: 1400px;
}
/* Was 880. With a tempo fader on each deck the three-across layout runs out of
   room around 1100 (measured: at 1024 a deck column is 213px for 221px of
   content), so it stacks sooner rather than squeezing. */
/* Three across only while the decks can still look like 1210s. Measured: at
   1280 a deck came out 386x482 (aspect 0.80, a tall oblong), so below 1350 the
   booth stacks and each deck gets the full width instead. */
@media (max-width: 1350px) {
  .booth { grid-template-columns: 1fr; justify-items: center; }
  /* stacked, a deck keeps 1210 proportions instead of stretching page-wide */
  .booth > * { width: 100%; max-width: 560px; }
  .mixer-face { max-width: 380px; }
}

/* ─── Deck chassis: brushed gunmetal faceplate over a deep rubber base,
   like the real SL-1210's matte black body ─── */
.deck {
  background:
    radial-gradient(130% 100% at 18% 0%, rgba(255,255,255,.055), transparent 45%),
    repeating-linear-gradient(100deg, rgba(255,255,255,.014) 0 1px, transparent 1px 3px),
    linear-gradient(175deg, #191920, #0c0c0f 50%, #08080a);
  border: 1px solid #000; border-radius: 10px;
  padding: clamp(1.1rem, 2.6vw, 1.6rem);
  position: relative;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    inset 0 -2px 0 rgba(0,0,0,.7),
    inset 0 0 0 1px rgba(255,255,255,.03),
    inset 0 0 40px rgba(0,0,0,.35),
    0 4px 0 -1px #050506,
    0 30px 50px -22px rgba(0,0,0,.85);
  transition: border-color .35s var(--ease), box-shadow .35s var(--ease), transform .35s var(--ease);
  transform-style: preserve-3d;
}

/* Faceplate screws (decks + mixer share these) */
.screw {
  position: absolute; width: 9px; height: 9px; border-radius: 50%; z-index: 3;
  background: radial-gradient(circle at 35% 30%, #4c4c55, #17171b 70%);
  box-shadow: inset 0 1px 1px rgba(255,255,255,.2), inset 0 -1px 1px rgba(0,0,0,.7), 0 1px 2px rgba(0,0,0,.5);
}
.screw::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 6px; height: 1.5px;
  background: rgba(0,0,0,.75); transform: translate(-50%, -50%) rotate(38deg); border-radius: 1px;
}
.screw--tl { top: 7px; left: 7px; } .screw--tr { top: 7px; right: 7px; }
.screw--bl { bottom: 7px; left: 7px; } .screw--br { bottom: 7px; right: 7px; }
.screw--tr::after { transform: translate(-50%, -50%) rotate(-24deg); }
.screw--bl::after { transform: translate(-50%, -50%) rotate(81deg); }
.screw--br::after { transform: translate(-50%, -50%) rotate(-60deg); }
.deck.is-active {
  border-color: rgba(182,255,58,.5);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.08), inset 0 -1px 0 rgba(0,0,0,.6),
    0 0 0 1px var(--acid-glow), 0 30px 60px -20px var(--acid-glow);
}
.deck.is-loaded:not(.is-active) { cursor: pointer; }
.deck.is-loaded:not(.is-active):hover { transform: translateY(-3px); }
.deck.is-dragover { border-color: var(--acid); }
.deck::after {
  content: attr(data-drop-hint);
  position: absolute; inset: 0; border-radius: 10px;
  display: flex; align-items: center; justify-content: center; text-align: center; padding: 1.5rem;
  background: rgba(6, 8, 4, .88); color: var(--acid); font-size: .82rem; font-weight: 600;
  opacity: 0; pointer-events: none; transition: opacity .15s; z-index: 5;
}
.deck.is-dragover::after { opacity: 1; }
.booth-hint { text-align: center; color: var(--faint); font-size: .8rem; margin-top: 1.1rem; }
.booth-hint .icon { width: 1em; height: 1em; vertical-align: -.15em; }

.deck-top { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 1rem; gap: .6rem; }
.deck-brand { display: flex; flex-direction: column; gap: .15rem; }
.deck-brand b {
  font-family: var(--font-display); font-weight: 800; font-size: .82rem; letter-spacing: .06em;
  color: #b9b9c2; text-transform: none; font-style: italic;
  text-shadow: 0 1px 0 rgba(0,0,0,.8), 0 -1px 0 rgba(255,255,255,.06);
}
.deck-brand span { font-size: .58rem; letter-spacing: .18em; text-transform: uppercase; color: var(--faint); }
.deck.is-active .deck-brand span { color: var(--acid); }
.quartz-block {
  display: flex; align-items: center; gap: .4rem;
  font-size: .55rem; letter-spacing: .14em; text-transform: uppercase; color: var(--faint);
  padding: .3rem .55rem; border-radius: 4px;
  background: rgba(0,0,0,.45); box-shadow: inset 0 1px 3px rgba(0,0,0,.7), inset 0 0 0 1px rgba(255,255,255,.04);
}
.quartz-led {
  width: 6px; height: 6px; border-radius: 50%; background: #3a1414; flex-shrink: 0;
  box-shadow: inset 0 0 2px rgba(0,0,0,.6); transition: background .2s, box-shadow .2s;
}
.deck.is-spinning .quartz-led { background: #ff6a3a; box-shadow: 0 0 6px #ff6a3a; }

.platter-stage { display: flex; gap: clamp(1.3rem, 3vw, 2rem); align-items: center; }

/* ─── Platter: machined edge, strobe-dot rows on the rim, glossy label ─── */
.platter-wrap { position: relative; width: min(44vw, 190px); aspect-ratio: 1; flex-shrink: 0; }
/* The die-cast platter edge the record sits inside — stays still while the vinyl spins */
.platter-rim {
  position: absolute; inset: -5px; border-radius: 50%;
  background: conic-gradient(from 210deg, #3c3c44, #101013 22%, #2e2e36 42%, #0e0e11 62%, #34343c 82%, #101013);
  box-shadow:
    0 2px 0 rgba(255,255,255,.05),
    0 14px 30px -12px rgba(0,0,0,.85),
    inset 0 0 0 1px rgba(0,0,0,.8);
}
.platter {
  width: 100%; height: 100%; border-radius: 50%;
  background:
    repeating-radial-gradient(circle at center, #242329 0 2px, #17161b 2px 4px),
    conic-gradient(from 200deg, #2a2930, #17161b 30%, #26252b 55%, #17161b 80%, #2a2930);
  box-shadow:
    inset 0 0 0 7px #0a0a0c,
    inset 0 3px 10px rgba(0,0,0,.7),
    inset 0 -2px 6px rgba(255,255,255,.03),
    0 20px 40px -16px rgba(0,0,0,.8);
  position: relative;
  animation: spin 1.9s linear infinite;
  animation-play-state: paused;
}
.deck.is-spinning .platter { animation-play-state: running; }
@keyframes spin { to { transform: rotate(360deg); } }
/* Slipmat: swaps the plain vinyl texture for an uploaded design, still spins/reacts the same */
.platter.has-slipmat {
  background: var(--slipmat-image) center/cover no-repeat;
}
/* Two rows of strobe dots around the rim, like the 1210's speed-check dots */
.strobe-ring {
  position: absolute; inset: 2px; border-radius: 50%; pointer-events: none;
  background: repeating-conic-gradient(rgba(255,255,255,.35) 0deg 1.7deg, transparent 1.7deg 6.5deg);
  -webkit-mask: radial-gradient(circle, transparent 87%, #000 88%, #000 91%, transparent 92%, transparent 93.5%, #000 94.5%, #000 97.5%, transparent 98.5%);
          mask: radial-gradient(circle, transparent 87%, #000 88%, #000 91%, transparent 92%, transparent 93.5%, #000 94.5%, #000 97.5%, transparent 98.5%);
}
/* Pop-up target light, bottom-left of the platter — glows when the deck spins */
.target-light {
  position: absolute; left: 2%; bottom: 6%; width: 13px; height: 13px; border-radius: 50%; z-index: 4;
  background: radial-gradient(circle at 38% 32%, #3c3c44, #101013 75%);
  box-shadow: 0 3px 6px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.06);
  transition: background .25s, box-shadow .25s;
}
.deck.is-spinning .target-light {
  background: radial-gradient(circle at 50% 45%, #fff, var(--acid) 45%, #6aa81e 90%);
  box-shadow: 0 0 12px var(--acid-glow), 0 0 4px var(--acid), 0 3px 6px rgba(0,0,0,.6);
}
.platter-label {
  position: absolute; inset: 0; margin: auto; width: 44%; height: 44%; border-radius: 50%;
  background: radial-gradient(circle at 34% 26%, #d4ff8a, var(--acid) 45%, #7fdb1e 100%);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 0 0 2px #0a0a0c, 0 0 0 3px rgba(255,255,255,.06), 0 6px 16px rgba(0,0,0,.6);
}
.platter-label::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: linear-gradient(115deg, rgba(255,255,255,.55) 0%, transparent 30%, transparent 70%, rgba(0,0,0,.18) 100%);
  mix-blend-mode: overlay;
}
.platter-label img { width: 100%; height: 100%; object-fit: cover; }
.platter-label .fallback { color: var(--acid-ink); opacity: .85; font-weight: 800; font-size: .8rem; letter-spacing: .05em; }
.spindle {
  position: absolute; inset: 0; margin: auto; width: 11px; height: 11px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #4a4a52, #08080a 70%);
  box-shadow: 0 0 0 2px rgba(255,255,255,.06), 0 2px 4px rgba(0,0,0,.6);
}

/* ─── Tonearm: base, cylindrical arm, counterweight, headshell + stylus ───
   Deck B is deliberately NOT mirrored — both decks use identical markup and
   positioning so they look and behave exactly the same. Rest angle + base
   inset are conservative so the arm can't swing far enough to visually
   touch the gain fader sitting right next to the platter (it did at a
   steeper -30deg with the base flush to the edge). */
.tonearm-base {
  position: absolute; top: 6%; right: 8%; width: 28px; height: 28px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #4a4a54, #0c0c0e 75%);
  box-shadow:
    0 4px 10px rgba(0,0,0,.6),
    inset 0 0 0 1px rgba(255,255,255,.05),
    0 0 0 4px #131317, 0 0 0 5px rgba(255,255,255,.04);
  z-index: 4;
}
.tonearm-base::after {
  content: ""; position: absolute; inset: 6px; border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, #67676f, #1a1a1f 75%);
  box-shadow: inset 0 1px 1px rgba(255,255,255,.15);
}
/* Arm-rest clip beside the base */
.tonearm-rest {
  position: absolute; top: calc(6% + 32px); right: calc(8% - 6px); width: 7px; height: 16px; z-index: 3;
  background: linear-gradient(90deg, #2c2c33, #131316); border-radius: 2px;
  box-shadow: 0 2px 4px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.07);
}
.tonearm {
  position: absolute; top: calc(6% + 13px); right: calc(8% + 12px); width: 4px; height: 42%;
  background: linear-gradient(90deg, #3a3a42, #8a8a94 45%, #3a3a42);
  border-radius: 4px; box-shadow: 1px 1px 3px rgba(0,0,0,.6);
  transform-origin: top center; transform: rotate(-20deg); z-index: 4;
  transition: transform .6s var(--ease);
}
.tonearm-counterweight {
  position: absolute; top: -6px; left: 50%; transform: translateX(-50%);
  width: 13px; height: 13px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #4e4e58, #131316 75%);
  box-shadow: 0 2px 4px rgba(0,0,0,.5);
}
.tonearm-headshell {
  position: absolute; bottom: -3px; left: 50%; transform: translateX(-50%) rotate(-14deg);
  width: 16px; height: 9px; border-radius: 2px;
  background: linear-gradient(90deg, #d8d8dc, #8f8f96);
  box-shadow: 0 2px 5px rgba(0,0,0,.5);
}
.tonearm-headshell::after {
  content: ""; position: absolute; bottom: -2px; left: 3px; width: 2px; height: 4px; background: var(--acid);
  box-shadow: 0 0 3px var(--acid);
}
.deck.is-spinning .tonearm { transform: rotate(7deg); }

/* ─── Gain fader strip (styled like a 1210's pitch fader, drags that deck's volume) ─── */
.pitch-strip { display: flex; flex-direction: column; align-items: center; gap: .3rem; flex-shrink: 0; }
.pitch-tick { font-size: .56rem; color: var(--faint); font-variant-numeric: tabular-nums; letter-spacing: .08em; }
.pitch-track {
  width: 30px; height: clamp(80px, 16vw, 130px); border-radius: 4px;
  background: linear-gradient(180deg, #0b0b0e, #060608);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06), inset 0 3px 8px rgba(0,0,0,.75), 0 1px 0 rgba(255,255,255,.04);
  position: relative; cursor: ns-resize; touch-action: none; padding: 5px 0;
}
/* Slot groove */
.pitch-track::before {
  content: ""; position: absolute; left: 50%; top: 6px; bottom: 6px; width: 3px; border-radius: 2px;
  background: #000; box-shadow: inset 0 1px 2px rgba(0,0,0,.9), 0 1px 0 rgba(255,255,255,.05);
  transform: translateX(-50%);
}
/* Tick scale down both sides, brighter line at the halfway detent */
.pitch-track::after {
  content: ""; position: absolute; inset: 6px 3px; pointer-events: none;
  background:
    repeating-linear-gradient(180deg, rgba(255,255,255,.14) 0 1px, transparent 1px calc((100% - 1px) / 8)),
    linear-gradient(180deg, transparent calc(50% - 1px), rgba(255,255,255,.3) calc(50% - 1px), rgba(255,255,255,.3) calc(50% + 1px), transparent calc(50% + 1px));
  -webkit-mask: linear-gradient(90deg, #000 6px, transparent 6px calc(100% - 6px), #000 calc(100% - 6px));
          mask: linear-gradient(90deg, #000 6px, transparent 6px calc(100% - 6px), #000 calc(100% - 6px));
}
.pitch-thumb {
  position: absolute; left: 50%; top: 0%; transform: translate(-50%, -50%);
  width: 30px; height: 16px; border-radius: 2px; z-index: 2;
  background: linear-gradient(180deg, #35353c, #17171b 48%, #26262c 52%, #101013);
  box-shadow: 0 3px 6px rgba(0,0,0,.7), inset 0 1px 0 rgba(255,255,255,.14), inset 0 -1px 0 rgba(0,0,0,.8);
  transition: box-shadow .15s;
}
.pitch-thumb::after {
  content: ""; position: absolute; left: 2px; right: 2px; top: 50%; height: 2px;
  background: #e8e8ec; transform: translateY(-50%); border-radius: 1px;
  box-shadow: 0 0 3px rgba(255,255,255,.4);
}
.pitch-track:hover .pitch-thumb { box-shadow: 0 0 0 3px var(--acid-glow), 0 3px 6px rgba(0,0,0,.7); }
.pitch-caption { font-size: .58rem; letter-spacing: .18em; color: var(--faint); margin-top: .1rem; }

/* ─── Loaded-track readout: full-width LCD-style display strip ─── */
.deck-display {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  margin-top: 1.1rem; padding: .55rem .8rem; border-radius: 5px;
  background: linear-gradient(180deg, #05070a, #0a0f08);
  box-shadow: inset 0 1px 4px rgba(0,0,0,.85), inset 0 0 0 1px rgba(182,255,58,.12), inset 0 0 18px rgba(182,255,58,.05);
}
.deck-display .dm-title {
  min-width: 0; font-family: var(--font-display); font-weight: 800; font-size: .78rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--acid); text-shadow: 0 0 6px var(--acid-glow);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.deck-display .dm-artist {
  flex-shrink: 0; color: rgba(182,255,58,.55); font-size: .72rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40%;
}

/* ─── Bottom row: Start/Stop left, 33/45 speed buttons right ─── */
.deck-bottom { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: .9rem; }
.deck-controls { display: flex; align-items: center; gap: .5rem; flex-shrink: 0; }
.startstop {
  display: flex; align-items: center; gap: .45rem;
  font: inherit; font-size: .58rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); cursor: pointer; padding: .6rem .65rem; border-radius: 5px;
  background: linear-gradient(180deg, #26262d, #101014);
  border: 1px solid #000;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.09), inset 0 -1px 0 rgba(0,0,0,.7), 0 3px 5px rgba(0,0,0,.5), 0 0 0 1px rgba(255,255,255,.03);
  transition: color .2s;
}
.startstop:hover { color: var(--ink); }
.startstop:active { box-shadow: inset 0 2px 5px rgba(0,0,0,.7), 0 1px 2px rgba(0,0,0,.5); }
.start-light {
  width: 7px; height: 7px; border-radius: 50%; background: #3a1414; flex-shrink: 0;
  box-shadow: inset 0 0 2px rgba(0,0,0,.6); transition: background .2s, box-shadow .2s;
}
.deck.is-spinning .start-light { background: var(--acid); box-shadow: 0 0 8px var(--acid), 0 0 2px var(--acid); }
.rpm-btn {
  width: 26px; height: 26px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: .56rem; font-weight: 700; color: var(--faint);
  background: linear-gradient(180deg, #26262d, #101014); border: 1px solid #000;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.09), 0 2px 4px rgba(0,0,0,.5);
}
.rpm-btn.is-lit { color: var(--acid); text-shadow: 0 0 6px var(--acid-glow); }

/* ─── Mixer: brushed faceplate, DJM-style channel strips either side of transport ─── */
.mixer { display: flex; align-items: center; justify-content: center; padding-top: 2.2rem; }
.mixer-face { max-width: 380px; width: 100%; }
/* The channels row (CH A | transport | CH B) needed 428px inside a 310px face,
   so it spilled out both sides and slid behind the decks. Everything inside the
   face is now allowed to shrink, and the face itself can never be exceeded. */
.mixer-face > * { max-width: 100%; }
.mixer-channels { width: 100%; gap: .7rem; justify-content: space-between; }
.channel-strip { min-width: 0; flex: 0 1 auto; }
/* The transport may shrink as a row, but its BUTTONS must never be squashed —
   allowing that turned the play button into a 27x50 egg at 1440+. */
.mixer-transport { flex: 0 1 auto; min-width: 0; }
.mixer-transport button, .play-btn { flex: 0 0 auto; aspect-ratio: 1; }
.mixer-face {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: .8rem;
  padding: 1.1rem 1rem 1.2rem;
  background:
    radial-gradient(130% 100% at 20% 0%, rgba(255,255,255,.05), transparent 45%),
    repeating-linear-gradient(100deg, rgba(255,255,255,.014) 0 1px, transparent 1px 3px),
    linear-gradient(175deg, #191920, #0b0b0e 55%);
  border: 1px solid rgba(182,255,58,.45); border-radius: 10px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07), inset 0 -2px 0 rgba(0,0,0,.7),
    0 4px 0 -1px #050506,
    0 25px 50px -22px rgba(0,0,0,.85),
    0 0 0 1px var(--acid-glow), 0 0 30px var(--acid-glow);
}
.mixer-brand { font-family: var(--font-display); font-size: .62rem; letter-spacing: .22em; color: var(--faint); text-transform: uppercase; display: flex; align-items: baseline; gap: .5rem; }
.mixer-brand span { color: var(--acid); }
.mixer-brand i { font-style: normal; font-size: .52rem; letter-spacing: .14em; color: var(--faint); opacity: .7; }

.mixer-channels { display: flex; align-items: flex-start; gap: clamp(.7rem, 2vw, 1.3rem); }
.channel-strip {
  display: flex; flex-direction: column; align-items: center; gap: .45rem;
  padding: .5rem .5rem .6rem; border-radius: 6px;
  background: rgba(0,0,0,.35);
  box-shadow: inset 0 1px 4px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.03);
}
.channel-label { font-size: .58rem; font-weight: 700; color: var(--faint); letter-spacing: .14em; text-transform: uppercase; }
.channel-strip.is-live .channel-label { color: var(--acid); }
/* Decorative EQ mini-knobs (Hi/Mid/Low), fixed positions — the real working control is the Trim knob below */
.eq-stack { display: flex; flex-direction: column; gap: .35rem; }
.eq-cell { display: flex; align-items: center; gap: .4rem; }
.eq-cell i { font-style: normal; font-size: .5rem; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); width: 1.6rem; }
.mini-knob {
  width: 15px; height: 15px; border-radius: 50%; flex-shrink: 0; position: relative;
  background: radial-gradient(circle at 35% 30%, #3c3c44, #101013 75%);
  box-shadow: 0 2px 4px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.06);
}
.mini-knob::after {
  content: ""; position: absolute; top: 1.5px; left: 50%; width: 1.5px; height: 5px;
  background: #c9c9d2; transform: translateX(-50%) rotate(var(--rot, 0deg)); transform-origin: bottom center; border-radius: 1px;
}
.knob-caption { font-size: .5rem; letter-spacing: .16em; text-transform: uppercase; color: var(--faint); }
.vu-meter { display: flex; flex-direction: column-reverse; gap: 2px; height: 38px; }
.vu-meter i { width: 14px; height: 5px; border-radius: 1px; background: var(--surface-2); transition: background .15s; }
.vu-meter i:nth-child(4) { background: var(--surface-2); }
.channel-strip.is-live .vu-meter i { animation: vu 1.1s ease-in-out infinite; animation-delay: calc(var(--i, 0) * .08s); }
.channel-strip.is-live .vu-meter i:nth-child(1) { --i: 4; background: var(--acid); }
.channel-strip.is-live .vu-meter i:nth-child(2) { --i: 2; background: var(--acid); }
.channel-strip.is-live .vu-meter i:nth-child(3) { --i: 0; background: var(--acid); }
.channel-strip.is-live .vu-meter i:nth-child(4) { --i: 3; background: #d4e84a; }
.channel-strip.is-live .vu-meter i:nth-child(5) { --i: 1; background: #ff9a4a; }
@keyframes vu { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.knob {
  width: 30px; height: 30px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #3c3c44, #101013 75%);
  box-shadow: 0 3px 8px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.06);
  position: relative; cursor: ns-resize; touch-action: none; --rot: 135deg;
  transition: box-shadow .15s;
}
.knob:hover, .knob:focus-visible { box-shadow: 0 0 0 3px var(--acid-glow), 0 3px 8px rgba(0,0,0,.6); outline: none; }
.knob::after { content: ""; position: absolute; top: 3px; left: 50%; width: 2px; height: 9px; background: var(--acid); transform: translateX(-50%) rotate(var(--rot)); transform-origin: bottom center; border-radius: 1px; box-shadow: 0 0 3px var(--acid-glow); }

.mixer-transport { display: flex; align-items: center; gap: .55rem; align-self: center; }
.mixer-transport button {
  background: linear-gradient(175deg, #2a2a32, #131316); border: 1px solid var(--line-strong); color: var(--muted);
  width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  cursor: pointer; transition: color .2s, border-color .2s; box-shadow: 0 3px 8px rgba(0,0,0,.5);
}
.mixer-transport button:hover { color: var(--ink); border-color: var(--acid); }
.mixer-transport .play-btn {
  width: 50px; height: 50px; background: linear-gradient(150deg, var(--acid), #8fe022); border: none; color: var(--acid-ink);
  box-shadow: 0 10px 26px -8px var(--acid-glow);
}
.mixer-transport .play-btn:hover { transform: scale(1.05); border-color: transparent; }
.mixer-transport .play-btn .icon-pause { display: none; }
.mixer-transport .play-btn.is-playing .icon-play { display: none; }
.mixer-transport .play-btn.is-playing .icon-pause { display: block; }

/* ─── Crossfader: a real draggable hardware-style slider ─── */
.crossfader-unit { display: flex; flex-direction: column; align-items: center; gap: .4rem; }
.crossfader-track {
  width: min(160px, 38vw); height: 26px; border-radius: 6px; background: #08080a;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06), inset 0 3px 8px rgba(0,0,0,.6);
  position: relative; cursor: pointer; touch-action: none;
}
.crossfader-track::before {
  content: ""; position: absolute; left: 10px; right: 10px; top: 50%; height: 2px; background: rgba(255,255,255,.08); transform: translateY(-50%);
}
.crossfader-fill { position: absolute; inset: 0; border-radius: 6px; background: linear-gradient(90deg, var(--acid-dim), transparent); width: 0%; transition: width .1s linear; pointer-events: none; }
.crossfader-handle {
  position: absolute; top: 50%; left: 0%; width: 22px; height: 26px; border-radius: 3px;
  background: linear-gradient(90deg, #35353c, #17171b 48%, #26262c 52%, #101013);
  box-shadow: 0 3px 8px rgba(0,0,0,.7), inset 0 1px 0 rgba(255,255,255,.14), inset 0 -1px 0 rgba(0,0,0,.8);
  transform: translate(-50%, -50%); transition: box-shadow .15s; pointer-events: none;
}
.crossfader-handle::after {
  content: ""; position: absolute; left: 50%; top: 2px; bottom: 2px; width: 2px;
  background: #e8e8ec; transform: translateX(-50%); border-radius: 1px;
  box-shadow: 0 0 3px rgba(255,255,255,.4);
}
.crossfader-track:hover .crossfader-handle, .crossfader-track.is-dragging .crossfader-handle { box-shadow: 0 0 0 3px var(--acid-glow), 0 3px 8px rgba(0,0,0,.7); }
.crossfader-caption {
  font-size: .6rem; letter-spacing: .14em; text-transform: uppercase; color: var(--faint);
  display: flex; justify-content: space-between; align-items: center; width: min(160px, 38vw);
}
.crossfader-caption em { font-style: normal; font-size: .5rem; letter-spacing: .18em; opacity: .7; }

.automix-toggle { display: flex; align-items: center; gap: .55rem; cursor: pointer; user-select: none; }
.automix-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.automix-switch {
  width: 36px; height: 20px; border-radius: 99px; background: var(--surface-2); border: 1px solid var(--line-strong);
  position: relative; transition: background .2s, border-color .2s; flex-shrink: 0;
}
.automix-switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%;
  background: var(--muted); transition: transform .2s var(--ease), background .2s;
}
.automix-toggle input:checked + .automix-switch { background: var(--acid-dim); border-color: var(--acid); }
.automix-toggle input:checked + .automix-switch::after { transform: translateX(16px); background: var(--acid); }
.automix-label { font-size: .78rem; color: var(--muted); font-weight: 600; }
.automix-toggle input:checked ~ .automix-label { color: var(--acid); }

@media (max-width: 880px) {
  .mixer { padding-top: 0; }
}

/* ─── Seek bar: big hit-area, real drag + touch scrubbing ─── */
.seek-row { display: flex; align-items: center; gap: 1rem; margin-top: clamp(1.6rem, 4vw, 2.4rem); }
.seek-time { font-size: .85rem; color: var(--muted); width: 3.4rem; text-align: center; font-variant-numeric: tabular-nums; flex-shrink: 0; }
.seek-track {
  flex: 1; position: relative; height: 28px; display: flex; align-items: center; cursor: pointer; touch-action: none;
}
.seek-track::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%);
  height: 8px; border-radius: 99px; background: var(--surface-2); border: 1px solid var(--line);
}
.seek-fill { position: absolute; left: 0; top: 50%; transform: translateY(-50%); height: 8px; border-radius: 99px; width: 0%; background: linear-gradient(90deg, var(--acid), #7fdb1e); pointer-events: none; }
.seek-handle {
  position: absolute; top: 50%; left: 0%; width: 18px; height: 18px; border-radius: 50%;
  background: var(--ink); box-shadow: 0 0 0 3px var(--acid), 0 4px 10px rgba(0,0,0,.5);
  transform: translate(-50%, -50%); pointer-events: none; transition: box-shadow .15s;
}
.seek-track:hover .seek-handle, .seek-track.is-dragging .seek-handle { box-shadow: 0 0 0 4px var(--acid), 0 0 16px var(--acid-glow); }

.player-volume { display: flex; align-items: center; gap: .6rem; color: var(--muted); flex-shrink: 0; }
.player-volume input[type="range"] { width: 80px; accent-color: var(--acid); cursor: pointer; }

/* ─── Playlist ─── */
.playlist { margin-top: clamp(2rem, 5vw, 3rem); border-top: 1px solid var(--line); padding-top: 1.4rem; }
.playlist-row {
  display: flex; align-items: center; gap: 1rem; padding: .9rem .7rem; border-radius: var(--radius-sm); cursor: pointer;
  transition: background .2s, opacity .2s;
}
.playlist-row:hover { background: rgba(255,255,255,.04); }
.playlist-row.is-current { background: var(--acid-dim); }
.playlist-row.is-dragging { opacity: .4; }
.playlist-row .pl-deck-badge {
  font-size: .68rem; font-weight: 700; color: var(--acid-ink); background: var(--acid);
  border-radius: 5px; padding: .1rem .4rem; flex-shrink: 0; display: none;
}
.playlist-row .pl-deck-badge:not(:empty) { display: inline-block; }
.playlist-row .pl-num { width: 1.6rem; color: var(--faint); font-size: .85rem; flex-shrink: 0; }
.playlist-row .pl-num .pl-eq { display: none; }
.playlist-row.is-current.is-playing .pl-num .pl-eq { display: flex; }
.playlist-row.is-current.is-playing .pl-num .pl-idx { display: none; }
.pl-eq { gap: 3px; align-items: flex-end; height: 14px; }
.pl-eq i { width: 3px; background: var(--acid); border-radius: 2px; animation: eq .9s ease-in-out infinite; }
.pl-eq i:nth-child(1) { animation-delay: 0s; } .pl-eq i:nth-child(2) { animation-delay: .15s; } .pl-eq i:nth-child(3) { animation-delay: .3s; }
@keyframes eq { 0%,100% { height: 4px; } 50% { height: 14px; } }
.playlist-row .pl-cover { width: 40px; height: 40px; border-radius: 8px; overflow: hidden; background: var(--surface-2); flex-shrink: 0; }
.playlist-row .pl-cover img { width: 100%; height: 100%; object-fit: cover; }
.playlist-row .pl-meta { flex: 1; min-width: 0; }
.playlist-row .pl-title { font-size: .95rem; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.playlist-row .pl-artist { font-size: .8rem; color: var(--muted); margin-top: .1rem; }
.playlist-row .pl-genre { font-size: .74rem; color: var(--faint); border: 1px solid var(--line); border-radius: 999px; padding: .2rem .65rem; flex-shrink: 0; }
@media (max-width: 560px) { .playlist-row .pl-genre { display: none; } }
/* At 360 the track title was the last thing wider than the screen. */
.playlist-row .pl-meta, .playlist-row .pl-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.playlist-row .pl-drag-handle {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 40px; height: 40px; margin: -.9rem -.7rem -.9rem 0; color: var(--faint);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.playlist-row .pl-drag-handle:hover,
.playlist-row .pl-drag-handle:active { color: var(--acid); }
.playlist-row .pl-drag-handle .icon { width: 1.3em; height: 1.3em; }

.playlist-row .pl-queue-btn {
  flex-shrink: 0; width: 26px; height: 26px; border-radius: 50%;
  background: transparent; border: 1px solid var(--line-strong); color: var(--faint);
  font: inherit; font-size: .8rem; font-weight: 700; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  -webkit-tap-highlight-color: transparent; transition: color .15s, border-color .15s, background .15s;
}
.playlist-row .pl-queue-btn:hover { color: var(--acid); border-color: var(--acid); }
.playlist-row .pl-queue-btn.is-queued { background: var(--acid); border-color: var(--acid); color: var(--acid-ink); }

/* ─── Queue summary bar, shown once at least one track is queued ─── */
.queue-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-top: clamp(1.6rem, 4vw, 2.4rem); padding: .7rem 1rem;
  background: var(--acid-dim); border: 1px solid rgba(182,255,58,.3); border-radius: var(--radius-sm);
  font-size: .82rem; color: var(--ink);
}
.queue-bar[hidden] { display: none; }
.queue-bar button {
  flex-shrink: 0; font: inherit; font-size: .78rem; color: var(--muted); background: transparent;
  border: 1px solid var(--line-strong); border-radius: 999px; padding: .35rem .8rem; cursor: pointer;
}
.queue-bar button:hover { color: var(--acid); border-color: var(--acid); }

/* ─── "Load onto Deck A/B" popover, opened by the grip handle — works on
   touch regardless of scroll position, unlike a spatial drag ─── */
.pl-deck-menu {
  position: fixed; z-index: 60; display: flex; flex-direction: column; gap: .3rem;
  padding: .4rem; background: linear-gradient(175deg, #1c1c22, #0a0a0d 60%);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  box-shadow: 0 15px 30px -10px rgba(0,0,0,.7);
}
.pl-deck-menu[hidden] { display: none; }
.pl-deck-menu button {
  font: inherit; font-size: .85rem; color: var(--ink); background: transparent; border: none;
  border-radius: 6px; padding: .55rem .9rem; text-align: left; white-space: nowrap; cursor: pointer;
}
.pl-deck-menu button:hover { background: var(--acid-dim); color: var(--acid); }

/* ─── Beat sync: BPM readout, tempo fader, SYNC ──────────────────────────────
   The tempo fader is a second pitch strip beside GAIN, so it reads as part of
   the deck rather than an add-on. WIDTH IS THE WHOLE PROBLEM on a phone: a
   second 30px strip pushed deck B off the page in the mock, so below 880px
   both strips narrow and the platter gives up the difference. Checked at
   390px and 360px, not assumed. */
/* The deck is a grid item, and a grid item defaults to min-width:auto — so it
   is sized to the WIDEST thing inside it. This BPM row added ~130px of
   min-content and pushed deck B off the page on a phone (measured: deck
   min-content 260 -> 382). min-width:0 lets the deck fit its column and the
   text ellipsise instead. Same trap as the admin panel grids. */
.booth > *, .deck, .deck-display, .dm-bpm { min-width: 0; }
/* The display was one flex row (title | artist). Adding BPM to that row left
   the title as "SIMM…", so the display becomes two rows: the track keeps the
   full width on top, the tempo sits underneath with the artist. */
.deck-display { flex-wrap: wrap; }
.deck-display .dm-title { flex: 1 1 100%; }

/* Long titles: the display is only so wide, so a title that does not fit
   scrolls instead of being cut to "THE ASSIZES COU…". Only titles that
   genuinely overflow get the animation (player.js adds .is-scrolling), so a
   short title just sits still. */
.dm-title { position: relative; }
.dm-title.is-scrolling { text-overflow: clip; }
/* The inner span must ALWAYS be an inline-block: it is what gets measured, and
   while it was only made one by .is-scrolling its scrollWidth read 0, so the
   "does this overflow?" test could never be true and nothing ever scrolled. */
.dm-title-inner { display: inline-block; white-space: nowrap; }
.dm-title.is-scrolling .dm-title-inner {
  animation: dm-marquee var(--dm-dur, 12s) linear infinite;
}
.dm-title.is-scrolling:hover .dm-title-inner { animation-play-state: paused; }
/* -50% = exactly one copy of the duplicated text, so the loop is seamless and
   never pauses at either end. */
@keyframes dm-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .dm-title.is-scrolling .dm-title-inner { animation: none; }
}
.dm-bpm { display: flex; align-items: baseline; gap: .35rem; margin-left: auto; }

/* FITTING THE SECOND FADER, the honest version.
   A deck sized for platter + ONE strip cannot also hold a second one: measured,
   the stage needs 322px and has 236px, so both strips hung outside the chassis
   and rendered over the mixer. Two changes, in this order:
     1) the platter gives up some width and the gaps tighten, and
     2) below 1200px the deck's GAIN strip steps aside, because the mixer's own
        TRIM knobs already set each deck's level — TEMPO has no such twin, so it
        is the one worth the space.
   Verified at 1440/1280/1024/900/414/390/360, not assumed. */
/* On a real 1210 the pitch fader sits at the right edge of the chassis, not
   against the platter. The stage pushes the fader group over there and keeps a
   proper gap, so the tonearm never crowds it. */
/* Platter hard left, both faders TOGETHER at the right edge (space-between
   pushed them apart and left GAIN stranded mid-chassis). margin-left:auto on
   the first strip carries the whole group over. */
.platter-stage { gap: .7rem; justify-content: flex-start; width: 100%; }
/* NB :first-of-type would match .platter-wrap (both are divs) — target the
   GAIN strip itself so the whole fader group is carried to the right edge. */
.platter-stage .pitch-strip:not(.pitch-strip--tempo) { margin-left: auto; }
.platter-wrap { width: min(20vw, 215px); }
/* A 1210 is wider than it is tall (452 x 366mm). The chassis height comes from
   the display + controls as much as the platter, so those tighten too. */
@media (min-width: 1351px) {
  .deck { padding-top: 1rem; padding-bottom: 1rem; }
  .deck-display { margin-top: .7rem; padding-top: .45rem; padding-bottom: .45rem; }
  .deck-bottom { margin-top: .7rem; }
  .platter-stage { margin-block: .2rem; }
}
@media (max-width: 1450px) and (min-width: 1351px) {
  .platter-wrap { width: min(20vw, 165px); }
}
.dm-title, .dm-artist { overflow: hidden; text-overflow: ellipsis; }
.dm-bpm-n { font-family: var(--font-display, 'Syne', sans-serif); font-weight: 800; font-size: 1rem; color: var(--acid); }
.dm-bpm-l { font-size: .55rem; letter-spacing: .12em; color: rgba(255,255,255,.45); }
.dm-bpm-pct { font-size: .6rem; color: rgba(255,255,255,.55); font-variant-numeric: tabular-nums; }

.pitch-strip--tempo .pitch-track { background: linear-gradient(180deg, #0d1207, #060608); }
/* GAIN knob red, TEMPO knob green — you can tell them apart at a glance
   without reading the caption. */
.pitch-strip:not(.pitch-strip--tempo) .pitch-thumb {
  background: linear-gradient(180deg, #ff8a8a, #d43434 48%, #e84a4a 52%, #ae1616);
  box-shadow: 0 3px 6px rgba(0,0,0,.7), 0 0 12px rgba(255,74,74,.4), inset 0 1px 0 rgba(255,255,255,.3);
}
.pitch-strip:not(.pitch-strip--tempo) .pitch-caption { color: #ff6b6b; }

.pitch-strip--tempo .pitch-thumb {
  background: linear-gradient(180deg, #cdff6a, #8fd420 48%, #a8e83c 52%, #6fae14);
  box-shadow: 0 3px 6px rgba(0,0,0,.7), 0 0 12px rgba(182,255,58,.45), inset 0 1px 0 rgba(255,255,255,.3);
}
.pitch-strip--tempo .pitch-caption { color: var(--acid); }

/* Tick scale above the crossfader — |''''|''''| — the marks you get on a real
   mixer: full-height at each end and centre, short ones between. */
.crossfader-unit { position: relative; }
.crossfader-unit::before {
  content: ""; position: absolute; left: 0; right: 0; top: -9px; height: 7px; pointer-events: none;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.22) 0 1px, transparent 1px 12.5%),
    linear-gradient(90deg,
      rgba(255,255,255,.5) 0 2px, transparent 2px calc(50% - 1px),
      rgba(255,255,255,.5) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px) calc(100% - 2px),
      rgba(255,255,255,.5) calc(100% - 2px) 100%);
  background-size: 100% 4px, 100% 7px;
  background-position: 0 0, 0 0;
  background-repeat: no-repeat;
}

.mixer-sync { display: flex; flex-direction: column; align-items: center; gap: 6px; margin: 2px 0 10px; }
.sync-btn {
  font-family: var(--font-display, 'Syne', sans-serif); font-weight: 800; letter-spacing: .1em; font-size: .72rem;
  padding: .45rem 1.1rem; border-radius: 6px; cursor: pointer;
  background: #12131a; color: rgba(255,255,255,.7); border: 1px solid rgba(255,255,255,.18);
}
.sync-btn:hover { color: var(--ink); border-color: var(--acid); }
.sync-btn.is-locked {
  background: var(--acid); color: var(--acid-ink, #06231f); border-color: var(--acid);
  box-shadow: 0 0 14px rgba(182,255,58,.45);
}
.sync-read { display: flex; gap: 4px; }
.sync-lamp { width: 7px; height: 7px; border-radius: 50%; background: rgba(255,255,255,.16); transition: background .15s, box-shadow .15s; }
.sync-lamp.on { background: var(--acid); box-shadow: 0 0 8px var(--acid); }
.sync-note {
  font-size: .58rem; letter-spacing: .1em; text-transform: uppercase; color: rgba(255,255,255,.5);
  text-align: center; max-width: 14rem;
}

@media (max-width: 1350px) {
  /* Two strips must cost less than one wide one did. The PLATTER is the real
     variable here: it was sized min(44vw,190px) with room for one strip, so it
     has to give the second strip its width back or deck B runs off the page. */
  .pitch-track { width: 22px; }
  .pitch-thumb { width: 22px; }
  .platter-stage { gap: .9rem; }
  .pitch-strip { gap: .2rem; }
  .platter-wrap { width: min(38vw, 180px); }
}
@media (max-width: 420px) {
  .pitch-track { width: 18px; height: clamp(70px, 20vw, 100px); }
  .pitch-thumb { width: 18px; height: 13px; }
  .platter-stage { gap: .5rem; }
  .pitch-strip { gap: .15rem; }
  .pitch-tick, .pitch-caption { font-size: .5rem; }
  .dm-bpm-n { font-size: .85rem; }
  .platter-wrap { width: min(38vw, 150px); }
}

/* Nothing in the booth may exceed the screen. The mixer's channel strips and
   the deck's own decoration were still poking out by a few px once the tempo
   fader was in. Measured at 360/390/414, not assumed. */
@media (max-width: 1350px) {
  /* NB `.booth > *` is capped at 560px above so a stacked deck keeps 1210
     proportions — do NOT reset it to 100% here, that was overriding the cap and
     leaving each deck stretched across the page (1203x412). */
  .booth, .mixer, .mixer-face, .mixer-channels { max-width: 100%; }
  .booth > * { max-width: min(100%, 560px); }
  /* Do NOT wrap the channels: wrapping threw CH B under the transport and the
     mixer stopped reading as a mixer. They shrink instead, which is what the
     layout did before the tempo fader existed. */
  .mixer-channels { flex-wrap: nowrap; }
  .channel-strip { min-width: 0; }
}

/* A 320px phone (Galaxy S9+ and anything older/smaller) is narrower than every
   width I first tested at, and the mixer's channel strips ran 39px past the
   edge there. They shrink to fit rather than the page scrolling sideways. */
@media (max-width: 400px) {
  /* Measured on a Galaxy S9+ (320px): the mixer face had ~20px more inside it
     than the screen allows, so every part of it gives a little back. */
  .mixer-face { padding-left: .5rem; padding-right: .5rem; }
  .mixer-channels { gap: .35rem; }
  .channel-strip { padding: .45rem .25rem; gap: .3rem; }
  .channel-label { font-size: .5rem; letter-spacing: .04em; }
  .eq-stack { gap: .25rem; }
  .knob { transform: scale(.8); }
  .mini-knob { transform: scale(.78); }
  .vu-meter { transform: scale(.82); transform-origin: center; }
  .mixer-transport { gap: .3rem; }
  .mixer-transport button { width: 26px; height: 26px; flex: 0 0 26px; aspect-ratio: 1; }
  .play-btn { width: 34px; height: 34px; transform: none; flex: 0 0 34px; aspect-ratio: 1; }
  /* On a 320px phone the transport was landing on CH B's knobs: the row needs
     47+47 strips + 94 transport + gaps in 282px of face. Everything narrows so
     the three sit side by side without touching. */
  .channel-strip { width: 42px; }
  .mixer-channels { gap: .3rem; }
}
