@import './tokens.css';

/*
 * Vinyl collection tracker.
 *
 * Built on the shared tokens, and on the same skeleton as the jaarruimte
 * tracker — .wrap, .masthead, .wordmark, .nav, .btn, .badge all behave the
 * same, so the two read as siblings.
 *
 * Where it departs: this is a showcase, not a tool. The dark ground is doing
 * gallery-wall duty, so covers get the space and the chrome gets out of the
 * way — no card borders competing with sleeve art, metadata set quiet and
 * small beneath it, and the accent used sparingly enough that the artwork is
 * the only colourful thing on the page.
 */

/* ---- Reset ---- */
*,
*::before,
*::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; }

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, picture, svg { display: block; max-width: 100%; height: auto; }

/*
 * [hidden] must beat the display rules below it. The UA stylesheet sets
 * `display: none` for it, but any author `display:` on the same element wins —
 * so `.grid[hidden]` stayed visible and the wall/shelf switch did nothing.
 */
[hidden] { display: none !important; }

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--leading-tight);
  text-wrap: balance;
}
p { text-wrap: pretty; }

a { color: var(--color-accent); text-decoration: none; }
a:hover { color: var(--color-accent-hover); text-decoration: underline; }

::selection { background-color: var(--color-accent); color: var(--color-bg); }

:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
  border-radius: var(--radius);
}

::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: var(--color-bg); }
::-webkit-scrollbar-thumb { background: var(--color-muted); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--color-accent); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: var(--space-2); top: -4rem;
  background: var(--color-accent); color: var(--color-bg);
  padding: var(--space-1) var(--space-3);
  z-index: 100; transition: top var(--transition);
}
.skip-link:focus { top: var(--space-2); text-decoration: none; }

/* ---- Layout ---- */
.wrap {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--space-3);
}
@media (min-width: 48rem) {
  .wrap { padding-inline: var(--space-6); }
}
.wrap--narrow { max-width: 34rem; }

main { flex: 1 0 auto; padding-block: var(--space-8) var(--space-16); }

/* ---- Masthead ---- */
.masthead {
  border-bottom: 1px solid var(--color-border);
  background: var(--color-bg-sunken);
  position: sticky;
  top: 0;
  z-index: 10;
}
.masthead__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding-block: var(--space-2);
}

.wordmark {
  font-family: var(--font-heading-alt);
  font-size: var(--text-lg);
  letter-spacing: var(--tracking-wide);
  color: var(--color-text);
  text-decoration: none;
  white-space: nowrap;
}
.wordmark:hover { color: var(--color-text); text-decoration: none; }
.wordmark::after {
  content: '';
  display: block;
  width: 2.25rem;
  height: 1px;
  margin-top: 3px;
  background: var(--color-accent);
}

.nav { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); margin-inline-start: auto; }
.nav a {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  padding-block: var(--space-1);
  border-bottom: 1px solid transparent;
  transition: color var(--transition), border-color var(--transition);
}
.nav a:hover { color: var(--color-text); text-decoration: none; }
.nav a[aria-current='page'] { color: var(--color-accent); border-bottom-color: var(--color-accent); }

.nav .count {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  margin-inline-start: 2px;
}
.nav a[aria-current='page'] .count { color: var(--color-accent); }

.masthead__actions { display: flex; align-items: center; gap: var(--space-2); }
.form-inline { display: inline; }

/* ---- Buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: transparent;
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.btn:hover {
  background: var(--color-accent-dim);
  border-color: var(--color-accent);
  color: var(--color-text);
  text-decoration: none;
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn--primary {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-bg);
  font-weight: 500;
}
.btn--primary:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); color: var(--color-bg); }

.btn--quiet { border-color: transparent; color: var(--color-text-muted); }
.btn--quiet:hover { color: var(--color-text); background: transparent; border-color: var(--color-border); }

.btn--danger { border-color: var(--color-border); color: var(--color-danger); }
.btn--danger:hover { background: var(--color-danger-dim); border-color: var(--color-danger); color: var(--color-danger); }

.btn--small { padding: 2px var(--space-1); font-size: var(--text-xs); }

/* ---- Page head ---- */
.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-6);
  border-bottom: 1px solid var(--color-border);
}
.page-head h1 { font-size: var(--text-3xl); }
.page-head__sub {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  margin-top: var(--space-1);
}
.page-head__actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-accent);
  margin-bottom: var(--space-1);
}

/* ---- Search ---- */
.search { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-6); }
.search input[type='search'] { min-width: 15rem; flex: 1 1 15rem; }
.search select { flex: 0 0 auto; }

.result-count {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-faint);
  margin-bottom: var(--space-3);
}

.breadcrumb { margin-bottom: var(--space-4); font-size: var(--text-sm); }
.breadcrumb a {
  color: var(--color-text-muted);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  font-size: var(--text-xs);
}
.breadcrumb a:hover { color: var(--color-accent); }

/* ---- The wall ---- */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--space-6) var(--space-4);
}

/* On a phone the 11rem minimum plus the gap just exceeds the viewport, so
   auto-fill drops to one enormous tile per row. A smaller track and a tighter
   column gap keep it at two. */
@media (max-width: 30rem) {
  .grid {
    grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
    gap: var(--space-4) var(--space-2);
  }
  .record__title { font-size: var(--text-base); }
}

