/* ============================================================================
   Xplaymusic — styles
   Driver surfaces are lime-accented, passenger surfaces violet, so at a glance
   you always know whose screen you're looking at.
   ========================================================================== */

:root {
  --bg:        #08080a;
  --surface:   #131318;
  --surface-2: #1c1c23;
  --surface-3: #26262f;
  --border:    #2c2c36;
  --border-2:  #3a3a46;

  --text:      #f4f4f6;
  --text-dim:  #a1a1ad;
  --text-mute: #6d6d7a;

  --driver:    #b8ff3c;
  --driver-dim:#5d7d1e;
  --pax:       #7b61ff;
  --pax-dim:   #3f3180;
  --danger:    #ff4d5e;
  --warn:      #ffb020;
  --ok:        #4ade80;

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-xl: 26px;

  --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  /* The tab bar's real height, home indicator included. Anything that has to
     sit above it — the mini player, the last row of a list — measures from
     here rather than guessing at a number that is only right on one phone. */
  --tabbar-h: 62px;
  --safe-b: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  min-height: 100%;
}

button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }
input  { font-family: inherit; }

/* Touch, on everything the app treats as a control.

   touch-action: manipulation drops the browser's wait-and-see for a possible
   double-tap-to-zoom, which is a third of a second of nothing happening after
   every tap — the single biggest reason a working app feels dead in a moving
   car. Removing the grey tap flash goes with it: every control below has its
   own :active state, and those fire immediately. */
button, [data-act], [data-tab], [data-playrow], [data-mood], [data-genre], [data-shelf] {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
button:focus-visible, input:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--pax); outline-offset: 2px;
}

.hidden { display: none !important; }

/* ---------------------------------------------------------------- landing */
.landing {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
  gap: 30px;
  text-align: center;
}
.landing__mark {
  font-size: 13px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--text-mute);
}
.landing h1 {
  margin: 0; font-size: clamp(34px, 6vw, 58px); font-weight: 800; letter-spacing: -.03em;
}
.landing h1 span { color: var(--driver); }
.landing__sub { margin: 0; max-width: 620px; color: var(--text-dim); font-size: 16px; line-height: 1.6; }
.landing__cards { display: flex; flex-wrap: wrap; gap: 16px; justify-content: center; margin-top: 10px; }
.lcard {
  width: 250px; padding: 24px 22px; text-align: left;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  transition: border-color .15s, transform .15s, background .15s;
}
.lcard:hover { border-color: var(--border-2); transform: translateY(-3px); background: var(--surface-2); }
.lcard__icon { font-size: 22px; margin-bottom: 12px; display: block; }
.lcard__title { font-size: 17px; font-weight: 700; margin-bottom: 6px; }
.lcard__desc  { font-size: 13px; color: var(--text-dim); line-height: 1.55; }
/* The route each card leads to. Shown because this is a developer surface and
   the URL is half of what you came here for — worth typing directly next time. */
.lcard__path {
  margin-top: 14px; font-size: 11px; color: var(--text-mute);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.lcard--driver:hover { border-color: var(--driver-dim); }
.lcard--pax:hover    { border-color: var(--pax-dim); }
.landing__foot { font-size: 12px; color: var(--text-mute); max-width: 540px; line-height: 1.6; }

/* -------------------------------------------------------------- demo stage */
.stage {
  display: flex; gap: 34px; align-items: flex-start; justify-content: center;
  padding: 28px 24px 60px; flex-wrap: wrap;
}
.stage__col { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.stage__label {
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--text-mute);
  display: flex; align-items: center; gap: 8px;
}
.stage__label::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.stage__label--driver { color: var(--driver); }
.stage__label--pax    { color: var(--pax); }

.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 24px; border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.topbar__brand { font-weight: 800; font-size: 16px; letter-spacing: -.01em; }
.topbar__brand span { color: var(--driver); }
.topbar__actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.tbtn {
  font-size: 12px; padding: 7px 13px; border-radius: 999px;
  border: 1px solid var(--border); color: var(--text-dim); transition: .15s;
}
.tbtn:hover { border-color: var(--border-2); color: var(--text); background: var(--surface-2); }
.tbtn--on { background: var(--driver); color: #000; border-color: var(--driver); font-weight: 600; }

/* ---------------------------------------------------------------- devices */
.device { position: relative; }

/* Driver: dash-mounted tablet, landscape */
.device--tablet {
  width: 620px; max-width: 100%;
  background: #000; border-radius: 22px; padding: 12px;
  border: 1px solid var(--border-2);
  box-shadow: 0 26px 60px rgba(0,0,0,.6), 0 0 0 1px rgba(184,255,60,.06);
}
.device--tablet .screen { height: 660px; border-radius: 14px; }

/* Passenger: phone, portrait */
.device--phone {
  width: 340px; max-width: 100%;
  background: #000; border-radius: 38px; padding: 11px;
  border: 1px solid var(--border-2);
  box-shadow: 0 26px 60px rgba(0,0,0,.6), 0 0 0 1px rgba(123,97,255,.08);
}
.device--phone .screen { height: 690px; border-radius: 29px; }
.device--phone::after {
  content: ''; position: absolute; top: 20px; left: 50%; transform: translateX(-50%);
  width: 86px; height: 22px; background: #000; border-radius: 999px; z-index: 5;
}

.screen {
  background: var(--bg); overflow: hidden; position: relative;
  display: flex; flex-direction: column;
}

/* ------------------------------------------------- full-window (phone) mode
   Opened via the QR or ?role=. The passenger shell is a fixed-height app with
   its own scrolling region and bottom navigation, so here it simply fills the
   viewport — the document itself must NOT scroll, or the tab bar drifts away. */

/* Sized against the viewport directly rather than inherited as a percentage.
   A percentage height only resolves if EVERY ancestor has a definite height,
   and index.html puts an un-styled #app wrapper between body and .device: that
   one gap collapsed the whole chain, so .pax__scroll got no bounded height, grew
   to the full height of its content, and never became a scroller. With the
   document itself set to overflow:hidden, nothing scrolled at all — the rider
   could not swipe up past the first screenful.

   dvh, not vh: iOS reports 100vh as the viewport with the address bar HIDDEN, so
   a vh-sized shell is taller than what you can actually see and parks the tab bar
   below the fold. vh stays first as the fallback for browsers without dvh. */
.fullscreen-host {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;   /* no pull-to-refresh or rubber-band on the shell */
}
/* The missing link in the chain. */
.fullscreen-host #app { height: 100%; }
html:has(body.fullscreen-host) { height: 100%; overflow: hidden; }
.fullscreen-host .device { width: 100%; height: 100%; padding: 0; border: none; box-shadow: none; background: none; }
.fullscreen-host .device::after { display: none; }
.fullscreen-host .screen { height: 100%; border-radius: 0; }
.fullscreen-host .toasts { bottom: 128px; }

/* viewport-fit=cover plus a translucent status bar means the shell extends under
   the notch, which is what we want for the background and not at all what we want
   for the ride title. Only in full-window mode — the desktop device mock has no
   insets to inherit, and the inset is 0 on hardware without a notch anyway. */
.fullscreen-host .pax__top,
.fullscreen-host .pane__head { padding-top: calc(14px + env(safe-area-inset-top, 0px)); }

/* The driver's full-window view still scrolls its own body. */
.fullscreen-host .pane { height: 100%; }

/* ------------------------------------------------------------ audio unlock */
.unlock {
  position: absolute; inset: 0; z-index: 60;
  background: rgba(6,6,8,.9); backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.unlock__card {
  max-width: 340px; text-align: center;
  background: var(--surface); border: 1px solid var(--border-2);
  border-radius: var(--r-lg); padding: 26px 22px;
}
.unlock__icon { font-size: 30px; margin-bottom: 12px; }
.unlock__title { font-size: 17px; font-weight: 700; margin-bottom: 9px; }
.unlock__body { font-size: 12.5px; color: var(--text-dim); line-height: 1.6; margin-bottom: 18px; }
.unlock__btn {
  width: 100%; padding: 12px; border-radius: var(--r-md);
  background: var(--driver); color: #000; font-weight: 700; font-size: 14px;
}
.unlock__btn:hover { background: #c8ff5c; }

/* --------------------------------------------------------- shared chrome */
.pane { display: flex; flex-direction: column; height: 100%; min-height: 0; }

.pane__head {
  padding: 14px 16px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-shrink: 0;
}
.pane__head--driver { background: linear-gradient(180deg, rgba(184,255,60,.05), transparent); }
.pane__head--pax    { background: linear-gradient(180deg, rgba(123,97,255,.07), transparent); }

.ride-meta { min-width: 0; }
.ride-meta__title { font-size: 14px; font-weight: 700; display: flex; align-items: center; gap: 7px; }
.ride-meta__sub { font-size: 11px; color: var(--text-mute); margin-top: 3px; }

.livedot { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); flex-shrink: 0; }
.livedot--playing { animation: pulse 1.7s infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .28; } }

.code-pill {
  font-family: var(--mono); font-size: 13px; letter-spacing: .1em; font-weight: 700;
  padding: 6px 11px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border);
}

/* Everything under the dash header scrolls as one column: the now-playing
   block, the tab strip and the list below it. The player used to be pinned
   above its own scroller, so once music started it owned the top of the screen
   for the rest of the ride and the list under it could never be made bigger —
   on a phone that is a couple of visible rows. Now the driver can push the
   player up out of the way and pull it back down when they want the controls. */
.pane__scroll {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
}
.pane__scroll::-webkit-scrollbar { width: 8px; }
.pane__scroll::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 4px; }
.pane__scroll::-webkit-scrollbar-track { background: transparent; }

