/* =============================================================================
   DJ-responsive.css
   Load AFTER DJ.css. Cascade-only: no JS, no markup changes.
   -----------------------------------------------------------------------------
   The base DJ.css is built around a "single 3D perspective console" — every
   per-deck control lives INSIDE .deck-mount-a/-b, which are absolutely-
   positioned sibling overlays sized as a fraction of vmin and tilted with
   rotateX(55deg). That looks great when vmin sits in the laptop/desktop
   range (~700-1100), but it falls apart in three places:

     1. Mobile portrait — the base file does `.deck-mount { display:none }` at
        <=720px, which removes pitch faders, BPM/TRACK, AND the Songs button
        along with the overlay. Only the fallback .controls strip survives.

     2. Mobile landscape — vmin is small (~390px on phones) so the deck-mount
        becomes ~178px tall after rotation. The pitch fader's top:80/bottom:200
        rule tries to make it negative-height, the crate button's calc bottom
        offset lands inside the play-wrap, things pile up.

     3. Ultrawide — decks are capped at 624px while .deck-backdrop grows to its
        1700px cap. Steel margin per side balloons, controls feel small.

   This file installs three regimes:

     A. Flat 2-column grid layout when (width<=720) OR (height<=500). The
        deck-mounts become static brushed-steel panels under each deck, the
        vertical pitch fader unrotates into a horizontal slider, and the
        crossfader spans both columns at the bottom.
     B. Single column when (width<=600). Order: deckA, ctrlA, xfader, deckB,
        ctrlB. Crossfader between the decks so spatial A->B reads naturally
        when scrolling.
     C. Ultrawide scale-up when (width>=1800 and height>=900). Bumps deck/
        surface caps and perspective distance so the brushed-steel surface
        stays filled at large viewports.
   ========================================================================== */


/* ============================================================================
   GLOBAL — applies at every viewport.

   Kill horizontal scrolling entirely. The DJ app is a fixed-layout console;
   there is no scenario where the user should be panning sideways. Without
   this clamp, a momentary overflow in one orientation (e.g. the landscape
   2-col grid + crossfader span) leaves a horizontal scroll offset that
   persists when the device is rotated to portrait, dumping the now-narrow
   content half off the left edge of the viewport.
   ========================================================================== */
html, body {
  overflow-x: hidden !important;
  max-width: 100vw !important;
}

/* ============================================================================
   FULLSCREEN BUTTON

   The fullscreen button styles live in DJ.css (where they reliably load).
   This file used to contain the .fullscreen-btn base rules + a mobile
   override, but the bare HTML only links DJ.css — DJ-responsive.css is
   loaded via a separate mechanism that may or may not be present in
   every dev/deploy environment. To avoid the button rendering unstyled
   in any environment, all of its rules now live in DJ.css.

   The button is sized small enough by default (34px circle) that no
   mobile override is needed.
   ========================================================================== */


/* ============================================================================
   A. SHARED MOBILE/TABLET OVERRIDES — phones, tablets, and short viewports.

   Trigger has THREE legs (any one matches):
     1. width <= 1199 — phones (any orientation) and small/mid tablets.
     2. height <= 500 — phones in landscape, very short viewports.
     3. width <= 1366 AND aspect-ratio <= 16/10 — large tablets (iPad 12.9"
        and 13" models in landscape sit at 1366×1024 = 1.33:1, missing leg
        1 but caught here). The aspect-ratio guard is what excludes 1366×768
        budget laptops (1.78:1) from getting the touch-tuned layout — they
        keep using the desktop "cinematic" backdrop, which fits at that
        width because their lower vmin (768) keeps the backdrop under the
        viewport's horizontal extent.

   Why so many !important. The base DJ.css has its own `@media (max-width: 720px)`
   block that sets `display: none` on .deck-mount AND .pitch-fader-vert, plus
   its own @media-scoped overrides on .crossfader, .controls, etc. Both that
   block and ours match at the same specificity (single class selectors), and
   the base block's `display: none` will shut down our entire control layer if
   we don't explicitly assert `display: flex` ourselves. Same story for the
   absolute positioning leaking through from the desktop perspective overlay.

   This section ONLY handles overrides — the actual layout is in B (phone
   portrait single-column), B' (phone landscape 2-col), and B'' (tablet 2-col
   with bigger sizing). Sizing values here are tuned for phone; B'' overrides
   them for tablet.
   ========================================================================== */
