/* Plastic public pages (/@handle, PLA2-1042): the approved prototype-profile-v2 design plus the live
   page's additions at the end. Served under style-src 'self', so no inline style anywhere;
   public-profile.js is the page's one script. prototype-profile-v2/styles.css is a byte-identical
   copy so the UI kit shows the shipped components (check_public_profiles.mjs asserts it). */

:root {
  color-scheme: light dark;
  --profile-width: 1280px;
  --profile-gutter: 24px;
  --bg: #f5f5f5; /* surfaceBackground */
  /* AlbumHeroView.swift: .shadow(black.opacity(0.1), radius: 4, y: 4) */
  --art-drop: 0 2px 6px rgba(0, 0, 0, 0.14);
  --art-depth: linear-gradient(to top, rgba(0, 0, 0, 0.30) 0%, rgba(0, 0, 0, 0) 1%);
  --stack-drop: 0 1px 4px rgba(0, 0, 0, 0.10);
  --stack-edge: rgba(0, 0, 0, 0.05);
  --ink: #2b2b2b; /* textPrimary */
  --ink-soft: #5e5e65; /* textSecondary */
  --muted: #93939a; /* textTertiary */
  --line: #dfdfdf; /* borderTertiary */
  --sleeve: clamp(150px, 17vw, 250px);
  --tile: #e9e9ea; /* surfaceSecondary */
  --avatar-fill: #f5f5f5; /* fixed light ground for the dark Plastic record in both themes */
  --pill-bg: #000000; /* buttonPrimary */
  --pill-line: #c5c5c6; /* borderSecondary */
  --pill-ink: #ffffff; /* textOnAccent */
  --surface: #ffffff; /* the record panel: one step above the page */
  --art-lift: 0 10px 24px rgba(0, 0, 0, 0.18);
  /* The wall stands its sleeves up, so they cast a real shadow rather than the
     flat card drop the grids use. Five stacked layers, each roughly double the
     blur of the one before and a little fainter: that ramp is what reads as a
     shadow going progressively out of focus, which one blur radius cannot do. */
  --wall-drop: 0 1px 1px rgba(0, 0, 0, 0.07), 0 3px 4px rgba(0, 0, 0, 0.06),
               0 7px 9px rgba(0, 0, 0, 0.05), 0 14px 19px rgba(0, 0, 0, 0.045),
               0 26px 36px rgba(0, 0, 0, 0.035);
  --wall-lift: 0 2px 2px rgba(0, 0, 0, 0.08), 0 6px 8px rgba(0, 0, 0, 0.07),
               0 14px 19px rgba(0, 0, 0, 0.06), 0 27px 38px rgba(0, 0, 0, 0.05),
               0 46px 60px rgba(0, 0, 0, 0.04);
  /* The holder: a stand's front lip, lit from above, casting onto the shelf. */
  --holder-face: linear-gradient(to bottom, #efefef 0%, #e9e9e9 58%, #d6d6d6 100%);
  --holder-drop: 0 1px 1px rgba(0, 0, 0, 0.10), 0 3px 5px rgba(0, 0, 0, 0.09),
                 0 7px 13px rgba(0, 0, 0, 0.07);
  /* A hairline so the lip still separates from a sleeve its own colour — a white
     one on a white cover, and in dark, where the drop shadow does nothing at all. */
  --holder-edge: rgba(0, 0, 0, 0.07);
  --mono: 'Chivo Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  /* z scale: popover < hover-raise < scrim < panel */
  --z-pop: 5; --z-hover: 10; --z-scrim: 20; --z-panel: 30;
}

/* Dark is a token swap and nothing else — no component knows which theme it is in.
   The page follows the browser's colour scheme; there is no switcher (2026-09-19). */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f0f0f; /* surfaceBackground */
    --ink: #f5f5f5; /* textPrimary */
    --ink-soft: #5e5e65; /* textSecondary */
    --muted: #93939a; /* textTertiary */
    --line: #1e1e1e; /* borderTertiary */
    --tile: #2b2b2b; /* surfaceSecondary */
    --pill-bg: #ffffff; /* buttonPrimary */
    --pill-line: #4f4f4f; /* borderSecondary */
    --pill-ink: #000000; /* textOnAccent */
    /* Artwork sits on a dark ground now: the drop shadow does nothing, so the lift
       comes from a hairline instead, and the inner shadow deepens to keep a pale
       sleeve from bleeding into the page. */
    --art-drop: 0 2px 7px rgba(0, 0, 0, 0.55);
    --art-depth: linear-gradient(to top, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 1%);
    --stack-drop: 0 1px 5px rgba(0, 0, 0, 0.45);
    --stack-edge: rgba(255, 255, 255, 0.09);
    --surface: #1a1a1a;
    --art-lift: 0 10px 26px rgba(0, 0, 0, 0.7);
    --wall-drop: 0 1px 2px rgba(0, 0, 0, 0.50), 0 4px 7px rgba(0, 0, 0, 0.42),
                 0 9px 16px rgba(0, 0, 0, 0.34), 0 18px 32px rgba(0, 0, 0, 0.28),
                 0 32px 54px rgba(0, 0, 0, 0.22);
    --wall-lift: 0 2px 4px rgba(0, 0, 0, 0.55), 0 7px 13px rgba(0, 0, 0, 0.48),
                 0 16px 28px rgba(0, 0, 0, 0.40), 0 30px 50px rgba(0, 0, 0, 0.33),
                 0 52px 78px rgba(0, 0, 0, 0.26);
    /* A white lip would glare against the dark page; the stand takes the room's light. */
    --holder-face: linear-gradient(to bottom, #434346 0%, #3a3a3d 58%, #262629 100%);
    --holder-drop: 0 1px 2px rgba(0, 0, 0, 0.60), 0 4px 9px rgba(0, 0, 0, 0.50),
                   0 9px 18px rgba(0, 0, 0, 0.40);
    --holder-edge: rgba(255, 255, 255, 0.17);
  }
}


* { box-sizing: border-box; }

html, body { overflow-x: hidden; }
/* Hold the scrollbar's column open at all times. Without it the page jumps 15px
   wider and recentres whenever the scrollbar goes away — filtering down to a
   short result, or opening a record (which locks scroll below). Where scrollbars
   overlay the content, as on a trackpad Mac, the gutter is zero and nothing changes. */
