/* Palette repointed to the "PolanskiBros Branding 2026" identity (see
   /home/broot/temp/PolanskiBros Branding 2026/PolanskiBros_Brand_Color_Canvas.png):
   Matte Black / Carbon / Gunmetal backgrounds, Off White / Steel text, Neon
   Red as the single signature accent (CTAs, highlights, on-air), Warning Red
   as its darker secondary partner. Previously this file had its own
   invented blue-tinted dark palette and an orange/amber accent pair that
   matched neither the brand canvas nor the neon-red PB monogram icons. */
:root {
  --bg: #080808;
  --bg-panel: #151515;
  --bg-panel-2: #2a2d31;
  --line: rgba(255, 255, 255, 0.08);
  --text: #ececec;
  --muted: #a7adb5;
  --accent: #ff2b2b;
  --accent-2: #d61b1b;
  --live: #ff2b2b;
  --radius: 14px;
  --max-width: 720px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  max-width: 100%;
  overflow-x: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-tap-highlight-color: transparent;
}

html {
  touch-action: manipulation;
}

body {
  min-height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
  touch-action: pan-y;
}

a { color: inherit; }

.wrap {
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 16px;
  flex: 1;
}

#player-dock {
  order: 3;
  position: sticky;
  bottom: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  background: rgba(18, 22, 31, 0.96);
  border-top: 1px solid var(--line);
  box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.25);
  backdrop-filter: blur(10px);
}

.dock-art {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

.dock-spectrum {
  display: none;
}

.hero-scrim {
  display: none;
}

.hero-top,
.hero-spacer,
.hero-note,
.hero-actions,
.hero-more-panel {
  display: none;
}

.dock-controls {
  display: contents;
}

.dock-toggle,
.dock-mute {
  cursor: pointer;
  font-family: inherit;
}

.dock-mute {
  border: 1px solid var(--line);
}

#dock-toggle { order: 2; }
#dock-mute { order: 6; }

.dock-toggle {
  position: relative;
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border-radius: 50%;
  overflow: hidden;
  background: transparent;
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Half-size orange "face" — the Brobot icon layer below stays full-size
   (it's its own complete circular badge), so the default gradient+glyph
   button is scaled down via its own wrapper instead of shrinking #dock-toggle
   itself, which would shrink both. */
.dock-toggle-face {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 50%;
  height: 50%;
  border-radius: 50%;
  background: linear-gradient(160deg, var(--accent), var(--accent-2));
  color: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.15s ease;
}

.dock-toggle-glyph {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  line-height: 1;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.dock-toggle-glyph-play { opacity: 1; }

#player-dock[data-state="playing"] .dock-toggle-glyph-pause,
#player-dock[data-state="buffering"] .dock-toggle-glyph-pause,
#player-dock[data-state="reconnecting"] .dock-toggle-glyph-pause,
#player-dock[data-state="loading"] .dock-toggle-glyph-pause {
  opacity: 1;
}

#player-dock[data-state="playing"] .dock-toggle-glyph-play,
#player-dock[data-state="buffering"] .dock-toggle-glyph-play,
#player-dock[data-state="reconnecting"] .dock-toggle-glyph-play,
#player-dock[data-state="loading"] .dock-toggle-glyph-play {
  opacity: 0;
}

.dock-toggle-logo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  pointer-events: none;
  filter: grayscale(1) brightness(0.65);
  transition: opacity 0.15s ease, filter 0.2s ease;
}

#player-dock.brobot-icon .dock-toggle-logo-brobot {
  opacity: 1;
}

#player-dock.brobot-icon .dock-toggle-face {
  opacity: 0;
}

/* Greyed out ("off") while paused, full color + brightness pulse once
   playing — same states used elsewhere for the play/pause crossfade. */
#player-dock[data-state="playing"] .dock-toggle-logo-brobot,
#player-dock[data-state="buffering"] .dock-toggle-logo-brobot,
#player-dock[data-state="reconnecting"] .dock-toggle-logo-brobot,
#player-dock[data-state="loading"] .dock-toggle-logo-brobot {
  filter: brightness(calc(1 + var(--beat, 0) * 0.6)) saturate(calc(1 + var(--beat, 0) * 0.3));
}

