/* =====================================================================
   MuNi — Music Nights
   A single-page static archive. No framework, no build step.

   Contents
   1.  Design tokens (custom properties)
   2.  Reset & base
   3.  Utilities
   4.  Hero
   5.  Section labels & shared editorial bits
   6.  Playlist rail
   7.  Archive
   8.  People
   9.  Playlist overlay (dialog)
   10. Footer
   11. Reduced motion
   ===================================================================== */

/* ------------------------------------------------- 1. Design tokens -- */
:root {
  /* Colour ------------------------------------------------------------ */
  --ink:          #131211;  /* page background, near-black             */
  --ink-raised:   #1A1917;  /* charcoal, one step up                   */
  --ink-deep:     #0B0B0A;  /* backdrop / crop areas                   */
  --paper:        #F2EDE4;  /* warm off-white, primary type            */
  --paper-muted:  #A49C90;  /* metadata type            — 6.9:1 on ink */
  --paper-faint:  #837C74;  /* labels, table headers    — 4.6:1 on ink */
  --paper-on-img: #C9C2B7;  /* caption type over a photograph          */
  --rule:         rgba(242, 237, 228, 0.16);
  --rule-soft:    rgba(242, 237, 228, 0.08);
  --scrim:        rgba(11, 11, 10, 0.82);
  --focus:        #D8B36A;  /* warm ochre focus ring                   */

  /* Type -------------------------------------------------------------- */
  --font-sans: "Helvetica Neue", Helvetica, Inter, "Arial Nova", Arial,
               system-ui, -apple-system, "Segoe UI", sans-serif;

  --fs-3xs:  0.6875rem;  /* 11px  — micro labels                       */
  --fs-2xs:  0.75rem;    /* 12px  — table headers                      */
  --fs-xs:   0.8125rem;  /* 13px  — metadata                           */
  --fs-sm:   0.875rem;   /* 14px                                        */
  --fs-base: 1rem;       /* 16px  — body                               */
  --fs-lg:   clamp(1.625rem, 1.2rem + 2vw, 2.75rem);     /* archive titles  */
  --fs-xl:   clamp(2.25rem, 1.5rem + 3.6vw, 4.5rem);     /* overlay title   */
  --fs-tagline: clamp(0.9375rem, 0.84rem + 0.44vw, 1.125rem);

  --tracking-label: 0.14em;

  /* Spacing ----------------------------------------------------------- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: clamp(3.5rem, 7vw, 6rem);
  --space-9: clamp(5rem, 11vw, 9rem);     /* people/overlay block spacing */
  --space-10: clamp(5.5rem, 12vw, 10rem); /* between sections            */
  --space-archive: clamp(7rem, 13vw, 12rem); /* between archive entries, wider
                                                 than --space-9: a gallery-wall
                                                 pace, not a database row     */

  /* Page margins ------------------------------------------------------ */
  --margin-x: clamp(1.25rem, 4.2vw, 4.5rem);
  --content-max: 1600px;

  /* Rail item width --------------------------------------------------- */
  --rail-item-w: 34vw;

  /* Transitions ------------------------------------------------------- */
  --ease: cubic-bezier(0.22, 0.7, 0.26, 1);
  --dur-fast: 160ms;
  --dur: 320ms;
  --dur-slow: 720ms;

  /* Image ratios ------------------------------------------------------ */
  /* Covers are square everywhere: the rail, the archive, the overlay.
     Photographs keep their own ratio, taken from data/photos.js.        */
  --ratio-cover: 1 / 1;
}

/* ------------------------------------------------- 2. Reset & base --- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* keeps #archive / #people from landing under nothing in particular */
  scroll-padding-top: var(--space-6);
}

body {
  margin: 0;
  background-color: var(--ink);
  color: var(--paper);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.5;
  font-weight: 400;
  letter-spacing: 0.005em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Safety net: only the playlist rail may scroll sideways.
     `clip` (not `hidden`) so position: sticky keeps working.            */
  overflow-x: clip;
}