html { scrollbar-gutter: stable; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 17px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

.wrap { max-width: var(--profile-width); min-height: 100vh; min-height: 100dvh; margin: 0 auto; padding: 0 var(--profile-gutter); display: flex; flex-direction: column; }

/* Reserved-but-private and missing routes share the public-page header and footer. */
.route-state { flex: 1; width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 64px 12px 90px; }
.route-state h1 { max-width: 18ch; margin: 12px 0 10px; font-size: clamp(30px, 5vw, 56px); line-height: 1.06; letter-spacing: -.04em; }
.route-state p { max-width: 39ch; color: var(--ink-soft); line-height: 1.5; }
.route-state .pill { margin-top: 24px; }
.route-state-kicker { margin: 16px 0 0; color: #ce3300 !important; font-weight: 700; }
.route-state-mark { display: grid; place-items: center; width: 84px; height: 84px; border: 2px solid var(--line); border-radius: 50%; color: var(--ink); font-size: 64px; line-height: 1; }
.route-state-mark svg { width: 38px; height: 38px; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.route-state-note { margin-top: 26px; font-size: 14px; }
.route-404 { display: flex; align-items: center; gap: .02em; color: var(--ink); font-size: clamp(108px, 21vw, 236px); line-height: 1; font-weight: 650; letter-spacing: -.07em; }
.route-record { position: relative; display: inline-block; width: .74em; height: .74em; margin: 0 .04em; border-radius: 50%; background: #202020; box-shadow: inset 0 0 0 .035em #303030, inset 0 0 0 .055em #202020, inset 0 0 0 .085em #303030, inset 0 0 0 .11em #202020; }
.route-record::after { content: ''; position: absolute; inset: 41%; border-radius: 50%; background: #ce3300; box-shadow: 0 0 0 .028em #f4f4f4; }

/* ---------- header ---------- */

.topbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: 28px 0 14px;
}
.topbar-actions { display: flex; align-items: center; }

.wordmark { display: block; width: 200px; height: 36px; }
.wordmark img { display: block; width: 100%; height: 100%; }

.pill {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--pill-line);
  font-size: 15px;
  font-weight: 500;
  padding: 11px 21px;
  border-radius: 999px;
  white-space: nowrap;
}

/* ---------- identity ---------- */

.identity { text-align: center; padding: 18px 0 34px; }
.identity .avatar {
  width: 110px; height: 110px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 18px;
  background: var(--tile); color: var(--muted);
  font-size: 37px; font-weight: 600; letter-spacing: 0.02em;
  object-fit: cover;
  overflow: hidden;
}
.chip-avatar {
  width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--tile); color: var(--muted);
  font-size: 10px; font-weight: 700; margin-right: 7px;
  object-fit: cover;
}
.identity .avatar.placeholder-avatar, .chip-avatar.placeholder-avatar { background: var(--avatar-fill); }
.placeholder-avatar img { display: block; width: 68%; height: 68%; object-fit: contain; }
.chip-avatar.placeholder-avatar img { width: 20px; height: 20px; }
.identity .handle { font-size: 25px; font-weight: 700; letter-spacing: -0.01em; }
.identity .bio { font-size: 15px; color: var(--muted); margin-top: 9px; }

/* ---------- nav ---------- */

.nav {
  display: flex;
  justify-content: center;
  gap: 34px;
  font-size: 18px;
  padding-bottom: 46px;
}
.nav a { color: var(--ink-soft); padding-bottom: 6px; }
.nav a .n { color: var(--muted); }
.nav a.on { color: var(--ink); font-weight: 700; }
.nav a.on .n { color: var(--ink); font-weight: 400; }

/* ---------- sections ---------- */

.sec { padding-bottom: 68px; }
/* On a short section, source attribution belongs by the page footer. */
.sec:has(> .grid-credits:last-child) { flex: 1; display: flex; flex-direction: column; }
.sec > .grid-credits:last-child { margin-top: auto; padding-top: 36px; }
.sec-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 26px; }
/* One line always: filtering lengthens the title to "4 of 517 albums", and on a
   phone that wrapped and shoved the search field onto a second row. */
.sec-head h2 { font-size: 21px; font-weight: 700; letter-spacing: -0.01em; margin: 0; white-space: nowrap; }
.sec-head .more { font-size: 15px; color: var(--muted); }
.rule { border: 0; border-top: 1px solid var(--line); margin: 0 0 44px; }

/* ---------- covers ---------- */

.grid-rec { --gap-x: 24px; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 40px var(--gap-x); }

.cover { position: relative; display: block; transition: transform 200ms cubic-bezier(0.25, 1, 0.5, 1); }
/* Search hides non-matches; .cover sets display, so [hidden] alone loses. */
.cover[hidden] { display: none; }
.no-hits { font-size: 16px; color: var(--muted); margin: 0; padding: 12px 0 40px; }
.wishlist-empty { display: grid; justify-items: center; gap: 18px; padding: 50px 16px 70px; text-align: center; color: var(--muted); }
.wishlist-empty p { max-width: 28ch; margin: 0; font-size: 16px; }
.wishlist-empty-art { position: relative; width: 180px; height: 112px; }
.wishlist-empty-art .sleeve { position: absolute; top: 9px; width: 96px; height: 96px; background: var(--tile); border: 1px solid var(--line); box-shadow: var(--art-drop); }
.wishlist-empty-art .sleeve::after { content: ''; position: absolute; inset: 15px; border: 1px solid var(--line); border-radius: 50%; }
.wishlist-empty-art .sleeve.one { left: 3px; transform: rotate(-12deg); }
.wishlist-empty-art .sleeve.two { left: 40px; transform: rotate(4deg); }
.wishlist-empty-art .sleeve.three { left: 75px; transform: rotate(13deg); }
.wishlist-empty-art .wishlist-heart { position: absolute; z-index: 1; color: #ce3300; line-height: 1; }
.wishlist-empty-art .wishlist-heart.one { right: -10px; top: -11px; font-size: 40px; transform: rotate(12deg); }
.wishlist-empty-art .wishlist-heart.two { right: 15px; bottom: -11px; font-size: 27px; transform: rotate(-16deg); }
.cover img { transition: box-shadow 200ms cubic-bezier(0.25, 1, 0.5, 1); }
.cover:is(:hover, .is-hover) { transform: translateY(-3px); }
.cover:is(:hover, .is-hover) img { box-shadow: var(--art-lift); }
.cover:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }
.cover[data-pointer-focus]:focus-visible { outline: none; }
.cover img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 0; /* ADR-0016: sleeves are square, sharp corners */
  background: var(--tile);
  box-shadow: var(--art-drop);
}
/* An inset box-shadow on a replaced element paints behind its content, so the
   inner shadow has to be a sibling layer sitting over the image. */
