/* ============================================================
   music.css — styles for the music surfaces (music-v2 + library).

   Loaded by music-v2.html and library.html only. It defines NO tokens and
   overrides nothing in omni-tokens.css / omni-shell.css / styles.css — every
   value below reads a token that already exists, so the shell stays the single
   owner of the design system.

   All class names are prefixed mx- (shared render helpers) or scoped to a
   page-local block, so nothing here can reach markup outside these two pages.
   ============================================================ */

/* ---------- shared render primitives (music-render.js) ---------- */
.mx-art-slot { display: contents; }
.mx-art { display: block; width: 100%; height: 100%; object-fit: cover; }
.mx-ph { display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--violet); }
.mx-pill { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px;
  color: var(--text-3); background: var(--surface-2); border: 1px solid var(--line);
  padding: 3px 9px; border-radius: var(--r-pill); white-space: nowrap; }
.mx-pill.on { color: var(--violet-2); border-color: var(--violet); background: var(--violet-dim); }
.mx-artist-link { color: inherit; text-decoration: none; }
.mx-artist-link:hover { color: var(--text); text-decoration: underline; }
/* Artist icon + name as ONE routing target, so the avatar is not an inert decoration next to a
   working link. inline-flex keeps the avatar baseline-aligned with the name it belongs to. */
.track-artist-link { display: inline-flex; align-items: center; gap: 2px; color: inherit;
  text-decoration: none; max-width: 100%; min-width: 0; vertical-align: middle; }
.track-artist-link:hover { color: var(--text); text-decoration: underline; }
.track-artist-link:focus-visible { outline: 2px solid var(--violet); outline-offset: 2px; border-radius: var(--r-xs); }
@media (pointer: coarse) { .track-artist-link { min-height: 44px; } }
.mx-state { font-size: 14px; color: var(--text-3); text-align: center; padding: 38px 16px; }
.mx-state b { color: var(--text); display: block; margin-bottom: 6px; }
.mx-btn { font: inherit; cursor: pointer; }

/* ---------- toolbar: search + sort, above the genre chips ---------- */
.mx-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; }
/* 16px, not 14: iOS Safari zooms the viewport when a font-size < 16px input is focused, which
   leaves the visitor panned somewhere they did not ask to be. */
.mx-search {
  flex: 1 1 200px; min-width: 0; padding: 9px 12px; border-radius: var(--r-md);
  border: 1px solid var(--line-2); background: var(--surface-2); color: var(--text);
  font: inherit; font-size: 16px;
}
/* --text-3, never --text-4: omni-tokens.css marks --text-4 DECORATIVE ONLY (2.3:1) and forbids it
   for anything a user must read. This field has no visible label, so its placeholder is the only
   thing naming it. */
.mx-search::placeholder { color: var(--text-3); }
.mx-search:focus-visible { outline: none; border-color: var(--violet); box-shadow: 0 0 0 2px var(--violet-dim); }
.mx-sort {
  padding: 9px 12px; border-radius: var(--r-md); border: 1px solid var(--line-2);
  background: var(--surface-2); color: var(--text-2); font: inherit; font-size: 16px; cursor: pointer;
}
.mx-sort:focus-visible { outline: none; border-color: var(--violet); box-shadow: 0 0 0 2px var(--violet-dim); }
.mx-result { font-size: 12.5px; color: var(--text-3); flex-basis: 100%; }

/* ---------- resume bar: a hard reload restores paused; one tap continues ---------- */
.mx-resume {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; margin: 0 0 14px; border-radius: var(--r-md);
  background: var(--violet-dim); border: 1px solid var(--violet);
}
.mx-resume[hidden] { display: none; }
.mx-resume-text { flex: 1; min-width: 0; font-size: 13px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mx-resume-go {
  padding: 7px 14px; border-radius: var(--r-pill); border: 0; cursor: pointer;
  background: var(--violet); color: var(--brand-ink); font-weight: 700; font-size: 13px;
}
.mx-resume-x {
  padding: 7px 10px; border-radius: var(--r-pill); border: 1px solid var(--line-2);
  background: transparent; color: var(--text-3); cursor: pointer; font-size: 13px;
}

/* ---------- like control (card + detail) ---------- */
.mx-like {
  display: inline-flex; align-items: center; gap: 5px; padding: 5px 10px;
  border-radius: var(--r-pill); border: 1px solid var(--line-2); background: transparent;
  color: var(--text-3); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
  transition: color var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out),
              background var(--dur-2) var(--ease-out);
}
.mx-like:hover { color: var(--text); border-color: var(--line-hi); }
.mx-like[aria-pressed="true"] { color: var(--rose); border-color: var(--rose); background: var(--violet-dim); }
.mx-like:disabled { opacity: .5; cursor: default; }
.mx-like-n { font-variant-numeric: tabular-nums; font-weight: 600; }

