/* The record table takes over the player, below the header: the player's controls lie on the decks and the
   mixer on its table, so the panel is not shown meanwhile, nor reached with Tab or by a screen reader. Its
   own rules for each orientation and for karaoke (tablet-controls.css, which loads later) set its display
   with three classes: this one takes four, so it wins in all of them. */
.tablet-crate { position: absolute; inset: 0; z-index: 2; }
.tablet-crate[hidden] { display: none; }
.tablet.is-crate :is(.tablet-listening, .tablet-playlist) { visibility: hidden; }
.tablet.is-crate .tablet-body > .tablet-portrait-controls { display: none; }
.tablet-header #tabletCrate[aria-pressed="true"] { color: var(--tablet-active); }

.crate-room {
  --R: 140px; --cw: 168px; --cd: 110px; --tw: 1493px; --td: 840px; --th: 119px; --ttw: 292px; --ttd: 255px; --tth: 17px; --ttf: 6px; --tbd: 81px;
  --mxw: 196px; --mxh: 14px; --fxr: 59px; --plw: 808px; --pld: 182px; --spw: 218px; --sph: 630px; --fk: .875; --swh: 44px; --swt: 100px;
  /* The keys' glyphs, all one size, and the cells of a deck's transport row (crate.css, the flat panels). */
  --glyph: calc(var(--R) * .13); --key: calc(var(--R) * .36); --key-row: calc(var(--R) * .325);
  /* Clipped, not scrollable: focus moving to a plate off screen must not scroll the room askew. */
  position: absolute; inset: 0; overflow: hidden; overflow: clip; color: var(--ink); font: 300 15px/1.4 var(--font);
}
/* Every object in the room is one matte clay, as if rendered at once, never another hue; only the records
   keep their artwork and the crates their poster plates. Two sets of it: the room's (the ground it stands
   on, --ground: the wall, the floor and all round; the table; the shelf with its crates and its panel; the
   switch between the views; a record's card) follows the theme, light by day and true black at night; the
   players' (the turntables, the mixer and the playlists: what plays) are white in both, with dark ink on
   them, so at night white players stand on a black table. Each set is declared on what it colours, so the
   tones made from it (--line, --muted, --faint) are its own.

   By day one soft light hangs above the table, so faces differ by small steps of lightness, by where they
   turn and how high they stand: the lightest (--clay-1) for parts raised out of a face (the tonearm, the
   crossfader's knob), then the tops of what stands or lies on the table (--clay-2), the faces turned up of
   the unit and the crates' lit walls (--clay-3), faces towards the viewer and what is pressed into the clay
   (--clay-4), sideways faces (--clay-5), the backs of the cubbies and the crates' floors (--clay-6), and the
   deepest shade, under a turntable's slab (--clay-7). The ground lies a step under the table, the table's
   top (--table-top) under what stands on it, its sides (--table-side) under its top, its edges a fine matte
   line (--table-edge); the ground's own ink (--ground-ink, and stronger under the pointer) draws the
   switch on it. */
.crate-room, .crate-room :is(.crate-turntable, .dj-mixer, .room-playlist) {
  --clay-1: #fcfcfc; --clay-2: #f5f5f5; --clay-3: #efefef; --clay-4: #e8e8e8; --clay-5: #e1e1e1; --clay-6: #d9d9d9; --clay-7: #cfcfcf;
  --ground: #dadada;
  --table-top: var(--clay-3); --table-side: var(--clay-5); --table-edge: var(--edge-lit); --ground-ink: #4a4a4a; --ground-ink-strong: #1f1f1f;
  /* Type, the small dark marks (the arm's mark, the dots of toggles that are on) and the rings round what
     has the keyboard focus (--target, --ring) or takes a record (--room-target, round a turntable, on the
     table): dark on the light clay, light on the black. On every grey they lie on, type keeps at least
     7:1, the rings at least 6:1. */
  --ink: #474747; --mark: #2e2e2e; --target: #2b2b2b; --room-target: #2b2b2b; --ring: max(2px, calc(var(--R) * .018)) solid var(--target);
  /* The players' ink, kept apart from the room's (which turns light at night): what stands on a white
     player in the room's layer (a dancer beside a spinning record) takes it in both themes. */
  --player-ink: #474747;
  /* The flat panels' (the decks' bands, the mixer's top, the playlists and the shelf's panel) lines between
     their cells, and their muted type (4.5:1 on their clay), both of the ink and the clay. */
  --line: color-mix(in srgb, var(--ink) 25%, var(--clay-2)); --muted: color-mix(in srgb, var(--ink) 80%, var(--clay-2));
  /* What cannot be used: a key's glyph, a timeline's dot, faint but still there. */
  --faint: color-mix(in srgb, var(--ink) 32%, var(--clay-2));
  /* Shapes read by their shade, all of one colour (--shadow): occlusion where faces meet (--ao,
     --ao-soft), a fine shade along clay edges (--rim) and light along the top edges (--edge-lit); soft
     shadows cast a little towards the viewer, as the light is above the table, wider and further the
     higher a thing stands: records and sleeves lying on the table (--lift-1), parts raised out of a face
     with their rim (--lift-2), what stands on the table (--lift-3), and what stands higher or is held up
     over it (--lift-4); what is pressed in lies in its own shade (--press). No gloss, no sheen, no glow. */
  --shadow: #00000030; --ao: #00000021; --ao-soft: #00000010; --rim: #00000014; --edge-lit: #ffffffb3;
  --lift-1: 0 calc(var(--R) * .006) calc(var(--R) * .05) var(--shadow);
  --lift-2: 0 calc(var(--R) * .012) calc(var(--R) * .035) var(--shadow), inset 0 0 0 1px var(--rim);
  --lift-3: 0 calc(var(--R) * .025) calc(var(--R) * .1) var(--shadow), 0 0 calc(var(--R) * .025) var(--shadow);
  --lift-4: 0 calc(var(--R) * .05) calc(var(--R) * .2) var(--shadow), 0 0 calc(var(--R) * .04) var(--shadow);
  --press: inset 0 calc(var(--R) * .01) calc(var(--R) * .03) var(--shadow), inset 0 0 0 1px var(--rim);
  /* Corners: the turntables' and the mixer's round like the drawing on a turntable (TURNTABLE.round over
     its landscape width, 5 / 167), the panels' cells square; pills (tracks) round fully, a radius CSS
     scales down to half their height. */
  --round: calc(var(--ttw) * 5 / 167); --round-wide: calc(var(--R) * .12); --pill: var(--R);
  /* The turntables' canvas (turntable-visual.js) reads its colours here, on the turntable: the clay of the
     slab and its raised parts, the bare platter pressed into it, the fine line along the slab's edge, the
     record (dark, so it reads as a record on the white slab), its grooves and its label. */
  --deck-top: var(--clay-2); --deck-ink: var(--ink); --deck-mark: var(--mark); --deck-arm: var(--clay-1); --deck-platter: var(--clay-4);
  --deck-shadow: var(--shadow); --deck-rim: var(--rim); --deck-record: #1b1b1b; --deck-groove: #ffffff1c; --deck-label: var(--clay-1); --deck-edge: var(--edge-lit);
}
/* At night the room is true black: the ground, the table, the shelf and its crates all #000, every face of
   them, for the forms are not lit apart by lighter faces but drawn with fine dark grey lines (--edge-lit
   along the edges where a form turns, --rim round the crates' walls and the records, --table-edge round the
   table, --line between the panel's cells): a hairline, matte, never a glow. Shadows are black on black.
   The type and the switch are light on it. The players are not part of this: they stay white (above). */
