/* Colours: Fjäll × Linne. Fjäll's warm paper, graphite, pine and sage, with Linne's cards,
   serif headings and straight shapes. The design is in design/ (not in git). */
:root {
  color-scheme: light;
  --bg: #f4f3ef; /*           paper */
  --surface: #ffffff;
  --surface-hover: #f7f6f2;
  --surface-alt: #fbfaf8; /*  every other table row, between surface and hover */
  --field: #ffffff;
  --ink: #1d1e1b; /*          graphite */
  --ink-2: #3a3b37;
  --muted: #66655f; /*        stone */
  --line: #e2e0da;
  --line-strong: #cfcdc6;
  --primary: #2e3b34; /*      pine: buttons, the selected view */
  --primary-dark: #1f2823;
  --on-primary: #ffffff;
  --accent: #8c9a88; /*       sage: record labels */
  --tag-bg: #e7ebe4; /*       version pills */
  --tag-ink: #2e3b34;
  --secondary: #8c9a88; /*    "I got it" */
  --secondary-dark: #7a8876;
  --on-secondary: #1d1e1b;
  --link: #2e3b34;
  --strong: #1d1e1b; /*       toast */
  --on-strong: #f4f3ef;
  --header-bg: #ffffff;
  --header-fg: #1d1e1b;
  --header-border: #e2e0da;
  --wordmark: #1d1e1b;
  --frame: #e2e0da; /*        border around the table and cards */
  --card-shadow: none;
  --seg-on: #f0efea; /*       the pressed half of the table/cards switch */
  /* The records in the ratings: graphite with a sage label; unrated ones just an outline. */
  --disc: #1d1e1b;
  --groove: #3a3b37;
  --disc-label: #8c9a88;
  --disc-hole: #1d1e1b;
  --disc-off: #b9b7b0;
  /* The logo: the same record, with a little shine. */
  --logo-disc: #1d1e1b;
  --logo-edge: #1d1e1b;
  --logo-groove: #3a3b37;
  --logo-label: #8c9a88;
  --logo-hole: #f4f3ef;
  --logo-shine: rgba(255, 255, 255, 0.35);
  /* No cover yet: a record on a pale square. */
  --cover-bg: #e9e7e1;
  --cover-disc: #30312d;
  --cover-groove: #4a4b46;
  --cover-hole: #f4f3ef;
  --danger: #a33a2c;
  --danger-dark: #862e22;
  --on-danger: #ffffff;
  --focus-glow: rgba(46, 59, 52, 0.18);
  --shadow: rgba(29, 30, 27, 0.16);
  --backdrop: rgba(29, 30, 27, 0.45);

  --radius: 6px;
  --font: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  /* The serif carries the logo and album titles, italic for the personal. */
  --serif: "Instrument Serif", Georgia, "Times New Roman", serif;
}

/* Dark mode: the same fonts, logo and layout. The paper turns to charcoal, the graphite to chalk
   and the pine lightens to sage. Set by the switcher in the header, or by the system setting until one is picked. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #191a18; /*           charcoal */
  --surface: #21221f;
  --surface-hover: #2a2b28;
  --surface-alt: #242522;
  --field: #1c1d1b;
  --ink: #eceae4; /*          chalk */
  --ink-2: #cfcdc6;
  --muted: #a3a199;
  --line: #33342f;
  --line-strong: #474842;
  --primary: #a8b6a3;
  --primary-dark: #bcc8b7; /* lighter on hover in the dark */
  --on-primary: #191a18;
  --accent: #8c9a88;
  --tag-bg: #2c332d;
  --tag-ink: #a8b6a3;
  --secondary: #8c9a88;
  --secondary-dark: #9daa99;
  --on-secondary: #191a18;
  --link: #a8b6a3;
  --strong: #eceae4;
  --on-strong: #191a18;
  --header-bg: #21221f;
  --header-fg: #eceae4;
  --header-border: #33342f;
  --wordmark: #eceae4;
  --frame: #33342f;
  --card-shadow: none;
  --seg-on: #2e2f2b;
  /* Chalk records with a sage label. */
  --disc: #d6d4cd;
  --groove: #b5b3ac;
  --disc-label: #8c9a88;
  --disc-hole: #191a18;
  --disc-off: #5a5b55;
  /* The logo turns to an outline: a charcoal record with a chalk rim. */
  --logo-disc: #191a18;
  --logo-edge: #eceae4;
  --logo-groove: #474842;
  --logo-label: #8c9a88;
  --logo-hole: #191a18;
  --logo-shine: transparent;
  --cover-bg: #2a2b27;
  --cover-disc: #121311;
  --cover-groove: #2e2f2b;
  --cover-hole: #191a18;
  --danger: #e07a6b;
  --danger-dark: #ea9284;
  --on-danger: #191a18;
  --focus-glow: rgba(168, 182, 163, 0.25);
  --shadow: rgba(0, 0, 0, 0.5);
  --backdrop: rgba(0, 0, 0, 0.6);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.45;
  color: var(--ink);
  background: var(--bg);
}
[hidden] { display: none !important; }
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
h1, h2 { font-family: var(--serif); font-weight: 400; letter-spacing: -0.005em; }