/* Inside that scroller the body is just content — it must grow to its full
   height and let the parent do the scrolling, or there are two nested
   scrollers and the inner one swallows the gesture. */
.pane__body { min-height: 0; }

/* The tabs ride along until they reach the top, then stay. Scrolling the
   player away must not also scroll away the only way to reach Rules. */
.tabs--sticky {
  position: sticky; top: 0; z-index: 6;
  background: var(--bg);
}

/* ------------------------------------------------------------- album art */
.art { border-radius: var(--r-md); position: relative; overflow: hidden; flex-shrink: 0; }
.art::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(circle at 30% 25%, rgba(255,255,255,.28), transparent 60%);
}
.art__note {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 1.6em; opacity: .5; color: #000; z-index: 1;
}
.art__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 2;
}

/* ------------------------------------------------------- embedded player
   YouTube's terms require the player viewport stay at least 200x200 and
   forbid overlaying it, so this box is square and nothing sits on top. */
.np__stage { flex-shrink: 0; }
.np__stage--video { width: 220px; height: 220px; }
.np__video {
  width: 220px; height: 220px; border-radius: var(--r-md); overflow: hidden;
  background: #000; border: 1px solid var(--border);
}
.np__video iframe { display: block; width: 100%; height: 100%; border: 0; }
.np__info { flex: 1; min-width: 0; }

/* Audio-only mode.

   The frame keeps its real dimensions, because YouTube refuses to play in a
   hidden or zero-sized one. It is NOT parked off-screen, though — that was the
   bug. A frame at left:-10000px is outside the viewport, and both Chrome's
   autoplay heuristics and YouTube's own player treat "outside the viewport"
   much like "hidden": a load that wasn't triggered by a direct tap gets
   deferred, so the next song would load, show its poster, and sit there waiting
   for a click that never came.

   So it stays exactly where it was, at full size, layered underneath the
   artwork. Occluded is not hidden — the frame is on screen and painted as far
   as the browser is concerned, and playback starts on its own. */
.np__stage--audio {
  position: relative; width: 220px; height: 220px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md); overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--border);
}
.np__video--offstage {
  position: absolute; inset: 0; z-index: 0;
  width: 220px; height: 220px; pointer-events: none;
  border-radius: 0; border: 0;
}
/* Opaque cover between the frame and the art, so the video is not visible
   without ever being un-rendered. */
.np__stage--audio::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: var(--surface-2);
}
.np__stage--audio .art { position: relative; z-index: 2; }

/* Bigger hit area for scrubbing on a dash screen. */
.progress__bar { padding: 7px 0; background: none; height: auto; }
.progress__bar::before {
  content: ''; position: absolute; inset: 7px 0; background: var(--surface-3);
  border-radius: 3px;
}
.progress__fill { position: relative; height: 5px; margin: 7px 0; z-index: 1; }
.progress__bar:not(.progress__bar--static) { cursor: ew-resize; touch-action: none; }
.progress__bar:not(.progress__bar--static) .progress__fill::after {
  content: ''; position: absolute; right: -7px; top: 50%;
  width: 14px; height: 14px; margin-top: -7px;
  background: var(--driver); border-radius: 50%;
  border: 2px solid var(--bg); opacity: 0; transition: opacity .12s;
}
.progress__bar:hover .progress__fill::after { opacity: 1; }
/* On the rider's phone there is no hover, so the scrub handle is always shown. */
.progress__bar--pax .progress__fill--pax::after { background: var(--pax); opacity: 1; }
.progress__bar--pax { padding: 10px 0; }

.notice-strip--warn {
  background: rgba(255,77,94,.12); border-bottom-color: rgba(255,77,94,.3);
  color: #ffb3bb;
}

