/* Music — Apple Music's shape (the owner, 2026-10-03: "instead of reinventing the wheel, copy Apple
 * Music"): four tabs at the foot (Home · Radio · Library · Search) with the mini player floating above
 * them, large titles on the tabs, glass buttons over a pushed page, an album's page in its cover's
 * colours with Shuffle · Play · ✓ under the title, and Now Playing as a screen of its own.
 *
 * Light is the base; dark is a token swap; an album, a playlist and Now Playing re-colour the page by
 * setting the same tokens on <html> (app.js tint()), so every rule below follows them.
 *
 * ~/claude/IOS.md: §1 the glass offset once, on the header (and Now Playing's top); §25 THE STAGE
 * (musicapp-v34): the document never scrolls; #app is a screen tall (100lvh installed), the PAGE (#page)
 * scrolls inside it, and the foot (mini player + tab bar) is the page's sibling, absolute at the
 * bottom — so a tap on it is never eaten by a page still coasting after a flick. Nothing is
 * position: fixed (a fixed layer is clipped under the status bar); a ••• menu is ABSOLUTE in the body.
 */
:root {
  --bg:      #f2f2f7;
  --panel:   #ffffff;
  --panel-2: #f6f6f9;
  --line:    rgba(60, 60, 67, .16);
  --ink:     #000000;
  --ink-2:   #3c3c43;
  --dim:     #8a8a8e;
  --pill:    #e5e5ea;
  --good:    #1a9e4b;
  --warn:    #b8730a;
  --bad:     #e5322b;
  --accent:  #e8367d;
  --on-accent: #ffffff;
  --glass:   #ffffff;            /* SOLID (musicapp-v30): no translucency, no backdrop-filter — see the glass block */
  --shadow:  0 1px 2px rgba(0,0,0,.04), 0 6px 20px rgba(0,0,0,.06);
  --r-card: 20px; --r-mid: 13px; --r-tile: 9px;
  --font: -apple-system, BlinkMacSystemFont, system-ui, "SF Pro Text", "Helvetica Neue", sans-serif;
  --font-num: ui-rounded, -apple-system, "SF Pro Rounded", system-ui, sans-serif;   /* the shelf's numbers (gems, chess, Math Time…) */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --glass-t: 20px;
  --sb: 0px;                     /* installed: the status bar's height, which env(safe-area-inset-top) reports as 0 (IOS.md §25) */
  --top: calc(var(--safe-t) + var(--sb) + var(--glass-t));
  --foot-h: 0px; --kb: 0px;      /* set by app.js: the foot's height, and what the keyboard covers while a field is focused */
  --side: 16px;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #000000; --panel: #1c1c1e; --panel-2: #2c2c2e; --line: rgba(84, 84, 88, .48);
    --ink: #ffffff; --ink-2: #d7d7db; --dim: #98989f; --pill: #2c2c2e;
    --good: #30d158; --warn: #ffd60a; --bad: #ff453a; --accent: #ff4f93;
    --glass: #1c1c1e;
    --shadow: none;
  }
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html { touch-action: manipulation; -webkit-text-size-adjust: 100%; }
html, body { background: var(--bg); color: var(--ink); margin: 0; }
/* THE STAGE (musicapp-v34, IOS.md §25, the recipe measured with bin/tap_probe on iOS 27). The root never scrolls under a
   finger. Installed, the body is 100lvh (the screen; 100dvh and 100% are a status bar short) and app.js holds the
   document scrolled by that status bar (seat()), which puts the body's top at the screen's top: content runs behind the
   clock and to the bottom edge. In a browser tab the body is the visible area and nothing is held. The root's colour
   tints iOS's status bar, so it is always the page's own. */
html { overflow: hidden; overscroll-behavior: none; }
body { position: relative; height: 100vh; height: 100dvh; overflow: hidden; }
@media (display-mode: standalone) {
  :root { --sb: calc(100lvh - 100dvh); }
  body { height: 100vh; height: 100lvh; }
}
/* No transition on the background (musicapp-v29/v30): iOS's swipe back lifts its snapshot the frame after popstate, and a
   background still fading from the last page's tint was the flash the owner saw on every swipe; an album's colours
   arriving late faded the same way. Colours change at once. */