@media (max-width: 1199px),
       (max-height: 500px),
       (max-width: 1366px) and (max-aspect-ratio: 3/2) {

  body { padding: 10px 8px; }

  /* Hide the desktop perspective backdrop. */
  .deck-backdrop { display: none !important; }

  /* Hide the legacy fallback play strip — the deck-mounts now hold the
     real controls inline. */
  .controls { display: none !important; }

  /* === DECK-MOUNT — perspective overlay → flat brushed-steel panel ===
     The base CSS has BOTH `position: absolute` (general rule) AND `display:
     none` (in its 720px media query). We need !important on display, position,
     width, height, transform — every one of these is set by the base. */
  .deck-mount {
    display: grid !important;
    position: static !important;
    width: 100% !important;
    max-width: 320px !important;
    height: auto !important;
    transform: none !important;
    z-index: auto !important;
    pointer-events: auto !important;

    /* Layout: 3-cell row on top (play | meter | songs), pitch fader full
       width below. Grid (not flex-wrap) because the children's HTML order
       is mirrored between deck A and deck B on desktop, and flex-wrap
       produced asymmetric layouts on the two panels. Grid template areas
       pin each control by name regardless of source order. */
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
      "play  meter  songs"
      "pitch pitch  pitch";
    align-items: center;
    justify-items: center;
    gap: 6px 8px;
    padding: 8px 10px;

    background: linear-gradient(180deg,
      var(--metal-hi) 0%, var(--metal) 30%, var(--metal-lo) 100%);
    border: 1px solid #000;
    border-radius: 12px;
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,0.08),
      inset 0 -1px 0 rgba(0,0,0,0.6),
      0 6px 14px rgba(0,0,0,0.5);
  }

  /* Defeat the base file's per-deck justify-content (flex-start / flex-end
     pinned the controls to the outer corners on desktop). */
  .deck-mount-a,
  .deck-mount-b { justify-content: center !important; }

  /* Pin each child to its grid area. These selectors override any HTML-
     order behavior so deck A and deck B panels look identical. */
  .deck-mount .play-wrap        { grid-area: play; }
  .deck-mount .meter-stack      { grid-area: meter; }
  .deck-mount .crate-open-btn   { grid-area: songs; }
  .deck-mount .pitch-fader-vert { grid-area: pitch; }

  /* === SONGS BUTTON ===
     Base CSS pins this with `position: absolute` plus per-deck calc()-based
     left/right rules. !important needed on position to stop it absolute-
     positioning into the bottom corner of .decks. */
  .crate-open-btn {
    position: static !important;
    bottom: auto !important;
    left: auto !important;
    right: auto !important;
    width: 50px;
    height: 50px;
    /* Scale text down with the button. Base CSS uses 11px / 0.12em for
       the 72px desktop button; without these overrides the text stays
       11px and dominates the smaller button face. */
    font-size: 8px;
    letter-spacing: 0.08em;
  }
  /* Scale the new stack-of-records icon down for the smaller mobile/tablet
     button. Base CSS sets it to 36px for the 72px desktop button
     (50%); 25px in a 50px button keeps the same proportion. */
  .crate-open-btn svg { width: 25px; height: 25px; }

  /* === PITCH FADER ===
     CRITICAL: the base @media (max-width: 720px) block sets `display: none`
     on this element. Without `display: flex !important` here, nothing else
     we set on it matters because the element isn't rendered. This was the
     reason the pitch fader was missing entirely from mobile. */
  .pitch-fader-vert {
    display: flex !important;
    position: static !important;
    flex-direction: row !important;
    align-items: center !important;

    width: 100% !important;
    height: 38px !important;
    top: auto !important;
    bottom: auto !important;

    padding: 4px 10px;
    gap: 8px;
  }
  .pitch-fader-vert-label { flex: 0 0 auto; }
  .pitch-fader-vert-area  {
    flex: 1 1 auto;
    width: auto !important;
    height: 22px !important;
    min-height: 0;
  }
  .pitch-fader-vert-value {
    flex: 0 0 auto;
    min-width: 44px;
    text-align: right;
  }

  /* Slider: undo the desktop -90deg rotation so it renders as a normal
     horizontal slider. */
  .pitch-fader-slider-vert {
    position: static !important;
    width: 100% !important;
    height: 22px !important;
    transform: none !important;
    margin: 0;
    cursor: ew-resize;
    top: auto !important;
    left: auto !important;
  }
  .pitch-fader-slider-vert::-webkit-slider-thumb { cursor: ew-resize; }
  .pitch-fader-slider-vert::-moz-range-thumb     { cursor: ew-resize; }

  /* === PLAY/TRANSPORT === */
  .deck-mount .play-wrap { gap: 6px; }
  .play-btn      { width: 50px; height: 50px; border-radius: 11px; }
  .play-btn svg  { width: 22px; height: 22px; }
  .transport-btn { width: 38px; height: 38px; border-radius: 8px; }
  .transport-btn svg { width: 14px; height: 14px; }

  /* === METER STACK === */
  .meter-stack { gap: 4px; }
  .track-counter { height: 38px; min-width: 48px; padding: 0 4px; }
  .track-counter-value { font-size: 13px; min-width: 28px; padding: 1px 4px; }

  /* === CROSSFADER ===
     Same overrides as deck-mount: defeat absolute positioning + perspective
     transform from the desktop overlay. */
  .crossfader {
    display: flex !important;
    position: static !important;
    width: 100% !important;
    max-width: 320px !important;
    height: auto !important;
    transform: none !important;

    justify-content: center;
    align-items: center;
    padding: 0;
    margin: 0;
    pointer-events: auto;
  }
  .crossfader-cluster {
    flex-direction: column !important;
    width: 100%;
  }
  .crossfader-panel {
    width: 100% !important;
    max-width: 320px !important;
    margin: 0 auto;
  }

  /* === HEADER + HINT === */
  header { margin-bottom: 6px; }
  header h1   { font-size: 18px; letter-spacing: 0.16em; }
  header .sub { font-size: 9px; }
  .hint { font-size: 10px; margin-top: 10px; padding: 0 8px; line-height: 1.5; }

  /* (Fullscreen button no longer needs a mobile override — its base size
     in DJ.css is already 34px which is a comfortable mobile tap target.) */

  /* === DECK BOX SHAPE — fix vinyl overflow on mobile ===
     The .vinyl element is `width: 100%; aspect-ratio: 1/1` (a square),
     but the base .deck has `aspect-ratio: 1.8/1` (wide-and-short). On
     desktop the brushed-steel backdrop sits behind the deck and absorbs
     the vinyl's vertical overflow visually. On mobile there's no
     backdrop, so the vinyl's bottom edge — and especially the platter,
     which is 107% of vinyl size and gets scaled up further by the
     perspective rotation — renders past the deck box and overlaps the
     controls panel below it.

     Two-part fix:
       1. aspect-ratio: 1.2/1 makes the deck box taller relative to its
          width. With deck height = W/1.2, the rendered platter's bottom
          (W*0.357 below deck center) lands ~19px above the deck bottom
          instead of right at it.
       2. margin-bottom: 16px adds a clean visual gap to the next element.

     Total clearance from rendered platter bottom to next panel: ~35px.
     This rule lives in the SHARED mobile section so phones in the
     600-720px width range (which fall between sections B and B') still
     get the fix instead of the base 1.8/1 overflow. */
  .deck-unit { width: 100%; padding: 0; align-items: center; }
  .deck {
    width: 100%;
    max-width: 320px;
    aspect-ratio: 1.2 / 1;
    margin: 0 auto 16px;
  }

  /* === PLAY-WRAP BUTTON ORDER — unify deck A and deck B on mobile ===
     The desktop layout deliberately mirrors deck B's play-wrap so both
     play buttons sit at the OUTER edges of the stereo console (left for
     A, right for B) with the meter LCDs between them. That mirroring
     means deck B's HTML order is `prev, next, play` instead of deck A's
     `play, prev, next`.

     On mobile, where both decks stack vertically and read top-to-bottom,
     the mirroring is just inconsistent — users expect identical control
     layout on both decks. Use flex `order` on deck B's play-wrap children
     to render in the same visual order as deck A (play, prev, next)
     without any HTML changes. */
  .deck-mount-b .play-wrap .play-btn          { order: 1; }
  .deck-mount-b .play-wrap [data-action="prev"] { order: 2; }
  .deck-mount-b .play-wrap [data-action="next"] { order: 3; }

  /* === SPINDLE ALIGNMENT — track the platter's vertical offset ===
     The .spindle is positioned at top:50% of .deck (deck center). The
     platter, however, gets `translate(0, 13px)` applied in DJ.js to
     compensate for the perspective rotation. But that 13px is in the
     platter's LOCAL rotated frame, so it projects to only ~7.5px on
     screen — not enough to align with the album-label center the user
     reads as "the record's middle."

     Combined with the perspective making the visible vinyl ellipse
     center sit ~12-15px below its geometric center on a ~320px-wide
     mobile deck, the spindle (anchored at deck-center) ends up looking
     20-25px above where the user expects it. Empirically tuned to 25px
     after iterating from 15. If still off, this is the only number to
     adjust. */
  .spindle {
    top: calc(50% + 25px) !important;
  }
}