/* ---- header ---- */
.top {
  background: var(--header-bg);
  color: var(--header-fg);
  border-bottom: 1px solid var(--header-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem clamp(1rem, 4vw, 2.5rem);
  position: sticky;
  top: 0;
  z-index: 5;
}
.brand { display: flex; align-items: center; gap: 0.75rem; text-decoration: none; color: inherit; min-width: 0; }
.logo { width: 38px; height: 38px; flex: none; }
.brand:hover .logo { animation: spin 2.4s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.wordmark {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.6rem, 5vw, 2.1rem);
  color: var(--wordmark);
  line-height: 1;
  white-space: nowrap;
}

/* Header buttons, icons only: search, light/dark, and logging in or your initials. */
.header-actions { position: relative; display: flex; align-items: center; gap: 0.35rem; flex: none; }
.btn.round { width: 42px; min-height: 42px; padding: 0; display: inline-grid; place-items: center; border-radius: 50%; }
.top .btn.ghost.avatar {
  background: var(--primary); color: var(--on-primary); border-color: transparent;
  font-family: var(--serif); font-style: italic; font-size: 1.2rem; line-height: 1;
}
.top .btn.ghost.avatar:hover { background: var(--primary-dark); }
/* Your Google picture, over the initials. */
.top .btn.avatar { position: relative; overflow: hidden; }
.btn.avatar img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* A dot on the search button while a tucked-away search is narrowing the list. */
#search-btn { position: relative; }
#search-btn.active::after {
  content: ""; position: absolute; top: 6px; right: 6px; width: 9px; height: 9px;
  border-radius: 50%; background: var(--primary); box-shadow: 0 0 0 2px var(--header-bg);
}