.cover::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  aspect-ratio: 1 / 1;
  pointer-events: none;
  background: var(--art-depth);
}
.cover .a { font-size: 15px; margin-top: 14px; }
.cover .t { font-size: 15px; color: var(--muted); margin-top: 2px; }
.cover .a, .cover .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- the wall sleeve: a record standing in its holder ----------
   The Records wall only. Last added, Albums, Wishlist and the Lists keep the
   plain .cover with its title and artist — this is a modifier, not a new cover.
   Geometry read off the design: the lip is 77% of the sleeve's width and 5% of it
   tall, hung 3px below the bottom edge so it reads as a stand the sleeve rests in
   rather than a band across the artwork. .cover stays in the class list so the
   record overlay still picks the link up. */
.cover.on-wall img { box-shadow: var(--wall-drop); }
.cover.on-wall:is(:hover, .is-hover) img { box-shadow: var(--wall-lift); }
.cover.on-wall .holder {
  position: absolute;
  left: 11.5%; right: 11.5%; bottom: -3px;   /* clears the sleeve's bottom edge */
  height: 5%; min-height: 5px;
  border-radius: 1px;
  background: var(--holder-face);
  box-shadow: 0 0 0 1px var(--holder-edge), var(--holder-drop);
  z-index: 1;   /* over .cover::before, which paints the sleeve's bottom edge */
  transition: transform 200ms cubic-bezier(0.25, 1, 0.5, 1);
}
/* The hover lift belongs to the record, not to the stand: the sleeve rises out
   of the holder while the holder stays on the wall. Cancelling the parent's
   translate on the holder keeps the sleeve and its bottom-edge shading moving
   as one piece, which lifting the image alone would pull apart. */
.cover.on-wall:is(:hover, .is-hover) .holder { transform: translateY(3px); }

/* ---------- stacks ---------- */

.stacks { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 46px 32px; }

.stack-card { display: block; }
.stack { position: relative; display: block; height: calc(var(--sleeve) + 52px); }
.stack .sleeve::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--art-depth);
  box-shadow: inset 0 0 0 1px var(--stack-edge);
}
.stack .sleeve {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--sleeve);
  height: var(--sleeve);
  margin: calc(var(--sleeve) / -2) 0 0 calc(var(--sleeve) / -2);
  background: var(--tile);
  box-shadow: var(--stack-drop);
}
.stack .sleeve img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0; /* ADR-0016 */
}
.stack-cap { display: block; text-align: center; margin-top: 16px; }
.stack-cap .t { display: block; font-size: 17px; font-weight: 700; letter-spacing: -0.01em; }
.stack-cap .m { display: block; font-size: 14px; color: var(--muted); margin-top: 4px; }

.pill .narrow { display: none; }

/* ---------- list page ---------- */

.list-head { text-align: center; padding: 18px 0 40px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0;
  font-size: 15px;
  color: var(--ink-soft);
}
.chip img { width: 24px; height: 24px; border-radius: 50%; display: block; }
.list-head h1 { font-size: 42px; font-weight: 700; letter-spacing: -0.025em; margin: 18px 0 0; }
.list-head .desc { font-size: 18px; color: var(--ink); margin-top: 12px; }
.list-head .meta { font-size: 15px; color: var(--muted); margin-top: 9px; }

/* Shared data credit followed by the page report link. */
footer { display: flex; align-items: baseline; flex-wrap: wrap; gap: 16px; min-height: 60px; margin-top: auto; padding: 36px 0 24px; font-size: 13px; color: var(--muted); }
footer .report { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }

/* ---------- mobile ---------- */

@media (max-width: 720px) {
  :root { --sleeve: 165px; }

  :root { --profile-gutter: 16px; }
  .topbar { padding: 16px 0 4px; align-items: center; }
  .pill .wide { display: none; }
  .pill .narrow { display: inline; }
  .pill { padding: 8px 19px; }

  .identity { padding: 10px 0 20px; }
  .identity .avatar { width: 96px; height: 96px; }
  .identity .handle { font-size: 21px; }

  /* full-width tab bar with an underline on the active tab */
  .nav {
    justify-content: safe center;
    gap: 14px;
    font-size: 15.5px;
    padding-bottom: 0;
    margin: 0 -16px 26px;
    padding-left: 16px;
    padding-right: 16px;
    border-bottom: 1px solid var(--line);
    overflow-x: auto;
    scrollbar-width: none;
  }
  .nav::-webkit-scrollbar { display: none; }
  .nav a { padding-bottom: 10px; border-bottom: 2px solid transparent; margin-bottom: -1px; }
  .nav a.on { border-bottom-color: var(--ink); }

  .sec { padding-bottom: 30px; }
  .sec-head h2 { font-size: 19px; }

  /* rails: CSS scroll-snap, no carousel script */
  .grid-rec, .stacks {
    display: flex;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    margin: 0 -16px;
    padding: 0 16px 4px;
    scroll-padding: 0 16px; /* without this, snap-align:start hides the left gutter */
    scrollbar-width: none;
  }
  .grid-rec::-webkit-scrollbar, .stacks::-webkit-scrollbar { display: none; }
  .grid-rec > *, .stacks > * { flex: 0 0 96px; min-width: 0; scroll-snap-align: start; }
  .stacks > * { flex-basis: 150px; }

  /* Lists index stays a real 2-column grid */
  .stacks.two-up {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 22px 12px;
    overflow: visible;
    margin: 0;
    padding: 0;
  }
  .stacks.two-up > * { flex: none; }

  /* the single-list page grid stays a grid, 3 across */
  .grid-rec.static {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px 12px;
    overflow: visible;
    margin: 0;
    padding: 0;
  }
  .grid-rec.static > * { flex: none; }

  .list-head h1 { font-size: 28px; }
}


/* ---------- theme ----------
   Light and dark follow the browser (prefers-color-scheme); the tokens live in :root and
   its dark override at the top of this file. A manual override, if it is ever wanted,
   is a `?theme=` link + cookie on the server, never client script.
-------------------------------------------------------------------------------- */

