:root {
  /* Design tokens — from design_handoff_glass_shelf_player/README.md, "Glass Shelf v2" */
  --scrim-dark: #12100e;
  --card-bg: rgba(20, 15, 11, 0.52);
  --card-border: rgba(255, 255, 255, 0.24);
  --accent-a: #c8452f;
  --accent-b: #e8a34a;
  --gold: #e8c46a;
  --text: #fff;
  --text-dim-1: rgba(255, 255, 255, 0.9);
  --text-dim-2: rgba(255, 255, 255, 0.78);
  --text-dim-3: rgba(255, 255, 255, 0.6);
  --text-dim-4: rgba(255, 255, 255, 0.62);
  --margin: 48px;
  /* Shared by .shelf-row and .credit so the credit tag always sits on the
     same horizontal line as the player card's bottom edge, at every
     breakpoint, without having to update two rules in sync by hand. */
  --shelf-bottom: 48px;
  /* Glass Control Card handoff's single tunable "glass strength" dial (0–1,
     spec default 0.26; set to 0.1 by request). Background tint alpha and
     backdrop-blur radius both derive from this one value on purpose — see
     .player-card — so they can never drift out of sync with each other. */
  --glass-amount: 0.1;
  --font-display: 'Anek Devanagari', system-ui, sans-serif;
  --font-mono: 'DM Mono', ui-monospace, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
  background: var(--scrim-dark);
}

body {
  min-height: 100svh;
  font-family: var(--font-display);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

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

/* Static by decision — no idle animation on the illustration. Position/scrim
   values here are desktop's (from the Glass Control Card handoff) — mobile
   overrides both in its own media query below, using the same photo with a
   different focal point (both handoffs ship the identical dashboard-bg.png). */
.hero {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 45% 60%;
  z-index: 0;
  pointer-events: none;
}

.scrim {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(20, 14, 10, .5) 0%, rgba(20, 14, 10, .08) 42%, rgba(14, 9, 6, .72) 100%);
}

.grain {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: .25;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
}

.status-bar,
.masthead,
.shelf-row {
  position: relative;
  z-index: 1;
}

.status-bar {
  position: fixed;
  top: 22px;
  left: var(--margin);
  right: var(--margin);
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-dim-1);
}

.top-links {
  display: flex;
  align-items: center;
  gap: 22px;
}

.suggest-toggle {
  font: inherit;
  font-family: var(--font-mono);
  font-size: inherit;
  color: var(--gold);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.suggest-toggle:hover { color: var(--text); }

/* Independent of .player-card/.credit on purpose — a small popover anchored
   to the status bar, not tied to the player card's layout or height at all. */
.suggest-panel {
  position: fixed;
  top: 60px;
  right: var(--margin);
  z-index: 2;
  width: 220px;
  padding: 16px;
  border-radius: 14px;
  background: var(--card-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--card-border);
  box-shadow: 0 14px 40px rgba(0, 0, 0, .4), inset 0 1px 0 rgba(255, 255, 255, .2);
}

#recommend-form {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

#recommend-form input {
  border: 1px solid var(--card-border);
  border-radius: 8px;
  background: rgba(0, 0, 0, .28);
  padding: 8px 10px;
  color: var(--text);
  font: inherit;
  font-size: 13px;
}
#recommend-form input::placeholder { color: rgba(255, 255, 255, .4); }

#rec-submit {
  align-self: flex-start;
  border: 1px solid var(--card-border);
  border-radius: 999px;
  background: rgba(232, 196, 106, .16);
  color: var(--text);
  padding: 6px 16px;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
#rec-submit:hover { background: rgba(232, 196, 106, .28); }
#rec-submit:disabled { opacity: .5; cursor: default; }

.rec-status {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--text-dim-3);
}
/* Reserving height for this even when empty (the old min-height) left a
   visually disproportionate dead strip at the bottom of this small panel —
   only take up space once there's actually a message to show. */
