/* songs.css — the full-screen Songs page (songs.js).
 *
 * Layout mirrors the desktop SongsPageView: a top bar (title + total +
 * sort, then source tabs + search), a left facet rail, and a virtualized
 * table whose rows are absolutely positioned inside a fixed-height
 * viewport so only the on-screen slice is ever in the DOM. Uses the shared
 * --jamn-* tokens (jam.css) so it themes with the rest of the app. */

#view-songs.view.active { display: flex; }
.songs-page {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: calc(100vh - 120px);
  min-height: 480px;
  color: var(--jamn-text, #fff);
}

/* ---- top bar ---- */
.songs-topbar {
  padding: 18px 24px 12px;
  border-bottom: 1px solid var(--jamn-border, #2A2A36);
  flex: 0 0 auto;
}
.songs-title-row { display: flex; align-items: baseline; gap: 12px; }
.songs-title { font-size: 1.7rem; font-weight: 800; margin: 0; }
.songs-total { font-variant-numeric: tabular-nums; color: var(--jamn-text2, #A1A1AA); font-size: 1rem; }
.songs-spacer { flex: 1 1 auto; }
.songs-sort { display: inline-flex; align-items: center; gap: 6px; }
.songs-sort-label { font-size: .8rem; color: var(--jamn-text2, #A1A1AA); }
.songs-sort-select {
  background: var(--jamn-surface1, #14141A);
  color: var(--jamn-text, #fff);
  border: 1px solid var(--jamn-border, #2A2A36);
  border-radius: var(--jamn-radius-sm, 8px);
  padding: 5px 8px; font-size: .85rem;
}

.songs-tabs-row { display: flex; align-items: center; gap: 16px; margin-top: 12px; flex-wrap: wrap; }
.songs-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.songs-tab {
  display: inline-flex; align-items: center; gap: 6px;
  background: transparent; border: 0; cursor: pointer;
  color: var(--jamn-text2, #A1A1AA);
  padding: 6px 12px; border-radius: var(--jamn-radius-sm, 8px);
  font: inherit; font-size: .9rem;
}
.songs-tab.is-active {
  background: color-mix(in srgb, var(--jamn-accent, #8B5CF6) 22%, transparent);
  color: #fff; font-weight: 600;
}
.songs-tab:disabled { cursor: default; color: rgba(255,255,255,.32); }
.songs-tab-soon {
  font-size: .62rem; font-weight: 700; letter-spacing: .04em;
  padding: 1px 5px; border-radius: 999px; background: rgba(255,255,255,.08);
}
.songs-search {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  background: var(--jamn-surface1, #14141A);
  border: 1px solid var(--jamn-border, #2A2A36);
  border-radius: var(--jamn-radius-sm, 8px);
  padding: 6px 10px;
}
.songs-search-icon { opacity: .6; font-size: .85rem; }
.songs-search-input {
  background: transparent; border: 0; outline: none; color: var(--jamn-text, #fff);
  font: inherit; font-size: .9rem; width: 220px;
}
.songs-search-input::placeholder { color: var(--jamn-text2, #A1A1AA); }
/* Active seed: "Matches for ‹title› ×" inside the search box. */
.songs-seed-chip {
  display: inline-flex; align-items: center; gap: 4px; max-width: 220px;
  padding: 2px 4px 2px 9px; border-radius: 999px; font-size: .8rem; white-space: nowrap;
  background: color-mix(in srgb, var(--jamn-accent, #8B5CF6) 26%, transparent);
  color: var(--jamn-text, #fff);
}
.songs-seed-chip-text { overflow: hidden; text-overflow: ellipsis; }
.songs-seed-chip-x {
  flex: 0 0 auto; width: 20px; height: 20px; border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(255,255,255,.12); color: inherit; font: inherit; line-height: 1; padding: 0;
}
.songs-seed-chip-x:hover { background: rgba(255,255,255,.24); }

/* "Match to" — seed picker beside the search box (Crate tab only). */
.songs-matchto { position: relative; display: none; }
.songs-matchto.is-shown { display: inline-block; }
.songs-matchto-btn.is-active { border-color: var(--jamn-accent, #8B5CF6); }
.songs-matchto-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  width: 280px; max-width: calc(100vw - 32px); box-sizing: border-box;
  display: flex; flex-direction: column; gap: 2px; padding: 6px;
  background: var(--jamn-surface2, #1C1C24);
  border: 1px solid var(--jamn-border, #2A2A36);
  border-radius: var(--jamn-radius-md, 12px);
  box-shadow: 0 12px 32px rgba(0,0,0,.45);
}
.songs-matchto-item {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; text-align: left;
  background: transparent; border: 0; border-radius: 8px; cursor: pointer;
  color: var(--jamn-text, #fff); font: inherit; padding: 8px 10px;
}
.songs-matchto-item:hover:not(:disabled) { background: rgba(255,255,255,.06); }
.songs-matchto-item:disabled { opacity: .45; cursor: default; }
.songs-matchto-item-label { font-size: .88rem; font-weight: 600; }
.songs-matchto-item-sub { font-size: .75rem; color: var(--jamn-text2, #A1A1AA); }
.songs-matchto-pick { display: flex; flex-direction: column; gap: 6px; padding: 6px 4px 2px; border-top: 1px solid var(--jamn-border, #2A2A36); }
.songs-matchto-search {
  background: var(--jamn-surface1, #14141A); color: var(--jamn-text, #fff);
  border: 1px solid var(--jamn-border, #2A2A36); border-radius: 7px;
  font: inherit; font-size: .85rem; padding: 6px 8px;
}
.songs-matchto-list { display: flex; flex-direction: column; max-height: 240px; overflow-y: auto; }
.songs-matchto-song {
  background: transparent; border: 0; border-radius: 6px; cursor: pointer; text-align: left;
  color: var(--jamn-text, #fff); font: inherit; font-size: .85rem; padding: 6px 8px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.songs-matchto-song:hover { background: rgba(255,255,255,.06); }
.songs-matchto-note { font-size: .8rem; color: var(--jamn-text2, #A1A1AA); padding: 6px 8px; }

/* "Rank by match to: ‹Title› …" typeahead strip above the table. */
.songs-seedchips {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 16px; border-bottom: 1px solid var(--jamn-border, #2A2A36);
}
.songs-seedchips-label { font-size: .8rem; color: var(--jamn-text2, #A1A1AA); }
.songs-seedchip {
  width: auto; flex: 0 1 auto; max-width: 240px; padding: 4px 12px; border-radius: 999px;
  background: rgba(255,255,255,.06); border: 1px solid var(--jamn-border, #2A2A36);
}
.songs-seedchip:hover { border-color: var(--jamn-accent, #8B5CF6); }
.songs-seedchip .songs-chip-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- body: rail + main ---- */
.songs-body { display: flex; flex: 1 1 auto; min-height: 0; }

.songs-rail {
  flex: 0 0 224px; width: 224px;
  border-right: 1px solid var(--jamn-border, #2A2A36);
  padding: 16px; overflow-y: auto;
  display: flex; flex-direction: column; gap: 18px;
}
.songs-facet { display: flex; flex-direction: column; gap: 7px; }
.songs-facet-head {
  font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--jamn-text2, #A1A1AA);
}
.songs-chip {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: transparent; border: 0; cursor: pointer; text-align: left;
  color: var(--jamn-text, #fff); font: inherit; font-size: .88rem;
  padding: 6px 10px; border-radius: 7px; width: 100%;
}
.songs-chip:hover { background: rgba(255,255,255,.05); }
.songs-chip.is-active {
  background: color-mix(in srgb, var(--jamn-accent, #8B5CF6) 22%, transparent);
  font-weight: 600;
}
.songs-chip-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.songs-chip-count { font-variant-numeric: tabular-nums; color: var(--jamn-text2, #A1A1AA); font-size: .78rem; }
.songs-tempo { display: flex; align-items: center; gap: 6px; }
.songs-tempo-input {
  width: 60px; background: var(--jamn-surface1, #14141A);
  border: 1px solid var(--jamn-border, #2A2A36);
  border-radius: 6px; color: var(--jamn-text, #fff); font: inherit;
  padding: 5px 8px; font-size: .85rem;
}
.songs-tempo-dash { color: var(--jamn-text2, #A1A1AA); }
.songs-clear {
  background: transparent; border: 0; cursor: pointer;
  color: var(--jamn-accent, #8B5CF6); font: inherit; font-size: .82rem;
  padding: 4px 0; text-align: left;
}

/* ---- main: table ---- */
.songs-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; position: relative; }
.songs-thead {
  display: grid; align-items: center;
  padding: 0 16px; height: 38px; flex: 0 0 auto;
  border-bottom: 1px solid var(--jamn-border, #2A2A36);
  background: var(--jamn-bg, #0B0B0F);
}
.songs-th {
  font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--jamn-text2, #A1A1AA);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.songs-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; position: relative; }
.songs-vport { position: relative; width: 100%; }

.songs-row {
  position: absolute; left: 0; right: 0;
  display: grid; align-items: center; gap: 0;
  padding: 0 16px; box-sizing: border-box;
  border-bottom: 1px solid color-mix(in srgb, var(--jamn-border, #2A2A36) 60%, transparent);
}
.songs-row:hover { background: rgba(255,255,255,.03); }
/* Ranked search (crate-ranked-search): rows FLIP to their new slot — songs.js
 * inverts each row with an inline transform, then clears it so this
 * transition glides it home (FLIP_MS in songs.js). Entering/leaving rows
 * fade through the opacity half. */
.songs-row { transition: transform 280ms ease-out, opacity 280ms ease-out; }
/* Rank, don't filter: non-matches stay listed (and clickable), dimmed under a divider. */
.songs-row--dim { opacity: .45; }
.songs-row--dim:hover { opacity: .8; }
/* A row that just left the virtual window, fading out — a picture only. */
.songs-row--ghost { pointer-events: none; }
.songs-divider {
  display: flex; align-items: flex-end; padding-bottom: 9px;
  border-bottom: 1px solid var(--jamn-border, #2A2A36);
}
.songs-divider:hover { background: transparent; }
.songs-divider-label {
  font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--jamn-text2, #A1A1AA);
}
/* Seed mode's per-row badge in the Status ("Match") column: "92% · Key". */
.songs-match {
  display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
  font-size: .78rem; font-weight: 600; font-variant-numeric: tabular-nums;
  padding: 2px 8px; border-radius: 999px;
  color: var(--jamn-text, #fff);
  background: color-mix(in srgb, var(--jamn-accent, #8B5CF6) 26%, transparent);
}
.songs-match--weak { background: rgba(255,255,255,.07); color: var(--jamn-text2, #A1A1AA); }
.songs-match--none { background: transparent; color: var(--jamn-text2, #A1A1AA); padding-left: 0; }
@media (prefers-reduced-motion: reduce) {
  .songs-row { transition: none; }
}
.songs-cell { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 8px; }
.songs-dim { color: var(--jamn-text2, #A1A1AA); }
.songs-num { font-variant-numeric: tabular-nums; }
.songs-cell-title { display: flex; align-items: center; gap: 10px; }
.songs-cell-title .jamn-art { flex: 0 0 auto; width: 32px; height: 32px; border-radius: 7px; }
/* Title stacks over an optional CC-attribution sub-line (crate rows); min-width:0 lets both ellipsis inside the flex cell. */
.songs-title-lines { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.songs-title-text { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.songs-attrib { font-size: .72rem; color: var(--jamn-text2, #A1A1AA); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.songs-cell-action { display: flex; align-items: center; gap: 8px; padding-right: 0; }

/* ---- song preview (songpreview.js): the artwork thumb is the button ----
 * The title cell must not clip: the 44 px hit area and the progress ring
 * reach outside the 32 px thumb. Its text still ellipsizes — the title and
 * attribution lines carry their own overflow:hidden. */
.songs-cell-title { overflow: visible; }
.songs-preview {
  position: relative; flex: 0 0 auto;
  width: 32px; height: 32px; padding: 0; margin: 0;
  border: 0; border-radius: 7px; background: transparent;
  color: #fff; font: inherit; line-height: 1; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* 44 px touch target (WCAG / Apple HIG) without growing the 56 px row. */
.songs-preview::before { content: ''; position: absolute; inset: -6px; }
.songs-preview .jamn-art { display: flex; transition: opacity .15s; }
.songs-preview:focus { outline: none; }
.songs-preview:focus-visible { outline: 2px solid var(--jamn-accent, #8B5CF6); outline-offset: 3px; }
/* ▶ / ❚❚ / ⚠ on a 45% scrim: hidden at rest, shown on row hover, keyboard
 * focus and in every non-idle state (so the active row is always marked). */
.songs-preview-glyph {
  position: absolute; inset: 0; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  border-radius: 7px; background: rgba(0, 0, 0, .45);
  font-size: 11px; pointer-events: none;
  opacity: 0; transition: opacity .12s;
}
.songs-row:hover .songs-preview-glyph,
.songs-preview:focus-visible .songs-preview-glyph,
.songs-preview:not([data-state="idle"]) .songs-preview-glyph { opacity: 1; }
/* ❚❚ is two glyphs — keep them from fusing into a block at 11 px. */
.songs-preview[data-state="playing"] .songs-preview-glyph { letter-spacing: 1px; text-indent: 1px; }
/* A ♪ placeholder (no artwork found) would muddle the glyph through the
 * scrim, so it steps aside whenever the full glyph shows; real art stays.
 * Hover only counts on real pointers — iOS keeps :hover stuck after a tap,
 * where the idle glyph is just the corner badge. */
.songs-preview:focus-visible .jamn-art--ph,
.songs-preview:not([data-state="idle"]) .jamn-art--ph { color: transparent; }
@media (hover: hover) {
  .songs-row:hover .songs-preview .jamn-art--ph { color: transparent; }
}
/* Progress ring: 2 px accent arc filling clockwise from 12 o'clock over a
 * faint track. --p (0..1) is written per frame by songpreview.js — a paint-
 * only custom property, so the ring never forces layout. */
.songs-preview-ring {
  position: absolute; inset: -4px; padding: 2px; border-radius: 10px;
  pointer-events: none; display: none;
  background: conic-gradient(var(--jamn-accent, #8B5CF6) calc(var(--p, 0) * 1turn),
                             rgba(255, 255, 255, .16) 0);
  /* Punch out the padding box's interior: what's left is the 2 px band. */
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
}
.songs-preview[data-state="playing"] .songs-preview-ring,
.songs-preview[data-state="paused"] .songs-preview-ring { display: block; }
/* Loading: a spinner in place of the glyph until audio is audible. */
.songs-preview[data-state="loading"] .songs-preview-glyph::after {
  content: ''; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .3); border-top-color: #fff;
  box-sizing: border-box; animation: songs-spin .8s linear infinite;
}
/* Failed: dimmed art + ⚠ until the next tap (retry) or stop. */
.songs-preview[data-state="failed"] .jamn-art { opacity: .4; }
.songs-preview[data-state="failed"] .songs-preview-glyph {
  background: rgba(0, 0, 0, .3); color: #F59E0B; font-size: 14px;
}
/* Touch: no hover, so idle rows always carry a small ▶ badge bottom-right. */
@media (hover: none) {
  .songs-preview[data-state="idle"] .songs-preview-glyph {
    opacity: 1; inset: auto -4px -4px auto; width: 16px; height: 16px;
    border-radius: 50%; background: rgba(0, 0, 0, .72); font-size: 8px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .songs-preview[data-state="loading"] .songs-preview-glyph::after { animation-duration: 2.4s; }
}

/* ---- status badge ---- */
.songs-badge { display: inline-flex; align-items: center; gap: 6px; font-size: .8rem; }
.songs-badge-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }
.songs-badge--done { color: var(--jamn-success, #22C55E); }
.songs-badge--running { color: var(--jamn-accent, #8B5CF6); }
.songs-badge--queued { color: #F59E0B; }
.songs-badge--error { color: var(--jamn-danger, #EF4444); }

/* ---- buttons ---- */
.songs-btn {
  background: var(--jamn-surface2, #1C1C24); color: var(--jamn-text, #fff);
  border: 1px solid var(--jamn-border, #2A2A36);
  border-radius: 7px; cursor: pointer; font: inherit; font-size: .82rem;
  padding: 5px 11px;
  /* Also used on an <a> (crate row "Source" link) — kill the anchor underline. */
  text-decoration: none;
}
.songs-btn:hover { border-color: var(--jamn-accent, #8B5CF6); }
.songs-btn--sm { padding: 4px 10px; }
.songs-btn--primary { background: var(--jamn-accent, #8B5CF6); border-color: transparent; color: #fff; font-weight: 600; }
/* Disabled applies to any variant now (crate "Borrow" is a disabled ghost when
 * no host song is loaded); keep the border steady so it doesn't light on hover. */
.songs-btn:disabled { opacity: .45; cursor: default; }
.songs-btn:disabled:hover { border-color: var(--jamn-border, #2A2A36); }
.songs-btn--primary:disabled { opacity: .45; cursor: default; }
.songs-btn--ghost { background: transparent; }
/* Compact icon-only action (crate row source ↗). */
.songs-btn--icon { padding: 4px 9px; font-weight: 600; }
.songs-action-progress { display: inline-flex; align-items: center; gap: 6px; color: var(--jamn-text2, #A1A1AA); }
.songs-pct { font-variant-numeric: tabular-nums; font-size: .8rem; }
.songs-spinner {
  width: 13px; height: 13px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.25); border-top-color: var(--jamn-accent, #8B5CF6);
  display: inline-block; animation: songs-spin .8s linear infinite;
}
@keyframes songs-spin { to { transform: rotate(360deg); } }

/* ---- footer + empty/loading overlay ---- */
.songs-footer {
  flex: 0 0 auto; display: flex; align-items: center; gap: 12px;
  padding: 10px 16px; border-top: 1px solid var(--jamn-border, #2A2A36);
  min-height: 20px;
}
.songs-error { color: var(--jamn-danger, #EF4444); font-size: .82rem; }
.songs-state { display: none; }
.songs-state.is-shown {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  position: absolute; inset: 38px 0 42px 0; pointer-events: none;
  color: var(--jamn-text2, #A1A1AA);
}
.songs-state-title { font-size: 1.1rem; font-weight: 700; color: var(--jamn-text, #fff); }
.songs-state-sub, .songs-state-msg { font-size: .9rem; }

@media (max-width: 760px) {
  .songs-rail { display: none; }
  .songs-search-input { width: 140px; }
}

/* Sidebar "Recent songs" header row + "View all" shortcut into this page
 * (the sidebar keeps a short recent list; Songs is the full destination). */
.jamn-side-label--row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.jamn-side-viewall {
  background: transparent; border: 0; cursor: pointer; padding: 0;
  color: var(--jamn-accent, #8B5CF6); font: inherit; font-size: .78rem; font-weight: 600;
}
.jamn-side-viewall:hover { text-decoration: underline; }

/* ---- Favourites tab (♥'d song + borrow combos) ---- */
.songs-page [hidden] { display: none !important; }
.songs-tab--fav span { letter-spacing: .01em; }
.songs-favs {
  flex: 1 1 auto; overflow-y: auto;
  padding: 20px 24px; display: flex; flex-direction: column; gap: 8px;
}
.songs-fav-row {
  display: flex; align-items: center; gap: 14px;
  padding: 10px 14px;
  background: var(--jamn-surface2, #1C1C24);
  border: 1px solid var(--jamn-border, #2A2A36);
  border-radius: var(--jamn-radius-md, 12px);
}
.songs-fav-heart { color: var(--jamn-accent, #8B5CF6); font-size: 1.05rem; }
.songs-fav-text { flex: 1 1 auto; min-width: 0; }
.songs-fav-title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.songs-fav-sub { font-size: .78rem; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.songs-favs-empty {
  margin: auto; max-width: 420px; text-align: center;
  display: flex; flex-direction: column; gap: 8px; align-items: center;
}
.songs-favs-heart { font-size: 2.2rem; color: var(--jamn-accent, #8B5CF6); }
.songs-favs-empty-title { font-weight: 700; }
@media (max-width: 520px) {
  .songs-favs { padding: 14px 16px; }
  .songs-fav-row { flex-wrap: wrap; }
}