/* ---------- section browse pages (Albums, Wishlist) ---------- */

.sec-count { font-size: 16px; color: var(--muted); }

.search { display: flex; gap: 8px; margin: 14px 0 22px; }
.search input {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--tile);
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 10px 13px;
}
.search input::placeholder { color: var(--muted); }
.search input:focus { outline: none; border-color: var(--muted); }
.search button {
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--pill-ink);
  background: var(--pill-bg);
  border: 0;
  border-radius: 8px;
  padding: 10px 18px;
  cursor: pointer;
  flex: 0 0 auto;
}

.more-btn {
  display: inline-block;
  margin-top: 26px;
  font-size: 13px;
  padding: 10px 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
}
.more-btn:hover { background: var(--tile); }

@media (max-width: 700px) {
  .search button { padding: 10px 14px; }
}

/* ---------- nav: stop the text dancing ----------
   The active tab is bolder, and bold is wider, so every tab shifted when the
   active one moved. Each tab now reserves its own bold width with a zero-height
   clone of its label, so the row is laid out once and never reflows. */

.nav a[data-tab]::after {
  content: attr(data-tab);
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: 700;
  pointer-events: none;
}

/* ---------- section tools: search and sort ---------- */

.sec-head .tools { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.sec-head .sec-count + .tools { margin-left: 14px; }

.tool { position: relative; }
.tool > summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  border-radius: 999px;
  cursor: pointer;
  color: var(--ink);
}
.tool > summary::-webkit-details-marker { display: none; }
.tool > summary:hover, .tool[open] > summary { background: var(--tile); }
.tool svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }

.sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* <details> is the whole popover mechanism — native disclosure, no script. */
.tool-pop {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: var(--z-pop);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
  padding: 6px;
}


.tool-pop.menu { width: 176px; }
.tool-pop.menu a {
  display: block;
  font-size: 13.5px;
  padding: 8px 10px;
  border-radius: 7px;
  white-space: nowrap;
}
.tool-pop.menu a:hover { background: var(--tile); }
.tool-pop.menu a.on { font-weight: 600; }
.tool-pop.menu a.on::before { content: "\2713\00a0"; }
.tool-pop.menu a:not(.on)::before { content: "\00a0\00a0\00a0"; }

/* The count belongs to the heading, not to the middle of the row. */
.sec-head .sec-count { margin-right: auto; margin-left: 10px; }
.sec-head .sec-count + .tools { margin-left: 0; }


/* ---------- search: a field that opens in place, not a floating box ----------
   The popover was a component where none was needed: a bordered, shadowed card
   holding one input. Here the icon IS the affordance and the field grows out of
   it along the header row. Nothing floats, so nothing can be clipped by an
   overflow ancestor, and there is no second surface to style or dismiss. */

.seek {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  min-width: 0;
}

.seek-field {
  font: inherit;
  font-size: 13.5px;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid transparent;
  border-radius: 0;
  padding: 6px 0;
  width: 0;
  opacity: 0;
  /* ease-out-quart: fast to open, settles rather than stops */
  transition: width 260ms cubic-bezier(0.25, 1, 0.5, 1),
              opacity 160ms cubic-bezier(0.25, 1, 0.5, 1),
              margin 260ms cubic-bezier(0.25, 1, 0.5, 1),
              border-color 160ms linear;
  margin-right: 0;
}
.seek-field::placeholder { color: var(--muted); }
.seek-field::-webkit-search-cancel-button { display: none; }

/* Focus is the only state that matters: tab to the icon, hit it, type. */
.seek-field:focus,
.seek:hover .seek-field,
.seek-field:not(:placeholder-shown) {
  width: clamp(150px, 30vw, 260px);
  opacity: 1;
  margin-right: 8px;
  border-bottom-color: var(--line);
  outline: none;
}
.seek-field:focus { border-bottom-color: var(--ink); }

.seek-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 999px;
  cursor: pointer;
  color: var(--ink);
  flex: 0 0 auto;
  transition: background 160ms linear;
}
.seek-btn:hover { background: var(--tile); }
.seek-btn svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }

/* The sort menu keeps a popover because a menu genuinely is one — but quieter:
   no heavy card, just a surface that reads as a layer. */
.tool-pop.menu {
  width: 172px;
  padding: 5px;
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.09);
}

@media (prefers-reduced-motion: reduce) {
  .seek-field { transition-duration: 1ms; }
  .seek-btn { transition-duration: 1ms; }
}

@media (max-width: 700px) {
  /* Collapsed behind the magnifier, the same as on desktop: the two icons sit
     together at the end of the heading row. Touch has no hover, but the button
     is a <label> for the field, so tapping it focuses the field and focus is
     what opens it — the same gesture, the same result. */
  .sec-head .tools, .sec-head .seek { min-width: 0; }
  /* Open, the field takes whatever the title leaves rather than a fixed width,
     so the head stays one row and nothing below it shifts. Keyed on the field's
     own focus: `:focus-within` also matched the sort button, and tapping sort
     shunted the whole toolbar down a line instead of opening its picker. */
  .sec-head:has(.seek-field:focus) .tools,
  .sec-head:has(.seek-field:not(:placeholder-shown)) .tools,
  .sec-head:has(.seek-field:focus) .seek,
  .sec-head:has(.seek-field:not(:placeholder-shown)) .seek { flex: 1 1 auto; }
  /* The toolbar is pushed right by `margin-left: auto`, and an auto margin eats
     the free space before flex-grow can have any — so the field's width: 100%
     resolved against nothing and stayed shut. Hand the space back while open. */
  .sec-head:has(.seek-field:focus) .tools,
  .sec-head:has(.seek-field:not(:placeholder-shown)) .tools { margin-left: 12px; }
  .seek-field:focus, .seek-field:not(:placeholder-shown) { width: 100%; min-width: 0; }
}

@media (max-width: 340px) {
  /* On the narrowest phones the title, the field and two fixed-width icons
     cannot all have their natural width, and the field was giving up all of it
     — 24px at 320px, too narrow to read back what you typed. Floor the field and
     let the title clip instead; its count leads, so the useful half survives.
     340px, not 380: at 360 and 375 the field already clears 100px on its own,
     and a wider net clipped the title there for nothing. */
  .sec-head:has(.seek-field:focus) h2,
  .sec-head:has(.seek-field:not(:placeholder-shown)) h2 {
    min-width: 0; overflow: hidden; text-overflow: ellipsis;
  }
  .sec-head:has(.seek-field:focus) .seek-field,
  .sec-head:has(.seek-field:not(:placeholder-shown)) .seek-field { min-width: 7rem; }
}