/* Scroll lock while the playlist overlay is open. */
body.is-locked {
  position: fixed;
  inset-inline: 0;
  width: 100%;
  overflow-y: scroll; /* keep the scrollbar gutter, avoids a width jump */
}

h1, h2, h3, h4, p, figure, dl, dd, ul { margin: 0; padding: 0; }
ul { list-style: none; }

img {
  display: block;
  max-width: 100%;
  height: auto;
  background-color: var(--ink-raised);
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  margin: 0;
  padding: 0;
  cursor: pointer;
}

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

table { border-collapse: collapse; }

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

::selection {
  background-color: var(--paper);
  color: var(--ink);
}

/* ---------------------------------------------------- 3. Utilities --- */
.visually-hidden:not(:focus):not(:active) {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
  z-index: 100;
  padding: var(--space-2) var(--space-4);
  background-color: var(--paper);
  color: var(--ink);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }

.noscript {
  padding: var(--space-8) var(--margin-x);
  color: var(--paper-muted);
  max-width: 42ch;
}

/* -------------------------------------------------------- 4. Hero --- */
.hero {
  position: relative;
  display: grid;
  grid-template-columns: 46fr 54fr;
  min-height: 100svh;
  background-color: var(--ink);
  /* the wordmark deliberately bleeds past the right edge */
  overflow: clip;
}

.hero__panel {
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: var(--margin-x);
  position: relative;
  z-index: 2;
}

/* Navigation — Archive / People only, always visible, always side by
   side (not stacked) at every breakpoint. */
.nav__list {
  display: flex;
  flex-direction: row;
  gap: var(--space-6);
  align-items: center;
}

.nav__link {
  display: inline-block;
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--paper);
  padding-block: 2px;
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.nav__link:hover { border-bottom-color: var(--paper); }

.hero__tagline {
  grid-row: 3;
  align-self: end;
  /* wide enough to hold the intended two-line break on one line each */
  max-width: 44ch;
  font-size: var(--fs-tagline);
  line-height: 1.42;
  color: var(--paper);
}

.hero__since {
  display: block;
  margin-top: var(--space-4);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--paper-muted);
}

/* The oversized typographic panel ------------------------------------- */
/* Not clipped: the wordmark is allowed to reach left, across the panel.
   The hero itself clips, so nothing escapes the viewport. No background
   of its own — it shares the same flat --ink as the rest of the hero,
   so there's no darker box sitting visibly behind the type. */
.hero__art {
  position: relative;
  /* Lets .hero__logo's right margin below be expressed in cqh (a % of
     *this element's* height) — plain % margins resolve against the
     containing block's width even on the left/right sides, which can't
     track a height-based gap the way this needs to. */
  container-type: size;
}

/* Anchored to the right edge with a hair of bleed, so the logo runs
   across the panel: architectural, tightly cropped, full height.
   width: fit-content — explicitly, not left to the flex container to
   work out — so the box genuinely shrinks to the image's own rendered
   width. An absolutely positioned flex container with only `right` set
   doesn't reliably shrink-to-fit on its own, which left the logo capped
   at the panel's width instead of its natural (square) aspect ratio.
   flex + justify-content: center gives the logo equal top/bottom
   breathing room (see .hero__logo) without CSS margin percentages,
   which resolve against the container's *width*, not its height — the
   wrong axis for a vertical gap that has to track a responsive height. */
.hero__wordmark {
  position: absolute;
  top: 0;
  bottom: 0;
  right: -0.02em;
  left: auto;
  width: fit-content;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Prevents the flex column from stretching .hero__logo-wrap to fill
     this box's cross-axis width — this box's own width is fit-content,
     derived FROM the wrapper's width, so stretching would be circular. */
  align-items: flex-start;
  pointer-events: none;
  user-select: none;
}