.record { position: relative; }
.record__link { display: block; color: inherit; text-decoration: none; }
.record__link:hover { color: inherit; text-decoration: none; }

/*
 * The sleeve. A real record leans into the light, so the hover state lifts it
 * a touch and throws the shadow further, rather than tinting or bordering it —
 * anything drawn on top of cover art is competing with the artwork.
 */
.record__sleeve {
  position: relative;
  aspect-ratio: 1;
  background: var(--color-bg-raised);
  overflow: hidden;
  /* box-sizing is border-box throughout, so this takes its pixel from the
     inside: the tiles keep their size and the grid does not shift. */
  border: 1px solid var(--cover-edge);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  transition: transform var(--transition), box-shadow var(--transition);
}
.record__sleeve img { width: 100%; height: 100%; object-fit: cover; }

.record__link:hover .record__sleeve,
.record__link:focus-visible .record__sleeve {
  transform: translateY(-3px);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.7);
}

/* A hairline of accent along the bottom edge on hover: enough to show the tile
   is live without putting colour over the artwork. */
.record__sleeve::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 2px;
  background: var(--color-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--transition);
}
.record__link:hover .record__sleeve::after,
.record__link:focus-visible .record__sleeve::after { transform: scaleX(1); }

/* Missing cover: a record, drawn in chrome tones so it reads as an absence
   rather than as art. */
.sleeve-empty {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  background:
    radial-gradient(circle at 50% 50%, var(--color-bg-sunken) 0 22%, transparent 22%),
    repeating-radial-gradient(circle at 50% 50%, var(--color-muted) 0 1px, transparent 1px 4px),
    var(--color-bg-raised);
}
.sleeve-empty__label {
  width: 30%; aspect-ratio: 1; border-radius: 50%;
  background: var(--color-accent-dim);
  border: 1px solid var(--color-accent-line);
  display: grid; place-items: center;
}
.sleeve-empty__label::after {
  content: '';
  width: 12%; aspect-ratio: 1; border-radius: 50%;
  background: var(--color-bg);
}

.record__meta { padding-top: var(--space-2); }
.record__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  line-height: 1.25;
  color: var(--color-text);
}
.record__artist {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin-top: 1px;
}
.record__line {
  margin-top: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  display: flex; flex-wrap: wrap; gap: 0 var(--space-1);
}
.record__line span:not(:last-child)::after { content: ' ·'; }

/* ---- Detail ---- */
.detail {
  display: grid;
  grid-template-columns: minmax(0, 24rem) minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}
/* minmax(0, 1fr), not 1fr: a bare "1fr" is minmax(auto, 1fr), so the widest
   min-content in the column — a table, a long title — becomes a floor the
   viewport cannot push below, and the whole page scrolls sideways. */
@media (max-width: 52rem) {
  .detail { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
}

.detail__sleeve {
  aspect-ratio: 1;
  background: var(--color-bg-raised);
  border: 1px solid var(--cover-edge);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
  overflow: hidden;
}
.detail__sleeve img { width: 100%; height: 100%; object-fit: cover; }

.detail h1 { font-size: var(--text-3xl); margin-block: var(--space-1) var(--space-1); }
.detail__artist {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  color: var(--color-text-muted);
  margin-bottom: var(--space-6);
}

.detail__meta {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-2) var(--space-6);
  padding-block: var(--space-4);
  border-block: 1px solid var(--color-border);
}
.detail__meta dt {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-faint);
}
.detail__meta dd { font-size: var(--text-sm); }

.detail__notes { margin-top: var(--space-6); max-width: var(--measure); }
.detail__notes h2 {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-faint);
  margin-bottom: var(--space-1);
}
.detail__notes p { white-space: pre-wrap; color: var(--color-text-muted); }
.detail__actions { margin-top: var(--space-6); display: flex; gap: var(--space-2); flex-wrap: wrap; }

/* ---- Badges ---- */
.badge {
  display: inline-block;
  padding: 2px var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.badge--owned { color: var(--color-positive); border-color: rgba(143, 191, 138, 0.35); }
.badge--wishlist { color: var(--color-accent); border-color: var(--color-accent-line); }

/* ---- Panels & forms ---- */
.panel {
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-6);
  margin-bottom: var(--space-6);
}
.panel--center { text-align: center; }
.panel--danger { border-color: rgba(224, 132, 114, 0.35); }
.panel h1 { font-size: var(--text-2xl); }
.panel h2 { font-size: var(--text-xl); margin-bottom: var(--space-1); }
.panel__sub { color: var(--color-text-muted); font-size: var(--text-sm); margin-bottom: var(--space-4); }

.error-code {
  font-family: var(--font-display);
  font-size: var(--text-4xl);
  color: var(--color-text-faint);
  line-height: 1;
}

.empty {
  text-align: center;
  padding-block: var(--space-16);
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
}
.empty p { margin-bottom: var(--space-3); }