/* ============================================================================
   B. PORTRAIT (and narrow desktop) — single-column flex layout.

   Each deck is grouped with its own controls (deck → ctrl → deck → ctrl) so
   the user sees a deck and its panel together as one unit. Crossfader sits
   at the END so it doesn't drive a wedge between deck A's controls and deck
   B (which previously caused a "big black gap" mid-page).

   Using flex with `order:` instead of grid template areas. The key reason:
   .deck-mount-a and .deck-mount-b are SIBLINGS of the deck-units, not
   children, but their position in the document is interleaved with them
   (mount-a, mount-b, deck-a, deck-b). `order` lets us interleave
   visually without changing DOM, and is simpler than grid for a 1-col flow.
   ========================================================================== */
@media (max-width: 600px) {

  .decks {
    display: flex !important;
    flex-direction: column !important;
    flex-wrap: nowrap !important;
    align-items: center;
    gap: 8px;
    width: 100%;
    max-width: 380px;
  }

  .deck-unit[data-deck="a"]  { order: 1; }
  .deck-mount-a              { order: 2; }
  .deck-unit[data-deck="b"]  { order: 3; }
  .deck-mount-b              { order: 4; }
  .crossfader                { order: 5; }

  .deck-unit { width: 100%; padding: 0; align-items: center; }

  /* aspect-ratio (1.2/1) and margin-bottom (16px) inherit from
     section A above. Only override max-width here to use 86vw cap
     for narrow phones where 320px would crowd the screen edges. */
  .deck {
    width: 100%;
    max-width: min(86vw, 320px);
  }

  .deck-mount       { max-width: min(86vw, 320px) !important; }
  .crossfader,
  .crossfader-panel { max-width: min(86vw, 320px) !important; }
}


