/* CSS Design System */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');

/* Dark Theme (default) */
:root {
  color-scheme: dark light;
  --bg-primary: #0a0a0a;
  --bg-card: #161616;
  --bg-surface: #1a1a1a;
  --bg-elevated: #2a2a2a;
  --bg-hover: #222;
  --text-primary: #fff;
  --text-secondary: #a0a0a0;
  --text-muted: #666;
  --accent: #00D4AA;
  --accent-dim: rgba(0, 212, 170, 0.15);
  --accent-glow: rgba(0, 212, 170, 0.3);
  --danger: #FF4757;
  --danger-dim: rgba(255, 71, 87, 0.15);
  --border: rgba(255, 255, 255, 0.08);
  --glass-bg: rgba(26, 26, 26, 0.78);
  --glass-border: rgba(255, 255, 255, 0.1);
  --shadow: 0 -2px 20px rgba(0, 0, 0, 0.5);
  --card-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
  --img-bg: #1e1e1e;
  --search-bg: #1e1e1e;
  --pill-bg: #222;
  --pill-active-bg: var(--accent);
  --pill-active-text: #000;
  --skeleton: #1e1e1e;
  --overlay: rgba(0, 0, 0, 0.6);
}

/* Light Theme — the same variables apply two ways: automatically when the
   system prefers light (unless the user forced dark), and explicitly when the
   theme switcher sets data-theme="light". Dark stays the base :root above, so
   data-theme="dark" simply keeps the defaults even on a light system. */
:root[data-theme="light"],
:root[data-theme="light"] .embed-root {
  --bg-primary: #F2F2F7;
  --bg-card: #FFF;
  --bg-surface: #FFF;
  --bg-elevated: #E5E5EA;
  --bg-hover: #F0F0F5;
  --text-primary: #000;
  --text-secondary: #3C3C43;
  --text-muted: #8E8E93;
  --accent: #00B894;
  --accent-dim: rgba(0, 184, 148, 0.12);
  --accent-glow: rgba(0, 184, 148, 0.25);
  --danger: #FF3B30;
  --danger-dim: rgba(255, 59, 48, 0.12);
  --border: rgba(0, 0, 0, 0.08);
  --glass-bg: rgba(255, 255, 255, 0.82);
  --glass-border: rgba(0, 0, 0, 0.06);
  --shadow: 0 -1px 12px rgba(0, 0, 0, 0.08);
  --card-shadow: 0 1px 6px rgba(0, 0, 0, 0.06);
  --img-bg: #E5E5EA;
  --search-bg: #E5E5EA;
  --pill-bg: #E5E5EA;
  --pill-active-text: #FFF;
  --skeleton: #E5E5EA;
  --overlay: rgba(0, 0, 0, 0.35);
}

@media (prefers-color-scheme:light) {
  :root:not([data-theme="dark"]) {
    --bg-primary: #F2F2F7;
    --bg-card: #FFF;
    --bg-surface: #FFF;
    --bg-elevated: #E5E5EA;
    --bg-hover: #F0F0F5;
    --text-primary: #000;
    --text-secondary: #3C3C43;
    --text-muted: #8E8E93;
    --accent: #00B894;
    --accent-dim: rgba(0, 184, 148, 0.12);
    --accent-glow: rgba(0, 184, 148, 0.25);
    --danger: #FF3B30;
    --danger-dim: rgba(255, 59, 48, 0.12);
    --border: rgba(0, 0, 0, 0.08);
    --glass-bg: rgba(255, 255, 255, 0.82);
    --glass-border: rgba(0, 0, 0, 0.06);
    --shadow: 0 -1px 12px rgba(0, 0, 0, 0.08);
    --card-shadow: 0 1px 6px rgba(0, 0, 0, 0.06);
    --img-bg: #E5E5EA;
    --search-bg: #E5E5EA;
    --pill-bg: #E5E5EA;
    --pill-active-text: #FFF;
    --skeleton: #E5E5EA;
    --overlay: rgba(0, 0, 0, 0.35);
  }
}

/* Reset */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box
}

html {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent
}

body {
  background: var(--bg-primary);
  color: var(--text-primary);
  min-height: 100vh;
  min-height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-font-smoothing: antialiased
}

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

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

img {
  display: block;
  max-width: 100%
}

input {
  font-family: inherit
}

/* App Shell */
#app {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding-top: env(safe-area-inset-top);
  /* Native feel: no 300ms tap delay / double-tap zoom, and no accidental
     text selection on UI chrome (content inputs re-enable it below). */
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none
}

input,
textarea,
.desc,
[data-selectable] {
  -webkit-user-select: text;
  user-select: text
}

#app-content {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain
}

#app-content::-webkit-scrollbar {
  width: 0
}

.view {
  min-height: 100%;
  padding: 16px 16px 0;
  animation: fadeIn .25s ease
}

.view-title {
  font-size: 28px;
  font-weight: 800;
  margin-bottom: 20px;
  letter-spacing: -.5px
}

/* Tab Bar */
#tab-bar {
  display: flex;
  justify-content: space-around;
  align-items: center;
  height: 52px;
  min-height: 52px;
  background: var(--glass-bg);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border-top: 1px solid var(--glass-border);
  padding-bottom: env(safe-area-inset-bottom);
  box-sizing: content-box;
  z-index: 100
}

.tab-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 6px 0;
  flex: 1;
  transition: transform .15s;
  -webkit-user-select: none;
  user-select: none
}

.tab-item:active {
  transform: scale(.9)
}

.tab-item svg {
  width: 24px;
  height: 24px;
  fill: var(--text-muted);
  transition: fill .2s
}

.tab-item span {
  font-size: 10px;
  font-weight: 500;
  color: var(--text-muted);
  transition: color .2s
}

.tab-item.active svg {
  fill: var(--accent)
}

.tab-item.active span {
  color: var(--accent)
}

/* Mini Player */
#mini-player {
  display: none;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  background: var(--glass-bg);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  /* Accent top line + elevation so it clearly reads as the (expandable) player. */
  border-top: 2px solid var(--accent);
  box-shadow: 0 -6px 24px rgba(0, 0, 0, .28);
  cursor: pointer;
  z-index: 99
}