.field { margin-bottom: var(--space-4); border: 0; padding: 0; min-width: 0; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
@media (max-width: 34rem) { .field-row { grid-template-columns: 1fr; } }

.field label, .field legend {
  display: block;
  margin-bottom: var(--space-1);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.field__hint { font-size: var(--text-xs); color: var(--color-text-faint); margin-top: 2px; }
.required { color: var(--color-danger); }

input[type='text'], input[type='search'], input[type='password'],
input[type='url'], input[type='file'], select, textarea {
  width: 100%;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg-sunken);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  transition: border-color var(--transition);
}
input:focus, select:focus, textarea:focus { border-color: var(--color-accent); }
textarea { resize: vertical; line-height: var(--leading-normal); }
input::placeholder, textarea::placeholder { color: var(--color-text-faint); }

.radio {
  display: inline-flex; align-items: center; gap: var(--space-1);
  margin-inline-end: var(--space-4);
  font-size: var(--text-sm); text-transform: none; letter-spacing: normal;
  color: var(--color-text);
}
.radio input { width: auto; }

.form__actions { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; margin-top: var(--space-6); }

.alert {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-left: 2px solid var(--color-text-muted);
  border-radius: var(--radius);
  background: var(--color-bg-sunken);
  font-size: var(--text-sm);
  margin-bottom: var(--space-4);
}
.alert--error { border-left-color: var(--color-danger); color: var(--color-danger); background: var(--color-danger-dim); }
.alert--success { border-left-color: var(--color-positive); color: var(--color-positive); }

.details { margin-bottom: var(--space-4); font-size: var(--text-sm); color: var(--color-text-muted); }
.details summary {
  cursor: pointer;
  color: var(--color-text);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  margin-bottom: var(--space-2);
}
.details ul { margin: 0 0 var(--space-2); padding-inline-start: var(--space-3); }
.details code { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-accent); }

/* ---- Table ---- */
.table-wrap { overflow-x: auto; border: 1px solid var(--color-border); border-radius: var(--radius); }
.table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.table th, .table td {
  padding: var(--space-1) var(--space-2);
  text-align: left;
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}
.table th {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-faint);
  background: var(--color-bg-sunken);
  font-weight: 400;
}
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--color-bg-raised); }
.table__art img {
  width: 2.5rem; height: 2.5rem; object-fit: cover;
  border: 1px solid var(--cover-edge);
}
.table__art--empty {
  width: 2.5rem; height: 2.5rem;
  display: grid; place-items: center;
  background: var(--color-bg-sunken);
  color: var(--color-muted);
}
.table__actions { display: flex; gap: var(--space-1); flex-wrap: wrap; }
.table .badge { margin: 0; }

/* ---- Cover management ---- */
.cover-manage { display: grid; grid-template-columns: 11rem 1fr; gap: var(--space-6); align-items: start; }
@media (max-width: 40rem) { .cover-manage { grid-template-columns: 1fr; } }
.cover-manage__preview img {
  width: 100%; aspect-ratio: 1; object-fit: cover;
  border: 1px solid var(--cover-edge);
}
.cover-manage__empty {
  aspect-ratio: 1; display: grid; place-items: center;
  background: var(--color-bg-sunken); color: var(--color-text-faint);
  font-size: var(--text-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase;
}
.cover-manage__controls { display: flex; flex-direction: column; gap: var(--space-4); }
.cover-manage__controls .form { padding-top: var(--space-4); border-top: 1px solid var(--color-border); }
.cover-manage__controls .field { margin-bottom: var(--space-2); }

/* ---- Import ---- */
.summary { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-4); }
.summary__item {
  flex: 1 1 7rem;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg-sunken);
}
.summary__value { display: block; font-family: var(--font-display); font-size: var(--text-2xl); line-height: 1; }
.summary__label {
  font-size: var(--text-xs); letter-spacing: var(--tracking-wide);
  text-transform: uppercase; color: var(--color-text-faint);
}

.preview-list { max-height: 20rem; overflow-y: auto; margin-bottom: var(--space-4); }
.preview-list h3 {
  position: sticky; top: 0;
  background: var(--color-bg-raised);
  font-family: var(--font-body);
  font-size: var(--text-xs); letter-spacing: var(--tracking-wider);
  text-transform: uppercase; color: var(--color-text-faint);
  padding-block: var(--space-1);
}
.preview-list ul { margin: 0; padding-inline-start: var(--space-3); font-size: var(--text-sm); }
.preview-list li { margin-bottom: 2px; }
.preview-list .problem { color: var(--color-danger); }
.preview-list .skipped { color: var(--color-text-faint); }