html[data-tablet-theme="night"] .crate-room {
  --clay-1: #000000; --clay-2: #000000; --clay-3: #000000; --clay-4: #000000; --clay-5: #000000; --clay-6: #000000; --clay-7: #000000;
  --ground: #000000;
  --table-top: #000000; --table-side: #000000; --table-edge: #333333; --ground-ink: #e6e6e6; --ground-ink-strong: #ffffff;
  --ink: #d0d0d0; --mark: #e2e2e2; --target: #e0e0e0; --room-target: #e0e0e0;
  --line: color-mix(in srgb, var(--ink) 25%, var(--clay-2)); --muted: color-mix(in srgb, var(--ink) 80%, var(--clay-2)); --faint: color-mix(in srgb, var(--ink) 32%, var(--clay-2));
  --shadow: #00000000; --ao: #00000000; --ao-soft: #00000000; --rim: #333333; --edge-lit: #333333;
}
/* The eye looks through the screen origin; the script moves perspective origin and room there. Behind the
   room the ground carries on, however far out the camera goes. */
.crate-view {
  position: absolute; inset: 0; perspective-origin: 50% 50%; touch-action: none; user-select: none; -webkit-user-select: none; cursor: grab;
  background: var(--ground);
}
.crate-view.is-panning { cursor: grabbing; }
.crate-table { position: absolute; left: 50%; top: 50%; width: 0; height: 0; transform-style: preserve-3d; }
/* One plain room: a floor and the wall behind the unit, both the ground. A tap on them picks nothing:
   each view shows its own part of the room (tapView). */
.crate-surface { position: absolute; background: var(--ground); }
/* Turned up from the floor line: its top edge is the floor, y the height. */
.room-wall { position: absolute; transform-origin: 50% 0; transform: rotateX(90deg); background: var(--ground); }
/* Things too close to the eye, or behind it, hide instead of tearing. */
.crate-room .is-culled { visibility: hidden; }

/* The wall unit, a belt of crates on a closed plinth: per place along it a fixed frame (the plinth's front,
   the boards of the rows with the ceilings under them and their backs, the top board), the panel at its
   left end and the closed end at its right, and the belt's columns moving along the boards in front of the backs, each its crates, built from
   flat faces the script places (flat ones lie at a height, front ones face the viewer, side ones face
   along u). Containers keep the 3D space; colours sit on the faces. The room's clay, shaded by where a
   face turns and darkest in the corners. In a face's own box, flat ones run from the back (top) to the
   front, front ones from the top down, and side ones along their height (from the board at the left, or
   at the right with `is-right`) and from the back down. */
.room-unit, .ru-column, .ru-belt, .ru-slot { position: absolute; left: 0; top: 0; transform-style: preserve-3d; }
.ru-column > div, .room-unit > .ru-back { position: absolute; }
.ru-flat {
  background: linear-gradient(to bottom, var(--ao), transparent calc(var(--R) * .35)), var(--clay-3);
}
.ru-board-top { background: linear-gradient(to bottom, var(--ao-soft), transparent calc(var(--R) * .3)), var(--clay-3); }
/* Front edges catch the light along the top. */
.ru-front { transform-origin: 50% 100%; background: linear-gradient(var(--edge-lit) 0 1px, transparent 1px), var(--clay-4); }
.ru-plinth { background: linear-gradient(var(--edge-lit) 0 1px, transparent 1px calc(100% - var(--R) * .35), var(--ao)), var(--clay-4); }
.ru-side { transform-origin: 0 50%; }
.ru-side.is-right { transform-origin: 100% 50%; }
.ru-outside { background: linear-gradient(to bottom, var(--ao-soft), transparent calc(var(--R) * .3)), var(--clay-5); }
/* Above the panel, where the unit is taller, and the closed end at its right that the belt goes round
   behind: a plain front, lit along its top edge. Its lip below the top board and the plinth's lip above
   the floor show the frame's thickness in front of the belt. */
.ru-cap { background: linear-gradient(var(--edge-lit) 0 1px, transparent 1px calc(100% - 1px), var(--ao-soft) calc(100% - 1px)), var(--clay-4); }
.ru-lip { background: var(--clay-4); }
.ru-under { background: var(--clay-5); }
/* A row: its ceiling seen from below lies in shade, deepest at the back; its back has a band of light in
   the middle and shade under the ceiling and over the board. */
.ru-ceiling { background: linear-gradient(to bottom, var(--ao), transparent calc(var(--R) * .35)), var(--clay-5); }
.ru-cabin-back {
  background:
    linear-gradient(to bottom, var(--ao), transparent calc(var(--R) * .24) calc(100% - var(--R) * .25), var(--ao)),
    linear-gradient(var(--clay-6), var(--clay-5) 55%, var(--clay-6));
}
/* The back panel behind the rows. */
.ru-back { background: var(--clay-6); }
/* Switched between the belt and every crate at once, the unit fades out, is built anew and fades in: the
   script writes how far it shows (--unit-fade) onto the unit, and every face takes it, never a container,
   which it would flatten. The records in the crates take it with their own fade; the panel stays. */
.room-unit :is(.ru-front, .ru-side, .ru-flat, .ru-ceiling, .ru-lip, .crate-floor, .crate-wall) { opacity: var(--unit-fade, 1); }

/* Boxes: the table, the turntables and the mixer stand on the floor plan, the playlists lie flat on the
   table. A box has four side faces --z high around its footprint. */
.room-table, .crate-turntable, .dj-mixer, .room-playlist { position: absolute; transform-style: preserve-3d; }
.box-face { position: absolute; }
.box-face.is-front { left: 0; bottom: 0; width: 100%; height: var(--z); transform-origin: 50% 100%; transform: rotateX(-90deg); }
.box-face.is-back { left: 0; top: 0; width: 100%; height: var(--z); transform-origin: 50% 0; transform: rotateX(90deg); }
.box-face.is-left { left: 0; top: 0; width: var(--z); height: 100%; transform-origin: 0 50%; transform: rotateY(-90deg); }
.box-face.is-right { right: 0; top: 0; width: var(--z); height: 100%; transform-origin: 100% 50%; transform: rotateY(90deg); }

/* A box casts a soft shadow round its foot, on a leaf of its own just above what it stands on: the
   turntables and the mixer the shadow of what stands on the table; under a turntable's slab the table
   lies in shade. The table stands on the ground without a shadow; the playlists lie flat and cast none. */
.crate-turntable::after, .dj-mixer::after {
  content: ''; position: absolute; inset: 0; transform: translateZ(.5px); pointer-events: none;
  border-radius: var(--round); background: var(--shadow); box-shadow: var(--lift-3);
}

/* The table: one plain block down to the floor, 16:9, its top a step off the ground with a fine matte line
   along its edges, its sides a step darker, lined along their top edges where they meet the top. Side faces run up from the floor at the left (is-left) or at the right
   (is-right). Light by day, black at night, a step under what stands on it. */