#mini-player.visible {
  display: flex
}

#mini-player:active {
  background: var(--bg-hover)
}

.mini-thumb {
  width: 42px;
  height: 42px;
  border-radius: 8px;
  object-fit: cover;
  background: var(--img-bg);
  flex-shrink: 0
}

.mini-info {
  flex: 1;
  min-width: 0
}

.mini-name {
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis
}

.mini-meta {
  font-size: 11px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis
}

.mini-eq {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 18px;
  margin-right: 4px
}

.mini-eq .eq-bar {
  width: 3px;
  border-radius: 2px;
  background: var(--accent);
  animation: eq .6s ease-in-out infinite alternate
}

.mini-eq .eq-bar:nth-child(1) {
  height: 40%;
  animation-delay: 0s
}

.mini-eq .eq-bar:nth-child(2) {
  height: 70%;
  animation-delay: .15s
}

.mini-eq .eq-bar:nth-child(3) {
  height: 50%;
  animation-delay: .3s
}

.mini-eq.paused .eq-bar {
  animation: none;
  height: 30%
}

.mini-play-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  box-shadow: 0 2px 14px var(--accent-glow);
  flex-shrink: 0;
  transition: transform .12s
}

.mini-play-btn:active {
  transform: scale(.88)
}

.mini-play-btn svg {
  width: 18px;
  height: 18px;
  fill: #00201b
}

/* Now Playing */
#now-playing {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--bg-primary);
  transform: translateY(100%);
  transition: transform .42s cubic-bezier(.16, 1, .3, 1);
  /* Native player: fills the viewport and never scrolls — .np-body flexes to
     the available height and the artwork shrinks to fit (see .np-art-wrap). */
  overflow: hidden;
  display: flex;
  flex-direction: column
}

#now-playing.open {
  transform: translateY(0)
}

.np-handle {
  width: 36px;
  height: 5px;
  border-radius: 3px;
  background: var(--text-muted);
  margin: 10px auto 0;
  opacity: .5
}

.np-close {
  position: absolute;
  top: calc(env(safe-area-inset-top) + 12px);
  left: 16px;
  padding: 8px
}

.np-close svg {
  width: 24px;
  height: 24px;
  fill: var(--text-secondary)
}

.np-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  min-height: 0;
  gap: clamp(10px, 2.2vh, 20px);
  padding:
    calc(env(safe-area-inset-top) + 48px) 32px
    calc(env(safe-area-inset-bottom) + 24px)
}

.np-art-wrap {
  /* Flexible: shrinks on short screens so the whole player always fits. */
  flex: 0 1 auto;
  height: min(280px, 38dvh);
  width: auto;
  max-width: 78vw;
  min-height: 0;
  aspect-ratio: 1;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .4)
}

.np-art {
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--img-bg)
}

.np-station-name {
  font-size: 22px;
  font-weight: 700;
  text-align: center;
  letter-spacing: -.3px
}

.np-station-country {
  font-size: 14px;
  color: var(--text-secondary)
}

.np-genres {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: center
}

.np-genre-tag {
  font-size: 11px;
  font-weight: 500;
  padding: 4px 10px;
  border-radius: 20px;
  background: var(--accent-dim);
  color: var(--accent)
}

.np-controls {
  display: flex;
  align-items: center;
  gap: 28px;
  margin-top: 8px
}

.np-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform .1s
}

.np-btn:active {
  transform: scale(.85)
}

.np-btn svg {
  fill: var(--text-primary)
}

.np-btn-skip svg {
  width: 28px;
  height: 28px
}

.np-btn-play {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 4px 20px var(--accent-glow)
}

.np-btn-play svg {
  width: 28px;
  height: 28px;
  fill: #000
}

.np-btn-fav svg {
  width: 24px;
  height: 24px
}

.np-btn-fav.active svg {
  fill: var(--danger)
}

.np-volume {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  max-width: 280px
}

.np-volume svg {
  width: 18px;
  height: 18px;
  fill: var(--text-muted);
  flex-shrink: 0
}

.np-volume input[type=range] {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border-radius: 2px;
  /* Filled portion (accent) up to --vol, unfilled track after */
  background: linear-gradient(to right, var(--accent) 0 var(--vol, 100%), var(--bg-elevated) var(--vol, 100%) 100%);
  outline: none;
  /* Own the touch drag — otherwise the ancestor's touch-action:manipulation
     treats a horizontal drag as a pan and the thumb freezes mid-drag. */
  touch-action: none
}

/* iOS locks HTMLMediaElement.volume to the hardware buttons, so a slider can't
   change playback volume there — hide it rather than show a dead control. */
:root.is-ios .np-volume {
  display: none
}

.np-volume input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--text-primary);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .3)
}

/* Firefox filled-track support */
.np-volume input[type=range]::-moz-range-progress {
  height: 4px;
  border-radius: 2px;
  background: var(--accent)
}

.np-volume input[type=range]::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: var(--bg-elevated)
}

.np-volume input[type=range]::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border: none;
  border-radius: 50%;
  background: var(--text-primary)
}

.np-visualizer {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: clamp(24px, 4vh, 40px);
  flex-shrink: 0;
  margin-top: 8px
}

/* Short screens: drop the decorative visualizer so the player still fits. */
@media (max-height: 640px) {
  .np-visualizer { display: none }
}

.np-visualizer .v-bar {
  flex: 1;
  max-width: 4px;
  border-radius: 2px;
  background: var(--accent);
  transition: height .08s ease;
  min-height: 2px
}

/* Search */
.search-wrap {
  position: relative;
  margin-bottom: 20px
}

.search-input {
  width: 100%;
  height: 40px;
  border-radius: 12px;
  background: var(--search-bg);
  border: 1px solid transparent;
  padding: 0 14px 0 40px;
  font-size: 15px;
  color: var(--text-primary);
  outline: none;
  transition: border-color .2s, background .2s
}

.search-input::placeholder {
  color: var(--text-muted)
}

.search-input:focus {
  border-color: var(--accent);
  background: var(--bg-card)
}