/* ---------- track detail sheet ---------- */
.mx-overlay { position: fixed; inset: 0; z-index: var(--z-modal); display: flex;
  align-items: center; justify-content: center; padding: 16px; }
.mx-overlay[hidden] { display: none; }
.mx-scrim { position: absolute; inset: 0; background: var(--bg); opacity: .7; }
.mx-sheet {
  position: relative; width: min(94vw, 560px); max-height: 86vh; overflow: auto;
  display: flex; flex-direction: column; gap: 12px; padding: 16px;
  background: var(--surface); border: 1px solid var(--line-2);
  border-radius: var(--r-lg); box-shadow: var(--shadow-pop);
}
/* padding-right reserves the absolutely-positioned close button's gutter — without it a long
   title runs underneath a 44px tap target. */
.mx-sheet-head { display: flex; gap: 14px; align-items: flex-start; padding-right: 40px; }
.mx-sheet-art { flex: 0 0 116px; width: 116px; height: 116px; border-radius: var(--r-md);
  overflow: hidden; border: 1px solid var(--line); background: var(--surface-2); font-size: 34px; }
.mx-sheet-head-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
/* margin:0 — this is an <h2> (the page has no other heading), not a styled div. */
.mx-sheet-title { margin: 0; font-weight: 800; font-size: 19px; line-height: 1.2; color: var(--text); overflow-wrap: anywhere; }
.mx-sheet-artist { font-size: 13.5px; color: var(--text-2); }
.mx-sheet-meta { font-size: 12.5px; color: var(--text-3); overflow-wrap: anywhere; }
.mx-sheet-stats { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.mx-sheet-close {
  position: absolute; top: 10px; right: 10px; width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--line-2); background: var(--surface-2); color: var(--text-3);
  font-size: 15px; line-height: 1; cursor: pointer;
}
.mx-sheet-close:hover { color: var(--text); }
.mx-sheet-row { display: flex; align-items: center; gap: 10px; }
.mx-sheet-play {
  flex: 0 0 46px; width: 46px; height: 46px; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--violet); color: var(--brand-ink); font-size: 17px;
  display: flex; align-items: center; justify-content: center;
}
.mx-sheet-play:disabled { opacity: .5; cursor: default; }
.mx-sheet-wave { flex: 1; display: flex; align-items: flex-end; gap: 2px; height: 46px;
  cursor: pointer; outline: none; touch-action: none; }
.mx-sheet-wave i { flex: 1 1 0; min-width: 1px; background: var(--line-2); border-radius: 1px;
  transition: background var(--dur-1); }
.mx-sheet-wave i.played { background: var(--violet); }
.mx-sheet-wave:focus-visible { box-shadow: 0 0 0 2px var(--violet); border-radius: var(--r-xs); }
.mx-sheet-time { display: flex; justify-content: space-between; font-size: 11.5px;
  color: var(--text-3); font-variant-numeric: tabular-nums; }
.mx-sheet-acts { display: flex; gap: 8px; flex-wrap: wrap; }
.mx-sheet-acts > * { flex: 0 1 auto; }
/* --text-3, never --text-4: this line carries the memorial-receipt disclosure. It is the one
   sentence on the sheet that must be readable, and --text-4 is 2.3:1 decorative-only by contract. */
.mx-sheet-note { font-size: 12px; color: var(--text-3); border-top: 1px solid var(--line); padding-top: 10px; }

/* ---------- playlist art: one tile, or a 2×2 mosaic at four covers ----------
   Sized by the --mx-plart-size custom property so one rule serves the 44px chooser thumb and the
   56px library card. object-fit lives on the img (see .mx-plart-img) — the grid only frames it. */