/* ============================================================================
   B'. LANDSCAPE PHONE — 2-column grid layout.

   Side-by-side decks with their controls below each, crossfader spanning
   both columns. Vertical space is at a premium (CSS height ~390-420 on
   most phones in landscape) so we shrink controls and hide the hint.
   ========================================================================== */
@media (max-height: 500px) and (orientation: landscape) {

  .decks {
    display: grid !important;
    flex-direction: unset !important;
    flex-wrap: unset !important;
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "deckA  deckB"
      "ctrlA  ctrlB"
      "xfader xfader";
    gap: 4px 10px;
    width: 100%;
    max-width: 100%;
    align-items: start;
    justify-items: center;
  }

  /* `order` from section B doesn't apply to grid items — grid uses
     grid-area instead. Reset just to be safe. */
  .deck-unit[data-deck="a"]  { grid-area: deckA; order: unset; }
  .deck-unit[data-deck="b"]  { grid-area: deckB; order: unset; }
  .deck-mount-a              { grid-area: ctrlA; order: unset; }
  .deck-mount-b              { grid-area: ctrlB; order: unset; }
  .crossfader                { grid-area: xfader; order: unset; }

  body { padding: 4px 6px; }
  header { margin-bottom: 2px; }
  header h1  { font-size: 13px; letter-spacing: 0.12em; }
  header .sub { display: none; }
  .hint       { display: none; }

  .deck-unit { width: 100%; padding: 0; align-items: center; }

  /* aspect-ratio (1.2/1) inherits from section A. Override max-width
     (smaller for 2-col grid) and tighten margin-bottom — landscape
     vertical space is at a premium so we want the controls panel
     close beneath the deck, just past the platter's visual extent. */
  .deck {
    width: 100%;
    max-width: 240px;
    margin: 0 auto 8px;
  }

  .deck-mount {
    max-width: 280px !important;
    padding: 5px 8px !important;
    gap: 4px 6px !important;
  }
  .crossfader,
  .crossfader-panel { max-width: 280px !important; }

  /* Spindle override — section A sets +25px which works for portrait
     where decks are ~310px wide. Landscape caps decks at 240px so the
     perspective math is smaller (visual ellipse center sits ~7px below
     deck-center instead of ~12px), and 25px ends up putting the pin
     too far down. Empirically tuned to 18px. */
  .spindle {
    top: calc(50% + 18px) !important;
  }

  /* Even more compact controls for short viewport. */
  .play-btn      { width: 42px; height: 42px; }
  .play-btn svg  { width: 18px; height: 18px; }
  .transport-btn { width: 32px; height: 32px; }
  .transport-btn svg { width: 12px; height: 12px; }
  .track-counter { height: 32px; min-width: 42px; }
  .track-counter-value { font-size: 12px; }
  .pitch-fader-vert { height: 32px !important; }
  .crate-open-btn {
    width: 42px;
    height: 42px;
    font-size: 7px;
    letter-spacing: 0.06em;
  }
  .crate-open-btn svg { width: 21px; height: 21px; }
}