.search-icon {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  fill: var(--text-muted);
  pointer-events: none
}

.search-clear {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--text-muted);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0
}

.search-clear.visible {
  display: flex
}

.search-clear svg {
  width: 12px;
  height: 12px;
  fill: var(--bg-primary)
}

/* Sections */
.section {
  margin-bottom: 28px
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 14px
}

.section-title {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -.2px
}

.section-link {
  font-size: 13px;
  font-weight: 600;
  color: var(--accent)
}

/* Horizontal Scroll */
.h-scroll {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 4px;
  scrollbar-width: none
}

.h-scroll::-webkit-scrollbar {
  display: none
}

/* Station Cards */
.station-card-wrap {
  flex-shrink: 0;
  width: 150px;
  scroll-snap-align: start
}

.station-card {
  width: 100%;
  background: var(--bg-card);
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  transition: transform .15s, box-shadow .2s;
  box-shadow: var(--card-shadow)
}

.station-card:active {
  transform: scale(.96)
}

.station-card-img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  background: var(--img-bg)
}

.station-card-body {
  padding: 10px 12px 12px
}

.station-card-name {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis
}

.station-card-meta {
  font-size: 11px;
  color: var(--text-secondary);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis
}

/* Circle Card */
.circle-card {
  flex-shrink: 0;
  width: 72px;
  text-align: center;
  cursor: pointer;
  transition: transform .15s;
  scroll-snap-align: start
}

.circle-card:active {
  transform: scale(.92)
}

.circle-img {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--img-bg);
  margin: 0 auto 6px;
  border: 2px solid var(--border)
}

.circle-flag {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  background: var(--bg-card);
  margin: 0 auto 6px;
  border: 2px solid var(--border)
}

.circle-label {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis
}

/* Grid Cards */
.grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px
}

.grid-card {
  background: var(--bg-card);
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  transition: transform .15s;
  box-shadow: var(--card-shadow);
  display: block;
  width: 100%;
  text-align: left;
  position: relative
}

.grid-card:active {
  transform: scale(.96)
}

.grid-card-img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  background: var(--img-bg)
}

.grid-card-body {
  padding: 10px 12px 12px
}

.grid-card-name {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 3px
}

.grid-card-meta {
  font-size: 11px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis
}

.grid-card-tags {
  display: flex;
  gap: 4px;
  margin-top: 6px;
  flex-wrap: wrap
}

.grid-card-tag {
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .3px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--accent-dim);
  color: var(--accent)
}

/* Filter Pills */
.pills {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 4px;
  scrollbar-width: none;
  margin-bottom: 16px
}

.pills::-webkit-scrollbar {
  display: none
}

.pill {
  flex-shrink: 0;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 13px;
  font-weight: 600;
  background: var(--pill-bg);
  color: var(--text-secondary);
  cursor: pointer;
  transition: all .2s;
  -webkit-user-select: none;
  user-select: none;
  white-space: nowrap
}

.pill:active {
  transform: scale(.95)
}

.pill.active {
  background: var(--pill-active-bg);
  color: var(--pill-active-text)
}

/* Visually-hidden (screen-reader only) */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0
}

/* Active filters overview */
.active-filters {
  display: none;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px
}

.active-filters.visible {
  display: flex
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 6px 12px;
  border-radius: 20px;
  font-size: 13px;
  font-weight: 600;
  background: var(--accent-dim);
  color: var(--accent);
  border: 1px solid var(--accent-glow)
}

.filter-chip span {
  font-size: 16px;
  line-height: 1;
  opacity: .8
}

.filter-chip:active {
  transform: scale(.95)
}

.clear-all {
  min-height: 32px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  text-decoration: underline
}

.empty-cta {
  margin-top: 16px;
  padding: 10px 20px;
  border-radius: 22px;
  font-size: 14px;
  font-weight: 600;
  background: var(--accent);
  color: var(--pill-active-text)
}

.empty-cta:active {
  transform: scale(.96)
}

/* Genre Cards */
.genre-card {
  flex-shrink: 0;
  width: 120px;
  height: 72px;
  border-radius: 12px;
  padding: 12px;
  display: flex;
  align-items: flex-end;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  cursor: pointer;
  transition: transform .15s;
  scroll-snap-align: start;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .3)
}

.genre-card:active {
  transform: scale(.95)
}