/* The size-pulse lives on the button (#dock-toggle) itself, not the image
   inside it. Scaling just the image within its circular clip (overflow:
   hidden + border-radius: 50% on .dock-toggle) grew/shrank it past the
   clip edge on every beat, revealing/hiding a sliver of the source art's
   black margin around the ring and reading as the ring itself flashing.
   Scaling the button scales its clip boundary and the image together, so
   the ring-to-edge ratio never changes — no more flicker, still a real
   pulse. --beat sits at 0 whenever reduced motion is on (see
   visualizer.js's stopBrobotPulseIfInactive), which collapses this to a
   no-op the same way it already does for the brightness filter above. */
#player-dock.brobot-icon[data-state="playing"] #dock-toggle,
#player-dock.brobot-icon[data-state="buffering"] #dock-toggle,
#player-dock.brobot-icon[data-state="reconnecting"] #dock-toggle,
#player-dock.brobot-icon[data-state="loading"] #dock-toggle {
  transform: scale(calc(1 + var(--beat, 0) * 0.06));
}

.dock-toggle:active,
.dock-mute:active {
  transform: scale(0.96);
}

.dock-meta {
  order: 3;
  min-width: 0;
  flex: 1;
}

.dock-status {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: 0.78rem;
}

.dock-status {
  display: none;
}

.dock-mute {
  min-width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--bg-panel-2);
  color: var(--text);
  font-size: 1rem;
}

#player-dock[data-state="buffering"] #dock-toggle,
#player-dock[data-state="reconnecting"] #dock-toggle,
#player-dock[data-state="loading"] #dock-toggle {
  opacity: 0.7;
}

#player-dock[data-state="offline"] .dock-status,
#player-dock[data-state="fatal-error"] .dock-status {
  color: var(--live);
}

/* iOS can fully suspend/kill a backgrounded home-screen PWA, which wipes
   the audio session and drops us back to "idle" with no playback — the
   app can't autoplay its way out of that (no user gesture in a fresh
   page load), so this is the visual nudge telling the listener a tap
   will pick back up where they left off, instead of the toggle looking
   like ordinary idle state. */
#player-dock[data-resume-primed="true"] #dock-toggle {
  animation: pulse 2s infinite;
}

body.motion-reduced #player-dock[data-resume-primed="true"] #dock-toggle {
  animation: none;
}

#player-dock[data-resume-primed="true"] .dock-status {
  color: var(--live);
}

@media (min-width: 560px) {
  .dock-status {
    display: block;
  }
}

@media (min-width: 720px) {
  #player-dock {
    max-width: var(--max-width);
    margin: 0 auto;
    border: 1px solid var(--line);
    border-bottom: none;
    border-radius: var(--radius) var(--radius) 0 0;
  }
}

/* ---------------------------------------------------------------------- */
/* Hero "now playing" player — always full-bleed and always visible on    */
/* every page. Schedule/DJs/Archive/Settings float over it as cards       */
/* (.card-overlay below) instead of replacing it. Full-bleed background   */
/* art with a station-branded gradient fallback, big on-air DJ identity,  */
/* honest transport controls (no fake seek/skip — this is a live         */
/* broadcast, not an on-demand track).                                    */
/* ---------------------------------------------------------------------- */

#player-dock {
  position: fixed;
  inset: 0;
  z-index: 5;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  margin: 0;
  max-width: none;
  padding: 0;
  border: none;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(255, 43, 43, 0.16) 0%, transparent 55%),
    linear-gradient(165deg, #151515 0%, #080808 60%);
}

.hero-bg {
  order: initial;
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  flex: none;
  border: none;
  border-radius: 0;
  overflow: hidden;
  background: none;
}

.dock-art {
  opacity: 0;
  transition: opacity 0.3s ease;
}

.dock-art.has-artwork {
  opacity: 1;
}

/* Sized/positioned by visualizer.js's applyGeometry() from the studio-
   configured width/height/offset — the fallback left/bottom/width/height
   below only cover the brief window before that JS runs (or if the config
   fetch never resolves). z-index 1 lifts it above .hero-scrim (auto/0
   within this same stacking context), since the scrim's gradient is
   nearly opaque black at the very bottom — without this the bars would
   render right where the scrim is darkest. */