/* ---- Footer ---- */
.site-footer {
  flex-shrink: 0;
  border-top: 1px solid var(--color-border);
  background: var(--color-bg-sunken);
  padding-block: var(--space-6);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
}
.site-footer__inner { display: flex; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.site-footer a { color: var(--color-text-muted); }
.site-footer__meta { letter-spacing: var(--tracking-wide); }

/* ==========================================================================
   The shelf
   ==========================================================================
   Records stored the way they actually live: upright, spine out, in runs by
   artist. The sleeve art is cropped to a sliver down the spine, which is very
   nearly what the edge of a real sleeve looks like.
   -------------------------------------------------------------------------- */

.viewswitch { display: inline-flex; }
.viewswitch .btn { border-radius: 0; }
.viewswitch .btn:first-child { border-start-start-radius: var(--radius); border-end-start-radius: var(--radius); }
.viewswitch .btn:last-child { margin-inline-start: -1px; border-start-end-radius: var(--radius); border-end-end-radius: var(--radius); }
.viewswitch .btn[aria-pressed='true'] {
  background: var(--color-accent-dim);
  border-color: var(--color-accent);
  color: var(--color-text);
}

.shelf__rail {
  display: flex;
  align-items: flex-end;
  gap: var(--space-4);
  overflow-x: auto;
  padding: var(--space-6) var(--space-2) 0;
  /* The shelf board itself. */
  border-bottom: 3px solid var(--color-border-strong);
  box-shadow: 0 6px 12px -6px rgba(0, 0, 0, 0.8);
  scrollbar-width: thin;
}

.shelf__run { display: flex; align-items: flex-end; }
/* Records by one artist sit flush; the gap between runs is the grouping. No
   label under each run - it truncated to two characters on short runs, and
   every spine already prints the artist. */
.shelf__run + .shelf__run { margin-inline-start: var(--space-3); }

/* A spine. Leaning very slightly, as a shelf that is not quite full does. */
.spine {
  position: relative;
  flex: 0 0 auto;
  width: 2.25rem;
  height: 13rem;
  padding: 0;
  border: 0;
  border-inline: 1px solid rgba(0, 0, 0, 0.55);
  border-block-start: 1px solid var(--cover-edge);
  background: var(--color-bg-raised);
  cursor: pointer;
  overflow: hidden;
  transform-origin: bottom center;
  transition: transform var(--transition), box-shadow var(--transition), filter var(--transition);
}
.spine + .spine { margin-inline-start: -1px; }

.spine__face { position: absolute; inset: 0; }
.spine__face img,
.spine__face .sleeve-empty {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Show the left edge of the sleeve, as if looking at it side-on. */
  object-position: left center;
  filter: brightness(0.62) saturate(0.85);
  transition: filter var(--transition);
}

/* The printed spine text, running bottom-to-top like every record sleeve. */
.spine__text {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2);
  padding-block: var(--space-2);
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  background: linear-gradient(to right, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.35));
  text-align: start;
}
.spine__title {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-height: 60%;
}
.spine__artist {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-height: 34%;
}

.spine:hover,
.spine:focus-visible { transform: translateY(-0.9rem); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.6); }
.spine:hover .spine__face img { filter: brightness(0.9) saturate(1); }

/* The one currently pulled out. */
.spine[aria-expanded='true'] {
  transform: translateY(-1.6rem) rotate(-3deg);
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.7);
}
.spine[aria-expanded='true'] .spine__face img { filter: none; }
.spine[aria-expanded='true']::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 2px;
  background: var(--color-accent);
}

.shelf__hint {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-faint);
}

/* The record pulled off the shelf. */
.shelf__detail { margin-top: var(--space-6); }
.shelf__card {
  display: grid;
  grid-template-columns: 10rem minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-inline-start: 2px solid var(--color-accent);
  background: var(--color-bg-raised);
  animation: pull-out 220ms ease both;
}
@media (max-width: 40rem) { .shelf__card { grid-template-columns: 1fr; } }

@keyframes pull-out {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.shelf__card-sleeve {
  aspect-ratio: 1;
  overflow: hidden;
  border: 1px solid var(--cover-edge);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.6);
}
.shelf__card-sleeve img { width: 100%; height: 100%; object-fit: cover; }
.shelf__card h3 { font-size: var(--text-2xl); }
.shelf__card .record__artist { font-size: var(--text-base); margin-bottom: var(--space-2); }

/* ==========================================================================
   The turntable
   ========================================================================== */

.deck {
  display: grid;
  grid-template-columns: minmax(0, 26rem) minmax(0, 1fr);
  gap: var(--space-8);
  align-items: center;
}
@media (max-width: 52rem) { .deck { grid-template-columns: 1fr; gap: var(--space-6); } }

.deck__plinth {
  position: relative;
  aspect-ratio: 1;
  padding: var(--space-4);
  background:
    linear-gradient(145deg, var(--color-bg-raised), var(--color-bg-sunken));
  border: 1px solid var(--color-border);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.65);
}

.deck__brand {
  position: absolute;
  left: var(--space-4);
  bottom: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  color: var(--color-text-faint);
}

/* The platter sits slightly left of centre, leaving room for the arm. */
.platter {
  position: absolute;
  left: 6%;
  top: 50%;
  width: 74%;
  aspect-ratio: 1;
  transform: translateY(-50%);
  border-radius: 50%;
  background: radial-gradient(circle, var(--color-muted) 0 68%, var(--color-bg-sunken) 68% 100%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.6), 0 4px 14px rgba(0, 0, 0, 0.6);
  display: grid;
  place-items: center;
}

.disc {
  position: relative;
  width: 94%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: #0a0908;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.8);
  /* 33⅓ rpm is 1.8 seconds per revolution. Paused until Play. */
  animation: spin 1.8s linear infinite;
  animation-play-state: paused;
}
.deck.is-playing .disc { animation-play-state: running; }

@keyframes spin { to { transform: rotate(360deg); } }

.disc__grooves {
  position: absolute;
  inset: 4%;
  border-radius: 50%;
  background: repeating-radial-gradient(
    circle at 50% 50%,
    rgba(255, 255, 255, 0.045) 0 1px,
    transparent 1px 4px
  );
}

/* The cover art becomes the centre label, which is the closest a web page gets
   to the real object. */