/* ------------------------------------------------------------ now playing */
.np { padding: 18px 16px; border-bottom: 1px solid var(--border); }
.np--driver { display: flex; gap: 18px; align-items: center; }
.np__art-lg { width: 128px; height: 128px; }
.np__info { flex: 1; min-width: 0; }
.np__eyebrow {
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-mute); margin-bottom: 7px;
}
.np__title {
  font-size: 21px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.np__artist { font-size: 14px; color: var(--text-dim); margin-top: 3px; }
.np__requester {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 10px;
  font-size: 11px; padding: 4px 10px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-dim);
}
.np__requester i { width: 6px; height: 6px; border-radius: 50%; display: block; }
.np__empty { text-align: center; padding: 34px 16px; color: var(--text-mute); font-size: 13px; }
.np__empty strong { display: block; color: var(--text-dim); font-size: 15px; margin-bottom: 6px; }

/* ==========================================================================
   Passenger app shell
   A rider is handed something that should feel like a music app, not a form:
   fixed ride header, scrolling content, a mini player that's always there, and
   bottom navigation. The full player is a sheet that slides over the top.
   ========================================================================== */
.pax { display: flex; flex-direction: column; height: 100%; min-height: 0; position: relative; }

.pax__top {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 16px 12px; flex-shrink: 0;
  background: linear-gradient(180deg, rgba(123,97,255,.10), transparent);
}

.pax__scroll {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  /* Reaching the end of this list must not hand the scroll to the page behind
     it — on mobile that reads as the shell drifting under the rider's thumb. */
  overscroll-behavior-y: contain;
  padding-bottom: 8px;
}
.pax__scroll::-webkit-scrollbar { width: 0; }
/* Room for the mini player so the last row is never trapped under it. Measured
   from the tab bar's real height, home indicator included — a fixed number here
   traps the last row on any phone with a taller bar. */
.pax__scroll--hasmini { padding-bottom: calc(var(--tabbar-h) + var(--safe-b) + 14px); }

.searchwrap { flex-shrink: 0; }

.greet { padding: 16px 16px 2px; }
.greet__hi { font-size: 22px; font-weight: 800; letter-spacing: -.025em; }
.greet__sub { font-size: 12px; color: var(--text-mute); margin-top: 3px; }

/* --------------------------------------------------------------------- hero
   The now-playing card takes its colour from the artwork (--h1/--h2, set
   inline per track), so home changes character with the music instead of
   sitting in one fixed accent. */
.hero {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 14px; text-align: left;
  margin: 12px 16px 4px; width: calc(100% - 32px);
  padding: 13px 13px 15px; border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--border); cursor: pointer;
  transition: transform .12s, border-color .15s;
}
.hero:active { transform: scale(.985); }
.hero:hover { border-color: var(--border-2); }

/* Two soft washes of the artwork colours, behind everything. */
.hero__glow {
  position: absolute; inset: -40% -20%; pointer-events: none;
  background:
    radial-gradient(60% 80% at 18% 30%, var(--h1, var(--pax)), transparent 70%),
    radial-gradient(60% 90% at 88% 80%, var(--h2, var(--pax-dim)), transparent 70%);
  opacity: .38; filter: blur(6px);
}
.hero > *:not(.hero__glow) { position: relative; z-index: 1; }