.dock-spectrum {
  display: block;
  position: absolute;
  left: 20%;
  bottom: 12px;
  z-index: 1;
  width: 60%;
  height: 40px;
  opacity: 0.92;
  pointer-events: none;
}

.hero-scrim {
  display: block;
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(8, 8, 8, 0.6) 0%, rgba(8, 8, 8, 0.15) 28%, rgba(8, 8, 8, 0.55) 62%, rgba(8, 8, 8, 0.97) 100%);
}

.hero-fg {
  display: flex;
  flex-direction: column;
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  padding: max(18px, env(safe-area-inset-top)) 22px max(calc(20px + env(safe-area-inset-bottom)), calc(var(--eq-clearance, 52px) + 16px));
}

/* Wraps everything except #dock-spectrum (see the HTML) — #dock-spectrum is
   a sibling of this div, not a descendant, so it never inherits the idle
   opacity fade below. The fade itself lives on .hero-fade-group (a child of
   this element), not here, for the same reason: .hero-top (brand + on-air
   indicator) is also a direct child of .hero-controls, sitting outside
   .hero-fade-group, so it stays visible whenever the dock is idle too — a
   child can't opt back out of an ancestor's opacity, so anything that must
   stay visible has to live outside the fading subtree entirely. */
.hero-controls {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  width: 100%;
}

/* Everything except .hero-top (see the comment above) — this is what
   actually fades on idle. */
.hero-fade-group {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  order: 2;
  transition: opacity 0.5s ease;
}

#player-dock.controls-idle .hero-fade-group {
  opacity: 0;
  pointer-events: none;
}

.hero-top {
  order: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex: none;
}

.hero-brand {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  opacity: 0.85;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hero-brand .bros {
  color: var(--accent);
}

.hero-onair {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.hero-onair .label {
  text-decoration: none;
}

.hero-onair.locals-nudge .label:hover,
.hero-onair.locals-nudge .label:focus-visible {
  color: var(--text);
  text-decoration: underline;
}

.hero-onair.locals-nudge .label:focus-visible {
  outline: 1.5px solid var(--accent);
  outline-offset: 4px;
  border-radius: 4px;
}

.hero-onair .dot {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--muted);
}

.hero-onair.live {
  color: var(--live);
}

.hero-onair.live .dot {
  background: var(--live);
  animation: pulse 2s infinite;
}

body.motion-reduced .hero-onair.live .dot {
  animation: none;
}

.hero-onair.locals-nudge {
  position: relative;
}

.hero-onair.locals-nudge .dot {
  background: var(--accent);
}

.hero-onair.locals-nudge::before,
.hero-onair.locals-nudge::after {
  content: "";
  position: absolute;
  inset: -7px -12px;
  border-radius: 999px;
  border: 1.5px solid var(--accent);
  opacity: 0;
  pointer-events: none;
  animation: locals-radar 3.6s ease-out infinite;
}

.hero-onair.locals-nudge::after {
  animation-delay: 0.55s;
}

@keyframes locals-radar {
  0% { transform: scale(1); opacity: 0.55; }
  35% { opacity: 0.3; }
  70% { transform: scale(1.4); opacity: 0; }
  100% { transform: scale(1.4); opacity: 0; }
}

body.motion-reduced .hero-onair.locals-nudge::before,
body.motion-reduced .hero-onair.locals-nudge::after,
.hero-onair.locals-nudge:hover::before,
.hero-onair.locals-nudge:hover::after,
.hero-onair.locals-nudge:focus-within::before,
.hero-onair.locals-nudge:focus-within::after {
  animation: none;
  opacity: 0;
}

body.motion-reduced .hero-fade-group {
  transition: none;
}

.hero-spacer {
  order: 2;
  display: block;
  flex: 1;
  min-height: 12px;
}

.dock-meta {
  order: 3;
  flex: none;
  min-width: 0;
  text-align: left;
}

.dock-status {
  display: block;
  margin-top: 4px;
}

.hero-note {
  display: none;
  margin-top: 6px;
  font-size: 0.85rem;
  color: var(--muted);
}

.hero-note.show {
  display: block;
}

.dock-controls {
  order: 5;
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  margin-top: 10px;
}

#dock-toggle {
  order: initial;
}