/* Owns the load-in fade/zoom, sizing, and positioning — kept separate
   from .hero__logo (the img) so that entrance motion and the hover zoom
   below can each transition independently. A @keyframes animation and a
   :hover transition fighting over the same element's transform is what
   the previous single-layer version ran into: an animation's held end
   value (via fill-mode) outranks a plain author rule indefinitely, so
   hovering either did nothing or needed !important — which then made
   the hover itself snap instead of ease, since forcing a value past a
   competing animation origin doesn't go through the normal transition
   pipeline. Two elements, two transforms, no conflict.

   Sized to leave equal top/bottom breathing room around the logo,
   matching the gap the artwork already has between its own two rows of
   letters (measured from the source SVG: that inter-row gap is ~3.37%
   of the glyphs' total height). Solving so the logo plus both margins
   still fill the wordmark box exactly gives a 93.684% height, which —
   centered by the flex column above — leaves 3.158% of the box's
   height free on each side, reproducing that same ratio. If the
   artwork is ever redrawn with a different internal row-gap, remeasure
   and adjust this value; it isn't derived at runtime.

   width: fit-content, again explicitly rather than left to the flex
   item's own auto-sizing, for the same shrink-to-fit reason as the
   wordmark box itself above. */
.hero__logo-wrap {
  display: block;
  width: fit-content;
  height: 93.684%;
  /* Same 3.158% gap as top/bottom, but held off the right edge instead —
     cqh so it tracks .hero__art's height, not this box's own width
     (which is what a plain % margin would use here). Desktop/tablet
     only: the mobile override below resets it, since mobile already
     sits inside the page's ordinary side margins. */
  margin-right: 3.158cqh;
  opacity: 0;
  transform: scale(0.97);
  transition: opacity 900ms var(--ease), transform 900ms var(--ease);
}
.hero__logo-wrap.is-visible { opacity: 1; transform: scale(1); }

/* max-width: none overrides the global img reset (max-width: 100%),
   which would otherwise cap it at its fit-content parent's width —
   circular against the very thing that parent's width is derived from.
   background: none overrides the same reset's background-color (a
   loading tint meant for photo covers) — the logo's negative space is
   transparent, so that tint would show through as a mismatched box
   against the hero's flat background. pointer-events: auto re-enables
   hit-testing specifically here, since .hero__wordmark above (purely
   decorative type, by default) turns it off. */
.hero__logo {
  display: block;
  height: 100%;
  width: auto;
  max-width: none;
  background: none;
  pointer-events: auto;
  transition: transform var(--dur) var(--ease);
}

/* Same tiny hover zoom as the playlist covers (.entry__cover) — same
   duration, same easing, no !important needed now that entrance and
   hover motion are on separate elements. */
.hero__logo:hover { transform: scale(1.025); }

/* Tablet ---------------------------------------------------------- */
@media (max-width: 1023px) {
  .hero { grid-template-columns: 42fr 58fr; }
}

/* Mobile — recomposed vertically, not merely shrunk ---------------- */
@media (max-width: 767px) {
  .hero {
    grid-template-columns: 1fr;
    grid-template-rows: auto minmax(0, 1fr) auto;
    min-height: 100svh;
  }

  /* lets the nav and the tagline sit either side of the artwork */
  .hero__panel { display: contents; }

  .nav {
    grid-row: 1;
    padding: var(--margin-x) var(--margin-x) var(--space-6);
    z-index: 2;
  }

  .hero__art { grid-row: 2; min-height: 46svh; }

  /* Desktop lets the logo bleed past the edge by height alone — on a
     narrow phone that crops it down to one letter and slivers of the
     next, which reads as broken rather than architectural. Here it's
     width-constrained instead: full logo visible, fit between the same
     margins as everything else. top/bottom stay 0 (from the base rule)
     so the box still spans the full strip height and the flex column's
     justify-content: center still centers the (now shorter) logo
     vertically within it. */
  .hero__wordmark {
    left: var(--margin-x);
    right: var(--margin-x);
    width: auto;
  }

  .hero__logo-wrap {
    width: auto;
    height: auto;
    margin-right: 0;
  }

  .hero__logo {
    height: auto;
    width: 100%;
    max-width: 100%;
  }

  .hero__tagline {
    grid-row: 3;
    max-width: none;
    padding: var(--space-6) var(--margin-x) var(--margin-x);
  }
  .hero__since { margin-top: var(--space-3); }
}