body { font: 15px/1.4 var(--font); -webkit-font-smoothing: antialiased; -webkit-tap-highlight-color: transparent; }
button, input { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: var(--accent); text-decoration: none; }
img { display: block; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── the doors ─────────────────────────────────────────────────────────── */
.door { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
        padding: calc(24px + var(--top)) 28px calc(24px + var(--safe-b)); gap: 6px; }
.doormark { width: 92px; height: 92px; border-radius: 22px; box-shadow: var(--shadow); margin-bottom: 10px; }
.door h1 { font-size: 30px; letter-spacing: -.03em; margin: 0 0 14px; }
.note { color: var(--dim); max-width: 330px; margin: 12px auto 0; font-size: 14px; }
.note.small { font-size: 12px; }
.err { color: var(--bad); margin: 10px 0 0; }
.btn { border: 0; border-radius: 999px; background: var(--accent); color: var(--on-accent); font-weight: 650; padding: 9px 18px;
       display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.btn.big { font-size: 17px; padding: 13px 34px; min-width: 200px; }
.btn.quiet { background: var(--pill); color: var(--ink); }
.btn:disabled { opacity: .5; }
.btn, .round, .tile .art, .tile .mosaic, .ibtn, .heart, .more, .keys button { transition: transform .15s cubic-bezier(.2,.8,.2,1), opacity .15s; }
.btn:active, .round:active, .ibtn:active, .keys button:active { transform: scale(.94); }
.tile:active .art, .tile:active .mosaic, .tile:active .tart { transform: scale(.96); }
.tile .tart { display: block; transition: transform .15s cubic-bezier(.2,.8,.2,1); }
.row:active, .lrows a:active, .lrows button:active, .cell:active { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.row, .lrows a, .lrows button { transition: background-color .15s; }
@keyframes pop { 0% { transform: scale(1); } 40% { transform: scale(1.35); } 100% { transform: scale(1); } }
.heart.on svg, .mk-fav svg { animation: pop .3s cubic-bezier(.2,.8,.2,1); }

/* ── "glass": the buttons over a page, the mini player, the tab bar, a menu — SOLID since musicapp-v30 (the owner, 2026-10-04:
   "I'd rather have a solid app than a pretty one"). backdrop-filter inside a sticky layer is WebKit bug 298709 on iOS 26
   (the sticky's child blinks out past a scroll threshold; the fix was reverted 2025-10-20), and a backdrop-filter that
   is switched on mid-scroll (the old .top.sub) creates its compositing layer in front of the user — the top flashing on
   its own. No backdrop-filter anywhere in the shell; IOS.md §24. ── */
.glass { background: var(--glass);
         border: 1px solid color-mix(in srgb, var(--ink) 9%, transparent); box-shadow: 0 6px 24px rgba(0,0,0,.14); }
.round { width: 44px; height: 44px; border-radius: 50%; padding: 0; display: inline-flex; align-items: center; justify-content: center; color: var(--ink); flex: none; }
.round svg { width: 22px; height: 22px; }

/* ── the header ────────────────────────────────────────────────────────── */
.top { position: sticky; top: 0; z-index: 30;
       padding: calc(4px + var(--top)) calc(var(--side) + var(--safe-r)) 8px calc(var(--side) + var(--safe-l));
       background: var(--bg);
       border-bottom: 1px solid transparent; }
.top.scrolled { border-bottom-color: transparent; }   /* iOS 26's bars have no hairline (the owner saw it as a stray line) */
.topin, #main, .foot { max-width: 980px; margin: 0 auto; }
.titlerow { display: flex; align-items: center; gap: 8px; min-height: 48px; }
.titlerow h1 { font-size: 34px; font-weight: 800; letter-spacing: -.035em; margin: 0; flex: 1; min-width: 0;
               white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar { display: none; align-items: center; gap: 10px; height: 46px; }
.bartitle { flex: 1; min-width: 0; text-align: center; font-weight: 700; font-size: 17px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
            opacity: 0; transition: opacity .2s; }
.baracts { display: flex; align-items: center; gap: 0; border-radius: 999px; flex: none; min-width: 44px; justify-content: flex-end; }
.baracts.glass { padding: 0 2px; }
.baracts button { background: none; border: 0; width: 44px; height: 44px; padding: 10px; color: var(--ink); display: inline-flex; align-items: center; justify-content: center; }
.baracts button svg { width: 22px; height: 22px; }
.baracts .save { width: auto; padding: 0 14px; font-weight: 700; color: var(--accent); font-size: 16px; }
.back svg { width: 24px; height: 24px; }
/* a pushed page: glass buttons over the page; its title comes into the bar once the page's own has scrolled under */
.top.sub { background: transparent; padding-bottom: 4px; }
/* musicapp-v17 (the owner: the top "does not update dynamically"): the moment the page scrolls under the status bar the
   whole bar — safe area and all — becomes the page's material, as Apple Music's album page does; the title comes later */
.top.sub.scrolled { background: var(--bg); }
.top.sub .bar { display: flex; }
.top.sub .titlerow { display: none; }
.top.sub.titled { background: var(--bg); border-bottom-color: transparent; }
.top.sub.titled .bartitle { opacity: 1; }
.top.gone { display: none; }
.me { width: 36px; height: 36px; border-radius: 50%; border: 0; background: var(--accent); color: var(--on-accent);
      font-weight: 700; font-size: 15px; display: inline-flex; align-items: center; justify-content: center; flex: none; }
.me.big { width: 64px; height: 64px; font-size: 26px; }
.search { display: flex; align-items: center; gap: 7px; height: 40px; margin-top: 6px; padding: 0 10px;
          background: color-mix(in srgb, var(--ink) 9%, transparent); border-radius: 12px; }
.search svg { width: 17px; height: 17px; flex: none; color: var(--dim); }
.search input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; font-size: 17px; -webkit-appearance: none; }
.search input::-webkit-search-cancel-button { display: none; }
.qx { border: 0; background: var(--dim); color: var(--bg); width: 18px; height: 18px; border-radius: 50%; font-size: 13px; line-height: 18px; padding: 0; }
.offline, .update { flex: none; border-radius: 999px; padding: 3px 10px; font-size: 12px; font-weight: 650; border: 0; }
.offline { background: var(--pill); color: var(--dim); }
.update { background: var(--accent); color: var(--on-accent); }

/* the content clears the foot, or the keyboard while it is up (the foot is under the keyboard then, as a native tab bar is) */
#main { padding: 4px calc(var(--side) + var(--safe-r)) calc(28px + max(var(--foot-h), var(--kb))) calc(var(--side) + var(--safe-l)); width: 100%; }
#app { position: absolute; inset: 0; }
#page { position: absolute; inset: 0; overflow-x: hidden;   /* by id: .page is a page TITLE's class (h1.ptitle.page) */
         overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; }
#page > main { flex: 1 0 auto; }
h1.ptitle.page { font-size: 34px; font-weight: 800; letter-spacing: -.035em; margin: 6px 0 10px; }

/* ── the foot: the mini player above the tab bar, floating as glass — the page's SIBLING, absolute at the stage's bottom ── */
.foot { position: absolute; left: 0; right: 0; bottom: 0; z-index: 25; width: 100%; pointer-events: none;   /* the dock's FLIP is off (app.js MOTION) */
        display: grid; grid-template-columns: 1fr 62px; grid-template-areas: "toast toast" "mini mini" "tabs tabs"; column-gap: 8px; row-gap: 0; align-items: end; align-content: end;
        padding: 8px calc(14px + var(--safe-r)) calc(6px + max(0px, var(--safe-b) - 12px)) calc(14px + var(--safe-l)); }
.foot > * { pointer-events: auto; }
.toast { grid-area: toast; margin-bottom: 8px; }     /* margins, not row gaps: a hidden row must leave no band above the dock */
.mini { grid-area: mini; margin-bottom: 8px; }
.tabbar { grid-area: tabs; justify-self: stretch; }
.sbtn { grid-area: search; width: 62px; height: 62px; color: var(--ink); }
.sbtn svg { width: 26px; height: 26px; }
.sbtn.on { color: var(--accent); }
/* MINIMIZED (iOS 26's dock, v24, from the owner's recording): scrolled down, the pill shrinks to the tab you are on — the
   others blur and fade as it closes — Search leaves the pill for a circle at the right, and the mini player drops into the
   row between them, its skip key fading. app.js setMin moves the mini and the search circle with a FLIP; the rest is these transitions. */
/* The tracks are FIXED or minmax(0, …) so a width animated on the mini or the search circle (app.js setMin's FLIP) moves no
   other track — an auto track grew with the pill's animated width and pushed the mini to the edge (found 2026-10-04). */
.foot.min { grid-template-columns: 62px minmax(0, 1fr) 62px; grid-template-areas: "toast toast toast" "tabs mini search"; }
/* The pill leaves the grid: the same full-width box, absolute, CLIPPED to a circle at its left — so its tabs keep their
   places under the clip and fade as it closes over them (Apple's), and the clip is what setMin animates, not a width. */
.foot.min .tabbar { position: absolute; grid-area: auto; left: calc(14px + var(--safe-l)); right: calc(14px + var(--safe-r)); bottom: calc(6px + max(0px, var(--safe-b) - 12px));   /* grid-area auto: an absolute grid child is otherwise boxed by its area */
                    clip-path: inset(0 calc(100% - 62px) 0 0 round 999px); }
.foot.min .mini { height: 62px; margin-bottom: 0; }
#miniNext { transition: width .3s cubic-bezier(.32,.72,0,1), opacity .18s, padding .3s; overflow: hidden; }
.foot.min #miniNext { width: 0; padding: 0; opacity: 0; }
.tabbar a { transition: opacity .18s, filter .18s; overflow: hidden; }
.tabbar a span { transition: opacity .15s; max-height: 14px; }
.foot.measuring .mini, .foot.measuring .tabbar a, .foot.measuring .tabbar a span { transition-property: opacity, filter; }
.foot.min .tabbar a { flex: none; width: 25%; }
.foot.min .tabbar a:not(.on), .foot.min .tabbar a[data-tab="search"] { opacity: 0; filter: blur(4px); }
.foot.min .tabbar a.on { position: absolute; left: 4px; top: 4px; width: 54px; height: 54px; padding: 0; opacity: 1; filter: none; }
.foot.min .tabbar a.on span { opacity: 0; max-height: 0; }                /* the circle holds the icon alone, as Apple's */
.foot.min .tabbar.none a:first-child { position: absolute; left: 4px; top: 4px; width: 54px; height: 54px; padding: 0; opacity: 1; filter: none; }   /* on Search: Home stands for the pill */
.foot.min .tabbar.none a:first-child span { opacity: 0; max-height: 0; }
.mini { position: relative; display: flex; align-items: center; gap: 2px; height: 58px; padding: 0 8px 0 7px; border-radius: 999px; overflow: hidden; }
.miniopen { flex: 1; min-width: 0; display: flex; align-items: center; gap: 11px; background: none; border: 0; text-align: left; padding: 0; height: 100%; }
.miniopen img { width: 44px; height: 44px; border-radius: 50%; background: var(--pill); flex: none; object-fit: cover; }
.minitxt { min-width: 0; }
.minitxt b, .minitxt span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.minitxt b { font-weight: 600; font-size: 15px; }
.minitxt span { color: var(--dim); font-size: 13px; }
.ibtn { background: none; border: 0; width: 44px; height: 44px; padding: 9px; color: var(--ink); flex: none; }
.ibtn svg { width: 100%; height: 100%; }
.miniprog { position: absolute; left: 22px; right: 22px; bottom: 0; height: 2px; }
.miniprog i { display: block; height: 100%; width: 0; background: var(--accent); border-radius: 2px; }
.livedot { display: inline-block; font-style: normal; font-size: 10px; font-weight: 800; letter-spacing: .04em; color: #fff; background: var(--bad);
           border-radius: 4px; padding: 1px 5px; vertical-align: 2px; margin-right: 5px; }
.tabbar { display: flex; height: 62px; padding: 4px; border-radius: 999px; --tabink: var(--panel); overflow: hidden; position: relative; }
.tabbar a { flex: 1 1 0; min-width: 0; max-width: 200px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; border-radius: 999px;
            color: var(--ink); font-size: 10.5px; font-weight: 600; padding: 0 6px; }
.tabbar a svg { width: 25px; height: 25px; }
.tabbar a.on { color: var(--accent); background: color-mix(in srgb, var(--ink) 8%, transparent); }
.toast { align-self: center; max-width: 100%; background: var(--ink); color: var(--bg); border-radius: 999px; padding: 9px 16px; font-weight: 600; font-size: 14px;
         box-shadow: 0 6px 20px rgba(0,0,0,.2); text-align: center; }
.toast .undo { margin: -4px -8px -4px 12px; padding: 4px 12px; border: 0; border-radius: 999px; background: color-mix(in srgb, var(--bg) 18%, transparent); color: var(--accent);
               font: inherit; font-weight: 700; }

/* ── sections, tiles, rows ─────────────────────────────────────────────── */
h2.sec { font-size: 22px; letter-spacing: -.02em; margin: 24px 0 10px; display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
h2.sec a { font-size: 16px; font-weight: 500; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 18px 14px; }
.tile { background: none; border: 0; padding: 0; text-align: left; min-width: 0; color: var(--ink); }
a.tile { display: block; }
.tile .art { aspect-ratio: 1; width: 100%; border-radius: var(--r-tile); box-shadow: var(--shadow); }
.tile b { display: block; margin-top: 7px; font-weight: 500; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tile span { display: block; color: var(--dim); font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shelf { display: grid; grid-auto-flow: column; grid-auto-columns: 150px; gap: 14px; overflow-x: auto; margin: 0 calc(-1 * var(--side)); padding: 0 var(--side) 6px;
         scrollbar-width: none; scroll-snap-type: x mandatory; scroll-padding: 0 var(--side); }
.shelf > * { scroll-snap-align: start; }
.shelf::-webkit-scrollbar { display: none; }
.art { background: linear-gradient(135deg, var(--pill), var(--panel-2)); object-fit: cover; }
.art.none { display: flex; align-items: center; justify-content: center; color: var(--dim); font-size: 28px; }
.mosaic { display: grid; grid-template-columns: 1fr 1fr; overflow: hidden; aspect-ratio: 1; }
.mosaic img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 1; }
.tart { position: relative; display: block; }
.dlmark { position: absolute; right: 6px; bottom: 6px; width: 22px; height: 22px; border-radius: 50%; background: rgba(0,0,0,.55); color: #fff;
          font-style: normal; font-size: 13px; line-height: 22px; text-align: center; }
.list { background: var(--panel); border-radius: var(--r-mid); overflow: hidden; box-shadow: var(--shadow); }
.row { display: flex; align-items: center; gap: 12px; width: 100%; padding: 10px 14px; border: 0; background: none; text-align: left; color: var(--ink);
       border-top: 1px solid var(--line); min-height: 56px; }
.row:first-child { border-top: 0; }
.row img { width: 46px; height: 46px; border-radius: 7px; flex: none; object-fit: cover; }
.row .txt { flex: 1; min-width: 0; }
.row .txt b, .row .txt span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row .txt b { font-weight: 500; }
.row .txt span { color: var(--dim); font-size: 13px; }
.row .side { color: var(--dim); font-size: 13px; flex: none; }
.rowplay { flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px; padding: 8px 0; border: 0; background: none; text-align: left; color: inherit; }
.song-row { padding-top: 0; padding-bottom: 0; padding-right: 4px; }
.song-row.now .txt b { color: var(--accent); }
.letter { position: sticky; top: calc(var(--top) + 54px); z-index: 2; font-weight: 700; color: var(--dim); font-size: 13px;
          padding: 14px 2px 6px; background: var(--bg); }
.empty { color: var(--dim); text-align: center; padding: 40px 10px; }
.counts { color: var(--dim); font-size: 13px; text-align: center; margin: 26px 0 0; }
.credit { color: var(--dim); font-size: 12px; text-align: center; margin: 16px 0; }
.pill { display: inline-block; border-radius: 999px; padding: 2px 9px; font-size: 12px; font-weight: 600; background: var(--pill); color: var(--ink-2); flex: none; }
.pill.here { background: color-mix(in srgb, var(--good) 18%, transparent); color: var(--good); }
.pill.busy { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }
.pill.bad { background: color-mix(in srgb, var(--bad) 15%, transparent); color: var(--bad); }
.ask { margin: 18px 0; padding: 16px; border-radius: var(--r-mid); background: var(--panel); box-shadow: var(--shadow); text-align: center; }
.ask p { margin: 0 0 10px; color: var(--ink-2); }
.rowerr { display: block; color: var(--bad); font-size: 12px; white-space: normal !important; }
.actsrow { display: flex; gap: 10px; margin: 12px 0; flex-wrap: wrap; }
.linkish { border: 0; background: none; color: var(--accent); font: inherit; font-size: 15px; font-weight: 500; padding: 0; }

/* Home's Library row (v41; a 2×3 of cells at the top until v40): the six lists as one row of pills with their icons,
   Charts' .tabs; and Search's Here · Get, the same pills */
.tabs.lib a { display: inline-flex; align-items: center; gap: 6px; padding: 7px 13px 7px 11px; font-size: 15px; }
.tabs.lib svg { width: 17px; height: 17px; color: var(--accent); flex: none; }
.tabs.seg { margin-bottom: 10px; }
.tabs.seg a { padding: 6px 18px; }
/* Library, Search, Settings: Apple's plain rows — an icon, a word, a chevron */
.lrows { margin: 4px 0 8px; }
.lrows a, .lrows button { display: flex; align-items: center; gap: 14px; width: 100%; padding: 0; border: 0; background: none; color: var(--ink); font-size: 20px; text-align: left; }
.lrows a > span, .lrows button > span { flex: 1; padding: 13px 0; border-bottom: 1px solid var(--line); display: flex; justify-content: space-between; align-items: center; }
.lrows a > span small, .lrows button > span small { color: var(--dim); font-size: 15px; }
.lrows a > span::after, .lrows button > span::after { content: "›"; color: var(--dim); font-size: 22px; line-height: 1; margin-left: 8px; }
.lrows svg { width: 26px; height: 26px; color: var(--accent); flex: none; }
.who-head { display: flex; align-items: center; gap: 14px; margin: 6px 0 18px; }
.who-head b { display: block; font-size: 22px; }
.who-head small { color: var(--dim); font-size: 14px; }

/* ── an album, a playlist: Apple's page ────────────────────────────────── */
.hero { text-align: center; padding: 2px 0 4px; }
.hero .big { width: min(68vw, 300px); aspect-ratio: 1; margin: 2px auto 18px; border-radius: 10px; box-shadow: 0 16px 44px rgba(0,0,0,.28); }
.hero h1 { font-size: 23px; font-weight: 700; letter-spacing: -.02em; margin: 0; line-height: 1.2; }
.hero .by { font-size: 20px; margin: 3px 0 0; }
.hero .by a { color: inherit; }
.hero .meta { font-size: 13px; font-weight: 600; color: var(--dim); margin: 5px 0 0; }
.hero .dlline { font-size: 12px; color: var(--dim); margin: 6px 0 0; }
.cta { display: flex; justify-content: center; align-items: center; gap: 14px; margin: 18px 0 12px; }
.cta .round { width: 44px; height: 44px; border: 0; background: color-mix(in srgb, var(--ink) 11%, transparent); }
.cta .round svg { width: 20px; height: 20px; }
.cta .btn.play { flex: 1; max-width: 300px; }
.hero .big { transform-origin: 50% 100%; }   /* stretches from its foot when the page is pulled past its top (app.js onScroll) */
.cta .round.on { color: var(--ink); }
.cta .round:disabled { opacity: .4; }
.btn.play { min-width: 172px; height: 50px; font-size: 18px; background: var(--ink); color: var(--playink, var(--bg)); }
.btn.play svg { width: 18px; height: 18px; }
.songs { margin: 4px 0 0; padding-left: 20px; border-top: 1px solid var(--line); }   /* the 20px is the marks' gutter (v17) */
.song { position: relative; display: flex; align-items: center; width: 100%; min-height: 54px; transition: background-color .15s; }
.song:active { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.songs .song + .song::before, .songs .discno + .song::before { content: ""; position: absolute; left: 40px; right: 0; top: 0; border-top: 1px solid var(--line); }
.song .sp { flex: 1; min-width: 0; display: flex; align-items: center; gap: 14px; padding: 12px 0; border: 0; background: none; text-align: left; color: inherit; }
.song .n { width: 26px; text-align: center; color: var(--dim); font-variant-numeric: tabular-nums; font-size: 16px; flex: none; }
.song .t { flex: 1; min-width: 0; }
.song .t b { display: block; font-weight: 400; font-size: 17px; line-height: 1.25; overflow-wrap: anywhere; }
.song .t span { display: block; color: var(--dim); font-size: 14px; margin-top: 2px; overflow-wrap: anywhere; }
.song.now .t b { color: var(--accent); }
.song .thumb { width: 46px; height: 46px; border-radius: 6px; flex: none; object-fit: cover; }
.song .tw { position: relative; flex: none; width: 46px; height: 46px; }
.song .tw .thumb, .song .tw .n { position: absolute; inset: 0; width: 46px; }
.song .tw .n { display: flex; align-items: center; justify-content: center; }
.song .tw .eq { position: absolute; inset: 0; width: auto; height: auto; border-radius: 6px; background: rgba(0,0,0,.45); align-items: center; display: none; }
.song .tw .eq i { height: 14px; background: #fff; }
.song.now .tw .eq { display: flex; }
.song.now .tw .eq i { animation: eq .8s ease-in-out infinite alternate; animation-play-state: paused; }
.songs.playing .song.now .tw .eq i { animation-play-state: running; }
.song .n .eq { display: none; }
.song.now .n .num { display: none; }
.song.now .n .eq { display: inline-flex; }
.songs.playing .song.now .n .eq i { animation: eq .8s ease-in-out infinite alternate; }
.songs.playing .song.now .eq i:nth-child(2) { animation-delay: -.25s; } .songs.playing .song.now .eq i:nth-child(3) { animation-delay: -.5s; }
.songs.wart .song + .song::before { left: 60px; }
.song .dln { flex: none; width: 18px; height: 18px; color: var(--dim); margin-right: 2px; }
.more { flex: none; width: 40px; height: 44px; border: 0; background: none; color: var(--ink); font-size: 20px; line-height: 1; padding: 0; opacity: .75;
        display: inline-flex; align-items: center; justify-content: center; }
.more svg { width: 20px; height: 20px; }
.discno { color: var(--dim); font-size: 13px; font-weight: 600; margin: 16px 2px 4px; }
.albumfoot { color: var(--dim); font-size: 13px; margin: 18px 2px 0; line-height: 1.5; }
.eq { display: inline-flex; align-items: flex-end; justify-content: center; gap: 2px; width: 26px; height: 15px; flex: none; }
.eq i { width: 3px; height: 45%; background: var(--accent); border-radius: 1px; }
.eq i:nth-child(2) { height: 85%; } .eq i:nth-child(3) { height: 60%; }
.eq.go i { animation: eq .8s ease-in-out infinite alternate; }
.eq.go i:nth-child(2) { animation-delay: -.25s; } .eq.go i:nth-child(3) { animation-delay: -.5s; }
@keyframes eq { from { height: 20%; } to { height: 100%; } }

/* ── a ••• menu: Apple's pop-up, ABSOLUTE in the document beside its button (never fixed: IOS.md §15) ── */
.menu { position: absolute; z-index: 60; width: 270px; max-width: calc(100vw - 24px); padding: 6px 0; border-radius: 16px; overflow: hidden;
        background: var(--panel); color: var(--ink);
        box-shadow: 0 14px 44px rgba(0,0,0,.28), 0 0 0 1px color-mix(in srgb, var(--ink) 8%, transparent);
        transform-origin: top right; animation: menuin .14s ease-out; }
@keyframes menuin { from { opacity: 0; transform: scale(.92); } to { opacity: 1; transform: none; } }
.menu button { display: flex; align-items: center; justify-content: space-between; gap: 14px; width: 100%; padding: 11px 16px; border: 0; background: none;
               color: inherit; font-size: 16px; text-align: left; }
.menu button:active { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.menu button small { color: var(--dim); font-size: 13px; }
.menu button svg { width: 20px; height: 20px; flex: none; }
.menu button:disabled { opacity: .45; }
.menu .sep { height: 7px; background: color-mix(in srgb, var(--ink) 7%, transparent); }
.menu .mhead { padding: 8px 16px 6px; color: var(--dim); font-size: 13px; }
.menu .danger { color: var(--bad); }

/* ── Now Playing: a screen of its own ──────────────────────────────────── */
.np { padding-top: var(--top); margin: 0 calc(-1 * var(--side)); min-height: 100vh; display: flex; flex-direction: column; position: relative; isolation: isolate;
      background: var(--bg); will-change: transform; }
.np.moving { border-radius: 14px 14px 0 0; overflow: hidden; }
/* the cover, blurred and dimmed, is the page (Apple's); v18 */
.np-bg { position: absolute; inset: -60px; z-index: -1; background: center / cover no-repeat; filter: blur(50px) saturate(1.4) brightness(.5); transform: scale(1.1); pointer-events: none; }
.np-bg::after { content: ""; position: absolute; inset: 0; background: linear-gradient(rgba(0,0,0,.1), rgba(0,0,0,.4)); }
.grab { display: block; margin: 0 auto 8px; width: 64px; height: 22px; border: 0; background: none; padding: 8px 12px; }
.grab i { display: block; height: 5px; border-radius: 3px; background: color-mix(in srgb, var(--ink) 35%, transparent); }
/* edge to edge, and taller than wide on a tall phone (Apple crops the sides the same way) */
.np-art { width: 100%; max-width: 640px; margin: 0 auto; min-height: max(min(100vw, 640px), 52vh); flex: 1 0 auto; object-fit: cover;
          -webkit-mask-image: linear-gradient(#000 62%, transparent 100%); mask-image: linear-gradient(#000 62%, transparent 100%); }
.np-art.none { display: flex; align-items: center; justify-content: center; font-size: 80px; color: var(--dim); }
.np-body { padding: 0 calc(24px + var(--safe-r)) calc(14px + var(--safe-b)) calc(24px + var(--safe-l)); max-width: 560px; width: 100%; margin: -40px auto 0; position: relative; }
.np-head { display: flex; align-items: center; gap: 4px; }
.np-head .t { flex: 1; min-width: 0; }
.np-title { font-size: 21px; font-weight: 700; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-sub { font-size: 19px; color: var(--dim); margin: 1px 0 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-sub a { color: inherit; }
.np-head .heart, .np-head .more { color: var(--ink); opacity: 1; }
.heart { flex: none; width: 44px; height: 44px; padding: 10px; border: 0; background: none; color: var(--ink); }
.heart svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.8; }
.heart.on { color: var(--accent); }
.heart.on svg { fill: currentColor; }
.transport { margin: 14px 0 0; }
.scrub input { width: 100%; margin: 0; height: 22px; -webkit-appearance: none; appearance: none; background: transparent; }
.scrub input::-webkit-slider-runnable-track { height: 7px; border-radius: 4px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--ink) 70%, transparent) var(--p, 0%), color-mix(in srgb, var(--ink) 20%, transparent) var(--p, 0%)); }
.scrub input::-webkit-slider-thumb { -webkit-appearance: none; width: 7px; height: 7px; border-radius: 50%; background: transparent; margin-top: 0; }
.scrub input::-moz-range-track { height: 7px; border-radius: 4px; background: color-mix(in srgb, var(--ink) 20%, transparent); }
.scrub input::-moz-range-progress { height: 7px; border-radius: 4px; background: color-mix(in srgb, var(--ink) 70%, transparent); }
.times { display: flex; justify-content: space-between; font-size: 12px; font-weight: 600; color: var(--dim); font-variant-numeric: tabular-nums; margin-top: 2px; }
.livebar { display: flex; align-items: center; gap: 10px; margin: 20px 0 6px; font-size: 13px; font-weight: 600; color: var(--dim); }
.livebar::before, .livebar::after { content: ""; flex: 1; height: 7px; border-radius: 4px; background: color-mix(in srgb, var(--ink) 20%, transparent); }
.keys { display: flex; justify-content: center; align-items: center; gap: 46px; margin: 14px 0 6px; }
.keys button { background: none; border: 0; color: var(--ink); padding: 6px; }
.keys button:disabled { opacity: .3; }
.keys svg { width: 44px; height: 44px; }
.keys .pp svg { width: 62px; height: 62px; }
.np-tools { display: flex; justify-content: space-around; align-items: center; margin: 22px 0 4px; }
.np-tools button { background: none; border: 0; width: 48px; height: 44px; padding: 9px; color: var(--dim); border-radius: 12px; }
.np-tools button.on { color: var(--ink); background: color-mix(in srgb, var(--ink) 12%, transparent); }
.np-tools button svg { width: 100%; height: 100%; }
.np-small { display: flex; align-items: center; gap: 12px; padding: 0 calc(20px + var(--safe-r)) 10px calc(20px + var(--safe-l)); max-width: 560px; width: 100%; margin: 0 auto; }
.np-small img, .np-small .none { width: 60px; height: 60px; border-radius: 8px; flex: none; object-fit: cover; }
.np-small .t { flex: 1; min-width: 0; }
.np-small .np-title { font-size: 17px; }
.np-small .np-sub { font-size: 15px; }
.np-pane { flex: 1; padding: 0 calc(20px + var(--safe-r)) 10px calc(20px + var(--safe-l)); max-width: 560px; width: 100%; margin: 0 auto; }
.np-dock { position: sticky; bottom: 0; padding: 4px calc(24px + var(--safe-r)) calc(10px + var(--safe-b)) calc(24px + var(--safe-l));
           max-width: 560px; width: 100%; margin: 0 auto; background: linear-gradient(transparent, var(--bg) 22px); }
.np-dock .keys { margin: 4px 0 0; }
.np-dock .np-tools { margin: 8px 0 0; }
.lockline { text-align: center; font-size: 12px; color: var(--dim); margin: 6px 0 0; }
.lyrics { padding: 6px 0 30px; font-size: 26px; line-height: 1.3; font-weight: 750; letter-spacing: -.01em; }
.lyrics p { margin: 0 0 16px; color: color-mix(in srgb, var(--ink) 35%, transparent); transition: color .2s; }
.lyrics p.on { color: var(--ink); }
.lyrics.plain p { color: var(--ink); font-size: 19px; font-weight: 500; margin: 0 0 6px; }
.qhead { display: flex; justify-content: space-between; align-items: center; margin: 10px 0 6px; gap: 10px; }
.qhead b { font-size: 20px; display: block; }
.qhead small { display: block; color: var(--dim); font-size: 15px; margin-top: 1px; }
/* Up Next's rows (v18, Apple's): no card, no separators; the handle at the right; Remove waits behind a swipe */
.qlist { margin: 6px calc(-1 * var(--side)) 0; }
.qrow.row { padding: 0; border: 0; background: transparent; gap: 0; display: block; position: relative; overflow: hidden; }
.qbody { position: relative; z-index: 1; display: flex; align-items: center; gap: 6px; padding: 5px 8px 5px var(--side); transition: transform .22s cubic-bezier(.2,.8,.2,1); }
.qbody .rowplay { padding: 0; gap: 12px; }
.qbody img, .qbody .art.none { width: 50px; height: 50px; border-radius: 6px; flex: none; object-fit: cover; }
.qbody .txt b { font-size: 17px; font-weight: 500; }
.qbody .txt span { font-size: 14px; }
.qbody .handle { width: 40px; height: 48px; display: flex; align-items: center; justify-content: center; font-size: 22px; }
.qrow.open .qbody { transform: translateX(-92px); }
.qdel { position: absolute; top: 0; right: 0; bottom: 0; width: 92px; border: 0; background: var(--bad); color: #fff; font-weight: 600; font-size: 15px;
        transform: translateX(100%); transition: transform .22s cubic-bezier(.2,.8,.2,1); }
.qrow.open .qdel { transform: none; }
.qrow.dragging { z-index: 3; box-shadow: 0 8px 26px rgba(0,0,0,.3); transition: none; }
#qList .qrow { transition: transform .15s; }
html.locked .np-pane { -webkit-mask-image: linear-gradient(#000 calc(100% - 40px), transparent); mask-image: linear-gradient(#000 calc(100% - 40px), transparent); }
.np .linkish { color: var(--ink); font-weight: 600; }
.handle { flex: none; width: 30px; text-align: center; color: var(--dim); font-size: 20px; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
.qrow, .edrow { padding-top: 0; padding-bottom: 0; gap: 6px; background: var(--panel); }
.qrow .rowplay { padding-left: 2px; }
.edrow { padding-top: 8px; padding-bottom: 8px; }
.row.dragging { position: relative; z-index: 3; box-shadow: 0 8px 26px rgba(0,0,0,.22); transition: none; }
#qList .row, #edList .row { transition: transform .15s; }
#qList .row.dragging, #edList .row.dragging { transition: none; }
.np .list { background: color-mix(in srgb, var(--ink) 7%, transparent); box-shadow: none; }
.np .qrow { background: transparent; }
.rm, .add { flex: none; width: 32px; height: 32px; border-radius: 50%; border: 0; padding: 0; font-size: 20px; line-height: 32px; font-weight: 600; }
.rm { background: color-mix(in srgb, var(--bad) 14%, transparent); color: var(--bad); }
.add { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); }

/* ── Radio ─────────────────────────────────────────────────────────────── */
.station { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 18px 16px 20px; border-radius: var(--r-card);
           background: linear-gradient(160deg, #3a1d5c, #c2185b 60%, #ff7043); color: #fff; box-shadow: var(--shadow); margin-top: 8px; }
.station .lbl { font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; opacity: .85; display: flex; align-items: center; gap: 6px; }
.station img, .station .none { width: min(56vw, 230px); aspect-ratio: 1; border-radius: 12px; margin: 14px 0 14px; box-shadow: 0 14px 40px rgba(0,0,0,.35); object-fit: cover; }
.station .none { display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.15); font-size: 60px; }
.station h2 { margin: 0; font-size: 21px; }
.station p { margin: 2px 0 0; opacity: .85; }
.station .btn.play { margin-top: 16px; background: #fff; color: #000; }
.station .state { font-size: 12px; opacity: .8; margin-top: 8px; min-height: 1em; }

/* ── the playlist editor ───────────────────────────────────────────────── */
.field { display: block; width: 100%; margin: 6px 0 0; padding: 12px 14px; border: 0; border-radius: var(--r-mid); background: var(--panel);
         box-shadow: var(--shadow); font-size: 20px; font-weight: 650; outline: 0; }
.search.inpage { margin: 14px 0 10px; background: var(--panel); box-shadow: var(--shadow); }
.disc { margin: 16px 2px 10px; }
.disc p { margin: 6px 0 0; font-size: 13px; color: var(--dim); }
.disc p b { color: var(--ink-2); font-weight: 600; }
.meter { height: 6px; border-radius: 999px; background: var(--pill); overflow: hidden; }
.meter i { display: block; height: 100%; background: var(--accent); border-radius: 999px; }
.tabs { display: flex; gap: 6px; overflow-x: auto; margin: 8px calc(-1 * var(--side)) 6px; padding: 0 var(--side); scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tabs a { flex: none; padding: 6px 14px; border-radius: 999px; background: var(--pill); color: var(--ink); font-size: 14px; font-weight: 550; }
.tabs a.on { background: var(--ink); color: var(--bg); }
.tabs.tempo a { font-size: 13px; padding: 5px 12px; }
.newtag { font-style: normal; color: var(--accent); font-weight: 650; }
.draft { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin: 10px 0 0; padding: 10px 14px; border-radius: var(--r-mid);
         background: color-mix(in srgb, var(--accent) 12%, transparent); font-size: 14px; }

/* ── the leaderboard, Listened today, For you, Continue ────────────────── */
.row.board { gap: 10px; }
.row.board .rk { width: 22px; text-align: right; color: var(--dim); font-variant-numeric: tabular-nums; font-weight: 650; flex: none; }
.row.board .side { text-align: right; line-height: 1.3; }
.row.board.mine .txt b { color: var(--accent); }
.row .me { width: 46px; height: 46px; font-size: 18px; flex: none; }
.me.you { background: var(--ink); color: var(--bg); }
.mv { font-style: normal; font-size: 11px; font-weight: 700; color: var(--dim); }
.mv.up { color: var(--good); } .mv.down { color: var(--bad); } .mv.new { color: var(--accent); }
.youline { color: var(--ink-2); font-size: 14px; font-weight: 600; margin: 8px 4px 0; }
.shelf.today { grid-auto-columns: 132px; }
.who { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left; padding: 12px; border: 0; border-radius: var(--r-mid);
       background: var(--panel); box-shadow: var(--shadow); color: var(--ink); min-width: 0; }
.who b { font-size: 14px; }
.who span:not(.me) { color: var(--dim); font-size: 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.who .me { width: 34px; height: 34px; font-size: 15px; margin-bottom: 4px; }

/* ── settings: the foot (contract rule 5, members-only: no money rows, no games row) ── */
.group { margin: 22px 0 0; }
.group h3 { font-size: 13px; font-weight: 600; color: var(--dim); text-transform: uppercase; letter-spacing: .02em; margin: 0 0 6px 14px; }
.cell { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; border-top: 1px solid var(--line);
        background: none; border-left: 0; border-right: 0; border-bottom: 0; width: 100%; text-align: left; color: var(--ink); }
.cell:first-child { border-top: 0; }
.cell small { color: var(--dim); }
.cell.danger { color: var(--bad); }
a.cell { color: var(--ink); }
details.tech summary { padding: 12px 14px; color: var(--dim); cursor: pointer; }
details.tech .cell { font-size: 13px; }
.switch { appearance: none; -webkit-appearance: none; width: 51px; height: 31px; border-radius: 999px; background: var(--pill); position: relative;
          flex: none; transition: background .2s; margin: 0; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: 50%; background: #fff;
                 box-shadow: 0 2px 4px rgba(0,0,0,.2); transition: transform .2s; }
.switch:checked { background: var(--good); }
.switch:checked::after { transform: translateX(20px); }
.address { color: var(--dim); font-size: 12px; text-align: center; margin: 26px 0 8px; }

@media (min-width: 700px) {
  :root { --side: 28px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
  .shelf { grid-auto-columns: 180px; }
  .foot { max-width: 560px; }
  /* an album on a wide screen: the cover beside the title, as Apple's iPad and Mac apps put it */
  .hero.wide { display: grid; grid-template-columns: 260px 1fr; grid-template-rows: 1fr repeat(4, auto); gap: 0 28px; text-align: left; margin-top: 8px; }
  .hero.wide > :not(.big) { grid-column: 2; }
  .hero.wide h1 { align-self: end; }
  .hero.wide .big { width: 260px; margin: 0; grid-row: 1 / span 5; }
  .hero.wide .cta { justify-content: flex-start; }
}
.dlsm { display: inline-block; width: 16px; height: 16px; line-height: 16px; border-radius: 50%; background: var(--dim); color: var(--bg);
        font-style: normal; font-size: 10px; text-align: center; vertical-align: 1px; }
.np-art.tall { object-position: 50% 30%; }

/* ── Now Playing is ONE SCREEN (the owner, 2026-10-03: Apple's "doesn't let the elements move below";
 * ours had room under the keys and scrolled, which made it feel loose and the swipe down harder). It
 * locks the PAGE while it shows (musicapp-v34: the page, not the root — the root never scrolls now, and
 * the stage is the whole screen, so the band a short 100% root left under it is gone): the cover takes
 * what the song and the keys leave; Lyrics and Up Next scroll inside their own box (.scroller), the
 * keys docked under it. The foot keeps no height there: only its toast, floated above the bottom. ── */
html.locked #page { overflow: hidden; overscroll-behavior: none; }
html.locked #main { flex: 1 1 auto; min-height: 0; padding: 0; display: flex; flex-direction: column; }
html.locked .np { margin: 0; min-height: 0; height: 100%; flex: 1 1 auto; overflow: hidden; }
html.locked .np-art { flex: 1 1 0; min-height: 0; height: auto; }
html.locked .np-pane { flex: 1 1 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; padding-bottom: 44px; }
html.locked .np-dock { position: static; background: none; }
html.locked .foot { height: 0; padding: 0; }
html.locked .toast { position: absolute; bottom: calc(28px + var(--safe-b)); left: 50%; transform: translateX(-50%); white-space: nowrap; }

/* ── Ask: iTunes' price button (musicapp-v10). ASK → spinner → ring (stop square while it can be cancelled) → PLAY.
   The ring sits at the right of the button's own width, so nothing in the row moves when one becomes the other. */
.buy { flex: none; min-width: 64px; height: 30px; padding: 0 12px; border-radius: 999px; border: 1.5px solid var(--accent); background: none;
       color: var(--accent); font: 650 14px/1 var(--font); letter-spacing: .03em; }
.buy.own { border-color: var(--ink); color: var(--ink); }
.reqmore { display: block; margin: 12px auto 0; }                 /* Requests › Here: "Show all N" */
.buy:active { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.ring { flex: none; width: 64px; height: 30px; display: flex; justify-content: flex-end; align-items: center; padding: 0; border: 0; background: none; color: var(--accent); }
.ring svg { width: 30px; height: 30px; transform: rotate(-90deg); overflow: visible; }
.ring .tr { fill: none; stroke: color-mix(in srgb, var(--accent) 22%, transparent); stroke-width: 1.6; }
.ring .arc { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; transition: stroke-dasharray .4s; }
.ring rect { fill: currentColor; }
.ring.spin .arc { transform-origin: 15px 15px; animation: askspin .9s linear infinite; }   /* the arc turns; a stop square stays put */
.ring.spin .tr { stroke: none; }
@keyframes askspin { to { transform: rotate(360deg); } }
.row .txt .asknote { color: var(--dim); font-size: 12px; }
.btn.sm { padding: 6px 12px; font-size: 13px; flex: none; }

/* ── musicapp-v11 ─────────────────────────────────────────────────────────────────────────────────────── */

/* An empty page, as Apple's apps draw one: a symbol and a few words. */
.blank { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 56px 16px; color: var(--dim); }
.blank svg { width: 44px; height: 44px; stroke-width: 1.6; }
.blank p { margin: 0; font-size: 17px; font-weight: 600; }
/* A page waiting on its first answer: a spinner, shown only after a moment (most answers come sooner). */
.wait { display: flex; justify-content: center; padding: 56px 0; opacity: 0; animation: waitin .2s .3s forwards; }
.wait .ring { width: 30px; }
.wait.now { display: inline-flex; padding: 0; margin-left: 8px; vertical-align: middle; opacity: 1; animation: none; }
.wait.now .ring, .wait.now svg { width: 18px; height: 18px; }
@keyframes waitin { to { opacity: 1; } }

/* The badge on your initial: requests on their way (the Downloads badge of the iTunes Store). */
.me { position: relative; }
.me .badge { position: absolute; top: -5px; right: -7px; min-width: 19px; height: 19px; padding: 0 5px; border-radius: 10px; background: #ff3b30;
             color: #fff; font: 700 12px/19px var(--font); font-style: normal; text-align: center; box-shadow: 0 0 0 2px var(--bg); }
.row[data-open] { cursor: pointer; }
.row[data-open]:active { background: color-mix(in srgb, var(--ink) 6%, transparent); }

/* An album not here yet — the iTunes Store's album page: the cover beside what it is, then its songs as a table. */
.pv-head { display: flex; gap: 16px; align-items: stretch; margin: 4px 0 18px; }
.pv-head > img, .pv-head > .none { width: 42%; max-width: 220px; aspect-ratio: 1; flex: none; border-radius: 8px; object-fit: cover;
                                   box-shadow: 0 10px 30px rgba(0,0,0,.22); }
.pv-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.pv-meta .ptitle { font-size: 21px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2; margin: 0;
                   display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.pv-meta .by { margin: 4px 0 0; font-size: 16px; }
.pv-meta .by a { color: var(--dim); text-decoration: none; }
.pv-meta .meta { margin: auto 0 0; padding-top: 10px; color: var(--dim); font-size: 13px; line-height: 1.45; }
.pv-ask { margin-top: 10px; display: flex; justify-content: flex-start; }
.pv-ask .ring { justify-content: flex-start; }
.ptable { border-top: 1px solid var(--line); }
.phead, .prow { display: grid; grid-template-columns: 28px minmax(0, 1fr) 44px 30px 64px; align-items: center; column-gap: 8px; }
.phead { padding: 8px 0 6px; color: var(--dim); font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
         border-bottom: 1px solid var(--line); }
.phead .dur, .phead .pop0 { text-align: center; }
.prow { min-height: 54px; padding: 6px 0; border-bottom: 1px solid var(--line); cursor: pointer; }
.prow .n { text-align: center; color: var(--dim); font-variant-numeric: tabular-nums; display: flex; justify-content: center; }
.prow .n .ring { width: 26px; height: 26px; color: var(--accent); }
.prow .n .ring svg { width: 26px; height: 26px; }
.prow .t b, .prow .t span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prow .t b { font-weight: 500; }
.prow .t span { color: var(--dim); font-size: 13px; }
.prow .dur { color: var(--dim); font-size: 13px; text-align: center; font-variant-numeric: tabular-nums; }
.prow.on .t b, .prow.on .dur { color: var(--accent); }
.prow.lit { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.prow:active { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.ring-slot { width: 64px; }
/* Popularity as iTunes draws it: thin bars, the share that is "on" bright. */
.pop { --p: 0; height: 14px; width: 26px; justify-self: center;
       background: linear-gradient(90deg, var(--ink) calc(var(--p) * 100%), color-mix(in srgb, var(--ink) 22%, transparent) 0);
       -webkit-mask: repeating-linear-gradient(90deg, #000 0 1.5px, transparent 1.5px 3px); mask: repeating-linear-gradient(90deg, #000 0 1.5px, transparent 1.5px 3px); }

/* Pages slide as iOS pages do — Budget's view transitions (the M4's budget, styles.css): a pushed page in from the
   right over the one it covers, which drifts a third left and dims; back is the same, reversed. */
@keyframes vt-push-in  { from { transform: translateX(100%); } }
@keyframes vt-push-out { to   { transform: translateX(-30%); opacity: .6; } }
@keyframes vt-pop-out  { to   { transform: translateX(100%); } }
@keyframes vt-pop-in   { from { transform: translateX(-30%); opacity: .6; } }
::view-transition-old(root) { animation: vt-push-out 320ms cubic-bezier(.32,.72,0,1) both; }
::view-transition-new(root) { animation: vt-push-in 320ms cubic-bezier(.32,.72,0,1) both; box-shadow: -8px 0 24px rgba(0,0,0,.18); }
html:active-view-transition-type(back)::view-transition-old(root) { animation-name: vt-pop-out; z-index: 1; box-shadow: -8px 0 24px rgba(0,0,0,.18); }
html:active-view-transition-type(back)::view-transition-new(root) { animation-name: vt-pop-in; box-shadow: none; }
/* Now Playing rises over the page as a sheet and sinks back (musicapp-v17); the page under it settles back a touch. */
@keyframes vt-up-in    { from { transform: translateY(100%); } }
@keyframes vt-up-under { to   { transform: scale(.94); opacity: .7; } }
@keyframes vt-down-out { to   { transform: translateY(100%); } }
@keyframes vt-down-in  { from { transform: scale(.94); opacity: .7; } }
html:active-view-transition-type(up)::view-transition-old(root)   { animation: vt-up-under 380ms cubic-bezier(.32,.72,0,1) both; box-shadow: none; }
html:active-view-transition-type(up)::view-transition-new(root)   { animation: vt-up-in 380ms cubic-bezier(.32,.72,0,1) both; z-index: 1; box-shadow: 0 -8px 30px rgba(0,0,0,.25); border-radius: 12px 12px 0 0; }
html:active-view-transition-type(down)::view-transition-old(root) { animation: vt-down-out 320ms cubic-bezier(.32,.72,0,1) both; z-index: 1; box-shadow: 0 -8px 30px rgba(0,0,0,.25); border-radius: 12px 12px 0 0; }
html:active-view-transition-type(down)::view-transition-new(root) { animation: vt-down-in 320ms cubic-bezier(.32,.72,0,1) both; box-shadow: none; }
/* Now Playing grows out of the mini player and shrinks back into it (musicapp-v26, read off the owner's recording of
   Apple Music). The sheet (.np) is a group of its own: its image pair is the CARD — an overflow-hidden box animated
   from the pill's rectangle to the whole screen in plain lengths (app.js route() measures them into --card-*; the
   iPhone's WebKit dropped a clip-path of calc()s) — and the picture inside zooms from CARD_S, pinned at the box's
   top-left; the card fades out into the pill at the end, and the reverse coming up. The page under, dock included,
   settles back as before (the dock is no group of its own here: iOS stacked it over the sheet whatever its z-index).
   The root's half that is only the sheet's page background is not shown. A sheet let go part-way down starts from
   where the finger left it (--drag-y, wireSwipe). With no mini player to come from, the sheet slides as before. */
.np { view-transition-name: np; }
html.vt-up .np-art, html.vt-up .np-small img { view-transition-name: none; }
/* what a late answer adds to a page fades in rather than appearing (app.js put/arrived; the owner, 2026-10-04) */
@keyframes late-in { from { opacity: 0; } }
#main [data-new], #foryou [data-new] { animation: late-in .3s ease-out both; }   /* going up, the cover grows with the card */
::view-transition-old(np), ::view-transition-new(np) { animation: none; }
html:active-view-transition-type(up)::view-transition-new(np)   { animation: vt-up-in 380ms cubic-bezier(.32,.72,0,1) both; border-radius: 12px 12px 0 0; box-shadow: 0 -8px 30px rgba(0,0,0,.25); }
html:active-view-transition-type(down)::view-transition-old(np) { animation: vt-down-out 320ms cubic-bezier(.32,.72,0,1) both; border-radius: 12px 12px 0 0; box-shadow: 0 -8px 30px rgba(0,0,0,.25); }
html:active-view-transition-type(up)::view-transition-new(root), html:active-view-transition-type(down)::view-transition-old(root) { display: none; }
/* Apple's sheet is a spring: most of the way in the first 100 ms, then a long settle. linear() samples one (Safari 17.2+,
   Chrome 113+); a browser without it falls back to the keyframes' default ease (still 500 ms). */
:root { --spring: 500ms linear(0, .27 8%, .52 16%, .71 24%, .84 32%, .92 42%, .965 54%, .99 70%, 1); }
@keyframes vt-box-in   { from { left: var(--card-x); top: var(--card-y); width: var(--card-w); height: var(--card-h); border-radius: var(--card-r); }
                         to   { left: 0px; top: 0px; width: var(--np-w); height: var(--np-h); border-radius: 0px; } }
@keyframes vt-box-out  { from { left: 0px; top: var(--drag-y, 0px); width: var(--np-w); height: var(--np-h); border-radius: var(--drag-r, 0px); }
                         to   { left: var(--card-x); top: var(--card-y); width: var(--card-w); height: var(--card-h); border-radius: var(--card-r); } }
@keyframes vt-zoom-in  { from { transform: scale(var(--card-s)); } to { transform: none; } }
@keyframes vt-zoom-out { from { transform: none; } to { transform: scale(var(--card-s)); } }
@keyframes vt-card-show { from { opacity: 0; } 15% { opacity: 1; } }
@keyframes vt-card-hide { 65% { opacity: 1; } to { opacity: 0; } }
html:active-view-transition-type(up):active-view-transition-type(card)::view-transition-image-pair(np) {
  inset: auto; overflow: hidden; animation: vt-box-in var(--spring) both, vt-card-show 500ms linear both; }
html:active-view-transition-type(up):active-view-transition-type(card)::view-transition-new(np) {
  transform-origin: 0 0; width: var(--np-w); height: var(--np-h); border-radius: 0; box-shadow: none;
  animation: vt-zoom-in var(--spring) both; }
html:active-view-transition-type(up):active-view-transition-type(card)::view-transition-old(root) { animation: vt-up-under var(--spring) both; }
html:active-view-transition-type(down):active-view-transition-type(card)::view-transition-image-pair(np) {
  inset: auto; overflow: hidden; animation: vt-box-out var(--spring) both, vt-card-hide 500ms linear both; }
html:active-view-transition-type(down):active-view-transition-type(card)::view-transition-old(np) {
  transform-origin: 0 0; width: var(--np-w); height: var(--np-h); border-radius: 0; box-shadow: none;
  animation: vt-zoom-out var(--spring) both; }
html:active-view-transition-type(down):active-view-transition-type(card)::view-transition-new(root) { animation: vt-down-in var(--spring) both; }
/* The cover that moves between pages: the hero into the mini player when music starts (type cover: the page stays
   still), the mini player's art into Now Playing's cover and back (with up/down) — the bigger picture is the one
   shown, the mini player's circle squaring off into the cover and back. */
::view-transition-group(cover) { animation-duration: 400ms; animation-timing-function: cubic-bezier(.32,.72,0,1); z-index: 3; }
html:active-view-transition-type(card)::view-transition-group(cover) { animation-duration: 500ms; animation-timing-function: linear(0, .27 8%, .52 16%, .71 24%, .84 32%, .92 42%, .965 54%, .99 70%, 1); }
::view-transition-old(cover), ::view-transition-new(cover) { animation: none; height: 100%; object-fit: cover; }
::view-transition-image-pair(cover) { isolation: auto; overflow: hidden; }
::view-transition-old(cover) { display: none; }
html:active-view-transition-type(down)::view-transition-old(cover) { display: block; }
html:active-view-transition-type(down)::view-transition-new(cover) { display: none; }
@keyframes vt-art-square { from { border-radius: 22px; } to { border-radius: 0px; } }
@keyframes vt-art-round  { from { border-radius: 0px; transform: translateY(var(--drag-y, 0px)); } to { border-radius: 22px; transform: none; } }
html:active-view-transition-type(up)::view-transition-image-pair(cover)   { animation: vt-art-square 400ms cubic-bezier(.32,.72,0,1) both; }
html:active-view-transition-type(down)::view-transition-image-pair(cover) { animation: vt-art-round var(--spring) both; }
.np-art, .np-small img { view-transition-name: cover; }
html:active-view-transition-type(cover)::view-transition-old(root) { animation: none; opacity: 0; box-shadow: none; }
html:active-view-transition-type(cover)::view-transition-new(root) { animation: none; box-shadow: none; }
/* A tab: no slide — a short crossfade, as the Music app's tabs change. */
@keyframes vt-fade-out { to { opacity: 0; } }
@keyframes vt-fade-in  { from { opacity: 0; } }
html:active-view-transition-type(tab)::view-transition-old(root) { animation: vt-fade-out 140ms ease-out both; box-shadow: none; }
html:active-view-transition-type(tab)::view-transition-new(root) { animation: vt-fade-in 140ms ease-in both; box-shadow: none; }
/* The mini player and the tab bar stay where they are while the page slides, as in iOS. */
.foot { view-transition-name: foot; }
::view-transition-group(foot), ::view-transition-new(foot) { animation: none; }
::view-transition-old(foot) { display: none; }

/* Numbers in the shelf's rounded face (the owner, 2026-10-03: "yes i do like that font") — on Music's own screens:
   Charts, the badge, Requests' count, Storage, Up Next's times. The Apple-copied pages keep Apple's. */
.num, .row.board .rk, .row.board .side, .youline, .me .badge { font-family: var(--font-num); font-style: normal; font-variant-numeric: tabular-nums; }

/* ♥ a favourite, • one of the album's most popular — in the page's margin, left of the number, as Apple Music. */
.song .mk { position: absolute; left: -17px; top: 50%; transform: translateY(-50%); color: var(--dim); display: flex; }
.song .mk.mk-fav svg { width: 11px; height: 11px; }
.song .mk.mk-dot { left: -14px; }
.song .mk.mk-dot svg { width: 6px; height: 6px; display: block; }

/* B (the owner, 2026-10-03, from screenshots): the myjp.ca lockup — the games' foot row (games/index.php), the
   wordmark in the rounded face, ".ca" dimmed, the app's name tucked under it in the app's colour — as the
   sign-in page's title and Account's. */
.lockup { display: inline-flex; flex-direction: column; align-items: flex-end; line-height: 1; font-family: var(--font-num); font-weight: 700; }
.lockup .lm { font-size: 30px; letter-spacing: -.01em; color: var(--ink); }
.lockup .lc { color: var(--dim); }
.lockup .ls { font-size: 13px; letter-spacing: .02em; color: var(--accent); margin: -1px 1px 0 0; }
.ptitle.lockup { margin: 6px 0 14px; }
/* the foot's "myjp.ca apps" row (musicapp-v42): the lockup on one line, mealapp's .lockrow */
.lockrow { font-family: var(--font-num); font-weight: 800; letter-spacing: -.02em; }
.lockrow .lc { color: var(--accent); }
.door h1.lockup .lm { font-size: 40px; }
.door h1.lockup .ls { font-size: 17px; }