#dock-mute {
  display: none;
}

#dock-toggle {
  width: 216px;
  height: 216px;
  flex: 0 0 216px;
  border: none;
}

#dock-toggle .dock-toggle-face {
  font-size: 2.4rem;
  box-shadow: 0 10px 30px rgba(255, 43, 43, 0.35);
}

.hero-actions {
  order: 7;
  display: flex;
  flex: none;
  justify-content: center;
  gap: 56px;
  margin-top: 14px;
}

.hero-action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  font-family: inherit;
}

/* Author-stylesheet `display` always beats the browser's built-in
   `[hidden] { display: none }` rule at equal specificity (origin wins
   before specificity is even compared) — without this, JS setting
   .hidden on #hero-request/#hero-more (shell.js's applyHeroActionsGate)
   silently did nothing, since the unconditional `display: flex` above
   overrode it. */
.hero-action[hidden] {
  display: none;
}

.hero-action-icon {
  display: inline-flex;
  width: 1.35rem;
  height: 1.35rem;
  align-items: center;
  justify-content: center;
}

.hero-action-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.hero-action:active {
  transform: scale(0.96);
}

.hero-more-panel {
  order: 9;
}

.hero-more-panel:not([hidden]) {
  display: flex;
  flex-direction: column;
  position: absolute;
  left: 22px;
  right: 22px;
  bottom: 100px;
  z-index: 2;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.4);
}

.hero-more-panel a,
.hero-more-panel button {
  padding: 14px 16px;
  text-decoration: none;
  color: var(--text);
  font-weight: 700;
  font-size: 0.95rem;
  font-family: inherit;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}

.hero-more-panel a:last-child,
.hero-more-panel button:last-child {
  border-bottom: none;
}

.hero-more-panel a:active,
.hero-more-panel button:active {
  background: var(--bg-panel-2);
}

.hero-more-panel a.disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Landscape — album art alone on the left, everything else (status, controls,
   spectrum analyzer) on the right. #player-dock is already `display: flex`
   (inherited from the compact-dock rule near the top of this file) with the
   browser's default row direction, so making .hero-bg a normal in-flow item
   instead of an absolutely-positioned full-bleed layer is enough to turn it
   into the left pane — no flex-direction override needed. Moving
   #dock-spectrum's DOM position from .hero-bg into .hero-fg (see the HTML)
   is what actually re-homes the analyzer into the right pane: it's still
   positioned via applyGeometry()'s inline styles, which measure whatever
   element is now its parent, so it re-centers on the right pane's own width
   automatically — no extra CSS needed for that part. */
@media (orientation: landscape) {
  .hero-bg {
    position: relative;
    inset: auto;
    flex: 0 0 45%;
    width: 45%;
  }

  .hero-scrim {
    display: none;
  }

  .hero-fg {
    flex: 1;
    width: auto;
    padding: max(14px, env(safe-area-inset-top)) 24px max(calc(14px + env(safe-area-inset-bottom)), calc(var(--eq-clearance, 52px) + 16px)) 18px;
  }

  #dock-toggle {
    width: 140px;
    height: 140px;
    flex: 0 0 140px;
  }

  #dock-toggle .dock-toggle-face {
    font-size: 1.6rem;
  }

  /* Portrait's idle-fade reveals the full-bleed artwork behind the scrim
     when .hero-fade-group hides — an intentional ambient look. Landscape has
     no such background (.hero-scrim is display:none above and .hero-bg is
     just a 45%-wide in-flow pane), so .hero-fade-group is the entire right
     pane's content; fading it here would just leave that side blank. */
  #player-dock.controls-idle .hero-fade-group {
    opacity: 1;
    pointer-events: auto;
  }
}

/* Floating cards — Schedule/DJs/Archive/Settings render inside .card-panel,
   floating over the always-visible player instead of being separate pages.
   shell.js's existing fetch-swap router already swaps only <main>'s
   contents and toggles body[data-page]; visibility here is driven purely by
   that attribute, no extra JS state needed. Closing (X button or backdrop
   click) just navigates back to "/", same router path as any nav link. */