.mx-plart {
  --mx-plart-size: 56px;
  flex: 0 0 var(--mx-plart-size); width: var(--mx-plart-size); height: var(--mx-plart-size);
  display: grid; grid-template-columns: 1fr; grid-template-rows: 1fr; gap: 1px;
  border-radius: var(--r-sm); overflow: hidden;
  background: var(--surface); border: 1px solid var(--line);
}
.mx-plart.quad { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
/* min-height:0 — a grid item defaults to min-content, which lets a tall image push the row past
   the track it was given and burst the fixed square. */
.mx-plart .mx-art-slot { display: block; min-width: 0; min-height: 0; overflow: hidden; }
.mx-plart-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.mx-plart-ph { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;
  background: var(--surface-2); color: var(--violet); font-size: calc(var(--mx-plart-size) * .4);
  line-height: 1; }

/* ---------- add-to-playlist chooser ---------- */
.mx-pl-list { display: flex; flex-direction: column; gap: 6px; max-height: 40vh; overflow: auto; }
.mx-pl-item {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 12px 8px 8px;
  border-radius: var(--r-md); border: 1px solid var(--line); background: var(--surface-2);
  color: var(--text); font: inherit; font-size: 14px; cursor: pointer; text-align: left;
  transition: border-color var(--dur-2) var(--ease-out), background var(--dur-2) var(--ease-out);
}
.mx-pl-item:hover { border-color: var(--line-hi); }
.mx-pl-item[aria-pressed="true"] { border-color: var(--violet); background: var(--violet-dim); }
.mx-pl-item:focus-visible { outline: 2px solid var(--violet); outline-offset: 2px; }
.mx-pl-item .mx-plart { --mx-plart-size: 44px; }
.mx-pl-mark { flex: 0 0 16px; color: var(--violet-2); font-weight: 700; text-align: center; }
/* The name and the meta line stack, so a long title truncates on its own row instead of
   squeezing the count and the Private badge off the end of a shared line. */
.mx-pl-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mx-pl-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 600; }
.mx-pl-sub { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.mx-pl-n { font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.mx-pl-status { min-height: 18px; font-size: 12.5px; color: var(--text-3); }
.mx-pl-status.err { color: var(--err); }
.mx-pl-status.ok { color: var(--ok); }

/* Create form — a titled block, not a bare input floating under a list. The label and the hint
   are what stop "New playlist" reading as a button someone forgot to wire up. */
.mx-pl-make { display: flex; flex-direction: column; gap: 8px; padding: 12px;
  border-radius: var(--r-md); border: 1px solid var(--line); background: var(--surface-2); }
.mx-pl-make-t { font-size: 13px; font-weight: 700; color: var(--text); }
.mx-pl-make-h { font-size: 12px; color: var(--text-3); }
.mx-pl-new { display: flex; gap: 8px; flex-wrap: wrap; }
.mx-pl-input {
  flex: 1 1 160px; min-width: 0; padding: 10px 12px; border-radius: var(--r-md);
  border: 1px solid var(--line-2); background: var(--surface); color: var(--text);
  font: inherit; font-size: 16px;   /* 16px floor: under it, iOS zooms the page on focus */
}
.mx-pl-input::placeholder { color: var(--text-3); }
.mx-pl-input:focus-visible { outline: none; border-color: var(--violet); box-shadow: 0 0 0 2px var(--violet-dim); }
.mx-pl-badge { font-size: 11px; color: var(--text-3); border: 1px solid var(--line);
  border-radius: var(--r-pill); padding: 1px 7px; }

/* ---------- clickable track title (opens the detail sheet) ---------- */
.mx-titlebtn {
  display: block; max-width: 100%; padding: 0; border: 0; background: none; color: inherit;
  font: inherit; text-align: left; cursor: pointer; border-radius: var(--r-xs);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mx-titlebtn:hover { color: var(--violet-2); }

/* ---------- queue row controls (music-v2 panel) ---------- */
.mx-qhit { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; padding: 0;
  border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.mx-qacts { display: flex; gap: 2px; flex: 0 0 auto; }
/* min-* rather than fixed: at 200% text-only zoom a fixed 26px box clips its own glyph. */
.mx-qact {
  min-width: 26px; min-height: 26px; padding: 4px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-xs); border: 1px solid transparent; background: transparent;
  color: var(--text-3); font-size: 12px; line-height: 1; cursor: pointer;
}
.mx-qact:hover { color: var(--text); border-color: var(--line-2); }
.mx-qact:disabled { opacity: .3; cursor: default; }
.mx-qfoot { padding: 8px 12px; border-top: 1px solid var(--line); font-size: 11.5px;
  color: var(--text-3); display: flex; justify-content: space-between; gap: 8px; }

/* ---------- library: playlists tab ---------- */
.mx-plrow { display: flex; align-items: center; gap: 12px; padding: 10px 12px; flex-wrap: wrap;
  border-radius: var(--r-md); background: var(--surface-2); border: 1px solid var(--line);
  transition: border-color var(--dur-2) var(--ease-out); }
.mx-plrow:hover { border-color: var(--line-hi); }
/* :focus-within, not :focus — the row is a container and the focus actually lands on the open
   button or one of the actions inside it. */
.mx-plrow:focus-within { border-color: var(--violet); }
/* The art is a sibling of the open button, not a child of it: nesting it would make the whole
   56px square part of the button's accessible name computation for no benefit. Clicking it still
   opens the playlist — it carries the same handler — but it is a non-focusable, aria-hidden div,
   so it adds a pointer shortcut without adding a second tab stop per row. See library.html. */
.mx-plrow-art { flex: 0 0 auto; cursor: pointer; line-height: 0; }
.mx-plrow-open { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start;
  gap: 3px; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left;
  cursor: pointer; border-radius: var(--r-xs); }
.mx-plrow-open:focus-visible { outline: 2px solid var(--violet); outline-offset: 3px; }
.mx-plrow-name { font-weight: 700; font-size: 14.5px; color: var(--text); max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mx-plrow-open:hover .mx-plrow-name { color: var(--violet-2); }
.mx-plrow-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 12px; color: var(--text-3); }
.mx-plrow-acts { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.mx-danger { color: var(--fail); border-color: var(--fail); }
.mx-ordered { display: flex; flex-direction: column; gap: 8px; }
.mx-ordrow { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--line); }
.mx-ordrow.now { border-color: var(--violet); background: var(--violet-dim); }
/* min-width, not a fixed basis: a three-digit position must not be clipped at text zoom. */
.mx-ordn { flex: 0 0 auto; min-width: 22px; text-align: right; font-size: 11.5px; color: var(--text-3);
  font-variant-numeric: tabular-nums; }
/* Smaller than the playlist card's tile: this row is a list item, not a card, and a 56px square
   beside two short text lines would out-measure the content it belongs to. */
.mx-ordart { --mx-plart-size: 40px; }
.mx-ordhit { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.mx-ordt { font-weight: 700; font-size: 13.5px; color: var(--text); max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mx-ords { font-size: 12px; color: var(--text-3); max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- touch + narrow viewports ---------- */
/* 44px is the floor, not 40. Every control on these pages is named here — the row-open
   buttons and the title button are two short text lines and land around 31px unaided, and the
   title button is the ONLY way into the track detail sheet. */
@media (pointer: coarse) {
  .mx-qact { min-width: 44px; min-height: 44px; }
  .mx-like, .mx-sort, .mx-search, .mx-resume-go, .mx-resume-x { min-height: 44px; }
  .mx-pl-item, .mx-pl-input, .mx-sheet-close { min-height: 44px; }
  .mx-sheet-close { width: 44px; }
  .mx-titlebtn, .mx-qhit, .mx-ordhit, .mx-plrow-open, .track-q { min-height: 44px; }
  .mx-titlebtn, .track-q { display: flex; align-items: center; }
  .mx-plrow-acts .btn-sm { min-height: 44px; }
}
@media (max-width: 560px) {
  /* Three action buttons out-measure the name column on a phone (~255px of buttons against 332px
     of row), squeezing a playlist title to ~67px. Give the name the whole row and let the actions
     take the line below. The art keeps its place BESIDE the name on that first line — a full-width
     cover would push the actions below the fold on a small phone. */
  .mx-plrow-open { flex: 1 1 auto; }
  .mx-plrow-art .mx-plart { --mx-plart-size: 48px; }
  .mx-plrow-acts { width: 100%; }
  .mx-plrow-acts > * { flex: 1 1 auto; }
  .mx-sheet-head { flex-direction: column; padding-right: 0; }
  .mx-sheet-art { width: 100%; height: 190px; flex: none; }
  /* Bottom-anchored on a phone, so the last action row would otherwise sit under the iPhone home
     indicator — same treatment the share sheet already uses. */
  .mx-sheet { width: 100%; max-height: 92vh; border-radius: var(--r-lg) var(--r-lg) 0 0;
    padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
  .mx-overlay { align-items: flex-end; padding: 0; }
  .mx-sheet-acts > * { flex: 1 1 44%; text-align: center; }
}
