/* HARZ store: dark 2000s glass. Smoked black glass panels with a soft top-half shine, glassy black buttons,
   faint cool reflections. Layout of a mid-2000s music app: toolbar, LCD now-playing, striped list, status bar.
   Kept dark so the background visualizer glows through. */
/* Michroma (SIL OFL 1.1, fonts/LICENSE-michroma.txt), served from the store itself: no wait on another server. */
@font-face { font-family: "Michroma"; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/fonts/michroma-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Michroma"; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/fonts/michroma-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
:root {
  --bg: #000;
  --text: #e8eef2;
  --muted: #8b949b;
  --edge: rgba(255, 255, 255, .14);          /* glass edge highlight */
  --edge-dark: #000;
  --cool: rgba(170, 215, 255, .10);          /* faint cool reflection */
  --shine: linear-gradient(180deg, rgba(255,255,255,.16) 0%, rgba(255,255,255,.05) 49%, rgba(255,255,255,0) 50%);
  --glass: linear-gradient(180deg, rgba(40,44,48,.85), rgba(10,11,12,.92));
  --ui: "Segoe UI", Tahoma, Verdana, system-ui, sans-serif;
  --mono: "Lucida Console", Consolas, monospace;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { background: var(--bg); }
body { margin: 0; color: var(--text); font: 12px/1.4 var(--ui); padding: 0 0 48px; min-height: 100vh; min-height: 100dvh; position: relative; -webkit-font-smoothing: antialiased; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; height: auto; display: block; }
button { font: inherit; color: inherit; cursor: pointer; background: none; border: none; }
:focus-visible { outline: 1px dotted #fff; outline-offset: 2px; }
.muted { color: var(--muted); }

/* ---------- background visualizer: quick fade in, slow fade out ---------- */
#viz { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; opacity: 0;
       transition: opacity 1.2s ease-out; } /* shown exactly as drawn: no filters or blending over it */
/* Dark mode shows it at full strength all the time (no dimming); immersive mode only hides the UI. */
#viz.on { opacity: .9; transition: opacity .25s ease-in; }
/* A style that has just been switched to fades in (from the black the old one leaves) instead of cutting in. */
@starting-style { #viz.on { opacity: 0; } }
/* The two styles handing over (viz-switch.js): the canvas on top fades quickly; the one underneath snaps to full
   strength (hidden by the one above), so the picture never dips. AVS's preset-change still only shows with AVS. */
html.viz-blend #viz, html.viz-blend #viz.on { transition: opacity .4s ease-in-out; }
html.viz-blend #viz.snap { transition: none; }
/* Immersive: after 30 s of playback with no input, the UI fades away and the visualizer takes the screen.
   Light mode keeps its look exactly; only the menus fade. */
.toolbar, .window, .statusbar, .page, .top, .sitefoot { transition: opacity .4s ease; }
/* At 30 s everything fades but the bottom player bar (.toolbar), which never fades. */
html.immersive :is(.window, .statusbar, .page, .top, .drawer:not(.open), .sitefoot) { opacity: 0; pointer-events: none; transition: opacity 1.8s ease; } /* an open cart never fades: opened from the player while the rest has faded, it would be an invisible sheet under the dimmed screen */
/* Every element: buttons, links and rows set their own pointer cursor, which would otherwise stay visible. */
html.immersive, html.immersive body, html.immersive * { cursor: none !important; }
.toolbar, .window, .statusbar, .page, .top { position: relative; z-index: 1; }
/* Overall UI scale: everything (type, rows, buttons, LCD) grows together. The visualizer canvas is not scaled. */
.toolbar, .window, .statusbar, .drawer, .page, .top { zoom: 1.25; }
.window { max-width: 1040px; }
body { padding-bottom: 48px; }

/* Shared smoked-glass button */
.glassbtn, .tbtn, .lcd-buy, .cart-btn, .play, .price-btn, .add, .checkout, .btn, .files a, .mode-btn {
  color: #f2f6f8; border: 1px solid #000; text-shadow: 0 -1px 0 rgba(0,0,0,.7);
  background: var(--shine), linear-gradient(180deg, #3a3f44 0%, #16181a 100%);
  box-shadow: inset 0 1px 0 var(--edge), inset 0 0 0 1px rgba(255,255,255,.03), 0 1px 2px rgba(0,0,0,.8);
  transition: box-shadow .15s, background .15s, transform .18s cubic-bezier(.3, 1.6, .5, 1);
  position: relative; transform: translateZ(0); -webkit-tap-highlight-color: transparent; user-select: none;
}
/* Tactile press: buttons sink into the panel, then spring back with a quick glass flash. */
.glassbtn:active, .tbtn:active, .lcd-buy:active, .cart-btn:active, .play:active, .price-btn:active, .add:active,
.checkout:active, .btn:active, .files a:active, .mode-btn:active {
  transform: translateY(1px) scale(.93); transition-duration: .05s;
}
.pop::after {
  content: ""; position: absolute; inset: -1px; border-radius: inherit; pointer-events: none;
  animation: press-flash .45s ease-out forwards;
}
@keyframes press-flash {
  0%   { box-shadow: 0 0 0 0 rgba(190, 230, 255, .55), inset 0 0 12px rgba(255, 255, 255, .35); }
  100% { box-shadow: 0 0 0 9px rgba(190, 230, 255, 0), inset 0 0 0 rgba(255, 255, 255, 0); }
}
html[data-mode="light"] .pop::after { animation-name: press-flash-light; }
@keyframes press-flash-light {
  0%   { box-shadow: 0 0 0 0 rgba(60, 120, 170, .45), inset 0 0 10px rgba(255, 255, 255, .9); }
  100% { box-shadow: 0 0 0 9px rgba(60, 120, 170, 0), inset 0 0 0 rgba(255, 255, 255, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .pop::after { animation: none; }
  .glassbtn:active, .tbtn:active, .lcd-buy:active, .cart-btn:active, .play:active, .price-btn:active, .add:active,
  .checkout:active, .btn:active, .files a:active, .mode-btn:active { transform: none; }
}
.tbtn:hover, .lcd-buy:hover, .cart-btn:hover, .play:hover, .price-btn:hover, .add:hover, .checkout:hover, .btn:hover, .files a:hover {
  background: var(--shine), linear-gradient(180deg, #4b5157 0%, #1d2023 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 0 10px var(--cool), 0 1px 2px rgba(0,0,0,.8);
}
.tbtn:active, .add:active, .checkout:active { background: linear-gradient(180deg, #121416, #2c3034); box-shadow: inset 0 1px 3px rgba(0,0,0,.8); }

/* ---------- toolbar ---------- */
.toolbar {
  position: sticky; top: 0; z-index: 10;
  display: grid; grid-template-columns: minmax(max-content, 1fr) minmax(0, 760px) minmax(max-content, 1fr); gap: 16px; /* the now-playing display as long as the room allows, up to 760px */ align-items: center; padding: 8px 14px;
  background: var(--shine), linear-gradient(180deg, rgba(34,37,40,.92), rgba(6,7,8,.96));
  backdrop-filter: blur(10px);
  border-bottom: 1px solid #000; box-shadow: inset 0 1px 0 var(--edge), 0 1px 0 rgba(255,255,255,.05), 0 6px 20px rgba(0,0,0,.6);
}
.transport { display: flex; align-items: center; gap: 6px; }
.tbtn { width: 30px; height: 30px; border-radius: 50%; font-size: 11px; }
#p-shuffle { font-size: 13px; opacity: .55; }
#p-shuffle.on { opacity: 1; box-shadow: inset 0 1px 0 var(--edge), 0 0 10px var(--cool), 0 0 0 1px rgba(160,220,255,.35); }
.tbtn.big { width: 38px; height: 38px; font-size: 13px; box-shadow: inset 0 1px 0 var(--edge), 0 0 12px var(--cool), 0 1px 2px rgba(0,0,0,.8); }

/* LCD now-playing display: dark glass screen */
.lcd {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; gap: 10px; align-items: center;
  width: 100%; justify-self: center; padding: 5px 10px 5px 6px; border-radius: 7px;
  background: linear-gradient(180deg, rgba(255,255,255,.06) 0%, rgba(255,255,255,0) 45%), linear-gradient(180deg, #0c0e10, #050607);
  border: 1px solid #000; box-shadow: inset 0 1px 4px rgba(0,0,0,.9), 0 1px 0 rgba(255,255,255,.08);
}
.lcd img { width: 40px; height: 40px; object-fit: cover; border: 1px solid #000; box-shadow: 0 0 0 1px rgba(255,255,255,.08); }
.lcd img:not([src]), .lcd img[src=""] { visibility: hidden; }
.lcd-text { min-width: 0; text-align: center; }
.lcd-title { display: block; font-weight: 700; color: #f4f8fa; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-shadow: 0 0 8px rgba(190,225,255,.25); }
.lcd-title[href]:hover { text-decoration: underline; }
.lcd-sub { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lcd-row { display: grid; grid-template-columns: auto 1fr auto; gap: 6px; align-items: center; font: 10px var(--mono); color: #7f8a92; margin-top: 2px; }
.lcd .bar { height: 6px; border-radius: 3px; border: 1px solid #000; background: #15181a; cursor: pointer; position: relative; box-shadow: inset 0 1px 2px rgba(0,0,0,.8), 0 1px 0 rgba(255,255,255,.06); }
.lcd .fill { position: absolute; inset: 0 auto 0 0; width: 0; border-radius: 3px; background: var(--shine), linear-gradient(90deg, #8f9aa3, #dfe7ec); box-shadow: 0 0 6px rgba(200,230,255,.35); }
.lcd-buy { font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 4px; }

.right { display: flex; align-items: center; gap: 14px; }
.wordmark { font-family: "Michroma", var(--ui); font-size: 14px; letter-spacing: .28em; text-transform: uppercase; color: #f2f6f8; text-shadow: 0 0 10px rgba(190,225,255,.2); }
.cart-btn { font-size: 11px; padding: 4px 12px; border-radius: 12px; }
.cart-btn b { color: #fff; }
@media (max-width: 760px) {
  .toolbar { grid-template-columns: auto 1fr; }
  .lcd { grid-column: 1 / -1; order: 3; max-width: none; }
  .toolbar .wordmark { display: none; } /* the thanks, legal and payee pages keep theirs: their only way back */
}

/* Mid-size windows: not enough room for a long display between the transport and the right-hand buttons, so it
   takes its own full-width row under them instead of being squeezed. */
@media (min-width: 761px) and (max-width: 1100px) {
  .toolbar { grid-template-columns: auto 1fr auto; row-gap: 8px; }
  .toolbar .right { grid-column: 3; justify-self: end; }
  .toolbar .lcd { grid-column: 1 / -1; grid-row: 2; max-width: 760px; }
}

/* volume slider: dark glass */
.vol { display: flex; align-items: center; margin-left: 6px; }
.vol input {
  -webkit-appearance: none; appearance: none; width: 80px; height: 6px; border-radius: 3px; cursor: pointer;
  background: linear-gradient(90deg, #c9d3da 0, #7f8a92 var(--fill, 80%), #0d0f10 var(--fill, 80%));
  border: 1px solid #000; box-shadow: inset 0 1px 2px rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.07);
}
.vol input::-webkit-slider-thumb {
  -webkit-appearance: none; width: 13px; height: 13px; border-radius: 50%;
  background: radial-gradient(circle at 40% 30%, #ffffff 0 18%, #b7c2ca 40%, #4a5258 100%);
  border: 1px solid #000; box-shadow: 0 0 6px rgba(200,230,255,.35), 0 1px 1px rgba(0,0,0,.7);
}
.vol input::-moz-range-thumb { width: 13px; height: 13px; border-radius: 50%; background: radial-gradient(circle at 40% 30%, #fff 0 18%, #b7c2ca 40%, #4a5258 100%); border: 1px solid #000; }
@media (max-width: 760px) { .vol { display: none; } }

/* ---------- main window: striped glass track list ---------- */
.window { max-width: 980px; margin: 14px auto 0; padding: 0 14px; }
.filterbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.search {
  width: 230px; padding: 5px 10px 5px 26px; border-radius: 13px; font: 12px var(--ui); color: var(--text);
  background: #0b0d0e url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12'><circle cx='5' cy='5' r='3.6' fill='none' stroke='%238b949b' stroke-width='1.4'/><path d='M7.8 7.8 11 11' stroke='%238b949b' stroke-width='1.4'/></svg>") 9px 50% no-repeat;
  border: 1px solid #000; box-shadow: inset 0 1px 3px rgba(0,0,0,.9), 0 1px 0 rgba(255,255,255,.07);
}
.search:focus { outline: none; box-shadow: inset 0 1px 3px rgba(0,0,0,.9), 0 0 0 1px rgba(200,230,255,.25), 0 0 10px var(--cool); }
.count { color: var(--muted); font-size: 11px; }

.table { border: 1px solid #000; border-radius: 6px; overflow: hidden; box-shadow: 0 0 0 1px rgba(255,255,255,.06), 0 10px 30px rgba(0,0,0,.6); }
.thead, .row { display: grid; grid-template-columns: 30px 28px 32px minmax(0, 1fr) 56px 90px 76px; gap: 8px; align-items: center; padding: 0 8px; }
.thead { height: 22px; font-size: 11px; color: #c3cbd1; background: var(--shine), linear-gradient(180deg, #2c3034, #111315); border-bottom: 1px solid #000; }
.thead span + span { border-left: 1px solid #000; padding-left: 6px; box-shadow: inset 1px 0 0 rgba(255,255,255,.06); }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.list { list-style: none; margin: 0; padding: 0; }
.row { height: 34px; cursor: pointer; background: rgba(10,11,12,.55); border-bottom: 1px solid rgba(255,255,255,.03); }
.row.alt { background: rgba(20,22,24,.6); }
.row:hover { background: rgba(36,40,44,.8); }
.row.playing {
  background: var(--shine), linear-gradient(180deg, rgba(70,78,86,.95), rgba(28,31,34,.95));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.16), inset 0 0 18px var(--cool);
}
.row .idx { color: #5f686f; text-align: right; font-variant-numeric: tabular-nums; }
.row.playing .idx { color: #dfe7ec; }
.row img { width: 28px; height: 28px; object-fit: cover; border: 1px solid #000; box-shadow: 0 0 0 1px rgba(255,255,255,.06); }
.row .t { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row .t:hover { text-decoration: underline; }
.row.playing .t { color: #fff; text-shadow: 0 0 8px rgba(200,230,255,.35); }
.row .key { color: var(--muted); }
.play { width: 20px; height: 20px; border-radius: 50%; font-size: 8px; }
/* List rows' buttons aren't a compositor layer each (the shared glass button's translateZ): scrolling the list stays cheap. */
.row .play:not(:active), .row .price-btn:not(:active) { transform: none; }
.row.playing .play { box-shadow: inset 0 1px 0 rgba(255,255,255,.3), 0 0 8px rgba(200,230,255,.4); }
.price-btn { justify-self: end; font-weight: 700; padding: 2px 9px; border-radius: 10px; }
.empty { padding: 18px; color: var(--muted); background: rgba(10,11,12,.55); }
@media (max-width: 600px) {
  /* Phones: the name gets the room (BPM, key and the number are on the beat or loop page and in the player). */
  .thead, .row { grid-template-columns: 26px 28px minmax(0, 1fr) 54px; }
  /* Names in full: a long one wraps onto a second line (the row grows) instead of being cut short; the price button
     is a compact pill so the name gets the room. */
  .row .t { white-space: normal; overflow: visible; overflow-wrap: anywhere; line-height: 1.25; }
  .list .row { height: auto; min-height: 40px; padding-block: 4px; }
  .row .price-btn { padding: 3px 7px; font-size: 10px; border-radius: 9px; }
  .thead span:nth-child(2), .row .idx, .thead span:nth-child(5), .row > .num, .thead span:nth-child(6), .row .key { display: none; }
}

/* ---------- beat page ---------- */
.beat { display: grid; grid-template-columns: minmax(0, 360px) minmax(0, 1fr); gap: 28px; padding-top: 10px; padding-bottom: 40px; align-items: start; }
@media (max-width: 700px) { .beat { grid-template-columns: 1fr; } }
.beat .art img { width: 100%; border: 1px solid #000; box-shadow: 0 0 0 1px rgba(255,255,255,.08), 0 12px 34px rgba(0,0,0,.7);
                 -webkit-box-reflect: below 2px linear-gradient(transparent 70%, rgba(255,255,255,.14)); }
.back { display: inline-flex; align-items: center; gap: 2px; font-size: 12px; font-weight: 600; padding: 6px 14px; margin-bottom: 12px; }
.back:hover { color: #fff; text-decoration: none; }
/* The back arrow is a drawn shape centred with the label (the text triangle sat low and off-centre). */
.back, #p-back { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.back-ic { width: .9em; height: .9em; vertical-align: 0; flex: none; }
.beat h1 { font: 700 30px/1.1 var(--ui); margin: 0 0 4px; letter-spacing: -.01em; text-shadow: 0 0 14px rgba(200,230,255,.15); }
.sub { color: var(--muted); margin-bottom: 14px; }
.beat .coprod { color: var(--muted); font-size: 12px; letter-spacing: .06em; margin: 2px 0 8px; }
.beat .tbtn.big { margin-bottom: 16px; }
.tiers { border: 1px solid #000; border-radius: 6px; overflow: hidden; box-shadow: 0 0 0 1px rgba(255,255,255,.06); }
.tier { display: flex; justify-content: space-between; align-items: center; gap: 14px; padding: 9px 10px; background: rgba(10,11,12,.88); }
.tier:nth-child(even) { background: rgba(20,22,24,.88); }
.tier .name { font-weight: 700; }
.tier .terms { color: var(--muted); font-size: 11px; margin-top: 2px; }
.add, .checkout, .btn, .files a { font-size: 11px; font-weight: 700; padding: 5px 13px; border-radius: 12px; white-space: nowrap; }
.add.ghost { color: var(--muted); }
.note { color: var(--muted); font-size: 11px; margin-top: 10px; }

/* ---------- cart drawer ---------- */
.drawer {
  position: fixed; inset: 0 0 0 auto; width: min(360px, 80vw); z-index: 20; /* 80vw x zoom 1.25 = full phone width */ display: flex; flex-direction: column;
  background: var(--shine), linear-gradient(180deg, rgba(30,33,36,.97), rgba(6,7,8,.98)); border-left: 1px solid #000;
  box-shadow: inset 1px 0 0 rgba(255,255,255,.08), -10px 0 30px rgba(0,0,0,.75); transform: translateX(100%);
  visibility: hidden; transition: transform .2s ease, visibility 0s .2s; /* closed: no shadow peeking in at the edge */
}
.drawer.open { transform: none; visibility: visible; transition: transform .2s ease; }
.drawer header { display: flex; justify-content: space-between; align-items: center; padding: 10px 12px; border-bottom: 1px solid #000; box-shadow: 0 1px 0 rgba(255,255,255,.06); }
.drawer .items { flex: 1; overflow: auto; }
.drawer .items > p { padding: 0 12px; }
.drawer .line { display: flex; justify-content: space-between; gap: 10px; padding: 8px 12px; border-bottom: 1px solid rgba(255,255,255,.04); }
.drawer .line { align-items: center; }
.drawer .line-cover { width: 40px; height: 40px; flex: none; border-radius: 50%; object-fit: cover; }
.drawer .line-title { flex: 1; min-width: 0; }
.drawer .line-link { color: inherit; text-decoration: none; }
.drawer .line-link:hover, .drawer .line-link:focus-visible { text-decoration: underline; }
.drawer .line:nth-child(even) { background: rgba(255,255,255,.025); }
.drawer .free { font-weight: 700; color: #fff; }
.drawer footer { padding: 12px; border-top: 1px solid #000; box-shadow: inset 0 1px 0 rgba(255,255,255,.06); }
.drawer footer p { margin: 0 0 10px; }
.checkout { width: 100%; padding: 8px; font-size: 12px; }
.drawer footer .checkout-note { margin: 8px 0 2px; font-size: 12px; line-height: 1.4; color: #ffb4b4; text-align: center; } /* why checkout didn't open (app.js) */
html[data-mode="light"] .drawer footer .checkout-note { color: #a12a2a; }
.checkout-note[hidden] { display: none; }
@media (min-width: 761px) { .drawer .m-grab { display: none; } } /* the drag handle is for the phones' bottom sheet only */
.x { color: var(--muted); font-size: 18px; }
.drawer .x { min-width: 36px; min-height: 36px; } /* a fingertip, not a hairline */

/* ---------- status bar ---------- */
.statusbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 10; height: 24px; display: flex; justify-content: center; gap: 22px; align-items: center;
  font-size: 11px; color: #a9b2b8; background: var(--shine), linear-gradient(180deg, rgba(30,33,36,.95), rgba(6,7,8,.98));
  border-top: 1px solid #000; box-shadow: inset 0 1px 0 rgba(255,255,255,.08);
}
.statusbar a:hover { color: #fff; }
@media (max-width: 600px) { .statusbar span:first-child { display: none; } }

/* ---------- thanks page ---------- */
.top { display: flex; padding: 10px 14px; background: var(--shine), linear-gradient(180deg, rgba(34,37,40,.92), rgba(6,7,8,.96)); border-bottom: 1px solid #000; }
.page { max-width: 680px; margin: 0 auto; padding: 28px 16px 60px; }
.page h1 { font: 700 26px var(--ui); }
.files a { display: inline-block; margin: 6px 8px 0 0; }
.license { background: #fff; color: #111; border: 1px solid #999; padding: 22px; margin-top: 14px; line-height: 1.5; }

@media print { body * { visibility: hidden; } .license, .license * { visibility: visible; } .license { position: absolute; inset: 0; } }

/* ================= Light mode (2000s glass, bright) ================= */
html[data-mode="light"] {
  --bg: #e9eef2;
  --text: #1b2126;
  --muted: #5d6871;
  --edge: rgba(255, 255, 255, .95);
  --cool: rgba(120, 170, 210, .25);
  --shine: linear-gradient(180deg, rgba(255,255,255,.9) 0%, rgba(255,255,255,.35) 49%, rgba(255,255,255,0) 50%);
  color-scheme: light;
}
html[data-mode="light"], html[data-mode="light"] body { background: radial-gradient(1200px 600px at 50% -10%, #ffffff, #e9eef2 55%, #d6dde3); background-attachment: fixed; }

/* Light mode: the visualizers are drawn on black, so the pictures are inverted (hues kept) to sit on a light background. */
html[data-mode="light"] :is(#viz, #viz-egg) { filter: invert(1) hue-rotate(180deg); }

html[data-mode="light"] .glassbtn, html[data-mode="light"] .tbtn, html[data-mode="light"] .lcd-buy, html[data-mode="light"] .cart-btn,
html[data-mode="light"] .play, html[data-mode="light"] .price-btn, html[data-mode="light"] .add, html[data-mode="light"] .checkout,
html[data-mode="light"] .btn, html[data-mode="light"] .files a, html[data-mode="light"] .mode-btn {
  color: #1d2328; text-shadow: 0 1px 0 rgba(255,255,255,.8); border-color: #8d979f;
  background: var(--shine), linear-gradient(180deg, #ffffff 0%, #d9e0e5 100%);
  box-shadow: inset 0 1px 0 #fff, 0 1px 2px rgba(60,80,95,.35);
}
html[data-mode="light"] .tbtn:hover, html[data-mode="light"] .lcd-buy:hover, html[data-mode="light"] .cart-btn:hover,
html[data-mode="light"] .play:hover, html[data-mode="light"] .price-btn:hover, html[data-mode="light"] .add:hover,
html[data-mode="light"] .checkout:hover, html[data-mode="light"] .btn:hover, html[data-mode="light"] .files a:hover, html[data-mode="light"] .mode-btn:hover {
  background: var(--shine), linear-gradient(180deg, #ffffff 0%, #e6ecf0 100%);
  box-shadow: inset 0 1px 0 #fff, 0 0 8px var(--cool), 0 1px 2px rgba(60,80,95,.35);
}

html[data-mode="light"] .toolbar, html[data-mode="light"] .statusbar, html[data-mode="light"] .top {
  background: var(--shine), linear-gradient(180deg, rgba(250,252,253,.95), rgba(214,222,228,.95));
  border-color: #a3adb5; box-shadow: inset 0 1px 0 #fff, 0 2px 12px rgba(60,80,95,.18); color: #2a3137;
}
html[data-mode="light"] .lcd {
  background: linear-gradient(180deg, rgba(255,255,255,.7) 0%, rgba(255,255,255,0) 45%), linear-gradient(180deg, #eef1e8, #d7dccf);
  border-color: #7d8790; box-shadow: inset 0 1px 3px rgba(0,0,0,.25), 0 1px 0 #fff;
}
html[data-mode="light"] .lcd-title { color: #1b2126; text-shadow: none; }
html[data-mode="light"] .lcd-row { color: #5b646b; }
html[data-mode="light"] .lcd .bar { background: #f7f8f5; border-color: #8b949b; box-shadow: inset 0 1px 2px rgba(0,0,0,.2); }
html[data-mode="light"] .lcd .fill { background: var(--shine), linear-gradient(90deg, #6f7a83, #3d464d); box-shadow: none; }
html[data-mode="light"] .wordmark { color: #20262b; text-shadow: 0 1px 0 #fff; }
html[data-mode="light"] .cart-btn b { color: #10161a; }
html[data-mode="light"] .vol input { background: linear-gradient(90deg, #6f7a83 0, #3d464d var(--fill, 80%), #f4f6f7 var(--fill, 80%)); border-color: #7d8790; }

html[data-mode="light"] .search { background-color: #fff; color: #1b2126; border-color: #8d979f; box-shadow: inset 0 1px 2px rgba(0,0,0,.18); }
html[data-mode="light"] .table, html[data-mode="light"] .tiers { border-color: #8d979f; box-shadow: 0 6px 20px rgba(60,80,95,.18); }
html[data-mode="light"] .thead { color: #2a3137; background: var(--shine), linear-gradient(180deg, #f7f9fa, #d3dadf); border-color: #9aa4ac; }
html[data-mode="light"] .thead span + span { border-left-color: #b4bdc4; box-shadow: inset 1px 0 0 #fff; }
html[data-mode="light"] .row, html[data-mode="light"] .tier, html[data-mode="light"] .empty { background: rgba(255,255,255,.6); border-bottom-color: rgba(0,0,0,.04); }
html[data-mode="light"] .row.alt, html[data-mode="light"] .tier:nth-child(even) { background: rgba(237,242,245,.65); }
html[data-mode="light"] .row:hover { background: rgba(222,231,237,.85); }
html[data-mode="light"] .row.playing { background: var(--shine), linear-gradient(180deg, #c9d4dc, #9fadb8); box-shadow: inset 0 1px 0 #fff; }
html[data-mode="light"] .row.playing .t, html[data-mode="light"] .row.playing .idx { color: #10161a; text-shadow: 0 1px 0 rgba(255,255,255,.6); }
html[data-mode="light"] .row img, html[data-mode="light"] .lcd img { border-color: #7d8790; }
html[data-mode="light"] .drawer { background: var(--shine), linear-gradient(180deg, #f7f9fa, #dfe5e9); border-color: #9aa4ac; color: #1b2126; }
html[data-mode="light"] .drawer header, html[data-mode="light"] .drawer footer { border-color: #b4bdc4; box-shadow: none; }
html[data-mode="light"] .drawer .line { border-color: #d3dadf; }
html[data-mode="light"] .drawer .free { color: #10161a; }
html[data-mode="light"] .beat h1 { text-shadow: none; }
html[data-mode="light"] .beat .art img { box-shadow: 0 0 0 1px #9aa4ac, 0 12px 30px rgba(60,80,95,.3); }
/* Covers are cut-out circles (transparent around the dish): black behind them in dark mode, white in light. */
.row img, .lcd img, .beat .art img, #feature img { background-color: #000; background-size: cover; }
html[data-mode="light"] .row img, html[data-mode="light"] .lcd img, html[data-mode="light"] .beat .art img, html[data-mode="light"] #feature img { background-color: #fff; }

/* Light/dark switch button */
.mode-btn { width: 26px; height: 26px; border-radius: 50%; font-size: 13px; line-height: 1; padding: 0; }

/* Fallback note when a browser blocks new tabs from the HARZ logo */
.link-note { position: fixed; top: 70px; right: 16px; z-index: 30; padding: 8px 12px; border-radius: 8px; font-size: 12px;
  color: var(--text); background: var(--shine), var(--glass); border: 1px solid #000; box-shadow: inset 0 1px 0 var(--edge), 0 6px 20px rgba(0,0,0,.6);
  opacity: 0; transform: translateY(-6px); pointer-events: none; transition: opacity .2s, transform .2s; }
.link-note.show { opacity: 1; transform: none; pointer-events: auto; }
.link-note a { text-decoration: underline; }
html[data-mode="light"] .link-note { background: var(--shine), linear-gradient(180deg, #ffffff, #dfe5e9); border-color: #9aa4ac; }
.filter-right { display: flex; align-items: center; gap: 12px; }

/* "All beats": a physical key with real depth; it travels down into the panel when pressed. */
.cart-btn.back {
  padding: 8px 16px 7px; border-radius: 9px; letter-spacing: .04em; text-transform: uppercase; font-size: 11px;
  background: var(--shine), linear-gradient(180deg, #4a5056 0%, #24282b 55%, #1a1d1f 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28), inset 0 -2px 0 rgba(0,0,0,.45),
    0 1px 0 #2b2f33, 0 2px 0 #1e2124, 0 3px 0 #141618, 0 4px 0 #0a0b0c, 0 6px 10px rgba(0,0,0,.7);
  transform: translateY(0); transition: transform .08s ease-out, box-shadow .08s ease-out;
}
.cart-btn.back:hover { background: var(--shine), linear-gradient(180deg, #575e64 0%, #2b3034 55%, #1f2225 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.32), inset 0 -2px 0 rgba(0,0,0,.45),
    0 1px 0 #2b2f33, 0 2px 0 #1e2124, 0 3px 0 #141618, 0 4px 0 #0a0b0c, 0 6px 12px rgba(0,0,0,.7), 0 0 12px var(--cool); }
.cart-btn.back:active { transform: translateY(3px);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.7), 0 1px 0 #0a0b0c, 0 2px 4px rgba(0,0,0,.6); }
html[data-mode="light"] .cart-btn.back {
  background: var(--shine), linear-gradient(180deg, #ffffff 0%, #dfe5ea 60%, #cdd5db 100%);
  box-shadow: inset 0 1px 0 #fff, inset 0 -2px 0 rgba(90,105,118,.25),
    0 1px 0 #b7c0c7, 0 2px 0 #a6b0b8, 0 3px 0 #96a1aa, 0 4px 0 #87929b, 0 6px 10px rgba(60,80,95,.35);
}
html[data-mode="light"] .cart-btn.back:active { box-shadow: inset 0 1px 3px rgba(60,80,95,.45), 0 1px 0 #87929b, 0 2px 4px rgba(60,80,95,.3); }

/* Cursor hides after a few seconds without movement (viz-switch.js) and comes back on the next move. */

/* Admin-only rename pencils (shown once /api/admin/me confirms the session). */
.edit { display: none; width: 18px; height: 18px; margin-left: 4px; padding: 0; border-radius: 4px; font-size: 11px; line-height: 18px;
  color: var(--muted); opacity: .6; vertical-align: middle; flex: none; }
html.admin .edit { display: inline-block; }
html.admin .edit[hidden] { display: none; }
.lcd-title-row { display: flex; justify-content: center; align-items: center; min-width: 0; }
.lcd-title-row .lcd-title { min-width: 0; }
.edit:hover { opacity: 1; color: var(--text); background: rgba(255,255,255,.08); }
.row .t-wrap { display: flex; align-items: center; min-width: 0; }
.rename { font: inherit; font-weight: 600; width: 100%; min-width: 0; padding: 1px 4px; border-radius: 4px;
  color: var(--text); background: rgba(0,0,0,.6); border: 1px solid rgba(200,230,255,.35); }
html[data-mode="light"] .rename { background: #fff; border-color: #8d979f; }
.row .t-wrap .t { min-width: 0; }

/* Visualizer switch (list page and beat pages), shown only while audio plays. It keeps its space so nothing shifts. */
:is(#p-vizstyle, #p-switchup) { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .25s ease, visibility 0s .25s; }
html.viz-live :is(#p-vizstyle, #p-switchup) { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity .25s ease; }
html.viz-live :is(#p-vizstyle, #p-switchup)[aria-pressed="false"] { opacity: .4; } /* switched off */

/* ---------- Beats / loops toggle (the counter): one button, the whole list changes over ---------- */
.list-mode { display: inline-flex; padding: 0; overflow: hidden; white-space: nowrap; }
.list-mode span { padding: 4px 11px; opacity: .55; transition: opacity .15s, background .15s; }
.list-mode span + span { border-left: 1px solid rgba(0,0,0,.55); box-shadow: inset 1px 0 0 rgba(255,255,255,.06); }
.list-mode span.on { opacity: 1; background: rgba(255,255,255,.1); box-shadow: inset 0 0 10px var(--cool); }
html[data-mode="light"] .list-mode span.on { background: rgba(255,255,255,.7); }
html[data-mode="light"] .list-mode span + span { border-color: rgba(0,0,0,.18); box-shadow: none; }
/* Loops only: All / Solo / Collab, the same pill look with a real button per choice. */
.kind-switch[hidden] { display: none; }
/* The Beats / Loops switch stays put: counts keep their width as they change, the visualizer button keeps one
   width whatever its label, and the Solo / Collab pill opens to the left of the switch. */
#count b { display: inline-block; min-width: 4ch; text-align: left; font-variant-numeric: tabular-nums; }
:is(#p-vizstyle, #p-switchup) { min-width: 7.2em; text-align: center; }
.kind-switch button { padding: 4px 11px; border: 0; background: none; color: inherit; font: inherit; cursor: pointer; opacity: .55; transition: opacity .15s, background .15s; }
.kind-switch button + button { border-left: 1px solid rgba(0,0,0,.55); box-shadow: inset 1px 0 0 rgba(255,255,255,.06); }
.kind-switch button.on { opacity: 1; background: rgba(255,255,255,.1); box-shadow: inset 0 0 10px var(--cool); }
html[data-mode="light"] .kind-switch button.on { background: rgba(255,255,255,.7); }
html[data-mode="light"] .kind-switch button + button { border-color: rgba(0,0,0,.18); box-shadow: none; }
.player-link { white-space: nowrap; }
@media (max-width: 600px) {
  .filterbar { flex-wrap: wrap; }
  .search { width: auto; flex: 1 1 120px; min-width: 0; }
  .filter-right { gap: 6px; }
}

/* Progress bar: a taller invisible hit area (easy to grab on touch screens) without changing how it looks;
   touch drags seek instead of scrolling the page. */
.lcd .bar { touch-action: none; }
.lcd .bar::before { content: ""; position: absolute; inset: -9px 0; }
.lcd .bar:focus-visible { outline: 1px solid rgba(200,230,255,.6); outline-offset: 2px; }
.lcd .bar.scrubbing .fill { transition: none; }

/* The list page starts flush under the toolbar, so the sticky bar sits in the same place scrolled or not. */
.window:has(.filterbar) { margin-top: 0; }
/* The search / beats-loops / visualizer bar stays reachable under the toolbar while the list scrolls. */
.filterbar { position: sticky; top: var(--sticky-top, 56px); z-index: 5; margin: 0 -14px 8px; padding: 6px 14px;
  background: linear-gradient(180deg, rgba(6,7,8,.82), rgba(6,7,8,.6)); backdrop-filter: blur(8px); }
html[data-mode="light"] .filterbar { background: linear-gradient(180deg, rgba(240,243,245,.85), rgba(240,243,245,.65)); }

/* Back to top: appears once the page is scrolled well down; bottom-right, placed between the Key and Price columns by app.js. */
.to-top { position: fixed; right: 16px; bottom: 16px; z-index: 15; zoom: 1.25; width: 30px; height: 30px; padding: 0; border-radius: 50%;
  font-size: 11px; opacity: 0; visibility: hidden; transform: translateY(6px); transition: opacity .25s, transform .25s, visibility 0s .25s; }
.to-top.show { opacity: 1; visibility: visible; transform: none; transition: opacity .25s, transform .25s; }
.to-top { display: inline-grid; place-items: center; touch-action: manipulation; }
.to-top svg.ic { width: 14px; height: 14px; vertical-align: 0; }
html.immersive .to-top { opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .to-top, .to-top.show { transition: none; transform: none; } }

/* Admin edit dialog */
.editor { width: min(400px, calc(100vw - 32px)); padding: 18px; border-radius: 10px; border: 1px solid #000; color: var(--text); zoom: 1.25;
  background: var(--shine), linear-gradient(180deg, #2a2e32, #121416); box-shadow: inset 0 1px 0 var(--edge), 0 10px 30px rgba(0,0,0,.6); }
.editor::backdrop { background: rgba(0,0,0,.55); }
.editor h2 { font-size: 14px; margin: 0 0 10px; }
.editor label { display: block; font-size: 11px; color: var(--muted); margin-bottom: 8px; }
.editor .search { display: block; width: 100%; margin-top: 3px; padding-left: 10px; background-image: none; }
.editor .pair { display: grid; grid-template-columns: 1fr 90px; gap: 10px; }
.editor .source { font-size: 11px; margin: -4px 0 10px; overflow-wrap: anywhere; user-select: all; }
.editor .shown-as { font-size: 11px; margin: 2px 0 6px; overflow-wrap: anywhere; }
.editor .msg { min-height: 1.2em; font-size: 12px; margin: 4px 0 10px; }
.editor .actions { display: flex; gap: 8px; align-items: center; }
.editor .grow { flex: 1; }
.admin-tools { display: inline-flex; flex: none; align-items: center; }
.edit.regen, .edit.star { margin-left: 1px; }
.edit.star { font-size: 12px; }
.edit.star.on { opacity: 1; color: var(--text); text-shadow: 0 0 6px rgba(190,225,255,.45); } /* starred: in the ☆ shelf (phone.js) */
html[data-mode="light"] .edit.star.on { text-shadow: none; }
.edit.listen { margin-left: 1px; font-size: 12px; }
.edit.listen.on { opacity: 1; color: var(--text); } /* listen only: not for sale */
.listen-tag { justify-self: end; font-size: 10px; color: var(--muted); padding: 2px 9px; white-space: nowrap; }
.btn.listen-tag { font-size: inherit; cursor: default; }
.listen-note { color: var(--muted); }
.edit.regen:disabled { opacity: 1; animation: regen-busy .8s linear infinite; }
@keyframes regen-busy { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) { .edit.regen:disabled { animation: none; } }
.editor .del { color: #ff9b9b; }
.editor .vibe-edit { border: 1px solid rgba(255,255,255,.12); border-radius: 8px; padding: 8px 10px 10px; margin: 2px 0 8px; }
.editor .vibe-edit legend { font-size: 11px; color: var(--muted); padding: 0 4px; }
.editor .vibe-edit select { width: 100%; margin: 0 0 8px; font: inherit; font-size: 12px; padding: 4px 6px; border-radius: 6px; }
.editor .slider { display: grid; grid-template-columns: 62px 1fr 62px; align-items: center; gap: 6px; margin: 0 0 4px; font-size: 10px; }
.editor .slider span:last-child { text-align: right; }
.editor .slider input { width: 100%; margin: 0; accent-color: var(--text); }
.editor .slider input:not([data-touched]) { opacity: .45; } /* not set: the analysis decides */
.editor .vibe-edit .btn { margin-top: 6px; font-size: 11px; }
html[data-mode="light"] .editor { background: var(--shine), linear-gradient(180deg, #ffffff, #dfe5e9); border-color: #9aa4ac; }
html[data-mode="light"] .editor .del { color: #b02020; }
.toast { top: auto; bottom: 60px; right: 16px; }

/* ---------- beat page: back key and visualizer switch side by side ---------- */
.beat-tools { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.beat-tools .back { margin-bottom: 0; }

/* ---------- light / dark: one cross-fade of the whole page (viz-core.js harzSwapTheme) ---------- */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .25s; animation-timing-function: cubic-bezier(.2, 0, 0, 1); } /* quick and starting at once: the switch answers the click */
/* ---------- page to page (app.js navigate): the two pages cross-fade in one go, no gap between them ---------- */
/* Only <main> moves; the header, player and visualizer stay put. Both pages share one duration and curve, so their
   opacities always add up to one and the screen never dips. Phones slide sideways (forward: left; back: right). */
html.vt-page { --vt-x: -24px; --vt-y: 0px; }
html.vt-page.vt-back { --vt-x: 24px; }
@media (min-width: 761px) { html.vt-page { --vt-x: 0px; --vt-y: -8px; } html.vt-page.vt-back { --vt-y: 8px; } }
html.vt-page main { view-transition-name: page; }
/* The page's snapshot is drawn above the whole live page, so the player bar (fixed over the content on phones) and
   the status bar get layers of their own: those come after the page's (they paint above it) and stay still. */
html.vt-page .toolbar { view-transition-name: player; }
html.vt-page .statusbar { view-transition-name: statusbar; }
html.vt-page::view-transition-old(player), html.vt-page::view-transition-old(statusbar) { display: none; }
html.vt-page::view-transition-new(player), html.vt-page::view-transition-new(statusbar) { animation: none; }
html.vt-page::view-transition-group(player), html.vt-page::view-transition-group(statusbar) { animation: none; }
html.vt-page::view-transition-old(root), html.vt-page::view-transition-new(root) { animation: none; }
html.vt-page::view-transition-old(page) { animation: vt-page-out .26s cubic-bezier(.4, 0, .2, 1) both; }
html.vt-page::view-transition-new(page) { animation: vt-page-in .26s cubic-bezier(.4, 0, .2, 1) both; }
@keyframes vt-page-out { to { opacity: 0; transform: translate(var(--vt-x), var(--vt-y)); } }
@keyframes vt-page-in { from { opacity: 0; transform: translate(calc(var(--vt-x) * -1), calc(var(--vt-y) * -1)); } }
/* Browsers without view transitions: colours, surfaces and the visualizer's filter glide instead of jumping. */
html.theme-fade, html.theme-fade body, html.theme-fade *, html.theme-fade *::before, html.theme-fade *::after {
  transition: background-color .25s ease-out, color .25s ease-out, border-color .25s ease-out, box-shadow .25s ease-out, filter .25s ease-out, opacity .25s ease-out !important; }


/* ---------- lighter effects (phones and tablets from the start; any device whose frames run late) ----------
   Blurring the glass over a moving full-screen canvas is the most expensive thing on the page: the bars get a
   more solid tint instead. */
html.lowfx .toolbar, html.lowfx .filterbar { backdrop-filter: none; -webkit-backdrop-filter: none; }
html.lowfx .filterbar { background: linear-gradient(180deg, rgba(6,7,8,.93), rgba(6,7,8,.84)); }
html.lowfx[data-mode="light"] .filterbar { background: linear-gradient(180deg, rgba(240,243,245,.95), rgba(240,243,245,.88)); }

/* ---------- phones and small windows ---------- */
/* Covers keep their square before they load, so rows and pages never jump. */
.beat .art img { aspect-ratio: 1 / 1; object-fit: cover; }
#feature img { aspect-ratio: 1 / 1; object-fit: cover; }
.statusbar { padding-bottom: env(safe-area-inset-bottom); height: calc(24px + env(safe-area-inset-bottom)); }
@media (hover: none) {
  /* No sticky hover tints after a tap. */
  .row:hover { background: rgba(10,11,12,.55); }
  .row.alt:hover { background: rgba(20,22,24,.6); }
  html[data-mode="light"] .row:hover { background: rgba(255,255,255,.6); }
  html[data-mode="light"] .row.alt:hover { background: rgba(237,242,245,.65); }
}
@media (pointer: coarse) {
  /* Finger-sized targets (the UI is zoomed 1.25x: 28px here is 35px on screen). */
  .play { width: 28px; height: 28px; font-size: 10px; }
  .row { height: 40px; }
  .list .row { contain-intrinsic-size: auto 40px; }
  .tbtn { width: 34px; height: 34px; }
  .tbtn.big { width: 40px; height: 40px; }
  .mode-btn { width: 30px; height: 30px; }
  .price-btn { padding: 5px 10px; }
  .cart-btn { padding: 6px 12px; }
  .edit { width: 26px; height: 26px; line-height: 26px; }
  /* 13px x 1.25 zoom = 16px: phones don't zoom the page when the search box is tapped. */
  .search, .editor .search { font-size: 13px; }
  .lcd .bar { height: 8px; }
  .lcd .bar::before { inset: -12px 0; }
}
@media (max-width: 600px) {
  .window { padding: 0 10px; }
  .filterbar { margin: 0 -10px 8px; padding: 6px 10px; gap: 6px; }
  .filter-right { flex-wrap: wrap; justify-content: flex-end; row-gap: 6px; }
  :is(#p-vizstyle, #p-switchup) { min-width: 6.4em; }
  .toolbar { gap: 8px 10px; padding: 6px 10px; }
  .right { gap: 8px; }
  .lcd { grid-template-columns: 34px minmax(0, 1fr) auto; gap: 8px; }
  .lcd img { width: 34px; height: 34px; }
  .beat { gap: 16px; padding-top: 6px; }
  .beat .art { max-width: 420px; width: 100%; justify-self: center; }
  .beat h1 { font-size: 24px; overflow-wrap: anywhere; }
  .tier { flex-wrap: wrap; }
  .to-top { right: 10px; bottom: calc(34px + env(safe-area-inset-bottom)); }
}
@media (max-width: 380px) {
  /* Narrow phones: the UI zoom steps down a little so the toolbar and filter bar keep everything on screen. */
  .toolbar, .window, .statusbar, .drawer, .page, .top, .editor, .to-top { zoom: 1.1; }
  .drawer { width: 90.9vw; } /* 90.9vw x zoom 1.1 = full phone width */
  .transport { gap: 4px; }
  #p-shuffle { display: inline-block; }
}

/* When a beat or loop was made (from its audio file's tags): small, under the BPM | key line. */
.beat .made { color: var(--muted); font-size: 10px; letter-spacing: .12em; text-transform: uppercase; margin: -8px 0 14px; opacity: .8; }

/* ---------- beat / loop page text over the moving visualizer ----------
   Credit, BPM | key and year are full white on dark (full black on light) instead of grey, and every line of the
   heading block gets a soft, tight shadow (a dark halo on dark, a white halo on light) so it stays readable
   whatever the visualizer draws behind it. Shadows only: no outlines, no boxes, the look stays clean. */
:root { --page-ink: #fff; --page-halo: 0 1px 2px rgba(0,0,0,.9), 0 0 6px rgba(0,0,0,.55); }
html[data-mode="light"] { --page-ink: #000; --page-halo: 0 1px 1px rgba(255,255,255,.95), 0 0 6px rgba(255,255,255,.7); }
.beat .coprod, .beat .sub, .beat .made { color: var(--page-ink); opacity: 1; text-shadow: var(--page-halo); }
.beat h1, html[data-mode="light"] .beat h1 { color: var(--page-ink); text-shadow: var(--page-halo); }

/* Visualizer switch on beat and loop pages: a quiet chip a little below the back key, full strength on hover or
   focus, so it is always one tap away without sitting in the picture. */
.beat-tools { align-items: flex-start; }
.beat-tools :is(#p-vizstyle, #p-switchup) { margin-top: 8px; padding: 3px 9px; font-size: 10px; min-width: 6.2em; border-radius: 10px; }
html.viz-live .beat-tools :is(#p-vizstyle, #p-switchup) { opacity: .5; }
html.viz-live .beat-tools :is(#p-vizstyle, #p-switchup):is(:hover, :focus-visible) { opacity: 1; }
html.viz-live .beat-tools :is(#p-vizstyle, #p-switchup)[aria-pressed="false"]:not(:hover, :focus-visible) { opacity: .22; } /* switched off */
@media (hover: none) { html.viz-live .beat-tools :is(#p-vizstyle, #p-switchup) { opacity: .65; } }

/* Now-playing cover turns like a record while playing (app.js spinCover drives a transform-only animation). */
.lcd img { will-change: transform; backface-visibility: hidden; }
/* Loop rows link to their page like beat rows do. */
.table.loops .row .t:hover { text-decoration: underline; }
/* Phones only: one compact row under the search box, so the visualizer keeps more of the screen: the visualizer
   button on the left, Beats / Loops centred between it and Player on the right (on loops, All / Solo / Collab
   centred under them). Both side buttons are icons here, spectrum bars and the note (the full labels stay on bigger
   screens; the visualizer button names the current style in its tooltip and to screen readers). The visualizer
   button keeps its place while hidden (before anything plays), so Beats / Loops never moves when it appears. */
@media (max-width: 600px) {
  .filter-right { flex: 1 1 100%; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 6px; }
  .filter-right > :is(#p-vizstyle, #p-switchup) { grid-area: 1 / 1; justify-self: start; align-self: stretch; min-width: 0; width: auto; padding-inline: 11px; font-size: 0; }
  .filter-right > :is(#p-vizstyle, #p-switchup)::before { content: ""; display: block; width: 12px; height: 12px; background: currentColor;
    -webkit-mask: var(--viz-icon) center / contain no-repeat; mask: var(--viz-icon) center / contain no-repeat; }
  .filter-right > :is(#p-vizstyle, #p-switchup) { --viz-icon: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 12 12%27%3E%3Cpath fill-rule=%27evenodd%27 d=%27M6 2.2C3.4 2.2 1.3 4.1.2 6c1.1 1.9 3.2 3.8 5.8 3.8s4.7-1.9 5.8-3.8C10.7 4.1 8.6 2.2 6 2.2zm0 1.1c2 0 3.6 1.3 4.5 2.7C9.6 7.4 8 8.7 6 8.7S2.4 7.4 1.5 6C2.4 4.6 4 3.3 6 3.3z%27/%3E%3Ccircle cx=%276%27 cy=%276%27 r=%271.6%27/%3E%3C/svg%3E"); display: inline-flex; align-items: center; justify-content: center; }
  .filter-right > .player-link .label { display: none; }
  .filter-right > #count { grid-area: 1 / 2; justify-self: center; }
  .filter-right > .player-link { grid-area: 1 / 3; justify-self: end; align-self: stretch; display: inline-flex; align-items: center; padding-inline: 11px; }
  .filter-right > #loop-kind { grid-area: 2 / 1 / 3 / 4; justify-self: center; }
  .list-mode span { padding-inline: 9px; }
}
@media (max-width: 360px) { .list-mode span { padding-inline: 7px; } }
/* Phones: the toolbar's buttons (transport, light/dark, cart) sit centred above the now-playing display. */
@media (max-width: 760px) {
  .toolbar { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; }
  .toolbar .lcd { flex: 1 1 100%; order: 3; }
}

/* ---------- covers are round ----------
   Every cover is a dish cut to a circle with a transparent surround (engine/site.py cutouts), so its frame follows
   the circle: no square border, backing or box shadow around it, and on the big covers a shadow that follows the
   disc's own shape. While a big cover loads, a dark disc the size of the dish (43% radius, engine/dish.py DISH_R)
   holds its place, so a page never shows an empty white square. */
.row img, .lcd img, .beat .art img, #feature img,
html[data-mode="light"] :is(.row img, .lcd img, .beat .art img, #feature img) {
  border: 0; border-radius: 50%; background-color: transparent; box-shadow: none; }
.beat .art img, #feature img { filter: drop-shadow(0 12px 20px rgba(0,0,0,.55)); }
html[data-mode="light"] :is(.beat .art img, #feature img) { filter: drop-shadow(0 10px 18px rgba(60,80,95,.3)); }
.beat .art { position: relative; isolation: isolate; }
.beat .art::before { content: ""; position: absolute; left: 7%; top: 7%; width: 86%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, #1c1f22, #050506); z-index: -1; }

.cart-tab { display: none; } /* the phone bar's cart (below) */

/* ---------- phones: one now-playing panel along the bottom (thumb reach), nothing on top ----------
   The toolbar moves to the bottom edge as a single panel: the now-playing display (cover, title, seek, Buy) and
   under it the transport in five even slots (shuffle, previous, play / pause, next, and the cart in the store or
   repeat in the Player), so play / pause is always dead centre. The top of the screen is left to the search and
   Beats / Loops bar alone. The panel fades with the rest of the UI in immersive mode and sits under the cart drawer.
   Sizes are before the UI zoom (x1.25): 38px buttons are 48px on screen, play 58px. The light / dark switch and the
   wordmark are not shown here (touch screens follow the device's setting: viz-core.js). */
@media (max-width: 760px) {
  .toolbar { position: fixed; top: auto; bottom: 0; left: 0; right: 0; z-index: 10;
    display: flex; flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 6px;
    padding: 7px max(10px, env(safe-area-inset-right)) calc(5px + env(safe-area-inset-bottom) / 1.25) max(10px, env(safe-area-inset-left));
    border-bottom: 0; border-top: 1px solid #000; box-shadow: inset 0 1px 0 var(--edge), 0 -6px 20px rgba(0,0,0,.55); }
  .toolbar { background: linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,0) 40%), linear-gradient(180deg, #202326, #08090a); } /* solid: the list never shows through */
  html[data-mode="light"] .toolbar { background: linear-gradient(180deg, #fafcfd, #d9e0e5); }
  html[data-mode="light"] .toolbar { border-top-color: #a3adb5; box-shadow: inset 0 1px 0 #fff, 0 -2px 12px rgba(60,80,95,.18); }
  .toolbar .lcd { order: 0; flex: none; width: 100%; max-width: none; grid-column: auto; }
  .toolbar .right { display: none; }
  .toolbar .transport { order: 1; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); justify-items: center;
    align-items: center; gap: 0; touch-action: manipulation; }
  .transport #p-shuffle { grid-column: 1; grid-row: 1; }
  .transport #p-prev { grid-column: 2; grid-row: 1; }
  .transport #p-toggle { grid-column: 3; grid-row: 1; }
  .transport #p-next { grid-column: 4; grid-row: 1; }
  .transport #p-repeat, .transport .cart-tab { grid-column: 5; grid-row: 1; }
  .transport .tbtn { width: 38px; height: 38px; font-size: 13px; }
  .transport .tbtn.big { width: 46px; height: 46px; font-size: 16px; }
  .transport #p-shuffle, .transport #p-repeat { font-size: 15px; }
  .transport .cart-tab { display: inline-grid; place-items: center; }
  .transport .cart-tab::before { content: ""; width: 17px; height: 17px; background: currentColor;
    -webkit-mask: var(--bag) center / contain no-repeat; mask: var(--bag) center / contain no-repeat;
    --bag: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-.45 .45 24 24%27 fill=%27none%27 stroke=%27%23000%27 stroke-width=%272%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M2.5 4h2.6l2.3 11h10.9l2.2-7.8H6.2%27/%3E%3Ccircle cx=%279.5%27 cy=%2719.5%27 r=%271.4%27/%3E%3Ccircle cx=%2717%27 cy=%2719.5%27 r=%271.4%27/%3E%3C/svg%3E");; }
  .cart-tab b { position: absolute; top: -3px; right: -4px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
    font: 700 9px/16px var(--ui); color: #fff; text-shadow: none; background: linear-gradient(180deg, #e8453c, #a31a14);
    border: 1px solid #000; box-shadow: 0 1px 2px rgba(0,0,0,.6); }
  /* The search / Beats / Loops bar takes the top edge; the list scrolls clear of the panel. */
  .filterbar { top: 0; }
  .window { margin-top: 0; }
  body { padding-bottom: calc(170px + env(safe-area-inset-bottom)); }
  .to-top { bottom: calc(126px + env(safe-area-inset-bottom)); }
  .sitefoot { bottom: calc(128px + env(safe-area-inset-bottom)); } /* above the player panel */
}
/* Phones and tablets follow the device's light / dark setting (the head script and app.js / player.js): no switch. */
@media (hover: none) and (pointer: coarse) { .mode-btn { display: none; } }

/* ---------- phones: a cleaner list and beat page ----------
   List rows read as two lines: the name, and under it BPM and key in small type (so you can choose without opening
   every beat), with a slightly bigger cover and the price on the right. The column header goes (nothing to label).
   Beat and loop pages lead with the music: a smaller cover so the name and play button are on the first screen,
   the play button big and level with the name, and the licence buttons sized for thumbs. */
@media (max-width: 600px) {
  .thead { display: none; }
  .table .row { grid-template-columns: 30px 36px auto minmax(0, 1fr) auto; grid-template-rows: auto auto; column-gap: 10px; row-gap: 1px;
    min-height: 54px; padding-block: 7px; }
  .list .row { contain-intrinsic-size: auto 54px; }
  .table .row > .play { grid-area: 1 / 1 / 3 / 2; }
  .table .row > img, .table .row > span:empty { grid-area: 1 / 2 / 3 / 3; width: 36px; height: 36px; }
  .table .row > .t-wrap { grid-area: 1 / 3 / 2 / 5; align-self: end; flex-wrap: wrap; column-gap: 2px; }
  /* Whole words: a name only breaks between words (the owner's edit buttons drop under it instead of squeezing it
     into "EARTHQUA / KE"); only a single word longer than the whole line is broken. */
  .table .row .t { overflow-wrap: break-word; word-break: normal; }
  .table .row > .num { display: block; grid-area: 2 / 3; align-self: start; font-size: 10px; color: var(--muted); text-align: left; }
  .table .row > .key { display: block; grid-area: 2 / 4; margin-left: -6px; align-self: start; font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .table .row > .num:not(:empty)::after { content: " BPM"; }
  .table .row > .num:not(:empty) + .key:not(:empty)::before { content: "· "; }
  .table .row > .listen-tag { grid-area: 1 / 5 / 3 / 6; align-self: center; }
  .table .row > .price-btn { grid-area: 1 / 5 / 3 / 6; padding: 6px 10px; font-size: 11px; border-radius: 12px; }
  .table .row > .idx { display: none; }

  .beat .art { max-width: min(300px, 78vw); }
  .beat .info { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 14px; align-items: center; }
  .beat .info > * { grid-column: 1 / -1; }
  .beat .info > :is(h1, .coprod, .sub, .made) { grid-column: 1; }
  .beat .info > #beat-play { grid-column: 2; grid-row: 2 / span 4; align-self: center; width: 58px; height: 58px; font-size: 20px; }
  .beat .sub { margin-bottom: 6px; }
  .beat .made { margin: 0 0 4px; }
  .beat .tiers { margin-top: 16px; }
  .tier { padding: 12px; row-gap: 10px; }
  .tier .add { padding: 8px 20px; font-size: 12px; margin-left: auto; min-width: 128px; text-align: center; display: inline-flex; align-items: center; justify-content: center; }
  /* "Make an offer" is a link, not a cart button: same size as Add, readable text instead of the embossed grey. */
  .tier .add.ghost { color: #e6edf1; text-shadow: none; }
  html[data-mode="light"] .tier .add.ghost { color: #2a3238; }
  /* The now-playing panel: room under the time row, and a Buy button that matches the other rounded buttons. */
  .lcd { padding-bottom: 9px; }
  .lcd-buy { border-radius: 12px; padding: 8px 14px; }
}

/* ---------- vibe (engine/vibe.py): descriptor chips and "sounds like" on beat and loop pages ---------- */
.vibe-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 2px; }
.beat .vibe-row + .made { margin-top: 6px; } /* the year sat tucked under the tempo line; with the vibe words between, it gets its own space */
.vibe-chip { font-size: 11px; letter-spacing: .04em; text-transform: lowercase; padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--edge); background: var(--shine), rgba(20,22,24,.7); opacity: var(--c, .8); }
.similar { margin: 16px 0 4px; text-align: center; }
.similar h2 { font-size: 11px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin: 0 0 8px; }
.similar-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; justify-items: center; }
.similar-item { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; padding: 6px; border-radius: 8px; border: 1px solid transparent;
  min-width: 0; transition: background .15s ease, border-color .15s ease; }
.similar-item:hover, .similar-item:focus-visible { background: rgba(255,255,255,.06); border-color: var(--edge); }
.similar-item img { width: 44px; height: 44px; border-radius: 50%; flex: none; }
.similar-item span { font-size: 12px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
html[data-mode="light"] .vibe-chip { background: var(--shine), rgba(255,255,255,.7); }
@media (pointer: coarse) { .similar-item { min-height: 52px; } }
/* "Sounds like" over the moving visualizer: the same treatment as the heading block above it (full white with a dark
   halo on dark, full black with a soft white halo on light), so the heading and the track names read over any look. */
.similar h2, .similar-item span { color: var(--page-ink); text-shadow: var(--page-halo); }
.similar h2 { opacity: .9; }
.similar-item img { filter: drop-shadow(0 2px 4px rgba(0,0,0,.35)); }
/* Small covers (Similar, the cart): the cover's disc is cut at 41.8% of the picture with a clear margin round it, so
   the picture is scaled up until the disc fills the circle (scale, not transform: the cart's playing cover turns with a
   transform) and no dark ring shows round the CD. */
.similar-item img, .drawer .line-cover { scale: calc(1 / .836); background: none; }
html[data-mode="light"] .similar-item:hover, html[data-mode="light"] .similar-item:focus-visible { background: rgba(255,255,255,.55); }

/* Touch screens: every control at least 44 px tall (Apple / WCAG target size); desktop sizes unchanged. */
@media (pointer: coarse) {
  .cart-btn, .tiers .add, .tiers .add.ghost { min-height: 44px; }
  .lcd-buy { min-height: 38px; }
  .lcd-title { display: inline-block; padding: 12px 8px; margin: -12px -8px; } /* bigger hit area, same look */
}

/* ---------- records ----------
   The big cover on a beat / loop page is the plain round artwork and stays still. The now-playing cover at the top
   turns while sound is coming out and stops on the spot when it stops (vinyl.js). A click on either is play / pause. */
.vinyl { position: relative; display: block; aspect-ratio: 1; border-radius: 50%; isolation: isolate; contain: layout paint;
  cursor: pointer; -webkit-tap-highlight-color: transparent; -webkit-user-select: none; user-select: none; }
.vinyl:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.vinyl::before { content: ""; position: absolute; inset: 0; border-radius: 50%; z-index: -1; box-shadow: 0 14px 30px rgba(0,0,0,.5), 0 2px 4px rgba(0,0,0,.4); }
.vinyl-disc { position: absolute; inset: 0; border-radius: 50%; overflow: hidden; background: #0d0d0f;
  -webkit-mask-image: -webkit-radial-gradient(white, black); } /* Safari: a turning, round-clipped picture shows square corners and flickers unless the round shape is a mask */
/* The artwork's transparent surround is cut off by the disc's round edge, so the image is larger than the disc and
   centred absolutely (a grid centres an overflowing item from the top, which left the art hanging off the bottom). */
.vinyl-disc img, html[data-mode="light"] .vinyl-disc img { position: absolute; left: calc(50% - 50% / .836); top: calc(50% - 50% / .836); /* centred by offsets, not translate(-50%): Safari lost that offset and left the picture in a corner of the disc */
  width: calc(100% / .836) !important; /* the cover circle (cut at radius .418 of the image, engine/site.py) fills the disc */ height: auto !important; aspect-ratio: 1; max-width: none; object-fit: cover; border: 0 !important;
  box-shadow: none !important; filter: none !important; -webkit-box-reflect: none; background-color: transparent !important; pointer-events: none; }
/* A record's picture fades in once decoded (vinyl.js); no blurry thumbnail stand-in behind it on a turning disc. */
.vinyl-disc img { opacity: 0; transition: opacity .25s ease; background-image: none !important; }
.vinyl-disc img.ready { opacity: 1; }
/* The picture is what turns (vinyl.js), on its own layer inside the still round frame. */
.vinyl-disc img, .m-card.playing .m-card-art img { will-change: transform; backface-visibility: hidden; }
.vinyl.no-art .vinyl-disc img { visibility: hidden; }
.vinyl.no-art .vinyl-disc { background: radial-gradient(circle, #2a2d31 0 20%, #1d1f22 21% 100%); }
/* Sized as the covers always were: the disc takes 86% of the cover column, centred (the cut-out's transparent surround
   used to give it that margin). */
.beat .art.vinyl { width: 86%; margin: 7%; }
.beat .art.vinyl::before { inset: 0; left: 0; top: 0; width: auto; height: auto; aspect-ratio: auto; background: none; }
.art.vinyl .vinyl-disc img { will-change: auto; }
.vinyl { transition: transform .08s ease-out; }
.vinyl:active { transform: scale(.96); } /* pressed: shows at once, before the audio answers */
/* Now-playing bar: just the round artwork, no record dressing, and nothing at all until a track with art plays. */
.vinyl.mini { width: 34px; height: 34px; margin: 3px; flex: none; } /* the disc as it sat in the 40px cover */
.vinyl.mini::before { box-shadow: 0 1px 3px rgba(0,0,0,.5); }
/* Hidden only until a track is loaded; a track without a picture (or whose picture failed) gets the plain dark
   record, which can still be clicked to play or pause. */
.vinyl.mini.empty { visibility: hidden; }
@media (max-width: 600px) { .vinyl.mini { width: 29px; height: 29px; margin: 2.5px; } }
@media (prefers-reduced-motion: reduce) { .vinyl-disc img, .m-card-art img { will-change: auto; } }
/* ---------- the discs are CDs ----------
   The covers are printed CDs (engine/cdprint.py). The disc adds the see-through spindle hole, as a still mask (the
   hole of a real CD: 15 mm of 120), so the spin stays on the compositor. */
:root { --cd-hole: 12.5%; }
.vinyl-disc {
  -webkit-mask-image: radial-gradient(circle closest-side, transparent var(--cd-hole), #000 calc(var(--cd-hole) + .6%), #000 99.4%, transparent 100%);
  mask-image: radial-gradient(circle closest-side, transparent var(--cd-hole), #000 calc(var(--cd-hole) + .6%), #000 99.4%, transparent 100%); }
/* The CD overlay over every record: a clear plastic hub with its silver clamping ring, a bright rim and light glancing
   off the disc (proportions of a real CD: hub 33 mm, clamping ring 46 mm, of 120). One still layer above the turning
   picture, painted once and never repainted, outside the dark-mode colour flip so it stays silver in both modes. */
:root { --cd-hub: 27.5%; --cd-clamp: 38%;
  --cd-face:
    conic-gradient(from -40deg, transparent 0 3%, rgba(255,255,255,.13) 8%, transparent 14% 50%, rgba(255,255,255,.08) 57%, transparent 63%),
    radial-gradient(circle closest-side, rgba(255,255,255,.55) var(--cd-hole), rgba(220,228,236,.5) calc(var(--cd-hole) + 1%),
      rgba(200,210,220,.32) calc(var(--cd-hub) - 1%), rgba(255,255,255,.6) var(--cd-hub), rgba(170,180,190,.55) calc(var(--cd-hub) + .8%),
      rgba(205,212,220,.42) calc(var(--cd-clamp) - 1.2%), rgba(255,255,255,.35) calc(var(--cd-clamp) - .4%), rgba(0,0,0,.25) var(--cd-clamp),
      transparent calc(var(--cd-clamp) + 1.5%)),
    radial-gradient(circle closest-side, transparent 97.2%, rgba(255,255,255,.35) 98.6%, rgba(0,0,0,.35) 100%); }
.vinyl:not(.no-art)::after, .m-card-art::after { content: ""; position: absolute; inset: 0; border-radius: 50%; pointer-events: none; z-index: 2;
  background: var(--cd-face);
  -webkit-mask-image: radial-gradient(circle closest-side, transparent var(--cd-hole), #000 calc(var(--cd-hole) + .6%));
  mask-image: radial-gradient(circle closest-side, transparent var(--cd-hole), #000 calc(var(--cd-hole) + .6%)); }
/* The ink follows the page: the covers are printed as pale discs with deep ink (light mode shows them as made); in
   dark mode the disc's colours are flipped, light for dark, with the hues kept (invert, then turn the hue back), so it
   is a dark disc printed in pale ink. A colour filter on the still frame, done on the GPU: nothing repaints while the
   picture turns inside it. */
/* (on the picture itself: on the masked frame round it, browsers drew the frame and left the turning picture out) */
html:not([data-mode="light"]) :is(.vinyl-disc img, .drawer .line-cover, .m-card-art img) { filter: invert(1) hue-rotate(180deg) !important; }
html:not([data-mode="light"]) .similar-item img { filter: invert(1) hue-rotate(180deg) drop-shadow(0 2px 4px rgba(0,0,0,.35)); }
@media (max-width: 760px) { html.store:not([data-mode="light"]) .similar-item img { filter: invert(1) hue-rotate(180deg) drop-shadow(0 6px 10px rgba(0,0,0,.5)); } }

/* ---------- visualizer button: one look on every page ----------
   The spectrum-bars symbol plus the style's name on bigger screens, the symbol alone on phones; the same size,
   spacing and states on the home page, beat and loop pages and the player. It shows while something plays. */
:is(#p-vizstyle, #p-switchup) { --viz-icon: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 12 12%27%3E%3Cpath fill-rule=%27evenodd%27 d=%27M6 2.2C3.4 2.2 1.3 4.1.2 6c1.1 1.9 3.2 3.8 5.8 3.8s4.7-1.9 5.8-3.8C10.7 4.1 8.6 2.2 6 2.2zm0 1.1c2 0 3.6 1.3 4.5 2.7C9.6 7.4 8 8.7 6 8.7S2.4 7.4 1.5 6C2.4 4.6 4 3.3 6 3.3z%27/%3E%3Ccircle cx=%276%27 cy=%276%27 r=%271.6%27/%3E%3C/svg%3E");
  display: inline-flex; align-items: center; justify-content: center; gap: 7px; }
:is(#p-vizstyle, #p-switchup)::before { content: ""; display: block; flex: none; width: 12px; height: 12px; background: currentColor;
  -webkit-mask: var(--viz-icon) center / contain no-repeat; mask: var(--viz-icon) center / contain no-repeat; }
.beat-tools :is(#p-vizstyle, #p-switchup) { margin-top: 0; padding: 4px 12px; font-size: 11px; border-radius: 12px; min-width: 7.2em; align-self: center; margin-bottom: 12px; }
html.viz-live .beat-tools :is(#p-vizstyle, #p-switchup) { opacity: 1; }
@media (max-width: 600px) {
  :is(#p-vizstyle, #p-switchup), .beat-tools :is(#p-vizstyle, #p-switchup), .open-btns :is(#p-vizstyle, #p-switchup) { font-size: 0; gap: 0; min-width: 0; padding-inline: 11px; }
}



.beat h1 { overflow-wrap: anywhere; } .beat .info { min-width: 0; } /* a long one-word title (MOUNTAINSIDE) wraps instead of pushing the page sideways */

/* ---------- visualizer button: the icon alone, everywhere ----------
   The spectrum-bars symbol on every page and screen size; the style showing is named in its tooltip and to screen
   readers (viz-switch.js). Same size and place as before, so nothing around it moves. */
:is(#p-vizstyle, #p-switchup), .beat-tools :is(#p-vizstyle, #p-switchup), .filter-right > :is(#p-vizstyle, #p-switchup), .open-btns :is(#p-vizstyle, #p-switchup) {
  font-size: 0; gap: 0; min-width: 0; padding-inline: 11px; }
:is(#p-vizstyle, #p-switchup)::before { width: 13px; height: 13px; }
.beat-tools { align-items: center; }
.beat-tools :is(#p-vizstyle, #p-switchup) { align-self: stretch; margin: 0; } /* level with the back button: same height, centred on its line */

#drawer .muted:empty, #drawer .muted:empty + br { display: none; }
#drawer .sum { display: flex; justify-content: space-between; align-items: baseline; }
.drawer .line-end { display: inline-flex; align-items: center; gap: 4px; flex: none; } /* no store tagline set */

/* AVS Easter egg phases (viz-egg.js): the words' dots draw over the AVS picture, which dims underneath meanwhile. */
#viz-egg { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
#viz.avs.on.egg { opacity: .4; transition: opacity .6s ease; }

/* ---------- Beats / Loops and All / Solo / Collab: segmented switches ----------
   A recessed groove with the chosen half as a raised, glossy key that lights up, the others plain labels; the
   counts sit beside each label in lighter type. Same size and place as before, so nothing around them moves. */
.cart-btn.list-mode, .cart-btn.list-mode:hover, .cart-btn.list-mode:active {
  padding: 2px; gap: 2px; align-items: stretch; border-radius: 999px; transform: none;
  background: linear-gradient(180deg, rgba(0,0,0,.62), rgba(22,24,27,.78));
  border: 1px solid rgba(0,0,0,.85);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.85), inset 0 -1px 0 rgba(255,255,255,.04), 0 1px 0 rgba(255,255,255,.07);
}
.list-mode > span, .kind-switch > button {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 12px; border-radius: 999px; opacity: 1;
  color: #9aa3aa; font-weight: 600; letter-spacing: .02em; border: 0 !important; box-shadow: none !important; background: none;
  transition: color .15s, background .2s, box-shadow .2s;
}
.list-mode > span b, .kind-switch > button b { color: inherit; font-weight: 400; opacity: .7; min-width: 0; font-size: .92em; }
.list-mode > span:not(.on):hover, .kind-switch > button:not(.on):hover { color: #e8eef2; }
.list-mode > span.on, .kind-switch > button.on {
  color: #fff; text-shadow: 0 1px 1px rgba(0,0,0,.6);
  background: var(--shine), linear-gradient(180deg, #626b73 0%, #30363b 55%, #1f2326 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28), inset 0 0 0 1px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.6), 0 0 12px rgba(150,205,255,.22) !important;
}
.list-mode > span.on b, .kind-switch > button.on b { opacity: .85; }
.kind-switch > button:focus-visible { outline: 1px dotted #fff; outline-offset: -3px; }
html[data-mode="light"] .cart-btn.list-mode, html[data-mode="light"] .cart-btn.list-mode:hover {
  background: linear-gradient(180deg, rgba(0,0,0,.12), rgba(0,0,0,.05)); border-color: rgba(0,0,0,.2);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.25), 0 1px 0 rgba(255,255,255,.8);
}
html[data-mode="light"] .list-mode > span, html[data-mode="light"] .kind-switch > button { color: #56616a; }
html[data-mode="light"] .list-mode > span:not(.on):hover, html[data-mode="light"] .kind-switch > button:not(.on):hover { color: #1b2126; }
html[data-mode="light"] .list-mode > span.on, html[data-mode="light"] .kind-switch > button.on {
  color: #1b2126; text-shadow: 0 1px 0 rgba(255,255,255,.8);
  background: var(--shine), linear-gradient(180deg, #ffffff 0%, #e4ebf0 55%, #d3dde4 100%);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.25), 0 0 10px rgba(80,150,210,.25) !important;
}

/* ---------- legal pages and links (engine/legal.py) ----------
   Terms / Privacy / Refunds / Credits: a quiet line under every page, and plain readable text on their own pages. */
/* The policy links: a thin line under the end of the list (and of every other page), never over it. */
.sitefoot { position: absolute; left: 0; right: 0; bottom: 0; z-index: 1; text-align: center; padding: 14px 12px 12px; /* always at the very bottom: of the screen on a short page, of the content on a long one */ font-size: 10px; letter-spacing: .03em; color: var(--muted); }
.sitefoot a { color: var(--muted); text-decoration: none; padding: 2px 4px; display: inline-block; }
.sitefoot a:hover, .sitefoot a:focus-visible { color: var(--text); text-decoration: underline; }
#drawer .agree { font-size: 10.5px; line-height: 1.45; color: var(--muted); margin: 8px 0 0; }
#drawer .agree a { color: inherit; text-decoration: underline; display: inline-block; padding: 3px 0; }
.page.legal { font-size: 13px; line-height: 1.6; margin-top: 14px; border-radius: 10px; border: 1px solid rgba(255,255,255,.06);
  background: rgba(8,9,10,.82); box-shadow: 0 10px 40px rgba(0,0,0,.45); }
html[data-mode="light"] .page.legal { background: rgba(255,255,255,.88); border-color: rgba(0,0,0,.08); box-shadow: 0 10px 30px rgba(60,80,95,.18); }
.page.legal h2.part { font-size: 15px; margin-top: 40px; padding-top: 14px; border-top: 1px solid rgba(127,127,127,.25); scroll-margin-top: 90px; }
.page.legal h2.part:first-of-type { margin-top: 18px; border-top: 0; padding-top: 0; }
.page.legal h2 { font: 600 13px var(--ui); letter-spacing: .08em; text-transform: uppercase; margin: 26px 0 6px; }
.page.legal a { color: var(--text); }
.page.legal .authors { color: var(--muted); font-size: 11.5px; overflow-wrap: anywhere; }
.legal-table { width: 100%; border-collapse: collapse; margin: 6px 0; font-size: 12px; }
.legal-table th, .legal-table td { text-align: left; vertical-align: top; padding: 6px 8px; border-bottom: 1px solid rgba(255,255,255,.12); }
html[data-mode="light"] .legal-table th, html[data-mode="light"] .legal-table td { border-bottom-color: rgba(0,0,0,.12); }
@media (max-width: 520px) { .legal-table td:nth-child(2) { white-space: nowrap; } .legal-table th, .legal-table td { padding: 6px 4px; } }
.payee-form label { display: block; margin: 12px 0 4px; }
.payee-form input.search { width: 100%; box-sizing: border-box; min-height: 40px; font-size: 16px; } /* 16px: no zoom-in on iPhone */
.payee-form label.check { display: flex; gap: 10px; align-items: flex-start; line-height: 1.5; margin: 16px 0; }
.payee-form label.check input { margin-top: 3px; width: 18px; height: 18px; flex: none; }
.payee-form .btn { min-height: 40px; padding-inline: 18px; }
@media (pointer: coarse) { /* bigger invisible touch area for the row buttons; they look the same */
  .row .play, .row .price-btn { position: relative; }
  .row .play::after, .row .price-btn::after { content: ""; position: absolute; inset: -8px -6px; }
}

/* The free-download copy of the store (app.js setFree): no cart, prices or checkout; Download buttons instead. */
html.free :is(#cart-open, #cart-tab, #drawer, .agree, .deal) { display: none !important; }
.price-btn.dl { text-decoration: none; }

/* ---------- switch-up button (turntable): beside the visualizer button, same look and states ---------- */
#p-switchup { --viz-icon: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 12 12%27%3E%3Cpath fill-rule=%27evenodd%27 d=%27M5 1.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9zm0 3.4a1.1 1.1 0 1 1 0 2.2 1.1 1.1 0 0 1 0-2.2z%27/%3E%3Cpath d=%27M9.7.5l1.2.7-2.3 4-1.1-.6z%27/%3E%3Ccircle cx=%279.9%27 cy=%271%27 r=%27.95%27/%3E%3C/svg%3E") !important; }
#p-switchup[aria-pressed="false"] { opacity: .4; }
@media (max-width: 600px) {
  .filter-right { grid-template-columns: auto auto minmax(0, 1fr) auto; }
  .filter-right > #p-switchup { display: none; } /* phones: the list toggle takes its place */
  .filter-right > #p-listtoggle { display: inline-flex; grid-area: 1 / 2; justify-self: start; align-self: stretch; align-items: center; padding-inline: 11px; }
  .filter-right > #count { grid-area: 1 / 3; }
  .filter-right > .player-link { grid-area: 1 / 4; }
  .filter-right > #loop-kind { grid-area: 2 / 1 / 3 / 5; }
}

/* ---------- drawn transport icons (no emoji glyphs): sized from the button's font size, coloured by its text ---------- */
svg.ic { width: 1.15em; height: 1.15em; fill: currentColor; stroke: none; vertical-align: -.2em; pointer-events: none; }
svg.ic.st { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
/* Transport and list play buttons: the icon box is centred exactly (the text-baseline drop of svg.ic left it 2px low). */
.tbtn:not([hidden], .cart-tab), .play:not([hidden]) { display: inline-flex; align-items: center; justify-content: center; }
.tbtn svg.ic, .play svg.ic { display: block; vertical-align: baseline; }

/* ---------- visualizer / switch-up buttons: the look says on or off, and hovering never changes which ---------- */
:is(#p-vizstyle, #p-switchup)[aria-pressed="true"] { box-shadow: inset 0 1px 0 var(--edge), 0 0 10px var(--cool), 0 0 0 1px rgba(160,220,255,.35); }
html[data-mode="light"] :is(#p-vizstyle, #p-switchup)[aria-pressed="true"] { box-shadow: inset 0 1px 0 #fff, 0 0 0 1px rgba(60,110,160,.45); }
html.viz-live :is(#p-vizstyle, #p-switchup)[aria-pressed="false"]:is(:hover, :focus-visible) { opacity: .55; background: var(--shine), linear-gradient(180deg, #3a3f44 0%, #16181a 100%); box-shadow: none; }
html[data-mode="light"].viz-live :is(#p-vizstyle, #p-switchup)[aria-pressed="false"]:is(:hover, :focus-visible) { background: var(--shine), linear-gradient(180deg, #ffffff 0%, #d9e0e5 100%); }

/* ---------- phones: the track list toggle (#p-listtoggle, app.js), in the switch-up button's place ----------
   Hides the list and footer so the visualizer has the screen; search, Beats / Loops and the player stay. */
#p-listtoggle { display: none; }
#p-listtoggle::before { content: ""; display: block; width: 12px; height: 12px; background: currentColor;
  -webkit-mask: var(--list-icon) center / contain no-repeat; mask: var(--list-icon) center / contain no-repeat;
  --list-icon: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 12 12%27%3E%3Cpath d=%27M1 2h10v1.5H1zM1 5.25h10v1.5H1zM1 8.5h10V10H1z%27/%3E%3C/svg%3E"); }
#p-listtoggle[aria-pressed="false"] { opacity: .5; }
.window .table, .sitefoot { transition: opacity .3s ease, visibility 0s; }
html.viz-live:not(.viz-off).list-hidden :is(.window .table, .sitefoot, .to-top) { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .3s ease, visibility 0s .3s; }
/* Phones: fading layers are composited, so the fades never stutter over a long list. */
@media (pointer: coarse) { .window, .toolbar, .sitefoot { will-change: opacity; } }

/* Fast scrolling: each row lays out and paints on its own, so building or changing one never reflows the list. */
.list .row { contain: layout style; }

/* Taps act at once: no waiting to see whether it is a double-tap zoom. */
html { touch-action: manipulation; }
/* The list toggle shows only while a visualizer is on and playing (keeping its place, so nothing shifts); with the
   visualizer off or nothing playing, the list always shows. */
.filter-right > #p-listtoggle { visibility: hidden; opacity: 0; pointer-events: none; transition: opacity .25s ease, visibility 0s .25s; }
html.viz-live:not(.viz-off) .filter-right > #p-listtoggle { visibility: visible; opacity: 1; pointer-events: auto; transition: opacity .25s ease; }
html.viz-live:not(.viz-off) .filter-right > #p-listtoggle[aria-pressed="false"] { opacity: .5; }
/* Back to top stays a circle everywhere: phones give every button a 44px minimum height and side padding, which
   stretched it into an oval; there it sits in its own corner, never placed over the list's price column. */
.to-top { box-sizing: border-box; min-width: 0; min-height: 0; padding: 0; aspect-ratio: 1; }
@media (max-width: 760px) {
  .to-top { left: auto !important; width: 36px; height: 36px; right: max(10px, env(safe-area-inset-right)); }
}

/* Phones have no DJ mode at all: no button on any page. */
@media (hover: none) and (pointer: coarse) { #p-switchup { display: none !important; } }

/* Desktop: Beats / Loops (and the All / Solo / Collab filter on loops) sit right beside the search; the visualizer and
   Player buttons stay at the right edge. The group is dissolved here only; phones keep their own grid (above). */
@media (min-width: 601px) {
  .filterbar { justify-content: flex-start; }
  .filter-right { display: contents; }
  .search { order: 0; }
  #count { order: 1; }
  #loop-kind { order: 2; }
  #p-vizstyle { order: 3; margin-left: auto; }
  #p-switchup, #p-listtoggle, .filter-right > .player-link { order: 4; }
  .filterbar { gap: 8px; }
  #p-vizstyle ~ * { margin-left: 0; }
}

/* Taps, double-taps, long presses and swipes never select page text (the blue selection boxes over the list, the
   toolbar and the cart). Fields, the editor and the policy pages stay selectable. */
body { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
input, textarea, select, [contenteditable], .editor, .editor *, .legal, .legal * { -webkit-user-select: text; user-select: text; }

/* ---------- admin: add to the store by dropping files on the track list (admin/add.js) ---------- */
html.dropping main { position: relative; }
html:not(.admin) :is(.add-panel, .drop-over) { display: none !important; } /* admin mode only */
.drop-over { position: absolute; inset: 0; z-index: 30; display: flex; align-items: center; justify-content: center; pointer-events: none;
  border: 2px dashed rgba(160,220,255,.85); border-radius: 10px; background: rgba(6,10,14,.72); box-shadow: inset 0 0 40px rgba(120,190,255,.25); }
.drop-over > div { display: flex; flex-direction: column; gap: 6px; align-items: center; text-align: center; padding: 18px 24px; position: sticky; top: 40vh; }
.drop-over strong { font-size: 16px; letter-spacing: .03em; }
.drop-over small { color: var(--muted); font-size: 11.5px; }
.add-panel { position: fixed; right: 16px; bottom: 16px; z-index: 60; width: min(380px, calc(100vw - 32px)); box-sizing: border-box; padding: 10px 12px;
  border-radius: 10px; border: 1px solid rgba(255,255,255,.12); background: rgba(10,11,12,.94); box-shadow: 0 10px 40px rgba(0,0,0,.55); font-size: 12px; }
.add-panel[hidden] { display: none; }
.add-panel .drop-head { display: flex; align-items: center; gap: 8px; }
.add-panel .drop-head strong { flex: 1; }
.add-panel .kind, .add-panel .x { font: inherit; font-size: 11px; padding: 3px 9px; border-radius: 999px; border: 1px solid rgba(255,255,255,.18); background: transparent; color: var(--text); cursor: pointer; }
.add-panel .x { padding: 0 8px; font-size: 14px; line-height: 20px; }
.add-panel .drop-list { list-style: none; margin: 8px 0 0; padding: 0; max-height: 40vh; overflow: auto; }
.add-panel .drop-row { display: flex; gap: 8px; padding: 5px 0; font-size: 11.5px; border-top: 1px solid rgba(255,255,255,.06); }
.add-panel .drop-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.add-panel .drop-kind { flex: none; color: var(--muted); }
.add-panel .drop-status { flex: none; max-width: 50%; text-align: right; color: var(--muted); }
.add-panel .drop-row.busy .drop-status { color: var(--text); }
.add-panel .drop-row.done .drop-status { color: #8fd6a0; }
.add-panel .drop-row.done a { color: inherit; }
.add-panel .drop-row.failed .drop-status { color: #ff9a8a; }
html[data-mode="light"] .add-panel { background: rgba(250,251,252,.96); border-color: rgba(0,0,0,.15); color: #1b2126; }
html[data-mode="light"] .add-panel .kind, html[data-mode="light"] .add-panel .x { color: #1b2126; border-color: rgba(0,0,0,.25); }
html[data-mode="light"] .drop-over { background: rgba(240,244,247,.8); }

/* ================= phones: music-app layout (phone.js) =================
   Store pages only (html.store; the Player keeps its own bar). A mini player floats along the bottom and opens into
   a full-screen Now Playing sheet; rows play on a tap with their options behind a dots button; the list page has a
   header and shelves of covers above the list. Same glass, record and visualizer as everywhere else. Sizes are
   before the UI zoom (x1.25). Desktop: none of these parts show. */
.np-head, .more, .m-top, .m-shelves, .m-cart { display: none; }
@media (max-width: 760px) {
  /* ---- mini player ---- */
  html.store .toolbar {
    left: 6px; right: 6px; bottom: calc(6px + env(safe-area-inset-bottom) / 1.25);
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto auto; grid-template-areas: "art title prev play next" "art sub prev play next";
    gap: 0 8px; align-items: center; padding: 8px 8px 8px 6px; border: 1px solid #000; border-radius: 10px; overflow: hidden; cursor: pointer;
    box-shadow: inset 0 1px 0 var(--edge), 0 8px 24px rgba(0,0,0,.6), var(--np-backing); }
  /* A backing drawn by the floating player itself (so it always matches its size): solid in the gaps beside and below it
     (down past the home bar), a soft fade above, so the page scrolling by never shows around it or seems to load over it. */
  html.store { --np-backing: 0 40px 0 6px #000, 0 -6px 18px 6px rgba(0,0,0,.85); }
  html.store[data-mode="light"] { --np-backing: 0 40px 0 6px #e9eef2, 0 -6px 18px 6px rgba(233,238,242,.9); }
  /* The mini player is its own compositor layer, so page scrolling and the address bar sliding never repaint or shift it. */
  html.store .toolbar { transform: translateZ(0); will-change: transform, opacity; contain: layout paint; }
  html.store { overscroll-behavior-y: none; } /* no rubber-band pulling the page away from the fixed player */
  html.store .toolbar:not(.show) { visibility: hidden; } /* nothing played yet: no empty player */
  html.store[data-mode="light"] .toolbar { border-color: #a3adb5; box-shadow: inset 0 1px 0 #fff, 0 6px 18px rgba(60,80,95,.25), var(--np-backing); }
  html.store .toolbar :is(.transport, .lcd, .lcd-text) { display: contents; }
  html.store .toolbar :is(#p-prev, #p-shuffle, #p-cur, #p-dur) { display: none; }
  html.store:not(.np-open) .toolbar #p-next { grid-area: next; width: 40px; height: 40px; font-size: 14px; } /* skip, right of play */
  html.store .toolbar :is(.cart-tab, .vol, .right, .np-head) { display: none; } /* apart from the ids: :is() takes its weightiest argument */
  html.store .toolbar #p-vinyl { grid-area: art; width: 38px; height: 38px; margin: 0; pointer-events: none; }
  html.store .toolbar .lcd-title-row { grid-area: title; justify-content: flex-start; align-self: end; }
  html.store .toolbar .lcd-title { pointer-events: none; padding: 0; margin: 0; font-size: 12px; text-shadow: none; }
  html.store .toolbar .lcd-sub { grid-area: sub; align-self: start; text-align: left; font-size: 10.5px; }
  html.store .toolbar .lcd-title-row .admin-tools, html.store .toolbar .lcd-title-row .edit { display: none; }
  html.store .toolbar #p-buy { grid-area: buy; min-height: 0; padding: 10px 14px; font-size: 11.5px; border-radius: 16px; }
  html.store .toolbar #p-toggle { grid-area: play; width: 44px; height: 44px; font-size: 15px; }
  html.store .toolbar .lcd-row { position: absolute; left: 8px; right: 8px; bottom: 3px; display: block; margin: 0; pointer-events: none; }
  html.store .toolbar .lcd .bar { height: 2px; border: 0; border-radius: 1px; background: rgba(255,255,255,.14); box-shadow: none; }
  html.store .toolbar .lcd .bar::before { content: none; }
  html.store[data-mode="light"] .toolbar .lcd .bar { background: rgba(0,0,0,.12); }
  html.store body { padding-bottom: calc(124px + env(safe-area-inset-bottom)); }
  html.store .to-top { bottom: calc(78px + env(safe-area-inset-bottom)); }
  html.store .sitefoot { bottom: calc(80px + env(safe-area-inset-bottom)); }

  /* ---- Now Playing (the same toolbar, full screen) ---- */
  html.store.np-open, html.store.np-open body { overflow: hidden; }
  html.store.np-open:not(.np-peek) :is(main, main *, .sitefoot, .to-top) { visibility: hidden !important; } /* only the visualizer behind the sheet (np-peek: it is sliding away, phone.js) */
  html.store.np-open .toolbar {
    inset: 0; border: 0; border-radius: 0; cursor: auto; z-index: 15;
    grid-template-columns: repeat(2, minmax(0, 1fr)) minmax(0, 1.2fr) repeat(2, minmax(0, 1fr)); grid-template-rows: auto minmax(0, 1fr) auto auto auto auto; /* the play column a little wider: even gaps along the button row */
    grid-template-areas: "head head head head head" "art art art art art" "title title title title title" "sub sub sub sub sub" "bar bar bar bar bar" "shuf prev play next cart";
    --np-buy-w: 72px; /* Buy sits over the right end of the title and sub lines, which keep this lane (and a gap) clear */
    gap: 2px 0; padding: calc(8px + env(safe-area-inset-top) / 1.25) 18px calc(26px + env(safe-area-inset-bottom) / 1.25);
    background: linear-gradient(180deg, rgba(6,7,8,.55) 0%, rgba(6,7,8,.12) 22%, rgba(6,7,8,.12) 52%, rgba(6,7,8,.8) 78%, rgba(4,4,5,.92) 100%);
    box-shadow: none; } /* see-through: the visualizer plays around the record; darker under the text and buttons */
  html.store.np-open[data-mode="light"] .toolbar { background: linear-gradient(180deg, rgba(240,243,245,.6) 0%, rgba(240,243,245,.15) 22%, rgba(240,243,245,.15) 52%, rgba(240,243,245,.82) 78%, rgba(233,238,242,.94) 100%); }
  html.store.np-open .toolbar { backdrop-filter: none; -webkit-backdrop-filter: none; }
  html.store.np-open .toolbar .np-head { grid-area: head; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  .np-head button { width: 44px; height: 44px; display: inline-grid; place-items: center; border-radius: 50%; color: var(--text); }
  .np-head button svg.ic { width: 20px; height: 20px; vertical-align: 0; }
  .np-head button { flex: none; }
  .np-from { flex: 1; text-align: center; line-height: 1.2; min-width: 0; }
  /* each line's tracking also trails its last letter: a matching indent keeps the text truly centred */
  .np-from small { display: block; font-size: 9px; letter-spacing: .14em; padding-left: .14em; text-transform: uppercase; color: var(--muted); }
  .np-from b { display: block; padding-left: .2em; font-family: "Michroma", var(--ui); font-size: 11px; letter-spacing: .2em; text-transform: uppercase; }
  /* The record as big as the column allows (short screens: as the row allows). Like a music app's artwork it eases
     back a little while paused and springs forward when the sound comes back (phone.js sets np-paused). */
  html.store.np-open .toolbar #p-vinyl { width: auto; height: auto; max-width: 100%; max-height: 100%; aspect-ratio: 1; justify-self: stretch; align-self: center;
    margin: 10px 0; pointer-events: auto; transition: transform .55s cubic-bezier(.3,1.35,.5,1); }
  html.store.np-open.np-paused .toolbar #p-vinyl { transform: scale(.84); transition-duration: .4s; transition-timing-function: cubic-bezier(.4,0,.2,1); }
  html.store.np-open .toolbar #p-vinyl::before { box-shadow: 0 22px 50px rgba(0,0,0,.7), 0 4px 10px rgba(0,0,0,.45), 0 0 46px rgba(150,205,255,.14); transition: box-shadow .4s ease; }
  html.store.np-open.np-paused .toolbar #p-vinyl::before { box-shadow: 0 10px 26px rgba(0,0,0,.55), 0 2px 6px rgba(0,0,0,.4); }
  html.store.np-open .toolbar #p-vinyl .vinyl-disc { box-shadow: inset 0 0 0 1px rgba(255,255,255,.07); }
  @media (prefers-reduced-motion: reduce) { html.store.np-open .toolbar #p-vinyl, html.store.np-open .toolbar #p-vinyl::before { transition: none; } }
  /* Touch on the player is all the player's own: a drag down on Now Playing follows the finger (and a swipe on the
     mini player opens it or skips) without the page also scrolling, rubber-banding or pulling to refresh under it. */
  html.store .toolbar { touch-action: none; overscroll-behavior: none; }
  html.store.np-open .toolbar .lcd-title { pointer-events: auto; font-size: 19px; line-height: 1.2; text-shadow: 0 0 10px rgba(190,225,255,.2); }
  html.store.np-open[data-mode="light"] .toolbar .lcd-title { text-shadow: none; }
  html.store.np-open .toolbar .lcd-title-row { margin-top: 10px; }
  html.store.np-open .toolbar .lcd-title-row .admin-tools { display: inline-flex; }
  html.store.np-open .toolbar .lcd-sub { font-size: 11.5px; white-space: normal; }
  html.store.np-open .toolbar #p-buy { grid-area: 3 / 5 / 5 / 6; align-self: center; justify-self: end; width: var(--np-buy-w); padding: 12px 0; font-size: 12.5px; }
  html.store.np-open .toolbar :is(.lcd-title-row, .lcd-sub) { padding-right: calc(var(--np-buy-w) + 12px); } /* long names end in "…" before Buy, never under it */
  html.store.np-open .toolbar .lcd-row { position: static; grid-area: bar; display: grid; grid-template-columns: 1fr 1fr; grid-template-areas: "bar bar" "cur dur";
    gap: 6px 0; margin: 14px 0 6px; pointer-events: auto; }
  html.store.np-open .toolbar :is(#p-cur, #p-dur) { display: block; }
  html.store.np-open .toolbar #p-cur { grid-area: cur; text-align: left; }
  html.store.np-open .toolbar #p-dur { grid-area: dur; text-align: right; }
  html.store.np-open .toolbar .lcd .bar { grid-area: bar; height: 6px; border: 1px solid #000; border-radius: 3px; background: #15181a; box-shadow: inset 0 1px 2px rgba(0,0,0,.8), 0 1px 0 rgba(255,255,255,.06); }
  html.store.np-open[data-mode="light"] .toolbar .lcd .bar { background: #f7f8f5; border-color: #8b949b; box-shadow: inset 0 1px 2px rgba(0,0,0,.2); }
  html.store.np-open .toolbar .lcd .bar::before { content: ""; inset: -14px 0; }
  html.store.np-open .toolbar :is(#p-shuffle, #p-prev, #p-next, .cart-tab) { display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px; font-size: 16px; place-self: center; }
  html.store.np-open .toolbar #p-shuffle { grid-area: shuf; }
  html.store.np-open .toolbar #p-prev { grid-area: prev; }
  html.store.np-open .toolbar #p-next { grid-area: next; }
  html.store.np-open .toolbar .cart-tab { grid-area: cart; display: inline-grid; place-items: center; }
  html.store.np-open .toolbar .cart-tab::before { width: 19px; height: 19px; } /* in step with the bigger buttons beside it */
  html.store.np-open .toolbar #p-toggle { grid-area: play; width: 64px; height: 64px; font-size: 23px; place-self: center; }
  html.free.store.np-open .toolbar .cart-tab { display: none !important; }

  /* ---- list page header ---- */
  html.store .m-top { display: flex; align-items: center; justify-content: space-between; padding: 12px 0 6px; }
  .m-brand { font-family: "Michroma", var(--ui); font-size: 17px; letter-spacing: .28em; text-transform: uppercase; color: var(--page-ink); text-shadow: var(--page-halo); }
  .m-top-btns { display: flex; gap: 12px; }
  html.store .m-icon { display: inline-grid; place-items: center; width: 42px; height: 42px; padding: 0; }
  html.store .m-icon svg.ic { width: 18px; height: 18px; vertical-align: 0; }
  html.store .m-cart { position: relative; }
  .m-badge { position: absolute; top: -3px; right: -4px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
    font: 700 9px/16px var(--ui); color: #fff; text-shadow: none; background: linear-gradient(180deg, #e8453c, #a31a14); border: 1px solid #000; }
  .m-badge[hidden] { display: none; }
  html.store .beat-tools .m-cart { display: inline-grid; margin-left: auto; align-self: center; margin-bottom: 12px; }
  html.store .filter-right > .player-link { display: none; } /* it's in the header */

  /* ---- search and Beats / Loops chips ---- */
  html.store .filterbar { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "search search" "chips viz" "kind kind";
    gap: 8px; align-items: center; top: 0; padding-top: calc(8px + env(safe-area-inset-top) / 1.25); }
  html.store .filterbar, html.store[data-mode] .filterbar { background: none; backdrop-filter: none; -webkit-backdrop-filter: none; } /* see-through: the visualizer shows behind the search (beats lowfx's fill) */
  html.store .filter-right { display: contents; }
  html.store .search { grid-area: search; width: 100%; padding: 12px 12px 12px 30px; border-radius: 8px; background-position: 10px 50%;
    background-color: transparent; border: 1px solid rgba(255,255,255,.18); box-shadow: none; }
  html.store[data-mode="light"] .search { background-color: transparent; border-color: rgba(0,0,0,.22); box-shadow: none; }
  html.store .search:focus { border-color: rgba(200,230,255,.45); box-shadow: 0 0 10px var(--cool); }
  html.store #count { grid-area: chips; justify-self: start; }
  /* Browse by mood (phone.js): in the page while the search box is in use, never in the pinned bar. */
  html.store .m-moods { display: block; margin: 6px 0 16px; animation: moods-in .18s ease-out; }
  html.store .m-moods[hidden] { display: none; }
  @keyframes moods-in { from { opacity: 0; transform: translateY(6px); } }
  .m-moods h2 { margin: 0 0 8px; font: 700 15px/1.2 var(--ui); color: var(--page-ink); text-shadow: var(--page-halo); }
  .m-moods ul { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; list-style: none; margin: 0; padding: 0; }
  .m-mood { position: relative; display: flex; flex-direction: column; justify-content: flex-start; width: 100%; height: 64px; padding: 9px 10px; overflow: hidden;
    text-align: left; border-radius: 8px; color: #f2f6f8; border: 1px solid #000; -webkit-tap-highlight-color: transparent;
    background: var(--shine), linear-gradient(180deg, #3a3f44 0%, #16181a 100%); box-shadow: inset 0 1px 0 var(--edge), 0 1px 2px rgba(0,0,0,.8);
    transition: transform .12s ease-out; }
  .m-mood:active { transform: scale(.97); }
  .m-mood-name { font-weight: 700; font-size: 13px; }
  .m-mood-n { font-size: 10px; opacity: .65; }
  .m-mood img { position: absolute; right: -10px; bottom: -12px; width: 56px; height: 56px; border-radius: 50%; transform: rotate(18deg); box-shadow: 0 4px 10px rgba(0,0,0,.5); }
  html[data-mode="light"] .m-mood { color: #1d2328; border-color: #8d979f; background: var(--shine), linear-gradient(180deg, #ffffff 0%, #d9e0e5 100%); box-shadow: inset 0 1px 0 #fff, 0 1px 2px rgba(60,80,95,.35); }
  @media (prefers-reduced-motion: reduce) { html.store .m-moods { animation: none; } }
  html.store #loop-kind { grid-area: kind; justify-self: start; }
  html.store #loop-kind[hidden] { display: none; }
  html.store .m-top-btns > #p-vizstyle { width: 42px; height: 42px; min-height: 0; padding: 0; border-radius: 50%; justify-content: center; } /* phone.js moves it into the header row */
  html.store .filter-right > #p-listtoggle { display: none; } /* shelves and Now Playing replace the fade-the-list button */
  html.store .filter-right > :is(#p-vizstyle, #p-listtoggle) { width: 42px; height: 42px; min-height: 0; padding: 0; border-radius: 50%; justify-content: center; }
  html.store .cart-btn.list-mode, html.store .cart-btn.list-mode:hover, html.store .cart-btn.list-mode:active { background: none; border: 0; box-shadow: none; padding: 0; gap: 8px; min-height: 0; }
  html.store .kind-switch { display: inline-flex; gap: 8px; }
  html.store :is(.list-mode > span, .kind-switch > button) { padding: 10px 18px; border-radius: 999px; color: #c9d1d6;
    border: 1px solid #000 !important; background: var(--shine), linear-gradient(180deg, #3a3f44 0%, #16181a 100%);
    box-shadow: inset 0 1px 0 var(--edge), 0 1px 2px rgba(0,0,0,.8) !important; }
  html.store[data-mode="light"] :is(.list-mode > span, .kind-switch > button) { color: #2a3238; border-color: #8d979f !important;
    background: var(--shine), linear-gradient(180deg, #ffffff 0%, #d9e0e5 100%); box-shadow: inset 0 1px 0 #fff, 0 1px 2px rgba(60,80,95,.35) !important; }
  html.store :is(.list-mode > span.on, .kind-switch > button.on) { color: #0b0d0e; text-shadow: none;
    background: var(--shine), linear-gradient(180deg, #f4f8fb 0%, #b9c8d3 100%); box-shadow: inset 0 1px 0 #fff, 0 0 12px rgba(150,205,255,.35) !important; }
  html.store[data-mode="light"] :is(.list-mode > span.on, .kind-switch > button.on) { color: #0b2233; text-shadow: none;
    background: var(--shine), linear-gradient(180deg, #ffffff 0%, #cfe6f7 100%); box-shadow: inset 0 0 0 1.5px #2f7fb8, 0 1px 3px rgba(60,80,95,.35) !important; }
  html.store[data-mode="light"] :is(.list-mode > span, .kind-switch > button):not(.on) { color: #33414b; text-shadow: none; }

  /* ---- rows: tap to play, dots for the rest ---- */
  html.store .table { border: 0; border-radius: 10px; box-shadow: none; background: rgba(6,7,8,.55); }
  html.store[data-mode="light"] .table { background: rgba(255,255,255,.6); box-shadow: none; }
  html.store .table .row, html.store .table .row.alt, html.store[data-mode="light"] .table .row { background: transparent; border-bottom: 0; }
  html.store .table .row { grid-template-columns: 42px auto minmax(0, 1fr) 44px; column-gap: 10px; min-height: 58px; padding: 7px 4px 7px 10px; }
  html.store .list .row { contain-intrinsic-size: auto 58px; }
  html.store .table .row > :is(.play, .price-btn, .idx) { display: none; }
  html.store .table .row > img, html.store .table .row > span:empty { grid-area: 1 / 1 / 3 / 2; width: 42px; height: 42px; }
  html.store .table .row > .t-wrap { grid-area: 1 / 2 / 2 / 4; }
  html.store .table .row > .num { grid-area: 2 / 2; }
  html.store .table .row > .key { grid-area: 2 / 3; margin-left: -9px; }
  html.store .table .row .t { font-size: 13px; font-weight: 600; }
  html.store .table .row .admin-tools { display: none; } /* in the dots sheet */
  html.store .table .row > .more { grid-area: 1 / 4 / 3 / 5; display: inline-grid; place-items: center; width: 44px; height: 44px; color: var(--muted); }
  .more > span { width: 3px; height: 3px; border-radius: 50%; background: currentColor; box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor; }
  html.store .table .row.playing { background: var(--shine), linear-gradient(180deg, rgba(86,100,112,.92), rgba(40,46,52,.92)); border-radius: 8px; box-shadow: inset 3px 0 0 #a8dcff, inset 0 1px 0 rgba(255,255,255,.18); }
  html.store[data-mode="light"] .table .row.playing { background: var(--shine), linear-gradient(180deg, #d6e8f5, #aecbe0); box-shadow: inset 3px 0 0 #2f7fb8, inset 0 1px 0 #fff; }
  html.store .table .row.playing .t { color: #a8dcff; }
  html.store[data-mode="light"] .table .row.playing .t { color: #154e78; text-shadow: none; }

  /* ---- shelves ---- */
  html.store .m-shelves { display: block; margin: -8px 0 16px; } /* close under the Beats / Loops buttons */
  html.store .m-shelves[hidden] { display: none; }
  html.store .m-shelf[hidden] { display: none; }
  .m-shelf + .m-shelf { margin-top: 16px; }
  .m-shelf[hidden] + .m-shelf { margin-top: 0; } /* one shelf per tab (phone.js syncBrowse) */
  .m-shelf h2 { margin: 0 0 8px; font: 700 15px/1.2 var(--ui); color: var(--page-ink); text-shadow: var(--page-halo); }  .m-shelf-row { display: flex; gap: 12px; list-style: none; margin: -12px -12px -16px; padding: 12px 12px 20px; /* room for the shadows (blur 10px + offset): a scrolling row clips anything past its box */ overflow-x: auto; scroll-snap-type: x proximity; touch-action: pan-x pan-y; /* a swipe that starts on a shelf can still scroll the page (mandatory snapping with contained overscroll trapped it in Safari) */
    scroll-padding-inline: 12px; scrollbar-width: none; }
  .m-shelf-row::-webkit-scrollbar { display: none; }
  .m-shelf-row > li { flex: none; scroll-snap-align: start; }
  .m-card { display: flex; flex-direction: column; align-items: center; gap: 8px; width: 104px; padding: 0; text-align: center; -webkit-tap-highlight-color: transparent; }
  .m-card-art { position: relative; width: 104px; aspect-ratio: 1; border-radius: 50%; overflow: hidden; background: #0d0d0f; -webkit-mask-image: -webkit-radial-gradient(white, black); isolation: isolate;
    box-shadow: 0 4px 10px rgba(0,0,0,.45); transition: transform .12s ease-out, box-shadow .2s; } /* no border ring, and a shadow that fits the row's padding */
  .m-card-art img { position: absolute; left: calc(50% - 50% / .836); top: calc(50% - 50% / .836); width: calc(100% / .836); max-width: none; aspect-ratio: 1; }
  .m-card:active .m-card-art { transform: scale(.96); }
  .m-card.playing .m-card-art { box-shadow: 0 4px 10px rgba(0,0,0,.45), 0 0 10px rgba(150,205,255,.55); }
  .m-card-t { display: block; width: 100%; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--page-ink); text-shadow: var(--page-halo); }
  .m-card-t { font-size: 12px; font-weight: 700; }
  .m-card.playing .m-card-t { color: #a8dcff; }
  html[data-mode="light"] .m-card.playing .m-card-t { color: #154e78; }

  /* ---- mini player: back, play and skip (Now Playing keeps Buy, the header the cart) ---- */
  html.store:not(.np-open) .toolbar #p-buy { display: none; }
  html.store:not(.np-open) .toolbar #p-prev { grid-area: prev; display: inline-flex; width: 40px; height: 40px; font-size: 14px; }
  /* free copy: its download button keeps that spot instead of back */
  html.free.store:not(.np-open) .toolbar #p-prev { display: none; }
  html.free.store:not(.np-open) .toolbar #p-buy { grid-area: prev; display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; border-radius: 50%; font-size: 11px; }

  /* ---- beat and loop pages: album style ---- */
  html.store .beat { gap: 10px; padding-top: 0; }
  html.store .beat .info { order: 2; }
  html.store .beat .art { order: 1; max-width: min(280px, 64vw); margin-top: 52px; }
  html.store .beat-tools { position: absolute; top: 10px; left: 10px; right: 10px; margin: 0; flex-wrap: nowrap; }
  html.store .beat { position: relative; }
  html.store .beat-tools > * { margin-bottom: 0 !important; }
  html.store .beat-tools .back { width: 34px; height: 34px; min-height: 0; padding: 0; border-radius: 50%; font-size: 0; display: inline-flex; align-items: center; justify-content: center; gap: 0; letter-spacing: 0; } /* flex, not grid: grid put the chevron and the hidden label in separate rows, lifting the chevron above the middle */
  /* A round back button is flat like the cart beside it: the desktop key's stacked edge showed as a second disc under it. */
  html.store .beat-tools .cart-btn.back, html.store .beat-tools .cart-btn.back:hover, html.store .beat-tools .cart-btn.back:active,
  html.store[data-mode="light"] .beat-tools .cart-btn.back, html.store[data-mode="light"] .beat-tools .cart-btn.back:active {
    box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 2px 6px rgba(0,0,0,.45); transform: none; }
  html.store[data-mode="light"] .beat-tools .cart-btn.back { box-shadow: inset 0 1px 0 #fff, 0 2px 6px rgba(60,80,95,.3); }
  html.store .beat-tools .cart-btn.back:active { transform: scale(.94); }
  html.store .beat-tools .back::before { content: ""; width: 16px; height: 16px; background: currentColor;
    -webkit-mask: var(--chev) center / contain no-repeat; mask: var(--chev) center / contain no-repeat;
    --chev: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%23000%27 stroke-width=%272.4%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M15 5l-7 7 7 7%27/%3E%3C/svg%3E"); }
  html.store .beat-tools #p-vizstyle { width: 34px; height: 34px; min-height: 0; padding: 0; border-radius: 50%; margin-left: auto !important; }
  html.store .beat-tools .m-cart { margin-left: 10px; }
  html.store .beat .info > #beat-play { width: 56px; height: 56px; font-size: 20px; }
  html.store .beat h1 { font-size: 26px; margin-top: 6px; }
  html.store .beat .tiers { margin-top: 18px; border: 0; border-radius: 10px; box-shadow: none; background: rgba(6,7,8,.6); }
  html.store[data-mode="light"] .beat .tiers { background: rgba(255,255,255,.65); box-shadow: none; }
  html.store .tier, html.store .tier:nth-child(even), html.store[data-mode="light"] .tier { background: transparent; flex-wrap: nowrap; padding: 12px 14px; }
  html.store .tier + .tier { border-top: 1px solid rgba(127,127,127,.16); }
  html.store .tier .name { font-size: 13px; }
  html.store .tier .terms { font-size: 10.5px; line-height: 1.35; }
  html.store .tier .add { min-width: 0; padding: 8px 16px; flex: none; }
  html.store .similar { margin-top: 22px; }
  html.store .similar h2 { font: 700 15px/1.2 var(--ui); letter-spacing: 0; text-transform: none; }
  html.store .similar-list { display: flex; justify-content: safe center; gap: 12px; margin: -10px -10px -14px; padding: 10px 10px 18px; overflow-x: auto; scrollbar-width: none; scroll-snap-type: x mandatory; }
  html.store .similar-list::-webkit-scrollbar { display: none; }
  html.store .similar-item { flex: none; flex-direction: column; align-items: center; gap: 6px; width: 104px; padding: 0; border: 0; scroll-snap-align: start; }
  html.store .similar-item:hover, html.store .similar-item:focus-visible { background: none; }
  html.store .similar-item img { width: 104px; height: 104px; filter: drop-shadow(0 6px 10px rgba(0,0,0,.5)); }
  html.store .similar-item span { max-width: 100%; font-weight: 700; }

  /* ---- cart: a bottom sheet ---- */
  html.store .drawer { inset: auto 0 0 0; width: auto; max-height: 82vh; border-left: 0; border-top: 1px solid #000; border-radius: 14px 14px 0 0;
    padding-bottom: calc(env(safe-area-inset-bottom) / 1.25); transform: translateY(100%); box-shadow: inset 0 1px 0 var(--edge), 0 -10px 30px rgba(0,0,0,.6); }
  html.store .drawer.open { transform: none; }
  html.store .drawer.dragging { transition: none; }
  html.store .drawer header { flex-wrap: wrap; padding-top: 6px; }
  html.store .drawer header .m-grab { flex: 1 1 100%; margin-bottom: 4px; }
  /* The cart sheet in the phone's own look: round covers and 44px targets like the list rows, one raised pill to pay. */
  html.store .drawer header { align-items: center; padding: 6px 16px 10px; }
  html.store .drawer header strong { font-size: 15px; }
  html.store .drawer header .x { width: 44px; height: 44px; margin-right: -10px; display: inline-grid; place-items: center; border-radius: 50%; font-size: 22px; }
  html.store .drawer .items { padding: 4px 6px; overscroll-behavior: contain; }
  html.store .drawer .items > p { padding: 28px 10px; text-align: center; font-size: 13px; }
  html.store .drawer .line, html.store .drawer .line:nth-child(even) { gap: 12px; min-height: 58px; padding: 7px 4px 7px 10px; border: 0; border-radius: 8px; background: transparent; }
  html.store .drawer .line-cover { width: 44px; height: 44px; }
  html.store .drawer .line-title { font-size: 13px; font-weight: 600; line-height: 1.3; overflow-wrap: anywhere; }
  html.store .drawer .line-title .muted { font-size: 11px; font-weight: 400; }
  html.store .drawer .line-price { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
  html.store .drawer .line .x { width: 44px; height: 44px; display: inline-grid; place-items: center; border-radius: 50%; font-size: 20px; }
  html.store .drawer footer { padding: 12px 16px 14px; border-top: 1px solid rgba(127,127,127,.22); box-shadow: none; }
  html.store .drawer footer p { margin: 0 0 8px; }
  html.store .drawer footer .deal { font-size: 11px; }
  html.store .drawer footer .sum { font-size: 14px; margin-bottom: 12px; }
  html.store .drawer footer .sum strong { font-size: 20px; font-variant-numeric: tabular-nums; }
  html.store .drawer .checkout { min-height: 50px; padding: 0 18px; border-radius: 999px; font-size: 14px; font-weight: 700; color: #0b0d0e; text-shadow: none;
    border: 1px solid #000; background: var(--shine), linear-gradient(180deg, #f4f8fb 0%, #b9c8d3 100%); box-shadow: inset 0 1px 0 #fff, 0 0 12px rgba(150,205,255,.35); }
  html.store .drawer .checkout:disabled { opacity: .6; }
  html.store[data-mode="light"] .drawer .checkout { color: #0b2233; border-color: #8d979f; background: var(--shine), linear-gradient(180deg, #ffffff 0%, #cfe6f7 100%);
    box-shadow: inset 0 0 0 1.5px #2f7fb8, 0 1px 3px rgba(60,80,95,.35); }
  html.store.cart-open body::after { content: ""; position: fixed; inset: 0; z-index: 19; background: rgba(0,0,0,.55); }
}

/* ---- the dots action sheet (phones; opened from a row or Now Playing) ---- */
.m-sheet { zoom: 1.25; position: fixed; inset: auto 0 0 0; width: auto; max-width: none; max-height: 80vh; margin: 0; overflow: auto;
  padding: 6px 0 calc(10px + env(safe-area-inset-bottom) / 1.25); border: 1px solid #000; border-bottom: 0; border-radius: 14px 14px 0 0; color: var(--text);
  background: var(--shine), linear-gradient(180deg, #2a2e32, #0e1011); box-shadow: inset 0 1px 0 var(--edge), 0 -10px 30px rgba(0,0,0,.6); }
.m-sheet::backdrop { background: rgba(0,0,0,.55); }
html[data-mode="light"] .m-sheet { background: var(--shine), linear-gradient(180deg, #ffffff, #dfe5e9); border-color: #9aa4ac; }
.m-grab { width: 36px; height: 4px; margin: 2px auto 10px; border-radius: 2px; background: rgba(127,127,127,.45); }
.m-sheet-head { display: flex; align-items: center; gap: 12px; padding: 2px 16px 12px; border-bottom: 1px solid rgba(127,127,127,.18); }
.m-sheet-head img, .m-noart { width: 44px; height: 44px; flex: none; border-radius: 50%; object-fit: cover; background: #0d0d0f; }
.m-sheet-head div { min-width: 0; }
.m-sheet-head b { display: block; font-size: 13px; overflow-wrap: anywhere; }
.m-sheet-head small { display: block; color: var(--muted); font-size: 11px; }
.m-acts { padding-top: 4px; }
.m-act { display: flex; align-items: center; gap: 14px; width: 100%; padding: 12px 16px; font-size: 13px; text-align: left; -webkit-tap-highlight-color: transparent; }
.m-act:active, .m-act:focus-visible { background: rgba(127,127,127,.12); outline: none; }
.m-act svg.ic { width: 20px; height: 20px; flex: none; vertical-align: 0; }
.m-act-note { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }
@media (max-width: 380px) { .m-sheet { zoom: 1.1; } }