.room-table { --z: var(--th); width: var(--tw); height: var(--td); }
.rt-top { position: absolute; inset: 0; transform: translateZ(var(--th)); box-shadow: inset 0 0 0 1px var(--table-edge); background: var(--table-top); }
.room-table .box-face { background: var(--table-side); }
.room-table .rt-front { background: linear-gradient(var(--table-edge) 0 1px, transparent 1px), var(--table-side); }
.room-table .rt-left { background: linear-gradient(to left, var(--table-edge) 0 1px, transparent 1px), var(--table-side); }
.room-table .rt-right { background: linear-gradient(to right, var(--table-edge) 0 1px, transparent 1px), var(--table-side); }

/* A crate: floor, four walls, and the records standing in it. Every container keeps the 3D space;
   opacity sits on the faces, since opacity on a container would flatten it. The room's clay: under the
   light above the table the back wall's inside faces the viewer and is lit, the side walls are a step
   darker, every wall darkens towards the floor, and the rims catch the light. The crate's soft shadow
   lies on the board behind and beside it, never in front of the unit. It stands on a board of the wall
   unit and moves along it with the belt. */
.crate-box {
  position: absolute; width: var(--cw); height: var(--cd); transform-style: preserve-3d;
  --plate: var(--crate-paint, var(--clay-3));
}
/* White on the poster orange reads too faint (4.1:1): its plate is a shade deeper, 4.9:1. The sleeves
   keep the palette; the script writes each crate's paint into its style attribute. */
