html {
  scroll-behavior: smooth;
}
.site-nav {
  /* fixed, not sticky: some browsers paint a sticky element's translucent
     background as solid on the very first frame and only correct it
     after a scroll-triggered repaint (independent of backdrop-filter —
     it happened with and without it). fixed is promoted to its own
     compositing layer from the start, avoiding that class of bug. It
     no longer reserves space in normal flow, so the content right
     after it (.hero, and <main> on the demo page) carries matching
     top padding to clear it. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
  padding: 1rem 1.5rem;
  /* Plain alpha background, no backdrop-filter. backdrop-filter's blur
     depends on GPU compositing that isn't reliable across every
     browser/driver combo — when it fails, some renderers fall back to
     a blank/black backdrop source, so even this rgba's own transparency
     ends up blending against black instead of the photo (looks fully
     opaque, not just unblurred). Plain background-color transparency is
     ordinary alpha compositing with no such failure mode. */
  background: rgba(20, 21, 26, 0.45);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  transition: background-color 0.25s ease;
}
.site-nav.scrolled {
  background: rgba(20, 21, 26, 0.28);
}
.nav-inner {
  max-width: 1100px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.nav-brand {
  color: var(--text);
  text-decoration: none;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.nav-links {
  display: flex;
  gap: 1.5rem;
}
.nav-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.nav-links a:hover {
  color: var(--accent);
}
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 22px;
  height: 22px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  width: 100%;
  height: 2px;
  background: var(--muted);
  border-radius: 1px;
  transition: transform 0.2s ease, opacity 0.2s ease, background-color 0.2s ease;
}
/* (hover: hover) excludes touchscreens — without it, tapping the
   button (which has no mouse to later move away and clear :hover)
   leaves it stuck gold until the visitor taps elsewhere. */
@media (hover: hover) {
  .nav-toggle:hover span {
    background: var(--accent);
  }
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}
.nav-toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}
/* Below this, brand + 4 links + growing letter-spacing crowd into each
   other (confirmed by testing an emulated phone viewport) — collapse
   the links into a toggled dropdown instead. .nav-links goes absolute
   (relative to .site-nav, the nearest positioned ancestor) so it drops
   out of the flex row entirely, leaving .nav-toggle as the row's last
   flex item and space-between free to push it to the right edge. */