/* The search field pops out under the header, at the right on wide screens. */
.search-pop {
  position: absolute; top: calc(100% + 8px); right: clamp(1rem, 4vw, 2.5rem); width: min(380px, 100% - 2rem);
  padding: 0.5rem; background: var(--surface); border: 1px solid var(--frame);
  border-radius: var(--radius); box-shadow: 0 10px 30px var(--shadow);
}
.search-field { position: relative; }
.search-field input { padding-right: 2.75rem; }
/* Our own clear button instead of the browser's little cross. */
.search-field input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.search-clear {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 30px; height: 30px; display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 50%; background: var(--line); color: var(--ink); cursor: pointer;
}
.search-clear:hover { background: var(--line-strong); }
.search-clear .icon { width: 16px; height: 16px; }
.menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 6; min-width: 190px;
  display: grid; padding: 0.35rem; background: var(--surface); color: var(--ink);
  border: 1px solid var(--frame); border-radius: var(--radius); box-shadow: 0 10px 30px var(--shadow);
}
.menu button {
  display: flex; align-items: center; gap: 0.65rem; padding: 0.65rem 0.75rem; border: 0; border-radius: 4px;
  font: inherit; font-weight: 500; color: inherit; background: none; text-align: left; cursor: pointer;
}
.menu button:hover, .menu button:focus-visible { background: var(--surface-hover); }
.menu .icon { width: 18px; height: 18px; flex: none; }
/* Who is logged in, above logging out: the name, and the email on one line, cut short if it is long. */
.menu-who {
  display: grid; gap: 0.1rem; min-width: 0;
  padding: 0.5rem 0.75rem 0.6rem; margin-bottom: 0.35rem; border-bottom: 1px solid var(--line);
}
/* As wide as the email needs, up to a point. */
#account-menu { width: max-content; max-width: min(280px, 100vw - 2rem); }
#account-name { font-weight: 500; }
#account-email { font-size: 0.8rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- buttons & inputs ---- */
.btn {
  font: inherit;
  font-weight: 500;
  border-radius: var(--radius);
  border: 1px solid transparent;
  padding: 0.5rem 1.1rem;
  cursor: pointer;
  min-height: 42px;
  white-space: nowrap;
}
/* Wide screens: the icon beside the label. Small screens show the icon alone. */
.icon-btn, .with-icon { display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem; padding-left: 0.85rem; }
.icon-btn .icon, .with-icon .icon { width: 18px; height: 18px; flex: none; }
.icon { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.btn.primary { background: var(--primary); color: var(--on-primary); }
.btn.primary:hover { background: var(--primary-dark); }
.btn.ghost { background: transparent; color: inherit; border-color: currentColor; }
/* In the header the icon buttons stand bare, as in the design. */
.top .btn.ghost { border-color: transparent; }
.top .btn.ghost:hover { background: var(--surface-hover); }
main .btn.ghost { color: var(--ink); border-color: var(--line); }
main .btn.ghost:hover { border-color: var(--line-strong); background: var(--surface-hover); }
.btn.small { padding: 0.25rem 0.8rem; min-height: 32px; font-size: 0.9rem; }
.btn.danger:hover { color: var(--danger); border-color: var(--danger); }
.btn.danger-solid { background: var(--danger); color: var(--on-danger); }
.btn.danger-solid:hover { background: var(--danger-dark); }
.btn.icon-only { width: 32px; padding: 0; display: inline-grid; place-items: center; vertical-align: middle; }
.btn.icon-only .icon { width: 16px; height: 16px; }
.confirm p { margin: 0; line-height: 1.5; }
.btn.teal { background: var(--secondary); color: var(--on-secondary); }
.btn.teal:hover { background: var(--secondary-dark); }

input, textarea {
  font: inherit;
  color: var(--ink);
  background: var(--field);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 0.55rem 0.75rem;
  width: 100%;
  min-height: 42px;
}
select {
  font: inherit; color: var(--ink); background: var(--field); border: 1px solid var(--line-strong);
  border-radius: var(--radius); padding: 0.45rem 0.75rem; min-height: 42px;
}
/* iPhones zoom the page in on a field whose text is under 16px, and stay zoomed when the keyboard
   closes. So no field is smaller than that, whatever the label around it uses. */
input, textarea, select { font-size: max(1rem, 16px); }
select:focus { border-color: var(--ink); outline: none; box-shadow: 0 0 0 3px var(--focus-glow); }
textarea { resize: vertical; line-height: 1.4; }
input:focus, textarea:focus { border-color: var(--ink); outline: none; box-shadow: 0 0 0 3px var(--focus-glow); }

/* A text field with suggestions. The list is fixed to the screen so the dialog doesn't clip or scroll it. */
.combo { position: relative; display: block; }
.combo input { padding-right: 2.75rem; }
.combo-toggle {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 30px; height: 30px; display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 50%; background: none; color: var(--muted); cursor: pointer;
}
.combo-toggle:hover { color: var(--ink); background: var(--surface-hover); }
.combo-toggle .icon { width: 18px; height: 18px; transition: transform 0.15s; }
.combo input[aria-expanded="true"] + .combo-toggle .icon { transform: rotate(180deg); }
.combo-list {
  position: fixed; z-index: 10; margin: 0; padding: 0.35rem; list-style: none; overflow-y: auto;
  background: var(--surface); color: var(--ink); font-weight: 400;
  border: 1px solid var(--frame); border-radius: var(--radius); box-shadow: 0 10px 30px var(--shadow);
}
.combo-list li { padding: 0.55rem 0.75rem; border-radius: 4px; cursor: pointer; }

/* A field of tags: the chosen ones as pills, then the text field, wrapping inside one input-like box. */
.tags-field { display: grid; gap: 0.3rem; }
.tags-field > label { display: block; }
.tag-box {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; min-height: 42px; cursor: text;
  padding: 0.3rem 2.75rem 0.3rem 0.45rem; background: var(--field);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
}
.tag-box:focus-within { border-color: var(--ink); box-shadow: 0 0 0 3px var(--focus-glow); }
.tag-chips { display: contents; }
.tag-box input {
  flex: 1; width: auto; min-width: 9rem; min-height: 30px; padding: 0.2rem 0.3rem;
  border: 0; background: transparent;
}
.tag-box input:focus { box-shadow: none; }
.pill.tag { display: inline-flex; align-items: center; gap: 0.15rem; padding-right: 0.2rem; }
.pill.tag button {
  display: grid; place-items: center; width: 20px; height: 20px; padding: 0; border: 0; border-radius: 3px;
  background: transparent; color: inherit; cursor: pointer;
}
.pill.tag button:hover { background: color-mix(in srgb, currentColor 16%, transparent); }
.pill.tag .icon { width: 12px; height: 12px; stroke-width: 2.6; }
.combo-list li:hover, .combo-list li.active { background: var(--surface-hover); }
.combo-list li[aria-selected="true"] { font-weight: 500; }

/* ---- layout ---- */
/* The table grows to 1600px wide; the padding comes on top. */
main { max-width: calc(1600px + 5rem); margin: 0 auto; padding: 1.5rem clamp(1rem, 4vw, 2.5rem) 4rem; }
.bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem; }
/* The icons at the right of the tabs: view, sort and add, each a square as tall as the others. */
.tools { display: flex; align-items: center; gap: 0.6rem; flex: none; }
.btn.square { width: 44px; min-height: 44px; padding: 0; display: inline-grid; place-items: center; }
main .btn.ghost.square { background: var(--surface); border-color: var(--line-strong); }
main .btn.ghost.square:hover { background: var(--surface-hover); }
#add-btn .icon { width: 22px; height: 22px; }
/* The sort: the select lies invisibly over the icon and opens the browser's own list. Shown on
   small screens, and on wide ones in the card view; the table sorts by its headings. */