/* ---------- one rhythm on every page ----------
   The section head is 23px tall with only an <h2> in it and 32px once the 32px
   icon buttons arrive, so the heading and everything under it sat 3px and 9px
   lower on the pages that have tools. The row now reserves the toolbar's height
   whether or not a page uses tools, so the heading lands on the same baseline
   across the whole site and the grids start at the same y. */
.sec-head {
  min-height: 32px;
  align-items: center;
}

/* The stack box reserved 52px of slack around a centred sleeve — 26px above every
   pile — so the Lists grid appeared to fall away from its title. The fan needs
   about 10px of headroom (offset ~6.5px plus ~3px from a 2deg tilt on a 172px
   sleeve); 12px each side covers it with room to spare. */
.stack { height: calc(var(--sleeve) + 24px); }
.stack-cap { margin-top: 10px; }


/* ---------- 25% scale-up: controls track the type ---------- */
.sec-head { min-height: 38px; }
.tool > summary, .seek-btn { width: 38px; height: 38px; }
.tool svg, .seek-btn svg { width: 20px; height: 20px; }
.seek-field { font-size: 16px; padding: 8px 0; }
.tool-pop.menu { width: 200px; }
.tool-pop.menu a { font-size: 15.5px; padding: 9px 11px; }
.more-btn { font-size: 15px; padding: 11px 21px; }

/* The heading's line box is shorter than the 38px control row, so centring it
   left a sub-pixel difference between pages with tools and pages without.
   Giving the heading the row's height removes the variable entirely. */
.sec-head h2 { line-height: 38px; }
.sec-head .sec-count, .sec-head .more { line-height: 38px; }

/* The field's own line box (16px at 1.4) plus padding plus its rule came to
   39.4px and dragged the whole head row past 38. Pin it to the row height. */
.seek-field { height: 38px; padding: 0; line-height: 38px; }

@media (max-width: 700px) {
  /* A rail item's flex-basis was a flat 96px — fine for a cover, wrong for a
     stack, whose sleeve is absolutely positioned and so overflowed its own box
     and collided with its neighbour. Each kind of rail item now reserves the
     width it actually occupies. */
  :root { --sleeve: 140px; }
  .grid-rec > * { flex: 0 0 120px; }
  .stacks > * { flex: 0 0 calc(var(--sleeve) + 26px); }
}


/* ---------- identity: social links ---------- */

.identity .links { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 4px; margin-top: 14px; }
.identity .links a {
  display: inline-flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 9px; border-radius: 999px;
  color: var(--ink-soft); font-size: 14px;
  transition: color 160ms linear, background 160ms linear;
}
.identity .links a:is(:hover, .is-hover) { color: var(--ink); background: var(--tile); }
.identity .links a:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.identity .links svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- rail: six up, paged by radios ----------
   The arrows are <label>s for radio inputs and the track slides on :checked —
   no script, no URL change, no scroll jump. Each page owns an arrow pair. */

.rail-state { position: absolute; opacity: 0; pointer-events: none; }
/* The rail clips sideways so only six covers show and the track can page behind
   the edge — but `overflow: hidden` clips upward too, and it was cutting 3px off
   the top of a hovered cover along with its shadow. Pad the clip box and pull the
   padding back off the layout: the sideways clip is untouched, the lift has room. */
.rail-view { overflow: hidden; padding-top: 16px; margin-top: -16px; }
.rail-track {
  grid-template-columns: none;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 5 * var(--gap-x)) / 6);
  transition: transform 320ms cubic-bezier(0.25, 1, 0.5, 1);
}
#rail-2:checked ~ .rail-view .rail-track { transform: translateX(calc(-1 * (100% + var(--gap-x)))); }
#rail-3:checked ~ .rail-view .rail-track { transform: translateX(calc(-2 * (100% + var(--gap-x)))); }
.rail-nav { display: flex; justify-content: center; margin-top: 36px; }
.rail-nav .pg { display: none; gap: 12px; }
#rail-1:checked ~ * .pg-1, #rail-2:checked ~ * .pg-2, #rail-3:checked ~ * .pg-3,
.pg.is-shown { display: flex; }

.arrow {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer; color: var(--ink);
  transition: background 160ms linear, opacity 160ms linear;
}
.arrow:hover { background: var(--tile); }
.arrow svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.arrow.is-off { opacity: 0.28; pointer-events: none; }
.rail-state:focus-visible ~ * .arrow { outline: 2px solid var(--ink); outline-offset: 2px; }

/* The wall shows every selected record. Count-based sizing follows below. */
.grid-rec.five { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.view-all { display: flex; justify-content: center; margin-top: 36px; }
.view-all .more-btn { margin-top: 0; }

/* ---------- lists: leaf through a stack on hover ----------
   Five invisible strips sit over each pile; the strip under the pointer brings
   its sleeve to the front. The strip→sleeve order is shuffled per List. */

.stack .hz { position: absolute; top: 0; bottom: 0; width: 20%; z-index: var(--z-hover); }
.stack .hz:nth-of-type(1) { left: 0; }
.stack .hz:nth-of-type(2) { left: 20%; }
.stack .hz:nth-of-type(3) { left: 40%; }
.stack .hz:nth-of-type(4) { left: 60%; }
.stack .hz:nth-of-type(5) { left: 80%; }
.stack .sleeve { z-index: 1; transition: box-shadow 200ms cubic-bezier(0.25, 1, 0.5, 1); }
.stack .s1:hover ~ .sleeve:nth-of-type(1),
.stack .s2:hover ~ .sleeve:nth-of-type(2),
.stack .s3:hover ~ .sleeve:nth-of-type(3),
.stack .s4:hover ~ .sleeve:nth-of-type(4),
.stack .s5:hover ~ .sleeve:nth-of-type(5),
.stack .sleeve.is-raise { z-index: 2; box-shadow: var(--art-lift); }

/* ---------- the record: a route rendered over the grid ----------
   Not a dialog. The page under it is the section page, dimmed; the scrim and the
   close are links back to it, so Back works and the URL is the record. */

html:has(.panel:not(.static)) { overflow: hidden; }
.scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.38); z-index: var(--z-scrim); }
.panel {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
  /* Extend 10px past each grid edge, including when the viewport has a scrollbar. */
  width: min(calc(var(--profile-width) - 2 * var(--profile-gutter) + 20px),
             calc(100% - 2 * var(--profile-gutter) + 20px));
  max-height: calc(100vh - 48px);
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--surface); color: var(--ink);
  border-radius: 28px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.28);
  z-index: var(--z-panel);
  display: grid;
  grid-template-columns: 384px minmax(0, 1fr);
  column-gap: 56px;
  padding: 68px 108px 72px 88px;
}
.panel.static { position: static; transform: none; width: auto; max-height: none; overflow: visible; box-shadow: 0 0 0 1px var(--line); }
/* The panel scrolls, but a visible bar inside the rounded card reads as a second column. */
.panel { scrollbar-width: none; }
.panel::-webkit-scrollbar { display: none; }