.disc__label {
  position: absolute;
  inset: 32%;
  border-radius: 50%;
  background: var(--color-accent-dim);
  background-size: cover;
  background-position: center;
  /* Same hairline as every other cover, so a dark label keeps its edge
     against the black disc. The dark ring outside it seats the label into
     the vinyl rather than leaving it floating on top. */
  box-shadow: inset 0 0 0 1px var(--cover-edge), 0 0 0 1px rgba(0, 0, 0, 0.7);
}

.disc__spindle {
  position: absolute;
  inset: 48.4%;
  border-radius: 50%;
  background: var(--color-bg-sunken);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.8);
}

/* A single highlight sweeping the disc, so it reads as glossy vinyl. */
.disc__sheen {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, 0.07) 48%, transparent 58%);
  pointer-events: none;
}

.tonearm {
  position: absolute;
  right: 9%;
  top: 12%;
  width: 42%;
  height: 60%;
  transform-origin: top right;
  /* Parked off the platter, on the rest. */
  transform: rotate(-20deg);
  transition: transform 900ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* Cueing angle: the stylus drops onto the OUTER groove, where a side starts —
   swinging further in would be the arm halfway through the record. */
.deck.is-playing .tonearm { transform: rotate(1deg); }

.tonearm__pivot {
  position: absolute;
  right: 0;
  top: 0;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--color-muted);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.6), 0 2px 6px rgba(0, 0, 0, 0.6);
}
.tonearm__rod {
  position: absolute;
  right: 0.6rem;
  top: 0.65rem;
  width: 2px;
  height: 100%;
  background: linear-gradient(var(--color-text-faint), var(--color-muted));
  transform-origin: top center;
  transform: rotate(18deg);
}
.tonearm__head {
  position: absolute;
  bottom: -0.15rem;
  left: -0.35rem;
  width: 0.85rem;
  height: 1.1rem;
  background: var(--color-muted);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
}

.nowplaying__title { font-size: var(--text-3xl); margin-bottom: 2px; }
.nowplaying__artist {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  color: var(--color-text-muted);
  margin-bottom: var(--space-4);
}
.nowplaying .detail__meta { margin-bottom: var(--space-2); }

.deck.is-swapping .nowplaying { opacity: 0.35; transition: opacity 120ms ease; }

/*
 * Reduced motion: the deck still loads records and still shows which one is
 * playing, it just does not spin or swing. The global rule above kills the
 * durations; these make sure the arm still lands somewhere sensible.
 */
@media (prefers-reduced-motion: reduce) {
  .deck.is-playing .disc { animation: none; }
  .deck.is-playing .tonearm { transform: rotate(1deg); }
}

/* ---- Track listing ---- */
.tracklist { margin-top: var(--space-6); max-width: var(--measure); }

.tracklist__heading {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-faint);
  margin-bottom: var(--space-2);
}
.tracklist__count { font-family: var(--font-mono); color: var(--color-accent); }

.tracklist__side {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-accent);
  margin-top: var(--space-4);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--color-accent-line);
}
.tracklist__side:first-of-type { margin-top: 0; }

.tracklist__items { list-style: none; margin: 0; padding: 0; }

.track {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr) auto;
  gap: var(--space-2);
  align-items: baseline;
  padding-block: var(--space-1);
  border-bottom: 1px solid var(--color-border);
}
.track:last-child { border-bottom: 0; }

.track__number {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
}
.track__title { font-size: var(--text-sm); }
.track__length {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  font-variant-numeric: tabular-nums;
}

/* ---- Choosing a pressing ---- */
.pressings { list-style: none; margin: var(--space-2) 0 0; padding: 0; }

.pressing {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}
.pressing:last-child { border-bottom: 0; }

.pressing__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pressing__title { font-family: var(--font-display); font-size: var(--text-lg); }
.pressing__note { color: var(--color-text-muted); font-size: var(--text-sm); }
.pressing__meta { font-size: var(--text-sm); color: var(--color-text-muted); }
.pressing__shape {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
}

.pressing__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  flex-shrink: 0;
}

/* A row already added stays put, so a single search can furnish several
   shelves — it just stops offering to add itself twice. */
.pressing.is-added { opacity: 0.6; }

.pressing__error {
  font-size: var(--text-sm);
  color: var(--color-danger);
  margin-top: 2px;
}

@media (max-width: 34rem) {
  .pressing { flex-direction: column; align-items: stretch; }
  .pressing__actions { justify-content: flex-start; }
}

#tracks-text {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: 1.7;
}

/* ---- List order ----
   Only ever shown in the admin table: the position is how the galleries are
   ordered, not something to read on the page. */
.rank {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  margin-inline-start: var(--space-1);
}

/* ---- Drag to reorder ---- */
.table__grip { width: 1.75rem; padding-inline-end: 0; }

.grip {
  display: block;
  padding: var(--space-1) 2px;
  color: var(--color-text-faint);
  font-size: var(--text-base);
  line-height: 1;
  cursor: grab;
  /* Without this a touch drag scrolls the page instead of moving the row. */
  touch-action: none;
  user-select: none;
  transition: color var(--transition);
}
.grip:hover { color: var(--color-accent); }

/* While a drag is in progress, quieten everything except the row being moved
   so the insertion point is obvious. */
.is-sorting { cursor: grabbing; }