.genre-card:nth-child(1) {
  background: linear-gradient(135deg, #00D4AA, #00897B)
}

.genre-card:nth-child(2) {
  background: linear-gradient(135deg, #FF6B6B, #C0392B)
}

.genre-card:nth-child(3) {
  background: linear-gradient(135deg, #FECA57, #F39C12)
}

.genre-card:nth-child(4) {
  background: linear-gradient(135deg, #54A0FF, #2E86DE)
}

.genre-card:nth-child(5) {
  background: linear-gradient(135deg, #5F27CD, #341F97)
}

.genre-card:nth-child(6) {
  background: linear-gradient(135deg, #FF9FF3, #F368E0)
}

.genre-card:nth-child(7) {
  background: linear-gradient(135deg, #01A3A4, #006266)
}

.genre-card:nth-child(8) {
  background: linear-gradient(135deg, #FF6348, #EB2F06)
}

.genre-card:nth-child(9) {
  background: linear-gradient(135deg, #2ED573, #009432)
}

.genre-card:nth-child(10) {
  background: linear-gradient(135deg, #FFA502, #E67E22)
}

.genre-card:nth-child(n+11) {
  background: linear-gradient(135deg, #747d8c, #57606f)
}

/* Empty State */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  text-align: center
}

.empty-icon {
  font-size: 64px;
  margin-bottom: 16px;
  opacity: .4
}

.empty-title {
  font-size: 18px;
  font-weight: 700;
  margin-bottom: 8px
}

.empty-text {
  font-size: 14px;
  color: var(--text-secondary);
  max-width: 260px;
  line-height: 1.5
}

/* Live Badge */
.live-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--danger);
  letter-spacing: .5px
}

.live-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--danger);
  animation: pulse 1.5s ease-in-out infinite
}

/* Playing indicator */
.station-card.playing,
.grid-card.playing {
  outline: 2px solid var(--accent);
  outline-offset: -2px
}

.station-card.playing .station-card-name,
.grid-card.playing .grid-card-name {
  color: var(--accent)
}

/* Animations */
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(8px)
  }

  to {
    opacity: 1;
    transform: translateY(0)
  }
}

@keyframes eq {
  0% {
    height: 20%
  }

  50% {
    height: 80%
  }

  100% {
    height: 40%
  }
}

@keyframes pulse {

  0%,
  100% {
    opacity: 1
  }

  50% {
    opacity: .5
  }
}

/* Responsive */
@media(min-width:500px) {
  .grid {
    grid-template-columns: repeat(3, minmax(0, 1fr))
  }

  .station-card-wrap {
    width: 170px
  }
}

@media(min-width:768px) {
  #app {
    display: grid;
    grid-template-columns: 240px 1fr;
    grid-template-rows: 1fr auto;
    grid-template-areas:
      "sidebar main"
      "sidebar player";
    max-width: none;
    box-shadow: none;
    margin: 0;
  }

  #tab-bar {
    grid-area: sidebar;
    flex-direction: column;
    justify-content: flex-start;
    height: auto;
    border-top: none;
    border-right: 1px solid var(--glass-border);
    padding: 40px 0 0 0;
    align-items: stretch;
    background: transparent;
    backdrop-filter: none;
  }

  .tab-item {
    flex: none;
    flex-direction: row;
    gap: 16px;
    padding: 16px 24px;
    justify-content: flex-start;
  }

  .tab-item svg {
    width: 22px;
    height: 22px;
  }

  .tab-item span {
    font-size: 15px;
    font-weight: 600;
  }

  #app-content {
    grid-area: main;
    padding: 0;
  }

  .view {
    padding: 32px 40px 0;
  }

  #mini-player {
    grid-area: player;
    padding: 16px 32px;
    border-top: 1px solid var(--glass-border);
    border-left: 1px solid var(--glass-border);
  }

  .mini-thumb {
    width: 56px;
    height: 56px;
  }

  .mini-name {
    font-size: 16px;
  }

  #now-playing {
    width: 400px;
    left: auto;
    right: 0;
    border-left: 1px solid var(--glass-border);
    transform: translateX(100%);
    box-shadow: -10px 0 40px rgba(0, 0, 0, 0.5);
  }

  #now-playing.open {
    transform: translateX(0);
  }

  .np-handle {
    display: none;
  }

  .np-close {
    right: 24px;
    left: auto;
    top: 24px;
  }

  .np-close svg {
    transform: rotate(-90deg);
    width: 32px;
    height: 32px;
  }

  .grid {
    grid-template-columns: repeat(4, minmax(0, 1fr))
  }

  .bottom-spacer {
    height: 80px
  }
}

@media(min-width:1024px) {
  .grid {
    grid-template-columns: repeat(5, minmax(0, 1fr))
  }
}

@media(min-width:1440px) {
  .grid {
    grid-template-columns: repeat(6, minmax(0, 1fr))
  }
}

/* Browse country intro (editorial) */
.browse-intro {
  margin: 4px 0 20px;
  padding: 16px 18px;
  background: var(--accent-dim);
  border: 1px solid var(--border);
  border-radius: 14px;
}

.browse-intro-title {
  font-size: 16px;
  font-weight: 700;
  margin: 0 0 6px;
  color: var(--text-primary);
}

.browse-intro p {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-secondary);
}

/* Site footer (legal / info links) */
/* Margin spacing rather than flex `gap` — see .station-tags above. This footer
   renders on every prerendered page AND in all three app views, so it has the
   widest browser exposure of any component in the stylesheet. */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  padding: 28px 16px 8px;
  margin-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 13px;
}

.site-footer > a {
  margin: 4px 9px;
}

.site-footer a {
  color: var(--text-secondary);
  text-decoration: none;
  font-weight: 600;
}

.site-footer a:hover {
  color: var(--accent);
}

.site-footer .footer-copy {
  color: var(--text-muted);
  width: 100%;
  text-align: center;
  margin-top: 4px;
}

/* Static content / document pages (about, contact, privacy).
   These are standalone HTML documents (no #app shell) that reuse the same
   design tokens + theme system as the app, so they match in auto/light/dark. */