/* ------------------------------- 5. Section labels & shared bits ----- */
.section-label {
  font-size: var(--fs-2xs);
  font-weight: 400;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--paper-faint);
}

.rail-section,
.archive,
.people { padding-block: var(--space-10); }

.rail-section { padding-block: var(--space-10) var(--space-7); }
.people { padding-block-end: var(--space-9); }

.archive,
.people {
  padding-inline: var(--margin-x);
  max-width: var(--content-max);
  margin-inline: auto;
}

.archive > .section-label,
.people > .section-label {
  margin-bottom: var(--space-7);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--rule-soft);
}

/* Metadata definition lists ------------------------------------------- */
.meta-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--fs-xs);
  line-height: 1.45;
  --label-w: 5.25rem;
}

/* one label/value pair per row */
.meta-row {
  display: grid;
  grid-template-columns: var(--label-w) minmax(0, 1fr);
  column-gap: var(--space-4);
  align-items: baseline;
}

.meta-list dt {
  color: var(--paper-faint);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  font-size: var(--fs-3xs);
  white-space: nowrap;
}

.meta-list dd {
  color: var(--paper-muted);
  margin: 0;
  overflow-wrap: anywhere;
}

/* -------------------------------------------- 6. Playlist rail ------- */
.rail-wrap { position: relative; }

.rail {
  display: flex;
  gap: clamp(var(--space-5), 3vw, var(--space-8));
  padding-inline: var(--margin-x);
  padding-block: var(--space-2) var(--space-4);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: var(--margin-x);
  scrollbar-width: thin;
  scrollbar-color: var(--rule) transparent;
  cursor: grab;
}
.rail::-webkit-scrollbar { height: 3px; }
.rail::-webkit-scrollbar-track { background: transparent; }
.rail::-webkit-scrollbar-thumb { background: var(--rule); }

.rail.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none;
  user-select: none;
}

.rail__item {
  flex: 0 0 var(--rail-item-w);
  scroll-snap-align: start;
}

.rail__button {
  display: block;
  width: 100%;
  text-align: left;
}

.rail__frame {
  display: block;
  overflow: clip;
  aspect-ratio: var(--ratio-cover);
  background-color: var(--ink-raised);
}

.rail__cover {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur) var(--ease),
              opacity var(--dur) var(--ease);
}

.rail__button:hover .rail__cover,
.rail__button:focus-visible .rail__cover { transform: scale(1.028); }

.rail__caption {
  display: flex;
  gap: var(--space-4);
  align-items: baseline;
  margin-top: var(--space-4);
}

.rail__year {
  font-size: var(--fs-xs);
  color: var(--paper-faint);
  font-variant-numeric: tabular-nums;
  flex: none;
  transition: color var(--dur-fast) var(--ease);
}

.rail__title {
  font-size: var(--fs-sm);
  color: var(--paper);
  line-height: 1.3;
  /* matches the archive entry's interaction language: an underline that
     follows the text, not a box or a rule */
  text-decoration: underline 1px transparent;
  text-underline-offset: 0.16em;
  transition: text-decoration-color var(--dur) var(--ease);
}

.rail__button:hover .rail__year,
.rail__button:focus-visible .rail__year { color: var(--paper-muted); }
.rail__button:hover .rail__title,
.rail__button:focus-visible .rail__title { text-decoration-color: var(--paper); }