.sort-btn { position: relative; }
.sort-btn select {
  position: absolute; inset: 0; width: 100%; height: 100%; min-height: 0; padding: 0;
  opacity: 0; cursor: pointer; border: 0;
}
.sort-btn:focus-within { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Tabs underlined, with the count beside each in plain figures. */
.tabs { display: flex; gap: 1.75rem; }
/* Table or cards, on wide screens: a pair of icon buttons joined into one outlined box. */
.view-toggle {
  display: flex; background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius); overflow: hidden;
}
.view-toggle button {
  display: grid; place-items: center; width: 44px; height: 42px; padding: 0; border: 0; border-radius: 0;
  background: transparent; color: var(--muted); cursor: pointer;
}
.view-toggle button + button { border-left: 1px solid var(--line-strong); }
.view-toggle button:hover { color: var(--ink); }
.view-toggle button[aria-pressed="true"] { background: var(--seg-on); color: var(--ink); }
.view-toggle .icon { width: 18px; height: 18px; }
.tabs button {
  font: inherit; font-weight: 500; border: 0; border-bottom: 2px solid transparent; background: transparent;
  color: var(--muted); padding: 0.5rem 0 0.6rem; border-radius: 0; cursor: pointer;
}
.tabs button:hover { color: var(--ink); }
.tabs button[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--ink); }
.count { margin-left: 0.4rem; color: var(--muted); font-weight: 400; font-variant-numeric: tabular-nums; }