/* ============================================================================
   B''. TABLET — 601-1366 wide, aspect <= 16/10, taller than 500.

   Covers iPad in BOTH orientations across every current model (iPad mini
   1133px landscape, iPad Air 11" 1180, iPad Pro 11" 1194, iPad Air 13"
   and Pro 13" both 1366). The (max-aspect-ratio: 3/2) guard distinguishes
   tablets from wide laptops at the same width: a 1366×768 budget laptop
   has aspect 1.78:1 (16/9), exceeds 16/10, and skips this section to keep
   its desktop layout. iPads at 1366×1024 are 1.33:1 (4/3), well under
   16/10, and match.

   Layout strategy: 2-column grid like B' (decks side-by-side, controls
   below each, crossfader spanning), but with substantially bigger
   sizing — tablets have plenty of horizontal AND vertical room, so
   the 240px deck cap from phone-landscape would look comically small.
   Sized via clamp() so the layout scales smoothly across the 601-1366
   range without breakpoint stepping.
   ========================================================================== */
@media (min-width: 601px) and (max-width: 1366px)
       and (max-aspect-ratio: 3/2) and (min-height: 501px) {

  .decks {
    display: grid !important;
    flex-direction: unset !important;
    flex-wrap: unset !important;
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "deckA  deckB"
      "ctrlA  ctrlB"
      "xfader xfader";
    gap: 20px 32px;
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    align-items: start;
    justify-items: center;
  }

  /* Grid placement — `order` from section B doesn't apply to grid items. */
  .deck-unit[data-deck="a"]  { grid-area: deckA; order: unset; }
  .deck-unit[data-deck="b"]  { grid-area: deckB; order: unset; }
  .deck-mount-a              { grid-area: ctrlA; order: unset; }
  .deck-mount-b              { grid-area: ctrlB; order: unset; }
  .crossfader                { grid-area: xfader; order: unset; }

  body { padding: 16px 20px; }

  /* Headers stay readable, not shrunk to phone-size. */
  header { margin-bottom: 12px; }
  header h1   { font-size: 24px; letter-spacing: 0.18em; }
  header .sub { font-size: 11px; }
  .hint { font-size: 11px; margin-top: 12px; padding: 0 12px; line-height: 1.6; }

  /* Decks are the centerpiece — give them generous size. clamp() means
     small tablets get ~280px decks and big ones get up to ~480px,
     scaling linearly with viewport in between. */
  .deck-unit { width: 100%; padding: 0; align-items: center; }
  .deck {
    width: 100%;
    max-width: clamp(280px, 42vw, 480px);
    margin: 0 auto 16px;
  }

  /* Control panels match deck width so they read as visually grouped
     with the deck above them. */
  .deck-mount {
    max-width: clamp(280px, 42vw, 480px) !important;
    padding: 12px 16px !important;
    gap: 8px 12px !important;
  }
  .crossfader,
  .crossfader-panel {
    max-width: clamp(360px, 56vw, 600px) !important;
  }

  /* Slightly larger touch targets than phone — tablets are often used
     with finger taps too, but space allows for less cramped controls. */
  .play-btn      { width: 56px; height: 56px; }
  .play-btn svg  { width: 24px; height: 24px; }
  .transport-btn { width: 44px; height: 44px; }
  .transport-btn svg { width: 16px; height: 16px; }
  .track-counter { height: 40px; min-width: 56px; }
  .track-counter-value { font-size: 14px; }
  .crate-open-btn {
    width: 56px;
    height: 56px;
    font-size: 9px;
    letter-spacing: 0.1em;
  }
  .crate-open-btn svg { width: 28px; height: 28px; }

  /* Fullscreen button: keeps the default pill sizing on ultrawide (36px tall
     with the FULLSCREEN/EXIT FS label visible). No size override needed.
     The previous rule here forced top/right offsets that no longer apply
     since the button is now anchored inside the header. */

  /* Spindle — must scale with deck size, since the perceived offset
     between deck-center (where the pin anchors) and the visual record
     center grows linearly with deck width. From the phone data points:
     240px deck wants +18, 310px deck wants +25 — a clean fit at
     `0.1 × deck_width − 6`.

     Deck on tablet is clamp(280px, 42vw, 480px). Substitute into the
     formula: offset = 0.1 × clamp(280, 42vw, 480) − 6
                     = clamp(22, 4.2vw − 6, 42).

     This makes the spindle offset ride the same clamp curve as the deck
     itself — small iPad mini sizes get +22, full 13" iPad landscape
     gets +42, everything in between scales linearly with viewport width. */
  .spindle {
    top: calc(50% + clamp(22px, calc(4.2vw - 6px), 42px)) !important;
  }
}