.card-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 30;
  align-items: flex-end;
  justify-content: center;
  background: rgba(4, 4, 4, 0.65);
  backdrop-filter: blur(6px);
  padding: 16px;
  padding-bottom: calc(16px + env(safe-area-inset-bottom));
}

body[data-page="schedule"] .card-overlay,
body[data-page="djs"] .card-overlay,
body[data-page="archive"] .card-overlay,
body[data-page="recently-played"] .card-overlay,
body[data-page="settings"] .card-overlay,
body[data-page="install"] .card-overlay {
  display: flex;
}

.card-panel {
  position: relative;
  width: 100%;
  max-width: var(--max-width);
  max-height: min(80vh, 720px);
  overflow-y: auto;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.5);
  padding: 44px 0 20px;
}

.card-close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--bg-panel-2);
  color: var(--text);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.card-close:active {
  transform: scale(0.94);
}

@media (min-width: 560px) {
  .card-overlay {
    align-items: center;
  }
}

.card {
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
}

.card + .card { margin-top: 16px; }

@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgba(255, 43, 43, 0.5); }
  70% { box-shadow: 0 0 0 8px rgba(255, 43, 43, 0); }
  100% { box-shadow: 0 0 0 0 rgba(255, 43, 43, 0); }
}

/* Schedule */

.slot {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}

.slot:last-child { border-bottom: none; }

.slot .time {
  width: 84px;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: 0.85rem;
}

.slot .who .name { font-weight: 700; }
.slot .who .show { color: var(--muted); font-size: 0.85rem; }

/* DJ cards */

.dj-card .name {
  font-size: 1.2rem;
  font-weight: 800;
}

.dj-card .show-slot {
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 700;
  margin-bottom: 12px;
}

.dj-card dt {
  color: var(--muted);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 12px;
}

.dj-card dd { margin: 4px 0 0; }

/* Archive / requests */

.recent-track {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.9rem;
}

.recent-track:last-child { border-bottom: none; }

.recent-track .artist { color: var(--muted); }

form.request-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.request-form input,
.request-form textarea {
  background: var(--bg-panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  padding: 12px;
  font-size: 1rem;
  font-family: inherit;
  resize: vertical;
}

.request-form button {
  background: var(--accent);
  color: var(--bg);
  border: none;
  border-radius: 10px;
  padding: 14px;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}

.request-form button:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.request-picker {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

form.support-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.support-form input,
.support-form textarea {
  background: var(--bg-panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  padding: 12px;
  font-size: 1rem;
  font-family: inherit;
  resize: vertical;
}

.support-form button {
  background: var(--accent);
  color: var(--bg);
  border: none;
  border-radius: 10px;
  padding: 14px;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}

.premium-gate-panel {
  padding: 16px;
  gap: 10px;
}

.premium-gate-hint {
  color: var(--muted);
  font-size: 0.82rem;
  margin: 0;
}

.premium-gate-form {
  display: flex;
  gap: 8px;
}

.premium-gate-form input {
  flex: 1;
  min-width: 0;
  background: var(--bg-panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  padding: 10px 12px;
  font-size: 0.95rem;
  font-family: inherit;
}

.premium-gate-form button {
  background: var(--accent);
  color: var(--bg);
  border: none;
  border-radius: 10px;
  padding: 10px 16px;
  font-size: 0.95rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
}

.premium-gate-panel .form-status {
  padding: 0 2px;
}

.request-sort-controls {
  display: flex;
  gap: 8px;
}

.request-form .request-sort-button {
  background: none;
  border: 1px solid var(--line);
  color: var(--muted);
  padding: 10px 14px;
  font-size: 0.85rem;
}

.request-form .request-sort-button.active {
  background: var(--bg-panel-2);
  border-color: var(--accent);
  color: var(--text);
}

.request-song-list {
  max-height: min(34vh, 280px);
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-panel-2);
}

.request-song-list .muted {
  margin: 0;
  padding: 12px;
}

.request-catalog-retry {
  background: none;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--text);
  padding: 4px 10px;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  margin-left: 6px;
}

.request-catalog-retry:active {
  background: var(--bg-panel-2);
}

.request-form .request-song-option {
  display: block;
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  color: var(--text);
  padding: 11px 12px;
  text-align: left;
  font-size: 0.9rem;
  font-weight: 600;
}

.request-form .request-song-option:last-child {
  border-bottom: none;
}

.request-form .request-song-option.selected {
  background: rgba(255, 43, 43, 0.14);
  color: var(--text);
  box-shadow: inset 3px 0 0 var(--accent);
}

.form-status {
  font-size: 0.85rem;
  color: var(--muted);
  min-height: 1.2em;
}

.form-status.ok { color: #2ed573; }
.form-status.err { color: var(--accent); }

/* Settings */

.settings-form {
  display: flex;
  flex-direction: column;
}

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}

.setting-row:first-child { padding-top: 0; }
.setting-row:last-child { padding-bottom: 0; border-bottom: none; }

.setting-label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  cursor: pointer;
}

.setting-name {
  font-weight: 700;
  font-size: 0.95rem;
}

.setting-desc {
  color: var(--muted);
  font-size: 0.82rem;
}

.switch {
  position: relative;
  flex: 0 0 auto;
  width: 46px;
  height: 28px;
  cursor: pointer;
}

.switch input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.switch-track {
  position: absolute;
  inset: 0;
  background: var(--bg-panel-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: background 0.15s ease;
}

.switch-track::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--muted);
  transition: transform 0.15s ease, background 0.15s ease;
}