/* No tracklist yet: rendered as a plain (non-focusable) div rather than
   a button, so it doesn't open an overlay — cancel the hover feedback
   above too, or the cover/title would still imply it's clickable. */
.rail__button--static:hover .rail__cover { transform: none; }
.rail__button--static:hover .rail__year { color: var(--paper-faint); }
.rail__button--static:hover .rail__title { text-decoration-color: transparent; }

@media (max-width: 1023px) { :root { --rail-item-w: 64vw; } }
@media (max-width: 767px)  { :root { --rail-item-w: 82vw; } }

/* ------------------------------------------------- 7. Archive -------- */
.archive__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-archive);
}

.entry {
  position: relative;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--space-6);
  /* top-aligned, not centred: entries of different cover sizes (below)
     should stagger against each other like a hung wall, not line up
     like rows in a table */
  align-items: start;
}

/* Gentle entrance as an entry scrolls into view, matching the People
   section's rhythm. Toggled by observeEntrance() in app.js. */
.entry--reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity var(--dur-slow) var(--ease),
              transform var(--dur-slow) var(--ease);
}
.entry--reveal.is-visible { opacity: 1; transform: none; }

.entry__figure { grid-column: 1 / span 5; }
.entry__body   { grid-column: 7 / span 5; }

/* alternating rhythm: cover left, then cover right, then left … */
.entry:nth-child(even) .entry__figure { grid-column: 8 / span 5; grid-row: 1; }
.entry:nth-child(even) .entry__body   { grid-column: 1 / span 5; grid-row: 1; text-align: right; }

/* mirrored ledger: the label column hugs the outer edge */
.entry:nth-child(even) .meta-row {
  grid-template-columns: minmax(0, 1fr) var(--label-w);
}
.entry:nth-child(even) .meta-list dt { order: 2; }
.entry:nth-child(even) .meta-list dd { order: 1; }

/* Cover size varies on a 6-entry rhythm (standard → large → small, on
   both sides) so the archive reads as a hung wall of different-sized
   pieces rather than a repeating database row. Each pair keeps the same
   two reserved "breathing" columns as the standard case — one between
   cover and text, one at the outer edge — just redistributed as the
   cover grows or shrinks. Desktop only (>899px); mobile stacks everything
   full-width regardless of variant. */
.entry:nth-child(6n+2) .entry__figure { grid-column: 7 / span 6; }
.entry:nth-child(6n+2) .entry__body   { grid-column: 1 / span 4; }

.entry:nth-child(6n+3) .entry__figure { grid-column: 1 / span 4; }
.entry:nth-child(6n+3) .entry__body   { grid-column: 6 / span 6; }

.entry:nth-child(6n+5) .entry__figure { grid-column: 1 / span 6; }
.entry:nth-child(6n+5) .entry__body   { grid-column: 8 / span 4; }

.entry:nth-child(6n) .entry__figure   { grid-column: 9 / span 4; }
.entry:nth-child(6n) .entry__body     { grid-column: 1 / span 6; }

.entry__frame {
  display: block;
  overflow: clip;
  aspect-ratio: var(--ratio-cover);
  background-color: var(--ink-raised);
}

.entry__cover {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease);
}

.entry__title {
  font-size: var(--fs-lg);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.08;
  text-wrap: balance;
  margin-bottom: var(--space-5);
}

/* The whole entry is one target: this button's ::after covers it. */
.entry__link {
  text-align: inherit;
  /* underline follows the text itself rather than the button box */
  text-decoration: underline 1px transparent;
  text-underline-offset: 0.14em;
  transition: text-decoration-color var(--dur) var(--ease);
}
.entry__link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.entry:hover .entry__cover { transform: scale(1.025); }
.entry:hover .entry__link  { text-decoration-color: var(--paper); }
.entry:hover .meta-list dd { color: var(--paper); }
.entry:has(.entry__link:focus-visible) .entry__link { text-decoration-color: var(--paper); }

