/* ============================================================
   The Lost Archives — Liquid Glass
   Token layer first; components reference tokens only.
   ============================================================ */

:root {
  /* --- neutral ramp (cool-neutral signature) --- */
  --raw-000:#FFFFFF; --raw-100:#F7F7F9; --raw-200:#EEEEF1; --raw-300:#E3E3E8;
  --raw-400:#C9C9D1; --raw-500:#AEAEB6; --raw-600:#6E6E76; --raw-700:#3A3A3F; --raw-800:#1C1C1E;

  /* --- semantic content surfaces (SOLID — no blur) --- */
  --color-bg-app:#EAEAEF;
  --color-bg-surface:#F7F7F9;
  --color-bg-overlay:#FFFFFF;
  --color-bg-inset:#E3E3E8;
  --color-bg-row-alt:#F1F1F4;

  /* --- text --- */
  --color-text-primary:#1C1C1E;
  --color-text-secondary:#6E6E76;
  --color-text-tertiary:#8E8E96;
  --color-text-disabled:#AEAEB6;
  --color-text-inverse:#FFFFFF;

  /* --- borders --- */
  --color-border:#C9C9D1;
  --color-border-strong:#AEAEB6;
  --color-border-subtle:#E3E3E8;

  /* --- accent (reserved) --- */
  --color-accent:#3D7CE0;
  --color-accent-hover:#6398EA;
  --color-accent-pressed:#2C5FB8;
  --color-accent-subtle:#E9F0FC;

  /* --- highlight (search-term mark) --- */
  --color-mark-bg:#FCE7B0;
  --color-mark-fg:#3A2E00;

  /* --- glass tiers --- */
  --glass-bg:rgba(255,255,255,0.42);
  --glass-bg-topbar:rgba(255,255,255,0.50);
  --glass-bg-faint:rgba(255,255,255,0.20);
  --glass-bg-strong:rgba(255,255,255,0.58);
  --glass-bg-subtle:rgba(255,255,255,0.80);
  --glass-bg-selected:rgba(255,255,255,0.52);
  --glass-bg-hover:rgba(255,255,255,0.72);
  --glass-border:rgba(255,255,255,0.6);
  --glass-blur:20px; --glass-blur-sm:9px; --glass-saturate:180%;
  --glass-highlight:inset 0 1px 0 rgba(255,255,255,0.55);
  --glass-shadow:0 10px 30px rgba(30,30,45,.14);
  --glass-shadow-sm:0 2px 10px rgba(30,30,45,.10);

  /* --- type --- */
  --font-ui:-apple-system,BlinkMacSystemFont,'Segoe UI',ui-sans-serif,system-ui,Roboto,Helvetica,Arial,sans-serif;
  --font-read:var(--font-ui);
  --w-regular:400; --w-medium:500; --w-semibold:600; --w-bold:700;

  /* --- spacing --- */
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px;
  --space-6:24px; --space-8:32px; --space-12:48px; --space-16:64px;

  /* --- radius --- */
  --radius-glass-sm:10px; --radius-glass-md:14px; --radius-glass-lg:18px; --radius-pill:9999px;

  /* --- motion --- */
  --dur-fast:80ms; --dur-default:150ms; --dur-slow:240ms; --dur-deliberate:360ms;
  --ease:cubic-bezier(.25,.10,.25,1);
  --ease-enter:cubic-bezier(0,0,.20,1);
  --ease-exit:cubic-bezier(.40,0,1,1);

  /* --- structure --- */
  --h-topbar:64px;
  --w-sidebar:264px;

  --ambient-splash:
    radial-gradient(circle at 14% 18%, #3B6FE0 0%, transparent 42%),
    radial-gradient(circle at 84% 12%, #C0563B 0%, transparent 38%),
    radial-gradient(circle at 72% 82%, #4FBE8B 0%, transparent 46%),
    radial-gradient(circle at 18% 88%, #7A5BD0 0%, transparent 40%);
}

@media (prefers-color-scheme: dark) {
  :root {
    --raw-000:#000000;
    --color-bg-app:#141417;
    --color-bg-surface:#1F1F23;
    --color-bg-overlay:#26262B;
    --color-bg-inset:#18181B;
    --color-bg-row-alt:#232327;

    --color-text-primary:#F2F2F5;
    --color-text-secondary:#A9A9B2;
    --color-text-tertiary:#86868E;
    --color-text-disabled:#5A5A62;
    --color-text-inverse:#FFFFFF;

    --color-border:#3A3A40;
    --color-border-strong:#4C4C54;
    --color-border-subtle:#2C2C31;

    --color-accent:#5A93EC;
    --color-accent-hover:#7BABF0;
    --color-accent-pressed:#3D7CE0;
    --color-accent-subtle:rgba(90,147,236,0.18);

    --color-mark-bg:rgba(252,210,80,0.30);
    --color-mark-fg:#F7E3A0;

    /* dark glass: dim translucent, elevate by lightness not shadow */
    --glass-bg:rgba(58,58,66,0.44);
    --glass-bg-topbar:rgba(60,60,68,0.54);
    --glass-bg-faint:rgba(52,52,60,0.30);
    --glass-bg-strong:rgba(64,64,72,0.62);
    --glass-bg-subtle:rgba(48,48,54,0.86);
    --glass-bg-selected:rgba(90,90,100,0.42);
    --glass-bg-hover:rgba(80,80,90,0.55);
    --glass-border:rgba(255,255,255,0.12);
    --glass-highlight:inset 0 1px 0 rgba(255,255,255,0.14);
    --glass-shadow:0 12px 34px rgba(0,0,0,.5);
    --glass-shadow-sm:0 2px 12px rgba(0,0,0,.4);

    --ambient-splash:
      radial-gradient(circle at 14% 18%, #2B4FA0 0%, transparent 42%),
      radial-gradient(circle at 84% 12%, #7A2E1F 0%, transparent 38%),
      radial-gradient(circle at 72% 82%, #1F6B4A 0%, transparent 46%),
      radial-gradient(circle at 18% 88%, #4A3585 0%, transparent 40%);
  }
}

* { box-sizing:border-box; }
/* hidden must win over the display:flex/grid class rules below */
[hidden] { display:none !important; }
html,body { height:100%; }
body {
  margin:0;
  font-family:var(--font-ui);
  font-size:14px;
  line-height:1.45;
  color:var(--color-text-primary);
  background:var(--color-bg-app);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

/* Ambient color field — required behind glass on a content-poor UI */
body::before {
  content:''; position:fixed; inset:-10%; z-index:0; pointer-events:none;
  background:var(--ambient-splash);
  filter:blur(80px) saturate(1.25);
  opacity:.85;
}
@media (prefers-color-scheme: dark) { body::before { opacity:.7; } }

/* ---- SF-symbol icon helper ---- */
.icon { display:inline-block; vertical-align:middle; fill:currentColor; flex:none; }

/* ---- boot / loading ---- */
.boot {
  position:fixed; inset:0; display:grid; place-items:center; z-index:10;
  color:var(--color-text-secondary); font-size:14px;
}
.boot.err { color:var(--color-critical,#C6303A); padding:0 24px; text-align:center; }

/* ============================================================
   Shell
   ============================================================ */
.app { position:relative; z-index:1; height:100vh; height:100dvh; display:flex; flex-direction:column; }

/* ---- Top bar (glass) ---- */
/* Fixed overlay so the content plane runs underneath it and the backdrop-filter
   has scrolling content to frost. */
.topbar {
  position:fixed; top:0; left:0; right:0; z-index:100;
  height:var(--h-topbar);
  display:flex; align-items:center; gap:var(--space-3);
  padding:0 var(--space-4);
  background:var(--glass-bg-topbar);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate)) brightness(1.02);
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate)) brightness(1.02);
  box-shadow:var(--glass-highlight), 0 1px 0 var(--color-border-subtle);
  border-bottom:1px solid var(--glass-border);
}
.brand { display:flex; align-items:center; gap:var(--space-3); min-width:0; }
.brand-mark {
  width:34px; height:34px; border-radius:var(--radius-glass-sm); flex:none;
  background:linear-gradient(150deg, var(--color-accent), #7A5BD0);
  box-shadow:var(--glass-highlight), var(--glass-shadow-sm);
  display:grid; place-items:center;
}
.brand-logo { width:20px; height:auto; fill:#fff; display:block; }
.brand-text { display:flex; flex-direction:column; line-height:1.1; min-width:0; }
.brand-title { font-size:15px; font-weight:var(--w-semibold); letter-spacing:-.01em; margin-bottom:2px; }
.brand-sub { font-size:11px; color:var(--color-text-secondary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* search field — pill glass */
.search {
  position:relative; margin-left:auto;
  display:flex; align-items:center; gap:var(--space-2);
  width:min(420px, 46vw);
  height:40px; padding:0 var(--space-3);
  border-radius:var(--radius-pill);
  background:var(--glass-bg-strong);
  backdrop-filter:blur(var(--glass-blur-sm)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter:blur(var(--glass-blur-sm)) saturate(var(--glass-saturate));
  border:1px solid var(--glass-border);
  box-shadow:var(--glass-highlight);
  transition:box-shadow var(--dur-default) var(--ease);
}
.search:focus-within { box-shadow:var(--glass-highlight), 0 0 0 3px var(--color-accent-subtle); }
.search-glyph { color:var(--color-text-secondary); display:flex; }
.search-input {
  flex:1; min-width:0; border:0; background:none; outline:none;
  font:inherit; font-size:14px; color:var(--color-text-primary);
}
.search-input::placeholder { color:var(--color-text-tertiary); }
.search-input::-webkit-search-cancel-button { -webkit-appearance:none; }

/* generic glass icon button */
.icon-btn {
  -webkit-appearance:none; appearance:none; border:0; cursor:pointer;
  display:grid; place-items:center; flex:none;
  width:32px; height:32px; border-radius:var(--radius-pill);
  background:transparent; color:var(--color-text-secondary);
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.icon-btn:hover { background:var(--glass-bg-hover); color:var(--color-text-primary); }
.icon-btn:active { transform:scale(.94); }
.search-clear { margin-right:-4px; }

.menu-btn { display:none; }

/* ============================================================
   Body split
   ============================================================ */
.body { flex:1; min-height:0; display:flex; }

/* ---- Sidebar (glass floating card) ---- */
.sidebar {
  flex:none; width:var(--w-sidebar);
  padding:calc(var(--h-topbar) + var(--space-4)) var(--space-3) var(--space-4) var(--space-4);
  overflow-y:auto; overscroll-behavior:contain;
}
.sidebar-inner {
  background:var(--glass-bg);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate)) brightness(1.03);
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate)) brightness(1.03);
  border:1px solid var(--glass-border);
  border-radius:var(--radius-glass-lg);
  box-shadow:var(--glass-highlight), var(--glass-shadow);
  padding:var(--space-2);
}
.facet-group { padding:var(--space-2) var(--space-1); }
.facet-group + .facet-group { border-top:1px solid var(--glass-border); }
.facet-head {
  width:100%; -webkit-appearance:none; appearance:none; border:0; background:none; cursor:pointer;
  display:flex; align-items:center; gap:var(--space-2);
  padding:var(--space-2); border-radius:var(--radius-glass-sm);
  color:var(--color-text-secondary); font-family:inherit;
}
.facet-head:hover { background:var(--glass-bg-hover); }
.facet-head .icon { color:var(--color-text-secondary); }
.facet-title {
  font-size:11px; font-weight:var(--w-semibold); text-transform:uppercase; letter-spacing:.06em;
  color:var(--color-text-header,var(--color-text-secondary));
}
.facet-count-badge {
  margin-left:auto; font-size:11px; color:var(--color-text-tertiary);
  font-variant-numeric:tabular-nums;
}
.facet-chev { margin-left:var(--space-2); color:var(--color-text-tertiary); }
.facet-group[data-open="false"] .facet-list { display:none; }
.facet-list { list-style:none; margin:var(--space-1) 0 0; padding:0; max-height:280px; overflow-y:auto; }
.facet-item {
  display:flex; align-items:center; gap:var(--space-2);
  width:100%; -webkit-appearance:none; appearance:none; border:0; background:none; cursor:pointer;
  padding:6px var(--space-2); border-radius:var(--radius-glass-sm);
  font-family:inherit; font-size:13px; color:var(--color-text-primary); text-align:left;
  transition:background var(--dur-fast) var(--ease);
}
.facet-item:hover { background:var(--glass-bg-hover); }
.facet-item[aria-pressed="true"] { background:var(--glass-bg-selected); font-weight:var(--w-medium); }
.facet-item[aria-pressed="true"] .facet-check { opacity:1; }
.facet-check { opacity:0; color:var(--color-accent); flex:none; }
.facet-name { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.facet-badge {
  flex:none; font-size:11px; color:var(--color-text-tertiary);
  font-variant-numeric:tabular-nums;
}
.facet-more {
  margin-top:var(--space-1); padding:6px var(--space-2); font-size:12px;
  color:var(--color-accent); background:none; border:0; cursor:pointer; font-family:inherit;
}
.facet-more:hover { text-decoration:underline; }

/* ---- search-bar filter suggestions ---- */
.suggest {
  position:absolute; z-index:300; left:0; right:0; top:calc(100% + 6px);
  max-height:min(60vh, 420px); overflow-y:auto; overscroll-behavior:contain;
  background:var(--color-bg-overlay);
  border:1px solid var(--color-border); border-radius:var(--radius-glass-md);
  box-shadow:var(--glass-shadow); padding:var(--space-1);
}
.suggest-group {
  display:flex; align-items:center; gap:6px; padding:6px var(--space-2) 2px;
  font-size:10px; font-weight:var(--w-semibold); text-transform:uppercase; letter-spacing:.06em;
  color:var(--color-text-tertiary);
}
.suggest-group .icon { color:var(--color-text-tertiary); }
.suggest-item {
  display:flex; align-items:center; gap:var(--space-2); width:100%;
  -webkit-appearance:none; appearance:none; border:0; background:none; cursor:pointer;
  padding:7px var(--space-2); border-radius:var(--radius-glass-sm);
  font-family:inherit; font-size:13px; color:var(--color-text-primary); text-align:left;
}
.suggest-item:hover, .suggest-item.active { background:var(--color-accent-subtle); }
.suggest-item.on { color:var(--color-accent-pressed); }
@media (prefers-color-scheme: dark){ .suggest-item.on { color:var(--color-accent-hover); } }
.si-name { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.si-on { color:var(--color-accent); display:flex; }
.si-count { flex:none; font-size:11px; color:var(--color-text-tertiary); font-variant-numeric:tabular-nums; }
.suggest-empty { padding:10px var(--space-2); font-size:13px; color:var(--color-text-secondary); }

/* ---- back to top ---- */
.to-top {
  position:fixed; right:24px; bottom:24px; z-index:150;
  width:44px; height:44px; border-radius:var(--radius-pill);
  -webkit-appearance:none; appearance:none; border:1px solid var(--glass-border); cursor:pointer;
  display:grid; place-items:center; color:var(--color-text-primary);
  background:var(--glass-bg-faint);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate));
  box-shadow:var(--glass-highlight), var(--glass-shadow-sm);
  transition:transform var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.to-top:hover { background:var(--glass-bg); transform:translateY(-2px); }
.to-top:active { transform:translateY(0); }

.scrim { display:none; }

/* ============================================================
   Content plane (solid)
   ============================================================ */
.content {
  flex:1; min-width:0; overflow-y:auto; outline:none;
  padding:calc(var(--h-topbar) + var(--space-4)) var(--space-6) var(--space-12);
}
.content-head {
  display:flex; align-items:center; gap:var(--space-3); flex-wrap:wrap;
  margin-bottom:var(--space-4);
}
.result-count { font-size:13px; color:var(--color-text-secondary); font-variant-numeric:tabular-nums; }
.result-count b { color:var(--color-text-primary); font-weight:var(--w-semibold); }
.active-filters { display:flex; gap:var(--space-2); flex-wrap:wrap; flex:1; min-width:0; }
.chip {
  display:inline-flex; align-items:center; gap:5px;
  padding:4px 6px 4px 8px; border-radius:var(--radius-pill);
  background:var(--color-accent-subtle); color:var(--color-accent-pressed);
  font-size:12px; font-weight:var(--w-medium);
}
.chip .icon { opacity:.8; }
.chip-val { white-space:nowrap; }
@media (prefers-color-scheme: dark){ .chip{ color:var(--color-accent-hover);} }
.chip-x {
  -webkit-appearance:none; appearance:none; border:0; background:none; cursor:pointer;
  display:grid; place-items:center; color:inherit; padding:2px; border-radius:var(--radius-pill);
}
.chip-x:hover { background:rgba(0,0,0,.08); }
.chip.clear-all { background:transparent; color:var(--color-text-secondary); padding-left:6px; }
.chip.clear-all:hover { color:var(--color-text-primary); text-decoration:underline; }

.sort { margin-left:auto; display:flex; align-items:center; gap:var(--space-2); }
.sort-label { font-size:12px; color:var(--color-text-secondary); }
.select-wrap { position:relative; display:inline-flex; align-items:center; }
.select {
  -webkit-appearance:none; appearance:none; cursor:pointer; font-family:inherit;
  font-size:13px; color:var(--color-text-primary);
  padding:7px 28px 7px 12px; border-radius:var(--radius-pill);
  background:var(--glass-bg-strong);
  backdrop-filter:blur(var(--glass-blur-sm)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter:blur(var(--glass-blur-sm)) saturate(var(--glass-saturate));
  border:1px solid var(--glass-border); box-shadow:var(--glass-highlight);
}
.select:focus-visible { outline:none; box-shadow:var(--glass-highlight),0 0 0 3px var(--color-accent-subtle); }
.select-chev { position:absolute; right:10px; pointer-events:none; color:var(--color-text-secondary); display:flex; }

/* ---- results ---- */
.results { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--space-3); }
.card {
  --_pad:var(--space-4);
  position:relative; display:flex; gap:var(--space-4);
  text-align:left; width:100%; cursor:pointer; font-family:inherit;
  -webkit-appearance:none; appearance:none;
  background:var(--color-bg-surface);
  border:1px solid var(--color-border-subtle);
  border-radius:var(--radius-glass-md);
  padding:var(--_pad);
  box-shadow:var(--glass-shadow-sm);
  transition:transform var(--dur-fast) var(--ease), box-shadow var(--dur-default) var(--ease), border-color var(--dur-default) var(--ease);
}
.card:hover { border-color:var(--color-border); box-shadow:var(--glass-shadow); transform:translateY(-1px); }
.card:focus-visible { outline:none; border-color:var(--color-accent); box-shadow:0 0 0 3px var(--color-accent-subtle); }
.card:active { transform:translateY(0); }
.card-body { min-width:0; flex:1; }

/* card cover thumbnail — concentric with the card's own radius. This wrapper is
   ALWAYS the fixed-size box; its one child (real <img> or the placeholder tile)
   always fills it 100%, so the two can never collide over sizing. */
.card-thumb {
  /* Width AND height are set explicitly in px by JS (syncThumbSize in app.js), as a
     square matching .card-body's real rendered height -- NOT flex align-self:stretch
     (three stretch-based CSS approaches all produced wrong, timing-dependent heights
     on a genuine cold load, reproduced across engines -- see git history). Square,
     not just tall, so object-fit:cover on our square 300x300 source assets shows the
     complete image with no cropping. 130px here is only the pre-JS fallback. */
  position:relative; flex:none; width:130px; height:130px;
  border-radius:var(--radius-glass-sm);
  overflow:hidden; background:var(--color-bg-inset);
}
.cover-img { position:absolute; inset:0; display:block; width:100%; height:100%; object-fit:cover; }

/* small badge on the thumb signaling a listen link (Apple Music/Bandcamp) exists
   inside -- and now itself playable: click it to open the floating mini-player
   without opening the review. -webkit-appearance reset since this is a real
   <button> (needed for keyboard/AT access), not just a decorative span. */
.listen-badge {
  -webkit-appearance:none; appearance:none; border:0; cursor:pointer; padding:0; font:inherit;
  position:absolute; right:6px; bottom:6px; z-index:1;
  width:20px; height:20px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:rgba(0,0,0,.55); color:#fff;
  backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px);
  box-shadow:0 1px 3px rgba(0,0,0,.35);
  transition:transform var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.listen-badge:hover { background:var(--color-accent); transform:scale(1.08); }
.listen-badge:focus-visible { outline:none; box-shadow:0 0 0 3px var(--color-accent-subtle); }
/* Phosphor's play triangle sits slightly right-of-center in its own square
   viewBox (apex points right) -- nudge left to optically center in the circle.
   Recalibrated for this glyph; the old offset was tuned for the previous
   (SF Symbols) triangle's different geometry and was wrong for this one. */
.listen-badge .icon { position:relative; left:-0.5px; pointer-events:none; }

/* ---- floating mini-player: play straight from the list, no sheet needed ---- */
.float-player {
  position:fixed; left:var(--space-4); bottom:var(--space-4); z-index:60;
  width:min(375px, calc(100vw - var(--space-4) * 2));
  background:var(--glass-bg-subtle);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border-radius:var(--radius-glass-lg);
  /* No border anywhere in this rule -- the hard edge you'll still see is Apple's/
     Bandcamp's own iframe content (a solid white card, their UI, not ours) meeting
     the page background; we can't restyle cross-origin content. Bleeding the body
     to the container's own edges (see .float-player-body) at least means there's
     only ONE edge instead of two (container border + iframe border) stacked. */
  box-shadow:0 20px 50px rgba(20,20,40,.4), 0 4px 16px rgba(0,0,0,.25), 0 0 32px rgba(120,140,255,.14);
  padding:var(--space-3);
  animation:float-player-in var(--dur-default) var(--ease-enter);
}
@keyframes float-player-in { from { opacity:0; transform:translateY(12px); } to { opacity:1; transform:translateY(0); } }
.float-player-close {
  position:absolute; top:-10px; right:-10px; z-index:1;
  width:26px; height:26px; border-radius:50%; border:1px solid var(--color-border);
  display:flex; align-items:center; justify-content:center;
  background:var(--color-bg-surface); color:var(--color-text-secondary);
  box-shadow:var(--glass-shadow-sm); cursor:pointer;
  -webkit-appearance:none; appearance:none;
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.float-player-close:hover { background:var(--color-accent-subtle); color:var(--color-accent); }
/* Bleed the embed to the container's own edges (cancel the parent's padding
   on all sides) and match its corner radius, so the iframe's own edge lines
   up with the glass panel's edge instead of floating inside it with a
   visible gap all the way round. */
.float-player-body {
  margin:calc(var(--space-3) * -1);
  border-radius:var(--radius-glass-lg);
  overflow:hidden;
}
.float-player-body .bc-embed { display:block; }
.float-player-body .am-embed, .float-player-body .bc-embed-lg { max-width:100%; border-radius:0; }
.bc-embed-lg { display:block; width:100%; height:450px; border:0; } /* matches .am-embed's 375x450 footprint */
@media (max-width:560px) {
  .float-player { left:var(--space-2); right:var(--space-2); bottom:var(--space-2); width:auto; }
}

/* seeded placeholder tile — never real/fake art, just a deterministic color+initials mark */
.cover-ph {
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  background:linear-gradient(var(--ph-angle, 135deg), var(--ph-a), var(--ph-b));
}
.cover-ph span {
  color:#fff; font-weight:var(--w-semibold); letter-spacing:.02em;
  text-shadow:0 1px 3px rgba(0,0,0,.35);
  font-size:15px;
}
.sheet-thumb .cover-ph span { font-size:72px; }

.card-head { display:flex; align-items:baseline; gap:var(--space-2); flex-wrap:wrap; }
.card-artist { font-size:16px; font-weight:var(--w-semibold); letter-spacing:-.01em; color:var(--color-text-primary); }
.card-album { font-size:15px; color:var(--color-text-secondary); font-style:italic; }
.card-album.unknown { font-style:normal; color:var(--color-text-tertiary); }
.card-meta {
  display:flex; align-items:center; gap:var(--space-3); flex-wrap:wrap;
  margin-top:6px; font-size:12px; color:var(--color-text-secondary);
}
.card-meta .mi { display:inline-flex; align-items:center; gap:5px; }
.card-meta .mi .icon { color:var(--color-text-tertiary); }
/* clickable label / issue on cards */
.mi-link {
  -webkit-appearance:none; appearance:none; border:0; background:none; cursor:pointer;
  font:inherit; font-size:12px; color:var(--color-text-secondary);
  display:inline-flex; align-items:center; gap:5px;
  padding:2px 7px; margin:-2px -3px; border-radius:var(--radius-pill);
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.mi-link .icon { color:var(--color-text-tertiary); }
.mi-link:hover { background:var(--color-accent-subtle); color:var(--color-accent-pressed); }
.mi-link:hover .icon { color:var(--color-accent); }
.mi-link:focus-visible { outline:none; background:var(--color-accent-subtle); box-shadow:0 0 0 2px var(--color-accent-subtle); }
@media (prefers-color-scheme: dark){ .mi-link:hover, .mi-link:focus-visible { color:var(--color-accent-hover); } }
.card-snippet {
  margin-top:var(--space-3); font-size:13px; line-height:1.55; color:var(--color-text-secondary);
  overflow:hidden; max-height:calc(1.55em * 2); /* JS trims to whole words + ellipsis; this is the no-JS cap */
}
.card-tags { display:flex; gap:6px; flex-wrap:wrap; margin-top:var(--space-3); }
.tag-pill {
  font-size:11px; font-weight:var(--w-medium); color:var(--color-text-secondary);
  background:var(--color-bg-inset); border-radius:var(--radius-pill); padding:2px 9px;
}
/* clickable genre pills (cards + sheet) */
.tag-link {
  -webkit-appearance:none; appearance:none; border:0; cursor:pointer; font-family:inherit;
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.tag-link:hover { background:var(--color-accent-subtle); color:var(--color-accent-pressed); }
.tag-link:focus-visible { outline:none; box-shadow:0 0 0 2px var(--color-accent-subtle); }
@media (prefers-color-scheme: dark){ .tag-link:hover { color:var(--color-accent-hover); } }
mark { background:var(--color-mark-bg); color:var(--color-mark-fg); border-radius:3px; padding:0 1px; }

.empty { text-align:center; padding:var(--space-16) var(--space-4); color:var(--color-text-secondary); }
.empty h3 { color:var(--color-text-primary); font-size:16px; margin:0 0 6px; }

/* ============================================================
   Reading sheet
   ============================================================ */
.sheet-overlay { position:fixed; inset:0; z-index:300; display:flex; justify-content:center; }
.sheet-scrim {
  position:absolute; inset:0; background:rgba(20,20,30,.42);
  backdrop-filter:blur(2px); -webkit-backdrop-filter:blur(2px);
  animation:fade var(--dur-default) var(--ease);
}
.sheet {
  position:relative; margin:clamp(16px,4vh,56px) var(--space-4); align-self:flex-start;
  width:min(760px, 100%); max-height:calc(100dvh - clamp(32px,8vh,112px));
  display:flex; flex-direction:column;
  background:var(--color-bg-overlay); color:var(--color-text-primary);
  border:1px solid var(--color-border-subtle);
  border-radius:var(--radius-glass-lg);
  box-shadow:0 24px 60px rgba(20,20,40,.32);
  overflow:hidden; outline:none;
  animation:sheet-in var(--dur-slow) var(--ease-enter);
}
.sheet-chrome {
  position:sticky; top:0; z-index:2; flex:none;
  display:flex; align-items:center; gap:var(--space-2);
  padding:var(--space-3) var(--space-3) var(--space-3) var(--space-4);
  background:var(--glass-bg-subtle);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border-bottom:1px solid var(--color-border-subtle);
  box-shadow:var(--glass-highlight);
}
.sheet-chrome .src { font-size:12px; color:var(--color-text-secondary); font-weight:var(--w-medium); }
.sheet-close { margin-left:auto; }
.sheet-body { overflow-y:auto; padding:var(--space-6) clamp(20px,5vw,44px) var(--space-12); }
.sheet-head { display:flex; align-items:flex-start; gap:var(--space-4); }
.sheet-thumb {
  /* shown at the pipeline's native thumbnail size -- 300px, not further downscaled.
     position:relative -- containing block for the absolutely-positioned .cover-img/
     .cover-ph child (see .card-thumb for why they're positioned, not height:100%). */
  position:relative; flex:none; width:300px; height:300px; border-radius:var(--radius-glass-lg);
  overflow:hidden; background:var(--color-bg-inset); box-shadow:var(--glass-shadow-sm);
}
/* flex:1 so this reliably fills the width beside the fixed 300px art -- without
   it the column only sizes to its own content and the header player would have
   no predictable width to work with */
.sheet-head-text { min-width:0; flex:1; padding-top:6px; }
.sheet-artist { font-size:26px; font-weight:var(--w-bold); letter-spacing:-.02em; line-height:1.15; margin:0; }
.sheet-album { font-size:19px; color:var(--color-text-secondary); font-style:italic; margin:4px 0 0; }
.sheet-album.unknown { font-style:normal; }
.listen-links { display:flex; align-items:center; gap:var(--space-2); margin-top:var(--space-3); flex-wrap:wrap; }

/* Compact Bandcamp player, header-only -- sits in the ~200px of headroom below
   the title/album before this column would grow taller than the 300px art next
   to it. Bandcamp's embed is responsive width (250-700px per their own docs) but
   NOT graceful below ~250px, so this only appears where .sheet-head is a row
   (>560px -- see the mobile breakpoint) and the column has real width to give it. */
.header-player { margin-top:var(--space-3); }
.bc-embed { display:block; width:100%; height:120px; border:0; } /* Bandcamp's own content is square-cornered -- rounding the iframe just clips it oddly */
.listen-link {
  display:inline-flex; align-items:center; gap:6px;
  padding:7px 14px; border-radius:var(--radius-pill);
  font-size:13px; font-weight:var(--w-medium); text-decoration:none;
  color:var(--color-accent); border:1px solid var(--color-accent);
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.listen-link .icon { color:currentColor; }
.listen-link:hover { background:var(--color-accent); color:var(--color-text-inverse); }
.listen-link:focus-visible { outline:none; box-shadow:0 0 0 3px var(--color-accent-subtle); }

/* Sits after the review text (see renderSheet) -- deliberately not near the top,
   so it never displaces the thing people actually opened the sheet to read. */
.player-dock { margin-top:var(--space-6); }
.am-embed {
  display:block; width:100%; max-width:375px; height:450px; border:0;
  border-radius:var(--radius-glass-md); overflow:hidden;
}
.sheet-facts {
  display:flex; flex-wrap:wrap; gap:var(--space-2);
  margin:var(--space-4) 0; padding:var(--space-3) 0;
  border-top:1px solid var(--color-border-subtle); border-bottom:1px solid var(--color-border-subtle);
  font-size:13px; color:var(--color-text-secondary);
}
.sheet-fact { display:inline-flex; align-items:center; gap:6px; }
.sheet-fact .icon { color:var(--color-text-tertiary); }
.sheet-fact b { color:var(--color-text-primary); font-weight:var(--w-medium); }
.sheet-fact .link { cursor:pointer; color:var(--color-accent); }
.sheet-fact .link:hover { text-decoration:underline; }
/* icon-only external links (Apple Music / Bandcamp) in the same facts row */
.sheet-fact-icon {
  display:inline-flex; align-items:center; color:var(--color-text-tertiary);
  transition:color var(--dur-fast) var(--ease);
}
.sheet-fact-icon:hover { color:var(--color-accent); }
.sheet-tags { display:flex; gap:6px; flex-wrap:wrap; margin:0 0 var(--space-6); }
.sheet-tags .tag-pill { cursor:pointer; }
.sheet-tags .tag-pill:hover { background:var(--color-accent-subtle); color:var(--color-accent-pressed); }
.sheet-review { font-size:16px; line-height:1.72; color:var(--color-text-primary); max-width:66ch; }
.sheet-review p { margin:0 0 1.1em; }
.sheet-byline { margin-top:var(--space-8); padding-top:var(--space-4); border-top:1px solid var(--color-border-subtle);
  font-size:13px; color:var(--color-text-secondary); }

/* ============================================================
   Motion / a11y
   ============================================================ */
@keyframes fade { from{opacity:0} to{opacity:1} }
@keyframes sheet-in { from{opacity:0; transform:translateY(12px) scale(.99)} to{opacity:1; transform:none} }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration:.001ms !important; transition-duration:.001ms !important; }
  .card:hover { transform:none; }
}

/* solid fallback when backdrop-filter unsupported */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .topbar, .search, .sidebar-inner, .select, .sheet-chrome { background:var(--color-bg-surface); }
  .topbar { background:var(--color-bg-surface); }
}

/* ============================================================
   Responsive — substitution, not reflow
   ============================================================ */
@media (max-width: 900px) {
  :root { --w-sidebar:288px; }
  .menu-btn { display:grid; }
  .brand-sub { display:none; }
  .search { width:min(320px,52vw); }
  .sidebar {
    position:fixed; top:var(--h-topbar); bottom:0; left:0; z-index:200;
    width:var(--w-sidebar); padding:var(--space-3);
    transform:translateX(-108%); transition:transform var(--dur-slow) var(--ease);
  }
  .sidebar.open { transform:none; box-shadow:var(--glass-shadow); }
  .scrim {
    display:block; position:fixed; inset:var(--h-topbar) 0 0 0; z-index:150;
    background:rgba(20,20,30,.35); animation:fade var(--dur-default) var(--ease);
  }
  .content { padding:calc(var(--h-topbar) + var(--space-4)) var(--space-4) var(--space-12); }
}
@media (max-width: 560px) {
  .topbar { gap:var(--space-2); padding:0 var(--space-3); }
  .brand-text { display:none; }
  .search { width:auto; flex:1; }
  .card-album { font-size:14px; }
  .sheet { margin:0; max-height:100dvh; height:100dvh; border-radius:0; border:0; }
  .sheet-overlay { }
  /* a 300px hero doesn't comfortably fit beside text at phone widths -- stack it */
  .sheet-head { flex-direction:column; }
  .sheet-thumb { width:min(300px, 100%); height:auto; aspect-ratio:1/1; }
  .sheet-head-text { padding-top:0; }
}

/* ============================================================
   About / kindred sites / wanted issues / contact
   Reuses .sheet-overlay + .sheet wholesale (see index.html); everything
   below styles only the panel's own body content.
   ============================================================ */
.about-body { padding-top:var(--space-4); }
/* The chrome's title, and the panel's only one (the redundant in-body <h1> is
   gone). Qualified with .about-sheet to outrank `.sheet-chrome .src`.
   flex:none so the title claims only its own width — the free space then falls
   to .about-nav's auto margin below, which carries the pills and the X to the
   right together. */
.about-sheet .sheet-chrome .about-src {
  flex:none; margin:0; white-space:nowrap;
  font-size:15px; font-weight:var(--w-semibold); letter-spacing:-.01em;
  color:var(--color-text-primary);
}

.about-chrome { gap:var(--space-3); }

/* Section jump bar — docked in the chrome beside the title, so it never
   overlaps body content and needs no sticky positioning of its own.
   nowrap: this row is a fixed budget, and the icon-only fallback below is
   what absorbs narrow widths. Wrapping would silently grow the chrome. */
.about-nav { display:flex; gap:6px; flex-wrap:nowrap; min-width:0; margin-left:auto; }
/* The auto margin now lives on the nav, which puts the free space between the
   title and the pills. .sheet-close's own margin-left:auto has to be cancelled
   here or the two autos would split the gap between them and float the pills
   into the middle — the X sits flush against the pills at the right instead. */
.about-sheet .sheet-close { margin-left:0; }
.about-nav-item {
  -webkit-appearance:none; appearance:none; cursor:pointer;
  display:inline-flex; align-items:center; gap:5px; white-space:nowrap;
  padding:5px 10px; border-radius:var(--radius-pill);
  border:1px solid var(--color-border-subtle); background:var(--color-bg-surface);
  font:inherit; font-size:12px; font-weight:var(--w-medium); color:var(--color-text-secondary);
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.about-nav-item:hover { background:var(--color-bg-inset); color:var(--color-text-primary); }
.about-nav-item .icon { color:var(--color-text-tertiary); }

.about-section { padding-bottom:var(--space-8); }
.about-section + .about-section { border-top:1px solid var(--color-border-subtle); padding-top:var(--space-8); }
.about-section p { font-size:15px; line-height:1.65; margin:0 0 var(--space-4); }
.about-lede { font-size:17px !important; line-height:1.6 !important; color:var(--color-text-primary); }
.about-h {
  display:flex; align-items:center; gap:var(--space-2);
  font-size:19px; font-weight:var(--w-semibold); letter-spacing:-.01em; margin:0 0 var(--space-3);
}
.about-h .icon { color:var(--color-text-tertiary); }
.about-muted { color:var(--color-text-secondary); font-size:13px !important; }

/* ---- kindred sites ---- */
.site-list { display:grid; gap:var(--space-3); }
.site-card {
  display:block; padding:var(--space-4); text-decoration:none;
  border:1px solid var(--color-border-subtle); border-radius:var(--radius-glass-md);
  background:var(--color-bg-surface);
  transition:background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.site-card:hover { background:var(--color-bg-inset); border-color:var(--color-border); }
.site-name {
  display:flex; align-items:center; gap:6px;
  font-size:15px; font-weight:var(--w-semibold); color:var(--color-accent); margin-bottom:4px;
}
.site-note { display:block; font-size:13px; line-height:1.55; color:var(--color-text-secondary); }

/* ---- wanted issues ---- */
.pub-grid { display:grid; gap:var(--space-3); margin-bottom:var(--space-4); }
.pub {
  padding:var(--space-4);
  border:1px solid var(--color-border-subtle); border-radius:var(--radius-glass-md);
  background:var(--color-bg-surface);
}
.pub-head { display:flex; align-items:baseline; gap:var(--space-3); flex-wrap:wrap; }
.pub-name { font-size:15px; font-weight:var(--w-semibold); margin:0; }
.pub-stat { font-size:12px; color:var(--color-text-tertiary); }
.pub-range { font-size:13px !important; color:var(--color-text-secondary); margin:2px 0 var(--space-3) !important; }
.pub-missing { font-size:12px !important; font-weight:var(--w-medium); color:var(--color-text-secondary); margin:0 0 6px !important; }
.pub-gaps { display:flex; gap:6px; flex-wrap:wrap; }
.gap-chip {
  display:inline-block; padding:3px 9px; border-radius:var(--radius-pill);
  background:var(--color-mark-bg); color:var(--color-mark-fg);
  font-size:12px; font-weight:var(--w-medium); font-variant-numeric:tabular-nums;
}
.pub-complete { display:flex; align-items:center; gap:6px; font-size:13px !important; color:var(--color-text-tertiary); margin:0 !important; }

/* ---- contact form ---- */
.contact-form { display:grid; gap:var(--space-4); max-width:520px; }
.field-row { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-3); }
.field { display:grid; gap:6px; }
.field > span { font-size:13px; font-weight:var(--w-medium); color:var(--color-text-secondary); }
.field input, .field textarea {
  font:inherit; font-size:14px; color:var(--color-text-primary);
  padding:10px var(--space-3); border-radius:var(--radius-glass-sm);
  border:1px solid var(--color-border); background:var(--color-bg-overlay);
  outline:none; transition:box-shadow var(--dur-default) var(--ease), border-color var(--dur-default) var(--ease);
}
.field textarea { resize:vertical; line-height:1.55; }
.field input:focus, .field textarea:focus {
  border-color:var(--color-accent); box-shadow:0 0 0 3px var(--color-accent-subtle);
}
.form-actions { display:flex; align-items:center; gap:var(--space-3); flex-wrap:wrap; }
.btn-primary {
  -webkit-appearance:none; appearance:none; border:0; cursor:pointer;
  padding:10px var(--space-6); border-radius:var(--radius-pill);
  background:var(--color-accent); color:var(--color-text-inverse);
  font:inherit; font-size:14px; font-weight:var(--w-semibold);
  transition:background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.btn-primary:hover:not(:disabled) { background:var(--color-accent-hover); }
.btn-primary:active:not(:disabled) { transform:scale(.97); }
.btn-primary:disabled { opacity:.55; cursor:default; }
.form-status { font-size:13px; color:var(--color-text-secondary); }
.form-status.is-error { color:#C0563B; }
.form-thanks { display:flex; align-items:center; gap:var(--space-2); font-size:15px; color:var(--color-text-primary); margin:0; }

.about-footer {
  margin-top:var(--space-8); padding-top:var(--space-4);
  border-top:1px solid var(--color-border-subtle);
  font-size:12px; line-height:1.6; color:var(--color-text-tertiary);
}

@media (prefers-color-scheme: dark) {
  .site-name { color:var(--color-accent-hover); }
  .form-status.is-error { color:#E08A70; }
}
/* Below this the four labelled pills can't share the row with the title, so
   they go icon-only rather than wrapping the chrome onto a second line. The
   name survives in each button's title/aria-label. Matches the 900px sidebar
   breakpoint already used above rather than inventing a nearby one. */
@media (max-width: 900px) {
  .about-nav-item span { display:none; }
  .about-nav-item { padding:6px; }
}
@media (max-width: 560px) {
  .field-row { grid-template-columns:1fr; }
}

/* ============================================================
   Phone result cards
   Six discrete lines -- artist, album, label, issue, date, tags -- each on its
   own line, truncating with an ellipsis rather than wrapping. The artwork is
   sized to that block.

   One knob: --_thumb. It sets the artwork square AND the minimum body height,
   so the two stay locked together and every card in the list is identical --
   which is the whole point. Wrapping content was what produced two different
   artwork sizes before, since syncThumbHeights() matched each thumb to its own
   card's height.
   ============================================================ */
@media (max-width: 560px) {
  .card { --_thumb:124px; gap:var(--space-3); --_pad:var(--space-3); align-items:flex-start; }

  /* !important because syncThumbHeights() writes inline px at wider viewports;
     without it a stale inline value survives a rotate and wins over this. */
  .card-thumb { width:var(--_thumb) !important; height:var(--_thumb) !important; }

  /* Cards missing a label or tags would otherwise be shorter than the rest and
     break the alignment this whole block exists to guarantee. */
  .card-body { min-height:var(--_thumb); }

  /* The review preview goes entirely -- two lines of low-information text
     pushing the next card off screen. */
  .card-snippet { display:none; }

  /* Artist and album stop sharing a line. */
  .card-head { flex-direction:column; align-items:stretch; gap:0; }
  .card-artist { font-size:15px; line-height:1.4; }
  .card-album  { font-size:14px; line-height:1.4; }

  /* Label, issue and date each get their own line. .card-meta stops being a
     flex row; each item stays flex internally so its icon sits beside its
     text, and the ellipsis lives on the inner <span> -- text-overflow does
     nothing on a flex container itself. */
  .card-meta { display:block; margin-top:3px; font-size:12px; }
  .card-meta .mi {
    display:flex; align-items:center; gap:5px;
    max-width:100%; margin:0; padding:1px 0; line-height:1.45;
  }
  .card-meta .mi .icon { flex:none; }
  .card-meta .mi > span {
    min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }

  /* Tags: one line. Block rather than flex so the ellipsis works, with the
     pills riding inline. */
  .card-tags {
    display:block; margin-top:5px; max-width:100%;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .card-tags .tag-pill { vertical-align:middle; margin-right:5px; }

  .card-artist, .card-album {
    display:block; max-width:100%;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }

  /* The listen badge is a signal here, not a control -- it says "there is
     something to hear" and the tap belongs to the card underneath, which opens
     the review. Playback lives in the review sheet; a floating player hovering
     over a list is the wrong shape on a phone.
     pointer-events:none also kills the hover/active states, which would
     otherwise advertise it as tappable. */
  .listen-badge { pointer-events:none; }
}