.crate-box[style*="#d94f2b"] { --plate: #c4461f; }
.crate-floor {
  position: absolute; inset: 0; background: var(--clay-6);
  box-shadow: inset 0 0 calc(var(--R) * .2) var(--ao), 0 calc(var(--R) * -.05) calc(var(--R) * .08) var(--shadow);
}
.crate-wall { position: absolute; margin: 0; padding: 0; border: 1px solid var(--rim); border-radius: 0; box-shadow: none; background: var(--clay-4); }
.crate-wall-back {
  left: 0; top: 0; width: var(--cw); height: calc(var(--R) * .44); transform-origin: 50% 0; transform: rotateX(90deg);
  background: linear-gradient(to bottom, var(--clay-5), var(--clay-3)); box-shadow: inset 0 -2px 0 var(--edge-lit);
}
.crate-wall-left {
  left: 0; top: 0; width: calc(var(--R) * .44); height: var(--cd); transform-origin: 0 50%; transform: rotateY(-90deg);
  background: linear-gradient(to right, var(--clay-5), var(--clay-4)); box-shadow: inset -2px 0 0 var(--edge-lit);
}
.crate-wall-right {
  right: 0; top: 0; width: calc(var(--R) * .44); height: var(--cd); transform-origin: 100% 50%; transform: rotateY(90deg);
  background: linear-gradient(to left, var(--clay-5), var(--clay-4)); box-shadow: inset 2px 0 0 var(--edge-lit);
}
/* The front plate carries the category in its own poster colour, lit along its top edge. */
.tablet .crate-wall-front {
  left: 0; bottom: 0; width: var(--cw); height: calc(var(--R) * .34); transform-origin: 50% 100%; transform: rotateX(-90deg);
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; padding: 0 8%;
  background: linear-gradient(var(--edge-lit) 0 1px, transparent 1px 72%, #00000030), var(--plate);
  color: var(--crate-ink, var(--ink)); text-align: left; cursor: grab;
}
.crate-wall-front b { max-width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: 700 calc(var(--R) * .12)/1 var(--font); letter-spacing: -.04em; }
.crate-wall-front small { opacity: .9; font-size: max(10px, calc(var(--R) * .07)); line-height: 1; font-variant-numeric: tabular-nums; }
/* The keyboard ring sits a little inside the plate's edge, clear of the focused-crate frame along it. */
.crate-wall-front:focus-visible { outline: 3px solid var(--crate-ink, var(--target)); outline-offset: -9px; }
.crate-records { position: absolute; inset: 0; transform-style: preserve-3d; }
.crate-rec {
  position: absolute; left: calc((var(--cw) - var(--R)) / 2); top: calc(var(--cd) - var(--R) * 1.1);
  width: var(--R); height: var(--R); transform-origin: 50% 100%; transform-style: preserve-3d; cursor: pointer;
}
.crate-rec.is-front { cursor: grab; }
.crate-rec.is-out { visibility: hidden; }
/* Flipped records fade away; taps go through them to the front record. */
.crate-rec.is-flipped { pointer-events: none; }
.crate-face, .crate-back { position: absolute; inset: 0; overflow: hidden; backface-visibility: hidden; -webkit-backface-visibility: hidden; opacity: calc(var(--fade, 1) * var(--unit-fade, 1)); }
.crate-face { background: var(--clay-5); box-shadow: inset 0 0 0 1px var(--rim); }
.crate-face img { display: block; width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
/* Sleeves fall into the crate's shade towards their foot and towards the back: matte, no light on them. */
.crate-rec .crate-face::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, transparent 32%, var(--ao)), rgb(0 0 0 / var(--shade, 0));
}
/* The back of a flipped record: plain clay paper, its artist and title printed in the room's ink. */
.crate-back {
  transform: rotateX(180deg); display: flex; flex-direction: column; justify-content: flex-end; gap: 2px; padding: 9%;
  background: linear-gradient(to bottom, var(--clay-2), var(--clay-4)); color: var(--ink); font-size: calc(var(--R) * .06); line-height: 1.2;
}
.crate-back b { font-weight: 700; }
.crate-type {
  display: flex; flex-direction: column; justify-content: space-between; width: 100%; height: 100%; padding: 9%;
  background: var(--sleeve); color: var(--sleeve-ink);
}
.crate-type b {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; overflow: hidden; overflow-wrap: anywhere;
  font: 700 calc(var(--R) * .12)/.95 var(--font); letter-spacing: -.045em;
}
.crate-type span {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
  font: 300 calc(var(--R) * .065)/1.15 var(--font);
}
.crate-loading { opacity: calc(.35 * var(--unit-fade, 1)); }

/* Records lying on the table: the soft shadow of what lies flat (the light is above), the widest for
   one lifted or in the air. Focus rings take the target ink: dark on the light table by day, light at
   night. */
.crate-bodies { position: absolute; left: 0; top: 0; transform-style: preserve-3d; }
.tablet .table-rec {
  position: absolute; left: 0; top: 0; width: var(--R); height: var(--R); padding: 0; border: 0; border-radius: 0;
  background: none; cursor: grab; box-shadow: var(--lift-1);
}
.tablet .table-rec.is-held { cursor: grabbing; box-shadow: var(--lift-4); }
.table-rec .crate-face, .deck-sleeve .crate-face { backface-visibility: visible; }
.table-rec:focus-visible, .deck-sleeve:focus-visible { outline: 2px solid var(--target); outline-offset: 3px; }
.tablet .table-rec.is-flying { pointer-events: none; box-shadow: var(--lift-4); }
/* The dancers (table-dancers.js): stick figures lying flat on the table, each on the edge of what it
   stands on, a leaf of its own in the room's 3D space (their layer only keeps that space). They take the
   room's ink, dark on the light table by day and light on the black at night, and the players' where one
   stands on a white turntable; no shadow, no glow. They take no pointer but on a slim grip round each body
   (.cd-grip), so a press beside one goes through to the key or record under it. One with nowhere to stand
   fades away and back in elsewhere. */
.crate-dancers { position: absolute; left: 0; top: 0; transform-style: preserve-3d; pointer-events: none; }
.crate-dancer { position: absolute; left: 0; top: 0; transform-origin: 0 0; color: var(--ink); pointer-events: none; transition: opacity .2s linear; }
.crate-dancer.is-on-player { color: var(--player-ink); }
.crate-dancer.is-away { opacity: 0; }
/* The hand takes hold of a dancer by a slim area round its body, and carries it. */
.crate-dancer .cd-grip { position: absolute; pointer-events: auto; cursor: grab; touch-action: none; }
.crate-dancer.is-away .cd-grip, .crate-view.is-panning .cd-grip { pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .crate-dancer { transition: none; } }
/* The sleeve of the record on a turntable, flat on the table behind it, its front under the turntable. */
.tablet .deck-sleeve {
  position: absolute; left: 0; top: 0; width: var(--R); height: var(--R); padding: 0; border: 0; border-radius: 0;
  background: none; cursor: grab; box-shadow: var(--lift-1);
}
.deck-sleeve[hidden] { display: none; }
/* The crate the camera is close to: a frame along its plate's edge, outside the keyboard focus ring. */
.crate-box.is-focused .crate-wall-front::after {
  content: ''; position: absolute; inset: 0; border: 2px solid var(--crate-ink, var(--ink)); pointer-events: none;
}


/* The turntable: a landscape slab of matte clay on the table, its top the plan view drawn on a canvas
   (turntable-visual.js, which draws it turned as it lies) with the deck's band lying flat over the front
   of it, its sides rounding off from the top's colour into their shade. Its corners are rounded like the
   drawing's (--round): its flat sides stop where the corners start, and each corner is a quarter round
   of narrow faces (.box-arc), so no corner shows past the top; the mixer shares the radius. The slab stands --ttf high on a base set back from its edges, in its shade
   (the script places it), so the sleeve of its record slides into the gap under its back edge and no leg
   shows. Side faces run up from the table at the left (is-left) or at the right (is-right). */
.crate-turntable { width: var(--ttw); height: var(--ttd); transform: translateZ(var(--th)); }
.tt-base { --z: var(--ttf); position: absolute; transform-style: preserve-3d; }
.tt-base .box-face { background: var(--clay-7); }
.tt-body { --z: calc(var(--tth) - var(--ttf)); position: absolute; inset: 0; transform: translateZ(var(--ttf)); transform-style: preserve-3d; }
.tt-body .box-face, .dj-mixer .box-face { background: var(--clay-4); }
.tt-body :is(.tt-front, .tt-back), .dj-mixer :is(.mx-front, .mx-back) { left: var(--round); width: calc(100% - 2 * var(--round)); }
.tt-body :is(.tt-left, .tt-right), .dj-mixer :is(.mx-left, .mx-right) { top: var(--round); height: calc(100% - 2 * var(--round)); }
.tt-body .tt-front, .dj-mixer .mx-front, :is(.tt-body, .dj-mixer) .box-arc:is(.is-front-left, .is-front-right) {
  background: linear-gradient(var(--clay-2), var(--clay-3) 55%, var(--clay-4));
}
.tt-body .tt-left, .dj-mixer .mx-left { background: linear-gradient(to left, var(--clay-3), var(--clay-4) 55%); }
.tt-body .tt-right, .dj-mixer .mx-right { background: linear-gradient(to right, var(--clay-3), var(--clay-4) 55%); }
/* A corner's narrow faces: each stands on the corner's middle, --round in from both sides, pushed out by
   --round and turned by --turn (0 faces the front, -90deg the right), as wide as a quarter round's
   fourth seen from outside (2 · tan 11.25° = .398) and a hair more, so no seam shows between them. */
.box-arc {
  position: absolute; width: calc(var(--round) * .398 + 1px); height: var(--z); margin-left: calc(var(--round) * -.199 - .5px);
  transform-origin: 50% 100%; transform: rotateZ(var(--turn)) translateY(var(--round)) rotateX(-90deg);
  background: linear-gradient(var(--clay-3), var(--clay-4) 55%);
}
.box-arc.is-front-right { left: calc(100% - var(--round)); top: calc(100% - var(--round) - var(--z)); }
.box-arc.is-front-left { left: var(--round); top: calc(100% - var(--round) - var(--z)); }
.box-arc.is-back-left { left: var(--round); top: calc(var(--round) - var(--z)); }
.box-arc.is-back-right { left: calc(100% - var(--round)); top: calc(var(--round) - var(--z)); }
.tt-top { position: absolute; inset: 0; transform: translateZ(var(--z)); border-radius: var(--round); cursor: default; }
.tt-top canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
/* Over the record on a deck, seen from above, the pointer can take hold of it to scratch; held, it is. */
.crate-turntable.is-jog .tt-top { cursor: grab; }
.crate-turntable.is-scratching .tt-top { cursor: grabbing; }
/* A record held over the turntable marks it as the place to drop it: a ring round its top, on the table
   round the white slab, so in the room's ink (dark on the light table by day, light on the black at
   night), and the shadow of what stands higher; nothing moves. */
.crate-turntable.is-target .tt-top { outline: max(2px, calc(var(--R) * .018)) solid var(--room-target); outline-offset: calc(var(--R) * .03); }
.crate-turntable.is-target::after { box-shadow: var(--lift-4); }

/* The flat panels, minimal like the app's own player panel: the band on each deck, the mixer's top, the
   playlist on the table and the shelf's panel. Each is a surface lying flat on what carries it, with no
   edge, rim or shadow of its own, its cells divided by 1px lines (--line). Sizes are in record heights
   (--R), so they scale with the room.

   One kind of key everywhere (the decks' keys, the mixer's options and the auto-mix, the switches between
   the views): a cell with one plain glyph in its middle, every glyph the same size (--glyph), no name
   printed on it (its name is its accessible name and its tooltip). Transport keys take the ink. A toggle
   that is off is muted; one that is on takes the ink and a small dot under its glyph (like: the heart
   filled instead). A key that cannot be used shows its glyph faint (--faint) and takes no press. Pressed,
   a key darkens a step (--clay-3); under a fine pointer it shows half a step. Values with a name (the
   volume, the shelf's tools, a deck's playlist) print the name small and muted at the top
   left of their cell and the value in the ink under it. */
.tablet :is(.tb-key, .dj-mixer .mx-auto, .dj-mixer .mx-player .tablet-control-grid button, .dj-mixer .mx-dancers) {
  position: relative; display: grid; place-items: center; width: 100%; height: 100%; min-width: 0; min-height: 0; margin: 0; padding: 0;
  border: 0; border-radius: 0; background: var(--clay-2); color: var(--ink); box-shadow: none; transform: none; font: inherit; cursor: pointer;
}
.tablet .dj-mixer .mx-player .tablet-control-grid button > span:first-child { display: none; }
:is(.tb-key, .mx-auto, .mx-player .tablet-control-grid button, .mx-dancers) [data-symbol] { display: flex; }
:is(.tb-key, .mx-auto, .mx-player .tablet-control-grid button, .mx-dancers) svg { width: var(--glyph); height: var(--glyph); stroke-width: 1.6; }
/* Toggles: muted while off, the ink and a dot under the glyph while on. */
.tablet :is(.tb-like, .dj-mixer .mx-auto, .dj-mixer .mx-player .tablet-control-grid button, .dj-mixer .mx-dancers):is([aria-pressed="false"], [aria-checked="false"]) { color: var(--muted); }
.tablet :is(.dj-mixer .mx-auto, .dj-mixer .mx-player .tablet-control-grid button, .dj-mixer .mx-dancers):is([aria-pressed="true"], [aria-checked="true"]) { color: var(--ink); }
.tablet :is(.dj-mixer .mx-auto, .dj-mixer .mx-player .tablet-control-grid button, .dj-mixer .mx-dancers):is([aria-pressed="true"], [aria-checked="true"])::after {
  content: ''; position: absolute; display: block; left: 50%; top: calc(50% + var(--glyph) / 2 + var(--R) * .03); bottom: auto; right: auto;
  width: calc(var(--R) * .028); height: calc(var(--R) * .028); transform: translateX(-50%); border-radius: 50%; background: currentColor;
}
.tablet .tb-like[aria-pressed="true"] { color: var(--ink); }
.tablet :is(.tb-key, .dj-mixer .mx-auto, .dj-mixer .mx-player .tablet-control-grid button, .dj-mixer .mx-dancers):disabled { opacity: 1; color: var(--faint); cursor: default; }
.tablet :is(.tb-key, .dj-mixer .mx-auto, .dj-mixer .mx-player .tablet-control-grid button, .dj-mixer .mx-dancers):disabled::after { display: none; }
.tablet :is(.tb-key, .dj-mixer .mx-auto, .dj-mixer .mx-player .tablet-control-grid button, .dj-mixer .mx-dancers, .pl-rows button, .shelf-panel .sp-cell):enabled:active { background: var(--clay-3); }
@media (hover: hover) and (pointer: fine) {
  .tablet :is(.tb-key, .dj-mixer .mx-auto, .dj-mixer .mx-player .tablet-control-grid button, .dj-mixer .mx-dancers, .pl-rows button, .shelf-panel button.sp-cell):enabled:hover {
    background: color-mix(in srgb, var(--clay-3) 50%, var(--clay-2));
  }
}
.tablet .tb-key[aria-busy="true"] [data-symbol] { color: var(--faint); }

/* Each deck's controls in the band along the front of its turntable's top, where nothing else is drawn: at
   the top the deck's track as plain text, its title in the ink and its artist muted, where it is in its
   album at the right and the like key; under a line a row of the transport keys, prev, play or pause and
   next, then the timeline, a thin line with a small dot, filled in the ink as far as the track has played,
   the times at its ends. An empty deck says "empty" in the muted ink, its keys and timeline faint; so does
   deck B while this device controls another one. The band follows the slab's corners; above it the
   drawing takes the pointer, as the turntable does. */
.tt-controls { position: absolute; inset: 0; pointer-events: none; color: var(--ink); font: 400 calc(var(--R) * .08)/1.2 var(--font); }
.tt-band {
  position: absolute; left: 0; right: 0; bottom: 0; height: var(--tbd); pointer-events: auto; background: var(--clay-2);
  display: grid; grid-template-columns: repeat(3, var(--key)) minmax(0, 1fr) var(--key); grid-template-rows: minmax(0, 1fr) var(--key-row);
  border-top: 1px solid var(--line); border-radius: 0 0 var(--round) var(--round);
}
.tb-head { grid-area: 1 / 1 / 2 / 5; display: flex; align-items: center; gap: calc(var(--R) * .05); min-width: 0; padding: 0 0 0 calc(var(--R) * .07); }
.tb-track { display: grid; gap: calc(var(--R) * .012); flex: 1; min-width: 0; margin: 0; }
.tb-track > * { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.tb-track b { font-size: calc(var(--R) * .095); font-weight: 500; line-height: 1.1; }
.tb-track span, .tb-number, .tb-time { color: var(--muted); }
.tb-track span { font-size: calc(var(--R) * .075); line-height: 1.1; }
.tt-controls:is([data-state="empty"], [data-state="off"]) .tb-track b { color: var(--muted); font-weight: 400; }
.tb-number { flex: none; font-size: calc(var(--R) * .072); font-variant-numeric: tabular-nums; }
.tb-like { grid-area: 1 / 5 / 2 / 6; }
.tb-keys { display: contents; }
.tablet .tb-keys .tb-key { border-top: 1px solid var(--line); }
.tablet .tb-keys .tb-key + .tb-key { border-left: 1px solid var(--line); }
.tb-time {
  grid-area: 2 / 4 / 3 / 6; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: calc(var(--R) * .04);
  min-width: 0; padding: 0 calc(var(--R) * .07); border-top: 1px solid var(--line); border-left: 1px solid var(--line);
  font-size: calc(var(--R) * .068); font-variant-numeric: tabular-nums;
}
.tablet .tb-time input[type="range"] { width: 100%; min-width: 0; height: 100%; margin: 0; padding: 0; background: none; -webkit-appearance: none; appearance: none; cursor: pointer; }
.tb-time input::-webkit-slider-runnable-track { height: max(1px, calc(var(--R) * .012)); background: linear-gradient(to right, var(--ink) var(--p, 0%), var(--line) var(--p, 0%)); }
.tb-time input::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: calc(var(--R) * .05); height: calc(var(--R) * .05); margin-top: calc(var(--R) * -.019);
  border: 0; border-radius: 50%; background: var(--ink); box-shadow: none;
}
.tb-time input::-moz-range-track { height: max(1px, calc(var(--R) * .012)); background: var(--line); }
.tb-time input::-moz-range-progress { height: max(1px, calc(var(--R) * .012)); background: var(--ink); }
.tb-time input::-moz-range-thumb { width: calc(var(--R) * .05); height: calc(var(--R) * .05); border: 0; border-radius: 50%; background: var(--ink); box-shadow: none; }
.tb-time input:disabled { cursor: default; }
.tb-time input:disabled::-webkit-slider-thumb { background: var(--faint); }
.tb-time input:disabled::-moz-range-thumb { background: var(--faint); }

/* The mixer: a low clay box between the turntables, a little lower than them, its top a flat panel: the
   volume knob over the whole width, shuffle, repeat and scratch under it in a row of three, the auto-mix's
   key and the dancers' key under those in a row of two (six columns, three keys of two or two of three), and across its front, in its own row (--fxr, FADER.row in discogs-crate.js), the crossfader from A to
   B, a track pressed into the top with ticks under it and a round clay knob, which the script maps the
   pointer onto: 20% to 80% across, in the middle of that row. While this device controls another one the
   crossfader stands still: its knob lies flat like a key that cannot be used. */
.dj-mixer { --z: var(--mxh); width: var(--mxw); height: var(--ttd); transform: translateZ(var(--th)); }
.mx-top {
  position: absolute; inset: 0; transform: translateZ(var(--z)); overflow: hidden;
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); grid-template-rows: minmax(0, 1fr) calc(var(--R) * .3) calc(var(--R) * .3) var(--fxr);
  gap: 1px; border: 1px solid var(--line); border-radius: var(--round); background: var(--line); color: var(--ink);
  font: 400 calc(var(--R) * .085)/1 var(--font); cursor: default;
}
.mx-player, .tablet .dj-mixer .mx-player .tablet-button-grids, .tablet .dj-mixer .mx-player .tablet-control-grid { display: contents; }
.tablet .mx-fader:focus-visible .mx-knob { outline: 2px solid var(--target); outline-offset: 2px; }
.tablet .dj-mixer .mx-player .tablet-control-grid button { grid-column: span 2; }
.tablet .dj-mixer :is(.mx-auto, .mx-dancers) { grid-column: span 3; }
.mx-fader { grid-area: 4 / 1 / 5 / 7; position: relative; background: var(--clay-2); cursor: ew-resize; touch-action: none; }
.tablet .mx-fader:focus-visible { outline: none; }
.mx-end {
  position: absolute; top: 50%; width: 14%; transform: translateY(-50%); text-align: center; color: var(--muted);
  font: 400 max(8px, calc(var(--R) * .07))/1 var(--font); letter-spacing: .04em;
}
.mx-end:first-child { left: 3%; }
.mx-end:last-child { right: 3%; }
/* The track, pressed into the top, with ticks under it at both ends and a longer one at the middle,
   where both decks play alike. */