/* No tracklist yet: the title renders as plain text (no .entry__link),
   so there's no click target at all — cancel the whole-card hover
   feedback above too, or the entry would still look clickable. */
.entry--static:hover .entry__cover { transform: none; }
.entry--static:hover .meta-list dd { color: var(--paper-muted); }

.entry__link:focus-visible { outline: none; }
.entry:has(.entry__link:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: clamp(0.75rem, 2vw, 1.5rem);
}

.meta-list dd { transition: color var(--dur-fast) var(--ease); }

/* Tablet & mobile: stack, drop the alternation, keep the air. */
@media (max-width: 899px) {
  .archive__list { gap: var(--space-8); }

  .entry,
  .entry:nth-child(even) {
    display: block;
  }
  /* the desktop size-variant rules (6n+2/3/5/6n) carry the same
     specificity as :nth-child(even) and aren't scoped to a media query,
     so they must be named here explicitly to be reset on mobile too */
  .entry__figure,
  .entry:nth-child(even) .entry__figure,
  .entry:nth-child(6n+2) .entry__figure,
  .entry:nth-child(6n+3) .entry__figure,
  .entry:nth-child(6n+5) .entry__figure,
  .entry:nth-child(6n) .entry__figure,
  .entry__body,
  .entry:nth-child(even) .entry__body,
  .entry:nth-child(6n+2) .entry__body,
  .entry:nth-child(6n+3) .entry__body,
  .entry:nth-child(6n+5) .entry__body,
  .entry:nth-child(6n) .entry__body {
    grid-column: auto;
    grid-row: auto;
    text-align: left;
  }
  .entry:nth-child(even) .meta-row {
    grid-template-columns: var(--label-w) minmax(0, 1fr);
  }
  .entry:nth-child(even) .meta-list dt { order: 1; }
  .entry:nth-child(even) .meta-list dd { order: 2; }

  .entry__figure { max-width: 30rem; }
  .entry__body { padding-top: var(--space-5); }
  .entry__title { margin-bottom: var(--space-4); }
  .meta-list { max-width: 30rem; }
}

/* ------------------------------------------------- 8. People --------- */
.people__gallery {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  row-gap: var(--space-9);
  column-gap: var(--space-6);
}

.photo {
  position: relative;
  grid-column: var(--col-start, 1) / span var(--col-span, 5);
  grid-row: var(--row, auto);
  /* a small vertical nudge keeps the composition from settling into rows */
  margin-top: var(--nudge, 0);
  opacity: 0;
  transform: translateY(28px);
  transition: opacity var(--dur-slow) var(--ease),
              transform var(--dur-slow) var(--ease);
}
.photo.is-visible { opacity: 1; transform: none; }

.photo__image {
  width: 100%;
  height: auto;
  transition: opacity var(--dur) var(--ease);
}

/* Invisible control sitting over the photograph: a hover target for
   pointers, a focus target for keyboards, a pin/unpin toggle on click. */
.photo__trigger {
  position: absolute;
  inset: 0;
  z-index: 2;
}

.photo__meta {
  z-index: 1;
  font-size: var(--fs-xs);
  line-height: 1.55;
  color: var(--paper-muted);
  pointer-events: none;
}

.photo__meta b,
.photo__meta span { display: block; }

.photo__meta b {
  font-weight: 400;
  color: var(--paper);
}

.photo__people { color: var(--paper-faint); }

/* Pointer devices: metadata is a restrained overlay on the image. */
@media (hover: hover) and (pointer: fine) {
  .photo__meta {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    padding: var(--space-5);
    background-color: var(--scrim);
    /* lifted off the muted ink values: the backdrop here is a photograph,
       not the page, so the type has to hold up over any image */
    color: var(--paper-on-img);
    opacity: 0;
    transition: opacity var(--dur) var(--ease);
  }
  .photo__meta .photo__people { color: var(--paper-on-img); }
  .photo:hover .photo__meta,
  .photo:focus-within .photo__meta,
  .photo.is-open .photo__meta { opacity: 1; }
  .photo:hover .photo__image { opacity: 0.92; }
}