body.doc-page {
  overflow: auto;              /* undo the SPA shell's body{overflow:hidden} */
  min-height: 100vh;
  min-height: 100dvh;
  padding: 40px 20px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

.doc {
  max-width: 760px;
  margin: 0 auto;
}

.doc .brand {
  font-weight: 800;
  letter-spacing: .5px;
  color: var(--text-secondary);
  margin-bottom: 28px;
  text-align: center;
}

.doc h1 {
  font-size: 32px;
  font-weight: 800;
  color: var(--text-primary);
  margin-bottom: 20px;
}

.doc h1 + .updated {
  margin-top: -12px;           /* pull the "last updated" line under the h1 */
}

.doc .updated {
  color: var(--text-muted);
  font-size: 14px;
  margin-bottom: 32px;
}

.doc h2 {
  font-size: 20px;
  font-weight: 700;
  color: var(--text-primary);
  margin: 32px 0 10px;
}

.doc p,
.doc li {
  color: var(--text-secondary);
  font-size: 16px;
}

.doc ul {
  padding-left: 22px;
  margin: 10px 0;
}

.doc li {
  margin: 6px 0;
}

.doc a {
  color: var(--accent);
}

.doc a:hover {
  text-decoration: underline;
}

.doc code {
  background: var(--bg-elevated);
  padding: 1px 5px;
  border-radius: 5px;
  font-size: 14px;
}

.doc .home {
  display: inline-block;
  color: var(--accent);
  font-weight: 600;
}

.doc .email {
  display: inline-block;
  margin-top: 8px;
  background: var(--accent);
  color: var(--bg-primary);
  font-weight: 800;
  padding: 14px 28px;
  border-radius: 14px;
  font-size: 16px;
}

/* Country landing pages reuse .doc + this station list. */
.doc .station-list {
  list-style: none;
  padding: 0;
  margin: 10px 0 0;
}

.doc .station-list li {
  padding: 12px 0;
  margin: 0;
  border-bottom: 1px solid var(--border);
  font-size: 16px;
  color: var(--text-primary);
}

.doc .station-list li a {
  color: var(--accent);
  font-weight: 600;
}

.doc .station-list li a:hover {
  text-decoration: underline;
}

.doc .station-list .g {
  color: var(--text-muted);
  font-size: 13px;
  margin-left: 8px;
}

.doc .cta {
  display: inline-block;
  background: var(--accent);
  color: var(--bg-primary);
  font-weight: 800;
  padding: 14px 28px;
  border-radius: 14px;
  font-size: 16px;
}

/* Prerendered per-station pages (centered layout).
 *
 * The wrapper is .station-hero, NOT .station-card. It used to reuse
 * .station-card, which is the in-app 150px carousel tile (see ~line 705) — so
 * the page inherited that tile's background, border-radius, box-shadow,
 * cursor:pointer and :active scale, while this block set no padding. The
 * result was a visible card with zero internal padding: every line of text sat
 * flush against a rounded edge. The later `.station-card, .grid-card {
 * text-align: left }` rule also quietly beat the centering below. Keeping the
 * page on its own class means neither can happen again. */
body.station-page {
  overflow: auto;
  min-height: 100vh;
  min-height: 100dvh;
  padding: 48px 20px;
  -webkit-font-smoothing: antialiased;
}

.station-hero {
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  padding: 32px 28px;
  background: var(--bg-card);
  border-radius: 20px;
  box-shadow: var(--card-shadow);
  text-align: center;
}

.station-hero .brand {
  font-weight: 800;
  letter-spacing: .5px;
  color: var(--text-secondary);
  margin-bottom: 22px;
}

.station-art {
  width: 200px;
  height: 200px;
  border-radius: 28px;
  object-fit: cover;
  box-shadow: var(--card-shadow);
  background: var(--img-bg);
  margin: 0 auto 24px;
  display: block;
}

.station-hero h1 {
  font-size: 30px;
  font-weight: 800;
  line-height: 1.15;
  color: var(--text-primary);
}

.station-country {
  color: var(--text-secondary);
  margin-top: 8px;
  font-size: 16px;
}

/* Spacing is by margin rather than flex `gap`: Safari below 14.1 ignores gap in
   flex containers entirely, so the tags rendered touching each other. These
   pages are the destination for every share, QR scan and search result, so they
   are seen on a far wider spread of browsers than the app itself. The negative
   horizontal margin cancels the children's outer gutters so wrapped rows stay
   aligned with the rest of the card. */
.station-tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin: 16px -4px 4px;
}

.station-tags .tag {
  background: var(--pill-bg);
  color: var(--text-primary);
  border-radius: 999px;
  padding: 6px 14px;
  margin: 0 4px 8px;
  font-size: 13px;
  font-weight: 600;
}

.station-desc {
  color: var(--text-secondary);
  font-size: 15px;
  line-height: 1.6;
  margin: 22px auto 0;
  max-width: 460px;
  text-align: left;
}

/* Action stack.
 *
 * These were bare inline-block anchors sitting next to each other in the
 * markup, so "More about radio in X →" and "← Browse all Caribbean stations"
 * laid out on the SAME LINE whenever the container was wide enough, and wrapped
 * unpredictably as it narrowed. Their different margin-tops also made the
 * vertical spacing engine-dependent, because vertical margins on inline-level
 * boxes are exactly where browsers disagree.
 *
 * A flex column makes the stacking deterministic at every width. Spacing is by
 * margin, NOT gap — flex gap is ignored by Safari below 14.1, which is the same
 * bug being fixed in .station-tags and .site-footer below. */
.station-actions,
.doc-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 28px;
}

.station-actions > a,
.doc-actions > a {
  margin-top: 18px;
}

.station-actions > a:first-child,
.doc-actions > a:first-child {
  margin-top: 0;
}

.station-hero .cta {
  display: inline-block;
  background: var(--accent);
  color: var(--bg-primary);
  font-weight: 800;
  padding: 16px 34px;
  border-radius: 16px;
  font-size: 17px;
}

.station-hero .cta:active {
  transform: scale(.98);
}

.station-hero .home {
  display: inline-block;
  color: var(--accent);
  font-weight: 600;
  font-size: 14px;
}

.station-hero .site-footer {
  margin-top: 26px;
}

/* Back-link from a station to its island article (hub-and-spoke). */
.station-hero .country-link {
  display: inline-block;
  color: var(--accent);
  font-weight: 700;
  font-size: 15px;
}

/* In-content ad slot. Height is reserved so the page does not jump when the
   unit fills — an unreserved ad is the most common cause of a bad CLS score. */