@media (max-width: 700px) {
  .nav-toggle {
    display: flex;
  }
  .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    background: rgba(20, 21, 26, 0.97);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.25s ease;
  }
  .nav-links.open {
    max-height: 300px;
  }
  .nav-links a {
    padding: 1rem 1.5rem;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
  }
}
.site-footer {
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.6;
  padding: 3rem 1.25rem 2.5rem;
}
.site-footer .build-time {
  display: block;
  font-size: 0.85em;
  margin-top: 0.35rem;
}
:root {
  color-scheme: dark;
  --bg: #14151a;
  --panel: #1d1f27;
  --border: #2c2f3a;
  --text: #e8e8ec;
  --muted: #a4a9b3;
  --accent: #d8b36a;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
main {
  max-width: 480px;
  margin: 0 auto;
  /* Top padding clears the fixed .site-nav, which no longer reserves
     space in normal flow. */
  padding: calc(2.5rem + 4rem) 1.25rem 4rem;
  /* Mobile: a single stacked column in reading order — art, player,
     tracklist, about — which also doubles as sane DOM order (the
     no-CSS/accessibility fallback). .col-left/.col-right are `display:
     contents` at this width, so they disappear from layout entirely and
     their children (header/about-album, player/tracklist) place directly
     into this flat 4-row grid via their own grid-area below. */
  display: grid;
  grid-template-areas: "art" "player" "tracklist" "meta" "about";
  gap: 1.75rem;
}
.col-left, .col-right {
  display: contents;
}
header {
  grid-area: art;
}
.player {
  grid-area: player;
}
.about-album-meta {
  grid-area: meta;
}
ol.tracklist {
  grid-area: tracklist;
}
.about-album {
  grid-area: about;
}
@media (min-width: 860px) {
  main {
    max-width: 900px;
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "left right";
    column-gap: 2.5rem;
  }
  /* Real grid items now (no longer `contents`), each a normal block
     stack — so the right column's total height is just player + gap +
     tracklist, independent of how tall the left column's art + about
     text happens to be. Sharing a grid row between player and the much
     taller album art (the earlier approach) forced player's panel to
     stretch and fill the leftover space instead of sizing to its own
     content. */
  .col-left, .col-right {
    display: block;
  }
  .col-left {
    grid-area: left;
  }
  .col-right {
    grid-area: right;
  }
  header {
    margin-bottom: 1.75rem;
  }
  .player {
    margin-bottom: 1.75rem;
  }
  /* ol.tracklist's matching margin-bottom lives in player.css, after its
     `margin: 0` reset — see the comment there for why this file isn't
     the right place for it. */
}
header .album-art-wrap {
  position: relative;
}
header .album-art {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
header .demo-watermark {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(-18deg);
  color: rgba(232, 232, 236, 0.55);
  font-size: clamp(1.8rem, 8vw, 3rem);
  font-weight: 700;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  padding: 0.3em 0.6em;
  border: 3px solid rgba(232, 232, 236, 0.55);
  border-radius: 10px;
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
}
.player {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem 1.1rem;
}
.current-track {
  color: var(--text);
  font-size: 1.35rem;
  font-weight: 600;
  text-align: center;
  margin-bottom: 0.75rem;
}
.player-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  margin-bottom: 0.75rem;
}
.ctrl-btn {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 1.125rem;
  padding: 0.5rem 0.9rem;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .ctrl-btn:hover {
    border-color: var(--accent);
  }
}
.ctrl-btn:focus:not(:focus-visible) {
  outline: none;
}
.ctrl-btn.toggle-active {
  color: var(--accent);
  border-color: var(--accent);
}
#shuffle-btn, #repeat-btn {
  font-size: 1.35rem;
}
.play-pause-btn {
  background: var(--accent);
  color: var(--bg);
  border: none;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  font-size: 1.1rem;
  line-height: 1;
  padding: 0;
}
.play-pause-btn:hover {
  opacity: 0.9;
}
#player-audio {
  display: none;
}
.seek-row {
  display: flex;
  justify-content: center;
}
.seek {
  width: 80%;
  accent-color: var(--accent);
}
.time-row {
  width: 80%;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  color: var(--muted);
  font-size: 0.94rem;
  font-variant-numeric: tabular-nums;
}
ol.tracklist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
@media (min-width: 860px) {
  /* Overrides the `margin: 0` reset above (same specificity,
     later in source order) to give this the same bottom margin as
     .player/header at this breakpoint, matching the tracklist->meta gap
     to the player->tracklist gap above it. Living here, after the reset,
     instead of in base.css's media query, is what actually makes it win
     the cascade — base.css tried this and silently lost to the reset. */
  ol.tracklist {
    margin-bottom: 1.75rem;
  }
}
.track {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.75rem 1.1rem;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .track:hover {
    border-color: var(--accent);
  }
}
.track:focus:not(:focus-visible) {
  outline: none;
}
.track.active {
  border-color: var(--accent);
  background: #262a38;
}
.track-title {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}
.track-number {
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  font-size: 1.06rem;
  width: 1.6rem;
}
.track-name {
  font-size: 1.25rem;
  font-weight: 500;
}
.about-album {
  text-align: left;
}
.about-album h2 {
  color: var(--accent);
  font-size: 1.5rem;
  font-weight: 600;
  margin: 0 0 1rem;
}
.about-album p {
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.7;
  margin: 0 0 0.75rem;
}
.about-album p:last-child {
  margin-bottom: 0;
}
.about-album p.about-album-closing {
  color: var(--accent);
  font-weight: 600;
}
.about-album-meta {
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}
.about-album-meta p {
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.6;
  margin: 0 0 0.4rem;
}
.about-album-meta p:last-child {
  margin-bottom: 0;
}