/* Touch / no-hover: metadata is permanently visible beneath the
   photograph, so nothing essential depends on hovering. The overlay
   control has no job here and is removed. */
@media not all and (hover: hover) and (pointer: fine) {
  .photo__meta { padding-top: var(--space-4); }
  .photo__trigger { display: none; }
}

@media (max-width: 899px) {
  .people__gallery { row-gap: var(--space-8); }
  .photo {
    grid-column: 1 / -1;
    grid-row: auto;
    margin-top: 0;
    /* a gentle left/right offset keeps the rhythm without a rigid grid */
    margin-inline-start: var(--offset-start, 0);
    margin-inline-end: var(--offset-end, 0);
  }
  .photo--right  { --offset-start: 12%; --offset-end: 0; }
  .photo--left   { --offset-start: 0; --offset-end: 12%; }
  .photo--centre { --offset-start: 6%; --offset-end: 6%; }
}

@media (max-width: 479px) {
  .photo--right, .photo--left, .photo--centre {
    --offset-start: 0;
    --offset-end: 0;
  }
}

/* -------------------------------------- 9. Playlist overlay ---------- */
.overlay {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background-color: var(--ink);
  color: var(--paper);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.overlay::backdrop { background-color: rgba(11, 11, 10, 0.88); }

/* restrained entrance */
.overlay[open] { animation: overlay-in var(--dur) var(--ease); }
@keyframes overlay-in {
  from { opacity: 0; transform: translateY(1.25rem); }
  to   { opacity: 1; transform: none; }
}

.overlay__inner {
  max-width: var(--content-max);
  margin-inline: auto;
  padding: var(--space-5) var(--margin-x) var(--space-10);
}

.overlay__bar {
  position: sticky;
  top: 0;
  z-index: 3;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-5);
  padding-block: var(--space-4);
  margin-bottom: var(--space-8);
  background-color: var(--ink);
  border-bottom: 1px solid var(--rule-soft);
}

.overlay__close {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--paper);
  padding-block: var(--space-2);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease);
}
.overlay__close:hover { border-bottom-color: var(--paper); }

.overlay__index {
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--paper-faint);
  font-variant-numeric: tabular-nums;
}

.overlay__head {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--space-6);
  align-items: start;
  margin-bottom: var(--space-9);
}

.overlay__cover {
  grid-column: 1 / span 5;
  aspect-ratio: var(--ratio-cover);
  overflow: clip;
  background-color: var(--ink-raised);
}
.overlay__cover img { width: 100%; height: 100%; object-fit: cover; }

.overlay__meta { grid-column: 7 / span 6; }

.overlay__title {
  font-size: var(--fs-xl);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.03em;
  text-wrap: balance;
  margin-bottom: var(--space-7);
}
.overlay__title:focus-visible { outline-offset: 6px; }

.meta-list--overlay {
  row-gap: var(--space-4);
  font-size: var(--fs-sm);
  max-width: 46ch;
}
.meta-list--overlay dt { padding-top: 0.25em; }

.overlay__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 26%);
  column-gap: var(--space-8);
  align-items: start;
}

/* No Spotify link on this playlist: the Listen column is removed
   entirely (not just emptied), so the tracklist takes the full width
   rather than leaving a dead column beside it. */
.overlay__body--tracks-only {
  grid-template-columns: minmax(0, 1fr);
}

.overlay__tracks > .section-label,
.overlay__player > .section-label {
  display: block;
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--rule-soft);
  margin-bottom: var(--space-4);
}

.overlay__player {
  position: sticky;
  top: calc(var(--space-8) + var(--space-4));
}