.ad-slot {
  min-height: 280px;
  margin: 28px 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ad-slot ins {
  width: 100%;
}

/* Island-article lede: the 400-char summary that opens a country page. */
.doc .lede {
  font-size: 18px;
  color: var(--text-secondary);
  margin-bottom: 8px;
}

/* Per-station "Learn more" link inside a country page's station list. */
.doc .station-list .learn-more {
  display: block;
  margin-top: 3px;
  color: var(--accent);
  font-weight: 600;
  font-size: 13px;
}

/* The stylesheet's only max-width breakpoint. The prerendered pages were
   previously fixed-width at every viewport: 48px of body padding and a 200px
   cover on a 390px phone left almost nothing for the text column. */
@media (max-width: 480px) {
  body.station-page {
    padding: 24px 12px;
  }

  .station-hero {
    padding: 24px 18px;
    border-radius: 16px;
  }

  .station-hero h1 {
    font-size: 25px;
  }

  .station-art {
    width: 148px;
    height: 148px;
    border-radius: 22px;
    margin-bottom: 20px;
  }

  /* max-width:460px never binds on a phone; let it use the full column. */
  .station-desc {
    max-width: none;
  }

  .station-hero .cta {
    padding: 15px 20px;
  }

  body.doc-page {
    padding: 28px 16px;
  }
}

/* Visible crawlable directory injected into the homepage shell (SEO:INDEX). */
.static-directory {
  max-width: 900px;
  margin: 8px auto 0;
  padding: 8px 16px 28px;
}

.static-directory h2 {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .4px;
  margin: 22px 0 10px;
}

.static-directory ul {
  list-style: none;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
}

.static-directory li a {
  color: var(--accent);
  font-size: 14px;
  font-weight: 600;
}

.static-directory li a:hover {
  text-decoration: underline;
}

/* Install Prompt */
.install-prompt {
  position: fixed;
  bottom: 70px;
  left: 16px;
  right: 16px;
  background: var(--glass-bg);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  z-index: 150;
  transform: translateY(200%);
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

.install-prompt.visible {
  transform: translateY(0);
}

.install-content {
  display: flex;
  align-items: center;
  gap: 12px;
}

.install-icon img {
  width: 44px;
  height: 44px;
  border-radius: 10px;
}

.install-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.install-text strong {
  font-size: 14px;
}

.install-text span {
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.3;
}

.install-btn {
  background: var(--accent);
  color: #000;
  font-weight: 600;
  font-size: 13px;
  padding: 6px 14px;
  border-radius: 20px;
}

.install-btn:active {
  transform: scale(0.95);
}

.install-close {
  font-size: 24px;
  line-height: 1;
  color: var(--text-muted);
  padding: 0 4px;
}

/* Update toast — "a new version is available" (mirrors the install prompt). */
.update-toast {
  position: fixed;
  bottom: 70px;
  left: 16px;
  right: 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--glass-bg);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 12px 14px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  z-index: 160;
  /* Fully hidden (height-independent) so no sliver peeks over the tab bar. */
  transform: translateY(200%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease, visibility 0.3s;
}

.update-toast.visible {
  transform: translateY(0);
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

.update-text {
  flex: 1;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
}

.update-btn {
  background: var(--accent);
  color: var(--bg-primary);
  font-weight: 700;
  font-size: 13px;
  padding: 7px 16px;
  border-radius: 20px;
}

.update-btn:active {
  transform: scale(0.95);
}

.update-close {
  font-size: 24px;
  line-height: 1;
  color: var(--text-muted);
  padding: 0 4px;
}

/* ── Accessibility foundation (Batch B) ── */

/* Card <button> layout resets (were <div>s) */
.station-card,
.grid-card {
  text-align: left
}

.circle-card,
.genre-card {
  display: flex
}

.circle-card {
  flex-direction: column
}

/* Home search rendered as a button */
.search-btn {
  display: flex;
  align-items: center;
  width: 100%;
  height: 44px;
  border-radius: 12px;
  background: var(--search-bg);
  padding: 0 14px 0 40px;
  text-align: left
}

.search-placeholder {
  color: var(--text-muted);
  font-size: 15px
}

/* Visible keyboard focus for every interactive element */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 8px
}

/* pointer users don't get the ring */
:focus:not(:focus-visible) {
  outline: none
}

/* Minimum touch targets (WCAG 2.5.8) */
.pill,
.filter-chip,
.clear-all {
  min-height: 36px
}

.np-btn {
  min-height: 44px;
  min-width: 44px
}

.search-clear {
  width: 24px;
  height: 24px
}

/* Accessible mini-player: info area is a button */
.mini-open {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  text-align: left
}

.mini-open .mini-info {
  flex: 1
}

/* "Tap to open" hint — a subtly bouncing up-chevron. */
.mini-chevron {
  display: flex;
  flex-shrink: 0
}

.mini-chevron svg {
  width: 18px;
  height: 18px;
  fill: var(--text-muted);
  animation: chevBounce 1.8s ease-in-out infinite
}

@keyframes chevBounce {
  0%, 100% { transform: translateY(0) }
  50% { transform: translateY(-2px) }
}

.mini-name,
.mini-meta {
  display: block
}

/* Lock background scroll while the Now-Playing sheet is open */
body.np-lock #app-content {
  overflow: hidden
}

/* ── Playback & flows (Batch C) ── */

/* Favorite button overlaid on grid cards */
.card-wrap {
  position: relative
}

.card-fav {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, .55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  z-index: 2
}

.card-fav svg {
  width: 18px;
  height: 18px;
  fill: #fff
}

.card-fav.active svg {
  fill: #ff4d6d
}

.card-fav:active {
  transform: scale(.9)
}

.card-share {
  position: absolute;
  top: 8px;
  right: 50px;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, .55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  z-index: 2
}

.card-share svg {
  width: 17px;
  height: 17px;
  fill: #fff
}

.card-share:active {
  transform: scale(.9)
}

/* Now-playing status / error / retry */
.np-status {
  /* Always occupies its slot so showing/hiding the connecting/error text does
     not reflow (and re-center) the whole player. */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 40px;
  flex-shrink: 0;
  font-size: 13px;
  color: var(--text-secondary)
}

.np-status.error {
  color: #ff6b6b
}

.np-spinner,
.mini-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid var(--accent);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin .7s linear infinite;
  display: inline-block
}

.np-retry {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 32px;
  padding: 4px 12px;
  border-radius: 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-dim)
}

.np-retry svg {
  width: 16px;
  height: 16px;
  fill: currentColor
}

/* Mini-player state */
.mini-status {
  color: #ff6b6b;
  font-weight: 600
}

#mini-player.state-error .mini-play-btn {
  background: var(--accent-dim);
  color: var(--accent)
}

.mini-eq.connecting {
  gap: 0
}

.mini-eq.connecting .eq-bar {
  display: none
}

.mini-eq.connecting::after {
  content: "";
  width: 16px;
  height: 16px;
  border: 2px solid var(--accent);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin .7s linear infinite
}

.live-badge.dim {
  opacity: .45
}

@keyframes spin {
  to { transform: rotate(360deg) }
}

/* Honest visualizer: CSS-driven, reflects real play state (no fake FFT) */
.np-visualizer .v-bar {
  height: 15%
}

.np-visualizer.playing .v-bar {
  animation: eq .9s ease-in-out infinite alternate
}