.switch input:checked + .switch-track {
  background: var(--accent);
  border-color: var(--accent);
}

.switch input:checked + .switch-track::before {
  background: var(--bg);
  transform: translateX(18px);
}

.switch input:focus-visible + .switch-track {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

.switch input:disabled {
  cursor: not-allowed;
}

.switch input:disabled + .switch-track {
  opacity: 0.45;
}

.setting-row.disabled .setting-label {
  opacity: 0.55;
  cursor: not-allowed;
}

.settings-form.settings-locked .setting-label {
  opacity: 0.55;
  cursor: not-allowed;
}

.settings-auth-note {
  margin: 8px 0 16px;
}

.settings-reset:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.settings-reset {
  display: block;
  margin: 16px auto 0;
  background: none;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  padding: 10px 16px;
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
}

.settings-reset:active {
  background: var(--bg-panel-2);
}

/* Install */

.install-panel h2 {
  margin: 0 0 8px;
  font-size: 1.1rem;
}

.install-panel p {
  margin: 0;
}

.install-primary-action {
  width: 100%;
  margin-top: 16px;
  text-align: center;
  text-decoration: none;
}

button.install-primary-action {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
  font-size: 1rem;
}

.install-steps {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
}

.install-steps li {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--text);
  font-weight: 700;
}

.install-step-icon {
  display: inline-flex;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--accent-2);
  background: var(--bg-panel-2);
}

.install-step-icon svg {
  width: 20px;
  height: 20px;
}

.install-note {
  margin-top: 12px !important;
  font-size: 0.85rem;
}

.muted { color: var(--muted); }

/* Update banner */

.update-banner {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom));
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: auto;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 14px;
  color: var(--text);
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.45);
}

.update-banner-message {
  margin: 0;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.4;
}

.update-banner-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}

.update-banner-update,
.update-banner-dismiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  border: 1px solid var(--line);
  font: inherit;
  font-weight: 800;
  cursor: pointer;
}

.update-banner-update {
  padding: 0 14px;
  color: var(--bg);
  background: linear-gradient(160deg, var(--accent), var(--accent-2));
  border-color: transparent;
  border-radius: 999px;
}

.update-banner-dismiss {
  width: 40px;
  flex: 0 0 40px;
  padding: 0;
  color: var(--muted);
  background: var(--bg-panel-2);
  border-radius: 50%;
  line-height: 1;
}

.update-banner-update:focus-visible,
.update-banner-dismiss:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

.update-banner-update:active,
.update-banner-dismiss:active {
  transform: scale(0.96);
}

.update-banner-update:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

@media (min-width: 560px) {
  .update-banner {
    left: 16px;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom));
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px;
  }
}