/* ---- table (desktop) ---- */
.table-wrap {
  /* Scrolls sideways rather than clipping, should a long version name make the table too wide. */
  background: var(--surface); border-radius: var(--radius); overflow-x: auto;
  border: 1px solid var(--frame); box-shadow: var(--card-shadow);
}
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 0.75rem 1rem; vertical-align: middle; }
/* Just above the card layout, tighter cells keep every column in view. */
@media (max-width: 1199px) { th, td { padding-left: 0.5rem; padding-right: 0.5rem; } }
thead th {
  background: var(--surface); color: var(--muted); font-weight: 500; font-size: 0.85rem; white-space: nowrap;
  border-bottom: 1px solid var(--line);
}
thead th[aria-sort="ascending"], thead th[aria-sort="descending"] { color: var(--ink); }
thead th button {
  all: unset; cursor: pointer; display: inline-flex; gap: 0.35rem; align-items: center;
}
thead th button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.arrow { color: var(--ink); font-size: 0.7em; }
tbody tr + tr td { border-top: 1px solid var(--line); }
tbody tr:nth-child(even) { background: var(--surface-alt); }
tbody tr[data-open] { cursor: pointer; }
tbody tr:hover { background: var(--surface-hover); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* The album leads the row, its name in the serif, as on the cards. */
/* A touch larger than 1rem, so its capitals stand as tall as Manrope's beside it. */
td.album .name { font-family: var(--serif); font-size: 1.1rem; }
td.act { text-align: right; white-space: nowrap; }
/* The wishlist's own order: its place, and a handle to drag it by when it can be moved. */
td.pos { width: 1%; white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; }
td.pos .drag-handle { margin: -0.4rem 0.25rem -0.4rem -0.5rem; vertical-align: middle; }
.drag-handle {
  display: inline-grid; place-items: center; width: 32px; height: 32px; padding: 0;
  border: 0; border-radius: 4px; background: none; color: var(--muted);
  cursor: grab; touch-action: none;
}
.drag-handle:hover { color: var(--ink); background: var(--surface-hover); }
.drag-handle .icon { stroke-width: 3; }
.reordering, .reordering * { cursor: grabbing; user-select: none; -webkit-user-select: none; }
/* Dragging: the others dim and slide aside, the lifted one follows the pointer above them,
   and the gap where it will land is outlined. */
.reorder-list > * { transition: transform 0.18s ease, opacity 0.15s ease; }
.reorder-list > :not(.lifted) { opacity: 0.4; }
.reorder-list > .lifted { position: relative; z-index: 4; transition: none; }
.card.lifted { scale: 1.03; box-shadow: 0 14px 30px var(--shadow); }
tr.lifted td { background: var(--surface-hover); }
tr.lifted { outline: 2px solid var(--primary); outline-offset: -2px; }
.drop-marker {
  position: absolute; z-index: 3; pointer-events: none; box-sizing: border-box;
  border: 2px dashed var(--primary); border-radius: var(--radius);
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  transition: top 0.18s ease;
}
td.act .btn + .btn { margin-left: 0.35rem; }
.muted { color: var(--muted); }
/* Artist and album names: every word starts with a capital, however they were typed. */
.name { text-transform: capitalize; }

.pill {
  display: inline-block; font-size: 0.8rem; padding: 0.15rem 0.55rem; border-radius: 4px;
  background: var(--tag-bg); color: var(--tag-ink); font-weight: 500;
}
.pills { display: flex; flex-wrap: wrap; gap: 0.35rem; }


/* Picking the owner in the form: outlined pills, the chosen one filled in pine. */
.owner-field { border: 0; margin: 0; padding: 0; min-width: 0; }
.owner-field legend { padding: 0; margin-bottom: 0.4rem; }
.owner-options { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.owner-option { display: block; position: relative; font-weight: 400; }
.owner-option input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; min-height: 0; }
.owner-option .pill {
  cursor: pointer; padding: 0.3rem 0.85rem; font-size: 0.9rem;
  background: transparent; color: var(--ink); box-shadow: inset 0 0 0 1px var(--line-strong);
}
.owner-option .pill:hover { background: var(--surface-hover); }
.owner-option input:checked + .pill { background: var(--primary); color: var(--on-primary); box-shadow: none; }
.owner-option input:focus-visible + .pill { outline: 2px solid var(--primary); outline-offset: 2px; }

/* ---- rating: little records like the logo; the ones not given just an outline ---- */
.rating { display: inline-flex; align-items: center; gap: 3px; vertical-align: middle; }
.disc {
  width: 18px; height: 18px; display: block;
  --disc-fill: transparent; --groove-fill: transparent; --label-fill: transparent; --hole-fill: transparent;
  --rim-fill: var(--disc-off);
}
.disc.on {
  --disc-fill: var(--disc); --groove-fill: var(--groove); --label-fill: var(--disc-label); --hole-fill: var(--disc-hole);
  --rim-fill: transparent;
}
.rating.editable button {
  background: none; border: 0; padding: 2px; margin: 0; cursor: pointer; border-radius: 50%; line-height: 0;
}
.rating.editable button:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
/* Hovering previews the rating: the hovered record and the ones before it light up. */
.rating.editable:hover .disc {
  --disc-fill: transparent; --groove-fill: transparent; --label-fill: transparent; --hole-fill: transparent;
  --rim-fill: var(--disc-off);
}
.rating.editable button:hover .disc,
.rating.editable button:has(~ button:hover) .disc {
  --disc-fill: var(--disc); --groove-fill: var(--groove); --label-fill: var(--disc-label); --hole-fill: var(--disc-hole);
  --rim-fill: transparent;
}
td.rating-cell { white-space: nowrap; }
/* Version tags stay on one line; the column widens to fit them. */
td .pill { white-space: nowrap; }
.card .rating .disc { width: 16px; height: 16px; }
.detail-title .rating .disc { width: 24px; height: 24px; }
.rating-field { display: grid; gap: 0.3rem; justify-items: start; }
.field-label { font-weight: 500; font-size: 0.95rem; }

/* ---- covers ---- */
.cover {
  display: block; flex: none; width: 48px; height: 48px; border-radius: 3px;
  object-fit: cover; background: var(--cover-bg);
}
/* No cover yet: a record on a pale square, as in the design. */
.cover.none {
  background:
    radial-gradient(circle closest-side, var(--cover-hole) 0 3%, var(--accent) 3.5% 26%,
      var(--cover-disc) 26.5% 44%, var(--cover-groove) 44.5% 45.5%, var(--cover-disc) 46% 56%,
      var(--cover-groove) 56.5% 57.5%, var(--cover-disc) 58% 72%, transparent 72.5%),
    var(--cover-bg);
}
.cover.finding { animation: pulse 1s ease-in-out infinite alternate; }
@keyframes pulse { to { opacity: 0.4; } }
.with-cover { display: flex; align-items: center; gap: 0.75rem; }

/* ---- cards (mobile) ---- */
.cards { display: none; }
.card {
  background: var(--surface); border: 1px solid var(--frame); border-radius: var(--radius);
  padding: 0.85rem 1rem; display: grid; gap: 0.3rem; box-shadow: var(--card-shadow);
}
.card + .card { margin-top: 0.6rem; }
/* The album in the serif, the artist under it in Manrope. */
.card .title { font-family: var(--serif); font-size: 1.4rem; line-height: 1.1; }
.card .artist { color: var(--muted); }
.card .artist { font-size: 0.95rem; }
.card .meta { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; color: var(--muted); font-size: 0.85rem; }
.card { column-gap: 0.9rem; align-items: start; }
.card.has-cover { grid-template-columns: 72px 1fr; }
.card.has-handle { grid-template-columns: auto 72px 1fr; column-gap: 0.6rem; padding-left: 0.5rem; }
.card[data-open] { cursor: pointer; }
.card[data-open]:hover { background: var(--surface-hover); }
/* The buttons on a row of their own along the bottom, kept to the right. */
.card .act { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 0.4rem; margin-top: 0.2rem; }
.card.has-cover .cover { width: 72px; height: 72px; }
/* A cover with the owner's name in white on a dark see-through strip, stuck to the top left-hand
   corner, so it reads on any picture, light or dark. In the serif, like the album titles. */
.cover-wrap { position: relative; flex: none; }
.cover-owner {
  position: absolute; top: 0; left: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 0.2rem 0.65rem 0.25rem; border-radius: 3px 0 4px 0;
  font-family: var(--serif); font-size: 1.15rem; line-height: 1.1;
  background: rgba(20, 21, 19, 0.62); color: #fff;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.detail-head .cover-owner { font-size: 1.05rem; padding: 0.15rem 0.55rem 0.2rem; }
/* Version tags along the bottom of a card, across its full width, kept to the right. */
.card-tags { grid-column: 1 / -1; justify-content: flex-end; }
.card-body { display: grid; gap: 0.35rem; min-width: 0; }

/* Cards grouped under each artist, rating or owner; by artist with a rail of letters down the right-hand side. */
.cards.has-rail { margin-right: 0.75rem; }
.card-group + .card-group { margin-top: 1.4rem; }
/* Logged out, each person's wishlist under their name. */
.person-list + .person-list { margin-top: 2rem; }
.list-head { margin: 0 0 0.75rem; font-size: 1.75rem; }
.card-group, .card { scroll-margin-top: 76px; }
.group-head { display: flex; align-items: center; margin: 0 0 0.5rem; font-size: 1.5rem; line-height: 1.2; }
/* A rating or an owner as the heading: a little larger than in the cards. */
.group-head .disc { width: 22px; height: 22px; }
.group-head .pill { font-size: 0.95rem; padding: 0.15rem 0.75rem; }
.alpha { display: none; }

/* Covers as tiles, as in the design: no frame, the cover across the top and the words under it.
   The owner sits on the cover's corner. app.js marks the cards as
   tiles everywhere but in a wishlist being put in order on a small screen, which needs a list. */
.tiles .card {
  grid-template-columns: minmax(0, 1fr); padding: 0;
  /* Cards in a row are as tall as the tallest; the spare height goes below the words, not between. */
  align-content: start;
  background: none; border: 0; border-radius: 0; box-shadow: none;
}
.tiles .card + .card { margin-top: 0; }
.tiles .card[data-open]:hover { background: none; }
.tiles .card[data-open]:hover .cover { filter: brightness(0.95); }
.tiles .card > .cover, .tiles .cover-wrap { grid-row: 1; grid-column: 1 / -1; margin-bottom: 0.45rem; }
.tiles .card .cover { width: 100%; height: auto; aspect-ratio: 1; }
.tiles .card-body { grid-column: 1 / -1; }
/* The wishlist's buttons lie on the cover's bottom right-hand corner, sharing its grid cell, in
   the same dark see-through strip as the owner's name; "I got it" keeps its sage. */
.tiles .card .act {
  grid-row: 1; grid-column: 1 / -1; align-self: end; justify-self: end; z-index: 1;
  flex-direction: row; gap: 0.3rem; margin: 0 0.4rem calc(0.45rem + 0.4rem) 0;
}
.tiles .card .act .btn {
  border-color: transparent; background: rgba(20, 21, 19, 0.62); color: #fff;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.tiles .card .act .btn:hover { background: rgba(20, 21, 19, 0.85); }
.tiles .card .act .btn.danger:hover { color: #ff9b8c; }
.tiles .card .act .btn.teal { background: var(--secondary); color: var(--on-secondary); }
.tiles .card .act .btn.teal:hover { background: var(--secondary-dark); }
.tiles .card-tags { justify-content: flex-start; }

/* Wide screens, as cards: as many columns as fit, sorted by the menu, without artist groups. */
@media (min-width: 1024px) {
  [data-view="cards"] .table-wrap { display: none; }
  [data-view="cards"] .cards {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 2rem 1.25rem; margin: 0;
  }
  [data-view="cards"] .card-group { display: contents; }
  [data-view="cards"] .group-head { display: none; }
  [data-view="table"] .sort-btn { display: none; }
  /* Reordering by dragging needs a single column; the table view has it. */
  [data-view="cards"] .card .drag-handle { display: none; }
}

@media (max-width: 1023px) {
  .view-toggle { display: none; }
  .alpha {
    /* Starts below the tabs and sort menu, so it never covers them. */
    position: fixed; right: 0; top: 12.5rem; bottom: 1rem; z-index: 4; width: 24px;
    display: flex; flex-direction: column; justify-content: center;
    touch-action: none; user-select: none; -webkit-user-select: none;
  }
  .alpha button {
    flex: 0 1 18px; min-height: 0; display: grid; place-items: center; padding: 0;
    font: inherit; font-size: 0.7rem; font-weight: 600; line-height: 1;
    color: var(--primary); background: none; border: 0; cursor: pointer;
  }
  .alpha button.dim { color: var(--muted); opacity: 0.5; font-weight: 500; }
}

/* Phones and tablets: the table needs about 920px, so below 1024px the list becomes cards
   and the header goes compact, with smaller round buttons that sit well beside the logo. */
@media (max-width: 1023px) {
  .table-wrap { display: none; }
  .cards { display: block; }
  /* Tiles two (or more) to a row, under their artist, rating or owner headings. */
  .cards.tiles:not(.grouped), .tiles .card-group {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(135px, 1fr)); gap: 1.5rem 0.75rem;
  }
  .tiles .group-head { grid-column: 1 / -1; margin: 0; }
  .card .title { font-size: 1.2rem; }
  .tiles .cover-owner { font-size: 1.05rem; }
  .top { gap: 0.5rem; }
  .brand { gap: 0.5rem; }
  .logo { width: 34px; height: 34px; }
  .wordmark { font-size: clamp(1rem, 5.2vw, 1.5rem); }
  .header-actions { gap: 0.25rem; }
  .top .btn.round { width: 38px; min-height: 38px; }
  .top .btn.ghost.avatar { font-size: 1.1rem; }
  .top .icon { width: 18px; height: 18px; }
  #search-btn.active::after { top: 4px; right: 4px; width: 8px; height: 8px; }
  .tabs { gap: 1.25rem; }
  .tools { gap: 0.5rem; }
  .btn.square { width: 42px; min-height: 42px; }
}

@media (max-width: 640px) {
  .search-pop { left: 0.75rem; right: 0.75rem; width: auto; }
  .icon-btn { width: 42px; min-height: 42px; padding: 0; display: inline-grid; place-items: center; flex: none; }
  .icon-btn .icon { width: 20px; height: 20px; }
  .icon-btn .btn-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}

/* ---- empty state ---- */
.empty {
  background: var(--surface); border: 1px dashed var(--line-strong); border-radius: var(--radius);
  padding: 2.5rem 1.5rem; text-align: center; color: var(--muted);
}
.empty strong { display: block; color: var(--ink); font-family: var(--serif); font-weight: 400; font-size: 1.6rem; margin-bottom: 0.25rem; }

/* ---- dialogs ---- */
dialog {
  border: 0; border-radius: 10px; padding: 0; width: min(92vw, 440px);
  background: var(--surface); color: var(--ink); box-shadow: 0 20px 60px var(--shadow);
}
dialog.wide { width: min(92vw, 560px); }
dialog::backdrop { background: var(--backdrop); }

/* The page behind an open dialog stays put, without a scrollbar of its own. */
html:has(dialog[open]) { overflow: hidden; }

/* Dialogs grow in from the middle on wide screens and slide up from the bottom on phones,
   then leave the same way, a little quicker. --dlg-from is where they come from.
   Browsers without @starting-style just show and hide them, as before. */
dialog { --dlg-from: scale(0.9); }
dialog, dialog::backdrop {
  transition: opacity 0.16s ease-in, transform 0.16s ease-in, overlay 0.16s ease-in allow-discrete, display 0.16s ease-in allow-discrete;
}
dialog, dialog::backdrop { opacity: 0; }
dialog { transform: var(--dlg-from); }
dialog[open], dialog[open]::backdrop {
  opacity: 1; transform: none;
  transition-duration: 0.26s; transition-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
}
@starting-style {
  dialog[open], dialog[open]::backdrop { opacity: 0; }
  dialog[open] { transform: var(--dlg-from); }
}
/* On phones, dialogs are sheets: full width, resting on the bottom edge, with room left above. */
@media (max-width: 640px) {
  dialog {
    width: 100%; max-width: none; margin: auto 0 0; max-height: calc(100dvh - 3rem);
    border-radius: 12px 12px 0 0; --dlg-from: translateY(100%); transition-duration: 0.22s;
  }
  dialog.wide { width: 100%; }
  /* The whole way up takes a moment longer; the dialog stays opaque so it reads as a sheet. */
  dialog[open] { transition-duration: 0.34s; }
  dialog, dialog[open] { opacity: 1; }
  @starting-style { dialog[open] { opacity: 1; } }
}
dialog form { padding: 1.5rem; display: grid; gap: 1rem; }
dialog h2 { margin: 0; font-size: 1.9rem; line-height: 1.1; }
/* The close button sits in the top right-hand corner and stays there while the dialog scrolls.
   Its negative bottom margin gives its room back, so the content starts beside it. */
.dlg-close {
  position: sticky; top: 1rem; z-index: 2; display: grid; place-items: center;
  width: 42px; min-height: 42px; padding: 0; margin: 1rem 1rem calc(-42px - 1rem) auto;
}
/* Quiet, so the dialog's own button is the one that stands out. */
.btn.dlg-close { background: var(--surface-hover); color: var(--ink); border-color: var(--line); }
.btn.dlg-close:hover { background: var(--seg-on); }
/* Headings keep clear of it. */
#dlg-title, #match-title, #confirm-title, .detail-title { padding-right: 3rem; }
label { display: grid; gap: 0.3rem; font-weight: 500; font-size: 0.95rem; }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
.full-only { display: grid; gap: 1rem; }
.cover-tools { display: flex; align-items: center; gap: 0.75rem; }
.cover-buttons { display: flex; flex-wrap: wrap; gap: 0.4rem; }

/* ---- detail view ---- */
.detail, #detail-body { display: grid; gap: 1.25rem; }
.detail { padding: 1.5rem; }
.detail-head { display: flex; gap: 1.1rem; align-items: flex-start; }
.cover.big { width: 140px; height: 140px; border-radius: 3px; box-shadow: 0 6px 18px var(--shadow); }
.detail-title { display: grid; gap: 0.3rem; justify-items: start; min-width: 0; }
.detail-title p { margin: 0; }
.detail-title .artist { font-weight: 500; color: var(--muted); }
.detail-title h2 { font-size: 2.2rem; line-height: 1.05; }
.detail-title .meta { color: var(--muted); font-size: 0.95rem; }
.detail-tracks h3 {
  margin: 1rem 0 0.35rem; font-size: 0.75rem; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}
.detail-tracks h3:first-child { margin-top: 0; }
.detail-tracks p { margin: 0; }
.tracklist { list-style: none; margin: 0; padding: 0; }
.tracklist li { display: flex; gap: 0.75rem; padding: 0.4rem 0; border-top: 1px solid var(--line); }
.tracklist li:last-child { border-bottom: 1px solid var(--line); }
.tracklist .no { width: 2.2em; flex: none; color: var(--muted); font-variant-numeric: tabular-nums; }
.tracklist .name { flex: 1; min-width: 0; }
.tracklist .len { color: var(--muted); font-variant-numeric: tabular-nums; }
.detail-foot {
  margin: 0; display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.5rem;
  color: var(--muted); font-size: 0.9rem;
}
.detail-foot a { color: var(--link); }
@media (max-width: 640px) {
  .detail-head { flex-direction: column; }
  /* Delete and edit move up beside the close button, next to the cover. */
  .detail { position: relative; }
  .detail .actions { position: absolute; top: 1rem; right: calc(42px + 1.5rem); }
  .detail-title { padding-right: 0; }
}
/* Logged out, the detail view has nothing left down there. */
.detail .actions:not(:has(> :not([hidden]))) { display: none; }

/* Album titles open the detail view. */
.open { font: inherit; color: inherit; text-transform: inherit; text-align: left; background: none; border: 0; padding: 0; cursor: pointer; }
.open:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 4px; }
.open:hover span, .card .open:hover { text-decoration: underline; text-underline-offset: 3px; }
.error { margin: 0; min-height: 1.2em; color: var(--danger); font-size: 0.9rem; }
.error.note { color: var(--muted); }
.comment-field { display: grid; gap: 0.3rem; }
.hint { margin: 0; color: var(--muted); font-size: 0.85rem; }
/* A wishlist comment: in its own column in the table, under the album on a card. */
.comment { color: var(--ink-2); white-space: pre-line; overflow-wrap: anywhere; }
td.comment { max-width: 40ch; }
.card .comment { margin: 0; font-size: 0.9rem; }

/* ---- choosing the right release ---- */
.matches { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; max-height: 60vh; overflow: auto; }
.match {
  display: flex; align-items: center; gap: 0.75rem; width: 100%; padding: 0.5rem 0.6rem;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
  background: var(--field); border: 1px solid var(--line); border-radius: var(--radius);
}
.match:hover, .match:focus-visible { border-color: var(--frame); background: var(--surface-hover); }
.match:disabled { cursor: progress; opacity: 0.55; }
.match.picked { border-color: var(--primary); opacity: 1; }
.spinner {
  flex: none; margin-left: auto; width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid var(--line); border-top-color: var(--primary); animation: spin 0.8s linear infinite;
}
.match > span { display: grid; min-width: 0; }
.match strong { font-weight: 600; }
.match .meta { font-size: 0.85rem; color: var(--muted); }
#match-note { margin: 0.3rem 0 0; }
.actions { display: flex; justify-content: flex-end; gap: 0.6rem; }
dialog .btn.ghost { color: var(--ink); border-color: var(--line); }

/* ---- back to the top ---- */
#top-btn {
  position: fixed; z-index: 6; width: 48px; min-height: 48px;
  right: max(1.25rem, env(safe-area-inset-right)); bottom: max(1.25rem, env(safe-area-inset-bottom));
  background: var(--surface); color: var(--ink); border-color: var(--line-strong);
  box-shadow: 0 4px 14px var(--shadow);
  opacity: 0; visibility: hidden; transform: translateY(0.75rem);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}
#top-btn:hover { background: var(--surface-hover); }
#top-btn.show { opacity: 1; visibility: visible; transform: none; }
/* Small screens: clear of the letter rail down the right-hand side. */
@media (max-width: 1023px) {
  #top-btn { right: calc(24px + 0.75rem); }
}

/* ---- toast ---- */
#toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translate(-50%, calc(100% + 2rem));
  background: var(--strong); color: var(--on-strong); padding: 0.7rem 1.2rem; border-radius: var(--radius);
  transition: transform 0.25s ease; z-index: 10; max-width: 90vw;
}
#toast.show { transform: translate(-50%, 0); }

@media (prefers-reduced-motion: reduce) {
  .brand:hover .logo { animation: none; }
  .cover.finding { animation: none; opacity: 0.6; }
  .spinner { animation-duration: 2.4s; }
  #toast { transition: none; }
  #top-btn { transform: none; }
  /* Dialogs only fade. */
  dialog { --dlg-from: none; opacity: 0; }
  dialog[open] { opacity: 1; }
  @starting-style { dialog[open] { opacity: 0; } }
}

.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