.player-slot iframe {
  display: block;
  width: 100%;
  height: clamp(360px, 46svh, 460px);
  border: 0;
  /* Spotify's own dark embed (theme=0) renders at #121212, effectively
     identical to --ink — matching it here avoids a flash of a lighter
     tone while the iframe loads. True transparency isn't possible: the
     iframe's content is cross-origin, so our CSS can't reach inside it. */
  background-color: var(--ink);
  /* Spotify's card has rounded corners on a white page background — the
     white peeks through in the four corners of the iframe's box. This
     clips the iframe's own rendered box (not its cross-origin content,
     which we can't touch), hiding the white behind our matching --ink. */
  border-radius: 12px;
  overflow: hidden;
}

/* Tracklist ----------------------------------------------------------- */
.tracklist { width: 100%; font-size: var(--fs-sm); }

.tracklist thead th {
  text-align: left;
  font-weight: 400;
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--paper-faint);
  padding-block: var(--space-3);
  border-bottom: 1px solid var(--rule);
}

.tracklist td {
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: baseline;
}

.tracklist .col-num {
  width: 3.5rem;
  color: var(--paper-faint);
  font-variant-numeric: tabular-nums;
}
.tracklist .col-title { color: var(--paper); }
.tracklist .col-artist,
.tracklist .col-picked { color: var(--paper-muted); }
.tracklist .col-time {
  text-align: right;
  color: var(--paper-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  width: 5rem;
}
.tracklist tbody tr { transition: background-color var(--dur-fast) var(--ease); }

/* Overlay: tablet ----------------------------------------------------- */
@media (max-width: 1023px) {
  .overlay__body {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-8);
  }
  .overlay__player { position: static; }
  .overlay__head { margin-bottom: var(--space-8); }
}

/* Overlay: stacked ---------------------------------------------------- */
@media (max-width: 767px) {
  .overlay__head { display: block; }
  .overlay__cover { max-width: 22rem; margin-bottom: var(--space-6); }
  .overlay__title { margin-bottom: var(--space-5); }

  /* Tracklist becomes stacked rows — every field stays visible. */
  .tracklist thead {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
  .tracklist,
  .tracklist tbody,
  .tracklist tr,
  .tracklist td { display: block; }

  .tracklist tbody tr {
    display: grid;
    grid-template-columns: 2.5rem minmax(0, 1fr) auto;
    column-gap: var(--space-3);
    padding-block: var(--space-4);
    border-bottom: 1px solid var(--rule-soft);
  }
  .tracklist td { border: 0; padding-block: 0; }

  .tracklist .col-num    { grid-column: 1; grid-row: 1 / span 3; width: auto; }
  .tracklist .col-title  { grid-column: 2; grid-row: 1; }
  .tracklist .col-time   { grid-column: 3; grid-row: 1; width: auto; }
  .tracklist .col-artist { grid-column: 2 / span 2; grid-row: 2; }
  .tracklist .col-picked { grid-column: 2 / span 2; grid-row: 3; font-size: var(--fs-xs); }

  .tracklist .col-picked::before {
    content: attr(data-label) " ";
    color: var(--paper-faint);
  }
}

/* -------------------------------------------------- 10. Footer ------- */
.site-footer {
  padding: var(--space-8) var(--margin-x) var(--space-7);
  border-top: 1px solid var(--rule-soft);
  font-size: var(--fs-xs);
  color: var(--paper-faint);
  max-width: var(--content-max);
  margin-inline: auto;
}

/* ----------------------------------------- 11. Reduced motion -------- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 1ms;
    --dur: 1ms;
    --dur-slow: 1ms;
  }
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }

  /* no movement, only the opacity change */
  .photo,
  .entry--reveal,
  .hero__logo-wrap { transform: none; }
  .rail__button:hover .rail__cover,
  .rail__button:focus-visible .rail__cover,
  .entry:hover .entry__cover,
  .hero__logo:hover { transform: none; }
  .overlay[open] { animation: none; }
}