/* A zero-height first row that sticks to the top of the scrolling panel; the
   close hangs off it into the top-right padding, so it never covers text. */
.panel-top { grid-column: 1 / -1; position: sticky; top: 0; height: 0; z-index: 1; }   /* sticky top is measured from the content edge: 0 = level with the body */
.panel-close {
  position: absolute; right: -88px; top: -48px;   /* 20px in from the panel's top-right corner */
  display: flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 999px;
  color: var(--ink);
  transition: background 160ms linear;
}
.panel-close:hover { background: var(--tile); }
.panel-close:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.panel-close[data-pointer-focus]:focus-visible { outline: none; }
.panel-close svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }

.panel-art { position: sticky; top: 0; align-self: start; margin: 0; }
.panel-art img { display: block; width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover; background: var(--tile); box-shadow: var(--art-drop); }
.panel-art .credit { font-size: 12px; color: var(--muted); margin-top: 10px; }

.panel-body { min-width: 0; display: flex; flex-direction: column; }
.panel-body h1 { font-size: 40px; line-height: 1.1; font-weight: 700; letter-spacing: -0.02em; margin: 0; text-wrap: balance; }
.panel-artist { font-size: 26px; color: var(--muted); margin: 6px 0 0; }
.tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.tag {
  font-family: var(--mono); font-size: 13px; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 6px 14px; border: 1px solid var(--line); border-radius: 999px;
}
.panel-h { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin: 44px 0 10px; }
.panel-h .soft { font-size: 15px; font-weight: 400; color: var(--muted); margin-left: 8px; }

.tracks { list-style: none; margin: 0; padding: 0; }
.tracks li { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; align-items: baseline; gap: 10px; padding: 9px 0; font-size: 18px; }
.tracks .pos, .tracks .dur { font-family: var(--mono); font-size: 14px; color: var(--muted); }
.tracks .tt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A checkbox drives the tracklist so its toggle can sit AFTER the list and read
   "collapse" once open — <details> always puts its summary first. */
.tracks-state { position: absolute; opacity: 0; pointer-events: none; }
.tracks-state:not(:checked) ~ .tracks li:nth-child(n+5) { display: none; }
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 14px; }
.actions .more-btn { margin-top: 0; cursor: pointer; }
.tracks-state:checked ~ .actions .when-closed,
.tracks-state:not(:checked) ~ .actions .when-open { display: none; }
.tracks-state:focus-visible ~ .actions label { outline: 2px solid var(--ink); outline-offset: 2px; }
/* Service marks: the app's own filled marks (icons/*.svg), one per streaming service, no arrow. */
.svc { display: inline-flex; width: 28px; height: 28px; color: var(--ink); border-radius: 999px; transition: opacity 160ms linear; }
.svc:hover, .svc.is-hover { opacity: 0.7; }
.svc svg { width: 28px; height: 28px; fill: currentColor; }

.released { margin: 24px 0 0; font-size: 16px; color: var(--ink-soft); }
.released time { color: var(--ink); font-weight: 500; }

.credits { margin: 36px 0 0; font-size: 13px; color: var(--muted); }
.panel-body > .credits:last-child { margin-top: auto; padding-top: 36px; }
.credits a { text-decoration: underline; text-underline-offset: 2px; }
.panel-art .tile { aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center; padding: 24px; background: var(--tile); color: var(--muted); font-size: 22px; font-weight: 600; text-align: center; }

.story { margin-top: 30px; max-width: 62ch; }
.panel-h + .story { margin-top: 14px; }
.story p { margin: 0 0 1em; font-size: 17px; line-height: 1.6; text-wrap: pretty; }
.story p:last-child { margin-bottom: 0; }

.facts { margin: 0; }
.facts div { display: flex; justify-content: space-between; align-items: baseline; gap: 24px; padding: 17px 0; }
.facts dt { color: var(--ink-soft); font-size: 18px; }
.facts dd { margin: 0; font-size: 18px; font-weight: 500; text-align: right; }

/* Between a phone and a wide desktop the two columns cannot both fit: the
   panel stacks, keeps its card, and the cover caps at its desktop width. */
@media (max-width: 1100px) {
  .panel { grid-template-columns: minmax(0, 1fr); row-gap: 28px; padding: 56px 48px; }
  .panel-top { top: 0; }
  .panel-close { right: -36px; top: -40px; }
  .panel-art { position: static; width: min(100%, 384px); }
}

@media (max-width: 720px) {
  /* Other five-column grids use three columns on mobile. */
  .grid-rec.five { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  /* Rails: no arrows, just the scroll rail — the rule above already applies. */
  .rail .rail-nav { display: none; }
  .rail-view { overflow: visible; }
  .rail-track { --gap-x: 12px; gap: var(--gap-x); }
  /* Keep three covers and half of the fourth visible beyond the left gutter. */
  .rail-track > * { flex-basis: calc((100% + var(--profile-gutter) - 3 * var(--gap-x)) / 3.5); }
  .rail .rail-state:checked ~ .rail-view .rail-track, .rail-track { transform: none; }

  /* Record: the panel is the screen. Cover on top, then everything, one close. */
  .panel {
    top: 0; left: 0; transform: none;
    width: 100%; height: 100%; max-height: none;
    border-radius: 0; box-shadow: none;
    grid-template-columns: minmax(0, 1fr); row-gap: 22px;
    padding: 16px 16px 48px;
  }
  .panel-top { top: 0; }
  .panel-close { position: fixed; top: 12px; right: 12px; background: var(--surface); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.22); }
  .panel-close:hover { background: var(--surface); }
  .panel-art { position: static; }
  .panel-body h1 { font-size: 28px; }
  .panel-artist { font-size: 20px; }
  .panel-h { font-size: 20px; margin-top: 34px; }
  .tracks li, .facts dt, .facts dd { font-size: 16px; }
  .facts div { padding: 13px 0; }
  .identity .links a { height: 32px; padding: 0 7px; }
}