/* ============================================================================
   C. HIGH-RES — width>=1800 AND height>=900.
   Catches 1080p-class landscape monitors and up.

   Tweakable knob: --console-scale.

   What it does. The base file caps decks at 624px and the backdrop at
   1700×780 — sizes tuned for laptop-class viewports. On a 1440p+ monitor
   those caps freeze the console well below screen size. This rule lets
   you scale the whole console (deck + backdrop, all proportionally) by
   a single multiplier so you can pick the size that looks right on your
   display without breaking proportions.

       --console-scale: 0.85   compact. Console occupies less of the screen.
       --console-scale: 1.00   base sizes. Console at original dimensions.
       --console-scale: 1.15   bumps up slightly. Records noticeably bigger,
                               steel grows with them.
       --console-scale: 1.30+  approaches the look of 200% display mag —
                               beyond this point the caps stop saturating
                               at 1440p (vmin takes over) and the proportions
                               start to drift.

   The variable scales BOTH deck size and backdrop size by the same factor.
   That's important: the vinyl uses perspective(1000px) and the backdrop
   uses perspective(1600px), so the two don't render at proportional visual
   sizes if you change them independently — vinyl outgrows backdrop and
   spills over the bottom. Scaling both together preserves the tuned ratio
   regardless of where you set --console-scale.

   Adjust the value on the line below, save, and refresh. Try a few values
   to find what looks right on your display.
   ========================================================================== */