.np-visualizer.playing .v-bar:nth-child(3n) {
  animation-duration: 1.15s
}

.np-visualizer.playing .v-bar:nth-child(3n+1) {
  animation-duration: .75s
}

.np-visualizer.playing .v-bar:nth-child(4n) {
  animation-delay: .2s
}

.np-visualizer.playing .v-bar:nth-child(2n) {
  animation-delay: .35s
}

/* ── Sharing (Batch D) ── */
.np-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  margin-top: 8px
}

.np-btn-share svg {
  width: 24px;
  height: 24px;
  fill: var(--text-secondary)
}

.share-sheet {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: flex-end;
  justify-content: center
}

.share-backdrop {
  position: absolute;
  inset: 0;
  background: var(--overlay, rgba(0, 0, 0, .5))
}

.share-panel {
  position: relative;
  width: 100%;
  max-width: 480px;
  background: var(--bg-card);
  border-radius: 20px 20px 0 0;
  padding: 20px 16px calc(20px + env(safe-area-inset-bottom));
  animation: fadeIn .25s ease;
  outline: none
}

@media (min-width: 768px) {
  .share-sheet { align-items: center }
  .share-panel { border-radius: 20px }
}

.share-title {
  font-size: 16px;
  font-weight: 700;
  margin-bottom: 16px;
  text-align: center
}

.share-preview {
  display: block;
  margin: 0 auto 16px;
  width: auto;
  max-width: 100%;
  max-height: 46dvh;
  border-radius: 16px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .45)
}

.share-primary {
  display: flex;
  gap: 10px;
  margin-bottom: 14px
}

.share-cta {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 12px;
  border-radius: 14px;
  background: var(--accent);
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  text-align: center
}

.share-cta.secondary {
  background: var(--pill-bg);
  color: var(--text-primary)
}

.share-cta:active {
  transform: scale(.97)
}

.share-embed {
  margin-bottom: 12px
}

.share-embed-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 6px
}

.share-embed-code {
  width: 100%;
  resize: none;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  line-height: 1.5;
  padding: 10px 12px;
  margin-bottom: 8px
}

.share-links {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 12px
}

.share-link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 10px;
  border-radius: 12px;
  background: var(--pill-bg);
  color: var(--text-primary);
  font-size: 14px;
  font-weight: 600;
  text-align: center
}

.share-link:active {
  transform: scale(.96)
}

.share-cancel {
  width: 100%;
  min-height: 48px;
  border-radius: 12px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-secondary)
}

/* ── Visual polish (Batch E) ── */

/* Blurred-artwork background behind Now-Playing, with a scrim for contrast */
.np-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: blur(50px) saturate(1.5);
  transform: scale(1.4);
  opacity: .45;
  z-index: 0;
  pointer-events: none
}

.np-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, .25), var(--bg-primary) 90%);
  z-index: 0;
  pointer-events: none
}

.np-body {
  position: relative;
  z-index: 1
}

#now-playing .np-close,
#now-playing .np-handle {
  z-index: 3
}

/* Skeleton loading shimmer */
.skeleton-wrap {
  padding: 32px 20px 0
}

.skeleton {
  background: linear-gradient(90deg, var(--skeleton, #1c1c1e) 25%, var(--bg-hover) 37%, var(--skeleton, #1c1c1e) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease infinite;
  border-radius: 10px
}

.skeleton-title {
  width: 180px;
  height: 28px;
  margin-bottom: 20px
}

.skeleton-row {
  display: flex;
  gap: 12px;
  margin-bottom: 28px;
  overflow: hidden
}

.skeleton-card {
  flex: 0 0 150px;
  height: 190px
}

@keyframes shimmer {
  0% { background-position: 100% 0 }
  100% { background-position: -100% 0 }
}

/* ── Artwork with initials fallback ── */
.art {
  position: relative;
  display: block
}

.art-img {
  position: relative;
  z-index: 1;
  background: linear-gradient(135deg, var(--img-bg), var(--bg-hover))
}

.art-img.failed {
  opacity: 0
}

.art-ph {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--art-c, var(--accent));
  color: #fff;
  font-weight: 800;
  font-size: 40px
}

.np-art-wrap .art {
  width: 100%;
  height: 100%
}

.np-art-wrap .art-ph {
  font-size: 96px
}

/* Round variant for circle cards */
.circle-card .art-round {
  width: 64px;
  height: 64px;
  margin: 0 auto 6px;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid var(--border)
}

.circle-card .art-round .circle-img {
  width: 100%;
  height: 100%;
  margin: 0;
  border: none
}

.circle-card .art-round .art-ph {
  font-size: 24px
}

/* ── "Now playing" badge on the active card ── */
.art-slot {
  position: relative;
  display: block
}

.now-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 3;
  display: none;
  align-items: flex-end;
  gap: 2px;
  height: 16px;
  padding: 4px;
  border-radius: 6px;
  background: rgba(0, 0, 0, .55)
}

.now-badge i {
  width: 3px;
  height: 100%;
  background: var(--accent);
  border-radius: 1px;
  animation: eq .9s ease-in-out infinite alternate
}

.now-badge i:nth-child(2) { animation-duration: 1.15s }
.now-badge i:nth-child(3) { animation-duration: .7s }

.is-playing .now-badge {
  display: flex
}

/* Paused mini-player: hide the eq so it doesn't read as a "⋯" menu */
.mini-eq.paused {
  display: none
}

/* Filter row labels */
.pills-label {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .4px;
  color: var(--text-muted);
  margin-bottom: 8px
}

/* Result count + sort */
.results-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px
}

.results-count {
  font-size: 13px;
  color: var(--text-secondary);
  font-weight: 600
}

.sort-select {
  appearance: none;
  -webkit-appearance: none;
  background: var(--pill-bg);
  color: var(--text-primary);
  border: none;
  border-radius: 16px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  min-height: 36px;
  cursor: pointer
}

/* Favorites header actions */
.fav-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 16px
}

.fav-actions {
  display: flex;
  gap: 8px
}