.rec-status:empty {
  margin: 0;
  display: none;
}
.rec-status[data-tone="error"] { color: #ff9f8d; }
.rec-status[data-tone="ok"] { color: #9fe0b4; }

.masthead {
  position: fixed;
  top: 76px;
  left: var(--margin);
  z-index: 1;
  max-width: calc(100vw - 2 * var(--margin));
}

.masthead-title {
  font-weight: 800;
  font-size: 96px;
  line-height: .9;
  color: var(--text);
  letter-spacing: -0.03em;
}

.masthead-sub {
  margin-top: 18px;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--text-dim-2);
}

.shelf-row {
  position: fixed;
  left: var(--margin);
  right: var(--margin);
  bottom: var(--shelf-bottom);
  z-index: 1;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}

/* Glass Control Card handoff (design_handoff_glass_control_card/README.md).
   Fixed-width vertical card, not the old fit-content horizontal row —
   width no longer depends on content, so the old .blocked-help ballooning
   fix (max-width hack) isn't needed here; a fixed width can't balloon. */
.player-card {
  width: 420px;
  box-sizing: border-box;
  padding: 20px 22px 18px;
  display: flex;
  flex-direction: column;
  border-radius: 20px;
  /* Both derive from the one --glass-amount dial — see :root. */
  background: rgba(28, 20, 14, var(--glass-amount));
  backdrop-filter: blur(calc(30px * var(--glass-amount))) saturate(1.1);
  -webkit-backdrop-filter: blur(calc(30px * var(--glass-amount))) saturate(1.1);
  border: 1px solid rgba(255, 255, 255, .3);
  box-shadow: 0 20px 50px rgba(0, 0, 0, .4), inset 0 1px 0 rgba(255, 255, 255, .22);
  /* Keeps card text legible however transparent the glass fill gets —
     text opacity itself always stays 1, per the handoff. */
  text-shadow: 0 1px 10px rgba(0, 0, 0, .6);
}

/* Groups art+text into one row within the card's vertical stack — shared
   as-is by mobile too, since both breakpoints' Glass Control Card handoffs
   use the same column layout and content order. */
.track-row {
  display: flex;
  align-items: center;
  gap: 14px;
}

.art {
  width: 58px;
  height: 58px;
  flex: none;
  border-radius: 12px;
  background: linear-gradient(140deg, var(--accent-a), var(--accent-b));
  box-shadow: 0 4px 14px rgba(0, 0, 0, .35);
  object-fit: cover;
}

.track-info {
  min-width: 0;
}

/* "NOW PLAYING" eyebrow isn't part of this card's design on either
   breakpoint (kept in markup, not deleted, in case a future design wants it
   back). */
.eyebrow {
  display: none;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--text-dim-4);
}

.track-title {
  font-size: 20px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.track-channel {
  font-size: 14px;
  color: rgba(255, 255, 255, .6);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.time-labels {
  margin-top: 16px;
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 11px;
  color: rgba(255, 255, 255, .7);
}

.progress-track {
  margin-top: 6px;
  position: relative;
  height: 3px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .28);
  cursor: pointer;
  touch-action: none; /* dragging the thin bar shouldn't trigger page scroll on touch */
}

.progress-fill {
  display: block;
  width: 0%;
  height: 100%;
  border-radius: 2px;
  background: var(--text);
  position: relative;
}

/* Permanent scrubber handle on the fill's leading edge (mobile has its own,
   larger, ::after handle inside its own media query — this one is scoped
   to desktop's thinner 3px track via the min-width query below). */
.progress-fill::after {
  content: '';
  position: absolute;
  left: 100%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--text);
}

.controls {
  margin-top: 16px;
  padding: 0 2px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--text);
}

.ctrl {
  display: grid;
  place-items: center;
  /* 32px minimum hit target per the handoff, even though the visible glyph
     is smaller — the icon itself is sized via .ctrl svg below. */
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  border-radius: 50%;
}

.ctrl:disabled { opacity: .35; cursor: default; }

.ctrl svg {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linejoin: round;
}

.ctrl-play {
  width: 40px;
  height: 40px;
  background: rgba(255, 255, 255, .92);
  color: #1a1613;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .3);
}
.ctrl-play svg { fill: currentColor; stroke: currentColor; width: 16px; height: 16px; }

/* The `hidden` attribute does not hide SVG elements, so swap on a state class. */
.ctrl-play .icon-pause,
.ctrl-play.is-playing .icon-play { display: none; }
.ctrl-play.is-playing .icon-pause { display: block; }