.mx-slot {
  position: absolute; left: 20%; right: 20%; top: 50%; height: max(4px, calc(var(--R) * .045)); transform: translateY(-50%);
  border-radius: var(--pill); background: var(--clay-4); box-shadow: var(--press);
}
.mx-slot::before {
  content: ''; position: absolute; left: 0; right: 0; top: calc(100% + var(--R) * .05); height: calc(var(--R) * .05);
  background: linear-gradient(to right, currentColor 0 1px, transparent 1px calc(50% - .5px), currentColor calc(50% - .5px) calc(50% + .5px), transparent calc(50% + .5px) calc(100% - 1px), currentColor calc(100% - 1px));
  opacity: .55;
}
/* The knob: a round clay knob standing on the track with its soft shadow, and a small dark mark across
   it: clay on clay hardly shows where it stands, the mark does. */
.mx-knob {
  position: absolute; left: calc(20% + var(--x, .5) * 60%); top: 50%; width: calc(var(--R) * .14); height: calc(var(--R) * .14);
  transform: translate(-50%, -50%); border-radius: 50%; background: var(--clay-1); box-shadow: var(--lift-2);
}
.mx-knob::after {
  content: ''; position: absolute; left: calc(50% - max(.5px, var(--R) * .006)); top: 20%; width: max(1px, calc(var(--R) * .012)); height: 60%;
  border-radius: var(--pill); background: var(--mark);
}
.mx-fader[aria-disabled="true"] { cursor: default; }
.mx-fader[aria-disabled="true"] .mx-knob { background: var(--clay-2); box-shadow: inset 0 0 0 1px var(--rim); }
.mx-fader[aria-disabled="true"] .mx-knob::after { opacity: .35; }
/* The player's part (tablet-controls.js builds it without a track's keys, tablet-controls.css draws the
   panel's): the volume knob and the options. Its selectors start from the mixer, so the panel's rules for
   each orientation and for karaoke leave it alone; the panel's ink gives way to the room's. */