/* Without this the pointer sweeping down the table selects text across every
   row it crosses, which looks like the table has broken. preventDefault on
   pointerdown stops the selection starting, but not one the browser begins
   mid-drag. */
.is-sorting, .is-sorting * { user-select: none; -webkit-user-select: none; }
.is-sorting .grip { cursor: grabbing; }
.is-sorting tr:not(.is-dragging) { opacity: 0.55; }

.is-dragging {
  background: var(--color-bg-raised);
  outline: 1px solid var(--color-accent);
  outline-offset: -1px;
}
.is-dragging td:first-child { box-shadow: inset 2px 0 0 var(--color-accent); }

/* Briefly, while the new position is being written. */
.is-saving { opacity: 0.6; }

@media (prefers-reduced-motion: reduce) {
  .grip { transition: none; }
}

/* ---- Numbers ----
   The charts are drawn in SVG by js/charts.js. Everything here is the frame
   around them: the surface, the ink, and the one-row filter above. Series
   colours live in the script, where they are validated as a set. */

.stats-filter {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
}

.chip {
  display: inline-block;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
  text-decoration: none;
}
.chip:hover { border-color: var(--color-border-strong); color: var(--color-text); }
.chip--on {
  background: var(--color-accent-dim);
  border-color: var(--color-accent-line);
  color: var(--color-text);
}

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
}
.tile {
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  padding: var(--space-3);
}
.tile dt {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.tile dd {
  margin: 0.35rem 0 0;
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.chart-panel { margin-bottom: var(--space-4); }
.chart { margin: var(--space-3) 0 0; }
.chart__svg { display: block; max-width: 100%; overflow: visible; }

.chart__empty {
  color: var(--color-text-faint);
  font-size: var(--text-sm);
  padding: var(--space-4) 0;
}

/* Recessive: the data is the thing being read, not the scaffolding. */
.chart__grid { stroke: var(--color-border); stroke-width: 1; stroke-opacity: 0.45; }
.chart__axis { stroke: var(--color-border-strong); stroke-width: 1; }

/* Text wears text tokens, never a series colour. */
.chart__tick {
  fill: var(--color-text-faint);
  font-family: var(--font-mono);
  font-size: 0.7rem;
}
.chart__label {
  fill: var(--color-text-muted);
  font-family: var(--font-body);
  font-size: var(--text-sm);
}
.chart__value {
  fill: var(--color-text);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.chart__bar, .chart__bubble, .chart__slice { transition: opacity 120ms ease; }
.chart__bar:hover, .chart__bubble:hover, .chart__slice:hover { opacity: 0.78; }
.chart__bar:focus-visible, .chart__bubble:focus-visible, .chart__slice:focus-visible {
  outline: 2px solid var(--color-accent-hover);
  outline-offset: 2px;
}

.pie { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; }
.pie__figure { flex: 0 0 auto; }
.pie__total {
  fill: var(--color-text);
  font-family: var(--font-display);
  font-size: 1.9rem;
  font-variant-numeric: tabular-nums;
}
.pie__total-label {
  fill: var(--color-text-muted);
  font-family: var(--font-body);
  font-size: 0.7rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

.legend { list-style: none; margin: 0; padding: 0; flex: 1 1 14rem; min-width: 0; }
.legend__item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.22rem 0;
  font-size: var(--text-sm);
}
.legend__swatch {
  width: 12px; height: 12px; flex: 0 0 auto; border-radius: 3px;
  /* The same hairline the covers get: a dark slice needs an edge. */
  box-shadow: inset 0 0 0 1px var(--cover-edge);
}
.legend__name { color: var(--color-text); min-width: 0; }
.legend__count {
  margin-left: auto;
  color: var(--color-text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

.chart-tip {
  position: fixed;
  z-index: 40;
  pointer-events: none;
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border-strong);
  color: var(--color-text);
  font-size: var(--text-sm);
  padding: 0.35rem 0.6rem;
  border-radius: 4px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.55);
}

#stats-tables { margin-top: var(--space-3); }
.table--plain caption {
  text-align: left;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  padding: var(--space-3) 0 var(--space-1);
}
.table--plain { margin-bottom: var(--space-3); }

@media (max-width: 34rem) {
  .pie { justify-content: center; }
  .tile dd { font-size: var(--text-2xl); }
}

/* ---- Numbers: the charts as filter controls ---- */

/* A mark you can act on says so before it is clicked. */
.is-pickable { cursor: pointer; }
.chart__bar.is-pickable:hover, .chart__bubble.is-pickable:hover,
.chart__slice.is-pickable:hover { opacity: 0.85; }

/* One mark chosen: it stays lit, its siblings step back. The chart then says
   what is being shown without needing a caption to explain it. */
.is-dimmed { opacity: 0.28; }
.is-picked { opacity: 1; }
.chart__bubble.is-picked, .chart__slice.is-picked, .chart__bar.is-picked {
  stroke: var(--color-accent-hover);
  stroke-width: 2;
}

.legend__item.is-pickable { cursor: pointer; border-radius: 3px; }
.legend__item.is-pickable:hover .legend__name { color: var(--color-accent-hover); }
.legend__item.is-picked .legend__name { color: var(--color-accent-hover); font-weight: 500; }

.active-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  margin-bottom: var(--space-3);
}
.active-filters__intro {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin-right: 0.2rem;
}

button.chip { font: inherit; font-size: var(--text-sm); cursor: pointer; }
.chip--removable { display: inline-flex; align-items: center; gap: 0.45rem; }
.chip__x { color: var(--color-text-muted); font-size: 1.05em; line-height: 1; }
.chip--removable:hover .chip__x { color: var(--color-danger); }
.chip--quiet { background: none; border-style: dashed; }

.page-head--tight {
  align-items: baseline;
  margin-bottom: 0;
  padding-bottom: var(--space-2);
}
.album-count {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* Five columns of records do not fit a phone, and without this the page
   itself scrolls sideways — on a page whose charts are the point. */
#album-list { margin-top: var(--space-2); overflow-x: auto; }
#album-list table { width: 100%; }
#album-list td:nth-child(3) { font-variant-numeric: tabular-nums; }
#album-list td:nth-child(4), #album-list td:nth-child(5) {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* The genre chips carry a count, which needs to read as secondary. */
.chip .count {
  margin-left: 0.35rem;
  color: var(--color-text-faint);
  font-family: var(--font-mono);
  font-size: 0.85em;
}

/* ---------------------------------------------------------- price watch */

/*
 * What the shops are asking for a wishlist record, and whether the watch
 * itself is working.
 *
 * The trend line is a single series, so it wears the accent — the same tone
 * charts.js uses for single-series marks, rather than a second violet. Every
 * number and label stays in a text token: a coloured mark beside the text
 * carries the identity, the text never does.
 */

.pricewatch { margin-top: var(--space-4); }

.pw__lead {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.pw__label {
  margin: 0;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* A standalone figure, so the font's proportional digits — tabular-nums gives
   every digit the width of a zero, which reads loose at display sizes. Those
   belong in the column of prices below, not here. */
.pw__price {
  margin: 0.2rem 0 0;
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  line-height: 1;
}

.pw__at { margin: 0.3rem 0 0; color: var(--color-text-muted); font-size: var(--text-sm); }

.pw__change {
  margin: 0.5rem 0 0;
  font-size: var(--text-sm);
}
.pw__change--down { color: var(--color-positive); }
.pw__change--up { color: var(--color-warning); }
.pw__change--flat { color: var(--color-text-muted); }

/* A price nobody published as a price. Said in words, not implied by styling,
   wherever one appears. */
.pw__caveat {
  display: inline-block;
  margin-left: 0.3rem;
  padding: 0.05rem 0.4rem;
  border: 1px dashed var(--color-border-strong);
  border-radius: 999px;
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  text-transform: none;
  letter-spacing: 0;
  white-space: nowrap;
}

.pw__spark { margin: 0; text-align: right; }
.pw__sparksvg { display: block; overflow: visible; }
.pw__sparkline {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pw__sparkarea { fill: var(--color-accent-dim); stroke: none; }
/* The surface-coloured ring keeps the newest point readable where the line
   passes back underneath it. */
.pw__sparkdot {
  fill: var(--color-accent);
  stroke: var(--color-bg-raised);
  stroke-width: 2;
}
/* Invisible, and wide enough to be a real hover target for the native
   tooltip — the line itself is 2px and nobody can hit that. */
.pw__sparkhit { fill: transparent; }
.pw__spark figcaption {
  margin-top: 0.3rem;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}
.pw__nospark {
  margin: 0;
  max-width: 22rem;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* Below about 360px the three columns stop fitting. Scrolling the table is
   better than scrolling the page: the rest of the record stays where it is,
   and nothing is hidden. */
.pw__shopswrap { overflow-x: auto; }
.pw__shops { width: 100%; border-collapse: collapse; }
.pw__shops th, .pw__shops td {
  padding: 0.5rem 0.6rem 0.5rem 0;
  border-bottom: 1px solid var(--color-border);
  text-align: left;
  font-weight: 400;
  vertical-align: baseline;
}
.pw__shops th:last-child, .pw__shops td:last-child { padding-right: 0; }
.pw__shops thead th {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
/* A column of prices, which must align: tabular figures earn their keep here. */
.pw__num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.pw__when {
  text-align: right;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Sold out is dimmed, not hidden: a shop that had it and no longer does is
   worth seeing, and removing the row would read as never having stocked it. */
.pw__row--gone th, .pw__row--gone .pw__num { color: var(--color-text-faint); }
/* On a narrow screen the price and the date are already tight; letting this
   drop to its own line keeps "sold out" from running into the date. */
.pw__gone {
  display: inline-block;
  margin-left: 0.35rem;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-warning);
}

.pw__matched { margin-top: var(--space-2); font-size: var(--text-sm); }
.pw__matched summary { color: var(--color-text-muted); cursor: pointer; }
.pw__matched ul { margin: var(--space-1) 0 0; padding-left: 1.1rem; color: var(--color-text-muted); }
.pw__matched strong { color: var(--color-text); font-weight: 500; }

/* The price on a wishlist card. Quiet: the sleeve is the point of the card. */
.record__price {
  margin: 0.3rem 0 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------- shop health */

.shopstrip { list-style: none; margin: var(--space-2) 0 0; padding: 0; }
.shopstrip__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--color-border);
}
/* The glyph differs by state as well as the colour, and the word next to it
   says the same thing in text. Nobody has to see a hue to read this. */
.shopstrip__mark { font-size: 0.8em; }
.shopstrip__item--ok .shopstrip__mark { color: var(--color-positive); }
.shopstrip__item--warn .shopstrip__mark { color: var(--color-warning); }
.shopstrip__item--bad .shopstrip__mark { color: var(--color-danger); }

.shopstrip__name { font-weight: 500; }
.shopstrip__state {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.shopstrip__why { font-size: var(--text-sm); color: var(--color-text-faint); }
.shopstrip__when {
  margin-left: auto;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 560px) {
  .pw__lead { flex-direction: column; align-items: flex-start; }
  .pw__spark { text-align: left; }
  .shopstrip__when { margin-left: 0; }
  /* Three columns is one too many at this width: the price keeps its own
     line rather than being squeezed between the shop and the date. */
  .pw__gone { display: block; margin-left: 0; }
  .pw__caveat { margin-left: 0; }
}

/* "Not in stock" sits where a price would: same weight, smaller, muted, so the
   absence reads as the answer rather than as something failing to load. */
.pw__price--none { font-size: var(--text-xl); color: var(--color-text-muted); }

/* ------------------------------------------------- walking the list */

.recordbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.recordbar .breadcrumb { margin-bottom: 0; }

.recordnav {
  display: flex;
  align-items: center;
  gap: 0.2rem;
}
.recordnav__step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* A real hit target, not a glyph with a link around it — 2.4rem clears the
     44px touch minimum at the default root size. */
  min-width: 2.4rem;
  min-height: 2.4rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: var(--text-lg);
  line-height: 1;
}
a.recordnav__step:hover,
a.recordnav__step:focus-visible {
  border-color: var(--color-accent-line);
  background: var(--color-accent-dim);
  color: var(--color-text);
}
/* The end of a list is information. Dimmed and inert rather than removed, so
   the arrows stay where they were as you reach the last record. */
.recordnav__step--end {
  border-style: dashed;
  color: var(--color-muted);
}
.recordnav__count {
  min-width: 5.5rem;
  text-align: center;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 30rem) {
  .recordbar { gap: var(--space-2); }
  .recordnav__count { min-width: 4.5rem; }
}

/* --------------------------------------------- wishlist with no price */

.untracked { list-style: none; margin: var(--space-2) 0 0; padding: 0; }
.untracked__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--color-border);
}
.untracked__item a {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.6rem;
  text-decoration: none;
  color: inherit;
}
.untracked__item a:hover .untracked__title { color: var(--color-accent-hover); }
.untracked__artist { color: var(--color-text-muted); }
.untracked__title { color: var(--color-accent); }

/* The reason is a word, not a colour: "never found" is usually ours to fix
   and "no longer in stock" is the shop's, and nobody should need to see a hue
   to tell which. */
.untracked__why {
  margin-left: auto;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
}
.untracked__why--ours { color: var(--color-warning); }
.untracked__why--theirs { color: var(--color-text-faint); }

.untracked__none { margin: var(--space-2) 0 0; color: var(--color-text-muted); }

@media (max-width: 30rem) {
  .untracked__why { margin-left: 0; }
}

/* ------------------------------------ outstanding wishlist investment */

/* A standalone figure, so the font's proportional digits rather than
   tabular-nums, which reads loose at this size. */
.invest__total {
  margin: var(--space-2) 0 0;
  font-family: var(--font-display);
  font-size: var(--text-4xl, var(--text-3xl));
  line-height: 1;
}
.invest__at { margin: 0.35rem 0 0; color: var(--color-text-muted); font-size: var(--text-sm); }

.invest__fig { margin: var(--space-3) 0 0; }
/* viewBox plus width:100% is what makes it responsive without measuring
   anything in JavaScript; preserveAspectRatio="none" lets it stretch, and the
   stroke is told not to stretch with it. */
.invest__svg { display: block; width: 100%; height: 7.5rem; overflow: visible; }
.invest__line {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.invest__area { fill: var(--color-accent-dim); stroke: none; }

/*
 * The coverage panel under the money.
 *
 * Shorter and in muted ink on purpose: it is the supporting measure, and the
 * eye should land on the total first. The neutral is also the one tone left —
 * green, amber and red are reserved for status here and would read as a
 * verdict on a record count, which has no good or bad.
 *
 * No area fill. A fill reads as magnitude from zero, and this panel's floor is
 * the fewest records seen, not none of them.
 */
.invest__panel {
  margin: var(--space-3) 0 0.35rem;
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.invest__range { color: var(--color-text-faint); text-transform: none; letter-spacing: 0; }
.invest__svg--count { height: 2.75rem; }
.invest__svg--bought { height: 3.5rem; }

/*
 * What has been bought. An area, unlike the coverage line above it, because
 * this one is a running total that starts at nothing and only ever climbs —
 * a filled shape reads as accumulation, which is exactly what it is.
 */
.invest__boughtline {
  fill: none;
  stroke: var(--color-series-2);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.invest__boughtarea { fill: var(--color-series-2-dim); stroke: none; }
.invest__bought {
  margin: 0.5rem 0 0;
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  max-width: 46rem;
}
.invest__countline {
  fill: none;
  stroke: var(--color-text-muted);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.invest__fig figcaption {
  margin-top: 0.5rem;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  max-width: 46rem;
}