.hero__art {
  width: 66px; height: 66px; border-radius: var(--r-md); flex-shrink: 0;
  box-shadow: 0 6px 18px rgba(0,0,0,.45);
}
.hero__meta { flex: 1; min-width: 0; }
.hero__eyebrow {
  display: flex; align-items: center; gap: 6px;
  font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase;
  color: #fff; font-weight: 700; margin-bottom: 5px; opacity: .92;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hero__title {
  font-size: 16px; font-weight: 700; letter-spacing: -.015em; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.hero__artist {
  font-size: 12.5px; color: rgba(255,255,255,.72); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hero__open { font-size: 15px; color: var(--text-mute); flex-shrink: 0; padding-right: 4px; }
.hero__play {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.94); color: #111; font-size: 13px;
  box-shadow: 0 4px 14px rgba(0,0,0,.35); transition: transform .12s;
}
.hero__play:active { transform: scale(.9); }

.hero__bar {
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: rgba(255,255,255,.14); z-index: 1;
}
.hero__fill { height: 100%; background: #fff; transition: width .3s linear; }

.hero--empty { background: var(--surface); }
.hero--empty .hero__eyebrow { color: var(--text-mute); }
.hero--empty .hero__artist { color: var(--text-dim); }

/* Three bars that move only while audio is actually playing — the one piece of
   the rider's screen that proves the car is making noise. */
.eq { display: inline-flex; align-items: flex-end; gap: 2px; height: 9px; }
.eq i {
  width: 2px; background: currentColor; border-radius: 1px;
  animation: eq 900ms ease-in-out infinite;
}
.eq i:nth-child(1) { height: 40%; animation-delay: -300ms; }
.eq i:nth-child(2) { height: 100%; animation-delay: -600ms; }
.eq i:nth-child(3) { height: 65%; }
@keyframes eq { 0%, 100% { transform: scaleY(.35); } 50% { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) { .eq i { animation: none; } }

/* -------------------------------------------------------------------- shelf */
.shelf { margin-top: 24px; }
.shelf--loading { display: flex; justify-content: center; }
.shelf__head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 0 16px 11px;
}
.shelf__head h3 {
  margin: 0; font-size: 16px; font-weight: 750; letter-spacing: -.02em;
}
.shelf__sub { font-size: 11.5px; color: var(--text-mute); margin-top: 2px; }
.shelf__more {
  font-size: 11px; color: var(--text-dim); font-weight: 600; flex-shrink: 0;
  padding: 5px 10px; border-radius: 999px; border: 1px solid var(--border);
  transition: color .15s, border-color .15s;
}
.shelf__more:hover { color: var(--text); border-color: var(--border-2); }

.shelf__row {
  display: flex; gap: 13px; overflow-x: auto; padding: 0 16px 4px;
  scroll-snap-type: x proximity; scrollbar-width: none;
  scroll-padding-left: 16px;
}
.shelf__row::-webkit-scrollbar { display: none; }

.card {
  width: 136px; flex-shrink: 0; text-align: left; scroll-snap-align: start;
  background: none; padding: 0;
}
.card__frame { position: relative; margin-bottom: 9px; }
.card__art {
  width: 136px; height: 136px; border-radius: var(--r-md);
  box-shadow: 0 4px 14px rgba(0,0,0,.4);
  transition: transform .14s;
}
.card:active .card__art { transform: scale(.955); }

/* The play affordance rides on the artwork, revealed on hover and always shown
   on touch — where there is no hover and no room for ambiguity. */
.card__go {
  position: absolute; right: 8px; bottom: 8px;
  width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10,10,12,.82); backdrop-filter: blur(6px);
  color: #fff; font-size: 10px;
  opacity: 0; transform: translateY(5px); transition: opacity .16s, transform .16s;
}
.card:hover .card__go { opacity: 1; transform: translateY(0); }
@media (hover: none) { .card__go { opacity: 1; transform: none; } }
.card--playing .card__go { opacity: 1; transform: none; background: var(--pax); }

.card__title {
  font-size: 12.5px; font-weight: 600; line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.card--playing .card__title { color: var(--pax); }
.card__sub {
  font-size: 11px; color: var(--text-mute); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --------------------------------------------------------------------- moods
   The one shelf that works against any provider. A rider who doesn't have a
   song in mind — most of them — starts here. */
.shelf__row--moods { gap: 11px; }
.mood {
  position: relative; overflow: hidden; flex-shrink: 0;
  width: 168px; height: 92px; padding: 12px 13px;
  border-radius: var(--r-md); scroll-snap-align: start;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 3px;
  text-align: left; color: #fff;
  background: linear-gradient(135deg, var(--m1), var(--m2));
  transition: transform .13s;
}
.mood::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 35%, rgba(0,0,0,.42));
}
.mood > * { position: relative; z-index: 1; }
.mood:active { transform: scale(.965); }
.mood__label { font-size: 14px; font-weight: 750; letter-spacing: -.015em; }
.mood__sub { font-size: 10.5px; opacity: .85; }
/* Light gradients need dark type, not a heavier scrim. */
.mood--dark { color: #16110a; }
.mood--dark::after { background: linear-gradient(180deg, transparent 40%, rgba(255,255,255,.28)); }
.mood--dark .mood__sub { opacity: .72; }

/* -------------------------------------------------------------------- tiles */
.tiles {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 0 16px;
}
.tile {
  height: 62px; border-radius: var(--r-md); padding: 12px;
  font-size: 13px; font-weight: 700; text-align: left; color: #fff;
  display: flex; align-items: flex-end; overflow: hidden; position: relative;
  transition: transform .12s;
}
.tile:active { transform: scale(.97); }
.tile--0 { background: linear-gradient(135deg, #7b61ff, #43e5ff); }
.tile--1 { background: linear-gradient(135deg, #ff6b9d, #ffc371); }
.tile--2 { background: linear-gradient(135deg, #11998e, #38ef7d); }
.tile--3 { background: linear-gradient(135deg, #f7971e, #ffd200); color: #1a1a1a; }
.tile--4 { background: linear-gradient(135deg, #c31432, #240b36); }
.tile--5 { background: linear-gradient(135deg, #4568dc, #b06ab3); }

.bigsearch {
  display: flex; align-items: center; gap: 13px; width: calc(100% - 32px);
  margin: 0 16px; padding: 15px; text-align: left;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
}
.bigsearch__icon { font-size: 20px; color: var(--pax); }
.bigsearch strong { display: block; font-size: 13.5px; margin-bottom: 3px; }
.bigsearch em, .bigsearch span span, .bigsearch > span:last-child {
  font-size: 11.5px; color: var(--text-mute); line-height: 1.4; font-style: normal;
}

.pax__foot {
  padding: 26px 16px 8px; text-align: center;
  font-size: 11px; color: var(--text-mute);
}

/* Queue rows are wider than search rows — the remove button needs a target big
   enough to hit at a red light, without crowding the title. */
.row--queue { padding-right: 6px; }
.row--queue .row__actions { margin-left: 4px; }

.np__auto {
  margin-top: 14px; padding: 11px 14px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--border);
  font-size: 11.5px; color: var(--text-dim); line-height: 1.55; text-align: left;
}

/* --------------------------------------------------------------- mini player */
/* Sits directly on top of the tab bar. `bottom` is measured from the bar's real
   height rather than assumed: a hard-coded 62px is where the bar ends only on
   hardware with no home indicator, and on everything newer the mini player was
   hiding behind it. */
.mini {
  position: absolute; left: 8px; right: 8px; z-index: 30;
  bottom: calc(var(--tabbar-h) + var(--safe-b));
  display: flex; align-items: center; gap: 11px;
  padding: 9px 11px; border-radius: 14px;
  background:
    linear-gradient(120deg, color-mix(in srgb, var(--m1, #2a2a34) 34%, transparent),
                            color-mix(in srgb, var(--m2, #2a2a34) 34%, transparent)),
    rgba(30,30,38,.97);
  backdrop-filter: blur(16px);
  border: 1px solid var(--border-2);
  box-shadow: 0 10px 30px rgba(0,0,0,.55);
  transform: translateY(140%); opacity: 0;
  transition: transform .24s cubic-bezier(.2,.9,.3,1), opacity .2s;
  overflow: hidden;
}
.mini--show { transform: translateY(0); opacity: 1; }
.mini__tap { display: flex; align-items: center; gap: 11px; flex: 1; min-width: 0; cursor: pointer; }
.mini__art {
  width: 40px; height: 40px; border-radius: 8px; flex-shrink: 0;
  box-shadow: 0 3px 10px rgba(0,0,0,.45);
}
.mini__meta { flex: 1; min-width: 0; }
.mini__title {
  font-size: 12.5px; font-weight: 650; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.mini__sub {
  font-size: 10.5px; color: rgba(255,255,255,.6); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mini__btn {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.94); color: #111; font-size: 12px;
  transition: transform .12s;
}
.mini__btn:active { transform: scale(.9); }
.mini__btn--ghost { background: none; color: rgba(255,255,255,.7); font-size: 11px; }
.mini__btn--ghost:hover { color: #fff; }
.mini__bar { position: absolute; left: 0; right: 0; top: 0; height: 2px; background: rgba(255,255,255,.12); }
.mini__fill { height: 100%; background: #fff; transition: width .3s linear; }

/* ------------------------------------------------------------------ tab bar */
.tabbar {
  display: flex; flex-shrink: 0; z-index: 35;
  border-top: 1px solid var(--border); background: rgba(12,12,15,.98);
  backdrop-filter: blur(14px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.tabbar__item {
  flex: 1; padding: 9px 4px 10px; position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  font-size: 10px; font-weight: 600; color: var(--text-mute); transition: color .15s;
}
.tabbar__icon { font-size: 17px; line-height: 1; }
.tabbar__item--active { color: var(--pax); }
.tabbar__badge {
  position: absolute; top: 5px; right: 50%; margin-right: -22px;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
  background: var(--pax); color: #fff; font-size: 9.5px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}

/* ------------------------------------------------------------- full player */
.player {
  position: absolute; inset: 0; z-index: 60;
  background: var(--bg);
  display: flex; flex-direction: column;
  transform: translateY(100%); transition: transform .3s cubic-bezier(.2,.9,.3,1);
  overflow-y: auto;
}
.player--open { transform: translateY(0); }

/* The sheet takes the current artwork's colours (--h1/--h2, set per track), so
   opening it reads as opening this song rather than opening a panel. */
.player__wash {
  position: absolute; left: 0; right: 0; top: 0; height: 62%;
  pointer-events: none; z-index: 0;
  background:
    radial-gradient(90% 70% at 50% 0%, var(--h1, var(--pax)), transparent 72%),
    radial-gradient(80% 60% at 20% 22%, var(--h2, var(--pax-dim)), transparent 72%);
  opacity: .3;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, transparent 100%);
}
.player > *:not(.player__wash) { position: relative; z-index: 1; }

.player__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px 4px; flex-shrink: 0;
}
.player__close {
  width: 34px; height: 34px; border-radius: 50%; font-size: 19px; line-height: 1;
  color: var(--text-dim); display: flex; align-items: center; justify-content: center;
}
.player__close:hover { background: var(--surface-2); color: var(--text); }
.player__from {
  font-size: 9.5px; letter-spacing: .16em; color: var(--text-mute); font-weight: 700;
}
.player__spacer { width: 34px; }

.player .np--pax {
  display: block; text-align: center; padding: 8px 26px 30px;
  border-bottom: none;
}
.player__art { padding: 18px 0 26px; }
.player__artimg {
  width: 100%; max-width: 300px; aspect-ratio: 1; height: auto; margin: 0 auto;
  border-radius: var(--r-lg); box-shadow: 0 22px 48px rgba(0,0,0,.55);
}
.player__meta { text-align: left; }
.player__title {
  font-size: 22px; font-weight: 800; letter-spacing: -.02em; line-height: 1.25;
}
.player__artist { font-size: 15px; color: var(--text-dim); margin-top: 5px; }
.player .progress { margin-top: 22px; }
.player .transport--pax { justify-content: center; gap: 26px; margin-top: 20px; }
.player .tp-btn { width: 46px; height: 46px; font-size: 15px; }
.player .tp-btn--main { width: 62px; height: 62px; font-size: 20px; }
.player .np__hint { text-align: center; margin-top: 18px; }

.player__next {
  margin-top: 26px; padding: 13px 15px; text-align: left;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
}
.player__nextlabel {
  font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-mute); margin-bottom: 5px;
}
.player__nexttrack {
  font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ------------------------------------------------------------- progress */
.progress { margin-top: 14px; }
.progress__bar {
  height: 5px; background: var(--surface-3); border-radius: 3px; position: relative;
  cursor: pointer; overflow: hidden;
}
.progress__bar--static { cursor: default; }
.progress__fill { height: 100%; background: var(--driver); border-radius: 3px; transition: width .25s linear; }
.progress__fill--pax { background: var(--pax); }
.progress__times {
  display: flex; justify-content: space-between; margin-top: 6px;
  font-size: 11px; color: var(--text-mute); font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------- transport */
.transport { display: flex; align-items: center; gap: 12px; margin-top: 16px; }
.tp-btn {
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--surface-2); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center; font-size: 14px;
  transition: .15s; color: var(--text-dim);
}
.tp-btn:hover:not(:disabled) { background: var(--surface-3); color: var(--text); border-color: var(--border-2); }
.tp-btn:active:not(:disabled) { transform: scale(.92); }
.tp-btn:disabled { opacity: .3; cursor: not-allowed; }
.tp-btn--main {
  width: 52px; height: 52px; background: var(--driver); color: #000;
  border-color: var(--driver); font-size: 17px;
}
.tp-btn--main:hover:not(:disabled) { background: #c8ff5c; color: #000; border-color: #c8ff5c; }
.tp-btn--danger:hover:not(:disabled) { color: var(--danger); border-color: var(--danger); background: rgba(255,77,94,.1); }

.volume { display: flex; align-items: center; gap: 9px; margin-left: auto; min-width: 150px; }
.volume__icon { font-size: 13px; color: var(--text-mute); }
.volume__val { font-size: 11px; color: var(--text-mute); width: 30px; text-align: right; font-variant-numeric: tabular-nums; }

input[type=range] {
  -webkit-appearance: none; appearance: none;
  height: 4px; border-radius: 2px; background: var(--surface-3); flex: 1; outline: none;
}
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 14px; height: 14px; border-radius: 50%; background: var(--driver); cursor: pointer;
  border: 2px solid var(--bg);
}
input[type=range]::-moz-range-thumb {
  width: 12px; height: 12px; border-radius: 50%; background: var(--driver);
  cursor: pointer; border: 2px solid var(--bg);
}

/* ------------------------------------------------------------------ tabs */
.tabs { display: flex; gap: 4px; padding: 10px 16px 0; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.tab {
  font-size: 12.5px; font-weight: 600; padding: 9px 13px;
  color: var(--text-mute); border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: .15s; display: flex; align-items: center; gap: 6px;
}
.tab:hover { color: var(--text-dim); }
.tab:active { color: var(--text); }
.iconbtn:active:not(:disabled) { transform: scale(.9); }
.tab--active { color: var(--text); border-bottom-color: var(--driver); }
.tab--active.tab--pax { border-bottom-color: var(--pax); }
.tab__count {
  font-size: 10px; padding: 1px 6px; border-radius: 999px;
  background: var(--surface-3); color: var(--text-dim); font-variant-numeric: tabular-nums;
}

/* ----------------------------------------------------------------- lists */
.section-label {
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--text-mute);
  padding: 16px 16px 8px;
}
.list { padding: 4px 8px 20px; }

.row {
  display: flex; align-items: center; gap: 12px; padding: 9px 8px;
  border-radius: var(--r-md); transition: background .12s;
}
.row:hover { background: var(--surface); }
.row__art { width: 44px; height: 44px; border-radius: var(--r-sm); }
.row__main { flex: 1; min-width: 0; }
.row__title {
  font-size: 13.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: flex; align-items: center; gap: 6px;
}
.row__sub {
  font-size: 11.5px; color: var(--text-mute); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.row__actions { display: flex; gap: 5px; flex-shrink: 0; }
.row__index {
  width: 20px; text-align: center; font-size: 11px; color: var(--text-mute);
  font-variant-numeric: tabular-nums; flex-shrink: 0;
}
.row--playing { background: rgba(184,255,60,.06); }
.row--mine { box-shadow: inset 2px 0 0 var(--pax); }

.iconbtn {
  width: 30px; height: 30px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-mute); font-size: 13px; transition: .13s;
  border: 1px solid transparent;
}
.iconbtn:hover { background: var(--surface-3); color: var(--text); }
.iconbtn--veto:hover  { background: rgba(255,77,94,.14); color: var(--danger); border-color: rgba(255,77,94,.3); }
.iconbtn--block:hover { background: rgba(255,176,32,.14); color: var(--warn); border-color: rgba(255,176,32,.3); }
.iconbtn--add { color: var(--pax); border-color: var(--border); }
.iconbtn--add:hover { background: var(--pax); color: #fff; border-color: var(--pax); }
/* Removing from up next is destructive but reversible-by-re-adding, so it reads
   as quiet until touched rather than alarming by default. */
.iconbtn--remove { width: 34px; height: 34px; font-size: 13px; }
.iconbtn--remove:hover {
  background: rgba(255,77,94,.14); color: var(--danger); border-color: rgba(255,77,94,.3);
}
.iconbtn:disabled { opacity: .3; cursor: not-allowed; }
.iconbtn:disabled:hover { background: none; color: var(--text-mute); border-color: transparent; }

.badge {
  font-size: 9px; font-weight: 700; padding: 1px 5px; border-radius: 3px;
  letter-spacing: .04em; flex-shrink: 0;
}
.badge--e     { background: var(--surface-3); color: var(--text-dim); }
.badge--auto  { background: rgba(107,114,128,.25); color: #9ca3af; }
.badge--blocked { background: rgba(255,176,32,.16); color: var(--warn); }

.empty { text-align: center; padding: 44px 24px; color: var(--text-mute); font-size: 13px; line-height: 1.65; }
.empty__icon { font-size: 30px; opacity: .35; display: block; margin-bottom: 12px; }
/* An empty state that only says "nothing here" leaves the rider stuck. Each one
   gets a heading, a sentence explaining what happens next, and a way out. */
.empty strong {
  display: block; color: var(--text); font-size: 15px; font-weight: 700;
  letter-spacing: -.01em; margin-bottom: 6px;
}
.empty__cta {
  display: inline-block; margin-top: 16px; padding: 9px 18px;
  border-radius: 999px; border: 1px solid var(--border-2);
  color: var(--text); font-size: 12.5px; font-weight: 600;
  transition: background .15s, border-color .15s;
}
.empty__cta:hover { background: var(--surface-2); border-color: var(--pax); }

/* ---------------------------------------------------------------- skeletons */
.skel {
  background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 50%, var(--surface) 75%);
  background-size: 300% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
  border-radius: var(--r-sm);
}
@keyframes shimmer { to { background-position: -300% 0; } }
@media (prefers-reduced-motion: reduce) {
  .skel { animation: none; background: var(--surface); }
}
.row--skel, .card--skel { pointer-events: none; }
.skel__art  { width: 44px; height: 44px; border-radius: var(--r-sm); flex-shrink: 0; }
.skel__card { width: 136px; height: 136px; border-radius: var(--r-md); margin-bottom: 9px; }
.skel__line { height: 10px; border-radius: 5px; }
.skel__line--title { width: 62%; margin-bottom: 7px; }
.skel__line--sub   { width: 38%; height: 8px; }
.card--skel .skel__line--title { width: 100%; }
.card--skel .skel__line--sub   { width: 64%; margin-top: 6px; }

/* ---------------------------------------------------------------- search */
.searchbar { padding: 14px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.searchbar__field { position: relative; display: flex; align-items: center; }
.searchbar__icon { position: absolute; left: 13px; font-size: 13px; color: var(--text-mute); pointer-events: none; }
.searchbar input {
  width: 100%; padding: 11px 38px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text); font-size: 13.5px; outline: none; transition: .15s;
}
.searchbar input:focus { border-color: var(--pax); background: var(--surface-3); }
.searchbar input::placeholder { color: var(--text-mute); }
.searchbar__clear { position: absolute; right: 8px; }

.chips { display: flex; gap: 7px; overflow-x: auto; padding: 12px 16px; scrollbar-width: none; }
.chips::-webkit-scrollbar { display: none; }
.chip {
  font-size: 11.5px; font-weight: 600; padding: 7px 13px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-dim); white-space: nowrap; transition: .13s; flex-shrink: 0;
}
.chip:hover { border-color: var(--border-2); color: var(--text); }
.chip--active { background: var(--pax); border-color: var(--pax); color: #fff; }

.spinner {
  width: 15px; height: 15px; border: 2px solid var(--surface-3);
  border-top-color: var(--pax); border-radius: 50%;
  animation: spin .7s linear infinite; margin: 30px auto;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* -------------------------------------------------------------- settings */
/* ------------------------------------------------------- driver profile */
.section-label__hint { text-transform: none; letter-spacing: 0; color: var(--text-mute); }
.profile {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  padding: 4px 16px 12px;
}

/* These four fields are a form, not switches: they are only written when the
   driver presses Update, so the row has to say plainly whether what is on
   screen has been saved yet. */
.profile-actions {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 0 16px 16px; border-bottom: 1px solid var(--border);
}
.profile-actions__btn {
  padding: 9px 20px; border-radius: var(--r-sm);
  background: var(--driver); color: #000; font-weight: 700; font-size: 13px;
  border: 1px solid var(--driver); transition: background .15s, opacity .15s;
}
.profile-actions__btn:hover:not(:disabled) { background: #c8ff5c; }
.profile-actions__btn:active:not(:disabled) { transform: scale(.97); }
.profile-actions__btn:disabled {
  background: var(--surface-2); border-color: var(--border);
  color: var(--text-mute); cursor: default;
}
.profile-actions__hint { font-size: 11.5px; color: var(--text-mute); }
.profile-actions__hint--dirty { color: var(--warn); }
.field { display: block; }
.field__label {
  display: block; font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-mute); margin-bottom: 5px;
}
.field__input {
  width: 100%; padding: 9px 11px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text); font-size: 13px; outline: none; transition: border-color .15s;
}
.field__input:focus { border-color: var(--driver); background: var(--surface-3); }

/* --------------------------------------------------------- install prompt */
.install {
  display: flex; align-items: center; gap: 12px;
  margin: 12px 16px 4px; padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--driver-dim); border-radius: var(--r-md);
}
.install__text { flex: 1; min-width: 0; font-size: 12px; color: var(--text-dim); line-height: 1.5; }
.install__text strong { display: block; color: var(--text); font-size: 13px; margin-bottom: 3px; }
.install__btn {
  padding: 8px 14px; border-radius: var(--r-sm); flex-shrink: 0;
  background: var(--driver); color: #000; font-weight: 700; font-size: 12px;
}

.setting {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 13px 16px; border-bottom: 1px solid var(--border);
}
.setting__label { font-size: 13px; font-weight: 600; }
.setting__desc { font-size: 11.5px; color: var(--text-mute); margin-top: 3px; line-height: 1.5; }
.setting__text { min-width: 0; }

.toggle {
  width: 42px; height: 24px; border-radius: 999px; background: var(--surface-3);
  position: relative; transition: background .18s; flex-shrink: 0;
  border: 1px solid var(--border);
}
.toggle::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: 50%; background: var(--text-dim);
  transition: transform .18s, background .18s;
}
.toggle--on { background: var(--driver-dim); border-color: var(--driver); }
.toggle--on::after { transform: translateX(18px); background: var(--driver); }

.stepper { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.stepper__val { font-size: 13px; font-weight: 700; width: 18px; text-align: center; font-variant-numeric: tabular-nums; }
.stepper button {
  width: 26px; height: 26px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-dim);
  display: flex; align-items: center; justify-content: center; font-size: 14px;
}
.stepper button:hover { background: var(--surface-3); color: var(--text); }

/* ---------------------------------------------------------------- pairing */
.pair { padding: 22px 16px; text-align: center; }
.pair__qr {
  width: 190px; height: 190px; margin: 0 auto 16px; padding: 10px;
  background: #fff; border-radius: var(--r-md);
}
.pair__qr svg { display: block; }
.pair__code {
  font-family: var(--mono); font-size: 30px; font-weight: 700; letter-spacing: .18em;
  color: var(--driver); margin: 6px 0 4px;
}
.pair__hint { font-size: 12px; color: var(--text-mute); line-height: 1.65; max-width: 320px; margin: 8px auto 0; }
.pair__url {
  font-family: var(--mono); font-size: 10px; color: var(--text-mute);
  word-break: break-all; margin-top: 12px; padding: 9px 11px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm);
  max-width: 340px; margin-left: auto; margin-right: auto;
}

.pax-list { display: flex; flex-direction: column; gap: 2px; padding: 4px 8px 16px; }
.pax-row { display: flex; align-items: center; gap: 11px; padding: 9px 8px; border-radius: var(--r-md); }
.pax-row:hover { background: var(--surface); }
.pax-avatar {
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: #fff;
}

/* ------------------------------------------------------------- activity */
.feed { padding: 6px 16px 20px; }
.feed__item {
  display: flex; gap: 10px; padding: 8px 0; font-size: 12px;
  color: var(--text-dim); border-bottom: 1px solid rgba(255,255,255,.03);
  line-height: 1.5;
}
.feed__dot { width: 6px; height: 6px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; background: var(--text-mute); }
.feed__dot--veto { background: var(--danger); }
/* A rider tidying up, not the driver overruling — deliberately not danger red. */
.feed__dot--remove { background: var(--text-dim); }
.feed__dot--takeover { background: var(--pax); }
.feed__dot--block { background: var(--warn); }
.feed__dot--request { background: var(--pax); }
.feed__dot--join { background: var(--ok); }
.feed__dot--skip { background: var(--danger); }
.feed__dot--vote { background: var(--warn); }
.feed__dot--autodj { background: var(--text-mute); }
.feed__time { margin-left: auto; font-size: 10.5px; color: var(--text-mute); flex-shrink: 0; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------- toasts */
.toasts {
  position: absolute; bottom: 14px; left: 12px; right: 12px;
  display: flex; flex-direction: column; gap: 8px; pointer-events: none; z-index: 40;
}
.toast {
  background: var(--surface-3); border: 1px solid var(--border-2);
  border-radius: var(--r-md); padding: 11px 13px; font-size: 12.5px; line-height: 1.45;
  box-shadow: 0 10px 28px rgba(0,0,0,.5);
  animation: toast-in .22s cubic-bezier(.2,.9,.3,1.2);
  display: flex; gap: 9px; align-items: flex-start;
}
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } }
.toast--err  { border-color: rgba(255,77,94,.45); background: #2a1417; }
.toast--ok   { border-color: rgba(74,222,128,.4);  background: #12231a; }
.toast--warn { border-color: rgba(255,176,32,.4);  background: #2a2113; }
.toast__icon { flex-shrink: 0; }
/* Repeat counter on a deduped toast. Pushed to the right edge so the message
   itself never shifts as the count climbs. */
.toast__count {
  flex-shrink: 0; margin-left: auto; padding-left: 10px;
  font-variant-numeric: tabular-nums; font-weight: 600; opacity: .72;
}

/* --------------------------------------------------------- passenger CTA */
.np__hint {
  margin-top: 14px; font-size: 11.5px; color: var(--text-mute); line-height: 1.5;
}

/* Whole result rows are tap targets — the primary action is "play this now". */
.row--tappable[data-playrow] { cursor: pointer; }
.row--tappable[data-playrow]:active { background: var(--surface-3); }
.iconbtn--play {
  color: var(--pax); border-color: var(--border); font-size: 11px;
}
.iconbtn--play:hover:not(:disabled) { background: var(--pax); color: #fff; border-color: var(--pax); }
.badge--live { background: rgba(184,255,60,.16); color: var(--driver); }

/* --------------------------------------------------------------- account */
.account { padding: 4px 16px 20px; }
.account__pitch { display: flex; flex-direction: column; gap: 5px; margin-bottom: 13px; }
.account__pitch strong { font-size: 13.5px; font-weight: 650; }
.account__pitch span { font-size: 12px; color: var(--text-dim); line-height: 1.55; }
/* Google's button renders itself in here; leave its own metrics alone. */
.account__gbtn { min-height: 40px; }
.account__err {
  margin-top: 10px; font-size: 12px; color: #ffb3bb;
  background: rgba(255,77,94,.12); border: 1px solid rgba(255,77,94,.3);
  border-radius: var(--r-sm); padding: 8px 11px; line-height: 1.5;
}

.account--in .account__who { display: flex; align-items: center; gap: 11px; }
.account__pic { width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0; object-fit: cover; }
.account__pic--none {
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-3); font-size: 13px; font-weight: 700; color: var(--text-dim);
}
.account__meta { flex: 1; min-width: 0; }
.account__name { font-size: 13.5px; font-weight: 650; }
.account__email {
  font-size: 11.5px; color: var(--text-mute); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.account__status { margin-top: 10px; font-size: 11px; color: var(--text-mute); }
.account__status--saving { color: var(--warn); }
.account__status--saved  { color: var(--ok); }
.account__status--error  { color: var(--danger); }

/* ---------------------------------------------------------- never-play list */
.blocklist { padding: 4px 12px 24px; }
.blockrow {
  display: flex; align-items: center; gap: 10px; padding: 9px 6px;
  border-bottom: 1px solid var(--border);
}
.blockrow:last-child { border-bottom: none; }

.notice-strip {
  padding: 10px 14px; font-size: 12px; line-height: 1.5;
  background: rgba(255,176,32,.1); border-bottom: 1px solid rgba(255,176,32,.24);
  color: #ffd48a; display: flex; gap: 9px; align-items: flex-start;
}

/* ============================================================================
   Responsive

   Three surfaces have to survive being narrow, and they fail differently:

   - The demo stage is two device mock-ups side by side. Below ~1060px they no
     longer fit, so they stack — and their fixed screen heights become a
     problem, because a 660px screen on a 700px-tall laptop leaves the second
     device permanently off the bottom.
   - The driver's full-window view is the one that actually broke. Its transport
     row is six round buttons plus a volume slider — around 480px of content
     that had nothing telling it to wrap, so on any phone the skip and block
     buttons sat off the right edge, unreachable. The five tabs overflowed the
     same way.
   - The passenger's full-window view is phone-shaped by design, but its mini
     player was positioned a fixed 62px above the bottom, which is where the tab
     bar is only on hardware with no home indicator. On any modern iPhone the
     tab bar is ~34px taller and the mini player hid behind it.
   ========================================================================== */

/* -------------------------------------------------- things that are always on
   Not breakpoint-gated: a transport row that wraps when it must is correct at
   every width, and a phone in landscape is short rather than narrow. */

/* The dash's controls. Wrapping is the whole fix: at 620px they stay on one
   line exactly as before, and below that they fold instead of vanishing. */
.transport { flex-wrap: wrap; row-gap: 12px; }
.volume { flex: 1 1 150px; }

/* Five tabs do not fit on a phone. Let them scroll sideways rather than clip —
   an unreachable Rules tab is a driver who cannot turn the explicit filter off. */
.tabs {
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { display: none; }
/* A scroll container clips at its padding box, which would eat the 1px the
   active tab's underline used to hang below itself to cover the divider. Sit it
   flush instead — a pixel nobody can see, in exchange for reachable tabs. */
.tab { flex-shrink: 0; white-space: nowrap; margin-bottom: 0; }

/* The now-playing block is content, not a spacer: without this it can be
   squeezed by whatever shares its column, so on a short screen the video is
   clipped instead of the dash scrolling. It now lives inside .pane__scroll,
   where scrolling past it is the intended way to get it off the screen. */
.pane__scroll > [data-el="np"] { flex-shrink: 0; }

/* YouTube's terms put a floor under the player, so it cannot simply scale down.
   Keeping it inside the pane is the most that can be done. */
.np__stage, .np__stage--audio, .np__video, .np__video--offstage { max-width: 100%; }

/* The full-screen player scrolls its own content — a landscape phone is barely
   400px tall and the artwork alone is 300. */
.player { overscroll-behavior: contain; }
.player .np--pax { padding-bottom: calc(30px + var(--safe-b)); }

/* ------------------------------------------------------------- demo stage */
@media (max-width: 1060px) {
  .stage { gap: 24px; }
  .device--tablet { width: 560px; }
  /* Once the two devices are stacked, a fixed 660px screen is taller than most
     laptop viewports. Cap against the viewport and keep a usable floor. */
  .device--tablet .screen { height: clamp(460px, 78vh, 660px); }
  .device--phone .screen  { height: clamp(480px, 80vh, 690px); }
}

/* ----------------------------------------------------------------- phones */
@media (max-width: 620px) {
  .stage { padding: 16px 10px 40px; }
  .device--tablet, .device--phone { width: 100%; }

  .np--driver { flex-direction: column; align-items: stretch; gap: 14px; }
  .np__art-lg { width: 96px; height: 96px; }

  /* Six 40px circles plus gaps is 324px before the volume slider — more than a
     360px phone has once padding is taken out. Shrink the targets a little and
     give the slider its own line. */
  .np { padding: 14px 12px; }
  .np__title { font-size: 18px; }
  .transport { gap: 8px; }
  .tp-btn { width: 38px; height: 38px; font-size: 13px; }
  .tp-btn--main { width: 48px; height: 48px; font-size: 16px; }
  .volume { flex: 1 0 100%; margin-left: 0; min-width: 0; }

  .tabs { padding: 8px 10px 0; }
  .tab { padding: 9px 10px; font-size: 12px; }

  .pane__head, .pax__top { padding-left: 12px; padding-right: 12px; }
  .greet__hi { font-size: 20px; }
  .list { padding-left: 4px; padding-right: 4px; }
}

/* ------------------------------------------------------- very narrow phones */
@media (max-width: 380px) {
  .np__stage--video, .np__video { width: 200px; height: 200px; }   /* the terms' floor */
  .np__stage--audio, .np__video--offstage { width: 200px; height: 200px; }
  .tp-btn { width: 34px; height: 34px; }
  .tp-btn--main { width: 44px; height: 44px; }
  .hero { gap: 10px; }
  .hero__art { width: 56px; height: 56px; }
}

/* ------------------------------------------------------- short / landscape
   A phone on its side is 360-430px tall. The rider's artwork and the driver's
   video both have to give way, or the controls end up below the fold. */
@media (max-height: 560px) {
  .player__art { padding: 10px 0 14px; }
  .player__artimg { max-width: min(300px, 34vh); }
  .player .np--pax { padding-top: 0; }
  .np__art-lg { width: 84px; height: 84px; }
  .greet { padding-top: 10px; padding-bottom: 0; }
}

/* --------------------------------------------------------- big screens
   ?role=passenger opened on a laptop should not stretch a phone layout across
   1400px of glass. Centre it at a phone's width and let the rest be backdrop. */
@media (min-width: 900px) {
  /* The passenger only. The driver's view is a dash tablet and wants the width. */
  .fullscreen-host .device:has(.pax) { max-width: 460px; margin: 0 auto; }
  .fullscreen-host .device:has(.pax) .screen {
    border-left: 1px solid var(--border); border-right: 1px solid var(--border);
  }
}

/* ==========================================================================
   The driver gate — what fills the driver screen before there is a driver.

   Sized in the screen rather than the viewport: on the landing page this is a
   phone-shaped device frame, and a 100vh block inside one overflows it. The
   driver pane it replaces is a flex column filling the same box, so this
   matches that and centres inside it.
   ========================================================================== */
.gate {
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 40px 26px;
  text-align: center;
}
.gate__mark {
  font-size: 12px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--text-mute);
}
.gate__title {
  margin: 0; font-size: clamp(26px, 5vw, 38px); font-weight: 800; letter-spacing: -.03em;
}
.gate__title span { color: var(--driver); }
.gate__sub {
  margin: 0; max-width: 380px;
  color: var(--text-dim); font-size: 14px; line-height: 1.6;
}
.gate__sub strong { color: var(--text); display: block; margin-bottom: 6px; }

/* Google's button is an iframe of a fixed size that it picks itself, so this
   reserves the space rather than sizing it — otherwise the panel jumps as the
   SDK finishes loading. */
.gate__btn { min-height: 44px; display: flex; justify-content: center; }

.gate__hint {
  max-width: 400px;
  padding: 14px 16px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  color: var(--text-mute); font-size: 12px; line-height: 1.7;
  text-align: left;
}
.gate__hint code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px; color: var(--text-dim);
  background: var(--surface-2); border-radius: 4px; padding: 1px 5px;
}
.gate__err {
  max-width: 380px;
  color: var(--danger); font-size: 13px; line-height: 1.5;
}