.tablet .dj-mixer .mx-player.player-console { --control-ink: var(--ink); --control-mark: var(--clay-2); --control-line: var(--line); }
/* The volume knob, flat as on the panel: a disc of the ink with its mark, turning, the scale printed
   round it, its name and value at the top of its cell. */
.tablet .dj-mixer .mx-player .tablet-dials { grid-area: 1 / 1 / 2 / 7; display: block; border: 0; min-height: 0; background: var(--clay-2); }
.tablet .dj-mixer .mx-player .tablet-dial-cell { height: 100%; padding: calc(var(--R) * .17) 0 calc(var(--R) * .05); display: flex; justify-content: center; align-items: center; }
.tablet .dj-mixer .mx-player .tablet-dial-cell > :is(label, output) { top: calc(var(--R) * .06); font-size: calc(var(--R) * .072); line-height: 1; color: var(--muted); white-space: nowrap; }
.tablet .dj-mixer .mx-player .tablet-dial-cell > label { left: calc(var(--R) * .07); font-weight: 400; }
.tablet .dj-mixer .mx-player .tablet-dial-cell > output { right: calc(var(--R) * .07); color: var(--ink); }
.tablet .dj-mixer .mx-player .tablet-dial { width: calc(var(--R) * .48); max-width: 100%; }
.tablet .dj-mixer .mx-player .tablet-dial-scale i::before { left: calc(50% - max(.5px, var(--R) * .003)); width: max(1px, calc(var(--R) * .006)); height: calc(var(--R) * .03); background: var(--ink); }
.tablet .dj-mixer .mx-player .tablet-dial-scale i:nth-child(4n + 1)::before { height: calc(var(--R) * .045); }
.tablet .dj-mixer .mx-player .tablet-dial-face { inset: calc(var(--R) * .075); background: var(--ink); box-shadow: none; }
.tablet .dj-mixer .mx-player .tablet-dial-face > span { top: calc(var(--R) * .03); left: calc(50% - var(--R) * .008); width: calc(var(--R) * .016); height: calc(var(--R) * .07); background: var(--clay-2); }
.tablet .dj-mixer .mx-player .tablet-dial:has(input:focus-visible) { outline: var(--ring); outline-offset: calc(var(--R) * .01); }

/* The playlists, one flat at the outer side of each deck (deck A's at its left, deck B's at its right),
   as deep as the deck and in line with it, are the one black thing among the players, by day and at night:
   white type on black, fine dark grey 1px lines between their parts, the track a deck plays in full white
   with its small white dot, the others a slightly muted white, numbers, lengths and names muted further
   (every one at least 8:1 on the black, AA). They set their own tokens, after the players' and the night's,
   so --ring and the tones made from them are their own. */
.crate-room .room-playlist {
  --clay-2: #000000; --clay-3: #262626; --ink: #ffffff; --pl-rest: #cccccc; --muted: #a6a6a6; --faint: #707070;
  --line: #333333; --pl-thumb: #4d4d4d; --mark: #ffffff; --target: #ffffff;
}
/* Each is a drawer under its deck, a layer lower than the deck, pulled out sideways: along its outer end
   its lip, with the deck's small name (folded, also the title it plays) standing upright along it, reading
   up the left lip and down the right one, and at the lip's front end the key that slides it in under the
   deck and pulls it out again; beside the lip its tracks, each its number, its title and its length. A deck
   with none says "empty" (or "loading") in the muted ink. A long list scrolls in its place, the list alone,
   never the room. Type is a little under a tenth of a record height (10 px in the table view at
   1280 × 720), a track a little over a sixth (16 px).

   The face, a leaf lying flat on the slab and anchored at the deck's outer side, eases its width from the
   open one (--plw) to the lip's (--plbar) and back without overshoot; its content keeps its full width,
   with the lip at the face's outer end, and the face clips it at the deck's side, so the tracks slide in
   under the deck and their scroll stays as it is. Only the face moves. The slab's body keeps the 3D space
   and takes no pointer, so where the face has slid away the table under it does. */