/* Shuffle: the one constant-accent icon (amber), per the handoff — dims to
   the shared inactive tone when toggled off, no separate "toggled-off amber"
   state to define. Repeat cycles off/all/one and reuses the same colors. */
.ctrl-shuffle { color: var(--accent-b); }
.ctrl-shuffle[aria-pressed="false"] { color: rgba(255, 255, 255, .55); }

.ctrl-repeat[data-mode="off"] { color: rgba(255, 255, 255, .55); }
.ctrl-repeat[data-mode="all"],
.ctrl-repeat[data-mode="one"] { color: var(--accent-b); }

.repeat-badge {
  display: none;
  position: absolute;
  bottom: 2px;
  right: 2px;
  font-family: var(--font-mono);
  font-size: 8px;
  line-height: 1;
  color: inherit;
}
.ctrl-repeat { position: relative; }
.ctrl-repeat[data-mode="one"] .repeat-badge { display: block; }

/* Only shown when playback is actually blocked — drops onto its own full
   row (`flex: 1 0 100%` needs .player-card's `flex-wrap: wrap`) so the
   message can wrap instead of truncating like the title/channel lines. */
/* Simple now that .player-card is a fixed-420px-wide column layout: no
   flex-basis/min-width tricks needed (those were for the old row+wrap card,
   where width was content-derived and could balloon — a fixed width can't).
   Needs its own margin-top since .player-card has no `gap` of its own to
   borrow spacing from (each section here sets its own explicit margin-top
   instead, so this just follows that same pattern). */
.blocked-help {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--card-border);
  font-size: 12px;
  line-height: 1.5;
  color: var(--accent-b);
}

/* Sits on the same horizontal line as the player card's bottom edge
   (shares --shelf-bottom with .shelf-row) and matches the Spotify/YT Music
   links in the status bar — same gold, same 13px, same font. */
.credit {
  position: fixed;
  right: var(--margin);
  bottom: var(--shelf-bottom);
  z-index: 1;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--gold);
}
.credit:hover { color: var(--text); }

.yt-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  left: -9999px;
  opacity: 0;
  pointer-events: none;
}

/* Honeypot: off-screen rather than display:none, so naive bots that skip
   invisible fields still fill it in. Lost when the old recommend form's
   CSS was stripped during the rebrand — needed again now it's back. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

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

/* Design frame is 1280x720; below that the masthead and status bar are
   scaled down and the shelf stacks so the card never exceeds the viewport.
   The far-left/right scenery is lost on narrow viewports — accepted tradeoff. */
@media (max-width: 900px) {
  .masthead-title { font-size: clamp(48px, 12vw, 96px); }
}

/* Mobile — design_handoff_glass_control_card_mobile/README.md, 390x844
   frame. Same "Glass Control Card" language as desktop (shared column
   layout, shared --glass-amount dial, same card content/order) — the real
   differences are just the photo's focal point, the scrim ramp, and a
   handful of smaller-scale tokens (card padding, art/type sizes, handle). */