@media (prefers-reduced-motion: reduce) {
  .cover, .cover img, .rail-track, .stack .sleeve, .arrow, .identity .links a, .panel-close { transition-duration: 1ms; }
  .cover:is(:hover, .is-hover) { transform: none; }
  /* No lift to cancel, so the holder must not counter-move either. */
  .cover.on-wall .holder, .cover.on-wall:is(:hover, .is-hover) .holder { transition-duration: 1ms; transform: none; }
}


/* ---------- list page: owner link and Share ----------
   The owner chip is a link to the profile. Share copies the link — page.js is
   the page's one script; the button's copied state is a class it toggles. */

.chip { transition: color 160ms linear; }
.chip:is(:hover, .is-hover) { color: var(--ink); }
.chip:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 999px; }

.share-btn {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 22px; padding: 10px 20px 10px 16px;
  font: inherit; font-size: 15px; color: var(--ink);
  background: none; border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer;
  transition: background 160ms linear, border-color 160ms linear;
}
.share-btn:hover { background: var(--tile); }
.share-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.share-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.share-btn .i-check, .share-btn.copied .i-share { display: none; }
.share-btn.copied .i-check { display: inline; }
.share-btn.copied { border-color: var(--ink); }


/* ---------- desktop profile alignment ---------- */
@media (min-width: 721px) {
  .sec-head { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); column-gap: 12px; }
  .sec-head h2 { grid-column: 2; text-align: center; }
  .sec-head .tools { grid-column: 3; justify-self: end; min-width: 0; max-width: 100%; margin-left: 0; }
  .sec-head .seek-btn, .sec-head .tool { flex-shrink: 0; }
  .sec-head:has(.seek:hover, .seek-field:focus, .seek-field:not(:placeholder-shown)) { display: flex; }
  .sec-head:has(.seek:hover, .seek-field:focus, .seek-field:not(:placeholder-shown)) .tools { margin-left: auto; }
  .grid-rec.wall { justify-content: center; }
}

/* Each cover spans two tracks. An offset of one track centers a shorter row.
   The public wall supports at most 15 records. Keep all covers the same size. */
.grid-rec.wall {
  --wall-columns: 5;
  display: grid;
  grid-template-columns: repeat(calc(2 * var(--wall-columns)), minmax(0, 1fr));
}
.grid-rec.wall > * { grid-column: span 2; }
@media (min-width: 721px) {
  .grid-rec.wall:has(> :last-child:is(:nth-child(-n + 3), :nth-child(5), :nth-child(6))) { --wall-columns: 3; }
  .grid-rec.wall:has(> :last-child:is(:nth-child(4), :nth-child(7), :nth-child(8), :nth-child(11), :nth-child(12))) { --wall-columns: 4; }
  .grid-rec.wall:has(> :only-child) > :first-child { grid-column: 3 / span 2; }
  .grid-rec.wall:has(> :last-child:nth-child(2)) > :first-child,
  .grid-rec.wall:has(> :last-child:nth-child(5)) > :nth-child(4),
  .grid-rec.wall:has(> :last-child:nth-child(7)) > :nth-child(5),
  .grid-rec.wall:has(> :last-child:nth-child(9)) > :nth-child(6),
  .grid-rec.wall:has(> :last-child:nth-child(11)) > :nth-child(9),
  .grid-rec.wall:has(> :last-child:nth-child(13)) > :is(:nth-child(6), :nth-child(10)),
  .grid-rec.wall:has(> :last-child:nth-child(14)) > :nth-child(11) { grid-column: 2 / span 2; }
}
@media (max-width: 720px) {
  .grid-rec.wall { --wall-columns: 3; gap: 18px 12px; }
  .grid-rec.wall:has(> :last-child:is(:nth-child(-n + 2), :nth-child(4))) { --wall-columns: 2; }
  .grid-rec.wall:has(> :only-child) > :first-child,
  .grid-rec.wall:has(> :last-child:nth-child(5)) > :nth-child(4),
  .grid-rec.wall:has(> :last-child:nth-child(7)) > :is(:nth-child(4), :nth-child(6)),
  .grid-rec.wall:has(> :last-child:nth-child(8)) > :nth-child(7),
  .grid-rec.wall:has(> :last-child:nth-child(10)) > :is(:nth-child(7), :nth-child(9)),
  .grid-rec.wall:has(> :last-child:nth-child(11)) > :nth-child(10),
  .grid-rec.wall:has(> :last-child:nth-child(13)) > :is(:nth-child(10), :nth-child(12)),
  .grid-rec.wall:has(> :last-child:nth-child(14)) > :nth-child(13) { grid-column: 2 / span 2; }
}


/* ---------- live page additions (PLA2-1042) ---------- */

/* The fan behind a stack's top sleeve. Classes, not the prototype's inline transforms, so the
   page keeps style-src 'self'. Same hand-tuned offsets, without the per-List jitter. */
.stack .sleeve.f1 { transform: translate(-12px, 4px) rotate(-1.8deg); }
.stack .sleeve.f2 { transform: translate(6px, -4px) rotate(1.45deg); }
.stack .sleeve.f3 { transform: translate(-5px, 1px) rotate(-1.31deg); }
.stack .sleeve.f4 { transform: translate(2px, 0) rotate(2deg); }

/* The no-photo avatar uses the same line icon at profile and chip size. */
.chip .chip-avatar.placeholder-avatar { width: 24px; height: 24px; }

/* A record without an allowlisted cover: its title and artist typeset on the tile colour, in
   the sleeve's square. Never a stand-in image. Takes the same drop, lift and wall shadow. */