@media (min-width: 1800px) and (min-height: 900px) {

  :root {
    /* === ADJUST THIS to taste. === */
    --console-scale: 0.85;

    /* Derived caps — don't edit these directly. */
    --deck-cap:        calc(624px * var(--console-scale));
    --backdrop-w-cap:  calc(1700px * var(--console-scale));
    --backdrop-h-cap:  calc(780px * var(--console-scale));
  }

  /* Pull the decks apart so the platters don't crowd each other.
     The base column gap is 40px, but the .platter element is 107% of
     deck width — at any scale that means each platter overhangs its deck
     box by ~3.5% on each side, eating ~37px out of that 40px gap. The
     perspective tilt then flares the bottom edges further inward, making
     the strobe rings on the inner side of each platter look like they
     almost touch.

     80px column gap leaves ~60px of clear visible space between the
     two platter images. Still well within the .decks max-width budget. */
  .decks { gap: 24px 80px; }

  .deck { width: min(58vmin, var(--deck-cap)); }

  .deck-backdrop,
  .deck-mount,
  .crossfader {
    width:  min(160vmin, var(--backdrop-w-cap));
    height: min(80vmin,  var(--backdrop-h-cap));
  }

  /* The pitch slider's pre-rotation `width` (which becomes its rendered
     vertical length after the -90° rotation) is hard-coded at 100px in
     the base CSS. The chassis it sits in stretches between top:80 and
     bottom:200 of the deck-mount, so on a 1440p screen the chassis is
     ~380px tall but the slider track is only 100px — leaving big empty
     dark zones above and below the thumb. Scale the slider with vmin so
     the visible track fills most of the chassis, with comfortable
     breathing room top and bottom. clamp() bounds it so the slider
     doesn't get absurdly long on huge monitors or too short on tighter
     ones if you tweak --console-scale. */
  .pitch-fader-slider-vert {
    width: clamp(160px, 22vmin, 320px);
  }

  /* Header scales modestly so it reads at arm's length on a 27"+ panel. */
  header h1 { font-size: clamp(26px, 2.2vw, 38px); }
}


/* ============================================================================
   CRATE GRID — small-screen tweaks.

   The base CSS in DJ.css now ships a single responsive grid:
     `grid-template-columns: repeat(auto-fill, minmax(clamp(130px, 22vw, 180px), 1fr))`
   This gives 2 columns on a phone, 3-4 on a tablet, 5-6 on a laptop, and
   6+ on a desktop — all without media queries or JS. The grid scrolls
   vertically inside .crate-viewport.

   The previous file had three separate regimes here (horizontal scroll-snap
   carousel, 5-column desktop grid, mobile sizing patch) that each needed
   `!important` to defeat the base stylesheet's perspective+absolute layout.
   That whole structure is gone. This block is now JUST the mobile tweaks
   needed to stop the crate from overflowing very short viewports.

   Trigger matches the previous file's three-leg targeting so iPads (13" in
   landscape at 1366×1024 included) get the compact crate, AND any narrow
   phone in landscape (height ≤ 500) gets the same.
   ========================================================================== */
@media (max-width: 1199px),
       (max-height: 500px),
       (max-width: 1366px) and (max-aspect-ratio: 3/2) {

  .crate-overlay {
    /* `safe center` falls back to `start` if centering would push content
       off-screen — prevents the half-off-top symptom on short viewports. */
    align-items: safe center !important;
    overflow-y: auto;
    padding: 8px 0;
  }

  .crate {
    /* Use dvh to account for mobile address bars; clamp to viewport. */
    width: 96vw !important;
    height: calc(100dvh - 16px) !important;
    padding: 14px 12px 12px !important;
    gap: 8px !important;
  }

  /* Tighter grid gaps and smaller minimum column on small screens —
     ensures 2 columns fit at 360px-ish phone widths. */
  .crate-track {
    gap: 10px !important;
    grid-template-columns: repeat(auto-fill, minmax(clamp(110px, 28vw, 160px), 1fr)) !important;
  }

  /* Smaller close button, closer to the corner. */
  .crate-close {
    width: 32px !important;
    height: 32px !important;
    top: 10px !important;
    right: 10px !important;
    font-size: 14px !important;
  }
}