.room-playlist { width: var(--plw); height: var(--pld); transform: translateZ(var(--th)); cursor: default; pointer-events: none; }
.pl-face {
  position: absolute; top: 0; width: var(--plw); height: var(--pld); transform: translateZ(1px); overflow: hidden; pointer-events: auto;
  border: 1px solid var(--line); background: var(--line); color: var(--pl-rest);
  font: 400 calc(var(--R) * .098)/1.2 var(--font);
}
.room-playlist[data-list="a"] .pl-face { right: 0; }
.room-playlist[data-list="b"] .pl-face { left: 0; }
.room-playlist.is-folded .pl-face { width: var(--plbar); }
/* Only a press on its key eases it (is-easing, until it arrives): a new screen size or the room opening
   puts it where it is at once. */
.room-playlist.is-easing .pl-face { transition: width .32s cubic-bezier(.3, 0, .2, 1); }
.pl-deck { position: absolute; top: 0; bottom: 0; display: flex; gap: 1px; width: calc(var(--plw) - 2px); }
.room-playlist[data-list="a"] .pl-deck { left: 0; }
.room-playlist[data-list="b"] .pl-deck { right: 0; flex-direction: row-reverse; }
.pl-lip { flex: none; display: flex; flex-direction: column; gap: 1px; width: calc(var(--plbar) - 2px); background: var(--line); }
.pl-head {
  flex: 1; display: flex; align-items: center; gap: calc(var(--R) * .06); min-height: 0; margin: 0; padding: calc(var(--R) * .07) 0;
  overflow: hidden; writing-mode: vertical-rl; background: var(--clay-2);
}
.room-playlist[data-list="a"] .pl-head { transform: rotate(180deg); }
.pl-name { flex: none; line-height: 1; color: var(--muted); }
/* Folded, the lip says what its deck plays; it fades in and out with the fold, nothing hops. */
.pl-now { min-inline-size: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; line-height: 1; color: var(--ink); opacity: 0; }
.room-playlist.is-folded .pl-now { opacity: 1; }
.room-playlist.is-easing .pl-now { transition: opacity .2s linear; }
.tablet .pl-fold {
  flex: none; display: grid; place-items: center; width: 100%; height: calc(var(--R) * .3);
  margin: 0; padding: 0; border: 0; border-radius: 0; background: var(--clay-2); color: var(--ink);
  box-shadow: none; transform: none; cursor: pointer;
}
.pl-fold [data-symbol] { display: flex; }
.pl-fold svg { width: var(--glyph); height: var(--glyph); stroke-width: 1.6; }
.tablet .pl-fold:active { background: var(--clay-3); }
@media (hover: hover) and (pointer: fine) { .tablet .pl-fold:hover { background: color-mix(in srgb, var(--clay-3) 50%, var(--clay-2)); } }
.tablet .pl-fold:focus-visible { outline: var(--ring); outline-offset: calc(var(--R) * -.02); }
.pl-list { flex: 1; display: flex; flex-direction: column; min-width: 0; background: var(--clay-2); }
.pl-note { margin: 0; padding: calc(var(--R) * .05) calc(var(--R) * .07); color: var(--muted); }
.pl-note:empty { display: none; }
.pl-rows {
  position: relative; flex: 1; min-height: 0; margin: 0; padding: calc(var(--R) * .03) 0; list-style: none;
  overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; scrollbar-width: thin; scrollbar-color: var(--pl-thumb) transparent;
}
.tablet .pl-rows button {
  position: relative; display: grid; grid-template-columns: calc(var(--R) * .2) minmax(0, 1fr) auto; align-items: center; gap: calc(var(--R) * .04);
  width: 100%; height: calc(var(--R) * .16); margin: 0; padding: 0 calc(var(--R) * .07);
  border: 0; border-radius: 0; background: none; box-shadow: none; color: var(--pl-rest); font: inherit; text-align: left; transform: none;
}
.pl-no, .pl-len { color: var(--muted); font-variant-numeric: tabular-nums; }
.pl-title { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.tablet .pl-rows button[aria-current="true"] { color: var(--ink); }
.tablet .pl-rows button[aria-current="true"] :is(.pl-no, .pl-len) { color: var(--ink); }
.tablet .pl-rows button[aria-current="true"] .pl-title { font-weight: 600; }
.tablet .pl-rows button[aria-current="true"]::before {
  content: ''; position: absolute; left: calc(var(--R) * .03); top: 50%; width: calc(var(--R) * .028); height: calc(var(--R) * .028);
  transform: translateY(-50%); border-radius: 50%; background: var(--mark);
}
.tablet .pl-rows button:disabled { opacity: 1; cursor: default; color: var(--muted); }
.tablet :is(.tt-controls, .mx-top, .pl-rows) :is(button, input[type="range"]):focus-visible, .tablet .mx-auto:focus-visible { outline: var(--ring); outline-offset: calc(var(--R) * -.02); }

/* The shelf's panel: a flat face standing upright at the unit's front, a hair in front of it, over its rows
   at its left end, where the belt goes round behind it. One column of cells of one size, one under the
   other: the grouping, the sort, its order, the shelf (the belt or every crate), the filter, and clearing the
   table; in each its name small and muted at the top left and its value in the ink at its foot, also in the
   two choices (with a chevron) and the filter. Its cells are larger than the table's panels', so they read
   from in front, in the shelf view. */
.shelf-panel {
  position: absolute; width: var(--spw); height: var(--sph); transform-origin: 50% 100%;
  display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: repeat(6, minmax(0, 1fr));
  gap: 1px; border: 1px solid var(--line); background: var(--line); color: var(--ink); cursor: default;
  font: 400 calc(var(--R) * .1)/1 var(--font);
  --cell: calc((var(--sph) - 7px) / 6); --pad: calc(var(--R) * .08);
}
.sp-cell { position: relative; display: block; min-width: 0; background: var(--clay-2); }
.sp-name { position: absolute; z-index: 1; top: var(--pad); left: var(--pad); font-size: calc(var(--R) * .075); line-height: 1; color: var(--muted); pointer-events: none; }
.sp-value { position: absolute; left: var(--pad); right: var(--pad); bottom: var(--pad); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: calc(var(--R) * .1); line-height: 1; text-align: left; }
.tablet .shelf-panel button.sp-cell {
  width: 100%; height: 100%; margin: 0; padding: 0; border: 0; border-radius: 0; background: var(--clay-2); color: var(--ink);
  box-shadow: none; font: inherit; transform: none; cursor: pointer;
}
/* The choices and the filter: their value at the cell's foot like every other, its text 16px drawn at --fk,
   a record height's .1, so a phone does not zoom the page to it while it is typed into; the focus ring goes
   round the cell. */
.tablet .sp-cell.is-field > :is(select, input) {
  position: absolute; left: 0; top: 0; width: calc(100% / var(--fk)); height: calc(100% / var(--fk)); margin: 0; box-sizing: border-box;
  padding: calc((var(--cell) - var(--pad) - var(--R) * .1) / var(--fk)) calc(var(--R) * .2 / var(--fk)) calc(var(--pad) / var(--fk)) calc(var(--pad) / var(--fk));
  transform: scale(var(--fk)); transform-origin: 0 0; border: 0; border-radius: 0; box-shadow: none; outline: none;
  background: none; color: inherit; font: 400 16px/1 var(--font); -webkit-appearance: none; appearance: none;
}
.sp-cell.is-field > select { cursor: pointer; }
.tablet .sp-cell.is-field > input { padding-right: calc(var(--pad) / var(--fk)); user-select: text; -webkit-user-select: text; }
.sp-cell.is-field option { background: var(--clay-2); color: var(--ink); }
.sp-cell.is-field:has(:focus-visible) { outline: var(--ring); outline-offset: calc(var(--R) * -.02); }
.sp-cell.is-pick::after {
  content: ''; position: absolute; right: var(--pad); bottom: calc(var(--pad) + var(--R) * .03); width: calc(var(--R) * .04); height: calc(var(--R) * .04);
  border: solid currentColor; border-width: 0 max(1px, calc(var(--R) * .009)) max(1px, calc(var(--R) * .009)) 0; transform: rotate(45deg); pointer-events: none;
}
.sp-find input::placeholder { color: var(--muted); opacity: 1; }
.sp-find input::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none; width: 10px; height: 10px; background: currentColor; cursor: pointer;
  clip-path: polygon(10% 0, 50% 40%, 90% 0, 100% 10%, 60% 50%, 100% 90%, 90% 100%, 50% 60%, 10% 100%, 0 90%, 40% 50%, 0 10%);
}
.tablet .shelf-panel :is(button, input):focus-visible { outline: var(--ring); outline-offset: calc(var(--R) * -.02); }