@media (max-width: 767px) {
  :root { --margin: 24px; --shelf-bottom: 34px; }

  /* Same photo as desktop, different focal point — dashboard/shrine area. */
  .hero { object-position: 35% 65%; }

  .scrim {
    background: linear-gradient(180deg,
      rgba(20, 14, 10, .55) 0%,
      rgba(20, 14, 10, .15) 40%,
      rgba(14, 9, 6, .75) 100%);
  }

  .status-bar { top: 14px; font-size: 13px; color: var(--text); align-items: flex-start; }
  /* Three items (Spotify/YT Music/Suggest) don't fit on one line at mobile
     widths without crowding the clock — wraps to a second, right-aligned
     line instead of shrinking the gap to almost nothing. */
  .top-links { flex-wrap: wrap; justify-content: flex-end; gap: 10px 14px; max-width: 60%; }

  .masthead { top: 196px; }
  .masthead-title {
    font-size: 46px;
    line-height: .92;
    letter-spacing: -0.02em;
    text-shadow: 0 4px 26px rgba(0, 0, 0, .5);
  }
  .masthead-sub { margin-top: 12px; font-size: 11px; letter-spacing: .22em; }

  .shelf-row {
    flex-direction: column;
    align-items: stretch;
  }

  /* Card is full-width of the 24px gutters, not fixed-width like desktop's
     420px — everything else (column direction, glass background/blur,
     border, shadow, text-shadow) is inherited from the shared .player-card
     rule above, since the mobile handoff's values match desktop's exactly. */
  .player-card {
    width: 100%;
    padding: 20px 20px 18px;
  }

  .art { width: 56px; height: 56px; }

  .track-title { font-size: 19px; }
  .track-channel { font-size: 13px; }

  /* Handle is 1px larger than desktop's (12px vs 11px) — only the size
     changes, position still inherits the shared left:100% rule above. */
  .progress-fill::after { width: 12px; height: 12px; }

  /* All five transport icons meet the spec's 44x44 minimum touch target
     (desktop's 32px .ctrl is too small to tap reliably) at the spec's own
     19px base icon size. Play keeps desktop's proportionally-larger circle
     for the same visual hierarchy, just scaled to this card's smaller tokens. */
  .ctrl { width: 44px; height: 44px; }
  .ctrl svg { width: 19px; height: 19px; }
  .ctrl-play { width: 54px; height: 54px; }
  .ctrl-play svg { width: 21px; height: 21px; }

  /* Card is full-width here, so the shared bottom line would put this
     right on top of the play button — sits just below the card instead. */
  .credit { bottom: 10px; }
}

/* Every positioned element here is `position: fixed` and sized off the
   1280x720 design frame with no regard for viewport height. On a short
   viewport (landscape phone, a small resized window) the masthead and the
   bottom player card can overlap — this compresses both so they never meet.
   Scoped to >=768px: it collapses the card to a fixed-height single row,
   which would truncate the stacked mobile layout and push the transport
   controls out of view. Narrow-and-short is handled separately below. */
@media (max-height: 480px) and (min-width: 768px) {
  :root { --shelf-bottom: 14px; }

  .status-bar { top: 12px; }

  .masthead { top: 40px; }
  .masthead-title { font-size: clamp(28px, 8vw, 44px); line-height: .95; }
  .masthead-sub { margin-top: 6px; font-size: 10px; }

  /* No .transport to compress anymore (it's gone) — shrink the new vertical
     stack proportionally instead: smaller art/type, tighter inter-row
     margins, smaller buttons, narrower fixed card width. */
  .player-card { width: 320px; padding: 14px 16px 12px; }
  .art { width: 44px; height: 44px; }
  .track-title { font-size: 16px; }
  .track-channel { font-size: 12px; }
  .time-labels { margin-top: 10px; }
  .progress-track { margin-top: 4px; }
  .controls { margin-top: 10px; }
  .ctrl { width: 28px; height: 28px; }
  .ctrl svg { width: 14px; height: 14px; }
  .ctrl-play { width: 34px; height: 34px; }
  .ctrl-play svg { width: 14px; height: 14px; }
}

/* Narrow AND short — split-screen, a foldable, or a small resized window.
   Keeps the stacked mobile layout (so the transport stays reachable) but
   tightens the masthead and card enough that both still fit. */
@media (max-height: 620px) and (max-width: 767px) {
  :root { --shelf-bottom: 20px; }

  /* Card is still full-width here so this can't follow --shelf-bottom
     (same reasoning as the base mobile block) — and the gap below the card
     is only 20px now, too tight for the inherited 10px/13px pairing without
     touching the card, so both are pulled in further. */
  .credit { bottom: 2px; font-size: 11px; }

  .masthead { top: 56px; }
  .masthead-title { font-size: 30px; }
  .masthead-sub { margin-top: 8px; font-size: 10px; letter-spacing: .18em; }

  .player-card { padding: 14px 16px 16px; }
  .art { width: 48px; height: 48px; border-radius: 10px; }
  .track-title { font-size: 17px; }
  .track-channel { font-size: 12px; }

  .time-labels { margin-top: 10px; }
  .progress-track { margin-top: 4px; }

  .controls { margin-top: 8px; }
  .ctrl-play { width: 48px; height: 48px; }
  .ctrl-play svg { width: 18px; height: 18px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}