.cover-tile {
  display: flex; flex-direction: column; justify-content: flex-end; gap: 4px;
  width: 100%; aspect-ratio: 1 / 1; padding: 14px; overflow: hidden;
  background: var(--tile); box-shadow: var(--art-drop);
  transition: box-shadow 200ms cubic-bezier(0.25, 1, 0.5, 1);
}
.cover-tile .ct-a, .cover-tile .ct-t {
  display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere;
}
.cover-tile .ct-a { font-size: 17px; font-weight: 700; line-height: 1.2; letter-spacing: -0.01em; color: var(--ink); -webkit-line-clamp: 4; }
.cover-tile .ct-t { font-size: 14px; line-height: 1.25; color: var(--muted); -webkit-line-clamp: 2; }
.cover:is(:hover, .is-hover) .cover-tile { box-shadow: var(--art-lift); }
.cover.on-wall .cover-tile { box-shadow: var(--wall-drop); }
.cover.on-wall:is(:hover, .is-hover) .cover-tile { box-shadow: var(--wall-lift); }
.stack .sleeve .cover-tile { height: 100%; box-shadow: none; justify-content: center; text-align: center; }

/* Album artwork is always square-cornered (ADR-0016), app-wide: grid and rail covers, wall
   sleeves, stack sleeves, the record panel's art and the cover-less text tile. Buttons, chips,
   pills, avatars and the panel card keep their own radii. */
.cover img, .cover-tile, .stack .sleeve, .stack .sleeve img, .panel-art img, .panel-art .tile { border-radius: 0; }

/* Show more: a link to the next page; public-profile.js appends it in place. */
.show-more .more-btn[aria-busy="true"] { opacity: 0.5; pointer-events: none; }

/* Cover credits under a grid: one span per distinct attribution. */
.grid-credits span + span::before { content: "\0020\00b7\0020"; }

@media (max-width: 720px) {
  .cover-tile { padding: 8px; gap: 2px; }
  .cover-tile .ct-a { font-size: 12.5px; -webkit-line-clamp: 3; }
  .cover-tile .ct-t { font-size: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  .cover-tile { transition-duration: 1ms; }
}

.ios-return { margin: 16px 0; padding: 16px; border: 1px solid currentColor; }
.ios-return[hidden] { display: none; }
.ios-return p { margin: 0 0 12px; }
.ios-return button { font: inherit; cursor: pointer; }

/* PLA2-1321: public collections use a horizontal preview, with metadata below it on mobile. */
.collection-row {
  --collection-cover-size: 176px;
  --collection-secondary: #616167;
  display: grid;
  grid-template-columns: minmax(0, 43%) minmax(0, 1fr);
  gap: 44px;
  align-items: center;
  padding: 30px 0;
  border-bottom: 1px solid var(--line);
}
.collection-row:first-child { padding-top: 12px; }
.collection-row:last-child { border-bottom: 0; }
.collection-row:focus-visible { outline: 2px solid var(--ink); outline-offset: 7px; }
.collection-art {
  --gaps: 1;
  position: relative;
  display: block;
  width: 100%;
  max-width: 100%;
  height: var(--collection-cover-size);
  overflow: hidden;
  border-radius: 8px;
  isolation: isolate;
}
.collection-art[data-cover-count="0"], .collection-art[data-cover-count="1"] { width: var(--collection-cover-size); }
.collection-art[data-cover-count="3"] { --gaps: 2; }
.collection-art[data-cover-count="4"] { --gaps: 3; }
.collection-art[data-cover-count="5"] { --gaps: 4; }
.collection-art[data-cover-count="6"] { --gaps: 5; }
.collection-art[data-cover-count="7"] { --gaps: 6; }
.collection-art[data-cover-count="8"] { --gaps: 7; }
.collection-art[data-cover-count="9"] { --gaps: 8; }
.collection-art[data-cover-count="10"] { --gaps: 9; }
.collection-sleeve {
  --position: 0;
  position: absolute;
  top: 0;
  left: calc((100% - var(--collection-cover-size)) * var(--position) / var(--gaps));
  width: var(--collection-cover-size);
  height: var(--collection-cover-size);
  z-index: calc(10 - var(--position));
  box-shadow: -2px 0 4px rgb(0 0 0 / 18%);
}
.collection-sleeve:nth-child(2) { --position: 1; }
.collection-sleeve:nth-child(3) { --position: 2; }
.collection-sleeve:nth-child(4) { --position: 3; }
.collection-sleeve:nth-child(5) { --position: 4; }
.collection-sleeve:nth-child(6) { --position: 5; }
.collection-sleeve:nth-child(7) { --position: 6; }
.collection-sleeve:nth-child(8) { --position: 7; }
.collection-sleeve:nth-child(9) { --position: 8; }
.collection-sleeve:nth-child(10) { --position: 9; }
.collection-sleeve img { display: block; width: 100%; height: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 0; }
.collection-copy { min-width: 0; padding: 8px 0; }
.collection-copy h2 { margin: 0; font-size: 24px; font-weight: 650; line-height: 1.18; letter-spacing: -.02em; text-wrap: balance; overflow-wrap: anywhere; }
.collection-description { overflow-wrap: anywhere; max-width: 46ch; margin: 12px 0 0; color: var(--collection-secondary); font-size: 16px; line-height: 1.45; text-wrap: pretty; }
.collection-count { display: block; margin-top: 16px; color: var(--collection-secondary); font-size: 14px; font-variant-numeric: tabular-nums; }
.collection-row:hover h2 { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 5px; }
@media (max-width: 800px) {
  .collection-row { --collection-cover-size: 138px; gap: 26px; grid-template-columns: minmax(0, 44%) minmax(0, 1fr); }
  .collection-copy h2 { font-size: 22px; }
}
@media (max-width: 720px) {
  .collection-row { --collection-cover-size: clamp(144px, 46vw, 240px); grid-template-columns: minmax(0, 1fr); gap: 16px; padding: 24px 0; align-items: start; }
  .collection-copy { padding: 0; }
  .collection-copy h2 { font-size: 20px; }
}
@media (max-width: 560px) {
  .collection-copy h2 { font-size: 19px; }
  .collection-description { font-size: 14px; margin-top: 8px; line-height: 1.4; }
  .collection-count { font-size: 13px; margin-top: 10px; }
}
@media (prefers-color-scheme: dark) {
  .collection-row { --collection-secondary: #b8b8bf; }
  .collection-sleeve { box-shadow: -2px 0 4px rgb(0 0 0 / 60%); }
}