/* The switches between the views, a step up or down the column of views (the shelf, the room, the
   table): each one key of the room's kind, in the middle of a band over the room at the screen's edge
   towards the view it shows. Along the foot of the screen the band's key points down (from the shelf to
   the room, from the room to the table); from the top of the room (under the header's symbols) down to the
   table's back edge, or to the room's free screen, the band's key points up (from the table to the room,
   from the room to the shelf). The shelf view has only the one at its foot, the table view only the one at
   its top, the room view both. At rest a band is the ground and hides what lies beyond the view (the table
   under the shelf, the shelf behind the table); while the camera glides between the views it lets the room
   show through. Its glyph takes the ground's ink: a dark grey on the light ground by day, a light grey on
   the black at night. */
.crate-switch {
  position: absolute; z-index: 2; left: 0; right: 0; display: flex; justify-content: center; align-items: flex-end;
  background: transparent; pointer-events: none; transition: background-color .15s ease;
}
.crate-switch[hidden] { display: none; }
.crate-switch.is-still { background: var(--ground); }
.crate-switch[data-at="bottom"] { bottom: 0; height: var(--swh); }
.crate-switch[data-at="top"] { top: 0; height: var(--swt); }
.tablet .cs-key {
  display: grid; place-items: center; width: calc(var(--swh) * 1.5); height: var(--swh); margin: 0; padding: 0; border: 0; border-radius: 0;
  background: none; box-shadow: none; color: var(--ground-ink); pointer-events: auto; cursor: pointer; transform: none;
}
.cs-key [data-symbol] { display: flex; }
.cs-key svg { width: 26px; height: 26px; stroke-width: 1.6; }
@media (hover: hover) and (pointer: fine) { .tablet .cs-key:hover { color: var(--ground-ink-strong); } }
.tablet .cs-key:active { color: var(--ground-ink-strong); }
.tablet .cs-key:focus-visible { outline: 2px solid var(--ground-ink-strong); outline-offset: -6px; }
@media (prefers-reduced-motion: reduce) { .crate-switch { transition: none; } }

/* A note over the top of the room (nothing synced, nothing matching the filter), below the header; the
   room stands under it, its panels in reach. A tile of the room's clay, held a little over it. */
.crate-empty {
  position: absolute; z-index: 3; top: var(--top, 64px); left: 50%; transform: translateX(-50%); width: max-content; max-width: calc(100% - 32px);
  display: grid; gap: 8px; padding: 12px 18px; border-radius: var(--round-wide); text-align: center;
  color: var(--ink); background: var(--clay-2); box-shadow: var(--lift-3), inset 0 0 0 1px var(--rim);
}
.crate-empty[hidden] { display: none; }
.crate-empty p { margin: 0; font-size: 15px; }
.crate-empty a { color: var(--ink); text-decoration: underline; text-underline-offset: 5px; }

/* A record lifted off the table: details and play, over the whole room, which a veil of its clay keeps
   back. The card is a tile of the same clay held up over it, its type in the room's ink; the play keys
   are pills, deck A's (or the only one) filled with the ink, deck B's a raised clay key; focus rings take
   the target ink. */
.tablet-crate:has(.crate-detail:not([hidden])) { z-index: 5; }
.crate-detail {
  position: absolute; inset: 0; z-index: 6; display: grid; place-items: center; padding: 24px;
  background: color-mix(in srgb, var(--clay-5) 72%, transparent); color: var(--ink);
}
.crate-detail[hidden] { display: none; }
.tablet .crate-detail :focus-visible { outline-color: var(--target); }
.crate-card {
  display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 360px); align-items: center; gap: 32px;
  max-width: 100%; max-height: 100%; overflow: auto; padding: 28px;
  border-radius: var(--round-wide); background: var(--clay-2); box-shadow: var(--lift-4), inset 0 0 0 1px var(--rim);
}
.crate-card-sleeve { aspect-ratio: 1; overflow: hidden; --R: 300px; box-shadow: var(--lift-1); }
.crate-card-sleeve img { display: block; width: 100%; height: 100%; object-fit: cover; }
.crate-info { min-width: 0; }
.crate-info h2 { margin: 0 0 8px; overflow-wrap: anywhere; color: var(--ink); font: 700 clamp(24px, 3vw, 44px)/1 var(--font); letter-spacing: -.045em; }
.crate-info-artist { margin: 0 0 16px; font-size: clamp(16px, 1.6vw, 22px); }
.crate-info-meta { margin: 0 0 16px; font-size: 13px; line-height: 1.5; }
.crate-info-state { margin: 0 0 14px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; }
.crate-info-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 20px; }
.tablet .crate-play {
  display: inline-flex; align-items: center; gap: 10px; height: 48px; padding: 0 22px 0 16px;
  border: 0; border-radius: var(--pill); box-shadow: var(--lift-2); background: var(--ink); color: var(--clay-1); font: 400 16px var(--font);
}
.crate-play svg { width: 20px; height: 20px; }
.crate-play:disabled { opacity: .5; box-shadow: none; }
/* A record off the decks plays on either: deck B's key is a raised one of clay. */
.tablet .crate-play + .crate-play { background: var(--clay-1); color: var(--ink); }
.tablet .crate-play:enabled:active { background: var(--clay-4); color: var(--ink); box-shadow: var(--press); }
.tablet .crate-link {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0; border: 0; box-shadow: none;
  background: none; color: var(--ink); font: 400 14px var(--font); text-decoration: underline; text-underline-offset: 4px;
}
.crate-link svg { width: 14px; height: 14px; }
@media (max-width: 640px) {
  .crate-card { grid-template-columns: minmax(0, 1fr); gap: 16px; padding: 20px; }
  .crate-card-sleeve { width: min(220px, 60vw); --R: 220px; }
}