.pill-btn {
  min-height: 40px;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 14px;
  font-weight: 600;
  background: var(--accent);
  color: var(--pill-active-text)
}

.pill-btn#fav-shuffle {
  background: var(--pill-bg);
  color: var(--text-primary)
}

.pill-btn:active {
  transform: scale(.96)
}

/* Home top row: search + surprise */
.home-top {
  display: flex;
  gap: 10px;
  align-items: stretch;
  margin-bottom: 20px
}

.home-top .search-btn {
  flex: 1;
  margin-bottom: 0
}

.surprise-btn {
  flex-shrink: 0;
  padding: 0 16px;
  height: 44px;
  border-radius: 12px;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  background: var(--accent-dim);
  color: var(--accent)
}

.surprise-btn:active {
  transform: scale(.96)
}

/* Sleep timer button + menu */
.np-btn-sleep {
  position: relative
}

.np-btn-sleep svg {
  width: 24px;
  height: 24px;
  fill: var(--text-secondary)
}

.np-btn-sleep.active svg {
  fill: var(--accent)
}

.sleep-min {
  position: absolute;
  bottom: -6px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 10px;
  font-weight: 700;
  color: var(--accent);
  white-space: nowrap
}

.sleep-menu {
  position: fixed;
  z-index: 320;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px;
  border-radius: 14px;
  background: var(--bg-elevated, var(--bg-card));
  box-shadow: 0 8px 32px rgba(0, 0, 0, .4);
  border: 1px solid var(--glass-border)
}

.sleep-opt {
  min-width: 120px;
  min-height: 40px;
  padding: 8px 16px;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  text-align: left
}

.sleep-opt:hover {
  background: var(--bg-hover)
}

.sleep-opt.active {
  color: var(--accent);
  background: var(--accent-dim)
}

/* Respect reduced-motion preference */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important
  }

  .np-visualizer .v-bar {
    height: 3px !important
  }

  .live-dot {
    animation: none !important
  }
}
/* ── Guides tab + in-app article reader ───────────────────────────────────────
 * Articles render as a view inside #app-content rather than as a modal, so the
 * mini-player stays mounted below and playback continues while reading. */

.guides-intro {
  color: var(--text-secondary);
  font-size: 14px;
  line-height: 1.55;
  margin: -8px 0 20px;
}

.guide-list {
  display: flex;
  flex-direction: column;
}

.guide-card,
.island-card {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--bg-card);
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 10px;
  box-shadow: var(--card-shadow);
  transition: transform .15s;
}

.guide-card:active,
.island-card:active,
.guide-feature:active,
.art-related-item:active {
  transform: scale(.98);
}

.guide-card-title {
  display: block;
  font-weight: 700;
  font-size: 15px;
  line-height: 1.3;
}

.guide-card-lede {
  display: block;
  margin-top: 5px;
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.5;
}

.island-card {
  display: flex;
  align-items: center;
}

.island-flag {
  font-size: 26px;
  margin-right: 12px;
  flex-shrink: 0;
}

.island-body {
  min-width: 0;
}

.island-name {
  display: block;
  font-weight: 700;
  font-size: 15px;
}

.island-meta {
  display: block;
  margin-top: 2px;
  color: var(--text-secondary);
  font-size: 12px;
}

.guide-feature {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--accent-dim);
  border: 1px solid var(--accent);
  border-radius: 16px;
  padding: 16px;
  transition: transform .15s;
}

.guide-feature-kicker {
  display: block;
  color: var(--accent);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .6px;
  text-transform: uppercase;
}

.guide-feature-title {
  display: block;
  margin-top: 6px;
  font-weight: 800;
  font-size: 17px;
  line-height: 1.25;
}

.guide-feature-lede {
  display: block;
  margin-top: 6px;
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.5;
}

/* ── Reader ── */
.art-back {
  display: inline-block;
  margin-bottom: 12px;
  color: var(--accent);
  font-weight: 700;
  font-size: 14px;
}

.art-title {
  font-size: 26px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -.4px;
}

.art-lede {
  margin-top: 10px;
  color: var(--text-secondary);
  font-size: 16px;
  line-height: 1.6;
}

.art-h2 {
  margin: 26px 0 8px;
  font-size: 18px;
  font-weight: 800;
  line-height: 1.3;
}

.art-p {
  margin-top: 10px;
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-primary);
}

.art-loading {
  color: var(--text-secondary);
  font-size: 15px;
  padding: 24px 0;
}

.art-related {
  display: flex;
  flex-direction: column;
}

.art-related-item {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--bg-card);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 8px;
  transition: transform .15s;
}

.art-related-title {
  font-weight: 700;
  font-size: 14px;
  color: var(--accent);
}

/* Long-form text is selectable even though the app shell disables selection. */
.art-view .art-p,
.art-view .art-lede,
.art-view .art-h2,
.art-view .art-title {
  -webkit-user-select: text;
  user-select: text;
}

/* "Read the full guide" affordance under the Browse editorial block. */
.browse-intro-link {
  display: inline-block;
  margin-top: 8px;
  color: var(--accent);
  font-weight: 700;
  font-size: 13px;
}

.empty-cta {
  display: inline-block;
  margin-top: 16px;
  background: var(--accent);
  color: var(--bg-primary);
  font-weight: 700;
  padding: 12px 22px;
  border-radius: 14px;
  font-size: 15px;
}

/* Now Playing: country + genre are buttons into the reader, not inert text.
   Keep them looking like the labels they replaced. */
.np-station-country {
  background: none;
  border: none;
  font: inherit;
  color: var(--text-secondary);
  cursor: pointer;
}

.np-station-country[disabled] {
  cursor: default;
}

.np-genre-tag {
  cursor: pointer;
}

/* About / Contact / Privacy rendered inside the app. The fetched markup is
   styled by the .doc rules, so the wrapper carries `doc`; these overrides undo
   the standalone page's own page-level layout, which the app view supplies. */
.doc-in-app {
  max-width: 760px;
  margin: 0 auto;
}

.doc-in-app h1 {
  font-size: 26px;
  margin-bottom: 14px;
}

.art-fallback {
  color: var(--accent);
  font-weight: 700;
}
